Retire Murano: remove repo content

Murano project is retiring
- https://review.opendev.org/c/openstack/governance/+/919358

this commit remove the content of this project repo

Depends-On: https://review.opendev.org/c/openstack/project-config/+/919359/
Change-Id: I07209efe58bb1ea60fa43026b15beea112985d2b
This commit is contained in:
Ghanshyam Mann 2024-05-10 15:52:29 -07:00
parent 637f7d6d37
commit 4b967c365b
77 changed files with 8 additions and 16074 deletions

10
.gitignore vendored
View File

@ -1,10 +0,0 @@
AUTHORS
ChangeLog
build
.tox
.venv
*.egg*
*.swp
*.swo
*.pyc
.testrepository

View File

@ -1,7 +0,0 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover tests $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -1,3 +0,0 @@
- project:
templates:
- openstack-specs-jobs

View File

@ -1,14 +0,0 @@
The source repository for this project can be found at:
https://opendev.org/openstack/murano-specs
Pull requests submitted through GitHub are not monitored.
To start contributing to OpenStack, follow the steps in the contribution guide
to set up and use Gerrit:
https://docs.openstack.org/contributors/code-and-documentation/quick-start.html
This repository is for doing design review on feature proposal in Murano.
Please refer to `this document <https://opendev.org/openstack/murano-specs/src/branch/master/README.rst>`_
for more information.

View File

@ -1,3 +0,0 @@
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
http://creativecommons.org/licenses/by/3.0/legalcode

View File

@ -1,66 +1,10 @@
========================
Team and repository tags
========================
This project is no longer maintained.
.. image:: http://governance.openstack.org/badges/murano-specs.svg
:target: http://governance.openstack.org/reference/tags/index.html
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".
.. Change things from this point on
===============================
OpenStack Murano Specifications
===============================
This git repository is used to hold approved design specifications for additions
to the Murano project. Reviews of the specs are done in gerrit, using a similar
workflow to how we review and merge changes to the code itself.
The layout of this repository is::
specs/<release>/
Where there are two sub-directories:
specs/<release>/approved: specifications approved but not yet implemented
specs/<release>/implemented: implemented specifications
This directory structure allows you to see what we thought about doing,
decided to do, and actually got done. Users interested in functionality in a
given release should only refer to the ``implemented`` directory.
You can find an example spec in `doc/source/specs/template.rst`.
Specifications are proposed for a given release by adding them to the
`specs/<release>` directory and posting it for review. The implementation
status of a blueprint for a given release can be found by looking at the
blueprint in launchpad. Not all approved blueprints will get fully implemented.
Specifications have to be re-proposed for every release. The review may be
quick, but even if something was previously approved, it should be re-reviewed
to make sure it still makes sense as written.
Prior to the Kilo development cycle this repository was not used for
spec reviews. Reviews prior to Juno were completed entirely through
Launchpad blueprints::
http://blueprints.launchpad.net/murano
Starting from the Kilo-1 developement milestone Murano performs the pilot of
the specs repos approach.
Please note, Launchpad blueprints are still used for tracking the
current status of blueprints. For more information, see::
https://wiki.openstack.org/wiki/Blueprints
For more information about working with gerrit, see::
http://docs.openstack.org/infra/manual/developers.html#development-workflow
To validate that the specification is syntactically correct (i.e. get more
confidence in the Jenkins result), please execute the following command::
$ tox
After running ``tox``, the documentation will be available for viewing in HTML
format in the ``doc/build/`` directory.
For any further questions, please email
openstack-discuss@lists.openstack.org or join #openstack-dev on
OFTC.

View File

@ -1,274 +0,0 @@
# -*- coding: utf-8 -*-
#
# Tempest documentation build configuration file, created by
# sphinx-quickstart on Tue May 21 17:43:32 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import datetime
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('.'))
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['redirect',
'sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.viewcode',
'openstackdocstheme',
'yasfb',
]
# Feed configuration for yasfb
feed_base_url = 'https://specs.openstack.org/openstack/murano-specs'
feed_author = 'OpenStack Murano Team'
todo_include_todos = True
# 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-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Murano Specs'
copyright = u'%s, OpenStack Murano Team' % datetime.date.today().year
# 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 = [
'_build',
'**/template.rst',
]
# 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 = False
# 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 = 'native'
# A list of ignored prefixes for module index sorting.
modindex_common_prefix = ['murano-specs.']
# openstackdocstheme options
openstackdocs_repo_name = 'openstack/murano-specs'
openstackdocs_bug_project = 'murano'
openstackdocs_bug_tag = ''
# -- Options for man page output ----------------------------------------------
man_pages = []
# -- Options for HTML output ---------------------------------------------------
# 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 = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# 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
# 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 = False
# If false, no index is generated.
html_use_index = False
# 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 <link> 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 = 'Murano-Specsdoc'
# -- 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]).
latex_documents = [
('index', 'Murano-specs.tex', u'Murano Specs',
u'OpenStack Murano Team', '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 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', 'Murano-specs', u'Murano Design Specs',
u'OpenStack Murano Team', 'murano-specs', 'Design specifications for the Murano project.',
'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'
# -- Options for Epub output ---------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = u'Murano Specs'
epub_author = u'OpenStack Murano Team'
epub_publisher = u'OpenStack Murano Team'
epub_copyright = u'2014, OpenStack Murano Team'
# The language of the text. It defaults to the language option
# or en if the language is not set.
#epub_language = ''
# The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = ''
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#epub_identifier = ''
# A unique identification for the text.
#epub_uid = ''
# A tuple containing the cover image and cover page html template filenames.
#epub_cover = ()
# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_pre_files = []
# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []
# A list of files that should not be packed into the epub file.
#epub_exclude_files = []
# The depth of the table of contents in toc.ncx.
#epub_tocdepth = 3
# Allow duplicate toc entries.
#epub_tocdup = True

View File

@ -1,78 +0,0 @@
.. murano-specs documentation master file
=====================
Murano Specifications
=====================
Kilo specs:
.. toctree::
:glob:
:maxdepth: 1
specs/kilo/*
Liberty specs:
.. toctree::
:glob:
:maxdepth: 1
specs/liberty/*
Mitaka specs:
.. toctree::
:glob:
:maxdepth: 1
specs/mitaka/*
Newton specs:
.. toctree::
:glob:
:maxdepth: 1
specs/newton/approved/*
specs/newton/implemented/*
Ocata specs:
.. toctree::
:glob:
:maxdepth: 1
specs/ocata/approved/*
Pike specs:
.. toctree::
:glob:
:maxdepth: 1
specs/pike/approved/*
Queens specs:
.. toctree::
:glob:
:maxdepth: 1
specs/queens/approved/*
==========================
Murano apps Specifications
==========================
.. toctree::
:glob:
:maxdepth: 1
specs/murano-apps/*
==================
Indices and tables
==================
* :ref:`search`

View File

@ -1,50 +0,0 @@
# A simple sphinx plugin which creates HTML redirections from old names
# to new names. It does this by looking for files named "redirect" in
# the documentation source and using the contents to create simple HTML
# redirection pages for changed filenames.
# Stolen from openstack/nova-specs
import os.path
from sphinx.util import logging
LOG = logging.getLogger(__name__)
def process_redirect_file(app, path, ent):
parent_path = path.replace(app.builder.srcdir, app.builder.outdir)
with open(os.path.join(path, ent)) as redirects:
for line in redirects.readlines():
from_path, to_path = line.rstrip().split(' ')
from_path = from_path.replace('.rst', '.html')
to_path = to_path.replace('.rst', '.html')
redirected_filename = os.path.join(parent_path, from_path)
redirected_directory = os.path.dirname(redirected_filename)
if not os.path.exists(redirected_directory):
os.makedirs(redirected_directory)
with open(redirected_filename, 'w') as f:
f.write('<html><head><meta http-equiv="refresh" content="0; '
'url=%s" /></head></html>'
% to_path)
def emit_redirects(app, exc):
LOG.info('scanning %s for redirects...', app.builder.srcdir)
def process_directory(path):
for ent in os.listdir(path):
p = os.path.join(path, ent)
if os.path.isdir(p):
process_directory(p)
elif ent == 'redirects':
LOG.info(' found redirects at %s' % p)
process_redirect_file(app, path, ent)
process_directory(app.builder.srcdir)
LOG.info('...done')
def setup(app):
app.connect('build-finished', emit_redirects)

View File

@ -1 +0,0 @@
../../specs

View File

@ -1,10 +0,0 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr>=2.0.0,!=2.1.0 # Apache-2.0
sphinx>=2.0.0,!=2.1.0 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
yasfb>=0.8.0
openstackdocstheme>=2.2.1 # Apache-2.0

View File

@ -1,12 +0,0 @@
[metadata]
name = murano-specs
summary = OpenStack Murano Project Development Specs
description-file =
README.rst
author = OpenStack
author-email = openstack-discuss@lists.openstack.org
home-page = http://specs.openstack.org/openstack/murano-specs/
classifier =
Intended Audience :: Developers
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux

View File

@ -1,22 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
setuptools.setup(
setup_requires=['pbr>=2.0'],
pbr=True)

View File

@ -1,542 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==========================================
Environment Template Catalogue
==========================================
https://blueprints.launchpad.net/murano/+spec/blueprint-template
Problem description
===================
One of powerful Murano use cases is deploying compound applications, composed by set of
different layers such as DB, web server and others, which implies the deployment of
software not just in an unique VM but in several ones. The environment template is the specification of
the set of VMs plus the applications to be installed on top of. The user can define
environment templates from scratch or reuse and customize them (e.g. including keypairs).
Environment templates not only cover instantiation, but also the specification of such templates,
store them in a catalogue and clone them from the abstract template catalog. In this way,
an abstract environment template catalogue as well as a environment template one will be stored in the
database, storing templates shared among all users and individual ones.
Proposed change
===============
In order to fullfill this functionality, a new entity can be introduced in the MURANO
database. It is the Murano environment-template, which contains the specification about what
is going to be deployed in terms of virtual resources and application information, and it can be deployed
on top of Openstack by translating it into environment. This environment template can be created, deleted,
modified and customized by the users. In fact, it can be instantiate as many times as the user wants.
For instance, the user wants to have different deployments from the same environment template: one for
testing and another for production.
The environment template is composed by a set of services/applications with the software to be installed together their
properties to work with. This software can be instantiate over an virtual service.
In this case the workflow for the creation and the instantiation of the environment template will imply:
1.- Creation of the environment template (including application information)
2.- Transformation of the environment template into the environment (creation of the environment, session and
adding applications to the environment
3.- Deploy the environment on top of Openstack.
The environment template structure and information will be similar to the environment, not including some hardware information, like
default network, or virtual server name. Mainly, the environment template information will contain:
- template name, the name for the template. In case, it is not provided, the request will not be valid.
- services, the application information. For each service it will include information about the applications to be
installed (like tomcat), including application properties like tomcat port. In addition, in case applied, the information about
the virtual server (instance) will be incorporated like keyname, flavor, image and so on. The following lines show
an environment template example.
::
{
"name": "env_template_name",
"services": [
{
"instance": {
"assignFloatingIp": "true",
"keyname": "mykeyname",
"image": "cloud-fedora-v3",
"flavor": "m1.medium",
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": "ef984a74-29a4-45c0-b1dc-2ab9f075732e"
}
},
"name": "tomcat",
"port": "8080",
"?": {
"type": "io.murano.apps.apache.Tomcat",
"id": "54cea43d-5970-4c73-b9ac-fea656f3c722"
}
}
]
}
Alternatives
------------
None
Data model impact
-----------------
A environment template entity will be introduced in the MURANO object model. This implies its existence
in the database, the inclusion of Template services and the extension of the API. The template entity
can consist on:
template :-
murano:property(temp_id, "created", datetime)
murano:property(temp_id, "updated", datetime)
murano:property(temp_id, "id", ID)
murano:property(temp_id, "name", varchar)
murano:property(temp_id, "tenant-id", varchar)
murano:property(temp_id, "version", bigint)
murano:property(temp_id, "description", text)
murano:property(temp_id, "networking", text)
REST API impact
---------------
The inclusion of the environment-template entity will imply the extension of the API for the environment-template
creation, deletion, updating and translate into the environment.
**POST /templates**
*Request*
+----------+--------------------------------+--------------------------------------+
| Method | URI | Description |
+==========+================================+======================================+
| POST | /templates | Create a new environment template |
+----------+--------------------------------+--------------------------------------+
*Content-Type*
application/json
*Example Payload*
This template description can be composed just by the environment template name, or it can
include the description of all services/applications to be deployed.
1.- Just the template
::
{
'name': 'env_template_name'
}
2.- Specification of all the services
::
{
"name": "env_template_name",
"services": [
{
"instance": {
"assignFloatingIp": "true",
"keyname": "mykeyname",
"image": "cloud-fedora-v3",
"flavor": "m1.medium",
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": "ef984a74-29a4-45c0-b1dc-2ab9f075732e"
},
"name": "orion",
"port": "8080",
"?": {
"type": "io.murano.apps.apache.Tomcat",
"id": "54cea43d-5970-4c73-b9ac-fea656f3c722"
}
}
]
}
*Response*
::
{
"updated": "2015-01-26T09:12:51",
"networking":
{
},
"name": "template_name",
"created": "2015-01-26T09:12:51",
"tenant_id": "00000000000000000000000000000001",
"version": 0,
"id": "aa9033ca7ce245fca10e38e1c8c4bbf7",
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Environment Template created successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 409 | The environment template already exists |
+----------------+-----------------------------------------------------------+
**GET /templates/{env-temp-id}**
*Request*
+----------+--------------------------------+-------------------------------------------------+
| Method | URI | Description |
+==========+================================+=================================================+
| GET | /templates/{env-temp-id} | Obtains the environment template information |
+----------+--------------------------------+-------------------------------------------------+
*Parameters:*
* `env-temp-id` - environment template ID, required
*Content-Type*
application/json
*Response*
::
{
"updated": "2015-01-26T09:12:51",
"networking":
{
},
"name": "template_name",
"created": "2015-01-26T09:12:51",
"tenant_id": "00000000000000000000000000000001",
"version": 0,
"id": "aa9033ca7ce245fca10e38e1c8c4bbf7",
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Environment Template created successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 404 | The environment template does not exit |
+----------------+-----------------------------------------------------------+
**DELETE /templates/{env-temp-id}**
*Request*
+----------+-----------------------------------+-----------------------------------+
| Method | URI | Description |
+==========+===================================+===================================+
| DELETE | /templates/<env-temp-id> | Delete the template id |
+----------+-----------------------------------+-----------------------------------+
*Parameters:*
* `env-temp_id` - environment template ID, required
*Response*
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Environment Template deleted successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified environment template doesn`t exist |
+----------------+-----------------------------------------------------------+
**POST /templates/{template-id}/services**
*Request*
+----------+------------------------------------+----------------------------------+
| Method | URI | Description |
+==========+====================================+==================================+
| POST | /templates/{env-temp-id}/services | Create a new application |
+----------+------------------------------------+----------------------------------+
*Parameters:*
* `env-temp-id` - The environment-template id, required
* payload - the service description
*Content-Type*
application/json
*Example*
::
{
"instance": {
"assignFloatingIp": "true",
"keyname": "mykeyname",
"image": "cloud-fedora-v3",
"flavor": "m1.medium",
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": "ef984a74-29a4-45c0-b1dc-2ab9f075732e"
}
},
"name": "orion",
"port": "8080",
"?": {
"type": "io.murano.apps.apache.Tomcat",
"id": "54cea43d-5970-4c73-b9ac-fea656f3c722"
}
}
*Response*
::
{
"instance":
{
"assignFloatingIp": "true",
"keyname": "mykeyname",
"image": "cloud-fedora-v3",
"flavor": "m1.medium",
"?":
{
"type": "io.murano.resources.LinuxMuranoInstance",
"id": "ef984a74-29a4-45c0-b1dc-2ab9f075732e"
}
},
"name": "orion",
"?":
{
"type": "io.murano.apps.apache.Tomcat",
"id": "54cea43d-5970-4c73-b9ac-fea656f3c722"
},
"port": "8080"
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Application added successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 404 | The environment template does not exit |
+----------------+-----------------------------------------------------------+
**GET /templates/{env-temp-id}/services***
Request*
+----------+-------------------------------------+-----------------------------------+
| Method | URI | Description |
+==========+=====================================+===================================+
| GET | /templates/{env-temp-id}/services | It obtains the service description|
+----------+-------------------------------------+-----------------------------------+
*Parameters:*
* `env-temp-id` - The environment template ID, required
*Content-Type*
application/json
*Response*
::
[
{
"instance":
{
"assignFloatingIp": "true",
"keyname": "mykeyname",
"image": "cloud-fedora-v3",
"flavor": "m1.medium",
"?":
{
"type": "io.murano.resources.LinuxMuranoInstance",
"id": "ef984a74-29a4-45c0-b1dc-2ab9f075732e"
}
},
"name": "tomcat",
"?":
{
"type": "io.murano.apps.apache.Tomcat",
"id": "54cea43d-5970-4c73-b9ac-fea656f3c722"
},
"port": "8080"
},
{
"instance": "ef984a74-29a4-45c0-b1dc-2ab9f075732e",
"password": "XXX",
"name": "mysql",
"?":
{
"type": "io.murano.apps.database.MySQL",
"id": "54cea43d-5970-4c73-b9ac-fea656f3c722"
}
}
]
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Tier created successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 404 | The environment template does not exit |
+----------------+-----------------------------------------------------------+
**POST /templates/{env-temp-id}/create-environment**
*Request*
+----------+--------------------------------------------+--------------------------------------+
| Method | URI | Description |
+==========+============================================+======================================+
| POST | /templates/{env-temp-id}/create-environment| Create an environment |
+----------+--------------------------------------------+--------------------------------------+
*Parameters:*
* `env-temp-id` - The environment template ID, required
*Payload:*
* 'environment name': The environment name to be created.
*Content-Type*
application/json
*Example*
::
{
'name': 'environment_name'
}
*Response*
::
{
"environment_id": "aa90fadfafca10e38e1c8c4bbf7",
"name": "environment_name",
"created": "2015-01-26T09:12:51",
"tenant_id": "00000000000000000000000000000001",
"version": 0,
"session_id": "adf4dadfaa9033ca7ce245fca10e38e1c8c4bbf7",
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Environment template created successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 404 | The environment template does not exit |
+----------------+-----------------------------------------------------------+
| 409 | The environment already exists |
+----------------+-----------------------------------------------------------+
Versioning impact
-------------------------
Murano client will change to include this new functionality.
Other end user impact
---------------------
As well as a change in the API to include this new entity, the python-muranoclient will
be changed for including the environment template operations.
* env-template-create Create an environment template.
* env-template-delete Delete an environment template.
* env-template-list List the environment templates.
* env-template-rename Rename an environment template.
* env-template-show Show the information of the environment template
* env-template-add-app Add an application to the environment template
* env-template-create-environment It creates an environment from the environment template description
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
New views will be required for including the environment template functionality
Implementation
==============
Assignee(s)
-----------
Primary assignee:
hmunfru
Other contributors:
jesuspg
TBC
Work Items
----------
1.- Including the environment template entity in database
2.- Extension of the API for environment template catalogue
3.- Generation of environment from template operation
4.- Implement the changes in murano CLI
Dependencies
============
Testing
=======
TBD
Documentation Impact
====================
Environment template documentation should be included.
References
==========
https://etherpad.openstack.org/p/GLLAQ0m1H7

View File

@ -1,224 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==============================
Configuration Language Support
==============================
https://blueprints.launchpad.net/murano/+spec/conf-language-support
Problem description
===================
There is a huge community of applications (opscode, puppet-labs) where
deployment installation instructions are specified in configuration
languages such as Puppet or Chef. In order to reuse these applications,
adaptors like Chef or Puppet are required on the VM side. Both chef and
puppet recipes will not be managed by centralized server (chef-server,
puppet-master), but they will use the standalone version, specifically
the usage of chef-solo and puppet apply.
Proposed change
===============
Inclusion of new executors in the murano-agent project. These executors
will be objects to be used by murano-agent. Specifically, two executors
will be implemented: Puppet and Chef. Both executors will be in charge of:
* Obtaining the required modules or cookbooks in the virtual machine.
This task can be done by passing the information from murano-engine to
murano-agent, obtaining the information from the package itself. It requires
the user to upload the package information plus the cookbooks to be used.
The second option implies the cookbooks are downloaded in the virtual
machine, so that they only need the URL to be accessible.
* Generating the required files for the configuration language.
For instance, manifests and hiera data for puppet, and, node
specifications for chef from the information stored in the
execution plan.
* Executing the chef-solo or puppet-apply process.
Previously, some work has to be done to install Chef or Puppet inside the VM.
This task can be done by using cloud-init from the murano engine. The
following is an example on how these executors work:
::
## YAML Template.
---
FormatVersion: 2.0.0
Version: 1.0.0
Name: Deploy Tomcat
Parameters:
port: $port
Body: |
return deployTomcat(port=args.port).stdout
Scripts:
deployTomcat:
Type: Chef
Version: 1.0.0
EntryPoint: mycoockbook::myrecipe
Files:
tomcat:
Name: tomcat
URL: git://github.com/opscode-cookbooks/tomcat.git
Type: Downloadable
java:
Name: java
URL: git://github.com/opscode-cookbooks/java.git
Type: Downloadable
ssl:
Name: openssl
URL: https://github.com/opscode-cookbooks/ssl.git
Type: Downloadable
Options:
captureStdout: true
captureStderr: true
In this case, a new script Type appears (instead of Application). It is
Chef type, which will execute the Chef executor. The same happens with
the Puppet Type. In addition, the EntryPoint contains the information
about the cookbook and the recipe to be installed. The Files section
is used for the cookbooks and its dependence information. The cookbooks
properties are in the Parameter section.
All the required steps to be part of the executor can be summarized as follows.
For Chef,
#. Creating the node.json with the recipes and the configuration parameters::
{
orion::ports: 1026
orion::dbname: oriondb
"run_list": [
"recipe[orion::0.13.0_install]"
]
}
#. Executing chef-solo:
chef-solo -j node.json
For puppet,
#. Generating the manifest (site.pp)::
node 'default'
{
class{
'orion::install':
}
}
#. Creating the hiera data information: hiera.yaml::
## YAML Template.
---
orion::port: 1026
orion::dbname: oriondb
#. Executing:
puppet apply --hiera_config=hiera.yaml --modulepath=/opt/puppet/modules/orion site.pp
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
The solution proposed is valid for any VM which contains the configuration
language implementation already installed. There are event chef-solo and
puppet agents for Windows.
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
hmunfru
Other contributors:
jesuspg
Work Items
----------
#. Generate Chef executor
#. Generate Puppet executor
#. Work on configuration
Dependencies
============
None
Testing
=======
Integration tests will be done
Documentation Impact
====================
Information about how to defines application for Puppet and Chef will have
to be documented, explaining the different fields.
References
==========
* http://es.slideshare.net/hmunfru/fiware-and-murano-support-for-configuration-languages
* https://etherpad.openstack.org/p/conf-language-support-spec

View File

@ -1,189 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
======================================================
Policy Guided Fulfillment - Congress Support in Murano
======================================================
URL of launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/congress-support-in-murano
Problem description
===================
As a part of policy guided fulfillment we need to call Congress from Murano,
to enforce the policy on Murano environment. For current release
the enforcement will be done by Congress simulation API, where Murano will
query table *predeploy_error* in *murano_system* policy for passed update
sequence created by mapping of environment into congress schema.
Proposed change
===============
We need to provide
* python congress client in Murano
We will use simulation feature of `congress API
<https://docs.google.com/document/d/14hM7-GSm3CcyohPT2Q7GalyrQRohVcx77hx
Ex4AO4Bk/edit#heading=h.ll03wo2z9pcb>`_.
Using this API Murano will send decomposed Murano environment to Congress
tables, so simulation can evaluate *predeploy_error* rule without changing
existing data in Congress.
* mapping of Murano Environment into *update sequence* used in simulation API
Murano To Congress Mapping Details
----------------------------------
This section provides congress schema created for Murano environment mapping.
It will be created by Congress datasource drivers - see `murano driver spec
<https://blueprints.launchpad.net/congress/+spec/murano-driver>`_ .
* **Policies**
* **murano**
Dedicated policy for Murano data.
* **murano_system**
Dedicated policy for rules
* **Schema**
* *murano:objects(obj_id, owner_id, type)*
This table holds every MuranoPL object instance in an environment.
* *obj_id* - uuid of the object as used in Murano
* *owner_id* - uuid of the owner object as used in Murano
* *type* - string with full type indentifier as used in Murano
(e.g., io.murano.Environment,...)
* *murano:parent_types(obj_id, parent_type)*
This table holds parent types of *obj_id* object. Note that Murano
supports multiple inheritance, so there can be several parent types for
one object
* *murano:properties(obj_id, name, value)*
This table stores object's properties. For multiple cardinality
properties, there can be number of records here. MuranoPL properties
referencing class type (i.e., another object) are stored in
*murano:relatinoship*. Properties with structured content will be
stored component by component.
* *murano:relationships(src_id, trg_id, name)*
This table stores relationship between objects (i.e., MuranoPL property
to *class*). For multiple cardinality relationships several records
should be stored.
* *murano:connected(src_id, trg_id)*
This table stores tuples of objects connected directly and indirectly
via relationship. It is necessary since Congress does not support
recursive rules yet.
* *murano:states(end_id, state)*
This table stores *EnvironmentStatus* of Murano environment ( one of
'ready', 'pending', 'deploying', 'deploy failure', 'deleting',
'delete failure' ).
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
filip-blaha
Other contributors:
ondrej-vojta, radek-pospisil
Work Items
----------
1. Introduce Congress python client into Murano
2. Implement mapping of Murano Environment into Congress simulation API
update-sequence.
3. Provide tests
Dependencies
============
* Congress python client ( `GIT <https://opendev.org/openstack/python-congressclient>`_ )
will be added into Murano.
* *Murano datasource driver* in Congress `murano driver spec
<https://blueprints.launchpad.net/congress/+spec/murano-driver>`_
Testing
=======
Testing will use predefined Congress policy rules in order to test client and
mapping. See https://etherpad.openstack.org/p/policy-congress-murano-spec for
an example mapping and test.
Documentation Impact
====================
Documentation impact is specified in `Policy Enforcement Point <https://bluepri
nts.launchpad.net/murano/+spec/policy-enforcement-point>`_ blueprint.
References
==========
* *Murano datasource driver* in Congress
https://blueprints.launchpad.net/congress/+spec/murano-driver
* https://blueprints.launchpad.net/murano/+spec/policy-enforcement-point
* https://etherpad.openstack.org/p/policy-congress-murano-spec

View File

@ -1,309 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
====================================================
Provide opportunity to manage application categories
====================================================
https://blueprints.launchpad.net/murano/+spec/enable-category-management
Murano is an application catalog, where new applications can be easily added.
Those applications may belong to a category, that is not on predefined list.
Also, some categories may not be needed, and user can delete such kind
of categories.
All operations should be available only for admin users.
Problem description
===================
Category management should be provided during:
* Packages uploading in dashboard;
* Packages modifying in dashboard;
* Packages uploading or modifying via command line;
Adding new category:
* Category name may contain spaces and other special characters;
* Category name limit is equal to 80 characters;
* Only admin users can add new category;
Deleting category:
* Category may be deleted only if no packages belong to this category;
* Only admin users can delete category;
Proposed change
===============
Changes required to support this feature:
* Add new panel named 'Categories' under 'Manage' section;
It should be available only for admin users.
This panel should represent table with categories.
The table will contain 'name' column and 'assigned packages' column.
"Add category" will be a table action and "Delete Category" will be
row action.
Delete button should be hidden for those categories connected to
the packages.
* Provide corresponding methods in the python-muranoclient;
Category manager will be added to v1 module;
Alternatives
------------
Admin can edit a database to add or delete categories.
Data model impact
-----------------
None
REST API impact
---------------
**GET /catalog/categories**
The previous call /catalog/packages/categories is will still be valid to
support backward compatibility.
*Request*
+----------+----------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==================================+==================================+
| Get | /catalog/categories | Get list of existing categories |
+----------+----------------------------------+----------------------------------+
*Response*
::
{"categories": [
"id": "3dd486b1e26f40ac8f35416b63f52042",
"updated": "2014-12-26T13:57:04",
"name": "Web",
"created": "2014-12-26T13:57:04",
"package_count": 0
},
{
"id": "k67gf67654f095gf89hjj87y56g98965v",
"updated": "2014-12-26T13:57:04",
"name": "Databases",
"created": "2014-12-26T13:57:04",
"package_count": 0
}]
}
**GET /catalog/categories/<category_id>**
*Request*
+----------+-----------------------------------+----------------------------------+
| Method | URI | Description |
+==========+===================================+==================================+
| Get | /catalog/categories/<category_id> | Get category detail |
+----------+-----------------------------------+----------------------------------+
*Parameters*
* `category_id` - category ID, required
*Response*
::
{
"id": "0420045dce7445fabae7e5e61fff9e2f",
"updated": "2014-12-26T13:57:04",
"packages": [
"Apache HTTP Server",
"Apache Tomcat",
"PostgreSQL"
],
"name": "Web",
"created": "2014-12-26T13:57:04"
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Category retrieved successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified category doesn`t exist |
+----------------+-----------------------------------------------------------+
**POST /catalog/categories**
+----------------------+------------+--------------------------------------------------------+
| Attribute | Type | Description |
+======================+============+========================================================+
| name | string | Category name |
+----------------------+------------+--------------------------------------------------------+
*Request*
+----------+----------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==================================+==================================+
| POST | /catalog/categories | Create new category |
+----------+----------------------------------+----------------------------------+
*Content-Type*
application/json
*Example*
{"name": "category_name"}
*Response*
::
{
"id": "ce373a477f211e187a55404a662f968",
"name": "category_name",
"created": "2013-11-30T03:23:42Z",
"updated": "2013-11-30T03:23:44Z",
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Category created successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 403 | Forbidden. Category with specified name already exist |
+----------------+-----------------------------------------------------------+
**DELETE /catalog/categories**
*Request*
+----------+-----------------------------------+-----------------------------------+
| Method | URI | Description |
+==========+===================================+===================================+
| DELETE | /catalog/categories/<category_id> | Delete category with specified id |
+----------+-----------------------------------+-----------------------------------+
*Parameters:*
* `category_id` - category ID, required
*Response*
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Category deleted successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified category doesn`t exist |
+----------------+-----------------------------------------------------------+
| 403 | Forbidden. Category with specified name is assigned to |
| | the package, presented in the catalog. Only empty |
| | categories can be removed |
+----------------+-----------------------------------------------------------+
Versioning impact
-----------------
Murano dashboard will support only the version of the client, that includes
corresponding changes in the client. 'Categories' panel will not work
with the old murano version, but application catalog and package management
will work fine.
Other end user impact
---------------------
None
Murano-dashboard / Horizon impact
---------------------------------
Category management will be available in dashboard.
Areas to be changed: (described in sections above)
* Manage section will have new panel;
Deployer impact
---------------
None
Developer impact
----------------
None
Implementation
==============
Assignee(s)
-----------
Ekaterina Chernova
Primary assignee:
<efedorova@mirantis.com>
Work Items
----------
* Introduce 2 additional calls in API
* Update API specification
* Provide these calls in python-muranoclient
* Implement changes in dashboard
* Enable CLI to manage categories
Dependencies
============
None
Testing
=======
New tests should be added in dashboard integration tests
Documentation Impact
====================
API specification should be updated.
All changes are already represented here, just need to copy.
References
==========
None

View File

@ -1,165 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==================================
Add timeouts to murano-agent calls
==================================
https://blueprints.launchpad.net/murano/+spec/murano-agent-timeouts
Now there is no way to be sure that the agent successfully started execution
on a VM. Also there is no control of the execution time of scripts on agent.
This process should be more controllable. It can be done by adding timeouts
in Murano engine.
Problem description
===================
* During the agent`s work there could be some problems with execution of scripts and
VM may hang. In this case user will wait indefinitely without knowing
what's happened.
* Currently there is no feedback from agent so, it`s impossible to determine
whether agent is ready to accept execution plans or not.
It is proposed to provide mechanism of timeouts which solves these problems.
Proposed change
===============
1) First of all add timeout to method *call* of agent on engine-side.
Optional parameter *timeout* will be added to method *call* of class *Agent*
in agent.py. This parameter is the time in seconds with default value *600*.
Developer can set up custom value during developing apps for example in this
way::
- $.instance.agent.call($template, $resources, 300)
If the agent plan execution time exceeds the limit, it will be terminated.
2) Add method *waitReady* in Agent class.
Method will be added to *Agent* class in agent.py. It has optional parameter
*timeout* with default value *100*. *waitReady* creates test plan with trivial
body::
template = {'Body': 'return', 'FormatVersion': '2.0.0', 'Scripts': {}}
and sends this plan once to agent by method *call*. It can be used by developer
to stop deployment before sending template of app if agent is inaccessible as
follows::
- $.instance.agent.waitReady()
- $.instance.agent.call($template, $resources)
If the agent test plan execution time exceeds the time limit,
*TimeoutException* will be raised and deployment terminates. *TimeoutException*
will be created in murano/common/exceptions.py.
3) Add new method *isReady* in Agent class.
This method will simply call the *waitReady*. Method *isReady* returns:
* *True*, if test plan is executed on time;
* *False*, if the agent plan execution time exceeds the
limit.
* and raise *PolicyViolationException*, which will be created in
murano/common/exceptions.py, if the agent disabled by the server.
The method can be used during development Murano-applications. For example,
developer can check if the agent is running and ready to execute templates
before sending the execution plan of application:
::
- If: $.instance.agent.isReady()
Then:
- $._environment.reporter.report($this, 'Murano Agent is ready')
The message in above example will be reported to Murano Dashboard.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:lk
ddovbii
Work Items
----------
The change is simple and can be done in one Gerrit patch. Implementation is
acutally completed.
Dependencies
============
None
Testing
=======
Unit and integration tests must be done.
Documentation Impact
====================
MuranoPL specification should be updated.
References
==========
None

View File

@ -1,141 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==========================
murano-mistral-integration
==========================
https://blueprints.launchpad.net/murano/+spec/murano-mistral-integration-1
The purpose is to add integration between Murano and Mistral.
We would like to allow invocation of a Mistral workflow from Murano.
No prerequisite for uploaded Mistral workflow.
Problem description
===================
A new capability in Murano modeling process should be added in order to answer
several use cases, including:
#. The application modeler wishes to leverage existing workflow that deploys
a specific component as part of a new application model creation process.
#. The application modeler wishes to add post-deployment logic to an
application model.
For example:
a. Check that the application has been successfully deployed.
b. Inject initial data to the deployed application.
Proposed change
===============
Adding a new system class for Mistral Client that allows to call Mistral
APIs from the Murano application model.
The system class will allow you to:
#. Upload a Mistral workflow to Mistral.
#. Trigger the already-deployed Mistral workflow, wait for completion and
return the execution output.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
Natasha Beck
Work Items
----------
#. Add mistral client system class that can trigger pre-deployed Mistral
workflow.
#. Add ability to the client to upload the Mistral workflow.
#. Add test that deploys application which uploads the Mistral workflow from
Resources, triggers it and gets output as a result.
Dependencies
============
Openstack Mistral component.
Testing
=======
Functional test will be added to Murano.
The test deploys application which uploads the Mistral workflow from
Resources, triggers it and gets output as a result.
Documentation Impact
====================
Murano-Mistral integration must be documented from the following perspectives:
* Setup configuration (for example with and without mistral)
* Include usage of Mistral workflow as a part of an application model
The following Murano documentation will be affected:
* Murano Installation Guide
Add section on Mistral requirement
* Murano Workflow
Add section on Murano-Mistral integration
* Murano Article (new)
Article on Murano-Mistral integration
References
==========
None

View File

@ -1,190 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=========================
Murano Repository Support
=========================
https://blueprints.launchpad.net/murano/+spec/muranoclient-marketplace-support
Murano applications provide a powerful and flexible way to move workloads
from other cloud environments to OpenStack. In order to accelerate
application migrating we need a way to deliver Murano
packages and Glance images to customers incrementally, independent from major
releases of OpenStack.
Problem description
===================
Typical use cases:
* After the end users installed and configured Murano they would need to
install murano-enabled applications. To do so they would use `murano` CLI
client. Invoking a command like
`murano install-package io.apps.application --version=2.0` would
install the application in question alongside with all requirements
(applications and glance images)
* A developer would want to provide murano applications to end users, by
hosting them on a web server and providing http-access to application
packages. In that case end users would be able to install the application by
invoking a CLI command `murano install-package http://path/to/app`
* End user would want to install bundles of applications that are often
required to work together, but not necessarily depend on each other.
In that case end user would invoke a command
`murano install-bundle bundle_name` and murano-client would download all
the applications mentioned in the bundle alongside with their requirements.
* End users would want to perform same operations through
murano-dashboard instead of CLI tools.
Proposed change
===============
The proposition is to implement a set of features in python-muranoclient and
murano-dashboard, that would allow end users to install applications from
http application repository.
* Enable `package-import` command to support url as a parameter for import by
modifying the way package creation of murano-client works.
* Enable `package-import` command to support package name as a parameter for
import, introduce `--murano-repo-url` as a base path to the repository.
* Introduce `bundle-import` command and allow it to support local-files, urls
and bundle names as parameters for import. The command should parse the
bundle file and import all the packages, mentioned in the file.
Bundle should be a simple json and/or yaml-structured file.
* Introduce `Require:` section to `manifest.yaml`, that would specify which
packages are required by the appication.
* Enable package creation suite to automatically import all the packages
mentioned in `Require:` section.
* Introduce `images.lst` file in the package structure, that would contain a
list of images, required for the application to work.
* Enable package creation suite to automatically import required images into
glance image service.
* Allow `bundle-import` command to import bundles from local-files. In that
case first search for package files and image files in the local filesystem,
relative to the location of the bundle file. If file is not found locally
attempt to connect to the repository.
* Enable murano-dashboard to support changes made to client and introduce a way
to upload packages via url/name to dashboard.
* Implement importing of bundles in murano-dashboard by url or by name.
Since bundles are currently a simple json/yaml optionally we could optionally
support direct input.
* Implement error handling both for CLI-tools and dashboard, that would inform
end users about any errors that might have happened along the way of
importing.
* Optionally implement a progress marker and a ETA-marker for CLI `import`
commands.
Alternatives
------------
Implementing a server, that would hold versions and paths to package files
and implementing a client to that server might be a good alternative to a
simple http-server, although it seems a bit excessive at the moment.
Another idea would be to implement a service, that would download packages
asynchronously. This would allow client to download large package files and
image files with possibly better error handling mechanisms. This also seems a
bit excessive at the moment.
Data model impact
-----------------
It might be a good idea to store information about required apps and required
images, although it is not strictly required for the task.
REST API impact
---------------
It might be a good idea to warn the end user if the client installed a
package, that depends on other packages, not present in app catalog,
although it is not strictly required for the task.
Versioning impact
-----------------
This proposition adds functionality both to python-muranoclient and to
murano-dashboard. It should be fully backward compatible.
Minor version of python-muranoclient should be increased, because we add
functionality.
Other end user impact
---------------------
See *Proposed Change* section, as it describes all the ways users would
interact with the feature
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
Package import dialog should be changed to reflect different ways of
importing an application.
Additional bundle-import dialog should be implemented.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
<kzaitsev@mirantis.com>
Work Items
----------
* Add support for importing packages by url in client
* Add support for importing packages by name in client
* Add support for importing bundles by name/url in client
* Add support for recursive parsing of Require section of `manifest.yaml`
file in client
* Add support for image download/upload from `images.lst` file in client
* Handle `package exists` error in CLI client
* Add support for different ways to import a package in murano-dashboard
* Add support for bundle-import in murano-dashboard
* Add support for image/package requirements while importing packages and
bundles in murano-dashboard
Dependencies
============
None
Testing
=======
Unit testing should be sufficient to cover most of the use cases.
However an integration test, that would setup a simple repository is very
desirable, since we add changes to both `python-muranoclient` and
`muranodashboard`.
Documentation Impact
====================
Additional capabilities of the CLI client should be documented, otherwise
there should be no impact, since we do not change the API.
References
==========
None

View File

@ -1 +0,0 @@
../template.rst

View File

@ -1,221 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
====================================
Plugable pythonic classes for Murano
====================================
https://blueprints.launchpad.net/murano/+spec/plugable-classes
One of the key features of Murano is extensibility, and we need to push this
feature even further and give our customers a way to extend Murano with new
functions (e.g. support for F5 BigIP API) in a drag-n-drop manner. This spec
proposes a solution which will add this extensibility option.
Problem description
===================
Currently all the functionality which is available to user is limited to the
features of MuranoPL language which just provides data transformation
capabilities and flow control primitives. The language itself does not contain
any functions for I/O operations, hardware access or interaction with host
operating system, other OpenStack or third-party services. This is an
intentional design feature: MuranoPL code is provided by users and cannot be
always trusted. All the external communications and low-level interactions are
done via python code which is bundled with Murano Engine and is accessible to
MuranoPL code via MuranoPL wrappers. Any interactions which are not supported
by that Python classes are impossible.
Some deployment scenarios may need to extend this set of allowed low-level
interactions. They may include some customer-specific logic, custom software
bindings etc, so trying to bundle all of them into the standard Murano Engine
classes is not a good idea. Instead, there should be a way to dynamically
add extra interactions to any existing deployment of Murano without modifying
its core components but rather with installing some plugin-like components.
Installing these plugins is supposed to be a maintainer-only operation,
requiring administrative access to nodes running Murano services. It is
supposed that the maintainer is always aware about the contents of the plugins
and is able to verify them from security, performance and other sensible points
of view.
Proposed change
===============
It is proposed to implement each extension as independent Python Package built
using setuptools library. Each package should define one or more entry-point in
a specific namespace (``io.murano.extensions`` is suggested). Each of this
entry- points should export a class, which may be registered as MuranoPL class
when the engine loads.
Each package should be installed on Murano nodes into the same Python
environment with Murano engine service.
Murano will get a PluginLoader class which will utilize stevedore library [1]
to discover classes registered as entry-points in ``io.murano.extensions``
namespace.
Murano Engine will use PluginLoader to register all the loaded plugins in its
class loader (i.e. will call ``import_class`` with a class imported from the
plugin as a parameter). As the result, the classes will become available for
the MuranoPL code being executed in the Engine.
To prevent potential name collisions, MuranoPL names for the loaded classes
will be assigned automatically: the name will consist of the namespace
(``io.murano.extensions`` as suggested above) and the name of entry-point.
To guarantee this naming rule the imported classes should not define their
MuranoPL names on their own (i.e they should not have
``@murano_class.classname`` decorators or other code which modifies their
``_murano_class_name`` field). If they do, the PluginLoader will discard
that information and will log a warning message.
As the entry-point name will eventually become a name of MuranoPL class, the
PluginLoader will validate it accordingly.
As neither stevedore nor setuptools enforce any uniqueness constraints on the
entry-point names (i.e. several packages may define entry-points with the same
name within a same namespace, and all of them will be correctly loaded by
stevedore), then this enforcement should also be done by the Murano's Plugin
Loader. If two or more plugin packages attempt to register classes with the
same endpoint name, then a warning will be logged and no classes from all the
conflicting packages will be loaded.
PluginLoader will also ensure that objects being exported in these entry-points
are indeed classes, and will check if they define a classmethod called
``init_plugin``. If such method exists, the PluginLoader will execute it before
loading it.
The plugins which are already installed in the environment may be prevented
from being loaded by a configuration option. This new option called
``enabled_plugins`` will be added to ``murano.conf``. If it has its default
value ``None`` or is omitted from the config, there will be no restriction on
the plugins which are being loaded (any plugin registered within the
environment will be loaded). If it exists and is not None, then it is expected
to contain a list of names of the packages from which the plugins will be
loaded. If the package is not mentioned there, all its endpoints will be
ignored and no classes from it will be imported. Empty value of
``enabled_plugins`` will mean that no plugins may be loaded and only bundled
system classes are accessible from the MuranoPL code.
The ``enabled_plugins`` setting will be implemented using
``EnabledExtensionManager`` class of the stevedore library [2], so the disabled
plugins will be excluded from entry-point name analysis. Thus if there are
plugins which define conflicting entry-point names, then the conflict may be
resolved with this setting instead of uninstalling the plugin from the
environment.
Currently stevedore is unable to load packages which were installed after the
start of the current process. So, in current proposal it is required to restart
Murano services after plugin package is installed, removed or upgraded and
after the changing of ``enabled_plugins`` value in configuration file.
As the restart of the services is not a good thing for production solutions, it
may be a good idea to design a "graceful restart" solution which will make the
service to stop listening for incoming requests, finish its current tasks and
then exit and restart, loading the updated configuration and plugins. However
such solution is out of scope of the current spec and is left for future
blueprints.
Alternatives
------------
Instead of using stevedore to discover and load the plugins, some home-made
solution may be invented to load Python modules from some directory. This
solution may have its benefits (e.g. it does not require restarts to load new
plugins), however stevedore is currently a de-facto standard for building
plugable solutions in Openstack, so it is suggested to use it.
Data model impact
-----------------
This proposal does not affect data model.
REST API impact
---------------
N/A
Versioning impact
-----------------
N/A
Other end user impact
---------------------
N/A
Deployer impact
---------------
The change itself does not have any immediate impact on deployer: a new
configuration option is optional and has meaningful default. However
registering new plugins will require to restart the Services, which may bring
up some concerns in production environments.
Developer impact
----------------
Developers who build their own plugins should be aware about setuptools entry-
points and should inherit their exported classes from
`murano.dsl.murano_object.MuranoObject`.
Murano-dashboard / Horizon impact
---------------------------------
No immediate changes required.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
ativelkov
Work Items
----------
* Implement the PluginLoader class
* Modify MuranoEngine to register plugin-imported classes in class loader.
Dependencies
============
This requires stevedore library as a dependency. It is already part of
OpenStack Global Requirements, so no problems are expected.
Testing
=======
The unit-tests have to cover PluginLoader class using the make_test_instance
method of stevedore.
Separated tests should cover API method call.
Tempest tests are out of the scope of this spec.
Documentation Impact
====================
There should be created a "Plugin developer's Manual" which will describe the
process of plugin package creation.
References
==========
[1] http://docs.openstack.org/developer/stevedore/
[2] http://docs.openstack.org/developer/stevedore/managers.html#enabledextensionmanager

View File

@ -1,207 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
====================================================
Policy Guided Fulfillment - Policy Enforcement Point
====================================================
URL of launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/policy-enforcement-point
Problem description
===================
As a part of policy guided fulfillment we need to implement *predeploy* policy enforcement point - i.e., Murano calls Congress to evaluate *predeploy* policy rules on data representing Murano environment being deployed. If evaluation returns *predeploy error* data (i.e., enforcement failed), then deployment of Murano environment fails.
*Predeploy* policy rules are represented by *predeploy_error(env_id, obj_id, message)* congress table.
It means
* Congress administrator is responsible for creating predeploy rules, which has this table on the left side (see examples).
* Murano is not involved in policy rule evaluation, except that Murano provides data about Murano environments. Thus user can use any data (e.g., datasource tables, policy rules) available in Congress to define when environment can be deployed.
Table *predeploy_error(env_id, obj_id, message)* reports list of found errors:
* *env_id* environment id where error was detected
* *obj_id* object id (in environment id) on which error was detected
* *message* text message of error
Murano environment serialization/decomposition is described in `Congress Support in Murano <https://blueprints.launchpad.net/murano/+spec/congress-support-in-murano>`_ and `Murano Congress Driver <https://blueprints.launchpad.net/congress/+spec/murano-driver>`_
Example (generic):
::
predeploy_error(env_id, obj_id, message) :-
murano:state(env_id,"PENDING"),
my-rule-table1(env_id, obj_id),
concat("", "some error message 1", message)
predeploy_error(env_id, obj_id, message) :-
murano:state(env_id,"PENDING"),
my-rule-table2(env_id, obj_id),
concat("", "some error message 2", message)
my-rule-table1(env_id, obj_id) :- ....
my-rule-table2(env_id, obj_id) :- ....
Example (allow only environments where all VM instances has flavor with max 2048MB RAM):
::
predeploy_error(eid, oid, msg) :-
murano:object(oid, eid, type),
checkIfError(oid),
concat("", "Instance flavor has RAM size over 2048MB", msg)
checkIfError(oid) :-
murano:parent_type(oid, "io.murano.resources.Instance"),
murano:property(oid, "flavor", fname),
nova:flavors(i,fname,v,r,d,e,rx),
gt(r,2048)
Enforcement point will use Congress simulation api to evaluate rules on passed mapped environment into Congress schema.
Proposed change
===============
When user executes *deploy* action on an environment following steps will be done
* environment will be mapped into *update sequence*
* Congress simulation API will be executed:
::
openstack congress policy simulate murano_system 'predeploy-error(envId, objId, message)' 'env+(1000,"myEnv") obj+(1,1000,"VM") prop+(100,1,"name", "vm1") prop+(101,1,"image", "ubuntulinuximg") obj+(2,1000,"Tomcat") prop+(110,2,"name", "tomcat") prop+(111,2,"port", 8080) rel+(200,2,1, "instance") ' action
* if response will contain non empty result, then deployment will fails
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
Environment deployment may fail due to policy validation failure.
Deployer impact
---------------
Policy enforcement will be used only if
* Enforcement is enabled in *murano.conf*
* Congress is available in Keystone catalog (i.e., it is deployed in OpenStack)
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
ondrej-vojta
Other contributors:
filip-blaha, radek-pospisil
Work Items
----------
1. Use implementation of *Congress Support in Murano* in order to implement policy enforcement point as advised by Stan (see below). The Congress support must correctly deal with following setups
* Openstack with Congress installed
* Openstack without Congress
::
Stan: such approach makes PolicyEnforces (and thus dependency on Congress) be mandatory for Murano. Better approach for now could be just insert
at https://github.com/stackforge/murano/blob/master/murano/common/engine.py#L112
something like
if config.CONF.enable_policy_enforcer:
policyenforcer.validate(self.model)
2. Provide Developer and User Documentation (see Documentation section).
Dependencies
============
* *Congress Support in Murano* https://blueprints.launchpad.net/congress/+spec/murano-driver
* *Murano datasource driver* in Congress https://blueprints.launchpad.net/congress/+spec/murano-driver
* *Policy enforcement specification* https://etherpad.openstack.org/p/policy-congress-murano-spec
Testing
=======
Unit and integration tests must be done.
Integration tests must cover following setups
* Openstack has Congress installed
* situations when Congress is running (i.e., responding) and not running (i.e., not responding) must be tested
* Openstack has not Congress installed
Documentation Impact
====================
Policy enforcement must be documented from following perspectives
* Setup configuration (e.g., with and without congress)
* Murano rules (i.e., Murano environment data decompositiion) in Murano policy
* How Murano policy affects environment deployment
Following Murano documentation will be affected
* Murano Installation Guide
Add section on Congress requirement and section on enabling policy enforcement
* Murano Workflow
Add section on Murano policy enforcement
* Murano Article (new)
Article on Murano policy rules (e.g., Murano environment decomposition to Congress)
References
==========
* *Congress Support in Murano* https://blueprints.launchpad.net/congress/+spec/murano-driver
* *Murano datasource driver* in Congress https://blueprints.launchpad.net/congress/+spec/murano-driver
* *Policy enforcement specification* https://etherpad.openstack.org/p/policy-congress-murano-spec

View File

@ -1,215 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=================================
Add support for heat environments
=================================
https://blueprints.launchpad.net/murano/+spec/add-support-for-heat-environments-and-files
Add support for using Heat environments, when saving and deploying Heat
templates.
Problem description
===================
Today there is no option to create stacks neither with an environment nor with
nested stacks via Murano. Only basic stacks are supported.
Use cases for deploying a stack with an environment:
* Supporting resource registry
* Supporting saving 'test' and 'production' parameter profiles for the same
template
Proposed change
===============
The change described here will focus on supporting Heat environments. Another
spec was submitted for Heat files.
In this spec no UI changes are included. A UI part that can be added in future
specs, and in any case is out of the scope of this spec.
Allowing Heat environments to be saved and deployed as part of a Murano Heat
package. Adding environments to a package should be optional. Heat environment
files should be placed in the package under '/Resources/HotEnvironments' When a
user request to add a Heat-generated package to a Murano environment, he should
have an option to specify one of the hot-environment-files located at
'/Resources/HotEnvironments' in the package, and this heat environment file
should be sent to Heat with the template during Murano environment deployment.
If no heat environment file was specified, the template will be deployed
without a Heat environment.
The stage where the Heat environment for the deployment should be specified
is when adding a package to a Murano environment as part of a configuration
session.
The heat environment should be referenced by name.
In the future, there can be an API to list the hot environments of a package.
This might be done by using the existing API of getting the UI of a package.
Alternatives
------------
* The package structure can be different.
* Words that can replace the word environments to reference heat environments:
configurations, profiles, settings. The problem is that in Heat they use the
word environments.
* Specifying the heat environment to be deployed with the Heat template as
part of a Murano environment when deploying the environment (instead of
specifying it when adding a package to an environment). If we will wait to
this point, we will have to give a map of packages and the environments to be
deployed with them. this alternative requires more validations.
Data model impact
-----------------
new data objects:
* hotEnvironment - This parameter will be passed as part of the
/environments/{env-id}/services POST API request body. The value of this
parameter will be an environment file name.
* templateParameters - All heat parameters that were passed in the root of the
/environments/{env-id}/services POST API request body, will be moved under
this property.
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
User will now have the option to add heat environments and additional files to
the package, and have them deployed with the package as part of the Murano
environment. The Heat environment will be deployed when it is requested in the
relevant API, while the additional files will always be deployed.
At this point there will be no change in the python-muranoclient. If the user
will wish to add environments or additional files to a heat generated package.
He can edit the package and continue via API. If the user only added additional
files, he can continue via python-muranoclient/UI as well.
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
New features must not break UI. So since it was proposed to move the user
defined parameters from the root of the request body to the property
"templateParameters", the UI must change the way it build the request to add a
package to a Murano environment.
The new feature for sending a hot environment with the template will be exposed
in the UI the following way:
The user will be able to choose an environment file from a drop-down list
during the same wizard actions he uses to enter heat template parameters.
Implementation
==============
new data objects:
* envs
* env_name
envs will be generated when parsing the package, so if there is nothing in the
package, the new data objects will be empty. If an API to list the environments
will be implemented an empty list will return, same as in other Murano APIs.
A new object called envs of type dictionary will be added in HeatStack class
in the init method. It can be referenced from inside HeatStack by using
self._envs before/when sending the create request to Heat. This object will be
initialized to be empty.
A new method called setEnvs will be added in HeatStack class. It will allow to
enter a value into _envs just like setParameters allows to enter values into
_parameters.
env_name will take the value passed by the user in the parameter
heatEnvironment. It will be initialized and passed to class HeatStack the same
way parameters are passed today.
When sending the create stack request to heat the selected environment content
should be passed. If all is configured and passed correctly the environment
file content can be accessed from class HeatStack by using the next command:
self._envs[self._env_name]
A new method called _translate_envs will be add to HotPackage class. it will
get a path to the envs directory and will return a dictionary of environments
locations and files values. It will be in the next format:
environmentRelativePathStartingHeatEnvironmentsDirectory -> stringFileContent
For example if there is an environment with a full path of
/Resources/HeatEnvironments/my_heat_env.yaml and content of:
"heat_template_version: 2013-05-23\n\nparameters:\n" and it
is the only file in the folder, than this will be the dictionary returned:
{"my_heat_env.yaml": "heat_template_version: 2013-05-23\n\nparameters:\n"}
A very similar function was proposed for the Heat files feature. There will be
a reuse of the code there, if it will be implemented first.
Assignee(s)
-----------
Primary assignee:
michal-gershenzon
Other contributors:
noa-koffman
Work Items
----------
* Add support for adding a package to a Murano environment with a Heat
environment specified in the request.
* Add support for Heat environments when deploying a Murano environment. If
a Heat environment is saved in the session for the package, it should be
parsed and send with the template, when deploying a Murano environment.
* make sure that when ui generate a POST request for API:
/environments/{env-id}/services the user defined parameters are located under
templateParameters in the request body.
Dependencies
============
None
Testing
=======
Unit tests should cover API calls changes:
* Test sending a Heat environment when adding a package to a Murano environment
(positive and negative).
* Test that the request for Heat is build correctly with Heat environment
Documentation Impact
====================
None
References
==========
* http://docs.openstack.org/developer/heat/template_guide/environment.html

View File

@ -1,168 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
===========================================
Add support for heat environments and files
===========================================
https://blueprints.launchpad.net/murano/+spec/add-support-for-heat-environments-and-files
Add support for using Heat additional files, when saving and deploying Heat
templates.
Problem description
===================
Today there is no option to create stacks neither with an environment nor with
nested stacks via Murano. Only basic stacks are supported.
Use cases for deploying a stack with additional files:
* Supporting Heat nested stacks
* Supporting scripts
For more information see references section of this spec
Proposed change
===============
The change described here will focus on supporting additional files. Another
spec will be submitted for Heat environments.
Allowing Heat additional files to be saved and deployed as part of a Murano
Heat applications. Adding additional files to a package should be optional.
Such files should be placed in the package under '/Resources/HeatFiles'. When a
Heat generated package is being deployed, if the package contains Heat files,
they should be sent to Heat together with the template and params. If there are
any Heat additional files located in the package under '/Resources/HeatFiles',
they should all be sent with the template during stack creation in Heat.
There can be more nested directories under '/Resources/HeatFiles', and if they
have files in them, those should be send to heat as well together with their
relative path.
This part does not require any UI nor API changes.
Alternatives
------------
* The package structure can be different.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
User will have the option to add Heat files to the package, and have them
deployed with the package as part of the Murano environment.
At this point there will be no change in the python-muranoclient. If the user
will wish to add files to a heat generated package, he can edit the package and
continue normally from there.
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None.
Implementation
==============
new data objects:
* files
This new data object will be generated when parsing the package, so if there
is nothing in the package, the new data objects will be empty.
A new object called files of type dictionary will be added in HeatStack class
in the init method. It can be referenced from inside HeatStack by using
self._files when sending the create request to Heat. This object will be
initialized to be empty.
A new method called setFiles will be added in HeatStack class. It will allow to
enter a value into _files just like setParameters allows to enter values into
_parameters.
A new method called _translate_files will be add to HotPackage class. it will
get a path to the files directory and will return a dictionary of files
locations and files values. It will be in the next format:
fileRelativePathStartingHeatFilesDirectory -> stringFileContent
For example if there is a file with a full path of
/Resources/HeatFiles/my_heat_file.yaml and content of "echo hello world" and it
is the only file in the folder, than this will be the dictionary returned:
{"my_heat_file.yaml": "echo hello world"}
A new parameter of called files will be added to _generate_workflow method that
can be found inside HotPackage class. It will be included in the deploy
variable in the same way the template_parameters is included.
Assignee(s)
-----------
Primary assignee:
michal-gershenzon
Other contributors:
noa-koffman
Work Items
----------
* Add support for Heat additional-files. If such files exist in the package,
they should be parsed and send with the template, when deploying a Murano
environment.
Dependencies
============
None
Testing
=======
Unit tests should cover API calls changes:
* Test that the request for Heat is build correctly with Heat files
Documentation Impact
====================
None
References
==========
* http://docs.openstack.org/developer/heat/template_guide/hot_spec.html#get-file

View File

@ -1,214 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
===========================
Artifact Repository Support
===========================
https://blueprints.launchpad.net/murano/+spec/artifact-repository-support
Glance has recently got a new feature - ability to store not only the VM images
but also data assets and their metadata for other OpenStack projects.
This specification defines the usage of this feature in Murano, so Murano may
store its packages in Glance and benefit from all its features.
Problem description
===================
The current implementation of Murano Package Repository as part of murano-api
has the following major drawbacks:
* Code duplication. Lot's of the logic to manage the packages is very similar
for other OpenStack projects. Sharing that code with others will help to
improve the overall quality of OpenStack ecosystem.
* Database storage is a bad idea. Currently we store all the murano-packages as
blob fields in the database tables. This dramatically decreases the
performance and limits the maximum size of the packages, thus preventing us
from putting actual application binaries inside the packages. Using glance
for this purpose will allow us to utilize all the backing stores supported by
glance, including Swift, Ceph, S3 and others.
* No cross-package dependencies. Current implementation of package repository
does not have any concept of cross-package dependency, so MuranoPL package
loaders have to detect package dependencies only in runtime. This leads to
issues when some of the package's dependencies are not present in the repo,
but this cannot be detected until the actual deployment starts. Using glance
which has a notion of cross-artifact dependencies solves this issue natively
at the repository level.
* Image dependencies are manual. Current implementation has some manual way of
managing dependencies of murano packages to glance images. When glance is
user dependencies on Images will have the same nature as cross-package
dependencies.
* No versioning of packages. Current implementation does not allow to attach
semver-based version strings to the packages, and so no filtering is possible
by this info. Glance Artifact Repository provides a rich versioning tools and
allows to filter by specific version spec and range.
* No ability to query packages based on dependency hierarchy. We need a way to
query the repository for the classes which inherit some specific base class.
Glance Artifact Repository provides such queries out of the box.
Proposed change
===============
It is proposed to create a Glance Plugin which will define the artifact type
"Murano Package" with the following type-specific metadata attributes:
* **type** - a string defining the type of the package, may have values of
either `Application` or `Library`. Immutable. Required.
* **author** - a string defining the author of the package. Immutable.
Required.
* **display_name** - a display name for the package to be shown in the catalog.
Mutable. Required.
* **enabled** - a boolean indicating if that package is available for usage.
Proposed temporary, until Glance v3 has a support of "disable" operation for
all the types of artifacts. Mutable, True by default.
* **categories** - a set of strings containing the categories attached to the
package. Mutable.
* **class_definitions** - a set of strings containing the fully-qualified names
of muranoPL classes contained within the package. Immutable.
* **inherits** - a dictionary in which the keys are the interfaces inherited by
the classes of the packages and the values are the list of the names of these
classes. Immutable.
* **keywords** - a set of keywords to simplify the search of the package in the
catalog. Mutable.
..and the following binary objects:
* **logo** - a blob containing the logo of a package
* **archive** - a blob containing the zip archive with the package
* **ui_definition** - a blob containing the yaml-based definition of app's UI
if the one is present.
If worth noting that currently v3 of Glance API is tagged as EXPERIMENTAL, and
both its implementation and interfaces may (and will) change in Mitaka release
cycle. So, some of the plugin implementation details may have to be changed as
well in the next cycle.
Because of this, it is suggested to add this functionality as EXPERIMENTAL as
well, maintaining the old behavior as a preferred alternative, selected by
default.
Alternatives
------------
We may continue using murano-api to manage our packages, at least till the
Glance v3 is STABLE, however this will require us to introduce lots of
temporary code to support things like versioning and dependencies. So, it is
better to add the Glance support as an experimental feature, facade it under
the python-muranoclient bindings, and migrate to it completely in the next
release cycle.
Data model impact
-----------------
No impact. When the migration is complete and Glance is the only storage of
packages, we'll need to drop the old data tables which are currently storing
the old package repositories.
REST API impact
---------------
No impact.
Versioning impact
-----------------
No impact.
Other end user impact
---------------------
No impact.
Deployer impact
---------------
The deployer will have to add the glance plugin package into their environment.
It should be deployed into the same python env with the regular Glance. They'll
have to enable the V3 API in the glance-api config as well.
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
Only the configuration changes should be made in murano-dashboard.
Implementation
==============
Assignee(s)
-----------
Primary assignee: ativelkov
Work Items
----------
* Implement a glance plugin
* Copy the artifact-specific access logic from python-glanceclient into the
python-muranoclient, as glance is not going to release v3-aware clients until
the API is stable.
* Implement artifacts adapter in python-muranoclient
Dependencies
============
* Most of the artifacts functionality has been merged to Glance by L-1
milestone. However, several important bugfixes were merged only into the RC1.
So, the latest Glance master is required.
Testing
=======
As the new backend substitutes the old one, the regular testing of
package-related actions should be sufficient.
Documentation Impact
====================
New configuration settings have to be documented.
References
==========
None

View File

@ -1,139 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=================================================================
Download bundle of packages to local directory using muranoclient
=================================================================
https://blueprints.launchpad.net/murano/+spec/bundle-save
The purpose is to add command to muranoclient which allows to download the
bundle from application catalog to local dir.
Problem description
===================
There are cases when there is no Internet access cloud with murano installed.
Then if user wants to add some bundle of packages into murano, he has to
download all of them one-by-one from application catalog using local computer
with access to the Internet. After that he saves them somewhere on data storage
device and moves all files to cloud.
It is necessary to simplify process of saving packages to avoid manual
downloading.
Proposed change
===============
It's proposed to add new CLI command *bundle-save* to murano-client.
Method *do_bundle_save* will corresponds with new command. It will take three
arguments:
* *filename* is a bundle name, bundle url or path to the bundle file;
* *--path* (optional) is a path to directory in which user wants save packages.
If it is not specified, current directory will be used;
* *--no-images* (optional) is flag. If it is set, downloading of all required
images will be skipped.
Method will build whole list of packages and its dependencies. This ability is
already implemented and used in 'bundle-import'. Then method will save bundle
file and each package to specified path. For this, method 'save' will be added
to *FileWrapperMixin* -- the parent class for *Bundle* and *Package* classes.
This method will take one argument *dst* -- destination for file. It will copy
already downloaded file to the specified path.
Method *do_bundle_save* will also save images which packages require.
*save_image_local* method will be used for that. All images will be downloaded
if *--no-images* is not set.
After bundle saving directory with packages can be moved to lab with murano
where all of them can be imported to murano application catalog in one
command.
CLI command *package-save* also must be implemented. It will give to user the
opportunity to download specific package or several packages he need.
The implementation of command will be based on the methods described above.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
User will have access to a new command.
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Dmytro Dovbii
Primary assignee:
ddovbii
Work Items
----------
* Add method *save_image_local*
* Add method *save()* to *FileWrapperMixin* class
* Implement CLI command *bundle-save*
* Implement CLI commamd *package-save*
Dependencies
============
None
Testing
=======
Unit tests for CLI client must be updated
Documentation Impact
====================
CLI reference should be updated manually
References
==========
None

View File

@ -1,158 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=================================
Rework package class loader logic
=================================
https://blueprints.launchpad.net/murano/+spec/change-murano-class-loader
This spec describes rework of murano package class loader as part of the
another blueprint `simulated-execution-mode-murano-engine
<https://blueprints.launchpad.net/murano/+spec/simulated-execution-mode-murano-engine>`_.
The detailed logic regarding class modification would be described in this
specification.
Problem description
===================
Class loader should be able to load packages not only from the external
repository, but from a local directory. It's needed not only for testing new
packages, but for accepting packages on-the-fly.
During the development phase the package gets frequently updated, and the need
to upload it to the repository on each update complicates the development.
Ability to load it from the local filesystem will streamline the process
Another case, when there is no connection to the external repository.
Proposed change
===============
Need to create one more class, responsible for loading packages.
It will look up at the provided directory for a package, that name was requested.
It worth noting, that packages should not be zipped.
Class loader from repository (RCL) and new class loader from local dir (LCL)
will provide the following logic:
* If local dir is not provided, LCL is not operating.
Logic stays same as it's now. RCL do all the work.
* If directory path or several paths to load local packages from are provided,
LCL will check all packages in dir and compare with requested name.
If the desired class is found, package gets loaded. If not - next dir in the
provided list will be scaned.
If is not found in all the provided directories - RCL sends API call to find
it in the repository as usual.
We do have both class loader implemented, we need an ability to combine two
(or more) package loaders in one, with the ability to prioritize the queries.
For example, a ``CombinedPackageLoader`` may be created with an instances of
``DirectoryPackageLoader`` and ``ApiPackageLoader`` underneath. When a
request for a package or class comes in, it is first executed against loader
with the highest priority (say, ``DirectoryPackageLoader``), and if it is not
found there, then goes to the next one.
Alternatives
------------
Use separate class loader in test framework.
But support two different class loaders is not good.
Also as an alternative we can also mention
`this <https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-TEMPLATE_LOADERS>`_
approach.
That is: introduce package_loaders config parameter. It can be a list of
python-dot-notation class names, that murano would import and try to import pkg
from each loader. This could further be modified to a list of lists, to allow params
like this:
`package_loaders: [pkg_loader1, [pkg_loader2, param1, param2]]`
This would allow to easily add custom loaders without changing murano code itself.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
Enabling loading packages from local directory will be set up in config file.
New key in config file will be added under *[engine]* section and look
like that:
# Directory used as a way to load packages from. (string value)
# local_packages_dir = <None>
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
<efedorova>
Other contributors:
<ativelkov>, <slagun>
Work Items
----------
* Implement ``CombinedPackageLoader``:
* Perform testing
Dependencies
============
* Murano Simulation Mode:
https://blueprints.launchpad.net/murano/+spec/simulated-execution-mode-murano-engine
Testing
=======
Unit tests should be added/updated.
Documentation Impact
====================
Opportunity to load apps from local directory should be described in the
documentation.
References
==========
None

View File

@ -1,396 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==========================================
Implement Cloud Foundry Service Broker API
==========================================
https://blueprints.launchpad.net/murano/+spec/cloudfoundry-api-support
Cloud Foundry is PaaS which supports full lifecycle from initial development,
through all testing stages, to deployment. Most well known Cloud Foundry
flavours is Cloud Foundry OSS, Pivotal Cloud Foundry and Pivotal Web Services.
If we implement Cloud Foundry Service Broker API in murano, murano apps will
be available at Cloud Foundry as services. So Cloud Foundry users will be
granted an ability to operate murano applications.
Problem description
===================
Typical scenario of Cloud Foundry and murano collaboration will look like:
1. While configuring murano enable murano service broker in config file. Provide
host and port for it.
2. Add murano Service Broker in Cloud Foundry and grant access to murano apps for
Cloud Foundry organization.
3. Provision murano app as Cloud Foundry service instance using Cloud Foundry tools.
Proposed change
===============
We need to write Cloud Foundry Service Broker implementation for murano. One of
the parts of this implementation should be some mapping function between Cloud
Foundry and OpenStack resources. Now it's planned to map Cloud Foundry
Organizations to OpenStack tenants and Cloud Foundry spaces to murano
environments. So, all tenant users will be granted with the privileges based on
their existing roles in OpenStack tenant. Each Cloud Foundry space will be linked
wih murano environment. The parameters which is needed to murano for successful
application deployment will store in service object section parameters. The
Service Broker itself will parse them as soon as Cloud Foundry can't do it.
It will be parsed during Provision request. The request body will look like that:
.. code-block:: javascript
{
"service_id": "service-guid-here",
"plan_id": "plan-guid-here",
"organization_guid": "org-guid-here",
"space_guid": "space-guid-here",
"parameters":{
"parameter1": 1,
"parameter2": "value"
}
}
It's planned to setup a Service Broker as a separate service. Additional
options should be added to the configs. Also we want to use Cloud Foundry
experimental asynchronous operations[3].
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
No existing API of murano service is going to be changed. New service will be
created implementing the standard Cloud Foundry Service Broker API. Its API
methods are as follows:
**GET /v2/catalog**
*Request*
+----------+----------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==================================+==================================+
| GET | /v2/catalog | List all available apps |
+----------+----------------------------------+----------------------------------+
*Parameters:*
* None
*Response*
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. The expected resource body as below |
+----------------+-----------------------------------------------------------+
::
{
"services": [{
"id": "service-guid-here",
"name": "mysql",
"description": "A MySQL-compatible relational database",
"bindable": true,
"plans": [{
"id": "plan1-guid-here",
"name": "small",
"description": "A small shared database with 100mb storage quota and 10 connections"
},{
"id": "plan2-guid-here",
"name": "large",
"description": "A large dedicated database with 10GB storage quota, 512MB of RAM, and 100 connections",
"free": false
}],
"dashboard_client": {
"id": "client-id-1",
"secret": "secret-1",
"redirect_uri": "https://dashboard.service.com"
}
}]
}
**PUT /v2/service_instances/:instance_id?accepts_incomplete=true**
*Request*
+----------+-----------------------------------------------------------+-------------------------------------------+
| Method | URI | Description |
+==========+===========================================================+===========================================+
| PUT | /v2/service_instances/:instance_id?accepts_incomplete=true| Create new service resources for developer|
+----------+-----------------------------------------------------------+-------------------------------------------+
::
{
"service_id": "service-guid-here",
"plan_id": "plan-guid-here",
"organization_guid": "org-guid-here",
"space_guid": "space-guid-here"
}
*Response*
+----------------+------------------------------------------------------------+
| Code | Description |
+================+============================================================+
| | OK. May be returned if the service instance already exists |
| 200 | and the requested parameters are identical to the existing |
| | service instance. |
+----------------+------------------------------------------------------------+
| 202 | Accepted. Service instance creation is in progress. |
+----------------+------------------------------------------------------------+
| 409 | Conflict. Should be returned if the requested service |
| | instance already exists. The expected response body is “{}”|
+----------------+------------------------------------------------------------+
| 422 | Should be returned if the request did not include |
| | ?accepts_incomplete=true |
+----------------+------------------------------------------------------------+
::
{
"dashboard_url": "http://example-dashboard.com/9189kdfsk0vfnku"
}
**PATCH /v2/service_instances/:instance_id?accepts_incomplete=true**
*Request*
+----------+-----------------------------------------------------------+----------------------------------+
| Method | URI | Description |
+==========+===========================================================+==================================+
| PATCH | /v2/service_instances/:instance_id?accepts_incomplete=true| Update existing service instance |
+----------+-----------------------------------------------------------+----------------------------------+
::
{
"plan_id": "plan_guid_here"
}
*Response*
+----------------+------------------------------------------------------------+
| Code | Description |
+================+============================================================+
| 200 | Return if only the new plan matches the old one completely |
+----------------+------------------------------------------------------------+
| 202 | Accepted. Service instance update is in progress. |
+----------------+------------------------------------------------------------+
| 422 | Should be returned if the request did not include |
| | ?accepts_incomplete=true |
+----------------+------------------------------------------------------------+
**DELETE /v2/service_instances/:instance_id?accepts_incomplete=true**
+----------+-----------------------------------------------------------+-----------------------------------+
| Method | URI | Description |
+==========+===========================================================+===================================+
| DELETE | /v2/service_instances/:instance_id?accepts_incomplete=true| Delete all resources create during|
| | | the provision. |
+----------+-----------------------------------------------------------+-----------------------------------+
*Response*
+----------+--------------------------------------------------+
| Code | Description |
+==========+==================================================+
| 202 | Accepted. Service instance deletion in progress. |
+----------+--------------------------------------------------+
| 410 | Returned if service does not exist |
+----------+--------------------------------------------------+
| 422 | Should be returned if the request did not include|
| | ?accepts_incomplete=true |
+----------+--------------------------------------------------+
**PUT /v2/service_instances/:instance_id/service_bindings/:binding_id**
*Request*
+----------+----------------------------------------------------------------+----------------------------------+
| Method | URI | Description |
+==========+================================================================+==================================+
| PUT | /v2/service_instances/:instance_id/service_bindings/:binding_id| Bind service |
+----------+----------------------------------------------------------------+----------------------------------+
::
{
"plan_id": "plan_guid_here",
"service_id": "service_guid_here",
"app_guid": "app_guid_here"
}
*Response*
+----------------+------------------------------------------------------------------+
| Code | Description |
+================+==================================================================+
| 201 | Binding has been created. The expected response body is below. |
+----------------+------------------------------------------------------------------+
| 200 | May be returned if the binding already exists and the requested |
| | parameters are identical to the existing binding. The expected |
| | response body is below. |
+----------------+------------------------------------------------------------------+
| 409 | Should be returned if the requested binding already exists. The |
| | expected response. body is `{}`, though the description field can|
| | be used to return a user-factorin error message. |
+----------------+------------------------------------------------------------------+
::
{
"credentials": {
"uri": "mysql://mysqluser:pass@mysqlhost:3306/dbname",
"username": "mysqluser",
"password": "pass",
"host": "mysqlhost",
"port": 3306,
"database": "dbname"
}
}
**DELETE /v2/service_instances/:instance_id/service_bindings/:binding_id**
*Request*
+----------+----------------------------------------------------------------+----------------------------------+
| Method | URI | Description |
+==========+================================================================+==================================+
| DELETE | /v2/service_instances/:instance_id/service_bindings/:binding_id| Unbind service |
+----------+----------------------------------------------------------------+----------------------------------+
*Response*
+----------+-----------------------------------+
| Code | Description |
+==========+===================================+
| 200 | Binding was deleted |
+----------+-----------------------------------+
| 410 | Returned if binding does not exist|
+----------+-----------------------------------+
**GET /v2/service_instances/:instance_id/last_operation**
*Request*
+----------+--------------------------------------------------+-------------------------------+
| Method | URI | Description |
+==========+==================================================+===============================+
| GET | /v2/service_instances/:instance_id/last_operation| Polling status of the last 202|
| | | operation |
+----------+--------------------------------------------------+-------------------------------+
*Response*
+----------+--------------------------------------------------------+
| Code | Description |
+==========+========================================================+
| 200 | OK |
+----------+--------------------------------------------------------+
| 410 | GONE. Appropriate only for asynchronous delete requests|
| | Cloud Foundry will consider this response a success and|
| | remove the resource from its database. |
+----------+--------------------------------------------------------+
::
{
"state": "in progress",
"description": "Creating service (10% complete)."
}
Versioning impact
-------------------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
Service Broker should be deployed and enabled in the murano config.
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
starodubcevna
Work Items
----------
Changes can be split to this parts:
* Implement the stub of Service Broker itself. Add needed config opts and starting point.
* Implement basic Cloud Foundry API calls such as list and provision. Also on this step we
should add murano specific API calls.
* Series of extensions for Cloud Foundry API support:
* Add update and deprovision API calls
* Add bind/unbind API calls
Dependencies
============
None
Testing
=======
Unit tests should cover new API calls.
Documentation Impact
====================
Document "Murano and Cloud Foundry HowTo". It should be step by step guide for
Cloud Foundry and murano cooperation.
References
==========
[1] https://youtu.be/ezq9P1WN2LY
[2] http://docs.cloudfoundry.org/services/api.html
[3] https://docs.cloudfoundry.org/services/asynchronous-operations.html

View File

@ -1,146 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
============================================================
Remove name field from fields and object model in dynamic UI
============================================================
https://blueprints.launchpad.net/murano/+spec/dynamic-ui-specify-no-explicit-name-field
Now name is a required parameter in every single form definition.
But murano-engine doesn't know anything about this parameter. It mostly used
for dymanic UI purposes. So we can insert this field automatically in every
form.
Problem description
===================
* 'name' property has no built-in predefined meaning for MuranoPL classes
or applications.
Now all unknown parameters are ignored, but the error will be spawned and
all applications will be invalid in the near future.
To prevent global failure this change is suggested.
Proposed change
===============
Add automatic field inserting into the first form and store 'name' field value
in object header:
* Dynamic UI version will be increased to 2.1;
* 'name' property is not required in MuranoPL class definition anymore.
If user still have 'name' property in class definition, he should supply
corresponding field in UI definition. It will have no special meaning for
murano dashboard.
* New field will be inserted to the first form if Dymanic UI version is higher
or equal to 2.1;
* If Dymanic UI version is higher or equal to 2.1 'name' field value will be
placed to the object header ('?'), in "done" method of application creation
wizard;
* In get-mode, application 'name' parameter will be checked in:
* Primary under '?' parameter;
* Secondary in the object model root;
* Add new YAQL function to dashboard's YAQL to be used by dynamic UI.
The function will be called 'name' and will allow to use
automatically-inserted name field in object model description.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
This change introduces new version of dynamic UI form definition.
Only backward compatibility will be supported: new dashboard can work with old engine.
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
This spec is supposed to be implemented in murano-dashboard only.
User will see new field for adding app name.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
<efedorova@mirantis.com>
Work Items
----------
* Implement automatic 'name' field insertion if version satisfies the requirements;
* Put 'name' field value to the object header area;
* Use 'name' attribute from object header or inside object modal root
in environments table;
* Implement new YAQL function, which returns applications name.
Dependencies
============
This change is a dependency for a future changes in engine
Testing
=======
CI tests should be updated and catch all errors.
Documentation Impact
====================
Dynamic UI form definition examples should be updated
References
==========
None

View File

@ -1,237 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
===============================
Configure environments from CLI
===============================
Blueprint for this specification:
https://blueprints.launchpad.net/python-muranoclient/+spec/env-configuration-from-cli
Currently there is no way to configure and/or deploy a murano environment from
the command line. This specification describes how this issue can be addressed
and what steps have to be taken in order to implement this abilities.
Problem description
===================
Currently the only possible way to deploy a murano environment is through
interaction with horizon. CLI client currently lacks commands to add apps to
environment or deploy an environment. This makes murano useless without horizon
and murano-dashboard.
It also means, that scripting and/or automating deployment of murano
apps/environments is currently problematic to say the least.
Proposed change
===============
This spec proposes to add several new CLI commands and modify existing to
allow user to add apps to the env, configure it and send it to deploy.
Command ``environment-create`` currently only supports adding the name of the
environment, while the api call supports setting aditional params, such as
defaultNetworks. ``environment-create`` should be updated to allow setting
custom keys to environment model.
``environment-edit`` command should perform all the editing (adding, deleting,
modifying of existing apps)
This command should be non-interctive, adding an interactive mode is a
good idea as of itself, but is out of scope of this spec.
``environment-edit`` would use jsonpatch format for input (as described by
RFC 6902). This is a well known and powerfull instrument to manipulate json,
and object model is currently stored in json.
This would allow easy addition, modification and deletion of apps.
Editing of environment attributes is not allowed by API, so it's beyond the
scope of this spec.
During command execution, env configuration parameters should be read from
stdin or a file.
Supporting stdin as input source means it should be possible to issue a
command like ``murano environment-edit env_id < app_patch.json``
An example ``app_patch.json`` might look like::
[
{ "op": "add", "path": "/services/-",
"value":
{'?':
{'id': '2fc3005d-b4f8-420d-9e15-f961b41f49ee',
'type': 'io.murano.apps.App1'
},
'instance':
{'?': {'id': '53366263-04e9-49d1-829d-50e27158749c',
'type': 'io.murano.resources.LinuxMuranoInstance'},
'assignFloatingIp': True,
'availabilityZone': 'nova',
'flavor': 'm1.medium',
'image': 'afc1aa61-f623-4c66-bbd8-5359261c5272',
'name': 'ilphvibwqyu6h1' },
'name': 'App1'
}
},
]
All operations would only apply to services field, so the `/services/` part of
the path can be ommitted.
note::
This means, that a user has to generate unique ids. This can be a difficult
task and may hinder scripting capabilities. We might think of a way to
mitigate this issue, by introducing a way to generate ids. This can be done
by introducing an optional parameter ``--id-format``. It would accept a
template for strings to be replaced with generated ids. For example:
``--id-format=##id##`` would replace all occurrences of ##id##-1 with fist
generated id, all occurrences of ##id##-2 with second generated id and all
occurrences of ##id## with a unique id. uuids should be used for id
generation.
Command should perform validation of its input. This can be done using
MuranoPL classes and property contracts.
If an error happens during non-interactive mode (for example validation fails
for some field) ``murano`` should return a non-zero status, to facilitate
scipting and error-detecting.
Command ``environment-edit`` should support optional ``--session`` parameter,
that allows user to specify a session for editing an environment.
It should also
warn user in case more than one session is open. If the session parameter is
omitted: last open session for given environment is used.
If there are no open sessions — a new session would be opened.
note::
This means that to deploy a simple application one has to know jsonpatch
syntax. We might think about optional `syntax sugar` commands, that would
allow adding a single app to the environment. These would use predefined
jsonpatch patch documents and would accept only value to be added to
/Objects/services/- path.
We should implement session controlling commands during
implementation of this spec, for example:
#. ``session-list`` Show list of open sessions for a given environment.
#. ``session-show`` Show details of currently configured session..
#. ``session-delete`` Discard an open session for a given environment.
In case an error occurs during environment deployment this would allow to
rollback the changes to the previous version of environment.
This should also allow to handle cases, when a single environment is edited
simultaneously by different users.
``environment-action`` command should be implemented to allow performing
actions against an environment. One example of actions is a deploy action, so
``murano environment-action deploy`` should deploy the environment.
Alternatives
------------
Alternatively we can implement an interactive mode, that would mimic current
dashboard behaviour. This would not allow scripting, but would allow us to
build a more user-friendly CLI interface. The dowside is that current UI
definitions are scheduled to be changed and would most likely be replaced in
the forseable future. This means, that most of the work would go to waste.
Data model impact
-----------------
None
REST API impact
---------------
None, CLI should reuse API calls, already used by dashboard
Versioning impact
-------------------------
Since we're adding functionality — None
Other end user impact
---------------------
None
Deployer impact
---------------
It is possible that implementation of this spec would require setting and
reading intermediate environment variables to work correctly with sessions,
during app addition, env deployment.
Overall deployment of murano would not be affected.
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
<kzaitsev>
Work Items
----------
#. ``environment-edit`` command
(should create session, check permissions, add
patch resulting model into ).
#. Input validation for ``envieonment-edit``
(request packages from API, check ID
uniqueness, check input field adequacy).
#. (optional) ``--format-id`` option support
#. (optional) syntax sugar command, that would allow easy addition of a package
to an environment.
#. Session controlling commands.
#. ``environment-action`` command.
#. Shell unit tests.
#. Integration tests.
Dependencies
============
None
Testing
=======
We shall need Unit tests for new commands introduced.
Also, since this change introduces a way to deploy an env from CLI. This means
that integration tests for murano client should be implemented. A typical test
should upload and app, configure a simple environment with 1-2 apps and set
some custom parameters, like access port and optionally deploy the env in
question. This tests should probably take place in murano-ci.
Documentation Impact
====================
New python-muranoclient commands would have to get a proper documentation. It's
also possible, that we would want to document the whole process of deploying an
app or scripting of such a deployment as a separate article in murano
documentattion.
References
==========
* http://jsonpatch.com
* https://tools.ietf.org/html/rfc6902
* https://tools.ietf.org/html/rfc7159
* https://pypi.org/project/jsonpatch

View File

@ -1,180 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==============================
Environment abandoning support
==============================
https://blueprints.launchpad.net/murano/+spec/environment-abandon
The purpose is to add an ability to abandon the environment, which hangs during
deployment or deleting in order to hide it from the list of other environments.
Problem description
===================
There are cases when the process of deleting or deploying environment may hang.
Then the user has to release all used resources and manually clean the database
in order to get rid of the list of failed environments.
Manual cleaning of the database is unsafe and inconvenient operation. That's
why `abandon` feature has to be provided. It should improve usability and
allows to user to avoid direct database editing. But it is necessary to notify
the user that all resources used by abandoned environment must be also released
manually as previously.
Proposed change
===============
The implementation of this feature consists of three stages:
1) Modify environment-delete API endopoint to have *abandon* feature
The method *delete* must be changed. Depending on the parameter "abandon",
obtained from request data, the method should work differently. This parameter
has a boolean type. If it equals *True* enviroment will be directly removed
from the database without object model cleanup.
2) Provide corresponding changes in the python-muranoclient
Method *delete* of environment manager should be modified. New boolean
parameter *abandon* with default value *False* should be added. The value of
parameter affects the building of url, which is sent to murano-api.
3) Add new button *Abandon* to murano-dashboard
This button should be available with any environment state.
Proposed change doesn't solve problem of deployment process hanging.
Murano-engine may continue to deploy abandoned environment. It is
necessary to find a way how to stop murano-engine in this case.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
**DELETE /environments/<environment_id>?abandon**
*Request*
+----------+----------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==================================+==================================+
| DELETE | /environments/{id}?abandon | Remove specified environment. |
+----------+----------------------------------+----------------------------------+
*Parameters:*
* `abandon` - boolean, indicates how to delete environment. *False* is used if
all resources used by environment must be destroyed; *True* is used when just
database must be cleaned
*Response*
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Environment deleted successfully |
+----------------+-----------------------------------------------------------+
| 403 | User is not allowed to delete this resource |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified environment doesn`t exist |
+----------------+-----------------------------------------------------------+
Versioning impact
-------------------------
Murano dashboard will support only the version of the client, that includes
corresponding changes.
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
New action `Abandon` will be added to murano-dashboard. It will be always
available in the row of other action.
Dialog with warning should appear when user executes action
Implementation
==============
Assignee(s)
-----------
Dmytro Dovbii
Primary assignee:
<ddovbii@mirantis.com>
Work Items
----------
* Modify method 'delete' of environment API to support two delete modes
* Implement adding 'abandon' parameter to url in 'delete' method of environment
manager in muranoclient
* Add flag '--abandon' to CLI command 'environment-delete'
* Add new class 'AbandonEnvironment' which provide new button 'Abandon' in
murano-dashboard
Implementation is acutally completed.
Dependencies
============
None
Testing
=======
Functional tests for murano-dashboard must be updated.
Unit tests should cover API call and CLI client
Tempest tests are out of the scope of this spec.
Documentation Impact
====================
API specification should be updated
References
==========
None

View File

@ -1,172 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
========================
Logging API for MuranoPL
========================
https://blueprints.launchpad.net/murano/+spec/logging-api-for-muranopl
The purpose is to add an ability to log actions while developing MuranoPL
applications
Problem description
===================
It is good practice to log basic stages during application execution.
Logging API should make debugging and troubleshooting processes easier.
Proposed change
===============
Implemention key points
1) New MuranoPL class `io.murano.system.Logger`
Class `Logger` will be part of the MuranoPL core library.
This class should contain basic logging functionality.
Usage example in MuranoPL::
$.log: logger('logger_name')
$.log.info('message: {0}', 'checkpoint')
that code should be equivalent of python code::
from oslo_log import log as logging
LOG = logging.getLogger('logger_name')
LOG.info(_LI('message: {0}').format('checkpoint'))
Others logging methods are `Logger.debug`, `Logger.info`, `Logger.warning`,
`Logger.error`, `Logger.critical`. Each method corresponds to the oslo.log
logging level.
There is also separate method for exception stack trace output described
below.
2) Exceptions logging
Method `Logger.exception` intended to log a stack trace::
$.log.exception(exc, 'Something bad happened: {0}', 'Oops!')
`exception` method uses the same log level as `Logger.error`.
3) New global MuranoPL function `logger()`
Call of the function `logger('logger_name')` returns new instance of the
`io.murano.system.Logger`. If function with the same `logger_name` was
called previously then the same logger instance should be returned instead of
building new one.
4) Logging configuration
Logging should use standard Murano Engine logging subsystem.
Application itself cannot set logging settings at runtime.
All of appenders, formatters an etc. may be configured via standard way
as others loggers in Murano Engine.
Prefix `applications` should be added to each logger name which created by
application. As example, logger named `active_directory` in the MuranoPL
should be identified as `applications.active_directory` at the python side
and in the system config. This is for separation loggers used by
applications and engine system loggers. Also it will allow us to specify
settings for the application loggers separately from others loggers.
5) Default configuration
All logs written in the one file by default. Log rotation should be used,
so maximum size of logs is limited.
6) Logging naming conventions
A note about the logging naming conventions should be added to the MuranoPL
tutorial.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
Deployer will get more information about application execution stages and additional
tool for more precise troubleshooting
Developer impact
----------------
Logging API will allow developer to debug application in a more effective manner
getting information from logs.
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Alexey Khivin
Primary assignee:
<akhivin@mirantis.com>
Work Items
----------
* Create new MuranoPL class `io.murano.system.Logger`
* Create new global MuranoPL function `logger()`
* Create method `Logger.exception`
* Add new section for logging parameters into the Murano Engine config
* Describe naming conventions for loggers in the Murano docs
Dependencies
============
None
Testing
=======
Functional tests for MuranoPL must be updated.
Documentation Impact
====================
MuranoPL
References
==========
None

View File

@ -1,239 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=====================
Migration to yaql 1.0
=====================
https://blueprints.launchpad.net/murano/+spec/migrate-to-yaql-vnext
yaql 1.0 has a long list of improvements over yaql 0.2 used by Murano.
But it is not a drop-in replacement for yaql 0.2 and requires to perform
serious changes to Murano in order to switch to it.
-------------------
Problem description
-------------------
While yaql 1.0 is more or less similar in terms of query language to that in
v0.2 it is very different in how its functionality exposed to a hosting
project. Most notable differences are:
* syntax for Python function declaration for yaql is different from that in
yaql 0.2.
* yaql 0.2 had so called #resolve() function. When it encountered function
call expression (say ``foo()``) it tried to call ``#resolve()`` so that it
will do the function resolution. If #resolve was not present in context of
failed to resolve function standard yaql 0.2 resolution procedure was used.
Murano used #resolve to catch attempts to call ``$obj.something()`` where obj
is a MuranoObject because it is impossible to register all possible methods
of all possible objects in advance. yaql 1.0 doesn't have neither
``#resolve()`` nor anything similar to it.
* yaql 1.0 doesn't have tuples syntax any more. In v0.2 ``foo(a => b)`` meant
``foo(tuple(a, b))``. In v1.0 ``=>`` syntax means keyword argument value.
Murano used to convert tuples to keyword arguments when calling MuranoPL
methods.
* in yaql 0.2 parser was a global object so that you could say yaql.parse().
In v1.0 parser itself is customizable and need to be constructed by the
hosting project so you need a parser instance (called YaqlEngine in v1.0)
to parse expressions.
* yaql 1.0 doesn't have ``#validate()`` function used to implement ``:`` in
ns:TypeName syntax. yaql 1.0 also doesn't have ':' operator but has a way
to define custom operators that can be used instead.
* there is a great overlap between MuranoPL and yaql 1.0. yaql have a rich
and extensible framework to decorate function parameters to specify their
type and requirements, to inject hidden parameters and to control parameter
laziness. Not only it used for validation but also for function overload
resolution. In MuranoPL there are argument contracts serving similar purpose.
However their implementation is completely independent from each other as for
the whole function invocation process. As a result for MuranoPL methods that
are writen in Python (system classes) it is impossible neither contracts nor
yaql specs, have additional injected parameters and so on.
---------------
Proposed change
---------------
In Murano Engine:
=================
* Create and store in a global variable YaqlEngine instance that will be used
through the application to parse expressions. Update all the places where
parsing takes place to use that object
* extend list of yaql 1.0 parameters specifications (smart-types) with
additional that will validate parameter value using contract expression.
* generate yaql 1.0 FunctionDefinitions from MuranoPL yaql methods using
introduced smart-type. As a result all MuranoPL methods will be directly
exposed as yaql functions. Actual function payload will still point to
MuranoDslExecutor code to perform correct context switching, locking and
logging
* do similar thing for native MuranoPL methods (those that are written in
Python). Python methods could use any yaql parameter declarations and full
potential of yaql 1.0 specs. So now yaql functions, Python methods and YAML
methods will all be unified as yaql functions/methods with full
interoperability. For native methods there will be 2 FunctionDefinition:
one is the interface stub that gets registered in yaql context and calls
executor.invoke_method() under the hood. And another one for a native method
itself to call methods via yaql mechanics (and apply all the smart-type
specs) rather that via custom reflection-based implementation that is found
in dsl code. For YAML methods method.body will still remain the dictionary
as it is now
* implement ``#operator_.`` (``.`` operator) in such a way that for expressions
of a form ``$obj.foo()`` where ``$obj`` is a MuranoObject it will discover
all possible methods of ``$obj``'s type (via added MuranoClass functionality)
and continue with ``foo(sender=$obj)`` execution in a child context with all
``$obj``'s method registered in it. This is a way to dynamically register
functions in context overcoming absence of yaql 0.2's ``#resolve()``
* configure yaql engine to have additional operator ``:`` with a highest
priority. Expressions of a form ns:Type should be resolved in place using
current Namespaces specification and resulting type name will be used to
obtain MuranoClass from class loader. As a result of operation return
special object (MuranoClassReference) that will wrap MuranoClass and could
be used to reference type in YAML MuranoPL code without providing access
to MuranoClass internals. That can be used later to implement static methods
with ``ns:Type.foo()`` syntax
* add one more yaql smart-type so that it will be possible to declare that
function requires type reference. This smart type should accept both strings
and MuranoClassReference objects. new() and class() functions should be
implemented with this smart-type. This will allow transparency between
string-based syntax new('io.murano.MyClass') and new(ns:MyClass) since
ns:MyClass will not be a string anymore
* change dsl's and engine's yaql functions to have new declaration syntax.
Remove functions that are already present in yaql 1.0 standard library.
* use yaql 1.0 legacy mode for backward compatibility with existing
MuranoPL applications
In python-muranoclient:
=======================
* create global YaqlEngine and update code to use it (and new yaql module
structure)
* update YaqlExpression code to use that global parser object and new yaql's
module structure
In Murano Dashboard:
====================
* make dashboard either use parser object from updated python-muranoclient or
create one for itself
* update yaql functions that were written for dynamicUI forms to have new
declaration syntax
* because dashboard uses expression serialization (pickling) and yaql 1.0
expressions are not serializable because of a outer AST expression contains
reference to YaqlEngine used to create it and YaqlEngine cannot be made
serializable there is a need for custom pickling code that will make pickle
not to try to serialize YaqlEngine instance
* use yaql 1.0 legacy mode for backward compatibility with existing
MuranoPL applications. In the future we can switch to non-legacy mode on
newer form format versions.
------------
Alternatives
------------
Try to fix some of the bugs in yaql 0.2 and not to switch to v1.0
Data model impact
=================
None
REST API impact
===============
None
Versioning impact
=================
yaql migration should not break existing applications so there is no versioning
impact here. However it may have an impact on how plugins/system classes for
MuranoPL are written. But since versioning is not implemented yet there is
nothing to increment and backward compatibility will be broken for those
classes.
Also this yaql legacy mode may be switched off for next engine version and
still be turned on for old applications
Other end user impact
=====================
Because new yaql is not 100% compatible with yaql 0.2 there is still a
possibility that some applications will break even with compatibility mode
turned on. For example there might be bugs in applications that remained
unnoticed with yaql 0.2 but cause exception to be raised with v1.0 or
application might have relied on yaql 0.2 buggy behavior that is not present
anymore.
Deployer impact
===============
None
Developer impact
================
Plugins will have to be updated to use yaql-style method declarations. But
because yaql can infer many things automatically changes are going to be
minor and will not require much efforts to do. However without any
modifications old plugins will likely to break after migration will be made.
Murano-dashboard / Horizon impact
=================================
dashboard code need to be updated to use new yaql. This will not affect user
experience
--------------
Implementation
--------------
Assignee(s)
===========
Primary assignee:
Stan Lagun <slagun>
Other contributors:
Ekaterina Chernova <efedorova>
Work Items
==========
Bullets from "proposed changes" section may be used as a work items directly
------------
Dependencies
------------
This spec depends on yaql 1.0 be released and the latest changes in it.
-------
Testing
-------
Because applications can break they should be re-tested. When incompatibility
found it is better to try to fix it in engine's code rather that in application
to capture similar cases in other applications.
--------------------
Documentation Impact
--------------------
Documentation for how to write plugins/system classes need to be updated.
Most of the newly introduced features to MuranoPL are direct consequence
of new yaql features and should be documented in yaql's scope rather than
copying it to MuranoPL documentation.
----------
References
----------
None

View File

@ -1,219 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
===============================
Murano API - All Tenants Search
===============================
https://blueprints.launchpad.net/murano/+spec/murano-api-all-tenants-search
Congress Murano datasource driver pulls environments from one tenant only. The goal
is to pull all environments from all tenants (as nova driver does for servers).
Problem description
===================
Murano - Congress integration is part of a part of Policy Guided Fulfillment.
It uses Congress policy framework to define and evaluate restrictions on Murano
environments. So Murano environments are pulled by Congress Murano datasource driver,
so Congress policy rules can be evaluated.
The problem is that Murano REST API returns environments of one tenant of authenticated user's token only.
Thus Congress policy rules evaluation is run on data from one tenant only.
Other Congress datasource drivers are dealing with similar requirements also - for example
Nova datasource driver pulls data about all servers across all tenants
in its *nova* policy. It is possible because Nova REST API supports search option *all_tenants*.
Note that *Congress policy* is a place of both rules and data related to one *service*.
If *policy* is defined by datasource driver, then its configuration have *user*, *password* and *tenant*,
which are used to get token to access the service.
Proposed change
===============
Search option *all_tenants* will be added to operation *List Environments* of
Murano REST API. When set, the returned list will contain all environments accessible
by the user (specified by token) regardless of tenant.
Listing environments from all tenants can only admin user.
Alternatives
------------
The requested behavior can be also achieved by iterating operation
*List Environment* over all tenants available to the configuration user.
This solution has following performance issues:
* each pull cycle executes the REST operation for every tenant where user is member,
instead of one execution in case of *all_tenants*
* user's tenant assignment has to be periodically updated, so it leads to another
requests to keystone each such period
Data model impact
-----------------
None
REST API impact
---------------
* List Environments
* *all_tenants* parameter is added. When set to *true*, then search over all tenants
is executed, otherwise search on token's tenant is done
Example (without *all_tenants*):
::
GET http://<server-name>:8082/v1/environments
{
"environments": [
{
"status": "deploying",
"updated": "2015-05-06T08:14:06",
"networking": {},
"name": "test",
"created": "2015-05-06T08:08:40",
"tenant_id": "cd9e218f9b894ebdb421e9906fbec15e",
"version": 1,
"id": "8cc3187c763f4ca9bc58cdaf89f926d3"
}
]
}
Example (with *all_tenants* - note different *tenant_id*):
::
GET http://<server-name>:8082/v1/environments?all_tenants=true
{
"environments": [
{
"status": "deploying",
"updated": "2015-05-06T08:14:06",
"networking": {},
"name": "test",
"created": "2015-05-06T08:08:40",
"tenant_id": "cd9e218f9b894ebdb421e9906fbec15e",
"version": 1,
"id": "8cc3187c763f4ca9bc58cdaf89f926d3"
},
{
"status": "deploying",
"updated": "2015-05-08T09:34:16",
"networking": {},
"name": "test 2",
"created": "2015-05-08T08:18:20",
"tenant_id": "8908989abbeec239023489023ccc1234f",
"version": 1,
"id": "abecbf88328932bbecbefe82348238b"
}
]
}
Versioning impact
-------------------------
None
Other end user impact
---------------------
*python-muranoclient* will be changed as follows:
* *--all-tenants* on CLI
Example:
::
$ murano environment-list --all-tenants
* *search options* will be supported on API level
Example:
::
class EnvironmentManager(base.ManagerWithFind):
def list(self):
...
def list(self, search_opts):
...
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
filip-blaha
Work Items
----------
* Introduce *all_tenants* search option in
* file *murano/api/v1/environments.py*
* Modify *policy.json* file with rules
* file *etc/murano/policy.json*
* Add support for search options in *python-muranoclient*
* file *muranoclient/v1/environments.py*
* Add support for *--all-tenants* in *python-muranoclient* CLI
* file *muranoclient/shell.py*
Dependencies
============
None
Testing
=======
Unit tests should cover server API side also client and shell should be covered.
Documentation Impact
====================
REST API documentation will be modified to mention *all_tenants* search option.
References
==========
* https://wiki.openstack.org/wiki/PolicyGuidedFulfillmentLibertyPlanning
* https://wiki.openstack.org/wiki/PolicyGuidedFulfillmentLibertyPlanning_MuranoAPI

View File

@ -1,171 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=========================================================
Murano API - Core Model Component Integration Improvement
=========================================================
https://blueprints.launchpad.net/murano/+spec/murano-core-model-integration-improvements
Core Model can be seen as API, because user is using it when writing Datalog queries
in Congress, or integrating with Mistral workflows. Current Murano Core model does not
provide means to easy link them with realized OpenStack entities (for example Murano
Instance does not provide UUID of provisioned Nova Server).
Problem description
===================
Congress datalog queries are one of core features used by Policy Guided Fulfillment.
These queries are used to express validity of Murano environment either
in pre-deployment and/or runtime. In order to evaluate environment validity it is
necessary to work with realized entities by core Murano components - for example
* *I want to check if Murano Instance's Nova server exists and is running*
* In kilo I have to use IP address of the Murano Instance and do multiple joins of
neutron tables to identify Nova server.
* *I want to check if owner of network used by Murano Environment is from given group of
users*
* In kilo it is impossible because Murano network object contains only name
of the network (*a-network*), while realized network (via Heat) contains name
with Murano object id (*a-network-bed7a70ed791434c8acdd53a52a8d4ca*)
Proposed change
===============
Changes of core Murano model:
* **io.murano.resources.Instance**
* add property *openstackId* and fill the property with value once Heat provisioned
Instance
::
openstackId:
Contract: $.string()
Usage: Out
* **io.murano.resources.Network**
* add property *openstackId* and fill the property with value once Heat provisioned
network (as part of Instance provisioning)
::
openstackId:
Contract: $.string()
Usage: Out
Alternatives
------------
Instead of adding the same property to each class aware of openstack ID we can create
mixin class ( e.g. **OpenstackIdMixin**) with this property and all classes aware of
openstack ID will extend that mixin.
::
Name: OpenstackIdMixin
Properties:
openstackId:
Contract: $.string()
Usage: Out
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
Murano package versioning is currently analyzed and it is planned for Liberty.
It makes sense to introduce it (modifications of the core Murano packages) as new
versions of core Murano packages.
On the other hand, proposed changes are backward compatible, so they can be
done prior versioning.
Other end user impact
---------------------
None
Deployer impact
---------------
If proposed changes will be done prior Murano package versioning, then after upgrade
the Murano objects won't have initialized introduced properties (*openstackId*).
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
The change will simplify implementation of Horizon UI (instance detail)
Implementation
==============
Assignee(s)
-----------
Primary assignee:
filip-blaha
Work Items
----------
* introduce *openstackId* properties to
* *meta/io.murano/Classes/resources/Instance.yaml*
* *meta/io.murano/Classes/resources/Network.yaml*
* implemented instance and network *openstackId* property population
* *meta/io.murano/Classes/resources/Instance.yaml* , *deploy* method
* *meta/io.murano/Classes/resources/NeutronNetwork.yaml* , *deploy* method
* *meta/io.murano/Classes/resources/NovaNetwork.yaml* won't be modified, as nova
networking is deprecated
Dependencies
============
https://blueprints.launchpad.net/murano/+spec/murano-versioning
Testing
=======
Both unit and tempest tests of policy guided fulfillment will be enhanced to test properties *openstackId*.
Documentation Impact
====================
None
References
==========
* https://wiki.openstack.org/wiki/PolicyGuidedFulfillmentLibertyPlanning
* https://wiki.openstack.org/wiki/PolicyGuidedFulfillmentLibertyPlanning_MuranoAPI

View File

@ -1,168 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
======================
Murano unified logging
======================
https://blueprints.launchpad.net/murano/+spec/unified-style-logging
Rewrite murano logging in unified OpenStack style proposed by
https://blueprints.launchpad.net/nova/+spec/log-guidelines
Problem description
===================
Now log levels and messages in murano are mixed and don't match the OpenStack
logging guideliness.
Proposed change
===============
The good way to unify our log system would be to follow the major guidelines.
Here is a brief description of log levels:
* Debug: Shows everything and is likely not suitable for normal production
operation due to the sheer size of logs generated (e.g. scripts executions,
process execution, etc.).
* Info: Usually indicates successful service start/stop, versions and such
non-error related data. This should include largely positive units of work
that are accomplished (e.g. service setup, environment create, successful
application deployment).
* Warning: Indicates that there might be a systemic issue;
potential predictive failure notice (e.g. package execution problems,
problems with categories listing).
* Error: An error has occurred and an administrator should research the event
(e.g. deployment failed, app add failed).
* Critical: An error has occurred and the system might be unstable, anything
that eliminates part of murano's intended functionality; immediately get
administrator assistance (e.g. failed to access keystone/database, plugin
load failed).
As far as murano-dashboard has it own notification system all notifications
should be duplicated at log messages and should follow this spec in the selection
of log level.
Here are examples of log levels depending on environment execution:
* Action execution:
.. code:: python
LOG.debug('Action:Execute <ActionId: {0}>'.format(action_id))
..
* Environment creation:
.. code:: python
LOG.info(_LI('Environments:Create {id} succeed>'.format(id=environment.id)))
..
* Package execution problems
.. code:: python
LOG.warning(_LW("Class is defined in multiple packages!"))
..
* Environment is not found
.. code:: python
LOG.error(_LE('Environment {id} is not found').format(id=environment_id))
..
Additional step for our logging system should be usage of pep3101 as unified
format for all our logging messages. As soon as we try to make our code more
readable please use {<smthg>} instead of {0} in log messages.
Alternatives
------------
We need to follow OpenStack guidelines, but if needed we can move plugin logs
to DEBUG level instead of INFO. It should be discussed separately in each case.
Data model impact
-----------------
None
REST API impact
---------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None
murano-image-elements impact
----------------------------
None
murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
starodubcevna
Work Items
----------
* Unify existing logging system
* Unify logging messages
* Synchronize dasboard notifications and log entries
* Add additional logs if needed
Dependencies
============
None
Testing
=======
None
Documentation Impact
====================
None
References
==========
https://blueprints.launchpad.net/nova/+spec/log-guidelines
https://www.python.org/dev/peps/pep-3101/

View File

@ -1,410 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=================
Murano versioning
=================
https://blueprints.launchpad.net/murano/+spec/murano-versioning
This specification proposes set of arrangements that are going to allow Murano
keep backward compatibility with applications written for older version while
still making possible to introduce incompatible changes to any part of the
project.
Problem description
===================
Murano is a complex system that comprises from a number of services and
technologies including several domain specific/markup languages. All of them
evolve and change from release to release. New features are introduced, code is
being refactored and not always remains compatible with previous release.
But applications written for previous Murano versions must still work on newer
releases otherwise all applications would require at least retesting and often
code changes on each release.
Proposed change
===============
Because there are many different parts in Murano that can be broken it is
necessary to have versioning support to manage backward compatibility.
Murano packages versioning
''''''''''''''''''''''''''
Murano packages will have new optional attribute in their manifest called
``Version``. It will be standard SemVer format version string consisting
of 3 parts: ``Major.Minor.Patch`` and optional SemVer suffixes
``[-dev-build.label[+metadata.label]]``.
All MuranoPL classes are said to have version of the package they contained in.
If no version specified package version will be equal to "0.0.0"
Version number will become very important not just to distinguish modifications
of the same package but to determine compatibility between them. Two classes
(packages) said to be compatible for particular operation if class with newer
version number can be used instead of older class version without breaking
application/component written for that older version.
Compatibility rules differ for various class usages but they all assume
semantic versioning rules be strictly followed. Changes which break
backwards-compatibility should increment the major segment, non-breaking new
features increment the minor segment and all non-breaking bug fixes increment
the patch segment.
Changes that require major version segment to be incremented:
* class was removed from package
* public method or property was removed from any class in the package
* public method changed argument signature to incompatible with previous one.
For example argument removed or added without default value
* input property (or initializer argument) was added without ``Default`` value
and restrictive contract (e.g. one must provide its value)
* any other change (including in class behavior) that can break class
consumers (callers)
Minor version segment should be incremented upon:
* new class was introduced in the package
* new method or property was introduced in any package's class
* list of parents (``Extends`` section) changed for any class
* any other interface (including behavior) changes that don't break external
class users but can possibly break class inheritors
For all other backward compatible changes patch segment must be incremented.
One should not make changes to package contents without also updating version
number. However there is no requirement to do it on each change. Only released
packages need to differ in version. As a result:
#. several breaking changes can be accumulated into one version number change
#. major segment change may also imply changes that would normally affect minor
and/or patch segments and the same goes for minor version segment change
#. during one development iteration packages may be incompatible with each
other even if they have compatible version number
SemVer suffixes have no special meaning for Murano and affect how two version
strings compare to each other.
Murano core library is also a package which has its own version. The first
version to have a number will be 0.1.0 and be released in Liberty.
Murano Extension Plugins (i.e python packages which declare
setuptools-entrypoints in 'io.murano.extensions' namespace) also will have
similar versioning semantics: they will have a fully qualified name (defined
by the setuptools' package name) and a version (also defined by setuptools).
From the class-loader perspective the MuranoPL classes defined in the plugins
are no difference from the classes defined in a regular package. However
for initial implementation we may just assume that all exposed plugin
classes reside in a single MuranoPL package having a name of the Python package
and version `0.0.0` to keep backward compatibility until we find a better
way to represent MuranoPL packages using Python counterpart.
Package requirements
''''''''''''''''''''
Packages may require other packages for their work. Those requirements are
expressed via ``Require`` key in package manifest. It has a form of
.. code-block:: yaml
Require:
package1_FQN: version_spec_1
...
packageN_FQN: version_spec_N
``version_spec`` here denotes allowed version range.
It can be either in `semantic_version.Spec` pip-like format (for example
`>=1.2,<2.0,!=1.5` or `*`) or as partial version string. In the later case:
* x <==> x.0.0 <= version < (x+1).0.0
* x.y <==> x.y.0 <= version < x.(y+1).0
* z.y.z <==> version == x.y.z
* empty (null) <==> 0.0.0 <= version < 1.0.0
Upon package upload/validation it is checked that at least one package in
specified version range exists.
All packages considered to be dependent on ``io.murano`` package (core
library). If such requirement is absent from the list (or the list is empty or
even there is no ``Require`` key in package manifest) then dependency
``io.murano: 0`` will be automatically added (for package types other than
MuranoPL default version may differ).
Packages must explicitly request all other packages which types are mentioned.
This includes class() contracts, inheritance (``Extends``) and dynamic object
construction (``new()``). For any type name use type should not be resolved
by the engine if its not contained either in the class package itself nor in
any of its requirements. Transitional dependencies doesn't have to be
explicitly required.
Murano Extension Plugins treated as regular MuranoPL packages and thus need
to have a way to specify requirement via Python means.
Each package will also have implicit (unless specified explicitly) requirement
on itself of a form ``PackageFQN: X`` where ``X`` is the package major version
segment meaning package can tall to other versions of itself having the same
major version. This requirement is automatically satisfied by the package
itself.
Object version
''''''''''''''
Object in Object Model are also versioned by the version of object's class.
The version will be stored in ``?/classVersion`` attribute of each object.
When model loader tries to create object from its JSON representation it is
going to ask class loader for class of specified version. Versions of object's
parts that belong to parent classes are determined by normal package dependency
resolution rules (parent classes must be in package requirements for the class
version being loaded)
If no version specified then latest available version should be used.
If version is specified but is not present in catalog then:
#. latest class with the same major and minor segments used
#. if there is no match use latest class having the same major version segment
only
#. if there is no matching class then fail
class() contracts must validate object version against package requirements.
If class A has a property with contract $.class(B) then object passed in this
property when upcasted to B must have a version compatible with requirement
specification in A's package (requesting B's package)
Side by side versioning of packages
'''''''''''''''''''''''''''''''''''
There exist cases when several version of the same package may live in the
same environment:
* there are different versions of the same MuranoPL class inside single object
model (environment)
* several class versions encounter within class parents. For example class A
extends B and C and class C inherits B2 where B and B2 are two different
versions of the same class
This implies that class loader needs to:
#. be able to load/keep in memory several versions of the same class
independently
#. when asked for a class object (i.e. MuranoClass object) from MuranoPL code
(via ``class()`` contract or ``new()`` function analyzes caller's package
requirements and returns latest class version matches those requirements
(or fail otherwise)
#. when accessed from object model loader be able to return class version
specified in object header (and find compatible replacement when the request
cannot be satisfied)
The first case when 2 different versions of the same class need to talk to each
other is handled by the fact that in order to do that there must be a
``class()`` contract for that value and it will be validated by the rules from
previous section.
For the second case where single class will attempt to inherit from two
different versions of a same class engine (dsl) should attempt to to find a
version of this class which satisfies all parties and use it instead.
However if it is impossible all remained different versions of the same class
will be threatened as if they be unrelated classes.
For example: classA inherits classB from packageX and classC from packageY.
Both classB and classC inherit from classD from packageZ, however packageX
depends on the version 1.2.0 of packageZ, while packageY depends on the
version 1.3.0. This leads to a situation when classA transitively inherits
classD of both versions 1.2 and 1.3. So, an exception will be thrown.
However, if packageY's dependency would be just "1" (which means any of the
1.x.x family) the conflict would be resolved and a 1.2 would be used as it
satisfies both inheritance chains.
Engine versioning
'''''''''''''''''
Each package has a manifest attribute named ``Format`` of a form
[PackageType/]Version where PackageType is a language used for the package
with “MuranoPL” as a default and Version is a 3-component version string
with shortening rules ``null = 1 = 1.0 = 1.0.0``. Version indicates minimum
engine/language version to run.
Language, engine and manifest format versions are tied together into a
single version.
We assume that all of above are backward compatible or internally can handle
differences between versions. Engine internally knows what changed in each
version and can use that knowledge to emulate behavior of older versions.
Engine must ensure that for each incompatibility in execution behavior or in
YAQL functions particular class method gets properly initialized context with
functions and flags from requested engine version.
UI forms versioning
'''''''''''''''''''
UI forms are versioned using Format attribute inside YAML definition.
The only way to stay compatible with older format versions is either to
support several different formats internally in dashboard or have
auto-conversion utility that will upgrade forms on package upload.
API versioning
''''''''''''''
If single API service can handle several API versions simultaneously it
should be done via endpoint prefixes (/v1/, /v2/ etc.). Otherwise there
should be several separate services listening on different ports and
registered with different names in Keystone.
We assume that dashboard-API-engine are always consistent and upgraded as
the whole. We also assume to be acceptable for different API versions to
have separate databases or tables so that environments created with one
version would not be visible to APIs of other versions.
Alternatives
------------
Keep strict backward compatibility without ability to introduce breaking
changes.
Data model impact
-----------------
For current package API:
* need to store version number for each versioned entity in the database
* in many cases uniqueness must be constrained by name, version number
and tenant ID rather than by name and tenant ID alone
* requirements for each package need to be stored in database as well
However there is an ongoing process to move packages from Murano API to
Glance v3 Artifact Repository (GLARE).
In GLARE package manifest attributes like FQN and Version are going to be
naturally mapped to corresponding artifact attributes. The package dependencies
will be stored in Glance as cross-artifact dynamic dependencies (i.e.
dependencies not on a particular artifact but on the last artifact matching
the given name and the version range query) as soon as that feature is
implemented in Glance (currently only static dependencies are implemented
there). Until that dependencies are going to be stored as a regular list of
strings, and the Murano engine will process it and query Glance to fetch the
packages.
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
All versions of released packages should be available simultaneously.
That implies that for core library and other essential packages instead
of importing only those packages at system installation all versions of
those libraries need to be imported.
If there would be several independent API services it would require additional
deployment efforts.
Developer impact
----------------
Development process need to be changed for correct version tracking.
Here is an example how it can be organized:
* for each released version of the package there is a separate folder called
after version number plus one additional folder called “dev”
* during development all changes go to “dev” folder. All packages and
requirements have a version “0.0.0” effectively turning versioning off.
* after code freeze release manager assign version number to the version about
to be released by examining commits happened between releases. It is advised
to mark such commits somehow (for example [changes major version],
[changes minor version], [changes revision] or something similar).
* requirements may be defined more accurately from the same source
* new folder for released version is created and final version of the “dev”
package is put there.
* bug/fix and backport commits can be made in between modifying either already
released package or making a copy of it with different revision version
number according to versioning requirements.
* we should write a script to package/upload packages from such versioned
folder (e.g. producing a package for each released version)
Murano-dashboard / Horizon impact
---------------------------------
In L cycle we are not going to show multiple versions of the same app in
Murano dashboard: only the last one will be shown if the multiple versions
are present. This is to minimize the changes at Dashboard side: in future
releases we'll add the ability to select the proper version.
Implementation
--------------
Assignee(s)
```````````
Primary assignee:
Stan Lagun <istalker2>
GLARE integration (API to access packages with versions and GLARE plugin):
Alexander Tivelkov <ativelkov>
Work Items
``````````
* Make Murano Engine access package manifest information
* Implement more flexible processing of package format string (currently it
requires strict version number)
* Make engine be able to setup independent YAQL context chain depending on
package's engine version requirements
* Update class loader to work with versions
* Add support for version numbers and package requirements to
DirectoryPackageLoader (including version-aware directory structure as in
``murano-apps`` repo)
* Update APIPackageLoader to work with GLARE Murano plugin
* Implement version compatibility rules for contracts and inheritance
Dependencies
============
None
Testing
=======
In general, after each release we should try to test old applications on new
release to make sure that nothing broke (which may happen if versioning rules
were not followed correctly). But it is clear that in practice this cannot be
done for all applications in catalog. So we may peek selected set of
applications and to try to deploy all versions of those applications on current
release. This set should be representative to test the most possible set of
futures.
Subset of those applications can be used for per-commit tests.
Documentation Impact
====================
Changes introduced by each version change of each component should be
documented. There should be possible to see documentation for specific previous
Murano version as it remains usable.
References
==========
None

View File

@ -1,174 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
============================
MuranoPL object construction
============================
https://blueprints.launchpad.net/murano/+spec/object-construction
Object construction is ability to create instances of MuranoPL classes
(both YAML and Python-based) and initialize it property. It also directly
affect relations between those 2 types of classes just because they can
inherit from each other and have initializer of their own
Problem description
===================
There are several major problems with current object initialization:
* object created by ``new()`` function will always have an owner set to null.
Because of this you cannot create objects that expect themselves to be
nested in something (e.g. say ``find(std:Environment).require()``)
* there are ``initialize()`` method in Python classes and method with the same
name in YAML part, but they work completely different. YAML version is
currently doesn't invoked at all for ``new()`` making it useful for Python
classes only
* Python initializer may me called instead of YAML version in some cases as
they have the same name
* Python classes inherit from MuranoObject even if they not aware of it.
Because MuranoObject has ``__init__`` with many parameters and user
classes have constructor parameters of their own user class cannot have
``__init__`` or it will break MuranoObject. It looks very strange for a class
to inherit from Python's object and not being able to have ``__init__``.
* also because MuranoObject has many methods and properties of its own if user
class will define method with the same name it will break how MuranoPL work.
Proposed change
===============
* rename YAML initialize and destroy methods to ``.init"`` and ``.destroy``
as they are special. Make class loader automatically replace old names with
new ones for backward compatibility. Dot-prefixed names cannot be called from
MuranoPL directly as this will be a YAQL syntax error so there is no more
need to have special treatment for those names in MuranoDslExecutor and
block them from being called explicitly
* ``.init`` will be allowed to have parameters. During object initialization
object model values will go into .init parameters instead of properties
if parameter name matches key name in object model. Usual parameter contract
system applies here
* because ``.init`` need to be able to save values it receives in parameters to
corresponding objects it should be allowed to modify properties with
usage=In that are immutable in normal operation mode. The same extends to
functions that get called during initialization
* separate Python classes from MuranoObject. Classes will no longer inherit
from MuranoObject and thus will have ``__init__`` instead of initialize.
MuranoObject will store their native part in a property called ``extension``
* using YAQL injected parameters provide Python class with interface to access
its MuranoObject counterpart and invoke methods defined in YAML
* initialization should go as following:
1. YAML-defined properties initialized (in 1 pass for ``new()``, 2 passes
for object model load) except for those that can be found in ``.init``
parameters
2. Python ``__init__`` get called if present. The same property value used
to initialize object used as ``__init__`` parameters (i.e. subset of
them since ``__init__`` may have less parameters then number of declared
properties or not to have parameters at all)
3. For MuranoObject counterpart all ``.init`` methods in hierarchy get
invoked starting from the top-level classes and down to the class that
we are initializing. It should be invoked with special flag passed in
context that will allow it to write to even read-only properties.
Property values that were skipped on first stage become ``.init``
parameters on each hierarchy level. It is ``.init``'s job to set
corresponding properties (that might have different contract)
* Add ability to explicitly pass created object owner as a ``new()`` parameter
* Update object model serializer so that if object A is specified as an owner
of object B but doesn't references it and instead referenced by some other
object C that is nested inside A then reattach B to C. This will not break
object A since it remains nested in B. If A is referenced by several objects
conforming this criteria any one of them can be used.
Alternatives
============
None
Data model impact
=================
None
REST API impact
===============
None
Versioning impact
=================
* initialize and destroy will automatically be renamed to .init and .destroy
by the class loader so previously written apps won't break
* because currently initialize cannot have parameters at all backward
compatibility retained
* the same is true for ability to modify read-only properties in initializer
Other end user impact
=====================
Users gets ability to implement things like auto-scaling with
ability to create instances from within MuranoPL
Deployer impact
===============
None
Developer impact
================
None
Murano-dashboard / Horizon impact
=================================
None
Implementation
==============
Assignee(s)
```````````
Primary assignee:
Stan Lagun <slagun>
Work Items
``````````
Bullets from "proposed changes" section may be used as a work items directly
Dependencies
============
https://blueprints.launchpad.net/murano/+spec/migrate-to-yaql-vnext
Testing
=======
Please discuss how the change will be tested. We especially want to know what
tempest tests will be added. It is assumed that unit test coverage will be
added so that doesn't need to be mentioned explicitly, but discussion of why
you think unit tests are sufficient and we don't need to add more tempest
tests would need to be included.
Is this untestable in gate given current limitations (specific hardware /
software configurations available)? Is this untestable in murano-ci? If so,
are there mitigation plans (3rd party testing, gate enhancements, etc).
Documentation Impact
====================
Mentioned changes need to be included into MuranoPL documentation
References
==========
None

View File

@ -1,164 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
========================================
Policy Based Modification of Environment
========================================
https://blueprints.launchpad.net/murano/+spec/policy-based-env-modification
Goal is to be able to define modification of an environment by Congress policies prior
deployment. This allows to add components (for example monitoring), change/set properties
(for example to enforce given zone, flavors, ...) and relationships into environment,
so modified environment is after that deployed.
Problem description
===================
Currently it is possible to reject deployment of an environment if it does not follows
set of so called pre-deployment policies set by admin. Administrator wants to also modify
environment prior it is deployed:
* add/set/remove component properties
* add/remove relationships
* add/remove objects
**Example Use Case: Policy Based Monitoring**
Admin wants to monitor an environment, so he wants to
* install monitoring agent on each Instance
* it is done by adding component with the agent and creating relationship between
agent and Instance. It is done at pre-deploy time
* register monitoring agent on Monitoring server
* it is done by calling monitoring server API during deployment of monitoring agent.
Proposed change
===============
**Changes**
* Introduce new Congress policy rule *predeploy_modify(eid,oid,modify-action-id,priority,
[key-val]\*)*
*predeploy_modify* policy rule is queried on all actions.
Simulation Congress API is used like in case of *predeploy_errors* policy rule.
If it returns non empty list of *modifications* for given environment, then
* *deploy* action is temporarily paused, until all modifications are processed
* if any of modification fails, then environment *deploy* fails
* Pluggable modification actions
Modification actions can be plug using setup *entry_points*.
Out of box, there will be following modification actions
* add_property( name=name, value=value)
* remove_property( name=name)
* set_property( name=name, value=value)
* add_relationship( name=name, source=source-uuid, target=target-uuid)
* remove_relationship( name=name, object=object-uuid)
* add_object( type=type, owner=owner-uuid, owner-rel-name=name, [name=val]*)
* remove_object( object=object-uuid)
Alternatives
------------
Alternative can be usage of *executes[]* of Congress policy, which executes modify
actions. In this approach
* modify action has to be implemented as Congress datasource action
* triggering of executes[] has to be solved
* it is not possible to order modify action ordering
* Murano session-id of REST API must be passed to Congress
* actions can be executed only as asynchronous, so it is not possible to postpone
*deploy* environment action until all modify actions are finished
Thus it is not alternative.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
User (admin) can control modification by creating *predeploy_modify* Congress policy
rules.
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
filip-blaha
Work Items
----------
* design API of modify actions
* framework for pluggable modify actions - registering and managing available actions
* implement out-of-box actions
* add point to engine where congress called and returned action list is processed on given environment
Dependencies
============
None
Testing
=======
We need to cover by unit tests:
* framework for registering/managing modify actions
* applying modify actions on environment
* processing action list returned by congress
We need to create functional tests covering end-to-end scenario.
Documentation Impact
====================
It is documented as part of policy guided fulfillment.
References
==========

View File

@ -1,206 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=============================
Simple Software Configuration
=============================
https://blueprints.launchpad.net/murano/+spec/simple-software-configuration
The purpose is to add to Murano core-library new functionality allowing to
simplify the process of software configuration.
Problem description
===================
At the moment a developer of murano applications often has difficulties with
configuration of software on the instance. They are related with fact that
developer always has to create execution plans even in situations when some
short scripts must be executed on VM.
For example, developer wants to run mysql service. In this case he should:
* Prepare template file for execution plan
* Prepare script containing only something like this:
..
service mysql-server start
..
* Describe in code of class the sending of plan to the murano agent
It is proposed to update the murano core-library to allow to user make express
software configuration instructions without writing explicit configuration
scripts and execution plans for Murano Agent in order to develop applications
faster, and have concise and clear workflows.
Proposed change
===============
The extension of library will support only Linux instances.
The new class **io.murano.configuration.Linux** will be added. In initial
implementation this class has two methods:
::
runCommand:
Arguments:
- agent:
Contract: $.class(sys:Agent)
- command:
Contract: $.string().notNull()
- helpText:
Contract: $.string()
* **runCommand** method sends specified string containing CLI command to
murano-agent and then it will be executed.
Arguments:
* *agent* - instance of murano-agent
* *command* - string with CLI command
* *helpTest* - string (optional), description for logging. Will be used as
name of execution plan. If it is *Null* value of *command* will be used.
::
putFile:
Arguments:
- agent:
Contract: $.class(sys:Agent)
- fileContent:
Contract: $.string().notNull()
- path:
Contract: $.string().notNull()
- helpText:
Contract: $.string()
* **putFile** method takes content of file and writes it to specified path
on VM
Arguments:
* *agent* - instance of murano-agent
* *fileContent* - string, content of file
* *path* - string, path for writing
* *helpTest* - string (optional), description for logging. Will be used as
name of execution plan. If it is *Null*, value of *path* will be used.
The both methods actually use the same procedure of sending the execution plans
to the agent and require corresponding templates for that, but hide from a
developer this routine.
**Example of usage**
The next example describes how new feature can be used. This code demonstrates
workflow of method in WordPress application, which used for re-configuration
of database settings.
::
changeDatabaseConnection:
Arguments:
- dbHost:
Contract: $.string().notNull()
- dbName:
Contract: $.string().notNull()
- dbUser:
Contract: $.string().notNull()
- dbPassword:
Contract: $.string().notNull()
Body:
- $resources: new(sys:Resources)
# Creating instance of Linux class
- $linux: new(conf:Linux)
# First we need to stop server. 'runCommand' can be used here
- $linux.runCommand($.instance.agent, 'service apache2 stop')
# Creating a dictionary for replacement
- $configReplacements:
"%DB_HOST%": $dbHost
"%DB_NAME%": $dbName
"%DB_USER%": $dbUser
"%DB_PASS%": $dbPassword
# Making a replacement. `wp-config.php' is included to package
- $confFileContent: $resources.string('wp-config.php').replace($configReplacements)
# Putting ready content to necessary path on VM
- $linux.putFile($.instance.agent, $confFileContent, '/var/www/html/wordpress/wp-config.php')
# Now we can start Apache again
- $linux.runCommand($.instance.agent, 'service apache2 start')
Alternatives
------------
Instead of using the common procedure with creating execution plans and
communication with murano-agent some software configuration resources of heat
probably can be used. During updating of library it can be used in the future.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
Application developers will be able to use new functionality in their apps.
Existing apps will not be affected.
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
ddovbii
Work Items
----------
* Create new class *io.murano.configuration.Linux*
* Implement methods *putFile* and *runCommand*
* Update Murano PL docs
Dependencies
============
None
References
==========
None

View File

@ -1,282 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==========================================
Simulated Execution Mode For Murano Engine
==========================================
https://blueprints.launchpad.net/murano/+spec/simulated-execution-mode-murano-engine
Problem description
===================
As an Application Developer I'd like to execute my workflows without actual
deployment and interaction with murano-dashboard in order to verify my workflow
before actual deployment by those increasing my application development
speed.
Proposed change
===============
Verifying application packages should be simple and fast.
User doesn't have to re-upload package and add app to the environment on every
change.
* Allow application author to validate his application using unit-tests
* Those tests will be put to the application package to allow anyone to test
this app at any time
* Tests will look like regular unit tests. Testing framework, which will
run unit-tests will support commands, that will allow to load test package
from directory, to call class methods and configure deployments parameters.
That will make deployment test run easier. Also, test writer may run
deployment several times, examine and compare results with different
parameters
* Tests should be able to produce complete object model with some parameters
of deployment:
* environment attributes (such as tokens) (or overwriting values, defined in
config);
* mock the methods of system classes which include various kinds of external
communications. Dependent applications, system resources and various API
clients and also be mocked. It should be allowed to specify a returned
value. There would be separate specification for mocking, where the
details will be described.
Test-case prototype may look like that:
::
Namespaces:
=: io.murano.apps.foo.tests
sys: io.murano.system
pckg: io.murano.apps.foo
Extends: io.murano.tests.TestFixture
Name: FooTest
Methods:
initialize:
Body:
# - $.appJson: new(sys:Resources).json('foo-test-object-model.json')
- $.appJson:
- ?:
id: 123
type: io.murano.apps.foo.FooApp
name: my-foo-obj
instance:
?:
type: io.murano.resources.Instance
id: 42
...
setUp:
Body:
- $.env: $.createEnvironment($.appJson) # creates an instance of std:Environment
- $.myApp: $.env.applications.where($.name='my-foo-obj').first()
- mock($.myApp.instance, "deploy", "mockInstanceDeploy", $this)
- mock(res:Instance, deploy, "mockInstanceDeploy", $this)
testFooApp:
Body:
- $.env.deploy()
- $.assertEqual(true, $.myApp.getAttr('deployed'))
tearDown:
Body:
mockInstanceDeploy:
Arguments:
- mockContext
Body:
- Return:
# heat template
Alternatives
------------
Provide one CLI command, that will mock creation of VMs and other things and
returns the deployment result.
Cons:
Impossible to verify deployments, where execution plan returns a value, which
is used in future app workflow. Compare results of several deployments would be
inconvenient Real VMs cant be
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
Tests will be placed to a package, so manifest version need to be updated.
This functionality should be described in a separate spec.
For now, there will be no impact on project itself.
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
<efedorova@mirantis.com>
Work Items
----------
#. Add simulation mode (new entry-point) to Murano Engine, where
packages would be uploaded from the provided path there would be no
interconnection with RabbitMQ
#. Make changes to the class-loader, located in engine, to not use API.
Separate spec is provided for this change (https://review.opendev.org/#/c/198745/).
#. Implement testing framework, written in MuranoPL that will include the
classes, described below. The structure would be taken from python unittest
module. Framework will include test-runner
#. Implement mock support.
#. Define what is needed to change in MuranoPL itself
Testing framework may contain the following classes and methods.
This are base classes for simple testing framework.
* ``TestCase`` class
+------------------+-------------------------------------------------------------+
| Method | Description |
+==================+=============================================================+
| setUp() | Method called immediately before calling the test method. |
+------------------+-------------------------------------------------------------+
| tearDown() | Method called immediately after the test method has been |
| | called and the result recorded. |
+------------------+-------------------------------------------------------------+
| run(result=None) | Run the test, collecting the result into the test result |
| | object passed as result. |
+------------------+-------------------------------------------------------------+
| assert... | Different asserts (assertEqual, assertNotEqual, assertTrue, |
| | assertFalse). |
+------------------+-------------------------------------------------------------+
* ``TestResult`` class: This class is used to compile information about which tests have succeeded and which have failed.
+--------------+-------------------------------------------------------------+
| Attribute | Description |
+==============+=============================================================+
| errors | A list containing 2-tuples of TestCase instances and strings|
| | holding formatted tracebacks. Each tuple represents a test |
| | which raised an unexpected exception. |
+--------------+-------------------------------------------------------------+
| failures | A list containing 2-tuples of TestCase instances and strings|
| | holding formatted tracebacks. Each tuple represents a test |
| | where a failure was explicitly signalled using the |
| | TestCase.assert*() methods. |
+--------------+-------------------------------------------------------------+
| testsRun | The total number of tests run so far. |
+--------------+-------------------------------------------------------------+
* ``TestRunner(stream=sys.stderr, descriptions=True, verbosity=1)`` A basic test runner
implementation which prints results on standard error.
Has *run* method, witch executes the given test case. Also stores the execution result.
For the fist time test may be run only one by one. Later we can add ``TestSuite`` class and
``TestLoader`` class:
* ``TestLoader`` class is responsible for loading tests according to various criteria
and returning them wrapped in a TestSuite (or TestSuite if will add this class).
+--------------------------------------+----------------------------------------------------+
| Methods | Description |
+======================================+====================================================+
| loadTestsFromTestCase(testCaseClass) | Return a suite of all tests cases contained in the |
| | TestCase-derived testCaseClass. |
+--------------------------------------+----------------------------------------------------+
#. Implement simple mocking machinery
All mockes are separated into NonCallable and Callable mocks
``Mock`` class
Public methods
+-----------------------------+-----------------------------------------------------------------+
| Methods | Description |
+=============================+=================================================================+
| start() | Activate a patch, returning any created mock. |
+-----------------------------+-----------------------------------------------------------------+
| stop() | Stop an active patch. |
+-----------------------------+-----------------------------------------------------------------+
| patch(target) | The `target` is patched with a `new` object. `target` should be |
| | a string in the form `package.module.ClassName`. |
+-----------------------------+-----------------------------------------------------------------+
| attach_mock(mock, attribute)| Attach a mock as an attribute of this one, replacing its name |
| | and parent |
+-----------------------------+-----------------------------------------------------------------+
| configure_mock(kwargs) | Set attributes on the mock through keyword arguments |
+-----------------------------+-----------------------------------------------------------------+
Private methods:
initialize, __call__, _patch, __enter__, __exit__
Dependencies
============
None
Testing
=======
None
Documentation Impact
====================
New testing framework will be documented from scratch.
References
==========
Discussions in IRC will be provided

View File

@ -1,267 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
========================================
Add network selection element to UI form
========================================
Include the URL of your launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/ui-network-selection
Sometime a VM should be placed to existing network rather then to a new network
created during deployment. While our workflows support this, there is no way
for the end user to select this network in the easy way in the UI. It will be
great if there is a special form element which will pre-populate a list of
available networks and provide an easy option to select desired network for the
application.
Problem description
===================
Currently murano supports only so called "Default Scenario" when it comes to
networking: it creates a single network per environment, picks a router,
allocates an IP range and creates a subnet with this range within a created
network. This behavior is fine for most of the cases, however it may be
insufficient in complicated scenarios and topologies.
For example, an application may require some pre-configured networks to exist
so it may manipulate with the resources associated to them, allocate floating
IPs from the specific net etc. In this case, the existing net becomes a valid
input property for the application, so its developer may ask the users to
specify it before the deployment.
Another scenario is the need to have all the VMs of the environment to join
some pre-configured network - regardless of their configuration and the
applications they run for. This may be caused by some specific networking
requirements of a particular cloud (a frequent example is a custom proxy to
access the internet which is reachable only from a specific network segment).
When the Network Management scenarios were initially introduced in murano
`[1] <https://wiki.openstack.org/wiki/Murano/Specifications/Network_Management>`_
we planed to have a so-called "Advanced scenario", i.e to provide the users
with an ability to use existing networks, subnets, routers etc, or configure
some sophisticated combination of them.
This scenario was properly supported at engine and at the level of the Core
Library: the `io.murano.resources.Instance` class has a `networks` field which
allows to specify `customNetworks` as a collection of objects inheriting from
`io.murano.resources.Network`, which may include the existing networks or
new networks with non-default configuration.
However, there is no support of this functionality at the UI level: the object
model being generated by the Dynamic UI contains the default networking
definitions only: i.e. the directive to join Environment's default network,
which is - in its turn - is hardcoded to be a newly created network and a
subnet in it.
Proposed change
===============
A new field will be added to the Dynamic UI framework which will allow to pick
the network and a subnet from the ones available to the current user. This will
be a drop-down list populated when the form is rendered.
The value selected by the user in this field will be a tuple, consisting of
the network id and a subnet id. This ids may be passed to the application
either as plain strings or as part of a more complicated Object Model, for
example as the properties of `io.murano.resources.ExistingNeutronNetwork`
objects. It is up to application developer to properly interpret and use these
values. The existing applications will not be affected by this change, as their
"configure instance" step of the UI dialog will not include any networking
settings. In future some of our standard apps may be updated to utilize this
new field, but those updates are out of the scope of this spec.
A similar field (but a static one rather then defined as part of Dynamic UI
framework) should be added to the `New Environment` dialog form, so the user
may choose an existing network to be the default network of a given
environment. The default value in that choice should lead to the creation of a
new environment's network (i.e. to replicate the existing behavior), while any
other choice should lead to a generation of a new object of type
`io.murano.resources.ExistingNeutronNetwork` which will be passed to murano-api
as part of `defaultNetworks` dictionary as the default environment's network.
Both these fields should share the same logic for value population.
Additionally, the dynamic UI field should have the following options, defined
as constructor arguments and exposed to dynamic ui as yaml attributes:
* *include_subnets* - `True` by default. If `True`, the dropdown includes all
the possible combinations of network and subnet. E.g. if there are two
available networks X and Y, and X has two subnets A and B, while Y has a
single subnet C, then the dropdown will include 3 item: (X, A), (X, B),
(Y, C). If set to `False` the subnet info will not be retrieved, and `None`
values will be returned as second items in output tuples, so only network ids
are available.
* *filter* - `None` by default. If set to a regexp string, will be used to
display only the networks with names matching the given regexp.
* *murano_networks* - `None` by default. May have values `None`, `exclude` or
`translate`. Defines the handling of networks which are created by murano.
Such networks usually have very long randomly generated names, and thus look
ugly when displayed in dropdown. If this value is set to `exclude` then these
networks are not shown in the dropdown at all. If set to `translate` the
names of such networks are replaced by a string `Network of %env_name%`.
Note that this functionality is based on the simple string matching of the
network name prefix and the names of all the accessible murano environments.
If the environment is renamed after the initial deployment this feature will
not be able to properly translate or exclude its network name.
* *allow_auto* - `True` by default. Defines if the default value of the
dropdown (labeled "Auto") should be present in the list. The default value is
a tuple consisting of two `None` values. The logic on how to treat this value
is up to application developer. It is suggested to use this field to indicate
that the instance should join default environment network. For use-cases
where such behavior is not desired, this parameter should be set to `False`.
The string representation of the dropdown items should look like
`%NetworkName%: %cidr% (%SubnetName%)`, where `%SubnetName%` part is optional
and may be not present if the subnet's name is not set.
If neutron is not available (so murano falls back to nova-network support) the
dropdown (both the static and dynamic ones) are not populated and appropriate
hints are available in the `New Environment` dialog.
Alternatives
------------
Currently the only way to change the default networking behavior is the usage
of `networking.yaml` file which allows to override the networking setting at
the environment level, for all the murano environments of all the tenants. This
is not flexible enough and does not provide the desired user experience.
However this method will remain, as it allows to override the network setting
globally.
Data model impact
-----------------
No impact. The existing data structures will be used.
REST API impact
---------------
No impact. The existing API methods will be used.
Versioning impact
-----------------
As this feature adds a new type of Dynamic UI fields this will bump the minor
version of Dynamic UI format version. The version will change from 2.0 to 2.1
Other end user impact
---------------------
The user will see the new field in the "Create Environment" dialog. It will
also be shown when the environment is created inline in the environments grid.
The default value of this new field will follow the old behavior.
The user experience with the existing applications will not be changed.
Deployer impact
---------------
The dropdown in Dashboard will be calling public neutron APIs. If they are not
accessible due to some reason, the UI will guess that neutron is not installed
at all so nova network usage will be assumed.
However, the actual decision on the fallback to nova-network is done at the
murano-api. So, if the dashboard is unable to connect to neutron while the api
is then the behavior is inconsistent: the UI tells user that nova-network is
used, while this is not true. No error occur in this case though.
Developer impact
----------------
The application developers may need to modify their apps to use the new
feature. Patch [2] may be used as an example.
Existing apps will not be affected, they will just have the old default
behavior.
Murano-dashboard / Horizon impact
---------------------------------
The whole change proposed in this spec is a change of murano-dashboard.
No other components are modified.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
ativelkov
Other contributors:
ddovbii
Work Items
----------
* Implement the shared logic to retrieve and filter the list of networks
* Implement the DynamicUI control to select networks in apps
* Add a dropdown field to a static Create Environment form to select the
default network of the environment.
* Add the support of the new control in the existing murano apps in murano-apps
repository.
Dependencies
============
* Include specific references to specs and/or blueprints in murano, or in other
projects, that this one either depends on or is related to.
* If this requires functionality of another project that is not currently used
by Murano, document that fact.
* Does this feature require any new library dependencies or code otherwise not
included in OpenStack? Or does it depend on a specific version of library?
Testing
=======
There should be an acceptance testing implemented on this feature:
* We should test deploying the apps with existing network selected and with the
default option.
* Modified application (for example [2]) should be deployed both with "Auto" as
instance network or with some existing network selected.
* The test cases above should verify the ability to assign floating IPs to the
VMs
* The networks being used as an options for the manual selection should be
connected to a router uplinked to the external network (otherwise app
deployment will fail). Also the DNS nameservers has to be manually assigned
on those networks.
Documentation Impact
====================
A new Dynamic UI field type has to be documented at `Dynamic UI definition
specification` guide at [3]
References
==========
* [1] https://wiki.openstack.org/wiki/Murano/Specifications/Network_Management
* [2] https://review.opendev.org/#/c/201659/
* [3] https://murano.readthedocs.org/en/latest/draft/appdev-guide/muranopackages/dynamic_ui.html#dynamicuispec

View File

@ -1,33 +0,0 @@
Mitaka specifications
======================
This directory is supposed to hold approved specifications for the 'Mitaka' release.
You are welcome in contributing to Murano!
Murano
------
Murano Project introduces an application catalog, which allows application
developers and cloud administrators to publish various cloud-ready
applications in a browsable categorized catalog. Cloud users
-- including inexperienced ones -- can then use the catalog to
compose reliable application environments with the push of a button.
Murano Project Resources
------------------------
* `Murano Official Documentation <http://murano.readthedocs.org>`_
* Project status, bugs, and blueprints are tracked on
`Launchpad <https://launchpad.net/murano>`_
* Additional resources are linked from the project
`Wiki <https://wiki.openstack.org/wiki/Murano>`_ page
* `Python client <https://github.com/openstack/python-muranoclient>`_
License
-------
Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0

View File

@ -1,262 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=====================================
Actions authentication and visibility
=====================================
URL of launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/actions-authentication-and-visibility
Application actions is a way for external systems to perform action related
procedures such as maintenance, scaling etc. However those 3rd party
systems are incapable to authenticate themselves to Keystone to call this
API securely.
Problem description
===================
Currently in order to call an action caller needs to have a valid Keystone
token or trust. It is not always possible for cases where 3rd party system is
supposed to be such caller.
There can be a 4 types of authentication for application actions:
#. Public actions. Anybody can call them. No authentication required.
Usually those are the actions without side effect, but if they do
they do that on environment owner behalf.
#. Actions that require authentication and could be invoked from both Murano
UI/CLI (considering user has valid OpenStack credentials) and automation
systems that cannot authenticate to Keystone.
#. Actions that are supposed to be called from automation systems only.
#. Actions that are supposed to be called by admin only and thus require
valid OpenStack token.
It must be possible to associate actions with one of the categories above
and to handle authentication according to type that is chosen.
Proposed change
===============
It is proposed to implement pre-authenticated URLs for the actions.
We assume that any external system will be able to execute POST query
on a fixed HTTP URI that doesn't require authentication. Thus application
during deployment phase (when it has a valid Keystone token or trust)
may allocate such a secret URI on murano API server than when invoked would
trigger particular action on behalf of the user that owns the application
(environment).
There should be an ReST API call to allocate such URI and there also should
be a MuranoPL method to call it from inside of applications.
This API call works as following:
#. Creates a keystone trust for special service user (specified in config file)
to perform particular action
#. Creates a record in database that holds trust ID, project ID, environment
ID, target object ID, action name and action parameters - everything that
is necessary to call particular action on particular application with
specified input.
#. Returns URI that has ID of an inserted record.
#. Murano API should be configured to bypass authentication for such URIs.
#. When such URI is accessed, murano API should extract record ID from the URI.
Then obtain trust ID and action parameters from the database and call
the actions using trust ID putting it instead of Keystone token into
object model.
#. Existing API for calling actions should also work without authentication.
If it is accessed with Keystone token in HTTP header then it must be
validated in the API code. Otherwise only public actions (those that do
not require authentication) must be allowed there.
#. Pre-authenticated URIs can be revoked by revoking the trust and then
deleting the record from database. This should be also possible from within
MuranoPL code.
Alternatives
------------
None
Data model impact
-----------------
New database table holding:
* Record ID
* Trust ID
* OpenStack project ID
* Murano environment ID
* Target object (application) ID
* Action name
* Action parameters (JSON)
REST API impact
---------------
Several new API endpoints are added:
**POST /environments/<env_id>/actions-auth/<action_id>**
*Request*
+--------+-------------------------------------------------+----------------------------------------------+
| Method | URI | Description |
+========+=================================================+==============================================+
| POST | /environments/<env_id>/actions-auth/<action_id> | Creates pre-authenticated URI for the action |
+--------+-------------------------------------------------+----------------------------------------------+
::
{
"arg1": "value1",
"arg2": "value2"
}
*Response*
+----------------+-------------------------------------+
| Code | Description |
+================+=====================================+
| 200 | Authentication URI has been created |
+----------------+-------------------------------------+
::
{
"uri": "full pre-authenticated URI",
"id": "auth_id"
}
**DELETE /environments/<env_id>/actions-auth/<auth_id>**
*Request*
+-----------+-----------------------------------------------+------------------------------------+
| Method | URI | Description |
+===========+===============================================+====================================+
| DELETE | /environments/<env_id>/actions-auth/<auth_id> | Revokes authentication for auth_id |
+-----------+-----------------------------------------------+------------------------------------+
*Response*
+----------------+----------------------------+
| Code | Description |
+================+============================+
| 200 | Authentication was revoked |
+----------------+----------------------------+
**POST /environments/<env_id>/actions/pre-auth/<auth_id>**
*Request*
+--------+---------------------------------------------------+----------------------------------------------------+
| Method | URI | Description |
+========+===================================================+====================================================+
| POST | /environments/<env_id>/actions/pre-auth/<auth_id> | Calls action by its auth_id. If Keystoke header is |
| | | provided in HTTP readers it takes presendence over |
| | | trust_id. |
+--------+---------------------------------------------------+----------------------------------------------------+
*Response*
+----------------+----------------------------+
| Code | Description |
+================+============================+
| 200 | Action was executed |
+----------------+----------------------------+
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
Service user credentials should be configured in murano.conf.
Also base part of the URI need to be there as well so that API server
would know load balancer IP it stands behind. Keystone v3 should be enabled.
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
There should be a way for the user to create pre-auth URI from Murano
dashboard.
Implementation
==============
Assignee(s)
-----------
Stan Lagun <slagun@mirantis.com>
Work Items
----------
#. Define a markup for action visibility in MuranoPL.
#. Improve object model serialization to include action visibility.
#. Create database migration and model code to work with new table.
#. Add support for missing config parameters.
#. Create API endpoint to create pre-authenticated URI.
#. Create API endpoint to revoke pre-authenticated URI.
#. Create API endpoint to invoke pre-authenticated URI.
#. Configure authentication in paste.ini.
#. Improve python-muranoclient with support for new endpoints
#. Implement MuranoPL functions to create/revoke pre-authenticated URIs for
particular action. Function should return existing Action API endpoint
for public and token-only actions.
#. Provide the same capabilities in Murano dashboard.
Dependencies
============
None
Testing
=======
Develop sample application that would deploy some 3rd part system
and provide it with pre-authenticated URI that it could call periodically.
Observe action invocation fact by its side-effects (logs etc.)
Documentation Impact
====================
New ReST and MuranoPL APIs need to be documented.
References
==========
None

View File

@ -1,207 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
====================
Engine Package Cache
====================
Include the URL of your launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/murano-engine-package-cache
This specification provides means to improve caching of packages to fasten
consecutive deployments and action executions, that use the same package.
Problem description
===================
When murano-engine performs a deployment or executes an action on a deployed
environment it needs access to the code of the package. Currently it downloads
a package from API for each deployment and stores it in a local cache for the
duration of the deployment, but deletes it after the deployment has finished.
This means, that a consecutive deployment of the environment that uses the same
package would have to download it again. Same is true for actions. This puts an
undesired strain on murano-api and network, as the same package is downloaded
many times even if it didn't change
Currently murano-engine stores packages on disc, using package-id as cache key.
This further means that if two environments are using the same package the
first to finish would delete the cache, leaving the second environment in an
unexpected state. This can potentially lead to unexpected and hard to pinpoint
bugs.
Among other things the cache system should be able to satisfy and correctly
work around the following corner cases:
#. Several different versions of single package may be used simultaneously by
parallel deployments/actions.
#. Package may be deleted or re-uploaded to API (with or without
version change) while there are ongoing deployments that use previous
package version.
#. Deployment/action may require to download the package that is currently
being downloaded for another deployment/action.
#. Packages might need to be eventually invalidated and space constrained.
Generally there are 2 situation when a package cache needs to be invalidated:
#. A new package of the same version and FQN has been updated, meaning old one
is no longer available, but might still be used by an ongoing deployment
#. A package has not been used for long time (but may be exactly the same as
the most recent package in the API)
Proposed change
===============
Proposed change includes modifying current cache mechanism to allow it to
persist the packages on disk and not clean them up after deployment/action has
ended.
#. Change cache storage directory path from {id} to {fqn}/{version}/{id}
This would allow to easily detect outdated versions of the same package.
Listing {fqn}/{version} directory *before* asking API for an id would give
engine exact list of packages that are in cache and should be invalidated
#. Whenever engine starts executing a task it would acquire shared *usage*
lock on 2 levels: eventlet-based lock (to synchronise tasks from the
current execution task with other execution tasks) and file-system based
lock, using flock or similar primitives (to synchronise use of package
cache between different murano-engine processes). The lock should be
released after the package is no longer required.
#. If the package is not available in cache execution task would attempt to
acquire exclusive *download* lock on 2 levels (eventlet/file-based), thus
allowing only one download per id at a time. The lock should be released
after the download is finished.
#. The task/process, downloading the package would be the one responsible
for deleting outdated versions of the same package.
To do so it would acquire exclusive
*usage* lock on 2 levels for the packages it wishes to delete as part of
cleanup. This would ensure, that ongoing deployments would not be affected
by the cleanup.
Usage lock has to be acquired before download lock. Otherwise there is a
race condition where 2 versions of the same package were downloaded within
a very short interval of time by 2 tasks, and the newer version has finished
downloading before the first one did (for example the newer package is
significantly smaller) and engine started cleanup. This could lead to
newer version being the first to acquire the exclusive *usage* lock and
cleaning the package, that is in use.
(Alternatively we could have used just one *usage* lock and upgrade it from
shared to exclusive if the operation would be available for all types of
locks. Unfortunately this is not true for flock/fcntl based locks in
linux/bsd system. While the upgrade/downgrade operation is available it is
not guaranteed to be atomic, therefore we risk a race condition. See
respective man pages for more clarifications. Therefore it's not an option)
If the process crashes or is killed all the
locks held by it would be released. This is ensured by nature of flock/fcntl
locks and is obviously true for eventlet-based locks. Therefore new process
would not get deadlocked by those locks.
Limitations
-----------
This spec only aims to address the problem of invalidating package cache of
packages, that are outdated.
Solving the problem of invalidating of packages, that have not been used in a
while requires a separate cache-manager, process/service, which in turn would
require additional more fine grained locks to be implemented and it doesn't
look like a real problem right now as the size of the packages is relatively
small and the number of packages in a typical murano installation is not that
large to consume all of the space on the server.
However we should be aware of this situation and probably work on that solution
some time in the future.
Alternatives
------------
One of the alternatives would be to add HTTP headers for caching control, for
example If-Modified-Since. While this is a good idea as of itself it would
impact murano-api, python-muranoclient and murano-engine, thus making it a lot
harder to implement and test.
Instead of having 2-layer locking we could implement spin-locks around file
locks, which doesn't look like a good idea though.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
Since package cache would persist on disk — it would be possible to drain disk
resources by it. This is still possible to do today by creating a really large
amount of simultaneous deployments, although in the current situation the
package cache would be eventually deleted, and space would be reclaimed.
If we believe that this is a serious security flaw — we need to implement cache
invalidation/caps of max cache storage before M release
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
kzaitsev
Work Items
----------
#. Implement caching mechanisms.
#. Implement unit/functional tests.
Dependencies
============
None
Testing
=======
Looks like unit tests would be enough for proper coverage, although
functional tests against race conditions might be benefitial.
Documentation Impact
====================
Usual docs update required
References
==========
* `FreeBSD flock man page
<https://www.freebsd.org/cgi/man.cgi?query=flock&sektion=2>`_
* `Linux flock man page <http://linux.die.net/man/2/flock>`_

View File

@ -1,106 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
================================================
Middleware for external (non-OpenStack) requests
================================================
https://blueprints.launchpad.net/murano/+spec/external-request-middleware
When request is coming to murano (or any other service) from outside of OpenStack
it has no OpenStack-specific requests headers at all. So, it's hard to use
standart middlewares and authentication methods for exteranal requests.
Problem description
===================
Now we need to recreate keystoneclient and get authentication information for each request
which comes from outside of OpenStack using basic auth credentials. This can be look
better if we can use standart keystone middleware for external service requests,
but we don't have enough info (at least token) in the external requests.
Now you can see this behaviour in murano service broker for Cloud Foundry.
Proposed change
===============
Create a new middleware which will handle external requests and add X-Auth-Token
header. This should be enough for keystone middleware and murano context middleware.
Middleware should be added to all external services adaptors (now we have only
service broker). It's not recommended to add it directly to murano-api because
it can be real security issue.
Alternatives
------------
Take everything as it is.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
Developers which will create adapters for external service shouldn't worry about
how it will authenticate and work with murano. They can simply add this middleware
to their applications.
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
starodubcevna
Work Items
----------
* Implement external requests middleware
Dependencies
============
None
Testing
=======
Now this can be tested in a bunch of functional tests for Cloud Foundry service
broker.
Documentation Impact
====================
None

View File

@ -1,218 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
================================================
Mocking machinery for MuranoPL testing framework
================================================
https://blueprints.launchpad.net/murano/+spec/mocking-machinery
Currently we have separate executor, that allows to run MuranoPL code in
testing mode without dashboard. But the main purpose of this executor is to
provide 'mock' availability. This specification describes how this can be done.
Problem description
===================
It's not possible to provide unit-testing without mocking machinery.
The whole idea of murano simulation mode was in deployment imitation.
During the deployment of murano applications, a lot of external objects,
that are not connected to the app itself are involved, such as *murano agent*,
*networks*, *heat stacks* and etc.
All of the classes that should be mocked can be divided into:
* python classes
* yaml classes
* dependent applications
Mocks can really help with new application development (especially compound
ones).
Mock implementation will enable:
* Real deployment simulation
* Run several deployments with different parameters
Actually, list of use-cases is unlimited, since user will be allowed to provide
any alternative function implementation to speed up the development.
Proposed change
===============
Test-runner executor should have new context manager, that will take into
consideration specified mocks. Mocks will be specified with new global YAQL
function.
This will be first step to enable mocking. Later improvements will be added and
described in a separate specification.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None. Will be not available in the previous murano versions.
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None, only new opportunity for developers
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
<efedorova@mirantis.com>
Work Items
----------
#. Create MockContextManager.
Context manager is responsible for providing a valid context with
corresponding attributes and functions for the current object.
Modified context manager will be used for mock implementation. It will be
inherited from the original one and will be called ``MockContextManager``.
It will store instructions which objects or classes are needed to be
replaced with mocks and return context with mock definition instead of the
original function. For that purpose several dictionaries should be used:
one for mapping objects with mocks and other one for class mapping.
If mock for the current object exist, new linked context
(``murano.dsl.linked_context.LinkedContext``) will be returned. It links
existing context with the new context, where mock definition is presented.
So if mocked function will be called, context will contain two
definitions with that function: mock and original one, but mock will have
higher priority.
If there is no mock for the current object or class, existing context
will be returned. If there is no existing context, *None* will be returned.
#. Add global YAQL functions (it will be available only in test-runner mode) to
set scope of mocking and mock definition. It will be called ``inject`` and
will have several declarations for different purposes:
* ``inject`` for set up mock for *class* or *object*, where mock definition
is a *name of the test class method*
* `def inject(target, target_method, mock_object, mock_name)`
* ``inject`` for set up mock for *a class* or *object*, where mock
definition is a *YAQL expression*
* `def inject(target, target_method, yaql_expr)`
Description:
* *target*: MuranoPL class name (namespaces can be used or full class name
in quotes) or MuranoPL object
* *target_method*: Method name to mock in target
* *mock_object*: Object, where mock definition is contained
* *mock_name* Name of method, where mock definition is contained
* *yaql_expr*: YAQL expression, parameters are allowed
So user is allowed to specify concrete method to use instead of original,
or to provide YAQL expression from which new function will be composed.
Advantages of defining mock with YAQL expression:
* Simplicity
Thus, if you need your methods to return different constants, you can
return it inline instead of creating different methods for each constant.
* Restricted context
By default Local variables are not seen in the mock function scope, but
it's possible to specify which variables to pass to the expression.
#. Add `withOriginal` YAQL function
* `withOriginal(a => $x, b => $y)`
YAQL function, registered in the mock context.
Allows to pass values from the original context to the mock context,
where mock function is executed. Suppose, we have ``$x: 2`` in the mock
function and ``$x: 1`` in the original function. We can not just combine
the contexts since we want to use both 'x' variables and it will be
unclear which. With new YAQL function original variables can be passed to
a mock context with configurable name. So original context need to be
saved in advanced and ``withOriginal`` function should have access to it.
* `originalMethod()`
YAQL function, registered in the context of inject function.
Calls the original method and can be used in a mock function.
#. Add `OneOf` Smart type
In new function for injection mock parameter can be class or object.
So we need to accept one of those. This new type will check function
parameter for belonging to one of type in the provided list.
Dependencies
============
None
Testing
=======
New code should be 100% covered by unit tests.
Documentation Impact
====================
Separate documentation for the whole test-runner and mock machinery will
be provided.
References
==========
None

View File

@ -1,161 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=======================
Multiple engine workers
=======================
URL of launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/multiple-engine-workers
This specification is to implement multiple workers to murano-engine.
Problem description
===================
murano-engine is currently single process. It's a problem for scalability.
Proposed change
===============
Implement multiple workers to murano-engine by oslo.service library.
When starting service, murano-engine forks the number of workers which is
written in configuration file. When a configuration reload is required, restart
service is needed. If child process is killed, murano-engine forks new worker.
Most of the OpenStack projects use oslo.service.
Alternatives
------------
There are some external tools.
Configuration management tool such as Puppet, Chef, Ansible
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Configuration management tool controls services which is managed by init systems
like systemd, upstart. Configuration management tool does not manage processes.
Init systems
~~~~~~~~~~~~
Systemd, upstart are init systems of Unix like systems. Upstart is default init
system until Ubuntu 14.10 or RHEL6. Systemd is default init system of Ubuntu
15.04 or RHEL7, and other Linux systems.
Systemd manages processes based on configuration file. If process spawns child
processes, systemd recognizes child processes properly and manages under single
control group by a configuration file. Systemd can be configured automatically
restart process on crash but does not have ability to spawn process.
Supervisor
~~~~~~~~~~
Supervisor is time-proven process management tool written in python.
Supervisor can control a number of processes on UNIX-like operating systems.
Supervisor starts processes as subprocesses , so can true up/down and can be
configured automatically restart them on a crash.
Supervisor has good function itself, but must managed by init systems and
considered high availability. Supervisor is not working under Python 3. The
whole Openstack and murano are going to support python 3. This is not
appropriate for alternatives.
Combination of configuration management tool and systemd can be altenative for
implementing multiple processes. configuration management tool deploys services,
each service manages single murano-engine process.
Both proposed change and alternative can process restart if process crashed.
Proposed change can manage multi processes easier than alternative. Proposed
change has main process which spawns child processes. If you change the number
of processes, update configuration file and then restart service. On the other
hand, alternative needs to rewrite conf file of configuration managenment tool
and redeploy.
Proposed change can manage control group of murano-engine processes easier than
alternative. Because proposed change can change control group settings by update
a configuration file of systemd. On the other hand, alternative needs to update
each confifiguration file of systemd.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
The number of murano-engine workers config option is added in
murano.conf under engine section named workers. The default value
is oslo_concurrency.processutils.get_worker_count().
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
<nakamura-h>
Work Items
----------
* Add the number of murano-engine workers config option to murano.conf
* Replace oslo_service.service.ServiceLauncher with
oslo_service.service.launch in murano.engine.cmd module.
Worker parameter of oslo_service.service.launch method takes
the number of murano-engine workers config option.
Dependencies
============
* oslo_concurrency
Testing
=======
* Unit tests on murano-engine
Documentation Impact
====================
None
References
==========
* `Oslo.service <https://github.com/openstack/oslo.service>`_
* `Puppet <https://github.com/puppetlabs/puppet>`_
* `Chef <https://github.com/chef/chef>`_
* `Ansible <https://github.com/ansible/ansible>`_
* `Upstart <http://upstart.ubuntu.com/>`_
* `Systemd <http://www.freedesktop.org/wiki/Software/systemd/>`_
* `Supervisor <http://supervisord.org/>`_

View File

@ -1,222 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=================================================
MuranoPL metadata to properties, classes, methods
=================================================
https://blueprints.launchpad.net/murano/+spec/metadata-in-muranopl
MuranoPL metadata is a way to attach additional information to various MuranoPL
entities such as classes, packages, methods etc. That information might be used
by both applications (to implement dynamic programming techniques) or by the
external callers (API consumers like UI or even by the Murano Engine itself
to impose some runtime behavior based on well known meta values).
Problem description
===================
With time and development of the language new challenges arrived and MuranoPL
need to be extended with new keywords for new features. For example, it may
be needed to mark some method as the one that serves special purpose to
distinguish it from other methods in the program workflow. Let's say one
wants to obtain the list of all methods within the class and choose only
methods that can be called by the unprivileged user. The one way to do
it is to introduce a new possible value for the `Usage` attribute, something
like `Usage: Non-admin`. Another way is to introduce even new keyword. The
problem is that every application developer may need to attach different kinds
of such information depending on the needs of their apps, and the range of
these needs can be endless. With the current approach, every new sort of
additional information requires modification of the core MuranoPL language
code.
In order to solve this problem, metadata will be used to store new
information about various MuranoPL entities. With this new feature MuranoPL
will become more flexible and go away from the "new keyword for new feature"
rule. All the developer will need to do is to define his own kind of data he
wants to apply to the elements of his application (in the form of the custom
MuranoPL class) and use it.
Proposed change
===============
The proposed solution is to introduce another type of classes - meta-classes.
Meta classes are similar to regular classes but has additional attributes
that control how and where instances of that meta-class can be attached.
To distinguish meta-classes from regular classes new class-level attribute
will be introduced called `Usage`. When `Usage` is `Class` (which is a default)
the rest of markup is interpreted as a class. Usage `Meta` is used to define
meta-class.
In addition to Usage the following attributes are available for meta-classes:
#. `Cardinality` - either `One` or `Many` - controls if there can be more than
one instance of the meta-class attached to a single language entity.
Default is `One`.
#. `Applies` - one of `Package`, `Type`, `Method`, `Property`, `Argument` or
`All` - controls to which of the language entities instances of the meta-
class can be attached. It is possible to specify several values using YAML
list notation. Default is `All`.
#. `Inherited` - `true` or `false` - specifies if the metadata retained for
child classes, overridden methods and properties. Default is `false`.
Now, let's take a look at the examples of the meta-class in MuranoPL:
.. code-block:: yaml
Name: FooMetaOne
Usage: Meta
Applies: Property
Cardinality: One
Properties:
description:
Contract: $.string()
Default: null
count:
Contract: $.int()
Default: null
.. code-block:: yaml
Name: FooMetaMany
Usage: Meta
Applies: [Property, Method]
Cardinality: Many
The instances of meta-classes will never have an owner and thus cannot use
`find()` function.
Instances of `FooMetaOne` class can be attached to properties only and each
property may have at most on attached `FooMetaOne` instance.
To attach this class to a property is used `Meta` keyword in a property
description.
.. code-block:: yaml
Namespaces:
=: io.murano.apps.apache
std: io.murano
res: io.murano.resources
sys: io.murano.system
meta: io.murano.meta
Name: ApacheHttpServer
Extends: std:Application
Properties:
enablePHP:
Contract: $.bool()
Default: false
instance:
Contract: $.class(res:Instance).notNull()
Meta:
meta:FooMetaOne:
description: "Stub metaclass"
count: 2
In example above Meta keyword has a scalar value because it is only one
instance get attached. However it can also be an array:
.. code-block:: yaml
Meta:
- meta:FooMetaOne:
description: "Stub metaclass"
count: 2
- meta:FooMetaMany:
- meta:FooMetaMany:
Metadata can be accessed from MuranoPL using reflection capabilities and from
Python code using existing yaql mechanism (additional yaql smart type/helper
interface may be needed to simplify the task).
Alternatives
------------
Add new keyword for new feature when we need it.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
starodubcevna
Work Items
----------
#. Create a new basic class instead of `MuranoType`.
#. Create 2 new classes which will inherit from new basic class - one for regular
data structures and the other one will be `MetaAttribute`.
#. Provide possibility to create instances of meta-classes.
#. Provide an access to meta-classes.
#. Create a mechanism to attach instances of meta-classes to related objects and
store it.
Dependencies
============
None
Testing
=======
New unit tests should be added to packages.
Documentation Impact
====================
New documents about metadata usage should be added to the documents pool.
References
==========
None

View File

@ -1,169 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=======================
Pluggable Package Types
=======================
URL of launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/pluggable-package-types
This spec is about making possible to support different package formats
(besides `MuranoPL/1.x` and `Heat.HOT/1.0`) via package format plugins.
Problem description
===================
There are many different formats that can be used to describe applications
besides MuranoPL. Currently Murano supports 2 package types `MuranoPL/1.x` and
`Heat.HOT/1.0`. However because they both are parts of Murano source codes
it is impossible to add additional types without merging them into main source
tree thus making Murano team responsible for all of them.
Proposed change
===============
It is proposed to have support for non-MuranoPL packages the same way HOT
support is implemented: by dynamic generation of MuranoPL code at run time.
However the package types themselves need to be pluggable so that anyone
could extend Murano with additional package type by installing corresponding
plugin.
It is proposed to use stevedore library and similar approach to how MuranoPL
python plugins are currently handled.
Package types plugins will be identified by dedicated namespace
`io.murano.plugins.packages`. To specify package type one should append to
plugin's `setup.cfg` file
.. code-block:: ini
io.murano.plugins.packages =
FORMAT_STRING = CLASS_IDENTIFIER
For example:
.. code-block:: ini
io.murano.plugins.packages =
Cloudify.TOSCA/1.0 = murano_cloudify_plugin.cloudify_tosca_package:CloudifyToscaPackage
If target package type requires some utility to construct it (e.g. put right
files in right folders, zip them, generate manifest and so on) than it
should also be included in the plugin as additional shell endpoint.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None. There cannot be 2 versions of the same plugin simultaneously.
However single plugin may support several different package formats including
severals different versions of the same format using single of several Python
classes. Version number remains part of format string.
Other end user impact
---------------------
None
Deployer impact
---------------
Plugins need to be deployed to each Murano node (or to all machines running
either Murano API or Murano Engine) in order to support particular package
type. Installation is done as usually in python (`pip install PATH` or
`python setup.py install` etc.)
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
Stan Lagun <slagun@mirantis.com>
Work Items
----------
1. Refactor current package class hierarchy, change order of `__init__`
parameters so that format name and version will become the first two.
This is required because they will be supplied automatically by plugin
loader.
#. Implement plugin loader that would find all installed stevedore plugins
in `io.murano.plugins.packages` and build internal mapping
format name/version -> Python implementation class
#. Add function to register in that mapping implementations that remain inside
Murano sources like MuranoPL package type
#. Add method to retrieve `Package` instance of supplied format name/version.
Plugin-loader should return class factory that will instantiate appropriate
Python class for particular format by substituting first 2 arguments
(format name and version) while the rest arguments will be supplied by the
caller.
#. Refactor `load_utils` to use plugin-loader rather than its own hardcoded
mapping.
Dependencies
============
stevedore library
Testing
=======
Testing can be performed by attempt to deploy application that is not in
native Murano format like TOSCA is.
Documentation Impact
====================
Guide that tells how to develop custom package type plugins need to be
published.
References
==========
None

View File

@ -1,260 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
===========================
Public Environment Template
===========================
URL of launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/abstract-env-template
Continuing with the environment template catalog blueprint, which allowed
to store complex architecture for applications, an abstract environment
template catalog can be included.
It involves the existence of an environment template catalogue independent
on any user, which can be customized by anyone to include their concrete
information (e.g. keypair).
Concretely, it involves all the operations to manage environment templates
(creation, deletion, updating), plus the customization done by the user.
At the end, the customized environment template can be launched and converted
into an environment
Problem description
===================
MURANO environment template catalogue is composed by environment templates
which belong only to its owner. Thus, it is not possible to share or
reuse environment templates among tenants, since all are privates. The
idea is to have the possibility to have public templates beside private one,
which can be reused and customized by other tenants. In this
way the abstract environment template catalogue will be composed by all public
environment template from all tenants.
Proposed change
===============
Including public environment templates in MURANO requires to modify the
environment template entity in the model to include a property "is_public",
which describes whether the template is public or private. In addition, it is
required to extend the API to allow for obtaining all public environment
templates from all tenants, or customizing a concrete environment template
from another tenant.
Alternatives
------------
None
Data model impact
-----------------
A new property will be include in the environment template model.
environment-template :-
murano:property(temp_id, "is_public", bool)
REST API impact
---------------
The inclusion of the environment-template entity will imply the extension of
the API for the environment-template creation, deletion, updating and
translate into the environment.
**GET /templates?is_public=true/false**
*Request*
+----------+-----------------------------+-----------------------------------+
| Method | URI | Description |
+==========+=============================+===================================+
| GET |/templates?is_public | Get all public/privates template |
| | | from the tenant or all tenants. |
+----------+-----------------------------+-----------------------------------+
*Parameters:*
+----------------+-----------------------------------------------------------+
| Parameter | Description |
+================+===========================================================+
| `is_public` |boolean, indicates whether public environment templates are|
| |listed or not. |
+----------------+-----------------------------------------------------------+
Concretely, it is possible to have the following cases:
* GET /templates?is_public=true. All public templates from all tenants will be
returned.
* GET /templates?is_public=false. All private templates from current tenant
will be returned.
* GET /templates. All templates from current tenant plus all public templates
from all tenants will be returned.
* **Content-Type**
application/json
*Response*
::
[{
"updated": "2015-01-26T09:12:53",
"name": "env_template_name1",
"created": "2015-01-26T09:12:51",
"tenant_id": "00000000000000000000000000000001",
"version": 0,
"is_public": true,
"id": "aa9033ca7ce245fca10e38e1c8c4bbf7",
}
{
"updated": "2015-01-26T09:12:55",
"name": "env_template_name2",
"created": "2015-01-26T09:12:51",
"tenant_id": "00000000000000000000000000000082",
"version": 0,
"is_public": true,
"id": "aa9033ca7ce245fca10easdfasdfadsfaasdf",
}]
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Environment Templates obtained successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to perform the operation |
+----------------+-----------------------------------------------------------+
**POST /templates/{env-temp-id}/clone**
*Request*
+----------+------------------------------+-----------------------------------+
| Method | URI | Description |
+==========+==============================+===================================+
| POST |/templates/{env-temp-id}/clone|It clones a template from one |
| | |tenant to another, changing its |
| | |name, its tenant-id and its public |
| | |availability if required. |
+----------+------------------------------+-----------------------------------+
*Parameters:*
* `env-temp-id` - environment template ID, required
*Example Payload*
::
{
'name': 'cloned_env_template_name'
}
*Content-Type*
application/json
*Response*
::
{
"updated": "2015-01-26T09:12:51",
"name": "cloned_env_template_name",
"created": "2015-01-26T09:12:51",
"tenant_id": "00000000000000000000000000000001",
"version": 0,
"is_public": false,
"id": "aa9033ca7ce245fca10e38e1c8c4bbf7",
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Environment Template cloned successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to perform the operation |
+----------------+-----------------------------------------------------------+
| 404 | The environment template does not exit |
+----------------+-----------------------------------------------------------+
| 409 | Conflict. The environment template name already exists |
+----------------+-----------------------------------------------------------+
Versioning impact
-------------------------
None
Other end user impact
---------------------
As well as a change in the API to include this new entity, the
python-muranoclient will be changed for including the environment template
clone.
* env-template-clone Clone the environment template.
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
New views will be required for including the public template catalog and the
clone functionality.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
hmunfru
Other contributors:
jesuspg
Work Items
----------
1. Including the is_public in the model
#. Extension of the environment template API for the is_public parameter.
#. Extension of index operation and creation of clone functionality in API.
#. Adding functional tests.
Dependencies
============
Testing
=======
Unit and functional tests should be implemented.
Documentation Impact
====================
Environment template documentation should be included.
References
==========

View File

@ -1,272 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=============================
Support for OpenStack regions
=============================
Related blueprints:
https://blueprints.launchpad.net/murano/+spec/default-region-for-services
https://blueprints.launchpad.net/murano/+spec/assign-environment-to-region
Many if not most production grade OpenStack installations are comprised of
several so called OpenStack Regions - autonomous OpenStack clouds joined
together through shared Keystone identity server and managed through common
interface. However Murano is not region-aware and not always works correctly in
such setups.
Problem description
===================
There are several possible topologies for multi-region deployment:
#. There is a copy of all murano services at each region. Environments
consume resources in (or in other words get deployed to) the same regions
that murano-api/murano-engine run in. Because each murano-api instance is
going to use independent database each regions will have its own list of
environments, packages etc.
#. Single murano-engine is capable of deploying environments to different
regions. In this case environment gets deployed in one specific region but
not necessary the one engine is located in. The target region is chosen
according to attribute of the environment rather than location of the the
engine. Because in this case region of murano services is independent from
target environment region it is still possible that murano services are
present in more than one region up to the case where there is a copy in each
region and each one of them is capable of deploying applications to any of
the regions (but still each region has its own database and everything it
implies).
#. Single environment may contain applications and/or components that deploy
into different regions. Because environments cross region boundaries it is
no longer single heat stack per environment and applications, components and
resources need to be associated with regions and with stacks.
In the list above each subsequent item includes and extends the previous one
and thus can be implemented in turn.
This specification covers first two items because they can be implemented
without introducing major changes to applications design or existing Heat
API bindings.
Proposed change
===============
Only a few minor changes are needed in order to enable basic region support:
* Murano-engine should probe for correct region when querying endpoints from
keystone's service catalog.
* Add attribute (property) to the Environment class saying what is the
target region for the environment.
* Improve murano-dashboard with ability to select target environment.
Alternatives
------------
None
Data model impact
-----------------
Optionally target region name for the environment can be extracted from
object model and put into a separate column in environment/session tables.
This will allow to filter (group) environments that target different regions
in dashboard.
REST API impact
---------------
None
Versioning impact
-----------------
Because the changes are backward compatible a minor version component of
the core library need to be incremented (possibly by the end of Mitaka cycle).
Other end user impact
---------------------
For each OpenStack setup that has more than one region Horizon will
automatically presents user a drop-down that allow to switch between API
instances in different regions and thus see independent lists of environments,
packages etc. Nothing need to be done from murano side here.
In addition there should be a way to select target region for particular
environment independently of currently selected API region. However this
setting should remain optional and not affect existing user experience.
Murano CLI interface should not require any changes because region selection
for API is already supported using --os-region-name option or OS_REGION_NAME
environment variable. Target region name of environment is an ordinary
environment property as is set using all the same interface.
Deployer impact
---------------
Each region that has a copy of murano needs to have murano-api and
murano-engine as well as its own RabbitMQ for api to engine and engine to
agents communications (this can be either one shared or two independent
instances of RabbitMQ). Thus murano in different regions will have different
configuration files. In the same time the version of murano itself must be the
same in all regions. In addition service endpoint of each murano-api needs to
be registered in keystone.
In scenario where single murano instance can deploy to different regions it
might be that it is required to use different RabbitMQ instances in different
regions in order for engine to communicate with murano agents. Because
RabbitMQ instances are currently not registered in keystone service catalog
address and credentials for all RabbitMQs need to be put into murano config
file.
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
* Additional control (drop box with region names) is added to environment
configuration form.
* Dashboard need to correctly handle situation when murano is present only
in some of available regions.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
Stan Lagun <slagun>
Work Items
----------
Add setting that specifies default region name
``````````````````````````````````````````````
murano-engine needs to be aware what OpenStack region it belongs to.
When deploying environment that doesn't explicitly target some particular
environment (as it is now) this setting will control in what region should
a Heat stack be created. We assume that there is a Heat instance in each
region so we just need to use correct endpoint of the heat API.
There is already a setting `region_name_for_services` but it is located in
the wrong section ([murano] rather than [DEFAULT]).
Make ClientManager region aware
```````````````````````````````
There is a class in murano-engine that responsible for creation of specific
service clients. Typical workflow is to ask keystone for an endpoint of
desired type (using url_for() function) and then pass the endpoint to client's
`__init__` method. However in multi-region setups there can be several
endpoints for each service that differ by region name.
ClientManager's methods need to be extended with optional `region_name`
parameter to be used for url_for(). If no region name specified by the caller
then default region name must be used.
Two work items above alone is enough to enable first use case for regions.
Add region property to the Environment
``````````````````````````````````````
Add optional string property to the Environment class that will hold target
region name for the environment.
OpenStack API binding classes (like `HeatStack` and `NetExplorer`) that
internally request a client instance from ClientManager need to modified to
pass a region name of environment they are belong to (can be None)
Note, that murano-client must always use the default region endpoint because
it is used to update environment status and download packages and this is
always done in current region rather then in one we're deploying to.
Also optionally value from this property can be replicated to a dedicated
column in database so that it will be possible to filter on.
Extend [rabbitmq] configuration setting group
`````````````````````````````````````````````
Murano uses RabbitMQ to interact with guest-VM agents. But for multi-region
setup it is desirable to have dedicated RabbitMQ instance in each region.
Thus a single section with RabbitMQ parameters is not enough.
Instead it is proposed to have variable number of sections with a common
format [rabbitmq_RegionName] (i.e. [rabbitmq_RegionOne]).
When somebody needs RabbitMQ parameters it need to look in region specific
section and only if it is not present (or some particular setting is absent)
look in [rabbitmq] that now can be used to hold default values.
This will requre modifications to both Agent/AgentListener classes and
LinuxMuranoInstance/WindowsInstance core library classes.
Add UI control to environment configuration dialog
``````````````````````````````````````````````````
In order for introduced Environment property to get non-default value
a control need to be added to environment configuration form in dashboard.
It should be a drop-down with region names with possibility to leave it empty
to user server default.
A change of the region must also reset a network selection control because
the selected region is likely to have another set of networks.
Check that dashboard works when murano is missing in some regions
`````````````````````````````````````````````````````````````````
Murano services may be present just in one or in some of available regions.
Selection of region that doesn't run murano must not lead to errors.
Instead user must be presented with a message saying that it is impossible
to create environment in this region (or upload a package etc). However
this region can still be a target for environments in other regions.
Dependencies
============
None
Testing
=======
We should test application deployment with all possible combinations of
API region and environment region (which can be absent). In addition to manual
testing it would be good to improve automated CI tests to deploy applications
to different regions. However it will requires multi-region OpenStack setup for
tests.
Documentation Impact
====================
* Config settings that affect region selection need to be documented in
murano configuration guide.
* Changes made to UI need to be documented in user's guide.
References
==========
None

View File

@ -1,259 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
===============
Service API SDK
===============
https://blueprints.launchpad.net/murano/+spec/service-api-sdk
This specification defines the design of Murano Service API SDK - a high level
client library allowing cloud applications (both murano-deployed and external)
to access applications's Service API in consistent, convenient and secure way.
Problem description
===================
Service API is a way for murano applications to expose their configuration and
lifecycle & maintenance actions for other cloud applications, users and
administrators.
Since murano is designed to be a single integration point for applications in
the cloud, all the interactions with service APIs of deployed apps should be
done via Murano API by either of the two ways:
* Modifications of Object Model, i.e. changes of declarative definition of app
configuration;
* Calls of MuranoPL methods explicitly marked as externally executable actions.
Both these ways of interaction assume some deep and low-level work with murano
API: they require to fetch the object model from the environment, inspect it,
modify according to all the contracts and constraints, call appropriate methods
and so on. This does not bother end-users and administrators since the actual
API is hidden from them by various UI and CLI tools, but becomes a problem for
third-party software solutions since they have to interact with the API
directly and thus have to possess deep knowledge of murano internals.
If we want the cloud applications to be able to interact with each other via
murano we need to provide some higher level client library which will
encapsulate all the murano-related specifics and will provide the clients with
clean and streamlined software interface.
The primary consumers of this SDK library will be the developers of cloud
applications. This applications will integrate with SDK thus obtaining high
level access to their own (and their peers') service API exposed via murano.
Proposed change
===============
It is proposed to add a new set of python classes (distributed either as a
standalone pypi package or as a new module in python-muranoclient package)
which will provide a set of high level calls to murano API returning
dynamically constructed python objects representing appropriate entities of
object model. The attributes of these objects will match appropriate Input or
Output properties of their corresponding MuranoPL objects.
Consumer's code will be able to modify the values of Input (or InputOutput)
properties but only if the value being set matches the contracts of that
properties. Output properties are readonly, so attempts to modify the
corresponding python attributes will lead to exceptions.
The SDK will provide a context manager object creating a new session in the
given environment. Each property assignment being done within an appropriate
"with" code block will result in an API call immediately modifying the object
model of appropriate session. When the execution exits the "with" block the
session will be "committed", i.e. the changes will be copied to the main
environment object model. The SDK may be configured to automatically redeploy
the environment after commits.
The pythonic objects generated by the SDK will contain methods corresponding to
publicly-exposed MuranoPL methods ("actions"). Calling these pythonic methods
from the consumer code will execute appropriate actions. The parameters of the
called methods will be evaluated to match the contracts of appropriate MuranoPL
method arguments prior to calling the actual murano action API. These
dynamically generated methods will have names matching the names of appropriate
actions.
It will be possible to call these methods either synchronously or
asynchronously. In the former case the call will block the execution until the
action execution completes, so the method calls return final result, while the
actual execution will do polling on Action API under the hood. In the latter
case the action execution will be initiated, but the call will immediately
return a "Future" object which may be used later to retrieve the result (in a
single call if the action is already completed at that moment or by polling if
not).
The SDK will provide a factory class capable to create and configure the
instances of the client based on a set of configuration values. It should allow
passing these values both manually and reading them from a file in a specific
format. The latter will be used when the SDK access is provided to a virtual
machine deployed via murano: if the SDK access is granted to it the
configuration file will be delivered to the VM as part of the provisioning
process, so the SDK will be able to load it from the well-known location.
Deployment of SDK on the VMs may be done manually by the application developers
(e.g. they may include the dependency on appropriate python package in the
requirements.txt file of their python distribution), but it may be beneficial
to simplify this process by providing appropriate methods in the base class of
Standard Library: having a `deploySdk` method in the `LinuxMuranoInstance`
class will allow applications to easily deploy the SDK on its VMs with a single
call of a MuranoPL method. Such deployment will also sent a set of
configuration settings which will allow the SDK to properly connect to and
authenticate with murano API.
The SDK will include the authentication tooling: a set of utilities which will
allow applications to request access to murano API and the user to grant it.
This particular part is out of scope for this specification and should be
described separately.
Alternatives
------------
As an alternative to this SDK the client code could use regular Murano API
without any wrappers around it. This requires more efforts from application
developer and thus should be used only if the SDK does not provide the required
functionality.
Security Impact
---------------
Any consumers of Murano API should be properly authenticated to access its
resources. The regular users will use usual keystone-based authentication by
obtaining an access token using their username and password. However the
third-party applications which are the primary consumers of the SDK described
in this spec cannot be trusted with actual users credentials. Instead some role
delegation system should be used: based on trusts, OAuth delegation or
something else.
An authentication token of some kind should be delivered to VM and become part
of the SDK configuration file; this token will allow the SDK to authenticate in
murano API. This token will be scoped to
A separate spec is required to to describe the trust system, access scopes and
the changes which have to be introduced to support all of them in Murano.
Data model impact
-----------------
No model impact
REST API impact
---------------
To properly support transaction-like changes in Object Model the session API
needs to be improved to support session "commits" without the actual
deployments.
A new API call will be added:
* Complete Session
* Completes the session, thus merging its object model back to the
environment
* Method type: POST
* Normal http response code(s): 200
* Expected error http response code(s):
* 409 if the merge cannot be done due to a conflict, i.e. if the same parts
of the object model were modified by a another recently completed session
* 403 if the environment is being deployed
* URI: /v1/environments/%environment_id%/sessions/%session_id%/complete
* URI parameters:
* environment_id - id of the environment
* session_id - id of the session
Versioning impact
-----------------
Since the session completion operation adds a new call to murano API a minor
API version should be incremented
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
Application developers will need to be familiar with SDK, as well as with the
ways to authorize their VM-based apps to access it.
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
ativelkov
Work Items
----------
* Introduce API changes
* Create the SDK classes in python-muranoclient or standalone library
* Add helper methods to automate SDK deployments on the VMs provisioned by
murano-deployed applications.
Dependencies
============
* Authentication tooling has to be implemented before this SDK is created
Testing
=======
* The internals of the SDK should be covered by unit and functional tests.
* All the API calls utilized by the SDK should be covered by the integration
tests.
Documentation Impact
====================
The SDK has to be clearly documented so the application developers know how to
use it.
References
==========
None

View File

@ -1,216 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=======================================
Support Berkshelf for Chef applications
=======================================
URL of launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/support-chef-berkshelf
The goal of this specification is to make possible the use of Berkshelf
(http://berkshelf.com/) to manage Chef cookbooks dependencies when Chef is
used to configure a VM.
Problem description
===================
Currently, Chef is one of the types supported in the Execution plan template.
A Chef provider included in murano-agent gets the Chef cookbooks, generates
the node specifications file and executes chef-solo to configure the VM.
When a cookbook depends on other cookbooks, every transitive dependency must
be made available before executing Chef. That means that the dependencies
metadata for each cookbook must be recursively inspected by the creator of
the Murano package and added to the required files in the Execution plan
template.
Example from murano-apps::
Scripts:
executeRecipe:
Type: Chef
Version: 1.0.0
EntryPoint: git::default
Files:
- git: https://github.com/jssjr/git.git
- yum-epel: https://github.com/chef-cookbooks/yum-epel.git
- yum: https://github.com/chef-cookbooks/yum.git
- dmg: https://github.com/opscode-cookbooks/dmg
- openssl: https://github.com/opscode-cookbooks/openssl.git
- chef-sugar: https://github.com/sethvargo/chef-sugar.git
- chef_handler: https://github.com/opscode-cookbooks/chef_handler
- windows: https://github.com/opscode-cookbooks/windows
- build-essential: https://github.com/opscode-cookbooks/build-essential
Options:
captureStdout: true
captureStderr: true
This list of cookbooks is painful to maintain and error-prone. Furthermore,
a Chef cookbook can require a specific version or a range of versions for its
dependencies. Therefore, the master branch or a git repository does not contain
necessarily the right version of the cookbook. Versions resolution for the
whole dependency graph is not an easy task to execute manually. That is why
using a tool dedicated to this task is useful.
Proposed change
===============
It is proposed to add two new possible options to the Execution plan template.
These options will be available only with the Chef executor (options are
executor-dependent):
* ``useBerkshelf`` (optional, default ``false``)
* ``berksfilePath`` (optional, used only if ``useBerkshelf = true``)
If ``useBerkshelf`` is not set or set to ``false``, the Chef executor will
work as now.
If ``useBerkshelf`` is set to ``true``, the Chef executor will
expect Berkshelf to be present on the VM, and will use it to manage the
cookbooks dependencies.
In that case, the Chef executor will use Berkshelf and the *Berksfile* found on
``berksfilePath`` to *vendor* the package and its dependencies.
Dependency and version resolution is done by Berkshelf using the Berksfile.
The Chef executor will then specify to chef-solo the location of the cookbooks.
If ``berksfilePath`` is not provided, its default value is
``<cookbookName>/Berksfile``, where ``<cookbookName>`` is taken from the
``EntryPoint`` value. For example, if ``EntryPoint = example::default``,
default value for ``berksfilePath`` is ``example/Berksfile``.
A Murano package creator wanting to use Chef with Berkshelf will have to
provide a link to the URL of a repository containing the main cookbook.
Example::
|__ Classes
│   |__ Example.yaml
|__ logo.png
|__ manifest.yaml
|__ Resources
│   |__ DeployExample.template
|__ UI
|__ ui.yaml
With ``DeployExample.template``::
FormatVersion: 2.1.0
Version: 1.0.0
Name: Deploy example
Body: |
return executeRecipe(args).stdout
Scripts:
executeRecipe:
Type: Chef
Version: 1.0.0
EntryPoint: example::default
Files:
- example: https://github.com/cookbook/example.git
Options:
captureStdout: true
captureStderr: true
useBerkshelf: true
In that example, the *berksfile* is found on ``example/Berksfile``, in the
root directory of the git repository.
Alternatives
------------
Librarian-Chef is another tool to manage cookbooks. But Berkshelf is better
integrated in the Chef ecosystem than Librarian-Chef (Berkshelf is actually
part of ChefDK). Furthermore, Librarian-Chef requires the creation of a
``Cheffile``, whereas Berkshelf uses the ``Berksfile`` already included in
every cookbook.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
Minor version of ``FormatVersion`` for the Execution plan template should be
incremented (new feature, backwards-compatible). New ``FormatVersion``
should be ``2.2.0``.
Other end user impact
---------------------
None
Deployer impact
---------------
Berkshelf need to be installed in the VMs to be configured.
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
o-lemasle (Olivier Lemasle <olivier.lemasle@apalia.net>)
Work Items
----------
#. Add Berkshelf support in murano-agent
#. Create DIB elements to include Berkshelf in image
#. Create an example application using Chef with Berkshelf
Dependencies
============
None
Testing
=======
* Unit tests on murano-agent
* Functional tests: deploy an application with Chef template and Chef
cookbooks dependencies in Murano integration tests
(``MuranoDeploymentTest``)
Documentation Impact
====================
Information about how to create Execution plan templates with Chef and
Berkshelf will have to be documented.
References
==========
* http://berkshelf.com/

View File

@ -1,201 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
===================================================
Support TOSCA-Cloudify definitions for applications
===================================================
URL of launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/support-tosca-cloudify-format
TOSCA is a standard developed under OASIS foundation. It is aimed to cover
definition of complex enterprise applications which might consist of different
loosely coupled components. Components can be tied by using requirements and
capabilities which are part of TOSCA standard. As TOSCA covers most of the
Applications aspects (excluding application compilation and build) it should
be straightforward to support TOSCA format in Murano. TOSCA is adopted by
enterprises so it will allow the OpenStack ecosystem to integrate with
enterprise IT applications.
Cloudify is an open source TOSCA-based cloud orchestration software platform
written in Python, and YAML created by GigaSpaces Technologies.
It is licensed under the Apache License Version 2.0
With Murano-Cloudify TOSCA-based integration it will be possible to package
Cloudify-compatible TOSCA applications as Murano packages and deploy them via
Cloudify not necessary on OpenStack but on all cloud platforms currently
supported by Cloudify.
Problem description
===================
Murano currently does not support TOSCA and TOSCA-based applications. With
the growing popularity of TOSCA for describing application orchestrations
it would be nice if murano supports TOSCA-based orchestration templates.
Murano has accepted HOT-translator based TOSCA support but that is not the
only possible TOSCA implementation possible. Cloudify brings alternate
TOSCA solution that is not limited to Heat and OpenStack in general.
One standard for defining TOSCA-based application packages is CSAR
(http://tinyurl.com/tosca-yaml-csar). It is a compressed file that includes the
main application definition template called "blueprint" in Cloudify along with
the supporting templates and files that are referenced in the main template.
This specification addresses adding support for Cloudify blueprints
application packages in Murano application catalog with ability to deploy them
via Cloudify.
Proposed change
===============
Make it possible for Murano packages to ship Cloudify blueprints.
Cloudify blueprints will be stored in the Resource folder of the package.
The manifest will be in the package root folder.
The Cloudify code will be converted to Murano PL code on the fly.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
There should be no user impact. Users who are creating HOT-based packages would
do it the same way as before. Users who are creating TOSCA-based packages would
do it in a similar way. Application packages can be added to environments for
deployment the same way as before too.
There should be also a utility to help users package CSARs into Murano package
but it is out of the scope of this spec.
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
Murano would need to represent TOSCA-based components using a specific
logo, to distinguish them from HOT-based components. This applies to other
specification formats that may come on board in the future.
Implementation
==============
Assignee(s)
-----------
Trammell <trammell@gigaspaces.comx>
Work Items
----------
#. Define new package format Cloudify.TOSCA/1.0 and create a package-type
class that will process packages with such format string.
#. Cloudify Blueprint directory that contains a blueprint in the format
filename.yaml. The name of the file needs to be declared in the
`manifest.yaml` file.
#. From main blueprint yaml file extract information about application
inputs and outputs.
#. Generate UI form definition by generating 1 input field per each TOSCA
input and also generate Application section of UI form that will map
those fields to MuranoPL application class properties.
#. From TOSCA inputs/outputs and manifest data generate MuranoPL class
that will represent TOSCA application. There should be a MuranoPL
property for each TOSCA input and output and usual application methods
as in other Murano applications.
#. In order to avoid generation of complex MuranoPL code create base class
for Cloudify applications that will implement deploy, ``destroy`` and other
common methods. Generated application will inherit from this base class
and implement only application-specific method that will be used by the
base class to get required information (like input values, entry point
name, etc.). Bacause base class is going to be regular MuranoPL class
it will form a separate MuranoPL package that need to be present in
catalog as well. Cloudify package processing code will need to tell
Murano Engine that there is a dependency to that package without
explicitly specifying that in manifest file as normaly done in MuranoPL
packages.
#. For Cloudify application to be able to talk to Cloudify manager and
do the actual provisioning/deployment MuranoPL bindings to Cloudify
rest-client need to be developed. It should provide all required methods
to upload the blueprint, create deployment and execute TOSCA workflows.
#. In base CloudifyApplication class implement common application workflows:
for installation:
#. Provide name of the blueprint file in the Cloudify Blueprint directory.
Cloudify Rest Client will tar that directory and upload the payload
to the Cloudify Manager.
#. Create blueprint deployment (Cloudify term similar to Stack in Heat or
Environment in Murano). Generated application object ID can be used
as a deployment ID
#. Invoke "install" workflow on created deployment. Watch its progress.
for uninstallation (.destroy method):
#. Invoke "uninstall" workflow on previously created deployment.
#. Delete deployment.
Dependencies
============
Applications should be compatible with Cloudify 3.1 (latest GA version - 1)
Testing
=======
#. Follow these instructions to create a Cloudify Manager in a vagrant
box on the same machine as your development environment. From there
#. Add the manager IP to your etc/murano.conf file and install the
plugin.
#. Upload the Cloudify Application Package
(contrib/plugins/cloudify_application).
#. Upload the Nodecellar Example Deployment.
(contrib/plugins/cloudify-nodecellar-example-murano).
Documentation Impact
====================
How TOSCA packages can be added to catalog and deployed should be
documented, perhaps with some examples.
References
==========
* `Cloudify <http://getcloudify.org>`_
* `Tosca-Parser on GitHub <https://github.com/openstack/tosca-parser>`_

View File

@ -1,406 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==========================================
Support TOSCA definitions for applications
==========================================
URL of launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/support-tosca-format
TOSCA is a standard developed under OASIS foundation. It is aimed to cover
definition of complex enterprise applications which might consist of different
loosely coupled components. Components can be tied by using requirements and
capabilities which are part of TOSCA standard. As TOSCA covers most of the
Applications aspects (excluding application compilation and build) it should
be straightforward to support TOSCA format in murano. TOSCA is adopted by
enterprises so it will allow the openstack ecosystem to integrate with
enterprise IT applications.
The suggested approach for adding TOSCA support to murano is to leverage
the heat-translator project, which is an openstack project. Heat-translator is
a command line tool that takes non-heat templates (e.g., TOSCA-based templates)
as an input and produces a heat orchestration template (HOT) which can then be
deployed by heat. The heat-translator functionality is imported as a library.
The benefit of using heat-translator is that it is not TOSCA specific, and
designed to be easily extensible to support any other specification language.
And this flexibility will be transferred to murano as well.
Problem description
===================
Murano currently does not support TOSCA and TOSCA-based applications. With
the growing popularity of TOSCA for describing application orchestrations
it would be nice if murano supports TOSCA-based orchestration templates.
One standard for defining TOSCA-based application packages is CSAR
(http://tinyurl.com/tosca-yaml-csar). It is a compressed file that includes the
main application definition template along with the supporting templates and
files that are referenced in the main template. There is also a required
TOSCA.meta file in the CSAR that provides metadata about the package.
This specification addresses adding support for CSAR-based application packages
in murano application catalog. It can simply be expanded to other formats and
standards that are, or will be, supported by heat-translator.
Proposed change
===============
In order to support the TOSCA CSAR package format there are a couple of use
cases that need to be implemented in murano:
*package-create / package-import*
These commands are currently used to create application definition archives
from HOT templates (diagram below).
::
+------------------+
| Murano |
+--------+---------+
|
package-create(HOT) |
+---------------------> +++
| |
<---------------------+ +++
application definition |
archive (HOT ADA) |
|
|
package-import (HOT ADA) |
+---------------------> +++
| |
| | +-----+ add component
| | | to catalog
| | <-----+ along with
| | its HOT
<---------------------+ +++ template
OK |
|
+
Murano should be able to create similar application definition archives from
templates specified in TOSCA or any other language. Diagram below shows how
this can be achieved for TOSCA CSAR packages.
Note that the TOSCA parsing functionality has been taken out of heat-translator
and put into its stand-alone own OpenStack project, called tosca-parser.
Heat-translator relies on tosca-parser in translating TOSCA specifications.
Both projects are released as PyPI packages.
::
+------------------+ +------------------+
| Murano | | Tosca Parser |
+--------+---------+ +---------+--------+
| |
package-create(CSAR)(1) | |
+---------------------> +++ |
| | validate(CSAR) |
| | +--------------------> +++
| | | |
| | <--------------------+ +++
| | OK |
| | |
| | +-----+ extract |
| | | metadata |
| | <-----+ from CSAR |
| | |
<---------------------+ +++ |
application definition | |
archive (CSAR ADA) | |
| |
| |
package-import(CSAR ADA) | |
+---------------------> +++ |
| | validate(CSAR)(2) |
| | +--------------------> +++
| | | |
| | <--------------------+ +++
| | OK |
| | |
| | +-----+ add component |
| | | to catalog |
| | <-----+ along with |
<---------------------+ +++ its CSAR |
OK | package |
| |
+ +
(1) The package format is provided to the package-create command so murano
knows it has to process a TOSCA CSAR file. This can be done using a 'format'
parameter. Also, target platforms are specified using another parameter so
murano can build a proper UI field accordingly. To guarantee backward
compatibility if no format input is provided 'HOT' is assumed as default.
(2) Re-validation is required to cover cases where the application archive
is manually created or modified.
*Deploying an environment*
For HOT-based packages murano deploys one heat stack per component. Even if
two components are in the same environment they are deployed as their own
stack and independent of each other (diagram below)
::
+----------------+ +----------------+
| Murano | | Heat |
+--------+-------+ +--------+-------+
deploy env | |
+-----------------------------------> +++ |
| | |
+-------+------------------------------------------------------------------------+
| loop | | | | |
+-------+ +------+---------------------------------------------------------+ |
|[for each | opt | | | | | |
|component +------+ | | deploy component's HOT | | |
|in env] |[if component | | +--------------------------------> +++ | |
| |is not already | | | | | |
| |deployed] | | <--------------------------------+ +++ | |
| | | | deployed stack info | | |
| | | | | | |
| +----------------------------------------------------------------+ |
| | | | |
+--------------------------------------------------------------------------------+
| | |
+-------+------------------------------------------------------------------------+
| loop | | | | |
+-------+ | | remove component's stack | |
|[for each previously | | +--------------------------------> +++ |
|deployed component | | | | |
|removed from env] | | <--------------------------------+ +++ |
| | | OK | |
| | | | |
+--------------------------------------------------------------------------------+
| | |
<-----------------------------------+ +++ |
OK + +
A similar behavior can be achieved by introducing TOSCA or other non-HOT
templates. A TOSCA-based package is stored with its TOSCA template(s) (and not
the corresponding HOT template). It may or may not need translation depending
on the platform it is deployed to. Murano passes the CSAR file to
heat-translator. Heat-translator translates the CSAR file if translation is
required for deployment, and then deploys it to the target platform.
Similar to how it is done for HOT templates, proper UI forms will be created
using MuranoPL so users can specify input parameters for the TOSCA template.
The CSAR archive will appear inside the murano package archive in the same
compressed format. This is because murano does not need to process the
internals of the CSAR archive, and the vision is that any piece of information
required from the CSAR will be acquired through tosca-parser. MuranoPL cannot
access the root of the murano archive, and therefore one of the following
options will be implemented:
1. Similar to how attached files to a HOT template are handled put the CSAR
into Resources subfolder at package creation time.
#. Put the CSAR in the root folder and move it to Resources when processing the
unzipped package.
::
+--------------+ +-----------------+ +------------------+
| Murano | | Heat Translator | | Target Platform |
+--------+-----+ +---------+-------+ +---------+--------+
deploy env | | |
+-------------------------> +++ | |
| | | |
+-------+---------------------------------------------------------------------------------------+
| loop | | | | | |
+-------+ +------+-------------------------------------------------------------------------+ |
|[for each | opt | | | | | | |
|CSAR +------+ | | deploy CSAR (platform) (1) | | | |
|component |[if component | | +--------------------------> +-+ | | |
|in env] |is not already | | | | +---+ translate if | | |
| |deployed] | | | | | deployment | | |
| | | | | | <---+ requires | | |
| | | | | | translation | | |
| | | | | | | | |
| | | | | | deploy | | |
| | | | | | +-------------------> +-+ | |
| | | | | | | | | |
| | | | | | <-------------------+ +-+ | |
| | | | | | deployment info | | |
| | | | <--------------------------+ +-+ | | |
| | | | deployment confirmation | | | |
| | | | | | | |
| +--------------------------------------------------------------------------------+ |
| | | | | |
+--------------------------------------------------------------------------------------------- -+
| | | |
| | | |
+-------+---------------------------------------------------------------------------------------+
| loop | | | | | |
+-------+ | | remove deployed CSAR | | |
|[for each previously | | +--------------------------> +++ remove | |
|deployed CSAR | | | | +-------------------> +++ |
|removed from env] | | | | | | |
| | | | | <-------------------+ +++ |
| | | | | OK | |
| | | <--------------------------+ +++ | |
| | | removal confirmation | | |
| | | | | |
+-----------------------------------------------------------------------------------------------+
| | | |
<-------------------------+ +-+ | |
OK + + +
(1) Necessary bindings for the integration of murano and heat-translator will
be implemented similar to existing bindings for HOT.
Alternatives
------------
* An alternative to explicitly providing the format for package-create is
enhancing package-create so it can auto-detect the format of the input
template and act accordingly. This enhancement can be implemented via a
separate blueprint.
* If by the time the deployment functionality is implemented heat-translator
does not yet support deployment, murano's deployment through heat will be
used.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
This should not have any negative impact on versioning. Older versions of
murano would still not support TOSCA-based templates. And the new version
would work with HOT-based templates the same way as before.
Other end user impact
---------------------
There should be no user impact. Users who are creating HOT-based packages would
do it the same way as before. Users who are creating TOSCA-based packages would
do it in a similar way. Application packages can be added to environments for
deployment the same way as before too.
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
Murano would need to represent TOSCA CSAR-based components using a specific
logo, to distinguish them from HOT-based components. This applies to other
specification formats that may come on board in the future.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
vahidhashemian (I would be happy to take the lead on this, but I am hoping
I could leverage the existing knowledge on murano development by having a
co-contributor who knows murano code well).
Other contributors:
TBD
Work Items
----------
In order to support the above use cases murano needs to add functionality for
the pieces where it communicates with heat-translator. This is a break-down of
work items (each work item may be broken further into several patches for
implementation):
1. Enhance package-create command to accept CSAR format, validate the CSAR
package by calling tosca-parser, extracting metadata that comes as part of
CSAR, and eventually building the application definition archive for the
given CSAR (that includes the CSAR file too).
#. Enhance package-import command to accept CSAR-based application definition
archives, re-validate them using tosca-parser, and import them to murano
application catalog.
#. Enhance environment definition by creating a UI form for CSAR-based
applications, asking user for their input parameters and target platform
when adding them to an environment, and storing user-provided inputs along
with the added CSAR-based application.
#. Enhance environment deployment and send CSAR-based components to
heat-translator for, potential translation, and deployment to the user
specified target platform. Also, add support for removal of a deployed CSAR
component when it is removed from a re-deployed environment.
Dependencies
============
Aside from what needs to be implemented inside murano project, heat-translator
would need to implement a couple of new functionalities:
* Tosca-parser currently does not support full validation of TOSCA templates.
Workaround is to call tosca-parser and report errors, if any. To do so, an
option has to be added so it does not expect input parameters (and just
translates to HOT instead of translation and deployment) in case the TOSCA
template requires inputs (`related bug
<https://bugs.launchpad.net/heat-translator/+bug/1464024>`_).
* Tosca-parser needs to fully support translation of CSAR packages to HOT.
* Heat-translator needs to enhance its API and add a 'deploy' functionally
using which it would deploy the given application specification to the
platform of choice.
Testing
=======
Implementation work items above requires a number of overall unit tests each of
which may be broken into smaller unit tests for implementation:
1. Verify package-create for TOSCA CSAR files.
#. Verify package-import for TOSCA CSAR packages.
#. Verify UI form creation for TOSCA CSAR packages.
#. Verify deployment and removal of TOSCA CSAR packages.
Documentation Impact
====================
How TOSCA CSAR packages can be added to catalog and deployed should be
documented, perhaps with some examples.
References
==========
* `Mailing List Discussion
<http://lists.openstack.org/pipermail/openstack-dev/2015-June/065424.html>`_
* `TOSCA YAML CSAR Format <http://tinyurl.com/tosca-yaml-csar>`_
* `Heat-Translator on GitHub <https://github.com/openstack/heat-translator>`_
* `Tosca-Parser on GitHub <https://github.com/openstack/tosca-parser>`_

View File

@ -1,204 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=============================
Clearwater Murano application
=============================
https://blueprints.launchpad.net/murano-apps/+spec/clearwater-vims-implementation
Problem description
===================
It must be possible to deploy and manage lifecycle of Clearwater vIMS.
Clearwater vIMS consists of several components:
* Bono (Edge Proxy)
* Sprout (SIP Router)
* Homestead (HSS Cache)
* Homer (XDMS storage)
* Ellis (provisioning portal)
* Ralf (CTF)
Additionally following DNS server application should be written:
* BIND
Clearwater deployment diagram
::
+----------+
| |
| Ellis |
HTTP | |
+------+ +-----+
| | | | HTTP
| +----------+ |
| |
+-----+-----+ +-----+-----+ +------------------+
| | | | | |
| Homer | | Homestead | |Client SIP software
| | XCAP SIP | | | |
| +--+ +--+ | +---------------+--+
| | | | | | ^
+-----------+ | | +-----------+ |
| | |
| | |
+------------+ +-+-----+----+ +------------+ |
| | HTTP | | SIP | | SIP |
| Ralf +---------+ Sprout +----------+ Bono +---------+
| | | | | |
| | | | | |
| | | | | |
+------+-----+ +------------+ +---+--------+
| |
| HTTP |
+-------------------------------------------+
More details about Clearwater components may be found at http://www.projectclearwater.org
Proposed changes
================
Separate application should be written for each of Clearwater components.
One more application should be written for aggregation of all components
(Clearwater main application).
Main application input parameters:
* OS image for deploy
* user keypair name
* zone name
* DNSSEC key
This parameters should be passed to child components.
Components input parameters:
* Flavour for instances
* Count of instances
Main application workflow
#. Instantiate child applications
#. Create common networks and security group
#. Call child applications `deploy()` method
Components have to be deployed in following order:
#. DNS application
#. One application with initial
`etcd <https://coreos.com/etcd>`_ cluster node (Ellis preferred)
#. Rest of applications
Components common workflow
#. Find main application for common properties retrieving
#. Create security group for application
#. Create instances
#. Create deploy scripts from templates
#. Run deploy scripts
For components (except DNS server) following actions must be provided:
* Scale Up - add additional node to cluster
* Scale Down - remove node from cluster
Both actions can be implemented in two steps:
* add/remove node to/from component object model
* update appropriate DNS records
Alternatives
------------
* `OpenStack Heat templates for Clearwater deployments <https://github.com/Metaswitch/clearwater-heat>`_
* `Cloudify TOSCA application <https://github.com/Orange-OpenSource/opnfv-cloudify-clearwater>`_
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Konstantin <ksnihyr@mirantis.com>
Work Items
----------
#. Create Clearwater application prototype
#. Extend Clearwater application functionality using current Core Library
#. Add Scalable Application Framework support
Dependencies
============
#. `Scalable Application Framework <https://blueprints.launchpad.net/murano/+spec/scalable-application-framework>`_
Testing
=======
#. Clearwater live tests can be used for testing installation.
Documentation Impact
====================
None
References
==========
* `Project Clearwater Home <http://www.projectclearwater.org>`_
* `Clearwater documentation <http://clearwater.readthedocs.io/en/stable/>`_
* `Clearwater heat template <https://github.com/skolekonov/clearwater-heat/tree/mitaka>`_
* `Clearwater live tests <https://github.com/Metaswitch/clearwater-live-test>`_

View File

@ -1,3 +0,0 @@
Placeholder for implemented newton specs
========================================

View File

@ -1,650 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=================================
Application Development Framework
=================================
https://blueprints.launchpad.net/murano/+spec/application-development-framework
Build a library of MuranoPL classes to define basic building blocks for the
applications utilizing standard patterns for scaling, load balancing, healing
etc.
Problem description
===================
Currently Murano Applications are not opinionated about the workflow they have
to follow to be scalable, highly available, (self) healable and so on. The only
interface which is declared for a standard murano application defines a single
method called “deploy” which has to implement the complete provisioning
procedure of the app. This approach is cumbersome, requires lots of coding
while most of the code is a boilerplate which could be reused by most the
applications.
Also, the “deploy” workflow is just a beginning of applications life in the
cloud: Murano app should define the lifecycle management of the app as well: to
handle the scaling, healing and other special behaviors. Similarly to the
deployment behaviors these kinds of workflow may have some generic steps which
should be made on most of the applications and should not require manual
copying.
It would be beneficial for the developers of Murano Applications to have a set
of base classes defining the standard building blocks for the typical
applications and their life cycle management operations.
So Murano should allow Application Developers to focus on their
application-specific tasks only (e.g. “how to install the software on the
VMs”, “how to configure it to interact with other apps” etc) without the real
need to dive into resource orchestration, server farm configuration and so on.
The application developers experience has to be as lightweight as possible:
ideally they should be able to focus on the software configuration tools
(scripts, puppets etc) and completely ignore the MuranoPL if they do not need
to define any custom workflow logic.
Proposed change
===============
It is proposed to implement a set of base classes for the applications and
their components.
Library structure
-----------------
Scaling primitives
~~~~~~~~~~~~~~~~~~
To properly handle various scaling scenarios it is required to have a set of
classes which will be able to group similar resources together, produce new
copies of the same resources or release the existing ones on request.
The following hierarchy of classes is proposed to define this functionality on
the generic level as well as to implement it for the case of the Servers/VMs:
::
+-------+
| +-------+
| | +--------+ +------------------+ +-----------------+
| | | | | | | |
+-+ | Object <--------+ ReplicationGroup +--------> ReplicaProvider |
+-+ | | | | |
+--------+ +---+--------------+ +-+--------+------+
^ ^ ^
| | |
| +------------------+-----+ |
| | | |
+-------+ | | CloneReplicaProvider | |
| +-------+ | | | |
| | +----------+ | +------------------------+ |
| | | | | |
+-+ | Instance | | |
+-+ | | |
+----+-----+ | |
| | |
+-----+-------+ | |
| | | |
| ServerGroup | | +---------------+--+
| | | | Template |
+-----^-------+ +---+----------+ | Server +--+
| | Server +-------> Provider | |
+------------+ Replication | +-----+------------+ +---+
| Group | | | |
+--------------+ +---+---other---+ |
| |
+---------------+
**ReplicationGroup**
A base class which does the object replication. It holds the collection of
objects generated in runtime in one of its output properties and contains
a reference to a ``ReplicaProvider`` object which is used to dynamically
generate the objects in runtime.
Input properties of this class include the ``minItems`` and ``maxItems``
allowing to limit the number of objects it holds in its collection.
An input-output property ``numItems`` allows to declaratively change the
set of objects in the collection by setting its size.
The ``deploy`` method of this class will be used to apply the replica
settings: it will drop the objects from the collection if their number
exceeds the specified by the ``numItems`` or generate some new if there
are not enough of them.
**ReplicaProvider**
A class to generate the objects for a ``ReplicationGroup``. The base one
is abstract, its inheritors should implement the abstract
``createReplica`` method to create the actual object. The method may
accept some index parameter to properly parametrize the newly created copy.
The concrete implementations of this class should define all the input
properties needed to create new instances of object. Thus the provider
actually acts as a template of the object it generates.
**CloneReplicaProvider**
An implementation of ``ReplicaProvider`` capable to create replicas by
cloning some user-provided object, making use of the ``template()``
contract.
**ServerGroup**
A class that provides static methods for deployment and releasing
resources on the group of instances.
**ServerReplicationGroup**
A subclass of the ``ReplicationGroup`` class and the ``ServerGroup``
class to replicate the ``Instance`` objects it holds.
The ``deploy`` method of this group not only generates new instances of
servers but also deploys them if needed.
**TemplateServerProvider**
A subclass of ``CloneReplicaProvider`` which is used to produce the objects
of ``Instance`` class by cloning them with subsequent parameterization of
the hostnames. May be passed as ``provider`` property to objects of the
``ServerReplicationGroup`` class.
**other replica providers**
Other subclasses of ``ReplicaProvider`` may be created to produce different
objects of ``Instance`` class and its subclasses depending on particular
application needs.
Software Components
~~~~~~~~~~~~~~~~~~~
The class to handle the lifecycle of the application is the
``SoftwareComponent`` class which is a subclass of ``Installable`` and
``Configurable``:
::
+-----------+-+ +-+------------+
| | | |
| Installable | | Configurable |
| | | |
+-----------+-+ +-+------------+
^ ^
| |
| |
+-+---------------+-+
| |
| SoftwareComponent |
| |
+-------------------+
The hierarchy of the ``SoftwareComponent`` classes should be used to define the
workflows of different application lifecycles. The general idea is to have the
generic logic in the methods of the base classes and let the derived classes
implement the handlers for the custom logic. The model is event-driven: the
workflow consists of the multiple steps, and most of the steps invoke
appropriate `on%StepName%` methods intended to provide application-specific
logic.
It is proposed to split 'internal' step logic and their 'public' handlers
into separate methods. Technically this is not necessary since the subclass may
always call `super()` to invoke the base logic, but the developers tend to
forget to invoke these super-implementations so having the logic split into
two parts should improve the developers' experience and simplify the code of
derived classes.
The standard workflows (such as Installation and Configuration) will be defined
by the ``Installable`` and ``Configurable`` classes. The main implementation -
``SoftwareComponent`` will inherit both these classes and will define its
deployment workflow as a sequence of Installation and Configuration flows.
Other future implementations may add new workflow interfaces and mix them in
to change the deployment workflow or add new actions.
Installation workflow consists of the following methods:
::
+----------------------------------------------------------------------------------------------------------------------+
| INSTALL |
| |
| +------------------------------+ +---------------+ |
| +------------------------------+ | +---------------+ | |
| +------------------------------+ | | +---------------+ +---------------+ | | +----------------------+ |
| | | | | | | | | | | | | |
| | checkServerIsInstalled | +-+ +----> beforeInstall +----> installServer | +-+ +----> completeInstallation | |
| | +-+ | | | +-+ | | |
| +------------------------------+ +------+--------+ +------+--------+ +-----------+----------+ |
| | | | |
+----------------------------------------------------------------------------------------------------------------------+
| | |
| | |
| | |
v v v
onBeforeInstall onInstallServer onCompleteInstallation
**install**
* **Arguments:** ``serverGroup``
* **Description:**
Entry point of the installation workflow.
Iterates through all the servers of the passed ServerGroup and calls the
``checkServerIsInstalled`` method for each of them. If at least one
of the calls has returned `false` calls a ``beforeInstall`` method. Then,
for each server which returned `false` as the result of the
``checkServerIsInstalled`` calls the ``installServer`` method to do
the actual software installation.
After the installation has been completed on all the servers and if at
least one of the previous calls of ``checkServerIsInstalled``
returned `false` the method runs the ``completeInstallation`` method.
If all the calls to ``checkServerIsInstalled`` returned `true`
this method concludes without calling any others.
**checkServerNeedsInstallation**
* **Arguments:** ``server``
* **Description:** checks if the given server requires a (re)deployment of
the software component. By default checks for the value of the attribute
`installed` of the instance.
May be overridden by subclasses to provide some better logic (e.g. the
app developer may provide code to check if the given software is
pre-installed on the image which was provisioned on the VM)
**beforeInstall**
* **Arguments:** ``servers``, ``serverGroup``
* **Description:**
Reports the beginning of installation process and calls the public event
handler ``onBeforeInstall``.
**onBeforeInstall**
* **Arguments:** ``servers``, ``serverGroup``
* **Description:** Public handler of the `beforeInstall` event. Empty in
the base class, may be overridden in subclasses if some custom pre-install
logic needs to be executed.
**installServer**
* **Arguments:** ``server``, ``serverGroup``
* **Description:** Does the actual software deployment on a given server by
calling an ``onInstallServer`` public event handler. If the installation
completes successfully sets the `installed` attribute of the server to
`true`, reports successful installation and returns `null`. If an
exception encountered during the invocation of ``onInstallServer``, the
method handles that exception, reports a warning and returns the server.
The return value of the method indicates to the ``install`` method how
many failures encountered in total during the installation and with what
servers.
**onInstallServer**
* **Arguments:** ``server``, ``serverGroup``
* **Description:** an event-handler method which is called by the
``installServer`` method when the actual software deployment is needed.
Is empty in the base class. The implementations should override it with
custom logic to deploy the actual software bits.
**completeInstallation**
* **Arguments:** ``servers``, ``serverGroup``, ``failedServers``
* **Description:** is executed after all the ``installServer`` methods were
called. Checks for the number of errors reported during the installation:
if it is greater than some pre-configurable threshold an exception is
risen to interrupt the deployment workflow. Otherwise the method calls an
``onCompleteInstallation`` event handler and then reports a successful
completion of the installation workflow.
**onCompleteInstallation**
* **Arguments:** ``servers``, ``serverGroup``, ``failedServers``
* **Description:** an event-handler method which is called by the
``completeInstallation`` method when the component installation is about
to be completed.
Default implementation is empty. Inheritors may implement this method to
add some final handling, reporting etc.
Configuration workflow consists of the following methods:
::
+----------------------------------------------------------------------------------------------------------------------+
| CONFIGURATION |
| +-----------------+ |
| | | |
| | +---------------+ +-----------------+ |
| | +---------------+ | +-----------------+ | |
| +------------v--+ +---------------+ | | +--------------+ +-----------------+ | | +-----------------------+ |
| | | | | | | | | | | | | | | |
| | checkCluster\ +---> checkServer\ | +-+---> preConfigure +---> configureServer | +-+---> completeConfiguration | |
| | IsConfigured | | IsConfigured +-+ | | | +-+ | | |
| +------------+--+ +---------------+ +------+-------+ +--------+--------+ +-----------+-----------+ |
| | | | | |
| | | | | |
| +----------v----------+ | | | |
| | | | | | |
| | getConfigurationKey | | | | |
| | | | | | |
| +---------------------+ | | | |
| | | | |
+----------------------------------------------------------------------------------------------------------------------+
| | |
| | |
v v v
onPreConfigure onConfigureServer onCompleteConfiguration
**configure**
* **Arguments:** ``serverGroup``
* **Description:**
Entry point of the configuration workflow.
Calls a ``checkClusterIsConfigured`` method. If the call returns `true`,
workflow exits without any further action. Otherwise for each server in
the ``serverGroup`` it calls ``checkServerIsConfigured`` method and gets
the list of servers that need reconfiguration. The ``preConfigure``
method is called with that list. At the end calls the
``completeConfiguration`` method.
**checkClusterIsConfigured**
* **Arguments:** ``serverGroup``
* **Description:**
Has to return `true` if the configuration (i.e. the values of input
properties) of the component has not been changed since it was last
deployed on the given server group. Default implementation calls the
``getConfigurationKey`` method and compares the returned result with a
value of `configuration` attribute of ``serverGroup``. If the results
match returns `true` otherwise `false`.
**getConfigurationKey**
* **Arguments:** None
* **Description:**
Should return some values describing the configuration state of the
component. This state is used to track the changes of the configuration
by the ``checkClusterIsConfigured`` and ``checkServerIsConfigured``
methods.
Default implementation returns a synthetic value which gets updated on
every environment redeployment. Thus the subsequent calls of the
``configure`` method on the same server group during the same deployment
will not cause the reconfiguration, while the calls on the next
deployment will reapply the configuration again.
The inheritors may redefine this to include the actual values of the
configuration properties, so the configuration is reapplied only if the
appropriate input properties are changed.
**checkServerIsConfigured**
* **Arguments:** ``server``, ``serverGroup``
* **Description:**
It is called to check if the particular server of the server group has
to be reconfigured thus providing more precise control compared to
cluster-wide ``checkClusterIsConfigured``.
Default implementation calls the ``getConfigurationKey`` method and
compares the returned result with a value of `configuration` attribute
of the server. If the results match returns `true` otherwise `false`.
This method gets called only if the ``checkClusterIsConfigured`` method
returned `false` for the whole server group.
**preConfigure**
* **Arguments:** ``servers``, ``serverGroup``
* **Description:**
Reports the beginning of configuration process and calls the public
event handler ``onPreConfigure``. This method is called once per the
server group and only if the changes in configuration are detected.
**onPreConfigure**
* **Arguments:** ``servers``, ``serverGroup``
* **Description:**
Public event-handler which is called by the ``preConfigure`` method
when the (re)configuration of the component is required.
Default implementation is empty. Inheritors may implement this method to
set various kinds of cluster-wide states or output properties which may
be of use at later stages of the workflow.
**configureServer**
* **Arguments:** ``server``, ``serverGroup``
* **Description:**
Does the actual software configuration on a given server by calling the
``onConfigureServer`` public event handler. If the configuration
completes successfully calls the ``getConfigurationKey`` method and sets
the `configuration` attribute of the server to resulting value thus
saving the configuration applied to a given server. Returns `null` to
indicate successful configuration.
If an exception encountered during the invocation of
``onConfigureServer``, the method will handle that exception, report a
warning and return the current server to signal its failure to the
``configure`` method.
**onConfigureServer**
* **Arguments:** ``server``, ``serverGroup``
* **Description:**
An event-handler method which is called by the ``configureServer``
method when the actual software configuration is needed. It is empty in
the base class. The implementations should override it with custom logic
to apply the actual software configuration on a given server.
**completeConfiguration**
* **Arguments:** ``servers``, ``serverGroup``, ``failedServers``
* **Description:**
It is executed after all the ``configureServer`` methods were called.
Checks for the number of errors reported during the configuration: if it
is greater than set by some pre-configured threshold, an exception is
risen to interrupt the deployment workflow. Otherwise the method calls
an ``onCompleteConfiguration`` event handler, calls the
``getConfigurationKey`` method and sets the `configuration` attribute of
the server group to resulting value and then reports successful
completion of the configuration workflow.
**onCompleteConfiguration**
* **Arguments:** ``servers``, ``serverGroup``, ``failedServers``
* **Description:**
The event-handler method which is called by the ``completeConfiguration``
method when the component configuration is finished at all the servers.
Default implementation is empty. Inheritors may implement this method to
add some final handling, reporting etc.
Uninstallation workflow consists of the following methods:
::
+-----------------------------------------------------------------------------------+
| UNINSTALL |
| |
| +----------------+ |
| +-----------------+ | |
| +-----------------+ +-----------------+ | | +------------------------+ |
| | | | | | | | | |
| | beforeUninstall +------> uninstallServer | +-+------> completeUninstallation | |
| | | | +-+ | | |
| +-------+---------+ +--------+--------+ +-----------+------------+ |
| | | | |
| | | | |
+-----------------------------------------------------------------------------------+
| | |
v v v
onBeforeUninstall onUninstallServer onCompleteUninstallation
**uninstall**
* **Arguments:** ``ServerGroup``
* **Description:**
Entry point of the uninstallation workflow.
Iterates through all the servers of the passed ServerGroup, for each of
them checks the presence of the `installed_at_%serverId%` attribute.
If at least one attribute is present calls a ``beforeUninstall`` method
once, and then calls an ``uninstallServer`` method for each server which
has the attribute. If at least one method was called, calls an
``afterUninstall`` method at the end.
**beforeUninstall**
* **Arguments:** ``ServerGroup``
* **Description:** reports the beginning of uninstalling process and then
calls an ``onBeforeUninstall`` public event handler.
**onBeforeUninstall**
* **Arguments:** ``ServerGroup``
* **Description:** Public handler of the `beforeUninstall` event. Empty in
the base class, may be overridden in subclasses if some custom pre
uninstall logic needs to be executed.
**uninstallServer**
* **Arguments:** ``Server``
* **Description:** does the actual software removal on a given server by
calling an ``onUninstallServer`` public event handler. If the removal
completes successfully clear the `installed_at_%serverId%` attribute of
the component's attribute storage to indicate that the software component
is no longer installed on that particular machine.
If an exception was encountered during the invocation of
``onUninstallServer`` the method will handle that exception, report a
warning and increment the error counter for the particular deployment.
**onUninstallServer**
* **Arguments:** ``Server``
* **Description:** an event-handler method which is called by the
``uninstallServer`` method when the actual software removal is needed.
Is empty in the base class. The implementations should override it with
custom logic to uninstall the actual software bits.
**completeUninstallation**
* **Arguments:** ``ServerGroup``
* **Description:** is executed after all the ``uninstallServer`` methods
were called. Checks for the number of errors reported during the
uninstalling: if it is greater than some pre-configurable threshold an
exception is risen to interrupt the uninstalling workflow. Otherwise the
method calls an ``onCompleteUninstallation`` event handler and then
reports a successful completion of the uninstalling workflow.
**onCompleteUninstallation**
* **Arguments:** ``ServerGroup``
* **Description:** an event-handler method which is called by the
``completeUninstallation`` method when the component removal is done on
all the servers.
Default implementation is empty. Inheritors may implement this method to
add some final handling, reporting etc.
Alternatives
------------
The only alternative is to let application developers to write their own code
for these common tasks. We don't completely drop this alternative, since the
developers are not forced to use the framework and may still continue having
the applications which do not inherit its base classes.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
The first implementation of this spec will utilize the existing version of the
core library. Subsequent ones - redefining the hierarchy of base resource
classes - will need to increment the major version of the core library.
Other end user impact
---------------------
End users should not notice the difference between apps written using the
proposed framework and regular ones.
Deployer impact
---------------
The Framework's library package should be deployed in the target catalog for
other applications to use it.
Developer impact
----------------
This is all about simplifying the life of application developer. Developers
will have to learn the classes and patterns to utilize the benefits of the
framework.
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
ativelkov
Other contributors:
tbd
Work Items
----------
* Implement the base ``Server`` class and a stub for its core-library-compatible
inheritor.
* Implement scalable primitives (ReplicationGroup, ReplicaProvider and their
inheritors)
* Implement a Event/Notification layer in MuranoPL
* Implement ``SoftwareComponent`` class with its standard
Install/Configure/Uninstall workflows.
* Implement base application classes binding ``SoftwareComponent`` objects to
``ReplicationGroup`` objects producing Servers.
Dependencies
============
None
Testing
=======
All the new MuranoPL classes should be covered by test-runner based tests.
Documentation Impact
====================
The framework should be well documented so the package developers have a
reliable and up-to-date source of information.
References
==========
None

View File

@ -1,534 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==================================================
Dependency-driven multi-step resource deallocation
==================================================
https://blueprints.launchpad.net/murano/+spec/dependency-driven-resource-deallocation
Murano components may allocate various kinds of resources: virtual machines,
networks, volumes etc. When these components get removed from the deployment
appropriate resources have to be deallocated. Current implementation of this
process has some significant limitations and flaws.
This specification aims to address these issues and provide a design for the
better resource deallocation / garbage collection system for MuranoPL.
Problem description
===================
In Murano the deallocation of resources is managed by a garbage collection
system (GC). Its present implementation is based on the execution of special
methods called ``.destroy()`` which may be defined in each MuranoPL class and
are intended to contain the custom code to deallocate resources allocated by
the objects of those classes.
These methods get executed when their objects leave object graph, however the
exact order of these executions is currently undefined.
There are two different scenarios when the objects may leave the object graph
thus causing their ``.destroy`` methods to be called:
* "Offline" changes of the Object Graph, i.e. the changes introduced in the
serialized version of the object graph via the API. These changes are
detected by comparing the incoming object graph (the one passed from the
API for deployment) with the "snapshot" of current environment made after
the previous deployment has been completed. If some object exists in the
"snapshot" but is missing in the input graph it is considered to be
removed. Such objects are deserialized from the snapshot and their
``.destroy`` methods are called in the order from deepest nested objects
towards topmost ones.
* "Runtime" changes. Some objects may be removed from the object graph during
deployment: they may be unreferenced or assigned to Runtime properties or
local variable only. As a result after the deployment completes these
objects are not serialized neither into the output version of the object
graph nor into its "snapshot". The next deployments will know nothing about
their existence so the objects will be lost forever. To recover the
resources allocated by such unreferenced objects murano analyzes its
ObjectStore after the execution is complete. Each object which is present in
the store but is not present in the output version of the object graph is
considered to be "orphan" and thus its ``.destroy`` method is called. The
order of these calls is currently undefined: the objects get destroyed based
on their position in the object store, which is hardly predictable.
Such a design is insufficient for production grade applications which
often require the following scenarios:
* If some object is going to be deleted another object (either owning or just
referencing it) may need to execute some actions before or after the object
is deleted.
* When a group of nested or interconnected objects is about to be deleted the
order in which their destructors should be executed may be different in
different cases.
* Sometimes the actions being executed during the destruction of an object may
depend on the fact whether some other object is about to be deleted or not.
*Example*
*Consider an Application which consists of a Network component and several
VM components. All the components are owned by the Application but there
are no ownership relationships between them. When the Application is going
to be deleted (i.e. its whole subgraph leaves the environment) all of its
components are about to be removed as well, and so their ``.destroy``
methods will be called. Since Network does not own the VM's the order
of these calls is undefined. Due to various implementation details it may
be impossible to remove the Network before the VMs which are connected to
it (e.g. in case when the VM has a mandatory requirement to be always
connected to at least one network). In this case the ``.destroy`` of a
Network component should be always called after all the VMs have been
destroyed.*
Another issue is that murano uses ``Objects`` and ``ObjectsCopy`` objects
to transfer data between deployments. When destruction dependencies are
implemented, the handler will make changes (if any) to objects in
``ObjectsCopy``. Therefore, these changes are not applied during the next
deployment and this should be addressed.
Also, sometimes it can be useful to deallocate resources used by the
unreferenced objects even before the end of deployment on demand from the
application code.
Proposed change
===============
Several improvements have to be made in Murano engine to address the problems
described above.
General concepts
----------------
Destruction dependencies
^^^^^^^^^^^^^^^^^^^^^^^^
There should be a way to establish directional `destruction dependencies`
between Murano objects. If object `Foo` establishes such a dependency on the
object `Bar` then:
* `Foo` will be notified when `Bar` is about to be destroyed. These
notifications are covered in details in "Multi-step destruction" section
below.
* If both `Foo` and `Bar` are going to be destroyed in the same garbage
collection execution, `Bar` will be destroyed before Foo.
These dependencies are not related to object ownership relationship or
property-based cross-references: the owner may have a destruction dependency on
its nested object or vise versa; the objects referencing each other may have
some destruction dependency established. Even entirely unrelated objects may
have a destruction dependency between them.
Since the destruction dependencies are directional there is a theoretical
possibility of a circular dependency to exist. In case if two or more objects
form such a circle they will still be notified about pending destruction of
their dependencies, however the order of this notifications - and the
destruction itself - is undefined in this case.
Destruction dependencies are going to be used during all kinds of garbage
collection: pre-deployment ("offline"), on-demand (during deployment) and
post-deployment.
Multi-step destruction
^^^^^^^^^^^^^^^^^^^^^^
Instead of just iterating through all the objects going to be destructed and
calling their ``.destroy`` methods Murano should perform a multi-step garbage
collection according to the following algorithm:
1. Detect all the objects going to be destroyed. It can be done by using
Python GC to track and collect objects, as described in the
*Garbage collection executions* section.
2. Sort the list of detected objects using the following comparator: for
any two objects A and B in the list:
.. code::
IF (A owns B) THEN A>B
ELSE IF (A has-a-destruction-dependency-on B)
AND (NOT B has-a-destruction-dependency-on A)
THEN A>B
ELSE A==B
where `has-a-destruction-dependency-on` means that the left operand object
has a destruction dependency (probably transitive) on right operand object,
`owns` means that the left operand object owns (probably transitively) the
right operand object.
The objects which are considered to be equal by the algorithm above can be
destroyed in parallel.
The result of the sorting is the dictionary with indexes as keys and
lists of objects with equal destruction priority as values.
3. Sort the keys of the dictionary in the reversed order of destruction
priority and for each key start parallel notification about scheduled
destruction of the objects in the corresponding group. During
notification, handlers of the objects that have a destruction dependency on
some "sentenced" object will be invoked.
4. Sort the keys of the dictionary in the direct order of destruction
priority and for each index in the dictionary start parallel destruction of
all objects in the corresponding group. Destruction of individual object
means calling the ``.destroy()`` method of the object if present and
changing the object's status to "Destroyed" (see below).
As an environment does not have owners, it will always be in the last
group of destruction. There is no guarantee that some other objects (for
example, heat stack) will be alive at the time of its destruction. Thus
``io.murano.Environment`` class should not have the ``.destroy()`` method.
Destroyed objects
^^^^^^^^^^^^^^^^^
When an object is being processed by a garbage collector, it means that there
are no live references to it from the objects of the environment. However there
may be cases when the code which handles either the pre-destroy notification
(step 4 above) or the actual ``.destroy`` method re-establishes the references
to the object being destructed, and thus the object remains in the object graph
after the GC is completed. Since the resources may be deallocated at this time
the regular usage of the object is not possible, however if it is assigned to
a property of some another object in the graph it may not always be possible to
just nullify that property since it may cause a contract violation.
To resolve such collisions it is proposed to explicitly mark such destroyed
objects as "destroyed". It means setting object's ``destroyed`` attribute to
``True`` and removing the self-reference from it.
MuranoPL executor will not allow to execute any methods on such objects,
however their properties remain accessible (i.e. readable) so
any runtime information associated with them may be recovered. Destroyed
objects will be serialized with the rest of object graph but the
json-representation of the object will have a special flag in their class
header (the "?" section) to indicate their special status. When deserialized
from json such objects will retain their "destroyed" status, so the method
execution will still be impossible even in subsequent deployments.
When "destroyed" objects are unreferenced from the object graph, their
properties get nullified and they get destroyed automatically by Python GC.
Garbage collection executions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The multi-step object destruction described above should take place in three
different scenarios:
1. *(currently existing)* Before the deployment, destroys objects which were
present in the object graph after the previous deployment was finished but
were not found in the incoming object graph of a new deployment, i.e. the
ones explicitly removed using the API.
2. *(currently existing)* After the deployment, destroys the objects existing
in the Object Store but not being a part of the **persistable** object graph
of current environment, i.e. having no references to them from the
persistable (In, Out, InOut) properties of the environment or its transitive
children).
3. *(proposed)* During the deployment, explicitly initiated from MuranoPL code.
Destroys objects which are not part of the **complete** object graph, i.e.
having no references to them from any properties of the environment
(including runtime and private properties) AND not being referenced by local
variables in any frame of all the green threads of current deployment.
To implement scenario 3, a new algorithm is needed. As mentioned in the
*Multi-step destruction* section, Python garbage collector can be used
for that. MuranoPL can make use of the way Python's ``gc.collect`` works.
Python library ``gc`` allows running on-demand garbage collection through the
``gc.collect()`` method and provides access to unreachable objects that the
collector found but cannot free through collection ``gc.garbage`` [2].
To make use of this, there should be an ability to:
* Make object store have weak links only and prevent hard links in other DSL
places so that only links between objects remain.
* Prevent murano objects that should have been destroyed by Python GC from
being destroyed.
* Get the list of such objects and destroy them in correct order and notify
subscribers about destruction.
The prevention can be done by adding ``__del__()`` magic method to the
MuranoObject class and creating cyclic reference in the object to itself.
When ``gc.collect()`` is done, all unreachable objects can be examined and
murano objects owned by current executor can be distinguished among them.
The difference in Python 3.4 and higher is that objects with a ``__del__()``
method don't end up in ``gc.garbage`` anymore and this list should be empty
most of the time [3]. So logic of adding object to GC candidates can be added
directly to ``__del__()``.
It means that in Python versions 3.4 and higher, murano objects will be added
to planned destruction from ``__del__()`` call caused by ``gc.collect()``,
and in versions prior to 3.4, presence of ``__del__()`` along with cyclic
reference to itself will provide adding the object to ``gc.garbage`` list,
and it can be added to candidates for destruction from there.
This logic can be used for garbage collection in all three scenarios
mentioned above.
The resulting list of GC candidates is then destroyed as described in the
*Multi-step destruction* section above.
With this approach, the comparison of Objects and ObjectsCopy is not needed
anymore. Garbage collector works with the same objects on each deployment,
so all changes are saved properly.
Code changes
------------
GC class
^^^^^^^^
A new python-backed Murano class called ``GC`` should be added to the core
library. It should have the following static methods:
* ``collect()`` - initiates garbage collection of unreferenced objects of
current deployment (see p.3 in "Garbage collection executions" section
above).
* ``isDestroyed(object)`` - checks if the ``object`` was already destroyed
during some GC session and thus its methods cannot be called.
* ``isDoomed(object)`` - can be used within the ``.destroy()`` method to
test if another object is also going to be destroyed.
* ``subscribeDestruction(publisher, subscriber, handler=null)`` - establishes
a destruction dependency from the ``subscriber`` to the object passed as
``publisher``. Method may be called several times, in this case only a single
destruction dependency will be established, however the same amount of calls
of ``unsubscribeDestruction`` will be required to remove it.
``handler`` argument is optional. If passed it should be the name of an
instance method defined by the caller class to handle notification of
``publisher``'s destruction (see "Multi-step destruction" section above: this
handler is executed for p. 3.1)
The following arguments will be passed to the handler method:
* ``object`` - a target object which is going to be destroyed. It is not
recommended to persist the reference to this object anywhere. This will not
prevent the object from being garbage collected but the object will be
moved to the "destroyed" state which is almost always bad. The option to do
so is considered to be advanced feature which should not be done unless it
is absolutely necessary.
* ``unsubscribeDestruction(publisher, subscriber, handler=null)`` - removes
the destruction dependency from the ``subscriber`` to the object passed as
``publisher``. Method may be called several times without any side-effects.
If ``subscribeDestruction`` was called more than once the same (or more)
amount of calls to ``unsubscribeDestruction`` is needed to remove the
dependency.
``handler`` argument is optional and must correspond the handler passed
during subscription if it was provided back then.
Alternatives
------------
Application developers may try to implement their own event-based notification
logic to notify about pending and completed object destructions. However it
will solve only part of the problem: notifications will work properly, but they
will not affect the order in which the objects are destroyed, so the workflows
will be too complicated. Also this alternative will not have the advanced
features proposed in this spec, such as ability to check if some object is
going to be destroyed.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
The proposed change is completely backwards compatible: without explicit
destruction dependencies objects will be collected based on their ownership
relationships, i.e. as it is done in the current implementation.
The packages containing classes which explicitly call the methods of ``GC``
should have package format of at least 1.4 to prevent their execution on older
versions of Murano which do not have this feature.
Other end user impact
---------------------
None
Deployer impact
---------------
None
Developer impact
----------------
Developers will get the new MuranoPL-based API to manage resource deallocation
lifecycle. If they do not want to use it they don't need to do anything.
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
ativelkov
Other contributors:
Stan Lagun <istalker2>
starodubcevna
Work Items
----------
* Implement a system to define and use destruction dependencies in runtime.
* Introduce changes to MuranoObject class to keep track of "destroyed"
object status.
* Modify the serializer / deserializer to properly persist the value of the
"destroyed object" flag.
* Implement collecting unreferenced murano objects utilizing Python ``gc``
library
* Implement sorting algorithms to arrange objects-to-be-destroyed based on
criteria defined in p.2 of "Multi-step destruction" section above.
* Implement multi-step destruction workflow.
* Implement ``GC`` class to bind all the above.
* Create test-runner-based tests to cover all the test scenarios.
* Document the new features.
Dependencies
============
The development of this feature will enable Application Development Framework
[1] to address resource deallocation problems during application uninstall.
Testing
=======
Tests should be written for test-runner to cover various scenarios of resource
deallocation.
Runtime garbage collection
--------------------------
There should be test cases covering that:
* objects assigned to persistent (Input, Output, InputOutput) properties (both
locally-declared and inherited) of objects reachable from the current roots
are NOT garbage collected;
* objects assigned to transient (Runtime and undeclared) properties (both
locally-declared and inherited) of objects reachable from the current roots
are NOT garbage collected; target properties should be both locally-declared
and inherited;
* objects assigned to static properties of various classes are NOT garbage
collected;
* objects passed to python-backed objects and unreferenced in MuranoPL are NOT
garbage collected unless their MuranoObjectInterface proxies are unreferenced
/ GC'ed in python;
* objects assigned to local variables of the current execution frame (i.e.
variables of the current method and all the caller methods in call stack)
including method arguments are NOT garbage collected;
* single unreferenced objects ARE garbage collected;
* graphs of interconnected objects having no references from non-collected
objects ARE garbage collected;
* objects passed to python-backed objects and unreferenced in both MuranoPL and
python ARE garbage collected;
* garbage collector correctly processes stack-frame objects from green-threads
other than the one it is executed from
Destruction dependency resolution order
---------------------------------------
There should be test cases covering that:
* if some child object has a destruction dependency on its parent, the parent
gets destroyed before the child;
* if some parent object has a destruction dependency on its child, the child
gets destroyed before the parent;
* if some objects not being the part of some ownership hierarchy have some
destruction dependency, the dependency-object is destroyed before the
dependent one;
* if some objects have circular destruction dependency they are all destroyed
(the order is not enforced by the test);
Destruction events
------------------
Given the base scenario of object A having a destruction dependency on object B
and B being GC'ed, there should be tests covering that:
* the right order of events occurs (B scheduled for destruction -> A is
notified about planned B's destruction -> B's ``.destroy()`` method is
called -> B gets destroyed);
* A may prevent B's destruction by establishing a reference on B in the
handler;
* A may establish more than 1 destruction dependency on B and still be
notified just once;
* A may remove the destruction dependency and not get notified on B's
destruction;
* If A established N destruction dependencies and then removed them M times,
(N>M) then notifications are still delivered;
* If A established N destruction dependencies and then removed them M times,
(N<=M) then notifications are not delivered;
* B may establish a destruction dependency on itself thus subscribing to
appropriate notifications;
* ``isDoomed`` and ``isDestroyed`` methods return appropriate values when
called by A for B in appropriate event handlers.
Documentation Impact
====================
Developers documentation should be updated to describe the new ``GC`` class and
its methods, as well as the design guidelines for application developers to
follow to utilize the new capability.
References
==========
[1] https://github.com/openstack/murano-specs/blob/master/specs/newton/approved/application-development-framework.rst
[2] https://docs.python.org/2/library/gc.html
[3] https://docs.python.org/3/library/gc.html

View File

@ -1,521 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==============
MuranoPL forms
==============
https://blueprints.launchpad.net/murano/+spec/muranopl-forms
Murano has a YAML-based DSL to describe the UI form required by the
application. However it is completely independent from the application itself.
So the changes made to the application properties doesn't affect the form.
This specification is aimed to make UI definition be driven by the application
code and metadata rather than by a separate language.
Problem description
===================
Current UI definition format and the way Murano handles it comes with a bunch
of problems that are there by design and cannot be solved without making some
significant changes. Most notable problems are:
* It is monolithic. UI form defines all the inputs required not just by the
application but for all its object model subtree except for the other
application references. Thus it is impossible to have UI forms for
individual components. Neither it is possible for a user to choose the
desired implementation of those components without turning them into
applications (and putting in a separate packages).
* It contains yet another yaql-based DSL that defines the mapping between
input fields and application (and inner component) properties. However
this mapping is not bound to the property contracts. So any change made to
the properties or their contracts will not affect the form but only its
validation that happens upon deployment after the form is no longer visible
to the user.
* Because the input fields do not directly correlate to application properties
it is not possible to get the reverse mappings from object model to the
input fields. Because of that once the form is closed it is impossible to
edit entered values because they already transformed to some other structure
that corresponds to application's object model and we don't have any UI
definition for that structure.
* It also means that each property needs to be described in several places in
different syntax thus duplicating the work. It is also easy to fail or get
out of sync with the code if one changes the contract but forgets to update
the UI definition or vice versa.
* It is one more DSL to learn. One more DSL invented in Murano and not covered
by any standard.
* Its object model template part (yaql mappings) use functions that are not
available in MuranoPL and vice versa. And its syntax has its own number of
problems like inability to define an object and reference it from several
places.
* It requires the client be aware of several OpenStack entities like images,
flavors etc. For example murano-dashboard talks to nova to get the list of
available flavors. This brings two additional problems:
a. It cannot be used for application that is not targeting OpenStack or
targeting OpenStack cloud other than the one used to run the dashboard.
b. It is not extensible. Each new selector requires special type in UI
definition that must be know to the client.
* Applications cannot dynamically control content of the form. For example it
is not possible to populate values for a drop-down list if those values are
not constants that are known in advance.
* Neither murano-dashboard nor the UI definition syntax support non-scalar
properties (dictionaries, lists etc.). Thus it is easy to come up with a
class design that is very useful but yet cannot be shown in UI.
* There can be only one UI definition form per package.
Proposed change
===============
Solution overview
-----------------
Proposed solution is to implement two major paradigm changes:
* Switch from the current UI definition format to an auto generated form
definitions that are not supposed to be written manually. Form generator is
going to accept MuranoPL class as an input and produce json-schema based
output that has all the required information to both present the form to a
user and do a client-side validation of the input.
* Make that UI schemas be per-class. There will be a new API call to request
UI definition for particular class or even particular method of that class
rather than for a package.
As a result the UI workflow to add new application is going to be like this:
#. User wants to add application x.y.z identified by the application package
FQN.
#. Client asks for UI definition for that package using existing API call
(the one that returns UI definition in existing "old" format).
If the call is successful and UI definition was obtained then the rest of
workflow is remained as it is now.
#. Otherwise the client (dashboard) requests UI schema for the class x.y.z
using new API call.
#. API sends murano-engine request to generate UI schema for the class x.y.z.
#. Engine loads class definition from appropriate package including attached
meta-values.
#. Taking class property declarations (contracts) and attached meta-values
as an input, engine generates json-schema that has everything needed to
present the UI form and do most of the client-side validation.
#. The same is done for all model builder methods (see below) using the same
algorithm but using their arguments instead of class properties as an input.
#. List of schemas is sent back to the API and, in turn, returned to the
caller (client).
#. The client decides which of the schemas to use (usually by asking the user).
It can always go with default schema for the class or take advantage of
one of the schemas provided by model builder methods.
#. Using the extended json schema client generates UI form. The form is going
to have 1-1 mapping between input controls and class properties or method
arguments.
#. After the form was filled it is validated on the client side using given
json schema (and its optional murano-specific extensions) and then submitted
to the API.
#. If the client opted to go with one of the model builder schemas the form
output is sent to the engine in attempt to call the model builder method
using the form values as an argument values. Model builder will then
return modified object model that is sent back to the client (via API).
Then the client can continue with the form edit using default schema or
apply additional model builder method.
#. Otherwise the constructed object model is inserted into environment
definition into API's database.
To change the application settings later, the same workflow is applied. The
only difference is that it doesn't try to use the old UI definition approach
but instead immediately requests new UI schema for the type specified in the
object model.
Schema generation
-----------------
Schema generation is a special service provided by the API (through the RPC
call to murano-engine) that takes a class FQN (including version or version
spec) and optional method name and produces json-schema compliant JSON. The
schema may have extra attributes for information that cannot be expressed by
standard json-schema attributes alone (for example field order).
If no method was provided the generation code takes class declaration and tries
to produce json-schema records by running YAQL expression contracts for its
properties in a special yaql context where all contract functions are
redefined to produce json-schema rather than validate the input. Thus it
creates a different implementation of the same contract syntax. In addition
the generation code may take into account number of well-known Meta classes
from the core library (to be added) and alter the schema if corresponding Meta
is attached to the properties. Meta values can specify things that cannot be
taken from contracts alone. For example it can be a property description text.
For the check() contract that accepts arbitrary yaql expression the analysis
of the expression AST is performed:
#. If the expression matches EXPR1 and EXPR2 and ... and EXPRN pattern it is
split into several validations (as if it was written as
``check(EXPR1).check(EXPR2)...check(EXPRN))``.
#. Each of (sub)expressions is checked against supported patterns that can
be translated to json-schema:
* comparison of len($) for a string len
* regex match function
* number comparison
* `in` operator that can be converted to enum
All expressions that cannot be translated with this algorithm are ignored and
the value will not be validated on the client side.
If the property/argument has a `Default` specifier it is translated to
`default` schema property.
For the class() the generated schema type is going to be `muranoObject`
with the following attributes:
* `muranoType` - FQN of the base class;
* `version` - version or version-spec that should be used to obtain
`muranoType` (as seen in the manifest);
* `owned` which can be `true`, `false` or null (or missing which means the
same as null). `true` means that the object must be owned by the parent
(thus ID of existing object in object model cannot be provided here),
`false` means that only existing object can be referenced and `null`
means that both options are valid.
Custom json-schema type is needed in order to retain reference semantics that
is it is an object which real type needs to be looked up in the catalog rather
than some plain dictionary or string. Client must understand `muranoObject`
type and know how to get list of valid type inheritors.
When `check()` contract is used to validate MuranoObject value (i.e. the
result of `class()` contract) it may put some constraints on that object's
properties or properties of some inner objects. In this case the schema
generator can emit additional `context` attribute to the property schema.
`context` is set to json-schema for the nested object (or its children).
Upon the input of a referenced object the client should check it against
all the `context` schemas up in the object model tree.
By default the generation algorithm produces the schema for the class and
for each model builder method available.
If the method name was provided to the engine command the same algorithm is
applied to that method only and its arguments are used where the class
properties would be used otherwise. In this case methods can be any methods
that can be invoked by the API which currently are actions and model builder
methods.
Model builders
--------------
Model builders are special MuranoPL methods that take a class definition
(in an object model format dictionary form) and number of optional arguments
and return modified object model.
Model builders are used to simplify object model generation using the template
obtained from its parameters. When generating json schema from such methods
their first parameter (which is current object model) is skipped.
In order for a method to be considered a model builder it must have the
following properties:
#. It must be static (`Usage: Static`)
#. In must have the public scope (`Scope: Public`. I.e. it must be a static
action. See https://blueprints.launchpad.net/murano/+spec/static-actions for
more information on static actions)
#. It must have `io.murano.metadata.ModelBuilder` `Meta` applied to it.
This is a marker class that is going to be introduced to the core library
to distinguish model builders from other static actions.
Caller uses static actions API to invoke the builder and obtain a generated
object model snippet.
UI hints
--------
In addition to the information that can be obtained from contracts some
additional information is needed to produce correct representation for
the property or argument. This information is provided by meta-classes
that need to be introduced to the core library:
`io.murano.metadata.Title`: title of an entity. Can be applied to anything.
The value is in `text` property of a meta-class. Upon schema generation
it is translated to `title` schema key. If no meta is attached then the
property/argument name is used as a title.
`io.murano.metadata.Description`: description of an entity. Can be applied to
anything. The value is in `text` property of the meta-class. Upon schema
generation it is translated to `description` schema key.
`io.murano.metadata.HelpText`: help text of an entity. Can be applied to
anything. The value is in `text` property of the meta-class. Upon schema
generation it is translated to `helpText` schema key.
`io.murano.metadata.forms.Hidden`: marks property or argument to be invisible.
Upon schema generation `"visible": false` is produced.
`io.murano.metadata.Position`: position of the property/argument within the
form. It has two properties:
* `index`: integer by which all of the fields are sorted before rendering.
it doesn't have to be consecutive. If the inherited field has the same
index as the field from the generated class then inherited one goes first.
For this matter property indexes might be re-enumerated upon schema
generation to the consecutive unique indexes. This property is translated
to `formIndex` schema key. If no position specified then the field will be
placed in the list of unordered fields (probably sorted by their title).
* `section': section name for the field. If not provided then it will be
automatically placed in default section for all such fields.
Section name is represented as `formSection` key in the schema of each
field. Additional attributes for the section with that name can be found
in the root schema for the type/method.
`io.murano.metadata.forms.Section`: specifies form sections for the class.
Can be multiple times applied either to the class or to the method.
It has the following properties:
* `name`: name of the section that is going to be used in
`io.murano.metadata.Position` instances.
* `title`: title of the section. In no title provided it is assumed to be
equal to the section mame.
* `index`: index of the section in a section list (e.g. tab number).
Similar to `Position` indexes those numbers doesn't have to be consecutive
and only used to sort sections within the form.
Child classes may redefine sections inherited from their parent classes by
re-declaring section with the same name.
Sections are translated to the
::
"formSections": {
"mySectionName1": {
"title": "text1",
"index": 0
},
"mySectionName2": {
"title": "text2",
"index": 1
}
}
entries in the root schema of the type or method.
Alternatives
------------
Instead of switching to json-schema we could generate UI definition in existing
(or improved) UI definition format.
Data model impact
-----------------
None
REST API impact
---------------
**GET /schemas**
Execute static MuranoPL method. Method must have a Public scope.
*Request*
+---------+--------------------------------+-------------------------------------+
| Method | URI | Description |
+=========+================================+=====================================+
| GET | /schemas/{className} | Obtain json-schema for class |
+---------+--------------------------------+-------------------------------------+
| GET | /schemas/{className}/{methods} | Obtain json-schema for class method |
+---------+--------------------------------+-------------------------------------+
Parameters:
* `className`: name of the class
* `classVersion`: version or version spec for the class. Optional. If not
provided then '=0' is assumed
* `packageName`: optional FQN of the package. If provided the class will only
looked up there instead of full catalog.
* `methods`: model builder method name or list of names which schemas are
requested. Empty string indicates schema of the class rather than of one of
its methods. If the parameter is absent then all the schemas (both class and
model builders) are returned.
*Response*
::
{
"": {
# json-schema for the class
},
"myModelBuilder1": {
# json-schema for the myModelBuilder1 method
}
}
HTTP codes:
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Schema was generated successfully |
+----------------+-----------------------------------------------------------+
| 400 | Bad request. |
+----------------+-----------------------------------------------------------+
| 401 | User is not allowed to access the schema |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified class or doesn't exist |
+----------------+-----------------------------------------------------------+
Versioning impact
-----------------
If we introduce more capabilities to the contracts then a new FormatVersion
should be introduced.
New murano-dashboard/python-client could still talk to an older API service
that lacks new API call and uses old UI definition alone in this case.
New approach is backward compatible so existing applications will still work.
Other end user impact
---------------------
A new python-muranoclient with a method to obtain json-schema for the class
will be required in order to take advantage on the MuranoPL forms.
Deployer impact
---------------
Maximum number of class implementations need to be specified in murano.conf
file. However it is going to have a reasonable default value.
Developer impact
----------------
In order to have rich GUI, an application developer will have to decorate all
his properties with lots of Meta values. Otherwise if no UI definition file
was provided the UI form may present input fields in a random order with a
labels set to a property name which is not very user friendly.
We should design a way to extract all visual hints into a separate per-class
file to separate them from the application code. This is a subject for another
spec.
Murano-dashboard / Horizon impact
---------------------------------
murano-dashboard should present user with the form constructed from a json
schema. The schema would contain all the required visual hints in the extra
attributes (not defined by the json-schema standard).
The dashboard may either construct the form on its own or use 3rd party
libraries that are capable to generate UI from the schema. In the later case
dashboard might become responsible for generating form definition - a structure
describing visual aspects of the form that is provided in addition to the
schema. Such structure might be produced by extracting required information
from extra attributes of the schema. The dashboard might also split it into
several forms/schemas in order to have a wizard UI rather than a single form.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
Stan Lagun <istalker2>
Work Items
----------
* Create new API method;
* Write python-muranoclient method for new API call;
* Implement RPC method in murano-engine that will do schema generation;
* Write json-schema generator for the class/method;
* Define all the mentioned meta-classes and enhance schema generator to make
use of them.
Dependencies
============
* https://blueprints.launchpad.net/murano/+spec/static-actions
Testing
=======
All the path from the MuranoPL code to the rendered UI form can be tested
by the unit tests. Transformation from MuranoPL to json-schema can be tested
independently from the one from json-schema to the form definition or even
HTML layout.
Documentation Impact
====================
The following need to be documented:
* The new UI workflow.
* json-schema specification link along with description of extra fields added
by Murano;
* All changes made to the contracts;
* Standard Meta classes that can be used for visual hints in MuranoPL;
* Model builder methods documentation;
* Developers guide.
References
==========
* http://json-schema.org
* https://blueprints.launchpad.net/murano/+spec/static-actions

View File

@ -1,228 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=============================================
Change the naming scheme for MuranoPL plugins
=============================================
https://blueprints.launchpad.net/murano/+spec/plugin-fqn-rename
Current naming scheme for classes defined in MuranoPL extension plugins is not
consistent with the naming scheme for regular MuranoPL classes and packages.
This spec addresses this by changing the scheme and proposing a fallback logic
which will provide a backward compatibility for the existing MuranoPL
applications targeting old plugins.
Problem description
===================
MuranoPL classes and packages should have globally unique FQNs to prevent
potential name collisions when environment combines packages provided by
different developers. Recommended approach here is to start the name of a
package with a reversed Internet domain name given that the domain is
controlled by the developer of the package or class (such approach is inspired
by package naming rules of Java, see [1] for more details)
The examples of such class names may include:
* ``com.example.Foo`` - for demo applications and packages
* ``org.openstack.projectName.Foo`` - for applications and packages developed
and maintained by the teams of official Openstack projects
* ``com.companyname.Foo`` - for applications and packages developed and
maintained by a third party controlling the "companyname.com" domain name
* ``io.murano.Foo`` - for applications and packages developed and maintained
by the core murano team as part of the murano project. So, ``io.murano`` is
a preferred alias for longer ``org.openstack.murano`` FQN prefix.
However, currently this approach is not working for the classes defined by
MuranoPL extension plugins, since all the names of these classes have to start
with ``io.murano.extension`` prefix, as this is the requirement of the current
plugin management system. This breaks the naming convention and introduces the
possibility of name collision for plugin-defined classes.
Proposed change
===============
Current plugin system is based on stevedore library [2]. So we are utilizing
the concepts of `namespace` and `entry point name`. The namespace value
identifies the consumer of the plugin, the MuranoPL class plugins are
identified by the ``io.murano.extension`` stevedore namespace. Entry-point
names are the suffixes of the declared class' FQNs: the plugin loader forms the
actual FQN of the class by concatenating the stevedore namespace with entry
point name. For example, Murano's demo plugin [3] (providing Glance API
connectivity) declares the following stevedore-based extension:
::
[entry_points]
io.murano.extensions =
mirantis.example.Glance = murano_exampleplugin:GlanceClient
The developer's provided entry-point name is ``mirantis.example.Glance`` here,
and the current plugin loader will concatenate it with the namespace name thus
resulting in class ``io.murano.extensions.mirantis.example.Glance`` being
loaded by the class loader.
It is proposed to get rid of the concatenation: the stevedore's namespace name
should be used **only** to identify the type of the plugin, while the FQNs of
its classes should be defined only by the names of the entry points. So, when
this change is implemented the example above will load a class with an FQN
``mirantis.example.Glance``, without the ``io.murano.extensions`` prefix.
After this change is implemented the developers of the plugin will be able to
follow the regular naming rules of Murano. So, our example plugin will have to
be renamed to ``com.example.mirantis.Glance`` etc - and it will not be part of
the ``io.murano`` space, as this plugin is just an example and is not supposed
to be part of the core murano.
Backwards compatibility
-----------------------
The proposed change will effectively rename all the classes defined in the
existing plugins by removing the ``io.murano.extensions`` prefix from their
names. These may (and will) break all the MuranoPL code which relies on these
plugins.
To prevent this there should be a fallback logic implemented for the
class loader. When a class being loaded by name is not found and the name
starts with the ``io.murano.extensions`` prefix, there should be a second
attempt to load it by a shortened name without a prefix. If such class is found
and is loaded, a warning message should be logged to indicate that the plugin
is outdated and has to be updated with appropriate naming schema.
note::
This backwards-compatibility mode may be considered a way to deprecate the
old plugin naming scheme. In several releases this fallback logic may be
removed completely.
Alternatives
------------
We may postpone the change of the naming scheme till the next version of the
plugin system is introduced, which will some different format of plugins and
their content etc.
However postponing is bad, since the plugin development for murano is already
active, and having inconsistently named classes makes a bad example in the
community. Waiting for another cycle or two may greatly increase the number of
such bad examples.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Security impact
---------------
Because of the proposed change it will be now possible to define classes having
the names colliding with the Core Library and thus overriding the behavior of
the standard murano classes.
This should not be allowed unless the deployer explicitly allows that in the
configuration.
Deployer impact
---------------
Deployers will have to monitor the logs of Murano Engine for the Warning
messages produced by the loading of outdated plugins in the backwards
compatibility mode.
Developer impact
----------------
Plugin developers will have to update their plugin according the correct
naming scheme.
Application developers using the plugins will have to rename the class usages
in their MuranoPL code to use the new names.
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
ativelkov
Other contributors:
ksnihyr
Work Items
----------
* Modify the plugin loader
* Add backwards compatibility mode to the class loader
* Update existing plugins to utilize the proper naming schema
* Update the documentation
Dependencies
============
None
Testing
=======
No new testing needed. Existing plugin-loading tests should be updated so no
warnings are displayed.
Documentation Impact
====================
Plugin development manual has to be updated.
References
==========
#. https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html
#. https://docs.openstack.org/stevedore/latest/
#. https://opendev.org/openstack/murano/src/tag/mitaka-eol/contrib/plugins/murano_exampleplugin/setup.cfg

View File

@ -1,394 +0,0 @@
===============================================
Support for Service Function Chaining in Murano
===============================================
One of the foundations for NFV enabled clouds is to have Networking Service
Function Chaining which provides an ability to define an ordered list of
network services which to form a “chain” of services. This could be used by
f.e. telcos to simplify management of their infrastructure.
Problem description
===================
Service chaining allow to pass traffic from endpoint A to endpoint B thru any
number of additional network service VMs. Those VMs are managed by tenant
admin.
With standard OpenStack networking traffic goes directly from A to B::
+--------+ +--------+
| VM A |-->| VM B |
+--------+ +--------+
With SFC traffic goes thru additional hops, which can perform any action
(firewall, LB, ...)::
+------+ +-------+ +-------+ +-------+ +------+
| | |Service| |Service| |Service| | |
| VM A |-->| VM A |-->| VM B |-->| VM C |-->| VM B |
+------+ +-------+ +-------+ +-------+ +------+
Those service VMs are transparent for end-user.
To achieve this, it would require to extend some of the OpenStack components.
Murano is suitable for defining such chains, but currently lacks of necessary features.
SFC use few entities to deliver chaining:
* Port pair
Represents vNIC (ingress/input, egress/output) attached to service VM.
Those vNICs will be used to receive (ingress) and send (egress) SFC traffic.
* Port group
Represents list of port pairs of different VMs with the same service function.
* Flow classifier
Used to classify network traffic, based on different metrics (e.g. source IP,
destination IP, source port, destination port, ...).
Only traffic which matches flow classifier will be handled by SFC.
* Port chain
Represents a releationship between flow classifiers and port groups.
To be able to use NFV functionality it is needed to have Service Chaining
functionality available in OpenStack.
Neutron does not support Networking SFC out of the box.
Currently Heat does not support configuration for Networking SFC API.
Currently Murano does not support Networking SFC management at all.
If we want to use Murano as a Resource Orchestrator it needs to have support
for configuring Service Chaining.
.. note::
Networking-SFC caveats:
* Current SFC implementation is not mature
* Supports only Open vSwitch
* API under heavy development
* Multiple API limitations
* No ready service VM software (capture SFC traffic, do *thing*, pass SFC
traffic to next hop)
Proposed change
===============
To solve problems above it is needed to introduce changes in Murano.
Having Murano as a Resource Orchestrator we need to have an ability to
configure Networking SFC from within Murano application templates.
This involves to implement changes in several areas.
Murano will be extended with:
* `Murano plugin`_ that will provide Networking SFC class which will be
a wrapper for lower level Neutron API.
* `Murano library package`_ that will provide Murano PL classes for
Networking SFC entities (e.g. PortPair, PortPairGroup, etc.)
Murano plugin
-------------
A python plugin that provides low-level wrappers for Neutron API functions
which are provided by Networking SFC extension. It implements direct method
wrappers for neutronclient library:
.. note:: Interface may change in the future
* ``createPortPair``
* ``deletePortPair``
* ``listPortPairs``
* ``showPortPair``
* ``updatePortPair``
* ``createPortPairGroup``
* ``deletePortPairGroup``
* ``listPortPairGroups``
* ``showPortPairGroup``
* ``updatePortPairGroup``
* ``createFlowClassifier``
* ``deleteFlowClassifier``
* ``listFlowClassifiers``
* ``showFlowClassifier``
* ``updateFlowClassifier``
* ``createPortChain``
* ``deletePortChain``
* ``listPortChains``
* ``showPortChain``
* ``updatePortChain``
Murano library package
----------------------
Application developer should have a possibility to configure Networking SFC
entities from Murano PL classes. We will introduce Murano plugin which will
extend to support configuration of following SFC classes:
* Port Pair
* Port Pair Group
* Flow Classifier
* Port Chain
All above parameters should be provided to successfully configure application
chaining. This should be done in Murano template for meta application
responsible for provisioning whole set of applications. Only mandatory SFC
parameters should be available for editing in Murano application UI.
PortPair class
~~~~~~~~~~~~~~
A Port Pair represents a service function instance. The ingress port and the
egress port of the service function may be specified. If a service function
has one bidirectional port, the ingress port has the same value as the egress
port.
**Properties:**
* ``id`` - Port pair ID
* ``name`` - Port pair name (Default: '')
* ``description`` - Readable description (Default: '')
* ``ingressPort`` - Ingress port (Reference to NeutronPort object)
* ``egressPort`` - Egress port (Reference to NeutronPort object)
.. note:: ingressPort and egressPort need to be changed to references once
Murano Core Library has support of network objects.
**Methods:**
* ``PortPair.deploy()`` - Create port pair object
* ``PortPair..destroy()`` - Cleanup resources (called implicitly)
**Example:**
.. code-block:: yaml
Namespaces:
=: com.example
netsfc: io.murano.extensions.networkingSfc
Name: DemoApp
Properties:
...
portPair: $.class(netsfc:PortPair).notNull()
Methods:
deploy:
Body:
- ...
- $.portPair.deploy()
PortPairGroup class
~~~~~~~~~~~~~~~~~~~
Inside each "port-pair-group", there could be one or more port-pairs.
Multiple port-pairs may be included in a "port-pair-group" to allow the
specification of a set of functionally equivalent SFs that can be be used for
load distribution, i.e., the "port-pair" option may be repeated for multiple
port-pairs of functionally equivalent SFs.
**Properties:**
* ``id`` - Port pair group ID
* ``name`` - Readable name (Default: '')
* ``description`` - Readable description (Default: '')
* ``portPairs`` - List of PortPair class objects.
**Methods:**
See `PortPair class`_
Example:
.. code-block:: yaml
Name: DemoApp
Properties:
...
portPairs: [$.class(netsfc:PortPair).notNull()]
Methods:
deploy:
Body:
- ...
- $.portPairGroup: new(netsfc:PortPairGroup, portPairs => $.portPairs)
- $.portPairGroup.deploy()
FlowClassifier class
~~~~~~~~~~~~~~~~~~~~
Flow classifiers are used to select the traffic that can access the chain.
Traffic that matches any flow classifier will be directed to the first port
in the chain. The flow classifier will be a generic independent module and
may be used by other projects like FW, QOS, etc.
A flow classifier cannot be part of two different port-chains otherwise
ambiguity will arise as to which chain path that flow's packets should go.
A check will be made to ensure no ambiguity. But multiple flow classifiers
can be associated with a port chain since multiple different types of flows
can request the same service treatment path.
**Properties:**
* ``name`` - Classifier name
* ``ethertype`` - IPv4 (default) / IPv6
* ``protocol`` - IP protocol
* ``sourcePortRange`` - Source protocol port; port number or tuple of min and
max ports
* ``destinationPortRange`` - Destination protocol port; port number or tuple of
min and max ports
* ``sourceIpPrefix``
* ``destinationIpPrefix``
* ``logicalSourcePort`` - neutron source port (required)
* ``logicalDestinationPort`` - neutron destination port (required)
* ``l7Parameters`` - dictionary of L7 parameters (not used)
**Methods:**
See `PortPair class`_
PortChain class
~~~~~~~~~~~~~~~
A Port Chain is a directional service chain. The first port of the first
port-pair is the head of the service chain. The second port of the last
port-pair is the tail of the service chain. A bidirectional service chain would
be composed of two unidirectional Port Chains.
**Properties:**
* ``id`` - Port chain ID
* ``name`` - Readable name
* ``description`` - Readable description
* ``portPairGroups`` - List of PortPair class objects
* ``flowClassifiers`` - List of FlowClassifier class objects
**Methods:**
See `PortPair class`_
Delivering Murano extensions
----------------------------
Murano uses stevedore [0] library to support plugins. Basically stevedore
plugin is a python package with special metadata (plugin entry points).
It can be installed as python package (via ``pip``) or distribution specific
package (e.g. DEB, RPM, etc.). Murano plugins provides new classes
that are referenced in the plugin metadata.
Murano library package is a simple **zip** archive which contains
``metadata.yaml`` file and Murano PL classes.
It can be installed from file using ``murano`` command-line tool
or from the repository.
Alternatives
------------
Extend Heat to support Networking SFC.
Instead of accessing Neutron API directly from Murano plugins, Murano can
manage Networking SFC through Heat resources. It will require creating Heat
extension which will delegate SFC configuration from Heat templates.
Heat extension should provide set of resources which will implement.
Networking SFC entities:
* Port Chain
* Port Pair Group
* Port Pair
* Flow Classifier
Heat can be extended by adding new resources using plugins. It provides mapping
between heat resources and python classes. It will implement hooks on heat
events like resource create, update etc.
**PROS:**
* Resource management delegated to Heat. Heat can be used for resource cleanup
* Heat can provide some helpful transactional capabilities
* Cloud operator will be able to use SFC w/ and wo/ Murano
**CONS:**
* Security-related implications for customers, who wants to keep vanilla
OpenStack installation.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
End user will be able to use networking SFC from Murano templates.
Networking SFC will introduce additional delay in RTT (round-trip-time).
This mean some applications prone to network delays can stop working.
Deployer impact
---------------
To use SFC with Murano cloud operator needs to install and enable SFC Murano
plugin.
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Work Items
----------
* Create Murano Networking SFC plugin
* Create Murano library package
* Create Murano test application
* Implement support of multiple Neutron ports to Murano Core Library
* Tests
Dependencies
============
Murano plugin depends on networking-sfc package, which should be installed.
Testing
=======
Proper functional tests should be implemented.
Documentation Impact
====================
User will be informed how to enable and start using networking SFC inside
Murano templates.
References
==========
[0] - http://docs.openstack.org/developer/stevedore/

View File

@ -1,385 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==============
Static actions
==============
https://blueprints.launchpad.net/murano/+spec/static-actions
Currently Murano provides a way to invoke MuranoPL methods through the
actions API. However it doesn't cover all the use cases where one may want
to expose some MuranoPL code. This specification further improves the idea
of actions.
Problem description
===================
Existing actions approach has a number of limitations:
* Only instance methods can be exposed as actions. In other words you need
to have a class instance in order to call a method on it. And instance means
it has to be a part of object model. This makes impossible to expose MuranoPL
code that doesn't operate on object model or even produces it like factory
methods;
* Actions bring large overhead and complexity for simple methods. For each
action call a database record is created and never deleted then. All action
results are persisted as well;
* No two actions in the same environment can be called simultaneously.
All of above is not a problem for regular application actions that usually
involve deployment steps and can take long time to complete. However it makes
actions a bad choice in case when one just wants to expose some application
code to outside to keep all of his code in MuranoPL in single place.
Proposed change
===============
In order to overcome above issues it is proposed to add ability to expose and
call static MuranoPL methods through new API and engine RPC calls. Because
the methods are static they are not bound to any object model (environment)
and thus can be called simultaneously.
Also because now there are two types of action methods (static and instance)
the fact that method needs to be exposed cannot be expressed with the Usage
attribute of the method (static methods already have `Usage: Static`).
We could introduce yet another usage (e.g. `StaticAction`). But because action
means that regular MuranoPL method need to be exposed to outside and it has
much more to do with a method visibility rather then its usage it is proposed
to introduce another method keyword to declare its scope.
Thus current syntax for the action declaration
::
methodName:
Usage: Action
will become
::
methodName:
Scope: Public
and static actions will be declared as
::
methodName:
Usage: Static
Scope: Public
`Scope` attribute must be one of the two possible values:
* `Session` - regular method that is accessible from anywhere in the current
execution session. This is the default if the attribute is omitted;
* `Public` - accessible anywhere, both within the session and from outside
through the API call (i.e. it is an action in current terminology).
In the future new scopes might be added to further restrict the access
to the method (e.g. `Package`, `Class`)
For backward compatibility `Usage: Action` should remain valid and acceptable
but be deprecated for future format versions. An exception must be raised if
both `Usage: Action` and `Scope: Session` are specified.
Synchronous and asynchronous actions
------------------------------------
Current instance actions are always asynchronous and this is achieved by means
of API with action result being persisted into database. For static methods
that doesn't usually do any deployment and much more suitable for quick
request-response interactions that do not modify object model this would be
an overkill that greatly reduces their performance. However if we make
static actions synchronous this will cause confusion because we get two
completely different usage pattern for method that differ only by the fact
that one is static and another is not. This is especially confusing due to the
fact that one can easily imagine synchronous instance actions and asynchronous
static ones. Thus it is proposed to:
#. On MuranoPL side all actions are synchronous i.e. they are plain methods
that return the result;
#. RPC calls for action execution are always asynchronous. I.e. the call to
invoke the method and call to notify API on the method result are two
different calls rather than single request-response. However the request
may indicate that the response must be sent to specific API instance to
make synchronization on the API without database persistence possible.
#. On python-muranoclient side all actions are asynchronous in terms that you
get a Future object from which one can get result later as well as check for
its readiness. For synchronous call the result becomes available immediately.
However from the user's perspective all methods are asynchronous.
Current python-muranoclient method for action execution returns action ID
that can be later provided to another method rather that a Future object.
For consistency it is proposed to change that method to return Future
instead. For backward compatibility the method that accepted action ID
must accept task Future too.
#. It is the API who decides if the method is going to be executed
synchronously or not. In the former case API does RPC request to the engine
without creating database records and instead waits for response that
must be sent to that API instance. As soon as result is available it is
returned to the caller (python-muranoclient). For now the API is going
to do synchronous execution for static actions and asynchronous for
instance actions. However in the future we may consider making it
configurable or introduce some level of automation when API can wait for
some time and then switch to asynchronous mode (create database record
and so on) if there is still no result.
Alternatives
============
* Use actions instead for cases where static methods will be more appropriate;
* Declare static actions with yet another Usage value or make Usage be a list
([Static, Action])
* Use Meta to declare actions
Data model impact
=================
None
REST API impact
===============
**POST /actions**
Execute static MuranoPL method. Method must have a Public scope.
*Request*
+----------+----------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==================================+==================================+
| POST | /actions | Execute static action |
+----------+----------------------------------+----------------------------------+
Body:
::
{
"className": "my.class.fqn",
"methodName": "myMethod",
"packageName": "optional.package.fqn",
"classVersion": "1.2.3",
"parameters": {
"arg1": "value1",
"arg2": "value2"
}
}
packageName is optional. If provided the class must be in that package.
classVersion is optional. If provided it may contain either full SemVer version
or version spec (e.g. ">1.2"). If omitted "=0" is assumed.
*Response*
JSON-serialized method response or exception is returned.
HTTP codes:
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Action was executed successfully |
+----------------+-----------------------------------------------------------+
| 400 | Bad request. Either the format of the body is invalid or |
| | parameters doesn't match the contracts |
+----------------+-----------------------------------------------------------+
| 403 | User is not allowed to execute the action |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified class or method doesn't exist |
| | or not exposed |
+----------------+-----------------------------------------------------------+
| 503 | Unhandled exception in the action |
+----------------+-----------------------------------------------------------+
Versioning impact
=================
None
Other end user impact
=====================
python-muranoclient must be updated to provide method for the new API call.
Deployer impact
===============
None
Developer impact
================
Existing MuranoPL applications shouldn't be affected by the change.
For the next package format version old syntax of action declaration
should still work but produce a deprecation warning.
Murano-dashboard / Horizon impact
=================================
None
Implementation
==============
Assignee(s)
-----------
Stan Lagun <istalker2>
Work Items
----------
* Update DSL to make use Scope method attribute
* Update code that inspects if method is an action for the new syntax
(including object model serializer)
* Implement new RPC call in murano-engine
* Implement API call
* Implement method in python-muranoclient
Dependencies
============
None
Testing
=======
RPC call implementation can be tested by unit tests alone.
However to test the new API several tempest tests need to be added:
* Test that executes sample MuranoPL static action (hello world)
* Test that executes method that throws an exception
* Test that executes method with invalid parameters
Documentation Impact
====================
* Documentation for the actions need to be updated
* Developer's guide need to be extended with static actions info
* REST API specification need to be updated with new call info
References
==========
None
Versioning impact
-----------------
None
Other end user impact
---------------------
python-muranoclient must be updated to provide method for the new API call.
Deployer impact
---------------
None
Developer impact
----------------
Existing MuranoPL applications shouldn't be affected by the change.
For the next package format version old syntax of action declaration
should still work but produce a deprecation warning.
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Stan Lagun <istalker2>
Work Items
----------
* Update DSL to make use Scope method attribute
* Update code that inspects if method is an action for the new syntax
(including object model serializer)
* Implement new RPC call in murano-engine
* Implement API call
* Implement method in python-muranoclient
Dependencies
============
None
Testing
=======
RPC call implementation can be tested by unit tests alone.
However to test the new API several tempest tests need to be added:
* Test that executes sample MuranoPL static action (hello world)
* Test that executes method that throws an exception
* Test that executes method with invalid parameters
Documentation Impact
====================
* Documentation for the actions need to be updated
* Developer's guide need to be extended with static actions info
* REST API specification need to be updated with new call info
References
==========
None

View File

@ -1,668 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
===============================================
Validation tool for Murano Application Packages
===============================================
https://blueprints.launchpad.net/murano/+spec/murano-app-validation
Murano doesn't have validation mechanisms for MuranoPL language and
application packages.
This spec proposes a validation toolkit that improves workflow
by making error detection possible at the early stages of application
development lifecycle.
Problem description
===================
Early error detection simplifies application development,
troubleshooting and support.
Currently Murano does not provide mechanisms to perform validation of the
Murano application package before running deployment process.
Thus Murano cannot prevent uploading of invalid package and developer
cannot verify that application package contains valid structure
and code before deployment process.
Many problems with application packages (such as invalid package structure,
errors in code, typos, etc.) can be detected and solved by using
static validation tool.
Proposed change
===============
Introduce a new toolkit for validation MuranoPL language and Murano application
packages.
* Validation toolkit SHOULD be implemented as a standalone Python package
(library) with CLI interface.
* Validation library will be used to validate Murano packages during loading
process.
* CLI tool can be used by application developer to perform early checks before
package is assembled.
* Toolkit should be extensible with custom validators. It will provide API for
extension purposes.
* Toolkit should be configurable to run list of specified inspections
or to ignore specified inspections.
Toolkit should implement the following validation suites:
* Manifest validation
* Classes validation
* UI definition validation
Other validators will be implemented later as part of this tool or as external
packages
Manifest validation
-------------------
* ``manifest.yaml`` file should exist and should be a valid YAML document.
* ``manifest.yaml`` structure should respond to manifest structure described in
:ref:`manifest-structure-section`.
* All files referenced in ``Classes`` section should exist in ``Classes``
subdirectory and should be valid YAML documents.
* Warning should be reported in case when additional files exist in ``Classes``
subdirectory but not referenced in the manifest file.
* UI definition file should exist for Application package (MuranoPL =< 1.4)
Class validation
----------------
* Valid classes and methods should check if properties are defined
correctly and there are no extra keys that are not supported.
* Check if class is in correct namespaces according to manifest and
class name matches.
* Contract fields should be valid YAQL expressions.
* Methods blocks should be checked for MuranoPL code structure correctness.
Method blocks may consist only of Expressions, Assignments and Block
constructs. See `full terms description <http://docs.openstack.org/developer/murano/draft/appdev-guide/murano_pl.html#method-body>`_
for details.
* (Optional) Detect code that cannot be parsed as YAQL expression but is
considered to be a valid expression.
UI validation
-------------
* UI definition should contain ``Application`` and ``Forms`` sections
* YAQL expressions in UI definition should be valid
* ``Form`` section should contain only valid forms
`<http://docs.openstack.org/developer/murano/draft/appdev-guide/murano_packages.html#forms>`_
Errors
------
Error code consists of prefix and error number. Prefix is an upper case
alphabetical sequence. It can be empty for general errors. Errors specific for
some validator should use validator short name as prefix. Error number is an
upper case alphanumerical sequence (one single letter ``E`` or ``W``
following by three digits). Examples: ``E007``, ``MPL:E042`` for errors and
``W777``, ``UI:W123`` for warnings. Validation tool should have ability to
produce documentation of supported errors and warnings.
Package structure reference
---------------------------
http://docs.openstack.org/developer/murano/draft/appdev-guide/murano_packages.html#package-structure
Package consists of:
* Manifest - File in package root directory named ``manifest.yaml``.
* MuranoPL classes - YAML files located in ``Classes`` directory or its
subdirectories (optional).
* UI definition - YAML file in ``UI`` directory (optional).
* Resources - files in ``Resources`` directory (optional).
* Logo (optional)
* images.lst file (optional)
.. _manifest-structure-section:
Manifest structure
^^^^^^^^^^^^^^^^^^
**Format**
Application package format. Can be specified as ``<FORMAT>/<VERSION>``,
where format is a format name string (can be ``MuranoPL`` or ``Heat.HOT``).
If format is omitted, ``MuranoPL`` is used by default.
* Required: no
* Default: ``MuranoPL/1.0``
* Format: ``<FORMAT>/<VERSION>``
**Type**
* Required: yes
* Type: Enum(Application, Library)
**Name**
Package human readable name
* Required: no
* Type: String
**FullName**
Package fully qualified name. Should be in lowerCamelCase notation
separated by dots.
* Required: yes
* Type: String
**Version**
Version of package
* Required: no
* Default: ``0.0.0``
* Type: String, should have valid `SemVer format <http://semver.org/>`_
**Description**
* Required: no
* Type: String
**Author**
* Required: no
* Type: String
**Tags**
* Required: no
* Type: List(String)
**Classes**
* Required: no
* Type: Dict
- Keys: String, Fully qualified class name
- Values: String, Filename relative to ``Classes`` directory
**Require**
Package external requirements.
* Required: no
* Type: Dict
- Keys: Dependent package ``FullName``
- Values: ``null`` or string with exact version ('1', '2.3', '4.5.6') or
valid spec_strings according to `python-semanticversion docs <https://python-semanticversion.readthedocs.io/en/latest/reference.html#semantic_version.SpecItem>`_
**UI**
File with package UI definition
* Required: yes (for package type ``Application``)
* Type: String, Filename relative to root directory
* Default: ``logo.png``
**Logo**
Package logo in png format.
* Required: no
* Type: String, Filename relative to ``UI`` directory
* Default: ``ui.yaml``
**Meta**
* Required: no
* Type: Dict or List(Dict) with metadata information
Class structure
^^^^^^^^^^^^^^^
**Name**
* Required: yes, if more than one class defined in the file
* Type: String
* Format:
- Matches Python class name format, except leading
double underscore (``__ClassName``).
- Matches CamelCase naming style.
**Properties**
* Required: no
* Type: Dict
For more details see :ref:`class-properties-section`.
**Methods**
* Required: no
* Type: Dict
For more details see :ref:`class-methods-section`.
**Extends**
Single or multiple class names.
* Required: no
* Type: String | YAML List
**Namespaces**
* Required: no
* Type: Dict
* Keys: String; Namespace alias
* Values: String; Namespace full qualified name
* Format:
- Namespace alias is a valid YAQL identifier or ``=``.
- Namespace FQN is a string divided by dots (``.``).
- Recommendation is to use lowerCamelCase naming style.
**Import**
* Required: no
* Type: String, Class name, List(Class names)
**Usage**
* Required: no
* Type: Enum(Class, Meta)
* Default: ``Class``
**Meta**
* Required: no
* Type: Dict or List(Dict) with metadata information
MetaClass structure
^^^^^^^^^^^^^^^^^^^
In addition to regular Class structure, MetaClass (Class with Usage: Meta) can
have additional properties:
**Cardinality**
* Required: no
* Type: Enum(One, Many)
**Applies**
* Required: no
* Type: Enum(Package, Type, Method, Property, Argument, All) or List(Enum)
**Inherited**
* Required: no
* Type: boolean
.. _class-properties-section:
Class properties
^^^^^^^^^^^^^^^^
**Contract**
* Required: yes
* Type: YAQL Expression
**Usage**
* Required: no
* Type: Enum
========= ====================
Usage
========= ====================
In Default
Out
InOut
Const
Runtime
Config Since version 1.1
Static Since version 1.2
========= ====================
**Default**
* Required: no
* Type: Any value
**Meta**
* Required: no
* Type: Dict or List(Dict) with metadata information
.. _class-methods-section:
Class methods
^^^^^^^^^^^^^
**Scope**
.. versionadded:: 1.4
* Required: no
* Type: Enum
* Values: Public, Session
**Arguments**
* Required: no
* Type: List(Dict)
For more details see :ref:`methods-argument-section`.
**Body**
* Required: no
* Type: YAQL Expression | List(YAQL Expression)
**Usage**
* Required: no
* Type: Enum
========= ====================
Usage
========= ====================
Runtime Default
Static Since 1.3
Extension Since 1.3
Action Deprecated since 1.4
========= ====================
**Meta**
* Required: no
* Type: Dict or List(Dict) with metadata information
.. _methods-argument-section:
Method's Argument
^^^^^^^^^^^^^^^^^
* Type: Dict(String, Dict)
* Key: Argument name
**Values:**
* Contract: YAQL Expression
* Default: YAQL Expression
* Usage: Enum added since 1.4
========= ====================
Usage
========= ====================
Standard Default
VarArgs
KwArgs
========= ====================
**Meta**
* Required: no
* Type: List with metadata information
Extensions
----------
Validation tool should be extensible and provide unified mechanism for builtin
checks and extensions.
Extensions should be implemented as a python package and registered using
entry points.
Extensions are loaded using
`stevedore <http://docs.openstack.org/developer/stevedore/>`_ library.
CLI Usage
---------
::
Usage: mpl-check [options] <PACKAGE | DIRECTORY>
Arguments:
DIRECTORY Application working directory (e.g. contains
manifest.yaml, Classes/, etc.)
PACKAGE Compressed application (ZIP-archive)
Options:
--ignore=errors Skip errors and warnings.
--select=errors Check only for selected errors and warnings.
--scope=validators List of validators to execute
--strict Consider warnings as an errors.
Alternatives
------------
Implement validation as part of Murano and validate the package
when it is uploaded to Murano.
Pros:
- Easier to implement.
Cons:
- Suitable for Murano itself, but not for developers.
- Integration with CI which requires execution of functional
tests and is slower than static validation.
- Cannot be integrated with text editors or IDEs.
Data model impact
-----------------
None
REST API impact
---------------
Murano API for upload packages should use this tool to do package validation
before store it. If package is not valid, HTTP error with code 400 should be
returned to user with list of check errors in description.
Versioning impact
-----------------
None
Other end user impact
---------------------
* Murano application package developer will be able to validate package
during development process.
Deployer impact
---------------
None
Developer impact
----------------
Application developer will be able to validate application code
during development process without importing package to Murano
and running deployment process or test suite.
Murano-dashboard / Horizon impact
---------------------------------
Error message is displayed in Horizon when trying to upload
malformed package.
Implementation
==============
Application class
-----------------
Application class provides an entry point to the checker.
It is responsible for configuration, extensions loading and validation
execution.
Application options are registered using oslo.config
**Methods:**
* __init__(self, options)
* ``load_plugins(self)`` - Finds validators from installed plugins
* ``prepare_check_suit(self, loaded_package, validator_list)`` - Collect
prepared checks from all validators in validator_list against specified
package. Returns list with prepared checks.
* ``list_errors(self, filters)``- Lists errors/warnings exposed by all available
validators
Validator classes
-----------------
Validator class represents set for specific checks and logic to register them.
**Classes**
::
BaseValidator
+-- PackageValidator
+-- ManifestValidator
+-- UiValidator
+-- ClassValidator
**Attributes**
* ``short_name`` short name for validator. Used as prefix for validator specific
errors
**Methods**
* ``__init__(loaded_package)`` - Init validator for specific format
* ``run(self)`` - Runs validator against specified suit of files or
whole package if file_suit=None (for Package validator)
Checkers
--------
Checker is a function that performs checking logic. It takes data from args
and yields error if it is not valid. Checkers should not contain logic for
data preparation. Checker can be reused multiple times with different options
in a single suit of checks. Checker can be wrapped with custom filters
(i.e. manifest version), so it is called only for matching conditions.
Exceptions
----------
Class ``CheckerError`` contains information including error code, message,
file name and position in that file. Additionally it can include
code snippet, if it's available. For YAML data it's available using
``yaml.error.Mark`` class. Otherwise code snippet can be generated during
error formatting.
**Attributes**
* code - Error code (Usually single letter and three digits)
* message - Human readable error reason
* filename - File name relative to package root
* line - Line number (starts from 0, optional)
* column - Column number (starts from 0, optional)
* source - One line code snippet with highlighted column (optional)
Package loaders
---------------
Package loaders provide interface to Murano packages in multiple formats.
Currently packages can be loaded from directory, single file or zip archive
package.
::
PackageLoader
+-- DirectoryLoader
+-- FileLoader
+-- ZipLoader
**Methods**
* ``try_load(cls, path, *options)`` - [classmethod] Tries to load package, if it
can be loaded returns instance of loaded package, otherwise None.
Loaded package
^^^^^^^^^^^^^^
Loaded package class introduces a general interface for access to packages of
different format.
**Methods**
* ``get_file(self, name)`` - File wrapper if file exists, None otherwise
* ``format(self)`` - Ru
* ``exists(self, name)`` - Returns true if file exists in the package.
* ``list(self, subdir=None)`` - Returns list of all files in the package
(or in it's subdirectory).
* ``search_for(self, regex)`` - Return iterator of files fit to regex
File wrapper allows to access to raw file context with method ``raw()`` and
to parsed dict with method ``parsed()``
Formatters
----------
Formatter classes help to represent error report in various ways.
Errors can be printed to ``stdout``/``stderr`` using text representation,
which suits developer or written to file in ``JSON``/``YAML`` format.
Assignee(s)
-----------
Primary assignee:
Alexander Saprykin <cutwater>
Other contributors:
Krzysztof Szukielojc <kszukielojc>
Sergey Slipushenko <sslypushenko>
Work Items
----------
#. Develop core framework with support of extensions.
#. Implement manifest and package structure checks.
#. Implement Murano PL classes checks.
#. Implement UI definition file validation.
#. Implement YAQL checks.
#. Integrate package validation with murano API.
#. Develop CLI tool based on core framework
#. Create documentation.
Dependencies
============
* `PyYAML <http://pyyaml.org/>`_
* `stevedore <http://docs.openstack.org/developer/stevedore/>`_
Testing
=======
Package should include unit and functional tests.
Documentation Impact
====================
Documentation for the library should include:
* Usage information that describes how to use the application.
* API reference.
* Plugin developer documentation.
References
==========
None

View File

@ -1,669 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
====================
Application policies
====================
https://blueprints.launchpad.net/murano/+spec/application-policies
The spec proposes mechanism that cloud operators can use to impose
constraints on applications and alter application behavior without
making modifications to the source code of the apps.
Problem description
===================
Cloud operators often want to have control over what Murano applications can
or cannot do, impose limitations on environment content or alter applications
behavior somehow in a way that can be applied to a wide range of applications.
Possible policies that operator might want:
* Have a black list of applications (that either has explicit application names
or all apps in particular namespace) including their inheritors for
particular tenant
* Make each deployed environment have particular application
* Want particular script to be executed on each VM spawned regardless of the
image being used by the application
* Want to have quota on the number of instances that can be created by a single
application
* Do not allow to use large instance flavors for all applications except for
explicitly approved
* Change application defaults so that particular promoted image will become
the default value in UI for all applications that work on this OS
* Send notification when number of spawned instances in particular environment
exceeds quota
* Change default network topology for particular tenant
* Implement custom billing based on the application activities without
requiring all applications to emit notifications for them.
* Honor policies from the third party policy engine
As you can see all of the policies above are very different in their nature,
require different inputs and different ways to apply them. Also there can
be much more use cases and their variants in order have upfront support for
all of them.
Thus Murano needs a generic way to write policy enforcement rules and actions.
Proposed change
===============
Each policy case consists of two parts: rules specification and code that
applies them.
The code is going to be written as MuranoPL classes that implement required
interface. These classes are called aspects. Each aspect captures and applies
one policy pattern.
Policy rules are going to be the input for those classes (their property
values, similar to our regular object model).
Examples of such input might be:
* Endpoint of the third party policy engine
* Name of the image
* List of YAQL predicates (policy rules)
* Parameters of the largest flavor possible
So each instance of aspect class provided with the values for the rules
parameters can be called a policy as it contains both parts of the policy
definition.
Aspects are provided using the same Murano package format and reside in the
same catalog as applications are. Aspects are going to be located in the
catalog in the packages of the new type ``Aspect``. All aspect classes will be
inherited from the base ``Aspect`` class which should implement some basic
interface for aspects as well as some boilerplate code.
Policy UI workflow
------------------
To use policies, admin should execute the following workflow in UI:
* Import packages with aspect classes (usual package upload).
* Create policies by adding aspects to the list of the ones he wants to apply
and specifying the policy rules as an input parameters. The same UI workflow
(including dynamic UI parts) that is used for adding regular Murano
applications to environments is used here. The difference is that no
environment is needed.
* Apply aspects for particular tenants or globally. New type of GUI form must
be created for that but it should be quite simple.
Instances of aspects, a.k.a policies (i.e. their serialized representation) are
going to be created independently from environments and stored in a dedicated
table in the database. Terms "aspect instance" and "policy" can be used
interchangeable further in this spec to make accent on the one or another shade
of the meaning.
In order for aspects to do their job they are going to be provided with
additional capabilities that are not available to the rest of MuranoPL apps.
Aspects event hooking
---------------------
Aspects should have ability to hook themselves to various system events
produced by the engine. These could be:
* Object model load events
* Package load events
* Object creation events that happen before/after new() function is used
anywhere in the code
* Garbage collection events
In the initial implementation it is proposed to introduce hooking just to
object creation and package load events. It covers the most important use
cases of policies (changing MuranoPL class code and changing object property
values).
Two new MuranoPL classes need to be added to the Murano core library:
* ``io.murano.policy.Aspect`` - the basic interface and boilerplate code
provider for all custom aspects. It has the following methods:
+ ``subscribe(notifier)`` - method which invokes notifier's ``subscribe``
method passing the calling aspect, event name and aspect's method names
as arguments. It subscribes aspect to notifications from notifier.
Subscribes to all events in the base ``Aspect`` class and can be
overridden by inheritor not to subscribe to some events or to subscribe
to some event several times with different conditions and handlers.
This method is called by the engine right after aspects and notifier
objects initialization
+ *condition methods* - methods which define the condition needed to be
checked against some item (e.g. initializing object in case of object
init event, class in case of package load event) to determine whether
event handler method of the aspect should be called with that item. This
group of methods include ``objectInitCondition(object)`` and
``packageLoadCondition(class)``. ``modelLoadCondition(model)`` can be
added later. These methods return ``false`` in the base class which means
no item is handled. It should be overridden by inheritor to specify
actual condition. For example, ``objectInitCondition`` can check that
object is the instance of particular class or that it has some property
+ *handling methods* - methods which apply policy rules to some item (e.g.
initializing object in case of object init event, class in case of
package load event) when corresponding event occurs. So it is the core
part of the policy. This group of methods include
``handleObjectInit(object)`` and ``handlePackageLoad(class)``.
``handleModelLoad(model)`` can be added later. The body of these methods
is empty in the base class. Other handling methods can be also added and
used in the inheritor class
* ``io.murano.policy.Notifier`` - the class to manage notifications of
the proper aspects about system events. It has one property ``_handlers``
which holds the dict with event names as keys and lists of event handlers
as values. Each handler is a dict with aspect object, its condition method
name and handling method name. ``Notifier`` has the following methods:
+ ``subscribe(subscriber, eventName, methodName, conditionMethodName)`` -
method to populate notifier's ``_handlers`` dict. It is called by each
aspect that wants to subscribe to some event
+ ``callHandler(handler, item)`` - method that firstly invokes
conditionMethod stated in the handler dict, in case it returns ``true``
for the item, invokes handling method with the item
+ ``onEvent(event, item)`` - method that invokes ``callHandler`` for all
handlers under the ``event`` key of ``_handlers`` dict. This method is
invoked by engine when the event occurs
Extended MuranoPL reflection
----------------------------
In addition to standard MuranoPL reflection aspects must be provided with
methods that can modify MuranoPL code model:
* change property declarations including default values and contracts
* change methods: wrap it in another method, change argument contracts and
default values
Also aspect may want to modify the metadata which defines UI layout of the
application. For example, add ``io.murano.metadata.forms.Hidden`` class to
some property along with the inserting some predefined default value for this
property. It will result in hiding the corresponding field in GUI and using
the defined value. This part can be used once the new dynamic UI generation
from schema is introduced.
These capabilities can be written as new MuranoPL methods similar to ordinary
reflection and provided to aspects by registering them to the package context
of ``Aspect`` packages. Thus, other MuranoPL code will be unable to make use
of these methods.
The new methods should include ``setDefault``, ``setContract``, ``addMeta``,
``wrapMethod``.
Also the ability to set property values for other object should be provided to
aspects by setting ``CTX_ALLOW_PROPERTY_WRITES`` flag to ``true`` in the
``Aspect`` packages context.
Changes to engine workflow
~~~~~~~~~~~~~~~~~~~~~~~~~~
With all that, the engine workflow with policies is the following:
#. User adds package to the environment
#. The class schema generation in engine triggers package load event
#. Engine obtains a list of policies that need to be applied for particular
tenant (aspects and their input parameters)
#. Engine instantiates and initializes all those aspects and a notifier
#. Engine subscribes aspects to notifications from notifier
#. Engine loads the package and invokes ``Notifier``'s method
``onEvent(packageLoad)``.
#. ``Notifier`` finds out what aspects want to modify the package and invokes
their ``handlePackageLoad()`` method.
#. Handler gets a chance to examine the code of the MuranoPL class and make
necessary modifications using extended reflection capabilities.
# During the model load, objects initializing, garbage collection engine
instantiates aspects and notifier again and runs the process of
subscription => notification => modification with these events in a similar
fashion.
Alternatives
------------
None
Data model impact
-----------------
Model to store policies should look roughly like this:
Table name: policy
+------------------+--------------+------+-----+---------+
| Field | Type | Null | Key | Default |
+==================+==============+======+=====+=========+
| created | datetime | NO | | NULL |
+------------------+--------------+------+-----+---------+
| updated | datetime | NO | | NULL |
+------------------+--------------+------+-----+---------+
| id | varchar(255) | NO | PRI | NULL |
+------------------+--------------+------+-----+---------+
| object_model | longtext | YES | | NULL |
+------------------+--------------+------+-----+---------+
| description | text | YES | | NULL |
+------------------+--------------+------+-----+---------+
object_model field stores json-serialized representation of the policy
including its rules.
description field contains optional textual information.
Model to store policies assignment to tenants:
Table name: policy_assignment
+------------------+--------------+------+-----+---------+
| Field | Type | Null | Key | Default |
+==================+==============+======+=====+=========+
| created | datetime | NO | | NULL |
+------------------+--------------+------+-----+---------+
| updated | datetime | NO | | NULL |
+------------------+--------------+------+-----+---------+
| policy_id | varchar(255) | NO | PRI | NULL |
+------------------+--------------+------+-----+---------+
| tenant_id | varchar(36) | YES | PRI | NULL |
+------------------+--------------+------+-----+---------+
NULL value of the tenant_id field means that policy should be applied to all
tenants in the cloud.
REST API impact
---------------
+---------------------+------------+-----------------------------------------+
| Attribute | Type | Description |
+=====================+============+=========================================+
| objectModel | object | JSON representation of policy |
+---------------------+------------+-----------------------------------------+
| tenantIds | array | Array of the tenants to apply policy to |
+---------------------+------------+-----------------------------------------+
**List policies**
*Request*
+----------+------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==============================+==================================+
| GET | /policies | List available policies |
+----------+------------------------------+----------------------------------+
*Response*
List of policies with their basic properties.
::
{
"policies": [
{
"created": "2014-05-14T13:02:46",
"updated": "2014-05-14T13:02:54",
"id": "2fa5ab704749444bbeafe7991b412c33",
"description": "Policy to limit possible flavor",
"tenant_ids": ["726ed856965f43cc8e565bc991fa76c3"]
},
{
"created": "2014-05-14T13:02:51",
"updated": "2014-05-14T13:02:55",
"id": "744e44812da84e858946f5d817de4f72",
"description": "Policy to restrict access to apps",
"tenant_ids": ["726ed856965f43cc8e565bc991fa76c3"]
}
]
}
Response codes:
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. List of policies received successfully |
+----------------+-----------------------------------------------------------+
| 403 | User is not allowed to browse policies |
+----------------+-----------------------------------------------------------+
**Create policy**
*Request*
+----------+------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==============================+==================================+
| POST | /policies | Create policy |
+----------+------------------------------+----------------------------------+
Body:
::
{
"description": "Policy to limit possible flavor",
"objectModel": {
"maxFlavor": "m1.medium",
"?": {
"type": "com.example.MyAspect",
"id": "446373ef-03b5-4925-b095-6c56568fa518"
}
}
}
*Response*
::
{
"id": "ce373a477f211e187a55404a662f968",
"description": "Policy to limit possible flavor",
"created": "2013-11-30T03:23:42Z",
"updated": "2013-11-30T03:23:44Z",
"objectModel": {
"maxFlavor": "m1.medium",
"?": {
"type": "com.example.MyAspect",
"id": "446373ef-03b5-4925-b095-6c56568fa518"
}
}
}
Response codes:
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Policy has been created successfully |
+----------------+-----------------------------------------------------------+
| 400 | Bad request. Either the format of the body is invalid or |
| | parameters doesn't match the contracts |
+----------------+-----------------------------------------------------------+
| 403 | User is not allowed to create policies |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified class doesn't exist or it is not |
| | an Aspect |
+----------------+-----------------------------------------------------------+
**Update policy**
*Request*
+----------+------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==============================+==================================+
| PUT | /policies/<policy_id> | Update policy |
+----------+------------------------------+----------------------------------+
Body:
::
{
"description": "Changed description",
"tenantIds": ["726ed856965f43cc8e565bc991fa76d8"],
"objectModel": {
"maxFlavor": "m1.large",
"?": {
"type": "com.example.MyAspect",
"id": "446373ef-03b5-4925-b095-6c56568fa518"
}
}
}
*Response*
::
{
"id": "ce373a477f211e187a55404a662f968",
"description": "Changed description",
"created": "2013-11-30T03:23:42Z",
"updated": "2013-11-30T03:39:08Z",
"tenant_ids": ["726ed856965f43cc8e565bc991fa76d8"],
"objectModel": {
"maxFlavor": "m1.large",
"?": {
"type": "com.example.MyAspect",
"id": "446373ef-03b5-4925-b095-6c56568fa518"
}
}
}
Response codes:
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Policy has been updated successfully |
+----------------+-----------------------------------------------------------+
| 400 | Bad request. Either the format of the body is invalid or |
| | parameters doesn't match the contracts |
+----------------+-----------------------------------------------------------+
| 403 | User is not allowed to update this policy |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified policy doesn't exist |
+----------------+-----------------------------------------------------------+
| 409 | Policy with specified name already exists |
+----------------+-----------------------------------------------------------+
**Get policy details**
*Request*
+----------+------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==============================+==================================+
| GET | /policies/<policy_id> | Get policy details |
+----------+------------------------------+----------------------------------+
*Response*
::
{
"id": "ce373a477f211e187a55404a662f968",
"description": "Policy description",
"created": "2013-11-30T03:23:42Z",
"updated": "2013-11-30T03:39:08Z",
"tenant_ids": ["726ed856965f43cc8e565bc991fa76d8"],
"objectModel": {
"maxFlavor": "m1.medium",
"?": {
"type": "com.example.MyAspect",
"id": "446373ef-03b5-4925-b095-6c56568fa518"
}
}
}
Response codes:
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Policy details have been received successfully |
+----------------+-----------------------------------------------------------+
| 403 | User is not allowed to look up policies |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified policy doesn't exist |
+----------------+-----------------------------------------------------------+
**Delete policy**
*Request*
+----------+------------------------------+----------------------------------+
| Method | URI | Description |
+==========+==============================+==================================+
| DELETE | /policies/<policy_id> | Remove policy |
+----------+------------------------------+----------------------------------+
*Response*
::
{
"id": "ce373a477f211e187a55404a662f968",
"description": "Policy description",
"created": "2013-11-30T03:23:42Z",
"updated": "2013-11-30T03:39:08Z",
"tenant_ids": ["726ed856965f43cc8e565bc991fa76d8"],
"objectModel": {
"maxFlavor": "m1.medium",
"?": {
"type": "com.example.MyAspect",
"id": "446373ef-03b5-4925-b095-6c56568fa518"
}
}
}
Response codes:
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Policy has been removed successfully |
+----------------+-----------------------------------------------------------+
| 403 | User is not allowed to remove this policy |
+----------------+-----------------------------------------------------------+
| 404 | Not found. Specified policy doesn't exist |
+----------------+-----------------------------------------------------------+
Versioning impact
-----------------
None
Other end user impact
---------------------
python-muranoclient needs to be extended with support of new REST API calls.
Deployer impact
---------------
Deployers will need to check the logs and UI messages informing that some
parameters of deployment were changed by the policies, or for the reasons why
certain applications can not be deployed etc.
Developer impact
----------------
Business logic of the murano applications should not be affected by the
change. Policies will have the ability to modify its code on the fly during the
execution.
Murano-dashboard / Horizon impact
---------------------------------
The following changes need to be made in the GUI:
* Form to instantiate and initialize aspect with the rules (create policy)
* Form to map policies to tenants
* Page to display the list of policies
* Page to display each policy details
Implementation
==============
Assignee(s)
-----------
Primary assignee:
vakovalchuk
Work Items
----------
* Implement join points in engine where aspects can subscribe for events and
apply changes (object init and packages load during the first phase
of implementation, model load, garbage collection later).
* Create MuranoPL class ``Aspect`` that defines the basic interface for custom
aspects and place it to the core library.
* Create MuranoPL class ``Notifier`` that manages notifying process and place
it to the core library.
* Implement extended MuranoPL reflection capabilities and make it available
only to aspects.
* Create database model to store policies and model to store their assignment
to tenants.
* Implement API for CRUD operations for the aspect instances and their
assignment to tenants.
* Create python-muranoclient methods to support new API.
* Implement UI workflow to create policies and apply it to tenants.
* Create demo packages with example policies.
Dependencies
============
* https://blueprints.launchpad.net/murano/+spec/dependency-driven-resource-deallocation
* https://blueprints.launchpad.net/murano/+spec/schema-driven-ui
Testing
=======
* DSL unit tests for extended MuranoPL reflection
* Testrunner-based tests for the example policies functionality
* Tempest tests for the new REST API calls
* Unit and functional tests for the new python-muranoclient methods
* Selenium tests for the new GUI workflow
Documentation Impact
====================
* New functionality must be properly documented
* REST API specification need to be updated with new calls info
References
==========
* https://blueprints.launchpad.net/murano/+spec/dependency-driven-resource-deallocation
* https://blueprints.launchpad.net/murano/+spec/schema-driven-ui

View File

@ -1,363 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==================================================
Capability to edit existing environment properties
==================================================
https://blueprints.launchpad.net/murano/+spec/environment-edit
The spec proposes mechanism for users to edit any details of an existing
environment, for example edit its regions, set home region, change the
networks or any other possible input field.
Problem description
===================
Current Murano API and python-muranoclient only allow to specify its home
region and default network during the environment creation. These parameters
cannot be seen and cannot be updated by the user after the environment
creation. Users may want to examine and change these or other environment
properties after it is created. Adding a mechanism to apply custom JSON-patch
to environment object model would provide this capability and add a great
flexibility in managing environments.
Proposed change
===============
Changes in API
--------------
It is proposed to create a new API endpoint
`/environments/<env_id>/model` and two calls to it using GET and PATCH
requests.
**GET** request provides environment object model where all environment
properties can be seen. See the `REST API impact` section for the example of
such output. If session is specified in the request and it is not in deploying
state, response gives modified environment model from the session, otherwise
actual environment model.
**PATCH** request allows to perform custom change to the environment object
model using JSON-patch object. It requires session to be specified by request
and saves changes to environment model in the specified session.
JSON-patch is a valid JSON that contains a list of changes to be applied to
the current object. Each change contains a dictionary with three keys: ``op``,
``path`` and ``value``. ``op`` (operation) can be one of the three values:
`add`, `replace` or remove`. *See RFC 6902 [1] for details*.
To indicate that body of the request is JSON-patch and validate correct
format of the body, a new media type should be added -
`application/env-model-json-patch`. During the validation in the middleware,
the following conditions must be checked against the passed object:
* It is a valid JSON-patch object (already implemented for
`application/murano-packages-json-patch` media type and should be reused).
Otherwise `400 Bad Request` response is given.
* Not all kinds of operations can be applied to all sections of the
environment model. The list of allowed operations is the following:
+ defaultNetworks: replace
+ name: replace
+ region: replace
+ regions: add, replace, remove
+ services: add, replace, remove
+ ?: add, replace, remove
Attempt to perform the restricted change will result in the `403 Forbidden`
response.
* Types of the environment properties and possible values are validated by the
appropriate JSON-schema. Otherwise `400 Bad Request` response is given.
Changes in python-muranoclient
------------------------------
To support the new API calls, corresponding python-muranoclient methods for
environments are needed: ``get_model`` and ``update_model`` respectively.
New CLI command that displays the result of ``get_model`` method:
.. code-block:: shell
murano environment-model-show <ENV_ID> [--path <PATH>] [--session-id <SESSION_ID>]
<PATH> allows to get a specific section of the model, for example
`defaultNetworks`, `region` or `?` or any of the subsections. It defaults to
'/' which means getting the whole model. Specifying <SESSION_ID> allows to get
the state of the environment with pending changes, while omitting it gives
the actual state.
New CLI command that allows to update environment model with a custom patch:
.. code-block:: shell
murano environment-model-edit <ENV_ID> <FILE> --session-id <SESSION_ID>
The command calls ``update_model`` method with data (JSON-patch) provided in
the <FILE> file. Changes are to be saved in session <SESSION_ID>.
Alternatives
------------
Separate CLI command can be created for updating each environment property.
It will be somewhat easier for users because file with JSON-patch will not be
needed. On the other hand, it will require creating a bunch of commands
instead of one generic and necessity to add new commands in future for the
possible new properties.
Data model impact
-----------------
None
REST API impact
---------------
**Get environment model**
+----------+-------------------------------------+------------------------+--------------------------+
| Method | URI | Header | Description |
+==========+=====================================+========================+==========================+
| GET | /environments/<env_id>/model/<path> | X-Configuration-Session| Get an Environment model |
| | | (optional) | |
+----------+-------------------------------------+------------------------+--------------------------+
Specifying <path> allows to get a specific section of the model, for example
`defaultNetworks`, `region` or `?` or any of the subsections.
*Response*
**Content-Type**
application/json
::
{
"defaultNetworks": {
"environment": {
"internalNetworkName": "net_two",
"?": {
"type": "io.murano.resources.ExistingNeutronNetwork",
"id": "594e94fcfe4c48ef8f9b55edb3b9f177"
}
},
"flat": null
},
"region": "RegionTwo",
"name": "new_env",
"regions": {
"": {
"defaultNetworks": {
"environment": {
"autoUplink": true,
"name": "new_env-network",
"externalRouterId": null,
"dnsNameservers": [],
"autogenerateSubnet": true,
"subnetCidr": null,
"openstackId": null,
"?": {
"dependencies": {
"onDestruction": [{
"subscriber": "c80e33dd67a44f489b2f04818b72f404",
"handler": null
}]
},
"type": "io.murano.resources.NeutronNetwork/0.0.0@io.murano",
"id": "e145b50623c04a68956e3e656a0568d3",
"name": null
},
"regionName": "RegionOne"
},
"flat": null
},
"name": "RegionOne",
"?": {
"type": "io.murano.CloudRegion/0.0.0@io.murano",
"id": "c80e33dd67a44f489b2f04818b72f404",
"name": null
}
},
"RegionOne": "c80e33dd67a44f489b2f04818b72f404",
"RegionTwo": {
"defaultNetworks": {
"environment": {
"autoUplink": true,
"name": "new_env-network",
"externalRouterId": "e449bdd5-228c-4747-a925-18cda80fbd6b",
"dnsNameservers": ["8.8.8.8"],
"autogenerateSubnet": true,
"subnetCidr": "10.0.198.0/24",
"openstackId": "00a695c1-60ff-42ec-acb9-b916165413da",
"?": {
"dependencies": {
"onDestruction": [{
"subscriber": "f8cb28d147914850978edb35eca156e1",
"handler": null
}]
},
"type": "io.murano.resources.NeutronNetwork/0.0.0@io.murano",
"id": "72d2c13c600247c98e09e2e3c1cd9d70",
"name": null
},
"regionName": "RegionTwo"
},
"flat": null
},
"name": "RegionTwo",
"?": {
"type": "io.murano.CloudRegion/0.0.0@io.murano",
"id": "f8cb28d147914850978edb35eca156e1",
"name": null
}
}
},
services: []
"?": {
"type": "io.murano.Environment/0.0.0@io.murano",
"_actions": {
"f7f22c174070455c9cafc59391402bdc_deploy": {
"enabled": true,
"name": "deploy",
"title": "deploy"
}
},
"id": "f7f22c174070455c9cafc59391402bdc",
"name": null
}
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | Environment model received successfully |
+----------------+-----------------------------------------------------------+
| 403 | User is not authorized to access environment |
+----------------+-----------------------------------------------------------+
| 404 | Environment is not found or specified section of the |
| | model does not exist |
+----------------+-----------------------------------------------------------+
**Update environment model**
*Request*
+----------+--------------------------------+------------------------+-----------------------------+
| Method | URI | Header | Description |
+==========+================================+========================+=============================+
| PATCH | /environments/<env_id>/model/ | X-Configuration-Session| Update an Environment model |
+----------+--------------------------------+------------------------+-----------------------------+
* **Content-Type**
application/env-model-json-patch
* **Example**
::
[{
"op": "replace",
"path": "/defaultNetworks/flat",
"value": true
}]
*Response*
**Content-Type**
application/json
See GET request response.
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | Environment is edited successfully |
+----------------+-----------------------------------------------------------+
| 400 | Body format is invalid |
+----------------+-----------------------------------------------------------+
| 403 | User is not authorized to access environment or specified |
| | operation is forbidden for the given property |
+----------------+-----------------------------------------------------------+
| 404 | Environment is not found or specified section of the |
| | model does not exist |
+----------------+-----------------------------------------------------------+
Versioning impact
-----------------
None
Other end user impact
---------------------
Users will get new CLI commands to examine and edit environment object model.
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
New python-muranoclient method can be used for providing environment edit
capability from GUI, but this perspective is out of scope of this spec.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
vakovalchuk
Work Items
----------
* Implement new API call to get object model of environment
* Implement new API calls to update the object model of environment
* Implement new python-muranoclient methods to support new API calls
* Add shell command that allows to display environment object model
* Add shell command that allows to apply JSON-patch to the environment model
* Add the same commands to the OpenStack client shell
Dependencies
============
None
Testing
=======
* API calls should be tested by unit tests and tempest tests
* CLI commands should be tested by unit tests
Documentation Impact
====================
* API calls should be described in the Murano API specification
* CLI commands should be described in the end user guide
References
==========
[1] https://tools.ietf.org/html/rfc6902

View File

@ -1,293 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
===================================
Metadata Assignment And Propagation
===================================
https://blueprints.launchpad.net/murano/+spec/metadata-assignment-and-propagation
Cloud users and operators may need to assign some arbitrary key-value pairs to
environments and applications deployed by murano to associate some metadata
information with them. If applicable this metadata attributes should be
propagated to OpenStack resources provisioned by Murano.
Problem description
===================
The meta information may describe various aspects of the deployed applications,
for example:
* Deployed software: names, versions, descriptions and license terms of the
software components deployed on the VMs;
* VM-related configuration features, like listening ports or interfaces;
* Hardware specs of provisioned virtual machines;
* Guest OS info, like the type of operating system, its family, version
etc;
* Information about the deployments purpose: type of the deployed
environment (development, staging, production), usage purpose, security
consideration etc;
* Information about the user who deployed the app or environment: name,
department, contact information, etc.
This information may be consumed directly by inspecting murano applications
with dashboard or CLI, by indexing these metadata attributes into specialized
search software, such as Searchlight [1] or by building custom reports with
grouping or aggregation by these metadata.
For the latter case it is especially important to propagate the metadata from
the initial objects it is assigned to (application or environment) to the
resource objects spawned by them (VMs, Volumes, Networks etc).
Proposed change
===============
UI change
---------
It is proposed to utilize the functionality provided by Glance Meta Definition
Catalog [2] to define the schemas of the applicable metadata attributes. It is
proposed to add two types of resources for murano applications and murano
environments: ``OS::Murano::Application`` and ``OS::Murano::Environment``
accordingly (ability to add metadata attributes for murano packages is out of
scope for this spec, however in future this may also become possible, so
``OS::Murano::Package`` is likely to be appropriate resource type).
The standard Angular-based Metadata assignment dialog (the one being currently
used to assign metadata to Instances, Images and Volumes) should be extended to
support Murano Dashboard and these new resource types. This extended dialog
will load the metadata definition schemas for attributes which are assignable
to appropriate type of resources and will submit them to Murano API for
persistence once the input is saved.
Murano Object Model change
--------------------------
For the applications it is proposed to persist the metadata attributes in the
object model, in the new block called 'metadata', which should be placed under
the '?' section of each object. For example, the '?' block of Apache
application tagged with a couple of attributes may look like this:
::
"?": {
"_26411a1861294160833743e45d0eaad9": {
"name": "Apache HTTP Server"
},
"type": "com.example.apache.ApacheHttpServer",
"id": "19dfb844-6eee-48bd-826a-c6206d065e85",
"metadata": {
"sw_webserver_apache_version": "2.1",
"sw_webserver_apache_http_port": 80
}
}
Since the ?-headers of objects placed in the environment's object model may be
modified with the existing Murano API no changes in the API is needed.
For the Environments a similar approach may be followed — to store the
metadata attributes under the `/?/metadata` key of the Environment object in
the object model. However an alternative may be considered: since each
Environments have a dedicated entry in murano's database, the metadata
attributes for environments may be stored in database in normalized form. See
the "Alternatives" section below for more details.
Regardless of the chosen approach it is required to introduce a new API call
to assign metadata attributes to the Environment, since the existing API does
not have capabilities to edit the ?-headers of Environment object. The
appropriate change into API is out of scope here and is covered with a separate
spec [3]
MuranoPL Change
---------------
MuranoPL language should be extended with an ability to read the metadata
attributes assigned to any given object. It is proposed to create a global yaql
function named ``metadata()`` for this purpose (similar to ``id()`` and
``name()`` which read appropriate information from the same ?-header).
Murano's serializer/deserializer should be properly updated to load the
metadata attributes and persist them back.
Core Library Change
-------------------
Core library should be extended with an ability to communicate with Glance
Metadata Definition API to query the namespaces applicable to a given resource
type and extract all the names of attributes from those namespaces. This will
allow the resource class to check if the given metadata attribute attached to
the application the class belongs to is applicable for the resource itself. The
binding to the Glance API should be done via a python-backed class
``MetadefBrowser``, while the rest of the logic may be implemented in MuranoPL.
A new MuranoPL class called ``MetadataAware`` should be implemented. This class
will have two methods: ``collectMetadata`` and ``getResourceType``.
``collectMetadata`` method will return all the metadata attributes assigned to
the object itself and all the attributes assigned to the owners of the object,
traversing the ownership tree to the root (i.e. to the Environment). All the
attributes from the traversed objects may be checked for applicability to the
particular resource type. To do this check, the code should call the
``getResourceType`` method which is supposed to return the resource type as
defined in Glance (``OS::Nova::Server`` for VMs, ``OS::Cinder::Volume`` for
volumes etc) and then use the ``MetadefBrowser`` described above to check if
the attribute is applicable to the objects of this type.
The resource-specific classes of the Core Library (``Instance``,
``CinderVolume`` etc) have to extend the ``MetadataAware`` and override the
``getResourceType`` method.
Alternatives
------------
There are a number of alternatives to consider.
First, instead of using Glance Metadef catalog to store the possible attribute
names and constraints, we may assign attributes without any predefined schema.
This will reduce our dependency on other OpenStack components (Glance in this
case), but will introduce extra development burden (since we won't be able to
reuse the existing metadata-assignment dialog) and will prevent us from using
convenient schema-based validators of tags which are made for metadefs. So, it
is proposed to stay with metadef-compliant implementation.
Second option to consider is the storage of metadata attributes on environment
level. Most other OpenStack projects store metadata attributes in normalized
form: they have the separate table mapped to the primary object table as
one-to-many. The approach suggested above uses denormalized storage: the
attributes are stored inside the json-document describing the complete
environment, which is stored as a single value in the database. This is much
easier to implement, also having metadata in object model of environment object
is still needed, so duplicating data storage seems like an extra work.
Third option to consider: not to check for attribute applicability on resource
types. This simplifies the development (no need to create ``MetadefBrowser``
class and much simpler logic in ``MetadataAware``), however this will degrade
user experience, as resources may get inappropriate attributes assigned, which
will be confusing.
Data model impact
-----------------
This proposal adds new fields to the ?-headers of objects in object model. If
the normalized alternative is chosen, it will also introduce extra table in
database and a relationship with the ``Environments`` table. This will require
to create a database migration as well.
REST API impact
---------------
A modification of Murano API is required to allow assigning of metadata
attributes to the Environment objects, however it is out of scope here. See [3]
for details.
Versioning impact
-----------------
Since the proposed change requires to add a new yaql function to the DSL and
modifies the serializer/deserializer logic this requires to bump the MuranoPL
format version.
Other end user impact
---------------------
The users will see new action buttons "Update Metadata" in Murano Dashboard.
This buttons will be available as row actions for Environment Components and
Environments.
Deployer impact
---------------
The proposed change introduces a dependency on Glance API. To configure the
connectivity to this API (endpoint details, encryption etc) a new optional
configuration block should be added to Murano config.
Developer impact
----------------
Developers may implement the ``MetadataAware`` class to add metadata handling
logic for their classes.
Murano-dashboard / Horizon impact
---------------------------------
This change will add a custom version of metadata.service javascript module to
Murano Dashboard. It will have the similar logic as the standard Horizon's
module, but will add the references to murano api's, so the Metadata dialog can
update the attributes assigned to Murano entities.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
ativelkov
Other contributors:
TBD
Work Items
----------
* Add a rest api handlers for murano-dashboard to handle metadata updates and
fetching;
* Add a javascript API to this handlers;
* Create a custom version of metadata.service, so the metadata modal dialog may
utilize murano's javascript APIs to metadata;
* Modify Murano Dashboard to call metadata modal dialog as row handlers for
Environments and Services;
* Modify Murano API to allow edits of ?-section of Environment objects;
* Add a ``MetadefBrowser`` class to Core Library;
* Implement a ``MetadataAware`` class and extend ``Instance`` and
``CinderVolume`` classes with it.
Dependencies
============
* Glance Metadefinition Catalog [2]
* Environment modification API changes [3]
Testing
=======
The integration tests should verify that the attributes are propagated properly
Documentation Impact
====================
The new capabilities to add attributes should be documented in user manual.
The changes in core library and the usage of ``MetadataAware`` class should be
reflected in developers' manual.
References
==========
[1] https://wiki.openstack.org/wiki/Searchlight
[2] http://docs.openstack.org/developer/glance/glancemetadefcatalogapi.html
[3] https://review.opendev.org/#/c/378602

View File

@ -1,141 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=========================
Murano exception handling
=========================
https://blueprints.launchpad.net/murano/+spec/murano-exception-handling
Current exception handling in murano project differs from the way
all OpenStack projects handle their exception. Murano have very small list
of its own exceptions and use webob or general exceptions everywhere instead of
store all needed exceptions in one place.
Problem description
===================
* Murano is OpenStack project and should follow community practices.
* Using murano specific exceptions can make debugging easier.
* Now we have 3 different places where exceptions are stored: murano.packages.exceptions,
murano.dsl.exceptions, murano.common.exception depends on part of murano which
throws the exception.
Proposed change
===============
It's planned to create 2 new basic exceptions in murano.common.exceptions which
will be parents for others. First one will be general exception and the second
one will be exception for HTTP requests. Exceptions in murano.packages.exceptions
should have general MuranoException as a parent. Exceptions in murano.dsl.exceptions
should be kept as is since dsl is mostly separate part of murano.
These exceptions will be replaced with exceptions inherited from MuranoHTTPException:
* webob.exc.HTTPBadRequest
* webob.exc.HTTPInternalServerError
* webob.exc.HTTPForbidden
* webob.exc.HTTPUnsupportedMediaType
* webob.exc.HTTPUnauthorized
* webob.exc.HTTPForbidden
* webob.exc.HTTPConflict
* webob.exc.HTTPClientError
These exceptions will be replaced with exceptions inherited from MuranoException:
* ValueError
* Exception
* RuntimeError
* NotImplementedError
* SyntaxError
* TypeError
* NameError
All custom exceptions which defined in murano should be moved to one of the general
exceptions files.
Alternatives
------------
Keep everything as it is.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
End users will see new murano specific exceptions.
Deployer impact
---------------
None
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
New exceptions should be introduced and handled in horizon.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
starodubcena
Work Items
----------
* Create new exception in murano-api, change exception handling where it will be
needed
* Create new exception in packages, change exception handling where it will be
needed
* Handle new exceptions in python-muranoclient
* Handle new exception in murano-dashboard
Dependencies
============
None
Testing
=======
This change need a huge refactoring for unit and functional tests.
Documentation Impact
====================
None

View File

@ -1,175 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
============================
Encrypt Murano PL Properties
============================
https://blueprints.launchpad.net/murano/+spec/allow-encrypting-of-muranopl-properties
Currently the object model for an application in Murano is stored in the Murano
database as plain text. This can pose a security risk for applications whose
object model contains passwords or other sensitive data.
Problem description
===================
Many Murano applications request input data from users, which in most cases is
entered via the murano dashboard. Currently all input from users is stored in
database in plain text. In the case of a MySQL [#]_ app for example, the
password that the user enters will be stored in plain text in both the
``session`` and ``environment`` database tables. This info is available both to
the cloud admin, other users in the same project, and also to an attacker
should the database become compromised.
Proposed change
===============
This spec proposes to add a two new yaql functions; `encrypt_data` and
`decrypt_data`. The former will be processed at the dashboard stage, as it will
be applied to input fields presented to the user. `decrypt_data` will be
processed in the engine during app execution.
These functions will make use of Castellan [#]_ which is a generic
key manager interface for OpenStack. Castellan is designed to be used with a
variety of secret storage backends, the most common being Barbican [#]_. The
Castellan key manager is already being used by the Nova and Cinder project to
name two [#]_. Because Barbican is the default storage backend, Barbican and
Castellan will be referred to interchangeably for the rest of this document.
Alternatives
------------
Some questions have been raised as to the usefulness of Barbican as a whole
[#]_. Some community members are concerned with adding it as "yet another
dependency" to their project, while others have concerns about its integration
with Keystone with regards to secret storage.
With regards to dependency concerns, these functions will be optional to Murano.
If Castellan is not configured, an error message will be shown in Horizon
informing the user to contact their administrator if they wish to use apps
requiring encryption. The use of Castellan also helps here, as it gives
operators flexibility in which secret backend they wish to use. It should be
noted however that Castellan does not appear to currently provide any "dummy"
backend drivers [#]_.
With regards to security, the argument that Barbican is the common solution for
secret storage in OpenStack seems reasonable; security is something best left
to specialists in the field. If a flaw is discovered in Barbican, it can be
patched once by an operator and all projects using it will automatically
benefit.
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-----------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
Deployers wishing to use the new encryption functionality will be required to
deploy a key manager such as Barbican (it is worth noting Barbican may already
be available in some cloud environments in which case there would be minimal
impact).
The functionality will be made optional via a configuration item, hence
there will be no impact for deployers who don't wish to take advantage of this
feature.
Developer impact
----------------
Developers should be made aware of these functions via documentation, and also
how to use them.
Murano-dashboard / Horizon impact
---------------------------------
Will need to be updated to understand calls to `encrypt_data` in forms.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
paul.bourke@oracle.com
Other contributors:
None
Work Items
----------
* Integrate Castellan into murano-dashboard.
* Add a `encrypt_data` function to the dashboard to make use of the above.
* Integrate Castellan into the murano engine.
* Add a `decrypt_data` function to the dashboard to make use of the above.
* Testing.
Dependencies
============
* Castellan
* Barbican
Testing
=======
* Appropriate unit and functional tests will need to be added.
* Potentially the tempest tests could be updated for full end-to-end testing
with Barbican.
Documentation Impact
====================
Deployment docs will need info on Barbican configuration for Murano and
murano-dashboard. MuranoPL Docs will also be needed on the new functions.
References
==========
.. [#] https://opendev.org/openstack/murano-apps/src/branch/master/MySQL/package/UI/ui.yaml
.. [#] https://opendev.org/openstack/castellan
.. [#] https://opendev.org/openstack/barbican
.. [#] https://review.opendev.org/#/c/247561/
.. [#] http://lists.openstack.org/pipermail/openstack-dev/2017-January/110192.html
.. [#] https://opendev.org/openstack/castellan/src/branch/stable/ocata/castellan/key_manager
* Cinder discussion around their alternative insecure key manager for Castellan:
http://lists.openstack.org/pipermail/openstack-dev/2016-January/083241.html
* Murano discussion around implementation details for this blueprint:
http://lists.openstack.org/pipermail/openstack-dev/2017-June/118290.html

View File

@ -1,161 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==============
Policy in code
==============
`bp policy-in-code <https://blueprints.launchpad.net/murano/+spec/policy-in-code>`_
Deployers currently have to maintain policy files regardless if they change
the default policy provided from murano. They also have to trace through
code in order to determine the purpose behind each policy operation in the
policy file. Maintaining the policy files and tracing through code to provide
context to the operations in the policy files is cumbersome and error-prone.
By moving policy into code, we can leverage tooling to make maintenace easier
for deployers, provide a centralized location for default policy values,
and more effectively implement self-documenting policies.
Problem Description
===================
Today policy exists in a file that deployers are expected to maintain in their
deployment. If a deployer needs to change the default policy rules for an
operation, they have to make those changes and continuously check to make sure
conflicts are resolved with each new release of the policy file. This is
cumbersome to maintain, even if a deployment is only using the default policy.
Deployers must also trace through code to identify where certain policies
are enforced, which is also cumbersome.
Proposed Change
===============
The proposed solution is to check policy into the code base and register it
using the oslo.policy library. This is very similar to how projects register
and use configuration options using oslo.config. If policies are provided in a
policy file on disk, those policies will be registered instead of the in-code
default. This provides a way for deployers to override the defaults provided
in the in-code policies.
The registration will need two pieces of data:
1. The operation, e.g. "create_environment" or "list_environments_all_tenants"
2. The rule, e.g. "role:admin" or "rule:default"
Descriptions can also be provided in the registered policy object that help
describe the operation and the rule or role that is required to execute it,
in addition to which API endpoints enforce the policy operation. This
description can be used when generating sample policy files from registered
rules, as well as help operators to better understand policy enforcement
in murano.
This is the exact same approach
`nova <http://specs.openstack.org/openstack/nova-specs/specs/newton/implemented/policy-in-code.html>`_
and
`keystone <http://specs.openstack.org/openstack/keystone-specs/specs/keystone/pike/policy-in-code.html>`_
used to codify policy.
The following are benefits from the approach:
* There is no longer a need to maintain a policy file in tree.
* A tool can be written to auto-generate a policy.json file from the default
policy operations in code.
* It will be easier for operators to understand the intent of the policy
operations and where they are enforced in the system.
* It will be easier to provide a description of each policy much like we do
configuration options. This will ensure that the policies are well-documented
and maintained.
Alternatives
------------
An alternative approach was to pull policy into murano as an official
resource. This would still require some sort of policy override ablility for
deployments that do not wish to deploy the default.
Security Impact
---------------
None.
Notifications Impact
--------------------
None.
Other End User Impact
---------------------
None. Policy will continue to be evaluated and enforced like it does today.
Performance Impact
------------------
The performance impact of moving policy in code should be minimal. If the
deployment doesn't have a policy file on disk, the service will not have to
fetch it. Instead the default will be registered and used from within code. In
the event the deployment is using policy overrides, the combination of the two
approaches might cause some performance impact compared to defaults in code,
but the overall impact should be negligible.
Other Deployer Impact
---------------------
If a deployer already makes modifications to the default policy file, they
will have to continue maintaining those changes. For deployers who modify a
subset or none of the policy entries, they can essentially remove their policy
file, or the policies that are the default. The end result should be a policy
file that purely consists of overrides the deployer wishes to enforce.
Another deployer impact is that deployers no longer need to double-check they
are protecting all new operations by manually inspecting policy files across
releases. Instead, they can be notified about new policies available in a
release via release notes and then choose to either use the well-documented
defaults or to override them in the policy file.
Developer Impact
----------------
Any policies added to the code should be registered before they are used. There
should also be checks and tests added that make sure new policy entries are
accompanied with a release note.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
Felipe Monteiro (felipemonteiro)
Work Items
----------
* Investigate the process for adding oslo.policy into keystone's policy.
* Gradually move policy checks from ``policy.json`` into oslo.policy objects.
This can be done incrementally and should remove the check from
``policy.json``.
* Change genconfig tox environment to generate sample policy.json file.
* Update documentation.
* Remove the murano policy file from devstack and murano.
Dependencies
============
None.
Documentation Impact
====================
Documentation for deployers about the policy file will be updated to mention
that only policies which differ from the default will need to be included.
References
==========
* `nova specification <http://specs.openstack.org/openstack/nova-specs/specs/newton/implemented/policy-in-code.html>`_
* `keystone specification <http://specs.openstack.org/openstack/keystone-specs/specs/keystone/pike/policy-in-code.html>`_

View File

@ -1,220 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
=====================
Agent message signing
=====================
https://blueprints.launchpad.net/murano/+spec/message-signing
Problem description
===================
In order to deploy software, Murano sends scripts, playbooks and other files
to agents that run on each VM created. Murano uses RabbitMQ message broker
and its AMQP protocol to deliver messages to the agents. During first boot
each VM gets its RabbitMQ credentials, the queue name where the messages are
going to appear as well as instructions on where
to put execution results. Typical Murano installation has a dedicated
RabbitMQ instance that is used for such communications.
However, since user management is not included in AMQP protocol, Murano
requires RabbitMQ credentials to be provided in its config file. Hence all
the created VMs share the same credentials and it is only the queue name that
distinguishes one machine from another. Since murano agents steady pull new
commands from the RabbitMQ, if the queue name gets compromised, anyone could
send commands to the VM and take complete control over it. Luckily current AMQP
version does not have a function to list existing queues. However, since
queue name is generally not considered to be a secret information such
function might be added in the future. Also this information might be
exposed by the RabbitMQ plugins installed in the system. For example, there
is a so called Management plugin that can be used for that purpose. Besides,
the queue name can be found in the Heat stack definition for particular
Murano environment and anyone who can access it could take it from there.
Default Heat policy restricts it to users of that tenant plus the admin user.
However, particular OpenStack installations might have it configured
differently. Also even with default policy it is possible for users of a
single project (tenant) to control each other's VMs regardless of their role
in the tenant.
Proposed change
===============
The proposed solution is to implement message signing so that agents can
verify that the messages come from the murano-engine. There is a keypair
that is shared by all the murano-engine instances in the cloud. When murano
creates a VM, it provides it with a public part of the keypair in addition
to currently provided RabbitMQ credentials and queue name. Each message sent
by the murano-engine is going to be signed with the private key. Agents
will verify the signature with the public key they gave and ignore all the
messages that are not proven to be coming from the engine.
Here is how the communication workflow is going to become:
0. Murano engine is provided with the keypair (key file that has both the
private and the public parts). The default is `~/.ssh/id_rsa` which is a
standard RSA SSH keypair of the user that is running the murano-engine.
However, different key might be provided with the newly introduced config
file setting.
1. When a VM is created, its config that is passed to it via the user-data is
going to include the public part of the key.
2. Every time murano-engine is about to send message `M` to the agent with
queue name `Q` it calculates ``sign(Q + M, private_key)`` i.e. the
signature of the message bytes with prepended queue name in latin1 encoding.
The queue name is prepended so that the messages sent to one VM could not be
resent to other VMs. The signature is then put into a custom AMQP message
header so that the message body does not change.
3. Once the message is received by an gent, it performs
``verify(signature, Q + M, public_key)`` and drops the message if the
verification fails. Since the queue name is different for each agent, it
will also reject all messages that were signed for other VMs.
For the first version it all the cryptographic parameters are going to be
fixed so that no additional configuration is needed:
* The keypair must be PEM-encoded RSA without password protection
* The padding is PKCS#1 v1.5
* Digest function used for signing is SHA256
Engine-agent compatibility
--------------------------
Since the agent can be baked into the images Murano and updated
independently from the server, Murano must still work in situations where
the updated server talks to the old agents or vice versa (old engine, new
agents).
For the new engine / old agents case the compatibility is retained because
old agents will just ignore the new (and unknown to them) setting in the
config file (the public key) as well as custom AMQP header and just won't
verify the signature.
In the old engine / new agents case the server won't provide the public key
to the agents. Agents won't try to verify the messages in this case.
Thus the message signing is going to help only if both the server and the
agents support it. Otherwise everything is going to work the way it
currently does.
Replay attack prevention
------------------------
Having queue names prepended to the message bodies prevents messages sent to
one VM from being resent to another. However it is still possible to resend
the same message to the same VM later.
In order to prevent it, the message body JSON is going to get additional key
called ``Stamp``. It is a long integer value that is monotonic i.e. the
server guarantees that the number is greater from that of the previous
message. The field is optional (since older engines won't send it), but if
it is present, the agent must ensure that it exceeds the value of the
previously seen messages and ignores the message if it not the case. Murano
engine is going to derive the value from the current timestamp.
Messages with additional field remain compatible with the agents because
they ignore all unknown fields. As a bonus, this feature is going to protect
the agent against messages that for some reason got delivered twice which
can happen in rare cases due to the message was requeued because of
unexpected connectivity loss with RabbitMQ upon its acknowledgement or due
to some RabbitMQ cluster inconsistencies.
Alternatives
------------
None
Data model impact
-----------------
None
REST API impact
---------------
None
Versioning impact
-------------------------
None
Other end user impact
---------------------
None
Deployer impact
---------------
There should be generated and provisioned for all the engine instances
keypair file. However it is going to be optional in order not to break
existing murano deployment playbooks.
Developer impact
----------------
None
Murano-dashboard / Horizon impact
---------------------------------
None
Implementation
==============
Assignee(s)
-----------
Primary assignee:
Stan Lagun (slagun)
Work Items
----------
1. Add keypair to the murano-engine config file schema
2. Extract the public key from the keypair and inject it into the generated
agent config data
3. Implement message signing on the server
4. Implement signature verification in the python agent
5. Implement signature verification in the legacy Windows (PowerShell) C#
agent
6. Add stamp value to the messages
7. Validate stamp value on the agent (including persistent tracking of the
previous stamp value) for both agents
Dependencies
============
There are going to be new dependencies on the cryptography python package
that provides all the required crypto functionality. Several such libraries
are already present in the global requirements list.
Testing
=======
New functionality can be fully tested with unit tests.
Documentation Impact
====================
New config setting for the Murano engine should be documented.
References
==========
None

View File

@ -1,279 +0,0 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==========================================
Example Spec - The title of your blueprint
==========================================
Include the URL of your launchpad blueprint:
https://blueprints.launchpad.net/murano/+spec/example
Introduction paragraph -- why are we doing anything? A single paragraph of
prose that operators can understand. The title and this first paragraph
should be used as the subject line and body of the commit message
respectively.
Some notes about using this template:
* Your spec should be in ReSTructured text, like this template.
* Please wrap text at 79 columns.
* The filename in the git repository should match the launchpad URL, for
example a URL of: https://blueprints.launchpad.net/murano/+spec/awesome-thing
should be named awesome-thing.rst
* Please do not delete any of the sections in this template. If you have
nothing to say for a whole section, just write: None
* For help with syntax, see http://sphinx-doc.org/rest.html
* To test out your formatting, build the docs using tox, or see:
http://rst.ninjs.org
* If you would like to provide a diagram with your spec, ascii diagrams are
required. http://asciiflow.com/ is a very nice tool to assist with making
ascii diagrams. The reason for this is that the tool used to review specs is
based purely on plain text. Plain text will allow review to proceed without
having to look at additional files which can not be viewed in gerrit. It
will also allow inline feedback on the diagram itself.
* If your specification proposes any changes to the Murano REST API such
as changing parameters which can be returned or accepted, or even
the semantics of what happens when a client calls into the API, then
you should add the APIImpact flag to the commit message. Specifications with
the APIImpact flag can be found with the following query:
https://review.opendev.org/#/q/status:open+project:openstack/murano-specs+message:apiimpact,n,z
Problem description
===================
A detailed description of the problem:
* For a new feature this might be use cases. Ensure you are clear about the
actors in each use case: End User vs Deployer
* For a major reworking of something existing it would describe the
problems in that feature that are being addressed.
Proposed change
===============
Here is where you cover the change you propose to make in detail. How do you
propose to solve this problem?
If this is one part of a larger effort make it clear where this piece ends. In
other words, what's the scope of this effort?
Alternatives
------------
What other ways could we do this thing? Why aren't we using those? This doesn't
have to be a full literature review, but it should demonstrate that thought has
been put into why the proposed solution is an appropriate one.
Data model impact
-----------------
Changes which require modifications to the data model often have a wider impact
on the system. The community often has strong opinions on how the data model
should be evolved, from both a functional and performance perspective. It is
therefore important to capture and gain agreement as early as possible on any
proposed changes to the data model.
Questions which need to be addressed by this section include:
* What new data objects and/or database schema changes is this going to
require?
* What database migrations will accompany this change.
* How will the initial set of new data objects be generated, for example if you
need to take into account existing instances, or modify other existing data
describe how that will work.
REST API impact
---------------
Each API method which is either added or changed should have the following
* Specification for the method
* A description of what the method does suitable for use in
user documentation
* Method type (POST/PUT/GET/DELETE)
* Normal http response code(s)
* Expected error http response code(s)
* A description for each possible error code should be included
describing semantic errors which can cause it such as
inconsistent parameters supplied to the method, or when an
instance is not in an appropriate state for the request to
succeed. Errors caused by syntactic problems covered by the JSON
schema definition do not need to be included.
* URL for the resource
* Parameters which can be passed via the url
* Example use case including typical API samples for both data supplied
by the caller and the response
* Discuss any policy changes, and discuss what things a deployer needs to
think about when defining their policy.
Versioning impact
-----------------
Discuss how your change affects versioning and backward compatibility:
* Can it break any existing DSL code even in theory?
* Can it break API consumers that are using older python-muranoclient versions
or non-python clients?
* If you make changes to Murano package please state how the version number
should be incremented?
* Does your change require newer version of external or internal component?
* How to keep backward compatibility with code and consumers that were
available prior to your change?
Other end user impact
---------------------
Aside from the API, are there other ways a user will interact with this
feature?
* Does this change have an impact on python-muranoclient? What does the user
interface there look like?
Deployer impact
---------------
Discuss things that will affect how you deploy and configure OpenStack
that have not already been mentioned, such as:
* What config options are being added? Should they be more generic than
proposed (for example a flag that other hypervisor drivers might want to
implement as well)? Are the default values ones which will work well in
real deployments?
* Is this a change that takes immediate effect after its merged, or is it
something that has to be explicitly enabled?
* If this change is a new binary, how would it be deployed?
* Please state anything that those doing continuous deployment, or those
upgrading from the previous release, need to be aware of. Also describe
any plans to deprecate configuration values or features. For example, if we
change the directory name that instances are stored in, how do we handle
instance directories created before the change landed? Do we move them? Do
we have a special case in the code? Do we assume that the operator will
recreate all the instances in their cloud?
Developer impact
----------------
Discuss things that will affect other developers working on OpenStack,
such as:
* If the blueprint proposes a change to the driver API, discussion of how
other hypervisors would implement the feature is required.
Murano-dashboard / Horizon impact
---------------------------------
Does it require changes to the murano-dashboard / horizon? If so, changes
should be described well. If it's about complex changes than probably a
separate blueprint / spec should be created for it.
Implementation
==============
Assignee(s)
-----------
Who is leading the writing of the code? Or is this a blueprint where you're
throwing it out there to see who picks it up?
If more than one person is working on the implementation, please designate the
primary author and contact.
Primary assignee:
<launchpad-id or None>
Other contributors:
<launchpad-id or None>
Work Items
----------
Work items or tasks -- break the feature up into the things that need to be
done to implement it. Those parts might end up being done by different people,
but we're mostly trying to understand the timeline for implementation.
Dependencies
============
* Include specific references to specs and/or blueprints in murano, or in other
projects, that this one either depends on or is related to.
* If this requires functionality of another project that is not currently used
by Murano, document that fact.
* Does this feature require any new library dependencies or code otherwise not
included in OpenStack? Or does it depend on a specific version of library?
Testing
=======
Please discuss how the change will be tested. We especially want to know what
tempest tests will be added. It is assumed that unit test coverage will be
added so that doesn't need to be mentioned explicitly, but discussion of why
you think unit tests are sufficient and we don't need to add more tempest
tests would need to be included.
Is this untestable in gate given current limitations (specific hardware /
software configurations available)? Is this untestable in murano-ci? If so,
are there mitigation plans (3rd party testing, gate enhancements, etc).
Documentation Impact
====================
What is the impact on the docs team of this change? Some changes might require
donating resources to the docs team to have the documentation updated. Don't
repeat details discussed above, but please reference them here.
References
==========
Please add any useful references here. You are not required to have any
reference. Moreover, this specification should still make sense when your
references are unavailable. Examples of what you could include are:
* Links to mailing list or IRC discussions
* Links to notes from a summit session
* Links to relevant research, if appropriate
* Related specifications as appropriate (e.g. if it's an EC2 thing, link the
EC2 docs)
* Anything else you feel it is worthwhile to refer to

View File

View File

@ -1,102 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import glob
import re
import docutils.core
import testtools
class TestTitles(testtools.TestCase):
def _get_title(self, section_tree):
section = {
'subtitles': [],
}
for node in section_tree:
if node.tagname == 'title':
section['name'] = node.rawsource
elif node.tagname == 'section':
subsection = self._get_title(node)
section['subtitles'].append(subsection['name'])
return section
def _get_titles(self, spec):
titles = {}
for node in spec:
if node.tagname == 'section':
section = self._get_title(node)
titles[section['name']] = section['subtitles']
return titles
def _check_titles(self, fname, titles):
expected_titles = ('Problem description', 'Proposed change',
'Implementation', 'Dependencies',
'Testing', 'Documentation Impact',
'References')
self.assertEqual(
sorted(expected_titles),
sorted(titles.keys()),
"Expected titles not found in document %s" % fname)
proposed = 'Proposed change'
self.assertIn('Alternatives', titles[proposed])
self.assertIn('Data model impact', titles[proposed])
self.assertIn('REST API impact', titles[proposed])
self.assertIn('Versioning impact', titles[proposed])
self.assertIn('Other end user impact', titles[proposed])
self.assertIn('Deployer impact', titles[proposed])
self.assertIn('Developer impact', titles[proposed])
self.assertIn('Murano-dashboard / Horizon impact', titles[proposed])
impl = 'Implementation'
self.assertIn('Assignee(s)', titles[impl])
self.assertIn('Work Items', titles[impl])
def _check_lines_wrapping(self, tpl, raw):
for i, line in enumerate(raw.split("\n")):
if "http://" in line or "https://" in line:
continue
self.assertTrue(
len(line) < 80,
msg="%s:%d: Line limited to a maximum of 79 characters." %
(tpl, i+1))
def _check_no_cr(self, tpl, raw):
matches = re.findall('\r', raw)
self.assertEqual(
len(matches), 0,
"Found %s literal carriage returns in file %s" %
(len(matches), tpl))
def _check_trailing_spaces(self, tpl, raw):
for i, line in enumerate(raw.split("\n")):
trailing_spaces = re.findall(" +$", line)
self.assertEqual(len(trailing_spaces),0,
"Found trailing spaces on line %s of %s" % (i+1, tpl))
def test_template(self):
files = ['specs/template.rst'] + glob.glob('specs/*/*/*')
for filename in files:
self.assertTrue(filename.endswith(".rst"),
"spec's file must uses 'rst' extension.")
with open(filename) as f:
data = f.read()
spec = docutils.core.publish_doctree(data)
titles = self._get_titles(spec)
self._check_titles(filename, titles)
self._check_lines_wrapping(filename, data)
self._check_no_cr(filename, data)
self._check_trailing_spaces(filename, data)

30
tox.ini
View File

@ -1,30 +0,0 @@
[tox]
minversion = 3.1.1
envlist = docs,pep8
skipsdist = True
ignore_basepython_conflict = True
[testenv]
basepython = python3
usedevelop = True
setenv = VIRTUAL_ENV={envdir}
deps =
-c{env:UPPER_CONSTRAINTS_FILE:https://opendev.org/openstack/requirements/raw/branch/master/upper-constraints.txt}
-r{toxinidir}/requirements.txt
commands = python setup.py testr --slowest --testr-args='{posargs}'
whitelist_externals = find
[testenv:venv]
commands = {posargs}
[testenv:docs]
commands =
find . -type f -name "*.pyc" -delete
sphinx-build -W -b html doc/source doc/build/html
[testenv:doc8]
deps =
-c{env:UPPER_CONSTRAINTS_FILE:https://opendev.org/openstack/requirements/raw/branch/master/upper-constraints.txt}
-r{toxinidir}/requirements.txt
doc8
commands = doc8 doc/source