python-muranoclient-1.0.1/0000775000175100017510000000000013231417024015551 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/0000775000175100017510000000000013231417024020242 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/notes/0000775000175100017510000000000013231417024021372 5ustar zuulzuul00000000000000././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000python-muranoclient-1.0.1/releasenotes/notes/deprecate-murano-packages-service-glance-7d0052a5256adace.yamlpython-muranoclient-1.0.1/releasenotes/notes/deprecate-murano-packages-service-glance-7d0052a5256ada0000666000175100017510000000027013231416510033161 0ustar zuulzuul00000000000000--- deprecations: - Since glare is a separate project now usage of 'glance' value for --murano-packages-service has been deprecated and is scheduled to be removed in P cycle python-muranoclient-1.0.1/releasenotes/notes/support-endpoint-type-d7c6b32098b67eeb.yaml0000666000175100017510000000041413231416510031073 0ustar zuulzuul00000000000000fixes: - cli now makes use of type of the endpoint (defined either as a --os-endpoint-type command line parameter or OS_ENDPOINT_TYPE environment variable). This type defines which interface will be used when connecting to murano, glance and glare APIs. python-muranoclient-1.0.1/releasenotes/notes/bug-1629221-e7f1766eb9878f23.yaml0000666000175100017510000000014213231416510026042 0ustar zuulzuul00000000000000--- features: - CLI command :command:``env-templat-create-env`` now supports ``--region`` flag python-muranoclient-1.0.1/releasenotes/notes/added-environment-command-85b31973e101fd1f.yaml0000666000175100017510000000040413231416510031427 0ustar zuulzuul00000000000000--- features: - New OSC command ``environment create [--join-net-id ] [--join-subnet-id ] [--region ] `` - New OSC command ``environment delete [--abandon] [ ...]`` ././@LongLink0000000000000000000000000000015000000000000011211 Lustar 00000000000000python-muranoclient-1.0.1/releasenotes/notes/list-environments-of-a-given-project-e407dd5271649ad2.yamlpython-muranoclient-1.0.1/releasenotes/notes/list-environments-of-a-given-project-e407dd5271649ad2.y0000666000175100017510000000025113231416510033013 0ustar zuulzuul00000000000000--- features: - The client now is able to consume the updated `List Environments` API call, which may be used to filter environments by an owner project (tenant). python-muranoclient-1.0.1/releasenotes/notes/safeloader-cve-2016-4972-e3f7ad9b234655ca.yaml0000666000175100017510000000062513231416510030432 0ustar zuulzuul00000000000000--- security: - cve-2016-4972 has been addressed. In ceveral places Murano used loaders inherited directly from yaml.Loader when parsing MuranoPL and UI files from packages. This is unsafe, because this loader is capable of creating custom python objects from specifically constructed yaml files. With this change all yaml loading operations are done using safe loaders instead. python-muranoclient-1.0.1/releasenotes/notes/action-arguments-06a554f76783f3ed.yaml0000666000175100017510000000044113231416510027707 0ustar zuulzuul00000000000000--- feature: - environment-action-call command now accepts action argument values of any type in JSON format, for example - ``environment-action-call $ENV_ID --action-id $ACT_ID --arguments foo=bar listArg='["item1", "item2", "item3"]' nullArg=null stringArg='"null"' intArg=5`` python-muranoclient-1.0.1/releasenotes/notes/glare-endpoint-cdba1b2351c19592.yaml0000666000175100017510000000037313231416510027374 0ustar zuulzuul00000000000000--- features: - Since glare has been moved to a separate service muranoclient CLI now distinguishes between --glance-url and --glare-url. If --glare-url is not supplied muranoclient requests an endpoint of type 'artifact' from keystone. python-muranoclient-1.0.1/releasenotes/notes/enable-openstack-client-support-a273e33d6c31e36e.yaml0000666000175100017510000000021213231416510032664 0ustar zuulzuul00000000000000--- features: - Added python-muranoclient support in openstack-client by setting entry points and implementing interface functions. python-muranoclient-1.0.1/releasenotes/notes/global-inherits-fix-6da007ec44a774f2.yaml0000666000175100017510000000024313231416510030337 0ustar zuulzuul00000000000000--- fixes: - Importing a package into glare, now fills 'inherited' field with full inheritance info (previously it only contained immediate parent classes). python-muranoclient-1.0.1/releasenotes/notes/improved-cli-outputs-a3e75cf0224a1993.yaml0000666000175100017510000000020113231416510030515 0ustar zuulzuul00000000000000--- fixes: - Changed murano-client CLI outputs to show only items affected by current operation instead of full item list. python-muranoclient-1.0.1/releasenotes/notes/fix-owned-flag-e8b718c074c1c314.yaml0000666000175100017510000000017413231416510027221 0ustar zuulzuul00000000000000--- fixes: - It was impossible to use `--owned` flag when Glare was used to filter packages. This issue is fixed now. python-muranoclient-1.0.1/releasenotes/notes/added-schemas-support-e4a6e44c7bac2751.yaml0000666000175100017510000000057513231416510030753 0ustar zuulzuul00000000000000--- features: - Support for class/method JSON-schema API was added - New murano CLI command ``murano class-schema [--package-name PACKAGE_NAME] [--class-version PACKAGE_VERSION] [ [ ...]]`` - New OSC command ``openstack class-schema [--package-name PACKAGE_NAME] [--class-version PACKAGE_VERSION] [ [ ...]]`` python-muranoclient-1.0.1/releasenotes/notes/added-static-actions-3d45f5cdc5491770.yaml0000666000175100017510000000065513231416510030414 0ustar zuulzuul00000000000000--- features: - Support for static actions API was added - New Murano CLI command ``murano static-action-call [--arguments [ [ ...]]] [--package-name ] [--class-version CLASS_VERSION] `` - New OSC command ``openstack static-action call [--arguments [ [ ...]]] [--package-name ] [--class-version CLASS_VERSION] `` python-muranoclient-1.0.1/releasenotes/notes/import-package-from-directory-8f2b5e393004ef97.yaml0000666000175100017510000000025013231416510032271 0ustar zuulzuul00000000000000--- features: - Ability to load package from directory was added. If specified directory contains all the needed files then package will be imported as usual.python-muranoclient-1.0.1/releasenotes/notes/resources-dir-for-hot-c557c1472bbc79fa.yaml0000666000175100017510000000030413231416510030716 0ustar zuulzuul00000000000000--- fixes: - Added ability to use arguments ``--resources-dir`` and ``--template`` for ``package-create`` command simultaneously. It allows to create HOT-packages with Resources folder. python-muranoclient-1.0.1/releasenotes/notes/.placeholder0000666000175100017510000000000013231416510023644 0ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/notes/add-environment-support-to-OSC-173b86ec631283b7.yaml0000666000175100017510000000043613231416510032210 0ustar zuulzuul00000000000000--- features: - New OSC command ``environment list [--all-tenants]`` - New OSC command ``environment show [--session-id ] [--only-apps]`` - New OSC command ``environment rename `` - New OSC command ``environment session create `` python-muranoclient-1.0.1/releasenotes/notes/dep-exists-action-9af18bebcc0ef053.yaml0000666000175100017510000000050213231416510030244 0ustar zuulzuul00000000000000--- features: - Added '--dep-exists-action' option to murano ``package-import`` and ``bundle-import`` commands. It allows to specify a different default action for existing main package and existing dependencies. In case of specifying just '--exists-action', action for dependencies also defaults to it. python-muranoclient-1.0.1/releasenotes/notes/multi-class-yamls-support-914b3d155324214f.yaml0000666000175100017510000000016613231416510031341 0ustar zuulzuul00000000000000--- fixes: - Fixed a bug when a package containing multi-class yamls could not be added to glare-based catalog. python-muranoclient-1.0.1/releasenotes/notes/repair-package-update-command-72e4c85da1b2c897.yaml0000666000175100017510000000032213231416510032247 0ustar zuulzuul00000000000000fixes: - command 'package_update' was broken since murano start support of keystone v3. The error occurred because murano tried to pass custom content type parameter in the request kwargs, not headers. python-muranoclient-1.0.1/releasenotes/notes/osc-murano-url-507932234b49cf9f.yaml0000666000175100017510000000016413231416510027232 0ustar zuulzuul00000000000000--- features: - OSC plugin now honores ``--murano-url`` and ``MURANO_URL``, to allow using custom murano endpoint python-muranoclient-1.0.1/releasenotes/notes/bug-1527045-97993f04757b4901.yaml0000666000175100017510000000023713231416510025622 0ustar zuulzuul00000000000000--- fixes: - fixes no attribute error caused by the new raw_request return, by let the SessionClient raw_request only return response without data. python-muranoclient-1.0.1/releasenotes/notes/reauth-fix-e03ad966c3178167.yaml0000666000175100017510000000017013231416510026414 0ustar zuulzuul00000000000000--- fixes: - Added fallback from token to username/password if both are provided and token expires or is invalid. python-muranoclient-1.0.1/releasenotes/notes/osc-package-list-command-23e39dc92ead8834.yaml0000666000175100017510000000006413231416510031247 0ustar zuulzuul00000000000000--- features: - New OSC command ``package list``. python-muranoclient-1.0.1/releasenotes/notes/environment-edit-7faf5c8e8a3d44ac.yaml0000666000175100017510000000075513231416510030217 0ustar zuulzuul00000000000000--- features: - Support for environment model edit API was added - New Murano CLI command ``murano environment-model-show [--path ] [--session-id ]`` - New Murano CLI command ``murano environment-model-edit --session-id `` - New OSC command ``openstack environment model show [--path ] [--session-id ]`` - New OSC command ``openstack environment model edit --session-id `` python-muranoclient-1.0.1/releasenotes/notes/yamlloader-glare-d7d0506f6711b650.yaml0000666000175100017510000000025613231416510027554 0ustar zuulzuul00000000000000--- fixes: - It is now possible to import packages with '!yaql' tag, when glare is used as backend. Before this fix, importing such package caused a parsing error. python-muranoclient-1.0.1/releasenotes/notes/bug-1536121-51c42f77a9e97db1.yaml0000666000175100017510000000024613231416510026104 0ustar zuulzuul00000000000000--- fixes: - Fixes use murano package-import with version parameter, It always shows version of client. Rename the parameter 'version' to 'package-version' python-muranoclient-1.0.1/releasenotes/notes/added-category-command-01cb9dab21ab4a7b.yaml0000666000175100017510000000030613231416510031155 0ustar zuulzuul00000000000000--- features: - New OSC command ``category list`` - New OSC command ``category show `` - New OSC command ``category create `` - New OSC command ``category delete [ ...]`` python-muranoclient-1.0.1/releasenotes/notes/multiple-packages-glare-fix-b82a473ad976028f.yaml0000666000175100017510000000032413231416510031704 0ustar zuulzuul00000000000000--- fixes: - It was possible to import the same murano package from the CLI into the same project multiple times if glare was used and the package was imported as a private one. The issue is now fixed. python-muranoclient-1.0.1/releasenotes/notes/requirements-order-19ecc40ca6d34739.yaml0000666000175100017510000000026513231416510030334 0ustar zuulzuul00000000000000--- fixes: - Fixed order of packages import - main package can not be imported before all its dependencies are imported. Cyclic requirements are imported in random order. python-muranoclient-1.0.1/releasenotes/source/0000775000175100017510000000000013231417024021542 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/source/newton.rst0000666000175100017510000000023213231416510023604 0ustar zuulzuul00000000000000=================================== Newton Series Release Notes =================================== .. release-notes:: :branch: origin/stable/newton python-muranoclient-1.0.1/releasenotes/source/conf.py0000666000175100017510000002207313231416510023046 0ustar zuulzuul00000000000000# -*- coding: utf-8 -*- # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # Murano Release Notes documentation build configuration file, created by # sphinx-quickstart on Tue Nov 3 17:40:50 2015. # # 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. # 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('.')) # -- 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 = [ 'reno.sphinxext', 'openstackdocstheme', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Murano Client Release Notes' copyright = u'2015, Murano Developers' # Release notes are version independent. # The full version, including alpha/beta/rc tags. release = '' # The short X.Y version. version = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'openstackdocs' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # html_theme_path = [openstackdocstheme.get_html_theme_path()] # openstackdocstheme options repository_name = 'openstack/python-muranoclient' bug_project = 'python-muranoclient' bug_tag = '' # Must set this variable to include year, month, day, hours, and minutes. html_last_updated_fmt = '%Y-%m-%d %H:%M' # The name for this set of Sphinx documents. If None, it defaults to # " v 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 # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'MuranoClientReleaseNotesdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'MuranoClientReleaseNotes.tex', u'Murano Client Release Notes Documentation', u'Murano Developers', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'muranoclientreleasenotes', u'Murano Client Release Notes Documentation', [u'Murano Developers'], 1) ] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'MuranoClientReleaseNotes', u'Murano Client Release Notes Documentation', u'Murano Developers', 'MuranoClientReleaseNotes', 'One line description of 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' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] python-muranoclient-1.0.1/releasenotes/source/_templates/0000775000175100017510000000000013231417024023677 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/source/_templates/.placeholder0000666000175100017510000000000013231416510026151 0ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/source/pike.rst0000666000175100017510000000021713231416510023225 0ustar zuulzuul00000000000000=================================== Pike Series Release Notes =================================== .. release-notes:: :branch: stable/pike python-muranoclient-1.0.1/releasenotes/source/ocata.rst0000666000175100017510000000023013231416510023357 0ustar zuulzuul00000000000000=================================== Ocata Series Release Notes =================================== .. release-notes:: :branch: origin/stable/ocata python-muranoclient-1.0.1/releasenotes/source/liberty.rst0000666000175100017510000000022213231416510023743 0ustar zuulzuul00000000000000============================== Liberty Series Release Notes ============================== .. release-notes:: :branch: origin/stable/liberty python-muranoclient-1.0.1/releasenotes/source/locale/0000775000175100017510000000000013231417024023001 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/source/locale/en_GB/0000775000175100017510000000000013231417024023753 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/source/locale/en_GB/LC_MESSAGES/0000775000175100017510000000000013231417024025540 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po0000666000175100017510000003724213231416510030602 0ustar zuulzuul00000000000000# Andi Chandler , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: Murano Client Release Notes 0.14.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-05 02:06+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-10-21 09:05+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en-GB\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "0.10.0" msgstr "0.10.0" msgid "0.11.1" msgstr "0.11.1" msgid "0.12.0" msgstr "0.12.0" msgid "0.7.3" msgstr "0.7.3" msgid "0.8.1" msgstr "0.8.1" msgid "0.8.2" msgstr "0.8.2" msgid "0.8.4" msgstr "0.8.4" msgid "0.8.5" msgstr "0.8.5" msgid "0.8.6" msgstr "0.8.6" msgid "0.9.0" msgstr "0.9.0" msgid "" "Ability to load package from directory was added. If specified directory " "contains all the needed files then package will be imported as usual." msgstr "" "Ability to load package from directory was added. If specified directory " "contains all the needed files then package will be imported as usual." msgid "" "Add an ability to use arguments --resources-dir and --template for the " "command package-create simultaneously. It allows to create HOT-packages with " "Resources folder." msgstr "" "Add an ability to use arguments --resources-dir and --template for the " "command package-create simultaneously. It allows to create HOT-packages with " "Resources folder." msgid "" "Added '--dep-exists-action' option to murano ``package-import`` and ``bundle-" "import`` commands. It allows to specify a different default action for " "existing main package and existing dependencies. In case of specifying just " "'--exists-action', action for dependencies also defaults to it." msgstr "" "Added '--dep-exists-action' option to Murano ``package-import`` and ``bundle-" "import`` commands. It allows to specify a different default action for " "existing main package and existing dependencies. In case of specifying just " "'--exists-action', action for dependencies also defaults to it." msgid "" "Added '--dep-exists-action' option to murano command-line interface. It " "allows to apply different default actions for existing main package and " "existing dependencies. In case of specifying just '--exists-action', action " "for dependencies equals to that like it was previously." msgstr "" "Added '--dep-exists-action' option to Murano command-line interface. It " "allows to apply different default actions for existing main package and " "existing dependencies. In case of specifying just '--exists-action', action " "for dependencies equals to that like it was previously." msgid "" "Added ability to use arguments ``--resources-dir`` and ``--template`` for " "``package-create`` command simultaneously. It allows to create HOT-packages " "with Resources folder." msgstr "" "Added ability to use arguments ``--resources-dir`` and ``--template`` for " "``package-create`` command simultaneously. It allows to create HOT-packages " "with Resources folder." msgid "" "Added fallback from token to username/password if both are provided and " "token expires or is invalid." msgstr "" "Added fallback from token to username/password if both are provided and " "token expires or is invalid." msgid "" "Added python-muranoclient support in openstack-client by setting entry " "points and implementing interface functions." msgstr "" "Added python-muranoclient support in openstack-client by setting entry " "points and implementing interface functions." msgid "Bug Fixes" msgstr "Bug Fixes" msgid "" "CLI command :command:``env-templat-create-env`` now supports ``--region`` " "flag" msgstr "" "CLI command :command:``env-templat-create-env`` now supports ``--region`` " "flag" msgid "" "Changed murano-client CLI outputs to show only items affected by current " "operation instead of full item list." msgstr "" "Changed murano-client CLI outputs to show only items affected by current " "operation instead of full item list." msgid "Current Series Release Notes" msgstr "Current Series Release Notes" msgid "Deprecation Notes" msgstr "Deprecation Notes" msgid "" "Fixed a bug when a package containing multi-class yamls could not be added " "to glare-based catalog." msgstr "" "Fixed a bug when a package containing multi-class yamls could not be added " "to glare-based catalogue." msgid "" "Fixed order of packages import - main package can not be imported before all " "its dependencies are imported. Cyclic requirements are imported in random " "order." msgstr "" "Fixed order of packages import - main package can not be imported before all " "its dependencies are imported. Cyclic requirements are imported in random " "order." msgid "" "Fixes use murano package-import with version parameter, It always shows " "version of client. Rename the parameter 'version' to 'package-version'" msgstr "" "Fixes use Murano package-import with version parameter, It always shows " "version of client. Rename the parameter 'version' to 'package-version'" msgid "" "Importing a package into glare, now fills 'inherited' field with full " "inheritance info (previously it only contained immediate parent classes)." msgstr "" "Importing a package into glare, now fills 'inherited' field with full " "inheritance info (previously it only contained immediate parent classes)." msgid "" "It is now possible to import packages with '!yaql' tag, when glare is used " "as backend. Before this fix, importing such package caused a parsing error." msgstr "" "It is now possible to import packages with '!yaql' tag, when Glare is used " "as backend. Before this fix, importing such package caused a parsing error." msgid "" "It was impossible to use `--owned` flag when Glare was used to filter " "packages. This issue is fixed now." msgstr "" "It was impossible to use `--owned` flag when Glare was used to filter " "packages. This issue is fixed now." msgid "" "It was possible to import the same murano package from the CLI into the same " "project multiple times if glare was used and the package was imported as a " "private one. The issue is now fixed." msgstr "" "It was possible to import the same Murano package from the CLI into the same " "project multiple times if Glare was used and the package was imported as a " "private one. The issue is now fixed." msgid "Liberty Series Release Notes" msgstr "Liberty Series Release Notes" msgid "Mitaka Series Release Notes" msgstr "Mitaka Series Release Notes" msgid "Murano Client Release Notes" msgstr "Murano Client Release Notes" msgid "New Features" msgstr "New Features" msgid "" "New Murano CLI command ``murano environment-model-edit --session-" "id ``" msgstr "" "New Murano CLI command ``murano environment-model-edit --session-" "id ``" msgid "" "New Murano CLI command ``murano environment-model-show [--path ] " "[--session-id ]``" msgstr "" "New Murano CLI command ``murano environment-model-show [--path ] " "[--session-id ]``" msgid "" "New Murano CLI command ``murano static-action-call [--arguments [ " "[ ...]]] [--package-name ] [--class-version " "CLASS_VERSION] ``" msgstr "" "New Murano CLI command ``murano static-action-call [--arguments [ " "[ ...]]] [--package-name ] [--class-version " "CLASS_VERSION] ``" msgid "New OSC command ``category create ``" msgstr "New OSC command ``category create ``" msgid "New OSC command ``category delete [ ...]``" msgstr "New OSC command ``category delete [ ...]``" msgid "New OSC command ``category list``" msgstr "New OSC command ``category list``" msgid "New OSC command ``category show ``" msgstr "New OSC command ``category show ``" msgid "" "New OSC command ``environment create [--join-net-id ] [--join-subnet-" "id ] [--region ] ``" msgstr "" "New OSC command ``environment create [--join-net-id ] [--join-subnet-" "id ] [--region ] ``" msgid "" "New OSC command ``environment delete [--abandon] [ ...]``" msgstr "" "New OSC command ``environment delete [--abandon] [ ...]``" msgid "New OSC command ``environment list [--all-tenants]``" msgstr "New OSC command ``environment list [--all-tenants]``" msgid "New OSC command ``environment rename ``" msgstr "New OSC command ``environment rename ``" msgid "New OSC command ``environment session create ``" msgstr "New OSC command ``environment session create ``" msgid "" "New OSC command ``environment show [--session-id ] " "[--only-apps]``" msgstr "" "New OSC command ``environment show [--session-id ] " "[--only-apps]``" msgid "" "New OSC command ``openstack class-schema [--package-name PACKAGE_NAME] [--" "class-version PACKAGE_VERSION] [ [ ...]]``" msgstr "" "New OSC command ``openstack class-schema [--package-name PACKAGE_NAME] [--" "class-version PACKAGE_VERSION] [ [ ...]]``" msgid "" "New OSC command ``openstack environment model edit --session-id " "``" msgstr "" "New OSC command ``openstack environment model edit --session-id " "``" msgid "" "New OSC command ``openstack environment model show [--path ] [--" "session-id ]``" msgstr "" "New OSC command ``openstack environment model show [--path ] [--" "session-id ]``" msgid "" "New OSC command ``openstack static-action call [--arguments [ " "[ ...]]] [--package-name ] [--class-version " "CLASS_VERSION] ``" msgstr "" "New OSC command ``openstack static-action call [--arguments [ " "[ ...]]] [--package-name ] [--class-version " "CLASS_VERSION] ``" msgid "New OSC command ``package list``." msgstr "New OSC command ``package list``." msgid "" "New murano CLI command ``murano class-schema [--package-name PACKAGE_NAME] " "[--class-version PACKAGE_VERSION] [ [ ...]]``" msgstr "" "New Murano CLI command ``murano class-schema [--package-name PACKAGE_NAME] " "[--class-version PACKAGE_VERSION] [ [ ...]]``" msgid "Newton Series Release Notes" msgstr "Newton Series Release Notes" msgid "" "OSC plugin now honores ``--murano-url`` and ``MURANO_URL``, to allow using " "custom murano endpoint" msgstr "" "OSC plugin now honores ``--murano-url`` and ``MURANO_URL``, to allow using " "custom murano endpoint" msgid "Ocata Series Release Notes" msgstr "Ocata Series Release Notes" msgid "Pike Series Release Notes" msgstr "Pike Series Release Notes" msgid "Security Issues" msgstr "Security Issues" msgid "" "Since glare has been moved to a separate service muranoclient CLI now " "distinguishes between --glance-url and --glare-url. If --glare-url is not " "supplied muranoclient requests an endpoint of type 'artifact' from keystone." msgstr "" "Since Glare has been moved to a separate service muranoclient CLI now " "distinguishes between --glance-url and --glare-url. If --glare-url is not " "supplied muranoclient requests an endpoint of type 'artifact' from keystone." msgid "" "Since glare is a separate project now usage of 'glance' value for --murano-" "packages-service has been deprecated and is scheduled to be removed in P " "cycle" msgstr "" "Since Glare is a separate project now usage of 'glance' value for --murano-" "packages-service has been deprecated and is scheduled to be removed in P " "cycle" msgid "Support for class/method JSON-schema API was added" msgstr "Support for class/method JSON-schema API was added" msgid "Support for environment model edit API was added" msgstr "Support for environment model edit API was added" msgid "Support for static actions API was added" msgstr "Support for static actions API was added" msgid "" "Support for static actions API was added - New Murano CLI command ``murano " "static-action-call [--arguments [ [ ...]]] [--package-" "name ] [--class-version CLASS_VERSION] `` - New OSC " "command ``openstack static-action call [--arguments [ " "[ ...]]] [--package-name ] [--class-version " "CLASS_VERSION] ``" msgstr "" "Support for static actions API was added - New Murano CLI command ``murano " "static-action-call [--arguments [ [ ...]]] [--package-" "name ] [--class-version CLASS_VERSION] `` - New OSC " "command ``openstack static-action call [--arguments [ " "[ ...]]] [--package-name ] [--class-version " "CLASS_VERSION] ``" msgid "" "The client now is able to consume the updated `List Environments` API call, " "which may be used to filter environments by an owner project (tenant)." msgstr "" "The client now is able to consume the updated `List Environments` API call, " "which may be used to filter environments by an owner project (tenant)." msgid "Upgrade Notes" msgstr "Upgrade Notes" msgid "" "cli now makes use of type of the endpoint (defined either as a --os-endpoint-" "type command line parameter or OS_ENDPOINT_TYPE environment variable). This " "type defines which interface will be used when connecting to murano, glance " "and glare APIs." msgstr "" "CLI now makes use of type of the endpoint (defined either as a --os-endpoint-" "type command line parameter or OS_ENDPOINT_TYPE environment variable). This " "type defines which interface will be used when connecting to Murano, Glance " "and Glare APIs." msgid "" "command 'package_update' was broken since murano start support of keystone " "v3. The error occurred because murano tried to pass custom content type " "parameter in the request kwargs, not headers." msgstr "" "command 'package_update' was broken since Murano start support of keystone " "v3. The error occurred because Murano tried to pass custom content type " "parameter in the request kwargs, not headers." msgid "" "cve-2016-4972 has been addressed. In ceveral places Murano used loaders " "inherited directly from yaml.Loader when parsing MuranoPL and UI files from " "packages. This is unsafe, because this loader is capable of creating custom " "python objects from specifically constructed yaml files. With this change " "all yaml loading operations are done using safe loaders instead." msgstr "" "cve-2016-4972 has been addressed. In several places Murano used loaders " "inherited directly from yaml.Loader when parsing MuranoPL and UI files from " "packages. This is unsafe, because this loader is capable of creating custom " "python objects from specifically constructed yaml files. With this change " "all yaml loading operations are done using safe loaders instead." msgid "" "environment-action-call command now accepts action argument values of any " "type in JSON format, for example environment-action-call $ENV_ID --action-id " "$ACT_ID --arguments foo=bar listArg='[\"item1\", \"item2\", \"item3\"]' " "nullArg=null stringArg='\"null\"' intArg=5" msgstr "" "environment-action-call command now accepts action argument values of any " "type in JSON format, for example environment-action-call $ENV_ID --action-id " "$ACT_ID --arguments foo=bar listArg='[\"item1\", \"item2\", \"item3\"]' " "nullArg=null stringArg='\"null\"' intArg=5" msgid "" "fixes no attribute error caused by the new raw_request return, by let the " "SessionClient raw_request only return response without data." msgstr "" "fixes no attribute error caused by the new raw_request return, by let the " "SessionClient raw_request only return response without data." python-muranoclient-1.0.1/releasenotes/source/locale/fr/0000775000175100017510000000000013231417024023410 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/source/locale/fr/LC_MESSAGES/0000775000175100017510000000000013231417024025175 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po0000666000175100017510000000265713231416510030241 0ustar zuulzuul00000000000000# Gérald LONLAS , 2016. #zanata msgid "" msgstr "" "Project-Id-Version: Murano Client Release Notes 0.12.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-03-14 12:38+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2016-10-22 06:11+0000\n" "Last-Translator: Gérald LONLAS \n" "Language-Team: French\n" "Language: fr\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" msgid "0.10.0" msgstr "0.10.0" msgid "0.11.1" msgstr "0.11.1" msgid "0.7.3" msgstr "0.7.3" msgid "0.8.1" msgstr "0.8.1" msgid "0.8.2" msgstr "0.8.2" msgid "0.8.4" msgstr "0.8.4" msgid "0.8.5" msgstr "0.8.5" msgid "0.8.6" msgstr "0.8.6" msgid "0.9.0" msgstr "0.9.0" msgid "Bug Fixes" msgstr "Corrections de bugs" msgid "Current Series Release Notes" msgstr "Note de la release actuelle" msgid "Deprecation Notes" msgstr "Notes dépréciées " msgid "Liberty Series Release Notes" msgstr "Note de release pour Liberty" msgid "Mitaka Series Release Notes" msgstr "Note de release pour Mitaka" msgid "Murano Client Release Notes" msgstr "Note de release du Client Murano" msgid "New Features" msgstr "Nouvelles fonctionnalités" msgid "Newton Series Release Notes" msgstr "Note de release pour Newton" msgid "Security Issues" msgstr "Problèmes de sécurités" msgid "Upgrade Notes" msgstr "Notes de mises à jours" python-muranoclient-1.0.1/releasenotes/source/unreleased.rst0000666000175100017510000000016013231416510024421 0ustar zuulzuul00000000000000============================== Current Series Release Notes ============================== .. release-notes:: python-muranoclient-1.0.1/releasenotes/source/index.rst0000666000175100017510000000026613231416510023410 0ustar zuulzuul00000000000000============================= Murano Client Release Notes ============================= .. toctree:: :maxdepth: 2 unreleased pike ocata newton mitaka liberty python-muranoclient-1.0.1/releasenotes/source/mitaka.rst0000666000175100017510000000023213231416510023540 0ustar zuulzuul00000000000000=================================== Mitaka Series Release Notes =================================== .. release-notes:: :branch: origin/stable/mitaka python-muranoclient-1.0.1/releasenotes/source/_static/0000775000175100017510000000000013231417024023170 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/releasenotes/source/_static/.placeholder0000666000175100017510000000000013231416510025442 0ustar zuulzuul00000000000000python-muranoclient-1.0.1/setup.sh0000666000175100017510000001257113231416510017254 0ustar zuulzuul00000000000000#!/bin/sh # Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # # Ubuntu script. LOGLVL=1 SERVICE_CONTENT_DIRECTORY=`cd $(dirname "$0") && pwd` PREREQ_PKGS="wget make git python-pip python-dev python-mysqldb libxml2-dev libxslt-dev" SERVICE_SRV_NAME="python-muranoclient" GIT_CLONE_DIR=`echo $SERVICE_CONTENT_DIRECTORY | sed -e "s/$SERVICE_SRV_NAME//"` # Functions # Loger function log() { MSG=$1 if [ $LOGLVL -gt 0 ]; then echo "LOG:> $MSG" fi } # Check or install package in_sys_pkg() { PKG=$1 dpkg -s $PKG > /dev/null 2>&1 if [ $? -eq 0 ]; then log "Package \"$PKG\" already installed" else log "Installing \"$PKG\"..." apt-get install $PKG --yes > /dev/null 2>&1 if [ $? -ne 0 ];then log "installation fails, exiting!!!" exit fi fi } # git clone gitclone() { FROM=$1 CLONEROOT=$2 log "Cloning from \"$FROM\" repo to \"$CLONEROOT\"" cd $CLONEROOT && git clone $FROM > /dev/null 2>&1 if [ $? -ne 0 ];then log "cloning from \"$FROM\" fails, exiting!!!" exit fi } # install inst() { CLONE_FROM_GIT=$1 # Checking packages for PKG in $PREREQ_PKGS do in_sys_pkg $PKG done # If clone from git set if [ ! -z $CLONE_FROM_GIT ]; then # Preparing clone root directory if [ ! -d $GIT_CLONE_DIR ];then log "Creating $GIT_CLONE_DIR directory..." mkdir -p $GIT_CLONE_DIR if [ $? -ne 0 ];then log "Can't create $GIT_CLONE_DIR, exiting!!!" exit fi fi # Cloning from GIT GIT_WEBPATH_PRFX="https://git.openstack.org/cgit/openstack/" gitclone "$GIT_WEBPATH_PRFX$SERVICE_SRV_NAME.git" $GIT_CLONE_DIR # End clone from git section fi # Setupping... log "Running setup.py" #MRN_CND_SPY=$GIT_CLONE_DIR/$SERVICE_SRV_NAME/setup.py MRN_CND_SPY=$SERVICE_CONTENT_DIRECTORY/setup.py if [ -e $MRN_CND_SPY ]; then chmod +x $MRN_CND_SPY log "$MRN_CND_SPY output:_____________________________________________________________" #cd $GIT_CLONE_DIR/$SERVICE_SRV_NAME && $MRN_CND_SPY install #if [ $? -ne 0 ]; then # log "\"$MRN_CND_SPY\" python setup FAILS, exiting!" # exit 1 #fi ## Setup through pip # Creating tarball #cd $GIT_CLONE_DIR/$SERVICE_SRV_NAME && $MRN_CND_SPY sdist rm -rf $SERVICE_CONTENT_DIRECTORY/*.egg-info cd $SERVICE_CONTENT_DIRECTORY && python $MRN_CND_SPY egg_info if [ $? -ne 0 ];then log "\"$MRN_CND_SPY\" egg info creation FAILS, exiting!!!" exit 1 fi rm -rf $SERVICE_CONTENT_DIRECTORY/dist/* cd $SERVICE_CONTENT_DIRECTORY && python $MRN_CND_SPY sdist if [ $? -ne 0 ];then log "\"$MRN_CND_SPY\" tarball creation FAILS, exiting!!!" exit 1 fi # Running tarball install #TRBL_FILE=$(basename `ls $GIT_CLONE_DIR/$SERVICE_SRV_NAME/dist/*.tar.gz`) #pip install $GIT_CLONE_DIR/$SERVICE_SRV_NAME/dist/$TRBL_FILE TRBL_FILE=$(basename `ls $SERVICE_CONTENT_DIRECTORY/dist/*.tar.gz`) pip install $SERVICE_CONTENT_DIRECTORY/dist/$TRBL_FILE if [ $? -ne 0 ];then log "pip install \"$TRBL_FILE\" FAILS, exiting!!!" exit 1 fi else log "$MRN_CND_SPY not found!" fi } # uninstall uninst() { # Uninstall trough pip # looking up for python package installed #PYPKG=`echo $SERVICE_SRV_NAME | tr -d '-'` PYPKG="muranoclient" pip freeze | grep $PYPKG if [ $? -eq 0 ]; then log "Removing package \"$PYPKG\" with pip" pip uninstall $PYPKG --yes else log "Python package \"$PYPKG\" not found" fi } # Command line args' COMMAND="$1" case $COMMAND in install ) inst ;; installfromgit ) inst "yes" ;; uninstall ) log "Uninstalling muranoclient \"$SERVICE_SRV_NAME\" from system..." uninst ;; * ) echo "Usage: $(basename "$0") command \nCommands:\n\tinstall - Install $SERVICE_SRV_NAME software\n\tuninstall - Uninstall $SERVICE_SRV_NAME software" exit 1 ;; esac python-muranoclient-1.0.1/PKG-INFO0000664000175100017510000000745213231417024016656 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-muranoclient Version: 1.0.1 Summary: python-muranoclient Home-page: https://docs.openstack.org/murano/latest/ Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/python-muranoclient.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on Murano ====== .. image:: https://img.shields.io/pypi/v/python-muranoclient.svg :target: https://pypi.python.org/pypi/python-muranoclient/ :alt: Latest Version .. image:: https://img.shields.io/pypi/dm/python-muranoclient.svg :target: https://pypi.python.org/pypi/python-muranoclient/ :alt: Downloads Murano Project introduces an application catalog, which allows application developers and cloud administrators to publish various cloud-ready applications in a browsable categorised catalog, which may be used by the cloud users (including the inexperienced ones) to pick-up the needed applications and services and composes the reliable environments out of them in a "push-the-button" manner. * `PyPi`_ - package installation * `Launchpad project`_ - release management * `Blueprints`_ - feature specifications * `Bugs`_ - issue tracking * `Source`_ * `Specs`_ * `How to Contribute`_ .. _PyPi: https://pypi.python.org/pypi/python-muranoclient .. _Launchpad project: https://launchpad.net/python-muranoclient .. _Blueprints: https://blueprints.launchpad.net/python-muranoclient .. _Bugs: https://bugs.launchpad.net/python-muranoclient .. _Source: https://git.openstack.org/cgit/openstack/python-muranoclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html .. _Specs: https://specs.openstack.org/openstack/murano-specs/ Python Muranoclient ------------------- python-muranoclient is a client library for Murano built on the Murano API. It provides a Python API (the ``muranoclient`` module) and a command-line tool (``murano``). Project Resources ----------------- Project status, bugs, and blueprints are tracked on Launchpad: * Client bug tracker * https://launchpad.net/python-muranoclient * Murano bug tracker * https://launchpad.net/murano Developer documentation can be found here: https://docs.openstack.org/murano/latest/ Additional resources are linked from the project wiki page: https://wiki.openstack.org/wiki/Murano License ------- Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Environment :: OpenStack Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 python-muranoclient-1.0.1/.testr.conf0000666000175100017510000000055013231416510017640 0ustar zuulzuul00000000000000[DEFAULT] test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./muranoclient/tests/unit} $LISTOPT $IDOPTION test_id_option=--load-list $IDFILE test_list_option=--list python-muranoclient-1.0.1/CONTRIBUTING.rst0000666000175100017510000000243513231416510020217 0ustar zuulzuul00000000000000====================== Contributing to Murano ====================== If you're interested in contributing to the Murano project, the following will help get you started. Contributor License Agreement ============================= In order to contribute to the Murano project, you need to have signed OpenStack's contributor's agreement: * https://docs.openstack.org/infra/manual/developers.html * https://wiki.openstack.org/CLA Project Hosting Details ======================= * Bug tracker * https://launchpad.net/murano * https://launchpad.net/python-muranoclient * Mailing list (prefix subjects with ``[Murano]`` for faster responses) http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev * Wiki https://wiki.openstack.org/wiki/Murano * IRC channel * #murano at FreeNode * https://wiki.openstack.org/wiki/Meetings#Murano_meeting * Code Hosting * https://git.openstack.org/cgit/openstack/murano * https://git.openstack.org/cgit/openstack/murano-agent * https://git.openstack.org/cgit/openstack/murano-dashboard * https://git.openstack.org/cgit/openstack/python-muranoclient * Code Review * https://review.openstack.org/#/q/murano+AND+status:+open,n,z * https://docs.openstack.org/infra/manual/developers.html#development-workflow python-muranoclient-1.0.1/AUTHORS0000664000175100017510000001065613231417022016627 0ustar zuulzuul00000000000000Aaron-DH Alexander Koryagin Alexander Shlykov Alexander Tivelkov Anastasia Kuznetsova Andreas Jaeger Andrew Pashkin Andy Botting Anh Tran Ankur Rishi Artem Tiumentcev AvnishPal Bertrand Lallau Cao Xuan Hoang Christian Berendt Dai Dang Van Dmitry Teselkin Dmytro Dovbii Doug Hellmann Ekaterina Chernova Ekaterina Fedorova Felipe Monteiro Feng Shengqin Filip Blaha Flavio Percoco ForestLee Georgiy Okrokvertskhov Georgy Dyuldin Georgy Okrokvertskhov Hangdong Zhang Henar Muñoz Frutos Hidekazu Nakamura Igor Yozhikov Ilya Popov Ivan Udovichenko Jacek Tomasiak Janonymous Jeremy Stanley Jesus Perez Jose Phillips Junyuan Leng KATO Tomoyuki Kirill Zaitsev Konstantin Snihyr Lin Yang LiuNanke Longgeek M V P Nitesh MStolyarenko Maria Zlatkova Nam Nguyen Hoai Nikolay Mahotkin Nikolay Starodubtsev OlehBaran Oleksii Chuprykov Olivier Lemasle Omar Shykhkerimov OpenStack Release Bot Ravi Shekhar Jethani Rui Chen Ruslan Kamaldinov Ryan Peters Sascha Peilicke Serg Melikyan Serg Melikyan Sergey Melikyan Sergey Murashov Sergey Turivnyi Sergey Vilgelm Stan Lagun Stan Lagun Stanislav Lagun Steve Martinelli Steve Martinelli Steve McLellan Steve McLellan Swapnil Kulkarni (coolsvap) Tang Chen Tatyana Kuterina Tetiana Lashchova Timur Nurlygayanov Timur Sufiev TimurNurlygayanov Valerii Kovalchuk Victor Ryzhenkin Yosef Hoffman Zuul bhagyashris bharaththiruveedula chenaidong1 enthurohini gecong1973 howardlee hparekh huangsm leizhang lidong lingyongxu liyingjun liyingjun luqitao melissaml pawnesh.kumar ricolin ricolin srushti sslypushenko venkatamahesh visitor xiangxinyong yuyafei zhangyanxian zhu.rong zhurong python-muranoclient-1.0.1/babel.cfg0000666000175100017510000000002013231416510017270 0ustar zuulzuul00000000000000[python: **.py] python-muranoclient-1.0.1/requirements.txt0000666000175100017510000000134613231416510021042 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. pbr!=2.1.0,>=2.0.0 # Apache-2.0 PrettyTable<0.8,>=0.7.1 # BSD python-glanceclient>=2.8.0 # Apache-2.0 python-keystoneclient>=3.8.0 # Apache-2.0 iso8601>=0.1.11 # MIT six>=1.10.0 # MIT Babel!=2.4.0,>=2.3.4 # BSD pyOpenSSL>=16.2.0 # Apache-2.0 requests>=2.14.2 # Apache-2.0 PyYAML>=3.10 # MIT yaql>=1.1.3 # Apache 2.0 License osc-lib>=1.8.0 # Apache-2.0 murano-pkg-check>=0.3.0 # Apache-2.0 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 oslo.utils>=3.33.0 # Apache-2.0 oslo.log>=3.36.0 # Apache-2.0 oslo.i18n>=3.15.3 # Apache-2.0 python-muranoclient-1.0.1/run_tests.sh0000777000175100017510000000556513231416510020152 0ustar zuulzuul00000000000000#!/bin/bash function usage { echo "Usage: $0 [OPTION]..." echo "Run python-muranoclient's test suite(s)" echo "" echo " -p, --pep8 Just run pep8" echo " -h, --help Print this usage message" echo " -V, --virtual-env Always use virtualenv. Install automatically if not present" echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment" echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added." echo " -u, --update Update the virtual environment with any newer package versions" echo "" echo "This script is deprecated and currently retained for compatibility." echo 'You can run the full test suite for multiple environments by running "tox".' echo 'You can run tests for only python 2.7 by running "tox -e py27", or run only' echo 'the pep8 tests with "tox -e pep8".' exit } just_pep8=0 always_venv=0 never_venv=0 wrapper= update=0 force=0 export NOSE_WITH_OPENSTACK=1 export NOSE_OPENSTACK_COLOR=1 export NOSE_OPENSTACK_RED=0.05 export NOSE_OPENSTACK_YELLOW=0.025 export NOSE_OPENSTACK_SHOW_ELAPSED=1 export NOSE_OPENSTACK_STDOUT=1 function process_option { case "$1" in -h|--help) usage;; -p|--pep8) let just_pep8=1;; -V|--virtual-env) let always_venv=1; let never_venv=0;; -f|--force) let force=1;; -u|--update) update=1;; -N|--no-virtual-env) let always_venv=0; let never_venv=1;; esac } for arg in "$@"; do process_option $arg done function run_tests { # Cleanup *pyc and *pyo ${wrapper} find . -type f -name "*.py[c|o]" -delete # Just run the test suites in current environment ${wrapper} $NOSETESTS } function run_pep8 { echo "Running pep8 ..." PEP8_EXCLUDE=".venv,.tox,dist,doc,openstack,build" PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --repeat --select=H402" PEP8_IGNORE="--ignore=E125,E126,E711,E712" PEP8_INCLUDE="." pep8 $PEP8_OPTIONS $PEP8_INCLUDE $PEP8_IGNORE } NOSETESTS="nosetests $noseopts $noseargs" if [ $never_venv -eq 0 ] then # Remove the virtual environment if --force used if [ $force -eq 1 ]; then echo "Cleaning virtualenv..." rm -rf ${venv} fi if [ $update -eq 1 ]; then echo "Updating virtualenv..." python tools/install_venv.py fi if [ -e ${venv} ]; then wrapper="${with_venv}" else if [ $always_venv -eq 1 ]; then # Automatically install the virtualenv python tools/install_venv.py wrapper="${with_venv}" else echo -e "No virtual environment found...create one? (Y/n) \c" read use_ve if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then # Install the virtualenv and run the test suite in it python tools/install_venv.py wrapper=${with_venv} fi fi fi fi if [ $just_pep8 -eq 1 ]; then run_pep8 exit fi run_tests || exit run_pep8 python-muranoclient-1.0.1/tox.ini0000666000175100017510000000321113231416510017062 0ustar zuulzuul00000000000000[tox] envlist = py35,py27,pep8 minversion = 1.6 skipsdist = True [testenv] usedevelop = True whitelist_externals = bash find install_command = pip install {opts} {packages} setenv = VIRTUAL_ENV={envdir} passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY deps = -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = bash tools/pretty_tox.sh '{posargs}' [testenv:pep8] commands = flake8 {posargs} [testenv:py27-mitaka] install_command = pip install -U {opts} {packages} {toxinidir}/tools/tox_install.sh https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/mitaka {opts} {packages} [testenv:venv] commands = {posargs} [testenv:functional] setenv = OS_TEST_PATH = ./muranoclient/tests/functional passenv = OS_* MURANO_PACKAGES_SERVICE [testenv:uitests] commands = python setup.py testr --slowest --testr-args="--concurrency 1 {posargs}" [testenv:cover] commands = {toxinidir}/tools/cover.sh {posargs} [testenv:debug] commands = find . -type f -name "*.pyc" -delete oslo_debug_helper -t muranoclient/tests {posargs} [testenv:pyflakes] deps = -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} flake8 commands = flake8 [testenv:releasenotes] commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html [flake8] show-source = true builtins = _ exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,tools,build python-muranoclient-1.0.1/test-requirements.txt0000666000175100017510000000121113231416510022006 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD mock>=2.0.0 # BSD requests-mock>=1.1.0 # Apache-2.0 tempest>=17.1.0 # Apache-2.0 testrepository>=0.0.18 # Apache-2.0/BSD testscenarios>=0.4 # Apache-2.0/BSD testtools>=2.2.0 # MIT oslotest>=3.2.0 # Apache-2.0 # doc build requirements openstackdocstheme>=1.17.0 # Apache-2.0 sphinx!=1.6.6,>=1.6.2 # BSD reno>=2.5.0 # Apache-2.0 python-muranoclient-1.0.1/.coveragerc0000666000175100017510000000014013231416510017666 0ustar zuulzuul00000000000000[run] source = muranoclient omit = .tox/* muranoclient/tests/* [report] ignore_errors = True python-muranoclient-1.0.1/README.rst0000666000175100017510000000446413231416510017251 0ustar zuulzuul00000000000000======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/python-muranoclient.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on Murano ====== .. image:: https://img.shields.io/pypi/v/python-muranoclient.svg :target: https://pypi.python.org/pypi/python-muranoclient/ :alt: Latest Version .. image:: https://img.shields.io/pypi/dm/python-muranoclient.svg :target: https://pypi.python.org/pypi/python-muranoclient/ :alt: Downloads Murano Project introduces an application catalog, which allows application developers and cloud administrators to publish various cloud-ready applications in a browsable categorised catalog, which may be used by the cloud users (including the inexperienced ones) to pick-up the needed applications and services and composes the reliable environments out of them in a "push-the-button" manner. * `PyPi`_ - package installation * `Launchpad project`_ - release management * `Blueprints`_ - feature specifications * `Bugs`_ - issue tracking * `Source`_ * `Specs`_ * `How to Contribute`_ .. _PyPi: https://pypi.python.org/pypi/python-muranoclient .. _Launchpad project: https://launchpad.net/python-muranoclient .. _Blueprints: https://blueprints.launchpad.net/python-muranoclient .. _Bugs: https://bugs.launchpad.net/python-muranoclient .. _Source: https://git.openstack.org/cgit/openstack/python-muranoclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html .. _Specs: https://specs.openstack.org/openstack/murano-specs/ Python Muranoclient ------------------- python-muranoclient is a client library for Murano built on the Murano API. It provides a Python API (the ``muranoclient`` module) and a command-line tool (``murano``). Project Resources ----------------- Project status, bugs, and blueprints are tracked on Launchpad: * Client bug tracker * https://launchpad.net/python-muranoclient * Murano bug tracker * https://launchpad.net/murano Developer documentation can be found here: https://docs.openstack.org/murano/latest/ Additional resources are linked from the project wiki page: https://wiki.openstack.org/wiki/Murano License ------- Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 python-muranoclient-1.0.1/ChangeLog0000664000175100017510000010411113231417022017317 0ustar zuulzuul00000000000000CHANGES ======= 1.0.1 ----- * Updated from global requirements * Updated from global requirements 1.0.0 ----- * Updated from global requirements * Avoid tox\_install.sh for constraints support * Remove setting of version/release from releasenotes * Updated from global requirements * Updated from global requirements * Imported Translations from Zanata * Use generic user for both zuul v2 and v3 * update env template output * Updated from global requirements * Fix to use "." to source script files * Updated from global requirements * Update links in README * Add package download to openstack CLI * Add package update to openstack CLI * Add package show to openstack CLI * Updated from global requirements * Updated from global requirements * Add bundle import to openstack CLI * Skip two test due to apps.openstack.org is retired * Updated from global requirements * Update the documentation link for doc migration * Update reno for stable/pike * Updated from global requirements 0.14.0 ------ * Updated from global requirements * Update the documentation link for doc migration * Updated from global requirements * Updated from global requirements * Using the latest openstackdocstheme settings * Remove long-ago deprecated show\_categories * Updated from global requirements * import content from cli-reference in openstack-manuals * move existing content into the new standard structure * Turn on warning-is-error in sphinx build * switch to openstackdocstheme * Updated from global requirements 0.13.0 ------ * Updated from global requirements * Updated from global requirements * Updated from global requirements * Modify Default Domain * Updated from global requirements * Updated from global requirements * Add package import to openstack CLI * delete bash\_completion in subcommand * Updated from global requirements * Optimize the link address * Correct the unit test name * Updated from global requirements * Replace six.iteritems() with .items() * Updated from global requirements * Imported Translations from Zanata * Replaces uuid.uuid4 with uuidutils.generate\_uuid() * Remove log translations * Make method import\_versioned\_module work * Updated from global requirements * Update test requirement * Updated from global requirements * Updated from global requirements * Remove support for py34 * Allows fetching of deployments from all environments * Update reno for stable/ocata 0.12.0 ------ * Exclude build dir for flake8 test * Add debug to tox enviroment * Remove white space between print () * Fixes filtering applications by name with glare * Remove the data assert to pass the gate * Add package delete to openstack CLI * Using sys.exit(main()) instead of main() * Return error code when a error occurred during package-import * Fix Murano client to use V3 and MultiDomain Authentication * Use assertGreater() and assertLess() * Support i18n for LOG.warning * Update author in setup.cfg * Updated from global requirements * Show team and repo badges on README * Support for environment list filtering by project id * Delete python bytecode file * Fix typos in cover.sh * Fix removes date\_time items from dictionaries * Fix removes date\_time items from dictionaries * Updated from global requirements * move old apiclient code out of openstack/common * Updated from global requirements * Add validation to package import * Updated from global requirements * Updated from global requirements * Add plug-in summary for osc doc * Updated from global requirements * Add functional test for environment-model-show * Fix osc plugin gives the error when using keystone v3 * Add docstrings for environment-model-edit and environment-model-show commands * Fix OpenStack Licensing * OSC plugin should be using region/interface * Enable release notes translation * Add support for environment edit API * Fixing environment creation from template * Unskip the test due to bugfix * Skip some tests when using glare in a right way * Mark .testr.conf as non-executable * Make some OSC tests more clean * Updated from global requirements * TrivialFix: Fix typo in the bash shell file * Add package list to openstack CLI * Updated from global requirements * Updated from global requirements * TrivialFix: Using assertTrue() instead of assertEqual(True) * Remove unnecessary setUp * Updated from global requirements * Make OSC plugin be able to use glare backend * Updated from global requirements * Make --limit argument in package-list command robust * Add opportunity to import package from directory * Add Glare to python-muranloclient tests * Fix 'owned' flag when Glare is used * Populate tenant information in client * Cleanup, clarify newton release-notes * Update reno for stable/newton * Deprecate usage of 'glance' for --murano-pcakages-service 0.11.0 ------ * Sync tools/tox\_install.sh * Increase yaql quotas * [docs] Update Readme with correct Doc URL * Replace functions 'Dict.get' and 'del' with 'Dict.pop' * Updated from global requirements * Updated from global requirements * Decode PrettyTable output before printing for Python3 * Use upper constraints for all jobs in tox.ini * Updated from global requirements * Updated from global requirements * Add script for unit test coverage job * Trivial: clean up oslo-incubator related stuff * Add package create to openstack CLI 0.10.0 ------ * Correct default class version for static action call * Support for Schemas API was added * Support for multi-class yamls in client * Add Python 3.5 classifier and venv * Updated from global requirements * Change image for package in the code taken from Glance * Remove discover from test-requirements * Make environment-action-call command accept JSON arguments * Updated from global requirements * Add support for static actions API * Updated from global requirements * Add deployment list to openstack CLI * Add environment apps edit to openstack CLI * Add py27-mitaka tox target * Updated from global requirements * Use upper-constraints in tox test environments * Add \_\_ne\_\_ built-in function * Updated from global requirements * Use osc\_lib instead of cliff * Add 'description\_text' filed to test\_table\_struct\_env\_show * Use osc-lib instead of openstackclient 0.9.0 ----- * Updated from global requirements * Use DummyYaqlYamlLoader to load classes during upload * Use yaml.SafeLoader instead of yaml.Loader * Replace print statment with print function * Updated from global requirements * Fix python 2,3 compatibility issue with six * Fix client could not init glance client * Import package and dependencies in correct order * Fix typo in env-template-create-env arg description * Replace tempest\_lib with tempest.lib * Add environment deploy to openstack CLI * Support resources-dir for hot-packages * Reorder releasenotes and increase toctree depth * Add '--dep-exists-action' argument to murano CLI * Utilize enpoint\_type argument for client creation * Modified docstrings to comply with pep8 H405 style check * Store transitive inheritance information in glare * Updated from global requirements * Updated from global requirements * Remove unused httplib2 requirement * Updated from global requirements * Further refactor of Glare API urls * Improve muranoclient install scripts syntax * Updated from global requirements * Updated from global requirements * Refactor urls to Glare API * Fall back to glance API v1 * Correct variable name in code adopted from Glance * Updated from global requirements * Fix test case of test\_category\_create\_long\_name * Typo fix for python-muranoclient * GetPackageUI API is now called even if Glare is used * Updated from global requirements * Correct check for artifact package visibility * Move OpenStack client to test-requirements * Make use of version passed to glare artifacts\_client * Fix displaying packages in category-show subcommand * Improve dictionary representation of package from Glare * Set "glare" as valid choice for "--murano-packages-service" option * Refactor request methods in HTTP/SessionClient classes * Fix authentication in glare-api via keystone * Adds improvements for verification of values from created and listed package * Fix env-template-add-app command failed * Do not log contents of the download request * Updated from global requirements * Add test to check error message for bundle-import with invalid file format * Add test to check delete environment by environment ID * Add test to check error message for bundle-import with non-existing name * Add Category support for openstack CLI * Add environment create/delete to openstack CLI * Add ability to override MURANO\_URL for murano OSC plugin * Add Environment support for openstack CLI * Update reno for stable/mitaka * Updated from global requirements * Add reauth if token is expired and username/password are available * Update dummy application for testing after changes in murano * Distinguish between glance and glare endpoints 0.8.3 ----- * Remove unused pngmath Sphinx extension * Add test to check error message for category-create with long category name * Import bundle with a not regular-bundle json give no error * Add test to check error message for bundle-import with non-existed package * Add "Version" column in the package-list output * Add test to check error message for bundle-import without bundle name * Fix version in requests to GLARE * Updated from global requirements * Add test to check category-show error message * Add test to check category-delete error message 0.8.2 ----- * Remove unexpected kwargs when authenticating using token * Updated from global requirements * Updated from global requirements * Deletes redundant line in shell.py file * Make CLI outputs consistent with other OpenStack clients * Rename the package-import version parameter * Fix reading of app template file when adding to env template * Fix inconsistent argument name/placeholder in EnvTemplateManager.delete\_app * Add Status field\_labels for environment list * Fix checks for Project/Tenant command line arguments * Improving python3 compatibility * Improve is-public argument in env-template-create * environment-action-get-result now calls correct get\_result API * Adds region parameter to environment-create * Fixes incorrect endpoint\_override handling * Fixes TypeError in Client constructor * Updated from global requirements * Fix first argument of murano env-template-add-app usage * Add filter for do\_package\_list * Fix spellings for some words * Fix package delete on update when using Glare * Update translation setup * Updated from global requirements * CLI shell can now properly interact with Glance Artifacts * Fixed visibility parameter for create package glare call * Fix module's import order * Add is-public for environment-template list * Add environment template clone * Initial commit for openstack-client support in python-muranoclient * Add the cover case for 'body' kwarg in http json\_request * Updated from global requirements * Add python 3 support * Updated from global requirements 0.8.1 ----- * Updated from global requirements * Delete unuse variable in shell.py * Repair package-update command * Remove unnecessary statements for default argument * Updated from global requirements * Updated from global requirements * use keystoneclient exceptions instead of oslo-incubator code * Add machinery for translations via babel * Remove argparse dependency from requirements.txt file * Put py34 first in the envlist order of tox * Change LOG.warn to LOG.warning * Updated from global requirements * Delete the special character in README.rst * Remove arguments "{}" and "[]" in function definitions * Add Type field\_labels for package list * Make package-update help more clear * Let the SessionClient raw\_request only return response * Delete the extra space in delete package print * Updated from global requirements * Use oslo\_i18n instend of gettextutils * Updated from global requirements * Pass environment variables of proxy to tox * Change logging level in SessionClient * Fix Resource.\_\_eq\_\_ mismatch semantics of object equal * Update setup.cfg entries * Updated from global requirements 0.8.0 ----- * Remove py26 support * Add limit param for package-list * Catch correct exceptions in shell * Add missing space to error message * Fixed an incorrect call to the artifacts client * Fixed a download method wrapper in glare adaptor * 'to\_dict' method added to PackageWrapper class * Glare client now properly filters by class name * Updated from global requirements * Add reno for RElease NOtes * Replacing application\_catalog with application-catalog * New operation env-template-create-env * Show detailed info about app * Add python 3 support * Updated from global requirements * Rename folder with CLI tests * Add keystone v3 support to client * Add CLI tests for environment redeploy * Add unit-tests for categories * Import images publicly when package is public * Add test for environment deployment using CLI * Updated from global requirements * Use standard formatters for environment-create-session output * Small refactoring of CLI tests for packages * Updated from global requirements * Improve README contents * Updated from global requirements * Add more tests for categories, env-templates and packages * Updated from global requirements * Add Active field\_labels for package list * Updated from global requirements * Use non-absolute paths, to allow urljoin join them correctly * Hide token id in logs * Fix incorrect output after error in package-save * Add missing parameter 'acquired\_by' to environment model in tests * Updated from global requirements * Fix archive name generation in package\_create command 0.7.1 ----- * Fix the common/utils typo * Fixed YAQL tag leakage to YAML loader * Check package-download for stdout redirection * Update the python-muranoclient docs * Update MURANO\_REPO\_URL * Output detail informations about murano --debug command * Updated from global requirements * Update path to subunit2html in post\_test\_hook and fix env-show test * Updated from global requirements * Enable F812 and H904 style check * Fix app-show command * Fix test for environment table structure * Delete the unused LOG code * Return detailed info when get environment by name 0.7.0 ----- * Added the support of Glance Artifact Repository * Copy the code of Glance V3 (artifacts) client * Fixed issue with cacert parameter * Strip json and html from error messages * Update the git ingore * Fix the reversed incoming parameters of assertEqual * Add olso.log into muranoclient's requirements.txt * Updated from global requirements * Standardise help parameter of CLI commands * Fix some spelling mistakes of setup files 0.6.3 ----- * Support for YAQL 1.0.0 * Updated from global requirements * Generate ids in environment-apps-edit command * Allow editing packages with package-update command * Add parameter support to pagination-list * Add CLI command package-save * Add check for dashes in template name * Add environment-apps-edit command * Add environment-session-create command * Add action controlling commands * Add params to environment\_show command * Updated from global requirements * Add environment-deploy command * Updated package-import help description * Add sanity tests for testing actions with environment CLI command * Add ability to filter from categories with unicode * Allow joining existing networks when creating environment * Switch to oslo\_log in murano client * Add basic tests for Murano CLI client. Add CleanUp after tests * Add bundle-save CLI command * Place generated hot package to work directory * Updated from global requirements * Add description to CLI command category-show * Remove unused module cliutils and timeutils 0.6.2 ----- * Rename all visible occurrences of 'services' name * Add docstring to service-show command * Fix the unit tests with wrong using of mock * Add passenv parameter for tox G.variables passthrough * Allows congress to fetch environments from all tenants * Remove all vim modelines * Edits the help-text for python-muranoclient * Add abandon parameter to delete method * Add --version parameter for murano python client * Update requirements.txt * Adding config-like auth configuration for functional tests 0.6.0 ----- * Point default MURANO\_REPO\_URL to http://storage.apps.openstack.org * Support multiple filenames for package commands * Remove hash check during image upload * Make post\_test\_hook.sh executable * Add post\_test\_hook for functional tests * First pass at tempest\_lib based functional testing * Add OS\_TEST\_PATH to testr * Move unit tests into unit test directory * Drop use of 'oslo' namespace package * Only delete 'owned' packages for --exists-action update * Updated YAQL requirement to >= 0.2.6 * Update Readme * Limit parameter is no longer ignored for packages * Update .gitreview file to reflect repo rename * Better error logging for package/bundle import * Update package composing command * Tests for repository machinery * Bash completion script for murano * Add bash-completion subparser to shell client * Update from global requirements 0.5.6 ----- * Use HTTPClient in package\_create manager method * Removed default Content-Type HTTP request header * Improve image and bundle handling * Support local bundles * Fix service-show command * Fix category list CLI command * Enable Bundle.packages() to yield Package objects * Environment Template CLI * Handle duplicate packages during uploading via CLI * Add support for required images file * Client support for Require section in manifest * Allow importing bundles of packages * Allow importing packages name * Allow importing packages by url * Adds client support for action results * Use name or ID of environment for murano CLI commands * Enable category management support * Fixed pagination parameter to conform to API specs * Reverted "Add keystone v3 support to client" * Fixes pagination in "packages-list" command * Add keystone v3 support to client * Add 'verify' option to package.create * Do not parse empty body * Remove obsolete checks from tox.ini * Use pretty-tox for better test output * Update from global requirements * Use modules from oslo istead of openstack-common * Add opportunity to create public packages via shell * Revert "Add keystone v3 support to client" * Add keystone v3 support to client * Catch ConnectionError exception from requests * Updated from global requirements 0.5.5 ----- * Log response when using requests library * Provide method for calling action in an environment * Bump hacking to 0.9.x series 0.5.4 ----- * Fix some calls after switch to 'requests' 0.5.3 ----- * Convert muranoclient to 'requests' * Fix exception names and CLI args * Adds toggle public functionality * Add LICENSE to muranoclient * Update package-import command * Add package-create command * Updated from global requirements * Allow deletion of multiple environments * Infrastructure update * Add ability to retrieve supplier logo for package * Correct muranoclient service\_get function * Enable to set updating type for "Update package" * Extend package-show output with detailed information 0.5.2 ----- * Improve logging in CLI client * Extend CLI functionality * Fix issue with python 3.3 gate job * Paginate packages list using 'next\_marker' attribute * Run hacking in a right way * fixed several pep8 issues * Fixed Keystone endpoint query * Enable unpickling base.Resource objects 0.5.1 ----- * for pkg list, make include\_disabled default False * Return package object in packages.create method 0.5.0 ----- * Remove version from setup.cfg * Added HTTP proxy support * Fix the issue with stats API call * Update requirements.txt due to changes in global-requirements.txt * InstanceStatistics updated for corresponding API change * Parse YAML in muranoclient with the loader of the given class * Refactor packages filter and list methods * Interface to get instance statistics added * Support package update, toggle\_active and filter methods * Initial support of working with package definitions * Updated openstack-common * Calls to the v1 API are prefixed with the appropriate version prefix * Add Stats List method * Fixed issue with requirements * Update README with actual info * Update requirements to stable/havana * Update version in setup.cfg * Support passing networking info during environment create, not update * Support getting and updating network\_info of environment * Cherry-picked changes from release-0.3 * Support building wheels (PEP-427) * Update requirements to match havana's ones * Resolve issues with package setup.py * Cherry-pick following change-ids from release-0.2 * Fix error from previous commit * Fix service creation failure * Fix http.py to initial * Resolved bug 746 * Add SSL support to muranoclient * Modified client to support lastStatus fetching * Add CentOS setup shell script * setup.sh add * list deployments in client now properly returns a list, not dictionary * Fixed a couple of bugs in path resolution routine * Changes in client to work with deployment logs fetching * Added support for new API v0.2 * fixed python setup workflow * Added tests for new services * Another changes within Service::Delete * Correct Service::Delete params * Murano Python Client support for IIS/ASP.NET web farms * Fix API according to New Sessions Handling design * python-muranoclient to support ASP.NET apps deployment API * Added .gitreview file * glazierclient -> muranoclient in tests * KEERO-320 - Fix all occurrences of old names (keero, glazier) in python client * Removed all projects except Glazier Api Client * Removed all projects except Glazier Api Client * Small fixes for unit tests * Fixed issue with length of new name * Fixed small issue * Fixed issue with names * Fixed issue with names * Fixed issue with names * Fixed issue with names * Fixed issue with names * Fixed issue with names * Fixed issue with names * Fixed small issue with new names * Fixed issue with horizon component installation * Fixed issue with horizon component installation * Fixed issue with horizon component installation * Finished converting API Specification * Fixed small issue with setup.py * Fixed issue with renaming of the tabula component * Fixed issue with renaming of the tabula component * Added part of API Specification * Tabula renamed to dashboard * Tabula renamed to dashboard * Finished documentation for API * Finished documentation for API * Renamed Portas to API * Renamed Portas to API * Added tox for webUI tests * Added license to documentation of Portas Client * Small fix * Fixed api interface names to environments * Fixed api interface names to environments * Renamed and licensed python-glazierclient * Fixed api interface names to environments * Fixed api interface names to environments * Renamed documentation project * Fixed licenses for tabula and tests. Fixed name of tabula project * Fixed licenses for tabula and tests. Fixed name of tabula project * Fixed a few small issues * Pass all RabbitMQ settings from conductor to Agent * Initialization of tox for conductor and portas. Add new webUI automated tests * Licenses added * A lot of changes were made * Issue with figures * Main Documentation Project * Fixed ignore file for python-portasclient * Documentation for UI * Documentation for Python PortasClient * Forgot man pages * Documentation for Portas Project * Send token when deleting environment * Fixed https://mirantis.jira.com/browse/KEERO-227 * Fixed issue with sessions * Fixed issue with sessions * Experiments * Experiments * Experiments * Experiments * Experiments * Add logging to WebUI * Add initial files for unit tests * Fixed issues with sessions Added logging * Added unit tests for client. Coverage 66% * Rename RabbitMQ username field Removed use\_ssl option from settings * Fix running install\_venv.py * Updated python-portasclient * PEP8 compliance * Fixed unit tests * Added ability to add services to environment * bug fix * bug fix * Fixed index bug * Finalize UI * Finalize UI * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Fix PEP8 errors * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Fix issue with statuses * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Experiments * Fixed issue with sessions * Naming conventions: use name instead of id for instance names * Heat auto-discovery, keero-linux-keys -> keero-keys * Experiments with UI * typo * Scoped tokens * Experiments with UI * Experiments with UI * Experiments with UI * Experiments with UI * Experiments with UI * Experiments with UI * Experiments with UI * Fix issue for result of deleted environments * Fix merge issue * Merged * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fix name of the variable * Fixed small issue * Send token when deleting environment * Removed unneeded binding * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Added tabs for services * forgotten file * Fixed issue with activeDirectory deletion * Add support for reports filtering * Added tabs for services * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Fixed small issue * Added dropdown list with list of services * Added initial version of tabs for services * Added initial version of tabs for services * Added initial version of tabs for services * Fixed issues with templates * Fixed issue with installation * Fixed issue with installation * PEP-8 * Fixed issue with incorrect import * logging and bug-fixes * fixed VM initialization script * Evironment/Units deletion, bug-fixes * Fixed UI issues * Remove service deletion button * Finished installable UI * Removed old code * Naming conventions changed * Updated OpenStack Common (Fixed issue with notifier package) * Use Heat REST API instead of command-line * Added support for setup.py Added localization and documentation skeletons PEP8 Fixes, optimized imports * #KEERO-222 Remove random part of unit name * Send Env to Conductor for deletion * Hot fix for WebUI tests * Fixed WebUI tests. Added new tests * #KEERO-220 Send X-Auth-Token to Conductor * Added initial unit tests for RestAPI service * Fixed all pep8 * Fixed automated tests for web UI * Fixed automated tests for WebUI. Added class Page with simple objects * Code to start\stop keero components using devstack functions * Fixed: changed the run mode for install venv script * Added deployment script for automated tests * All Cloudbase-Init plugins disabled except UserDataPlugin * Userdata script updated to support computer renaming functionality * Entry point script renamed 2d27f4f5054f34982ed67da2bf4b35c8ac1558d3 * Issues #195 and #199 * README and guide for conductor * Fix and unit test for issue: https://mirantis.jira.com/browse/KEERO-219 * Added unit tests for REST API client. Fixed pep8 * New devstack scripts added * Old devstack scripts removed * Write-Host replaced by Write-Log * Fixed typo * Sync * Sync * Sync * Cloned horizon and added our dashboard * Removed obsolete code Removed projects: [windc, windcclient] * Added tests for REST API. Fixed issues with Web UI * Added tests for REST API. Fixed issues with Web UI * Merged iteration3 branch to master. Fixed pep8 * Fixed small issues with UI * Added lst fixes for demo * Fix another issue with environments list * Fix another issue with services * Fix issue with getting list of environments * Added progress bars for services. Fixed few issues for demo * Fix issue with ack on results * Add part of service id to unit name * Add ability to get status for Environments and Sessions * Added password-secure checks for UI, fix usability issues for demo * ExecutionPlanGenerator DSL processor * Updated workflow elements to reflect new name changes and to fix typos * ExecutionPlanGenerator DSL processor * Updated workflow elements to reflect new name changes and to fix typos * Another Issue with sessions * Added progress bar to Web UI. Fixed pep8 errors * Change behaviour of viewing services * Issue with session * No ack is needed when auto\_ack set to True * Resolved issue with reports from orchestration engine * FIx issue with fields created & updated * Fixed issue with logging * Added deploy button for data centers in UI. Fixed templates for services * Queues should be durable * Add debug logging for controllers * Sync before tag * Fixed issue with empty services list * Added new API for Web UI * typos * Fixed length of names * Fixed instance namings * Added WebServer and AD * Workflows, ExecutionPlanGenerator, Reporting, UserData, conductor improvements * Removed obsolete file * Bug with Session * Added Session operations * Added Environments CRUD operations * Issue with deleting Environment * Removed obsolete files * Added initial version for python-portasclient * Issue with port for RabbitMQ * Function updated to return IPv4 addresses only * Typo * Explicit import of module DnsServer added * Function to install IIS added * Code to return DNS listening IPs from DC added * WebServer API Added WebServer API Small refactoring * Fix issues with queues * Added units name generation * Write results from orchestration engine * Active Directory API * Remove obsolete service table * Enable session deployment * Reports from orchestration engine Added ability to store and expose reports from orchestration engine * Cleaned up API * Added support for reading messages from RabbitMQ asynchronously * Typo * userdata.py fixed * Finished Task KEERO-111. Added base UI tests * Hot fix: Fixed pep8 for Dashboard * Finished Task: KEERO-117. Added new UI wizard for Create Services Action * Userdata plugin with minimal MIME support added * User data sample file added * Extra functions moved to NotCoreFunctions.ps1 file in order to remove them in the future * Functions to work with Base64 strings added * Functions to work with Zip files added * Modified files from cloudbase-init added * Fixed pep8. Fixed deployment script * Added support for session checking * Most part of Session API * Removed obsolete code * Added new Session model and migration Fixed issues with previous models * Initial conductor implementation * Added deployment script and automated tests * Small PEP8 fixes * Fixed small issues with parameters. It is required fix * Added remove method for environments Also slightly updated routes table * Finished environments api * Only environments from same tenant as users should be shown * Remove unnecessary blocks of code * When new DC is adding tenant\_id is added as param * Fix issues with context * Moved utils.py from WindDC * Small changes to .gitignore Removed global .gitignore Added .gitignore to WindowsAgent project * Update added files * Added support for keystone-auth * Updated initial version of portas-api * Initial version of portas-api * Simple function to update agent config added * Simple function for working with templates added * Function to retrieve meta data opject from config drive added * localrc updated * Files to automate devstack installation added * Fixed small issues with WebUI * asd * test.commit * test.commit * Log functions updated * Stop-Execution modified * Removed obsole line * Removed obsolete file Added .gitignore file * Added reference JSON for Active Directory * Fixed urls for dashboard * Fixed Web UI for demo * Files removed * Windows PowerShell module added * Unattended installation files added * Execution plan files added * windc iteration2 * Added WebUI for correct configuration of new service AD * Resolved issue with datacenter id * Resolved issue with datacenter id * Fixed many small issues * Fixed typo * Fixed KEERO-89 * Fixed issue with data centers * Added services functions to client. Need to be tested * [KEERO-83] Windows Agent: Ability to reboot machine after execution plan is executed * [KEERO-83] Windows Agent: Typo fixes + sample values in config * [KEERO-83] Windows Agent initial implementation * Added operations for chef. They might be remove if we decide to not use chef * Fixed small issues * Fixed KEERO-85 * Fixed issue with virtual environment SQLAlchemy library * Added library libsqlite3-dev to virtual environment for windc client * Added new functional to dashboard, fixed small issues * Added windc API client, sync repo with dev box * Added new files * Updated design. Removed extra code * 1. Added support of CloudFormation templates. Made a simple interface to build template. Stan can work here to redesign template.py 2. Added calls of drivers. Now heat is called from cmd instead of client. Should be rewritten. 3. ActiveDirectory makes a static template. Need to rewrite this with working with actual parameters * Added additional fields for Domain Controller * Added simple form for configuration Domen Controllers and IIS Servers * Fixed small problems with links and titles on pages * Fixed small problems with links and titles on pages * Added initial project for horizon dashboard * 1. Added builders support. Each builder is a class dynamically loaded from ./windc/core/builders folder. The class name should be the same as module file name. 2. Updated core/api.py to support datacenter and service creation with extra parameters which are not defined by model explicitly. 3. Added event based approach for the windows environment change. Now when user submits a request to API the core updates database and initiates a new event which defined scope (datacenter, service, VM) and action (add, modify, delete). This event and data will be iterated over all registered builders. Each builder can use this event and data to plan some modification * 1. Fixed issue with main file start ./bin/windc-api 2. Added router to Route /datacenters/ and /services/ URLs 3. Added stubs for windc/core/api. 4. Fixed start-up process for service ------------------------------------------------- Now it is working service which will reply for curl http://localhost:8181/tenant\_id/datacenters/ curl http://localhost:8181/tenant\_id/datacenters/dc\_id/services curl http://localhost:8181/tenant\_id/datacenters/dc\_id/services/service\_id * Initial version of the Windows DataCenter project. It is openstak-skeleton based * Unattended files added * Initial empty repository python-muranoclient-1.0.1/setup.cfg0000666000175100017510000000623313231417024017400 0ustar zuulzuul00000000000000[metadata] name = python-muranoclient summary = python-muranoclient description-file = README.rst license = Apache License, Version 2.0 author = OpenStack author-email = openstack-dev@lists.openstack.org home-page = https://docs.openstack.org/murano/latest/ classifier = Development Status :: 4 - Beta Environment :: Console Environment :: OpenStack Intended Audience :: Developers Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.5 [files] packages = muranoclient [entry_points] console_scripts = murano = muranoclient.shell:main openstack.cli.extension = application_catalog = muranoclient.osc.plugin openstack.application_catalog.v1 = environment_list = muranoclient.osc.v1.environment:ListEnvironments environment_show = muranoclient.osc.v1.environment:ShowEnvironment environment_rename = muranoclient.osc.v1.environment:RenameEnvironment environment_session_create = muranoclient.osc.v1.environment:EnvironmentSessionCreate environment_create = muranoclient.osc.v1.environment:EnvironmentCreate environment_delete = muranoclient.osc.v1.environment:EnvironmentDelete environment_deploy = muranoclient.osc.v1.environment:EnvironmentDeploy environment_apps_edit = muranoclient.osc.v1.environment:EnvironmentAppsEdit environment_model_show = muranoclient.osc.v1.environment:EnvironmentModelShow environment_model_edit = muranoclient.osc.v1.environment:EnvironmentModelEdit category_list = muranoclient.osc.v1.category:ListCategories category_show = muranoclient.osc.v1.category:ShowCategory category_create = muranoclient.osc.v1.category:CreateCategory category_delete = muranoclient.osc.v1.category:DeleteCategory deployment_list = muranoclient.osc.v1.deployment:ListDeployment package_create = muranoclient.osc.v1.package:CreatePackage package_list = muranoclient.osc.v1.package:ListPackages package_delete = muranoclient.osc.v1.package:DeletePackage package_import = muranoclient.osc.v1.package:ImportPackage package_show = muranoclient.osc.v1.package:ShowPackage package_update = muranoclient.osc.v1.package:UpdatePackage package_download = muranoclient.osc.v1.package:DownloadPackage bundle_import = muranoclient.osc.v1.package:ImportBundle static-action_call = muranoclient.osc.v1.action:StaticActionCall class-schema = muranoclient.osc.v1.schema:ShowSchema [global] setup-hooks = pbr.hooks.setup_hook [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [build_sphinx] source-dir = doc/source build-dir = doc/build all_files = 1 warning-is-error = 1 [upload_sphinx] upload-dir = doc/build/html [wheel] universal = 1 [compile_catalog] directory = muranoclient/locale domain = muranoclient [update_catalog] domain = muranoclient output_dir = muranoclient/locale input_file = muranoclient/locale/muranoclient.pot [extract_messages] keywords = _ gettext ngettext l_ lazy_gettext mapping_file = babel.cfg output_file = muranoclient/locale/muranoclient.pot python-muranoclient-1.0.1/doc/0000775000175100017510000000000013231417024016316 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/doc/source/0000775000175100017510000000000013231417024017616 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/doc/source/conf.py0000666000175100017510000000554713231416510021131 0ustar zuulzuul00000000000000# -*- coding: utf-8 -*- # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import os project = 'python-muranoclient' # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'openstackdocstheme',] # autodoc generation is a bit aggressive and a nuisance when doing heavy # text edit cycles. # execute "export SPHINX_DEBUG=1" in your terminal to disable # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. copyright = u'OpenStack Foundation' exclude_trees = ['api'] # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = True # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'openstackdocs' # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = ['_theme'] #html_theme_path = [openstackdocstheme.get_html_theme_path()] # openstackdocstheme options repository_name = 'openstack/python-muranoclient' bug_project = 'python-muranoclient' bug_tag = '' # Must set this variable to include year, month, day, hours, and minutes. html_last_updated_fmt = '%Y-%m-%d %H:%M' # Output file base name for HTML help builder. htmlhelp_basename = '%sdoc' % project # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ ( 'index', '%s.tex' % project, u'%s Documentation' % project, u'OpenStack Foundation', 'manual' ), ] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} python-muranoclient-1.0.1/doc/source/index.rst0000666000175100017510000000052613231416510021463 0ustar zuulzuul00000000000000================================= python-muranoclient documentation ================================= This is a client for the OpenStack Application Catalog API. There's a Python API (the :mod:`muranoclient` module) and a :doc:`command-line script ` (installed as :program:`murano`). .. toctree:: :maxdepth: 2 cli/index python-muranoclient-1.0.1/doc/source/cli/0000775000175100017510000000000013231417024020365 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/doc/source/cli/index.rst0000666000175100017510000000263613231416510022236 0ustar zuulzuul00000000000000================= Murano API Client ================= In order to use the python api directly, you must first obtain an auth token and identify which endpoint you wish to speak to. Once you have done so, you can use the API like so:: >>> from muranoclient import Client >>> murano = Client('1', endpoint=MURANO_URL, token=OS_AUTH_TOKEN) ... Command-line Tool ================= In order to use the CLI, you must provide your OpenStack username, password, tenant, and auth endpoint. Use the corresponding configuration options (:option:``--os-username``, :option:``--os-password``, :option:``--os-tenant-id``, and :option:``--os-auth-url``) or set them in environment variables:: export OS_USERNAME=user export OS_PASSWORD=pass export OS_TENANT_ID=b363706f891f48019483f8bd6503c54b export OS_AUTH_URL=http://auth.example.com:5000/v2.0 The command line tool will attempt to reauthenticate using your provided credentials for every request. You can override this behavior by manually supplying an auth token using :option:``--os-image-url`` and :option:``--os-auth-token``. You can alternatively set these environment variables:: export MURANO_URL=http://murano.example.org:8082/ export OS_AUTH_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155 Once you've configured your authentication parameters, you can run :command:`murano help` to see a complete listing of available commands. .. toctree:: murano python-muranoclient-1.0.1/doc/source/cli/murano.rst0000666000175100017510000006745513231416510022442 0ustar zuulzuul00000000000000======================================================== Application Catalog service (murano) command-line client ======================================================== The murano client is the command-line interface (CLI) for the Application Catalog service (murano) API and its extensions. This chapter documents :command:`murano` version ``0.13.0``. For help on a specific :command:`murano` command, enter: .. code-block:: console $ murano help COMMAND .. _murano_command_usage: murano usage ~~~~~~~~~~~~ .. code-block:: console usage: murano [--version] [-d] [-v] [--cert-file OS_CERT] [--key-file OS_KEY] [--ca-file OS_CACERT] [--api-timeout API_TIMEOUT] [--os-tenant-id OS_TENANT_ID] [--os-tenant-name OS_TENANT_NAME] [--os-region-name OS_REGION_NAME] [--os-auth-token OS_AUTH_TOKEN] [--os-no-client-auth] [--murano-url MURANO_URL] [--glance-url GLANCE_URL] [--glare-url GLARE_URL] [--murano-api-version MURANO_API_VERSION] [--os-service-type OS_SERVICE_TYPE] [--os-endpoint-type OS_ENDPOINT_TYPE] [--include-password] [--murano-repo-url MURANO_REPO_URL] [--murano-packages-service {murano,glance,glare}] [--insecure] [--os-cacert ] [--os-cert ] [--os-key ] [--timeout ] [--os-auth-url OS_AUTH_URL] [--os-domain-id OS_DOMAIN_ID] [--os-domain-name OS_DOMAIN_NAME] [--os-project-id OS_PROJECT_ID] [--os-project-name OS_PROJECT_NAME] [--os-project-domain-id OS_PROJECT_DOMAIN_ID] [--os-project-domain-name OS_PROJECT_DOMAIN_NAME] [--os-trust-id OS_TRUST_ID] [--os-user-id OS_USER_ID] [--os-username OS_USERNAME] [--os-user-domain-id OS_USER_DOMAIN_ID] [--os-user-domain-name OS_USER_DOMAIN_NAME] [--os-password OS_PASSWORD] ... **Subcommands:** ``app-show`` List applications, added to specified environment. ``bundle-import`` Import a bundle. ``bundle-save`` Save a bundle. ``category-create`` Create a category. ``category-delete`` Delete a category. ``category-list`` List all available categories. ``category-show`` Display category details. ``class-schema`` Display class schema ``deployment-list`` List deployments for an environment or multiple environments. ``env-template-add-app`` Add application to the environment template. ``env-template-clone`` Create a new template, cloned from template. ``env-template-create`` Create an environment template. ``env-template-create-env`` Create a new environment from template. ``env-template-del-app`` Delete application from the environment template. ``env-template-delete`` Delete an environment template. ``env-template-list`` List the environments templates. ``env-template-show`` Display environment template details. ``env-template-update`` Update an environment template. ``environment-action-call`` Call action \`ACTION\` in environment \`ID\`. ``environment-action-get-result`` Get result of \`TASK\` in environment \`ID\`. ``environment-apps-edit`` Edit environment's object model. ``environment-create`` Create an environment. ``environment-delete`` Delete an environment. ``environment-deploy`` Start deployment of a murano environment session. ``environment-list`` List the environments. ``environment-model-edit`` Edit an environment's object model. ``environment-model-show`` Display an environment's object model. ``environment-rename`` Rename an environment. ``environment-session-create`` Creates a new configuration session for environment ID. ``environment-show`` Display environment details. ``package-create`` Create an application package. ``package-delete`` Delete a package. ``package-download`` Download a package to a filename or stdout. ``package-import`` Import a package. ``package-list`` List available packages. ``package-save`` Save a package. ``package-show`` Display details for a package. ``package-update`` Update an existing package. ``static-action-call`` Call static method \`METHOD\` of the class \`CLASS\` with \`ARGUMENTS\`. ``bash-completion`` Prints all of the commands and options to stdout. ``help`` Display help about this program or one of its subcommands. .. _murano_command_options: murano optional arguments ~~~~~~~~~~~~~~~~~~~~~~~~~ ``--version`` Show program's version number and exit. ``-d, --debug`` Defaults to ``env[MURANOCLIENT_DEBUG]``. ``-v, --verbose`` Print more verbose output. ``--cert-file OS_CERT`` **DEPRECATED!** Use --os-cert. ``--key-file OS_KEY`` **DEPRECATED!** Use --os-key. ``--ca-file OS_CACERT`` **DEPRECATED!** Use --os-cacert. ``--api-timeout API_TIMEOUT`` Number of seconds to wait for an API response, defaults to system socket timeout. ``--os-tenant-id OS_TENANT_ID`` Defaults to ``env[OS_TENANT_ID]``. ``--os-tenant-name OS_TENANT_NAME`` Defaults to ``env[OS_TENANT_NAME]``. ``--os-region-name OS_REGION_NAME`` Defaults to ``env[OS_REGION_NAME]``. ``--os-auth-token OS_AUTH_TOKEN`` Defaults to ``env[OS_AUTH_TOKEN]``. ``--os-no-client-auth`` Do not contact keystone for a token. Defaults to ``env[OS_NO_CLIENT_AUTH]``. ``--murano-url MURANO_URL`` Defaults to ``env[MURANO_URL]``. ``--glance-url GLANCE_URL`` Defaults to ``env[GLANCE_URL]``. ``--glare-url GLARE_URL`` Defaults to ``env[GLARE_URL]``. ``--murano-api-version MURANO_API_VERSION`` Defaults to ``env[MURANO_API_VERSION]`` or 1. ``--os-service-type OS_SERVICE_TYPE`` Defaults to ``env[OS_SERVICE_TYPE]``. ``--os-endpoint-type OS_ENDPOINT_TYPE`` Defaults to ``env[OS_ENDPOINT_TYPE]``. ``--include-password`` Send os-username and os-password to murano. ``--murano-repo-url MURANO_REPO_URL`` Defaults to ``env[MURANO_REPO_URL]`` or http://apps.openstack.org/api/v1/murano_repo/liberty/ ``--murano-packages-service {murano,glance,glare}`` Specifies if murano-api ("murano") or Glance Artifact Repository ("glare") should be used to store murano packages. Defaults to ``env[MURANO_PACKAGES_SERVICE]`` or to "murano" ``--insecure`` Explicitly allow client to perform "insecure" TLS (https) requests. The server's certificate will not be verified against any certificate authorities. This option should be used with caution. ``--os-cacert `` Specify a CA bundle file to use in verifying a TLS (https) server certificate. Defaults to ``env[OS_CACERT]``. ``--os-cert `` Defaults to ``env[OS_CERT]``. ``--os-key `` Defaults to ``env[OS_KEY]``. ``--timeout `` Set request timeout (in seconds). ``--os-auth-url OS_AUTH_URL`` Authentication URL ``--os-domain-id OS_DOMAIN_ID`` Domain ID to scope to ``--os-domain-name OS_DOMAIN_NAME`` Domain name to scope to ``--os-project-id OS_PROJECT_ID`` Project ID to scope to ``--os-project-name OS_PROJECT_NAME`` Project name to scope to ``--os-project-domain-id OS_PROJECT_DOMAIN_ID`` Domain ID containing project ``--os-project-domain-name OS_PROJECT_DOMAIN_NAME`` Domain name containing project ``--os-trust-id OS_TRUST_ID`` Trust ID ``--os-user-id OS_USER_ID`` User ID ``--os-username OS_USERNAME, --os-user-name OS_USERNAME, --os-user_name OS_USERNAME`` Username ``--os-user-domain-id OS_USER_DOMAIN_ID`` User's domain id ``--os-user-domain-name OS_USER_DOMAIN_NAME`` User's domain name ``--os-password OS_PASSWORD`` User's password .. _murano_app-show: murano app-show --------------- .. code-block:: console usage: murano app-show [-p ] List applications, added to specified environment. **Positional arguments:** ```` Environment ID to show applications from. **Optional arguments:** ``-p , --path `` Level of detalization to show. Leave empty to browse all applications in the environment. .. _murano_bundle-import: murano bundle-import -------------------- .. code-block:: console usage: murano bundle-import [--is-public] [--exists-action {a,s,u}] [ ...] Import a bundle. \`FILE\` can be either a path to a zip file, URL, or name from repo. If \`FILE\` is a local file, treat names of packages in a bundle as file names, relative to location of the bundle file. Requirements are first searched in the same directory. **Positional arguments:** ```` Bundle URL, bundle name, or path to the bundle file. **Optional arguments:** ``--is-public`` Make packages available to users from other tenants. ``--exists-action {a,s,u}`` Default action when a package already exists. .. _murano_bundle-save: murano bundle-save ------------------ .. code-block:: console usage: murano bundle-save [-p ] [--no-images] Save a bundle. This will download a bundle of packages with all dependencies to specified path. If path doesn't exist it will be created. **Positional arguments:** ```` Bundle URL, bundle name, or path to the bundle file. **Optional arguments:** ``-p , --path `` Path to the directory to store packages. If not set will use current directory. ``--no-images`` If set will skip images downloading. .. _murano_category-create: murano category-create ---------------------- .. code-block:: console usage: murano category-create Create a category. **Positional arguments:** ```` Category name. .. _murano_category-delete: murano category-delete ---------------------- .. code-block:: console usage: murano category-delete [ ...] Delete a category. **Positional arguments:** ```` ID of a category(ies) to delete. .. _murano_category-list: murano category-list -------------------- .. code-block:: console usage: murano category-list List all available categories. .. _murano_category-show: murano category-show -------------------- .. code-block:: console usage: murano category-show Display category details. **Positional arguments:** ```` ID of a category(s) to show. .. _murano_class-schema: murano class-schema ------------------- .. code-block:: console usage: murano class-schema [--package-name PACKAGE_NAME] [--class-version CLASS_VERSION] [ [ ...]] Display class schema **Positional arguments:** ```` Class FQN ```` Method name **Optional arguments:** ``--package-name PACKAGE_NAME`` FQN of the package where the class is located ``--class-version CLASS_VERSION`` Class version or version range (version spec) .. _murano_deployment-list: murano deployment-list ---------------------- .. code-block:: console usage: murano deployment-list [--all-environments] [] List deployments for an environment or multiple environments. **Positional arguments:** ```` Environment ID for which to list deployments. **Optional arguments:** ``--all-environments`` Lists all deployments for all environments in user's tenant. .. _murano_env-template-add-app: murano env-template-add-app --------------------------- .. code-block:: console usage: murano env-template-add-app Add application to the environment template. **Positional arguments:** ```` Environment template ID. ```` Path to the template. .. _murano_env-template-clone: murano env-template-clone ------------------------- .. code-block:: console usage: murano env-template-clone Create a new template, cloned from template. **Positional arguments:** ```` Environment template ID. ```` New environment template name. .. _murano_env-template-create: murano env-template-create -------------------------- .. code-block:: console usage: murano env-template-create [--is-public] Create an environment template. **Positional arguments:** ```` Environment template name. **Optional arguments:** ``--is-public`` Make the template available for users from other tenants. .. _murano_env-template-create-env: murano env-template-create-env ------------------------------ .. code-block:: console usage: murano env-template-create-env [--region ] Create a new environment from template. **Positional arguments:** ```` Environment template ID. ```` New environment name. **Optional arguments:** ``--region `` Name of the target OpenStack region. .. _murano_env-template-del-app: murano env-template-del-app --------------------------- .. code-block:: console usage: murano env-template-del-app Delete application from the environment template. **Positional arguments:** ```` Environment template ID. ```` Application ID. .. _murano_env-template-delete: murano env-template-delete -------------------------- .. code-block:: console usage: murano env-template-delete [ ...] Delete an environment template. **Positional arguments:** ```` ID of environment(s) template to delete. .. _murano_env-template-list: murano env-template-list ------------------------ .. code-block:: console usage: murano env-template-list List the environments templates. .. _murano_env-template-show: murano env-template-show ------------------------ .. code-block:: console usage: murano env-template-show Display environment template details. **Positional arguments:** ```` Environment template ID. .. _murano_env-template-update: murano env-template-update -------------------------- .. code-block:: console usage: murano env-template-update Update an environment template. **Positional arguments:** ```` Environment template ID. ```` Environment template name. .. _murano_environment-action-call: murano environment-action-call ------------------------------ .. code-block:: console usage: murano environment-action-call --action-id [--arguments [ [ ...]]] id Call action \`ACTION\` in environment \`ID\`. Returns id of an asynchronous task, that executes the action. Actions can only be called on a \`deployed\` environment. To view actions available in a given environment use \`environment-show\` command. **Positional arguments:** ``id`` ID of Environment to call action against. **Optional arguments:** ``--action-id `` ID of action to run. ``--arguments [ [ ...]]`` Action arguments. .. _murano_environment-action-get-result: murano environment-action-get-result ------------------------------------ .. code-block:: console usage: murano environment-action-get-result --task-id Get result of \`TASK\` in environment \`ID\`. **Positional arguments:** ```` ID of Environment where task is being executed. **Optional arguments:** ``--task-id `` ID of action to run. .. _murano_environment-apps-edit: murano environment-apps-edit ---------------------------- .. code-block:: console usage: murano environment-apps-edit --session-id [FILE] Edit environment's object model. \`FILE\` is path to a file, that contains jsonpatch, that describes changes to be made to environment's object-model. [ { "op": "add", "path": "/-", "value": { ... your-app object model here ... } }, { "op": "replace", "path": "/0/?/name", "value": "new_name" }, ] NOTE: Values '===id1===', '===id2===', etc. in the resulting object-model will be substituted with uuids. For more info on jsonpatch see RFC 6902 **Positional arguments:** ```` ID of Environment to edit. ``FILE`` File to read jsonpatch from (defaults to stdin). **Optional arguments:** ``--session-id `` Id of a config session. .. _murano_environment-create: murano environment-create ------------------------- .. code-block:: console usage: murano environment-create [--join-net-id ] [--join-subnet-id ] [--region ] Create an environment. **Positional arguments:** ```` Environment name. **Optional arguments:** ``--join-net-id `` Network id to join. ``--join-subnet-id `` Subnetwork id to join. ``--region `` Name of the target OpenStack region. .. _murano_environment-delete: murano environment-delete ------------------------- .. code-block:: console usage: murano environment-delete [--abandon] [ ...] Delete an environment. **Positional arguments:** ```` Id or name of environment(s) to delete. **Optional arguments:** ``--abandon`` If set will abandon environment without deleting any of its resources. .. _murano_environment-deploy: murano environment-deploy ------------------------- .. code-block:: console usage: murano environment-deploy --session-id Start deployment of a murano environment session. **Positional arguments:** ```` ID of Environment to deploy. **Optional arguments:** ``--session-id `` ID of configuration session to deploy. .. _murano_environment-list: murano environment-list ----------------------- .. code-block:: console usage: murano environment-list [--all-tenants] [--tenant ] List the environments. **Optional arguments:** ``--all-tenants`` Allows to list environments from all tenants (admin only). ``--tenant `` Allows to list environments for a given tenant (admin only). .. _murano_environment-model-edit: murano environment-model-edit ----------------------------- .. code-block:: console usage: murano environment-model-edit --session-id [] Edit an environment's object model. **Positional arguments:** ```` ID of Environment to edit. ```` File to read JSON-patch from (defaults to stdin). **Optional arguments:** ``--session-id `` Id of a config session. .. _murano_environment-model-show: murano environment-model-show ----------------------------- .. code-block:: console usage: murano environment-model-show [--path ] [--session-id ] Display an environment's object model. **Positional arguments:** ```` ID of Environment to show. **Optional arguments:** ``--path `` Path to Environment model section. Defaults to '/'. ``--session-id `` Id of a config session. .. _murano_environment-rename: murano environment-rename ------------------------- .. code-block:: console usage: murano environment-rename Rename an environment. **Positional arguments:** ```` Environment ID or name. ```` A name to which the environment will be renamed. .. _murano_environment-session-create: murano environment-session-create --------------------------------- .. code-block:: console usage: murano environment-session-create Creates a new configuration session for environment ID. **Positional arguments:** ```` ID of Environment to add session to. .. _murano_environment-show: murano environment-show ----------------------- .. code-block:: console usage: murano environment-show [--session-id ] [--only-apps] Display environment details. **Positional arguments:** ```` Environment ID or name. **Optional arguments:** ``--session-id `` Id of a config session. ``--only-apps`` Only print apps of the environment (useful for automation). .. _murano_package-create: murano package-create --------------------- .. code-block:: console usage: murano package-create [-t ] [-c ] [-r ] [-n ] [-f ] [-a ] [--tags [ [ ...]]] [-d ] [-o ] [-u ] [--type TYPE] [-l ] Create an application package. **Optional arguments:** ``-t , --template `` Path to the Heat template to import as an Application Definition. ``-c , --classes-dir `` Path to the directory containing application classes. ``-r , --resources-dir `` Path to the directory containing application resources. ``-n , --name `` Display name of the Application in Catalog. ``-f , --full-name `` Fully-qualified name of the Application in Catalog. ``-a , --author `` Name of the publisher. ``--tags [ [ ...]]`` A list of keywords connected to the application. ``-d , --description `` Detailed description for the Application in Catalog. ``-o , --output `` The name of the output file archive to save locally. ``-u , --ui `` Dynamic UI form definition. ``--type TYPE`` Package type. Possible values: Application or Library. ``-l , --logo `` Path to the package logo. .. _murano_package-delete: murano package-delete --------------------- .. code-block:: console usage: murano package-delete [ ...] Delete a package. **Positional arguments:** ```` Package ID to delete. .. _murano_package-download: murano package-download ----------------------- .. code-block:: console usage: murano package-download [file] Download a package to a filename or stdout. **Positional arguments:** ```` Package ID to download. ``file`` Filename to save package to. If it is not specified and there is no stdout redirection the package won't be saved. .. _murano_package-import: murano package-import --------------------- .. code-block:: console usage: murano package-import [-c [ [ ...]]] [--is-public] [--package-version PACKAGE_VERSION] [--exists-action {a,s,u}] [--dep-exists-action {a,s,u}] [ ...] Import a package. \`FILE\` can be either a path to a zip file, url or a FQPN. You can use \`--\` to separate \`FILE\`s from other arguments. Categories have to be separated with a space and have to be already present in murano. **Positional arguments:** ```` URL of the murano zip package, FQPN, path to zip package or path to directory with package. **Optional arguments:** ``-c [ [ ...]], --categories [ [ ...]]`` Category list to attach. ``--is-public`` Make the package available for users from other tenants. ``--package-version PACKAGE_VERSION`` Version of the package to use from repository (ignored when importing with multiple packages). ``--exists-action {a,s,u}`` Default action when a package already exists: (s)kip, (u)pdate, (a)bort. ``--dep-exists-action {a,s,u}`` Default action when a dependency package already exists: (s)kip, (u)pdate, (a)bort. .. _murano_package-list: murano package-list ------------------- .. code-block:: console usage: murano package-list [--limit LIMIT] [--marker MARKER] [--include-disabled] [--owned] [--search ] [--name ] [--fqn ] [--type ] [--category ] [--class_name ] [--tag ] List available packages. **Optional arguments:** ``--limit LIMIT`` Show limited number of packages ``--marker MARKER`` Show packages starting from package with id excluding it ``--include-disabled`` ``--owned`` ``--search `` Show packages, that match search keys fuzzily ``--name `` Show packages, whose name match parameter exactly ``--fqn `` Show packages, whose fully qualified name match parameter exactly ``--type `` Show packages, whose type match parameter exactly ``--category `` Show packages, whose categories include parameter ``--class_name `` Show packages, whose class name match parameter exactly ``--tag `` Show packages, whose tags include parameter .. _murano_package-save: murano package-save ------------------- .. code-block:: console usage: murano package-save [-p ] [--package-version PACKAGE_VERSION] [--no-images] [ ...] Save a package. This will download package(s) with all dependencies to specified path. If path doesn't exist it will be created. **Positional arguments:** ```` Package URL or name. **Optional arguments:** ``-p , --path `` Path to the directory to store package. If not set will use current directory. ``--package-version PACKAGE_VERSION`` Version of the package to use from repository (ignored when saving with multiple packages). ``--no-images`` If set will skip images downloading. .. _murano_package-show: murano package-show ------------------- .. code-block:: console usage: murano package-show Display details for a package. **Positional arguments:** ```` Package ID to show. .. _murano_package-update: murano package-update --------------------- .. code-block:: console usage: murano package-update [--is-public {true|false}] [--enabled {true|false}] [--name NAME] [--description DESCRIPTION] [--tags [ [ ...]]] Update an existing package. **Positional arguments:** ```` Package ID to update. **Optional arguments:** ``--is-public {true|false}`` Make package available to users from other tenants. ``--enabled {true|false}`` Make package active and available for deployments. ``--name NAME`` New name for the package. ``--description DESCRIPTION`` New package description. ``--tags [ [ ...]]`` A list of keywords connected to the application. .. _murano_static-action-call: murano static-action-call ------------------------- .. code-block:: console usage: murano static-action-call [--arguments [ [ ...]]] [--package-name ] [--class-version CLASS_VERSION] Call static method \`METHOD\` of the class \`CLASS\` with \`ARGUMENTS\`. Returns the result of the method execution. \`PACKAGE\` and \`CLASS_VERSION\` can be specified optionally to find class in a particular package and to look for the specific version of a class respectively. **Positional arguments:** ```` FQN of the class with static method ```` Static method to run **Optional arguments:** ``--arguments [ [ ...]]`` Method arguments. No arguments by default ``--package-name `` Optional FQN of the package to look for the class in ``--class-version CLASS_VERSION`` Optional version of the class, otherwise version =0 is used python-muranoclient-1.0.1/setup-centos.sh0000666000175100017510000001241113231416510020536 0ustar zuulzuul00000000000000#!/bin/sh # Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # # CentOS script. LOGLVL=1 SERVICE_CONTENT_DIRECTORY=`cd $(dirname "$0") && pwd` PREREQ_PKGS="wget make git python-pip python-devel" PIPAPPS="pip python-pip pip-python" PIPCMD="" SERVICE_SRV_NAME="python-muranoclient" GIT_CLONE_DIR=`echo $SERVICE_CONTENT_DIRECTORY | sed -e "s/$SERVICE_SRV_NAME//"` # Functions # Loger function log() { MSG=$1 if [ $LOGLVL -gt 0 ]; then echo "LOG:> $MSG" fi } # Check or install package in_sys_pkg() { PKG=$1 rpm -q $PKG > /dev/null 2>&1 if [ $? -eq 0 ]; then log "Package \"$PKG\" already installed" else log "Installing \"$PKG\"..." yum install $PKG --assumeyes > /dev/null 2>&1 if [ $? -ne 0 ];then log "installation fails, exiting!!!" exit fi fi } # find pip find_pip() { for cmd in $PIPAPPS do _cmd=$(which $cmd 2>/dev/null) if [ $? -eq 0 ];then break fi done if [ -z $_cmd ];then echo "Can't find \"pip\" in system, please install it first, exiting!" exit 1 else PIPCMD=$_cmd fi } # git clone gitclone() { FROM=$1 CLONEROOT=$2 log "Cloning from \"$FROM\" repo to \"$CLONEROOT\"" cd $CLONEROOT && git clone $FROM > /dev/null 2>&1 if [ $? -ne 0 ];then log "cloning from \"$FROM\" fails, exiting!!!" exit fi } # install inst() { CLONE_FROM_GIT=$1 # Checking packages for PKG in $PREREQ_PKGS do in_sys_pkg $PKG done # Find python pip find_pip # If clone from git set if [ ! -z $CLONE_FROM_GIT ]; then # Preparing clone root directory if [ ! -d $GIT_CLONE_DIR ];then log "Creating $GIT_CLONE_DIR directory..." mkdir -p $GIT_CLONE_DIR if [ $? -ne 0 ];then log "Can't create $GIT_CLONE_DIR, exiting!!!" exit fi fi # Cloning from GIT GIT_WEBPATH_PRFX="https://git.openstack.org/cgit/openstack/" gitclone "$GIT_WEBPATH_PRFX$SERVICE_SRV_NAME.git" $GIT_CLONE_DIR # End clone from git section fi # Setupping... log "Running setup.py" MRN_CND_SPY=$SERVICE_CONTENT_DIRECTORY/setup.py if [ -e $MRN_CND_SPY ]; then chmod +x $MRN_CND_SPY log "$MRN_CND_SPY output:_____________________________________________________________" ## Setup through pip # Creating tarball rm -rf $SERVICE_CONTENT_DIRECTORY/*.egg-info cd $SERVICE_CONTENT_DIRECTORY && python $MRN_CND_SPY egg_info if [ $? -ne 0 ];then log "\"$MRN_CND_SPY\" egg info creation FAILS, exiting!!!" exit 1 fi rm -rf $SERVICE_CONTENT_DIRECTORY/dist/* cd $SERVICE_CONTENT_DIRECTORY && python $MRN_CND_SPY sdist if [ $? -ne 0 ];then log "\"$MRN_CND_SPY\" tarball creation FAILS, exiting!!!" exit 1 fi # Running tarball install TRBL_FILE=$(basename `ls $SERVICE_CONTENT_DIRECTORY/dist/*.tar.gz`) $PIPCMD install $SERVICE_CONTENT_DIRECTORY/dist/$TRBL_FILE if [ $? -ne 0 ];then log "$PIPCMD install \"$TRBL_FILE\" FAILS, exiting!!!" exit 1 fi else log "$MRN_CND_SPY not found!" fi } # uninstall uninst() { # Uninstall trough pip find_pip # looking up for python package installed PYPKG="muranoclient" _pkg=$($PIPCMD freeze | grep $PYPKG) if [ $? -eq 0 ]; then log "Removing package \"$PYPKG\" with pip" $PIPCMD uninstall $_pkg --yes else log "Python package \"$PYPKG\" not found" fi } # Command line args' COMMAND="$1" case $COMMAND in install ) inst ;; installfromgit ) inst "yes" ;; uninstall ) log "Uninstalling muranoclient \"$SERVICE_SRV_NAME\" from system..." uninst ;; * ) echo -e "Usage: $(basename "$0") command \nCommands:\n\tinstall - Install $SERVICE_SRV_NAME software\n\tuninstall - Uninstall $SERVICE_SRV_NAME software" exit 1 ;; esac python-muranoclient-1.0.1/setup.py0000666000175100017510000000200613231416510017262 0ustar zuulzuul00000000000000# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT import setuptools # In python < 2.7.4, a lazy loading of package `pbr` will break # setuptools if some other modules registered functions in `atexit`. # solution from: http://bugs.python.org/issue15881#msg170215 try: import multiprocessing # noqa except ImportError: pass setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) python-muranoclient-1.0.1/python_muranoclient.egg-info/0000775000175100017510000000000013231417024023344 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/python_muranoclient.egg-info/dependency_links.txt0000664000175100017510000000000113231417022027410 0ustar zuulzuul00000000000000 python-muranoclient-1.0.1/python_muranoclient.egg-info/pbr.json0000664000175100017510000000005613231417022025021 0ustar zuulzuul00000000000000{"git_version": "2944800", "is_release": true}python-muranoclient-1.0.1/python_muranoclient.egg-info/PKG-INFO0000664000175100017510000000745213231417022024447 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-muranoclient Version: 1.0.1 Summary: python-muranoclient Home-page: https://docs.openstack.org/murano/latest/ Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/python-muranoclient.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on Murano ====== .. image:: https://img.shields.io/pypi/v/python-muranoclient.svg :target: https://pypi.python.org/pypi/python-muranoclient/ :alt: Latest Version .. image:: https://img.shields.io/pypi/dm/python-muranoclient.svg :target: https://pypi.python.org/pypi/python-muranoclient/ :alt: Downloads Murano Project introduces an application catalog, which allows application developers and cloud administrators to publish various cloud-ready applications in a browsable categorised catalog, which may be used by the cloud users (including the inexperienced ones) to pick-up the needed applications and services and composes the reliable environments out of them in a "push-the-button" manner. * `PyPi`_ - package installation * `Launchpad project`_ - release management * `Blueprints`_ - feature specifications * `Bugs`_ - issue tracking * `Source`_ * `Specs`_ * `How to Contribute`_ .. _PyPi: https://pypi.python.org/pypi/python-muranoclient .. _Launchpad project: https://launchpad.net/python-muranoclient .. _Blueprints: https://blueprints.launchpad.net/python-muranoclient .. _Bugs: https://bugs.launchpad.net/python-muranoclient .. _Source: https://git.openstack.org/cgit/openstack/python-muranoclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html .. _Specs: https://specs.openstack.org/openstack/murano-specs/ Python Muranoclient ------------------- python-muranoclient is a client library for Murano built on the Murano API. It provides a Python API (the ``muranoclient`` module) and a command-line tool (``murano``). Project Resources ----------------- Project status, bugs, and blueprints are tracked on Launchpad: * Client bug tracker * https://launchpad.net/python-muranoclient * Murano bug tracker * https://launchpad.net/murano Developer documentation can be found here: https://docs.openstack.org/murano/latest/ Additional resources are linked from the project wiki page: https://wiki.openstack.org/wiki/Murano License ------- Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Environment :: OpenStack Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 python-muranoclient-1.0.1/python_muranoclient.egg-info/entry_points.txt0000664000175100017510000000337513231417022026650 0ustar zuulzuul00000000000000[console_scripts] murano = muranoclient.shell:main [openstack.application_catalog.v1] bundle_import = muranoclient.osc.v1.package:ImportBundle category_create = muranoclient.osc.v1.category:CreateCategory category_delete = muranoclient.osc.v1.category:DeleteCategory category_list = muranoclient.osc.v1.category:ListCategories category_show = muranoclient.osc.v1.category:ShowCategory class-schema = muranoclient.osc.v1.schema:ShowSchema deployment_list = muranoclient.osc.v1.deployment:ListDeployment environment_apps_edit = muranoclient.osc.v1.environment:EnvironmentAppsEdit environment_create = muranoclient.osc.v1.environment:EnvironmentCreate environment_delete = muranoclient.osc.v1.environment:EnvironmentDelete environment_deploy = muranoclient.osc.v1.environment:EnvironmentDeploy environment_list = muranoclient.osc.v1.environment:ListEnvironments environment_model_edit = muranoclient.osc.v1.environment:EnvironmentModelEdit environment_model_show = muranoclient.osc.v1.environment:EnvironmentModelShow environment_rename = muranoclient.osc.v1.environment:RenameEnvironment environment_session_create = muranoclient.osc.v1.environment:EnvironmentSessionCreate environment_show = muranoclient.osc.v1.environment:ShowEnvironment package_create = muranoclient.osc.v1.package:CreatePackage package_delete = muranoclient.osc.v1.package:DeletePackage package_download = muranoclient.osc.v1.package:DownloadPackage package_import = muranoclient.osc.v1.package:ImportPackage package_list = muranoclient.osc.v1.package:ListPackages package_show = muranoclient.osc.v1.package:ShowPackage package_update = muranoclient.osc.v1.package:UpdatePackage static-action_call = muranoclient.osc.v1.action:StaticActionCall [openstack.cli.extension] application_catalog = muranoclient.osc.plugin python-muranoclient-1.0.1/python_muranoclient.egg-info/not-zip-safe0000664000175100017510000000000113231416776025607 0ustar zuulzuul00000000000000 python-muranoclient-1.0.1/python_muranoclient.egg-info/requires.txt0000664000175100017510000000052113231417022025740 0ustar zuulzuul00000000000000pbr!=2.1.0,>=2.0.0 PrettyTable<0.8,>=0.7.1 python-glanceclient>=2.8.0 python-keystoneclient>=3.8.0 iso8601>=0.1.11 six>=1.10.0 Babel!=2.4.0,>=2.3.4 pyOpenSSL>=16.2.0 requests>=2.14.2 PyYAML>=3.10 yaql>=1.1.3 osc-lib>=1.8.0 murano-pkg-check>=0.3.0 oslo.serialization!=2.19.1,>=2.18.0 oslo.utils>=3.33.0 oslo.log>=3.36.0 oslo.i18n>=3.15.3 python-muranoclient-1.0.1/python_muranoclient.egg-info/SOURCES.txt0000664000175100017510000001611113231417024025230 0ustar zuulzuul00000000000000.coveragerc .testr.conf AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE README.rst babel.cfg requirements.txt run_tests.sh setup-centos.sh setup.cfg setup.py setup.sh test-requirements.txt tox.ini doc/source/conf.py doc/source/index.rst doc/source/cli/index.rst doc/source/cli/murano.rst muranoclient/__init__.py muranoclient/client.py muranoclient/i18n.py muranoclient/shell.py muranoclient/version.py muranoclient/apiclient/__init__.py muranoclient/apiclient/auth.py muranoclient/apiclient/base.py muranoclient/apiclient/client.py muranoclient/apiclient/exceptions.py muranoclient/apiclient/fake_client.py muranoclient/common/__init__.py muranoclient/common/base.py muranoclient/common/exceptions.py muranoclient/common/http.py muranoclient/common/utils.py muranoclient/common/yaqlexpression.py muranoclient/common/yaqlexpression_legacy.py muranoclient/data/heat_logo.png muranoclient/data/mpl_logo.png muranoclient/glance/__init__.py muranoclient/glance/artifacts.py muranoclient/glance/client.py muranoclient/locale/en_GB/LC_MESSAGES/muranoclient.po muranoclient/osc/__init__.py muranoclient/osc/plugin.py muranoclient/osc/v1/__init__.py muranoclient/osc/v1/action.py muranoclient/osc/v1/category.py muranoclient/osc/v1/deployment.py muranoclient/osc/v1/environment.py muranoclient/osc/v1/package.py muranoclient/osc/v1/schema.py muranoclient/tests/__init__.py muranoclient/tests/functional/__init__.py muranoclient/tests/functional/muranoclient.py muranoclient/tests/functional/cli/__init__.py muranoclient/tests/functional/cli/murano_test_utils.py muranoclient/tests/functional/cli/test_murano.py muranoclient/tests/functional/cli/utils.py muranoclient/tests/functional/cli/MockApp/Classes/mock_muranopl.yaml muranoclient/tests/functional/hooks/post_test_hook.sh muranoclient/tests/unit/__init__.py muranoclient/tests/unit/base.py muranoclient/tests/unit/fakes.py muranoclient/tests/unit/test_base.py muranoclient/tests/unit/test_common_http.py muranoclient/tests/unit/test_exc.py muranoclient/tests/unit/test_methods.py muranoclient/tests/unit/test_package_creator.py muranoclient/tests/unit/test_shell.py muranoclient/tests/unit/test_utils.py muranoclient/tests/unit/fixture_data/heat-template.yaml muranoclient/tests/unit/fixture_data/logo.png muranoclient/tests/unit/fixture_data/empty-app/manifest.yaml muranoclient/tests/unit/fixture_data/test-app/ui.yaml muranoclient/tests/unit/fixture_data/test-app/Classes/testapp.yaml muranoclient/tests/unit/fixture_data/test-app/Resources/Deploy.template muranoclient/tests/unit/fixture_data/test-app/Resources/scripts/common.sh muranoclient/tests/unit/fixture_data/test-app/Resources/scripts/deploy.sh muranoclient/tests/unit/fixture_data/test-app/Resources/scripts/installer.sh muranoclient/tests/unit/osc/__init__.py muranoclient/tests/unit/osc/test_plugin.py muranoclient/tests/unit/osc/v1/__init__.py muranoclient/tests/unit/osc/v1/fakes.py muranoclient/tests/unit/osc/v1/test_action.py muranoclient/tests/unit/osc/v1/test_category.py muranoclient/tests/unit/osc/v1/test_deployment.py muranoclient/tests/unit/osc/v1/test_environment.py muranoclient/tests/unit/osc/v1/test_package.py muranoclient/tests/unit/osc/v1/test_schema.py muranoclient/tests/unit/osc/v1/fixture_data/heat-template.yaml muranoclient/tests/unit/osc/v1/fixture_data/logo.png muranoclient/tests/unit/osc/v1/fixture_data/test-app/ui.yaml muranoclient/tests/unit/osc/v1/fixture_data/test-app/Classes/testapp.yaml muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/Deploy.template muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/common.sh muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/deploy.sh muranoclient/tests/unit/osc/v1/fixture_data/test-app/Resources/scripts/installer.sh muranoclient/v1/__init__.py muranoclient/v1/actions.py muranoclient/v1/artifact_packages.py muranoclient/v1/categories.py muranoclient/v1/client.py muranoclient/v1/deployments.py muranoclient/v1/environments.py muranoclient/v1/instance_statistics.py muranoclient/v1/packages.py muranoclient/v1/request_statistics.py muranoclient/v1/schemas.py muranoclient/v1/services.py muranoclient/v1/sessions.py muranoclient/v1/shell.py muranoclient/v1/static_actions.py muranoclient/v1/templates.py muranoclient/v1/package_creator/__init__.py muranoclient/v1/package_creator/hot_package.py muranoclient/v1/package_creator/mpl_package.py python_muranoclient.egg-info/PKG-INFO python_muranoclient.egg-info/SOURCES.txt python_muranoclient.egg-info/dependency_links.txt python_muranoclient.egg-info/entry_points.txt python_muranoclient.egg-info/not-zip-safe python_muranoclient.egg-info/pbr.json python_muranoclient.egg-info/requires.txt python_muranoclient.egg-info/top_level.txt releasenotes/notes/.placeholder releasenotes/notes/action-arguments-06a554f76783f3ed.yaml releasenotes/notes/add-environment-support-to-OSC-173b86ec631283b7.yaml releasenotes/notes/added-category-command-01cb9dab21ab4a7b.yaml releasenotes/notes/added-environment-command-85b31973e101fd1f.yaml releasenotes/notes/added-schemas-support-e4a6e44c7bac2751.yaml releasenotes/notes/added-static-actions-3d45f5cdc5491770.yaml releasenotes/notes/bug-1527045-97993f04757b4901.yaml releasenotes/notes/bug-1536121-51c42f77a9e97db1.yaml releasenotes/notes/bug-1629221-e7f1766eb9878f23.yaml releasenotes/notes/dep-exists-action-9af18bebcc0ef053.yaml releasenotes/notes/deprecate-murano-packages-service-glance-7d0052a5256adace.yaml releasenotes/notes/enable-openstack-client-support-a273e33d6c31e36e.yaml releasenotes/notes/environment-edit-7faf5c8e8a3d44ac.yaml releasenotes/notes/fix-owned-flag-e8b718c074c1c314.yaml releasenotes/notes/glare-endpoint-cdba1b2351c19592.yaml releasenotes/notes/global-inherits-fix-6da007ec44a774f2.yaml releasenotes/notes/import-package-from-directory-8f2b5e393004ef97.yaml releasenotes/notes/improved-cli-outputs-a3e75cf0224a1993.yaml releasenotes/notes/list-environments-of-a-given-project-e407dd5271649ad2.yaml releasenotes/notes/multi-class-yamls-support-914b3d155324214f.yaml releasenotes/notes/multiple-packages-glare-fix-b82a473ad976028f.yaml releasenotes/notes/osc-murano-url-507932234b49cf9f.yaml releasenotes/notes/osc-package-list-command-23e39dc92ead8834.yaml releasenotes/notes/reauth-fix-e03ad966c3178167.yaml releasenotes/notes/repair-package-update-command-72e4c85da1b2c897.yaml releasenotes/notes/requirements-order-19ecc40ca6d34739.yaml releasenotes/notes/resources-dir-for-hot-c557c1472bbc79fa.yaml releasenotes/notes/safeloader-cve-2016-4972-e3f7ad9b234655ca.yaml releasenotes/notes/support-endpoint-type-d7c6b32098b67eeb.yaml releasenotes/notes/yamlloader-glare-d7d0506f6711b650.yaml releasenotes/source/conf.py releasenotes/source/index.rst releasenotes/source/liberty.rst releasenotes/source/mitaka.rst releasenotes/source/newton.rst releasenotes/source/ocata.rst releasenotes/source/pike.rst releasenotes/source/unreleased.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po tools/cover.sh tools/install_venv.py tools/install_venv_common.py tools/murano.bash_completion tools/pretty_tox.sh tools/with_venv.shpython-muranoclient-1.0.1/python_muranoclient.egg-info/top_level.txt0000664000175100017510000000001513231417022026070 0ustar zuulzuul00000000000000muranoclient python-muranoclient-1.0.1/tools/0000775000175100017510000000000013231417024016711 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/tools/install_venv_common.py0000666000175100017510000001631513231416510023346 0ustar zuulzuul00000000000000# Copyright 2013 OpenStack, LLC # Copyright 2013 IBM Corp. # # 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. """Provides methods needed by installation script for OpenStack development virtual environments. Synced in from openstack-common """ from __future__ import print_function import argparse import os import subprocess import sys class InstallVenv(object): def __init__(self, root, venv, requirements, test_requirements, py_version, project): self.root = root self.venv = venv self.requirements = requirements self.test_requirements = test_requirements self.py_version = py_version self.project = project def die(self, message, *args): print(message % args, file=sys.stderr) sys.exit(1) def check_python_version(self): if sys.version_info < (2, 6): self.die("Need Python Version >= 2.6") def run_command_with_code(self, cmd, redirect_output=True, check_exit_code=True): """Runs a command in an out-of-process shell. Returns the output of that command. Working directory is self.root. """ if redirect_output: stdout = subprocess.PIPE else: stdout = None proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout) output = proc.communicate()[0] if check_exit_code and proc.returncode != 0: self.die('Command "%s" failed.\n%s', ' '.join(cmd), output) return (output, proc.returncode) def run_command(self, cmd, redirect_output=True, check_exit_code=True): return self.run_command_with_code(cmd, redirect_output, check_exit_code)[0] def get_distro(self): if (os.path.exists('/etc/fedora-release') or os.path.exists('/etc/redhat-release')): return Fedora( self.root, self.venv, self.requirements, self.test_requirements, self.py_version, self.project) else: return Distro( self.root, self.venv, self.requirements, self.test_requirements, self.py_version, self.project) def check_dependencies(self): self.get_distro().install_virtualenv() def create_virtualenv(self, no_site_packages=True): """Creates the virtual environment and installs PIP. Creates the virtual environment and installs PIP only into the virtual environment. """ if not os.path.isdir(self.venv): print('Creating venv...'), if no_site_packages: self.run_command(['virtualenv', '-q', '--no-site-packages', self.venv]) else: self.run_command(['virtualenv', '-q', self.venv]) print('done.') else: print("venv already exists...") pass def pip_install(self, *args): self.run_command(['tools/with_venv.sh', 'pip', 'install', '--upgrade'] + list(args), redirect_output=False) def install_dependencies(self): print('Installing dependencies with pip (this can take a while)...') # First things first, make sure our venv has the latest pip and # distribute. # NOTE: we keep pip at version 1.1 since the most recent version causes # the .venv creation to fail. See: # https://bugs.launchpad.net/nova/+bug/1047120 self.pip_install('pip==1.1') self.pip_install('setuptools') self.pip_install('-r', self.requirements) self.pip_install('-r', self.test_requirements) def post_process(self): self.get_distro().post_process() def parse_args(self, argv): """Parses command-line arguments.""" parser = argparse.ArgumentParser() parser.add_argument('-n', '--no-site-packages', action='store_true', help="Do not inherit packages from global Python " "install") return parser.parse_args(argv[1:]) class Distro(InstallVenv): def check_cmd(self, cmd): return bool(self.run_command(['which', cmd], check_exit_code=False).strip()) def install_virtualenv(self): if self.check_cmd('virtualenv'): return if self.check_cmd('easy_install'): print('Installing virtualenv via easy_install...'), if self.run_command(['easy_install', 'virtualenv']): print('Succeeded') return else: print('Failed') self.die('ERROR: virtualenv not found.\n\n%s development' ' requires virtualenv, please install it using your' ' favorite package management tool' % self.project) def post_process(self): """Any distribution-specific post-processing gets done here. In particular, this is useful for applying patches to code inside the venv. """ pass class Fedora(Distro): """This covers all Fedora-based distributions. Includes: Fedora, RHEL, CentOS, Scientific Linux """ def check_pkg(self, pkg): return self.run_command_with_code(['rpm', '-q', pkg], check_exit_code=False)[1] == 0 def yum_install(self, pkg, **kwargs): print("Attempting to install '%s' via yum" % pkg) self.run_command(['sudo', 'yum', 'install', '-y', pkg], **kwargs) def apply_patch(self, originalfile, patchfile): self.run_command(['patch', originalfile, patchfile]) def install_virtualenv(self): if self.check_cmd('virtualenv'): return if not self.check_pkg('python-virtualenv'): self.yum_install('python-virtualenv', check_exit_code=False) super(Fedora, self).install_virtualenv() def post_process(self): """Workaround for a bug in eventlet. This currently affects RHEL6.1, but the fix can safely be applied to all RHEL and Fedora distributions. This can be removed when the fix is applied upstream. Nova: https://bugs.launchpad.net/nova/+bug/884915 Upstream: https://bitbucket.org/which_linden/eventlet/issue/89 """ # Install "patch" program if it's not there if not self.check_pkg('patch'): self.yum_install('patch') # Apply the eventlet patch self.apply_patch(os.path.join(self.venv, 'lib', self.py_version, 'site-packages', 'eventlet/green/subprocess.py'), 'contrib/redhat-eventlet.patch') python-muranoclient-1.0.1/tools/cover.sh0000777000175100017510000000534013231416510020371 0ustar zuulzuul00000000000000#!/bin/bash # # Copyright 2016: Mirantis Inc. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. ALLOWED_EXTRA_MISSING=4 show_diff () { head -1 $1 diff -U 0 $1 $2 | sed 1,2d } # Stash uncommitted changes, checkout master and save coverage report uncommitted=$(git status --porcelain | grep -v "^??") [[ -n $uncommitted ]] && git stash > /dev/null git checkout HEAD^ baseline_report=$(mktemp -t muranoclient_coverageXXXXXXX) find . -type f -name "*.pyc" -delete && python setup.py testr --coverage --testr-args="$*" coverage report > $baseline_report baseline_missing=$(awk 'END { print $3 }' $baseline_report) # Checkout back and unstash uncommitted changes (if any) git checkout - [[ -n $uncommitted ]] && git stash pop > /dev/null # Generate and save coverage report current_report=$(mktemp -t muranoclient_coverageXXXXXXX) find . -type f -name "*.pyc" -delete && python setup.py testr --coverage --testr-args="$*" coverage report > $current_report current_missing=$(awk 'END { print $3 }' $current_report) baseline_percentage=$(awk 'END { print $4 }' $baseline_report) current_percentage=$(awk 'END { print $4 }' $current_report) # Show coverage details allowed_missing=$((baseline_missing+ALLOWED_EXTRA_MISSING)) echo "Baseline report:" echo "$(cat ${baseline_report})" echo "Proposed change report:" echo "$(cat ${current_report})" echo "" echo "" echo "Allowed to introduce missing lines : ${ALLOWED_EXTRA_MISSING}" echo "Missing lines in master : ${baseline_missing}" echo "Missing lines in proposed change : ${current_missing}" echo "Current percentage : ${baseline_percentage}" echo "Proposed change percentage : ${current_percentage}" if [ $allowed_missing -gt $current_missing ]; then if [ $baseline_missing -lt $current_missing ]; then show_diff $baseline_report $current_report echo "I believe you can cover all your code with 100% coverage!" else echo "Thank you! You are awesome! Keep writing unit tests! :)" fi exit_code=0 else show_diff $baseline_report $current_report echo "Please write more unit tests, we should keep our test coverage :( " exit_code=1 fi rm $baseline_report $current_report exit $exit_codepython-muranoclient-1.0.1/tools/murano.bash_completion0000666000175100017510000000155113231416510023305 0ustar zuulzuul00000000000000_murano_opts="" # lazy init _murano_flags="" # lazy init _murano_opts_exp="" # lazy init _murano() { local cur prev kbc COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" if [ "x$_murano_opts" == "x" ] ; then kbc="$(murano bash-completion | sed -e "s/ -h / /")" _murano_opts="$(echo "$kbc" | sed -e "s/--[a-z0-9_-]*//g" -e "s/[ ][ ]*/ /g")" _murano_flags="$(echo " $kbc" | sed -e "s/ [^-][^-][a-z0-9_-]*//g" -e "s/[ ][ ]*/ /g")" _murano_opts_exp="$(echo "$_murano_opts" | sed -e "s/[ ]/|/g")" fi if [[ " ${COMP_WORDS[@]} " =~ " "($_murano_opts_exp)" " && "$prev" != "help" ]] ; then COMPREPLY=($(compgen -W "${_murano_flags}" -- "${cur}")) else COMPREPLY=($(compgen -W "${_murano_opts}" -- "${cur}")) fi return 0 } complete -o default -F _murano murano python-muranoclient-1.0.1/tools/install_venv.py0000666000175100017510000000504013231416510021767 0ustar zuulzuul00000000000000# Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Copyright 2010 OpenStack Foundation # Copyright 2013 IBM Corp. # # 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. """ Installation script for python-muranoclient's development virtualenv """ from __future__ import print_function import os import sys from six.moves import configparser import install_venv_common as install_venv def print_help(project, venv, root): help = """ %(project)s development environment setup is complete. %(project)s development uses virtualenv to track and manage Python dependencies while in development and testing. To activate the %(project)s virtualenv for the extent of your current shell session you can run: $ . %(venv)s/bin/activate Or, if you prefer, you can run commands in the virtualenv on a case by case basis by running: $ %(root)s/tools/with_venv.sh """ print(help % dict(project=project, venv=venv, root=root)) def main(argv): root = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) if os.environ.get('tools_path'): root = os.environ['tools_path'] venv = os.path.join(root, '.venv') if os.environ.get('venv'): venv = os.environ['venv'] pip_requires = os.path.join(root, 'requirements.txt') test_requires = os.path.join(root, 'test-requirements.txt') py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1]) setup_cfg = configparser.ConfigParser() setup_cfg.read('setup.cfg') project = setup_cfg.get('metadata', 'name') install = install_venv.InstallVenv( root, venv, pip_requires, test_requires, py_version, project) options = install.parse_args(argv) install.check_python_version() install.check_dependencies() install.create_virtualenv(no_site_packages=options.no_site_packages) install.install_dependencies() install.post_process() print_help(project, venv, root) if __name__ == '__main__': sys.exit(main(sys.argv)) python-muranoclient-1.0.1/tools/pretty_tox.sh0000666000175100017510000000021113231416510021461 0ustar zuulzuul00000000000000#!/usr/bin/env bash set -o pipefail TESTRARGS=$1 python setup.py testr --slowest --testr-args="--subunit $TESTRARGS" | subunit-trace -fpython-muranoclient-1.0.1/tools/with_venv.sh0000777000175100017510000000012413231416510021257 0ustar zuulzuul00000000000000#!/bin/bash TOOLS=`dirname $0` VENV=$TOOLS/../.venv source $VENV/bin/activate && $@ python-muranoclient-1.0.1/HACKING.rst0000666000175100017510000000017013231416510017346 0ustar zuulzuul00000000000000Style Commandments ================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ python-muranoclient-1.0.1/muranoclient/0000775000175100017510000000000013231417024020251 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/i18n.py0000666000175100017510000000152413231416510021405 0ustar zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """oslo.i18n integration module. See https://docs.openstack.org/oslo.i18n/latest/user/index.html """ import oslo_i18n _translators = oslo_i18n.TranslatorFactory(domain='muranoclient') # The primary translation function using the well-known name "_" _ = _translators.primary python-muranoclient-1.0.1/muranoclient/apiclient/0000775000175100017510000000000013231417024022221 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/apiclient/exceptions.py0000666000175100017510000003024613231416510024762 0ustar zuulzuul00000000000000# Copyright 2011 Nebula, Inc. # Copyright 2013 Alessio Ababilov # Copyright 2013 OpenStack Foundation # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Exception definitions. """ import inspect import sys from muranoclient.i18n import _ class ClientException(Exception): """The base exception class for all exceptions this library raises.""" pass class MissingArgs(ClientException): """Supplied arguments are not sufficient for calling a function.""" def __init__(self, missing): self.missing = missing msg = _("Missing arguments: %s") % ", ".join(missing) super(MissingArgs, self).__init__(msg) class ValidationError(ClientException): """Error in validation on API client side.""" pass class UnsupportedVersion(ClientException): """User is trying to use an unsupported version of the API.""" pass class CommandError(ClientException): """Error in CLI tool.""" pass class AuthorizationFailure(ClientException): """Cannot authorize API client.""" pass class ConnectionRefused(ClientException): """Cannot connect to API service.""" pass class AuthPluginOptionsMissing(AuthorizationFailure): """Auth plugin misses some options.""" def __init__(self, opt_names): super(AuthPluginOptionsMissing, self).__init__( _("Authentication failed. Missing options: %s") % ", ".join(opt_names)) self.opt_names = opt_names class AuthSystemNotFound(AuthorizationFailure): """User has specified an AuthSystem that is not installed.""" def __init__(self, auth_system): super(AuthSystemNotFound, self).__init__( _("AuthSystemNotFound: %s") % repr(auth_system)) self.auth_system = auth_system class NoUniqueMatch(ClientException): """Multiple entities found instead of one.""" pass class EndpointException(ClientException): """Something is rotten in Service Catalog.""" pass class EndpointNotFound(EndpointException): """Could not find requested endpoint in Service Catalog.""" pass class AmbiguousEndpoints(EndpointException): """Found more than one matching endpoint in Service Catalog.""" def __init__(self, endpoints=None): super(AmbiguousEndpoints, self).__init__( _("AmbiguousEndpoints: %s") % repr(endpoints)) self.endpoints = endpoints class HttpError(ClientException): """The base exception class for all HTTP exceptions.""" http_status = 0 message = _("HTTP Error") def __init__(self, message=None, details=None, response=None, request_id=None, url=None, method=None, http_status=None): self.http_status = http_status or self.http_status self.message = message or self.message self.details = details self.request_id = request_id self.response = response self.url = url self.method = method formatted_string = "%s (HTTP %s)" % (self.message, self.http_status) if request_id: formatted_string += " (Request-ID: %s)" % request_id super(HttpError, self).__init__(formatted_string) class HTTPRedirection(HttpError): """HTTP Redirection.""" message = _("HTTP Redirection") class HTTPClientError(HttpError): """Client-side HTTP error. Exception for cases in which the client seems to have erred. """ message = _("HTTP Client Error") class HttpServerError(HttpError): """Server-side HTTP error. Exception for cases in which the server is aware that it has erred or is incapable of performing the request. """ message = _("HTTP Server Error") class MultipleChoices(HTTPRedirection): """HTTP 300 - Multiple Choices. Indicates multiple options for the resource that the client may follow. """ http_status = 300 message = _("Multiple Choices") class BadRequest(HTTPClientError): """HTTP 400 - Bad Request. The request cannot be fulfilled due to bad syntax. """ http_status = 400 message = _("Bad Request") class Unauthorized(HTTPClientError): """HTTP 401 - Unauthorized. Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided. """ http_status = 401 message = _("Unauthorized") class PaymentRequired(HTTPClientError): """HTTP 402 - Payment Required. Reserved for future use. """ http_status = 402 message = _("Payment Required") class Forbidden(HTTPClientError): """HTTP 403 - Forbidden. The request was a valid request, but the server is refusing to respond to it. """ http_status = 403 message = _("Forbidden") class NotFound(HTTPClientError): """HTTP 404 - Not Found. The requested resource could not be found but may be available again in the future. """ http_status = 404 message = _("Not Found") class MethodNotAllowed(HTTPClientError): """HTTP 405 - Method Not Allowed. A request was made of a resource using a request method not supported by that resource. """ http_status = 405 message = _("Method Not Allowed") class NotAcceptable(HTTPClientError): """HTTP 406 - Not Acceptable. The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request. """ http_status = 406 message = _("Not Acceptable") class ProxyAuthenticationRequired(HTTPClientError): """HTTP 407 - Proxy Authentication Required. The client must first authenticate itself with the proxy. """ http_status = 407 message = _("Proxy Authentication Required") class RequestTimeout(HTTPClientError): """HTTP 408 - Request Timeout. The server timed out waiting for the request. """ http_status = 408 message = _("Request Timeout") class Conflict(HTTPClientError): """HTTP 409 - Conflict. Indicates that the request could not be processed because of conflict in the request, such as an edit conflict. """ http_status = 409 message = _("Conflict") class Gone(HTTPClientError): """HTTP 410 - Gone. Indicates that the resource requested is no longer available and will not be available again. """ http_status = 410 message = _("Gone") class LengthRequired(HTTPClientError): """HTTP 411 - Length Required. The request did not specify the length of its content, which is required by the requested resource. """ http_status = 411 message = _("Length Required") class PreconditionFailed(HTTPClientError): """HTTP 412 - Precondition Failed. The server does not meet one of the preconditions that the requester put on the request. """ http_status = 412 message = _("Precondition Failed") class RequestEntityTooLarge(HTTPClientError): """HTTP 413 - Request Entity Too Large. The request is larger than the server is willing or able to process. """ http_status = 413 message = _("Request Entity Too Large") def __init__(self, *args, **kwargs): try: self.retry_after = int(kwargs.pop('retry_after')) except (KeyError, ValueError): self.retry_after = 0 super(RequestEntityTooLarge, self).__init__(*args, **kwargs) class RequestUriTooLong(HTTPClientError): """HTTP 414 - Request-URI Too Long. The URI provided was too long for the server to process. """ http_status = 414 message = _("Request-URI Too Long") class UnsupportedMediaType(HTTPClientError): """HTTP 415 - Unsupported Media Type. The request entity has a media type which the server or resource does not support. """ http_status = 415 message = _("Unsupported Media Type") class RequestedRangeNotSatisfiable(HTTPClientError): """HTTP 416 - Requested Range Not Satisfiable. The client has asked for a portion of the file, but the server cannot supply that portion. """ http_status = 416 message = _("Requested Range Not Satisfiable") class ExpectationFailed(HTTPClientError): """HTTP 417 - Expectation Failed. The server cannot meet the requirements of the Expect request-header field. """ http_status = 417 message = _("Expectation Failed") class UnprocessableEntity(HTTPClientError): """HTTP 422 - Unprocessable Entity. The request was well-formed but was unable to be followed due to semantic errors. """ http_status = 422 message = _("Unprocessable Entity") class InternalServerError(HttpServerError): """HTTP 500 - Internal Server Error. A generic error message, given when no more specific message is suitable. """ http_status = 500 message = _("Internal Server Error") # NotImplemented is a python keyword. class HttpNotImplemented(HttpServerError): """HTTP 501 - Not Implemented. The server either does not recognize the request method, or it lacks the ability to fulfill the request. """ http_status = 501 message = _("Not Implemented") class BadGateway(HttpServerError): """HTTP 502 - Bad Gateway. The server was acting as a gateway or proxy and received an invalid response from the upstream server. """ http_status = 502 message = _("Bad Gateway") class ServiceUnavailable(HttpServerError): """HTTP 503 - Service Unavailable. The server is currently unavailable. """ http_status = 503 message = _("Service Unavailable") class GatewayTimeout(HttpServerError): """HTTP 504 - Gateway Timeout. The server was acting as a gateway or proxy and did not receive a timely response from the upstream server. """ http_status = 504 message = _("Gateway Timeout") class HttpVersionNotSupported(HttpServerError): """HTTP 505 - HttpVersion Not Supported. The server does not support the HTTP protocol version used in the request. """ http_status = 505 message = _("HTTP Version Not Supported") # _code_map contains all the classes that have http_status attribute. _code_map = dict( (getattr(obj, 'http_status', None), obj) for name, obj in vars(sys.modules[__name__]).items() if inspect.isclass(obj) and getattr(obj, 'http_status', False) ) def from_response(response, url, method): """Returns an instance of :class:`HttpError` or subclass based on response. :param response: instance of `requests.Response` class :param method: HTTP method used for request :param url: URL used for request """ req_id = response.headers.get("x-openstack-request-id") # NOTE(hdd): true for older versions of nova and cinder if not req_id: req_id = response.headers.get("x-compute-request-id") kwargs = { "http_status": response.status_code, "response": response, "method": method, "url": url, "request_id": req_id, } if "retry-after" in response.headers: kwargs["retry_after"] = response.headers["retry-after"] content_type = response.headers.get("Content-Type", "") if content_type.startswith("application/json"): try: body = response.json() except ValueError: pass else: if isinstance(body, dict): error = list(body.values())[0] kwargs["message"] = error.get("message") kwargs["details"] = error.get("details") elif content_type.startswith("text/"): kwargs["details"] = response.text try: cls = _code_map[response.status_code] except KeyError: if 500 <= response.status_code < 600: cls = HttpServerError elif 400 <= response.status_code < 500: cls = HTTPClientError else: cls = HttpError return cls(**kwargs) python-muranoclient-1.0.1/muranoclient/apiclient/auth.py0000666000175100017510000001546613231416510023551 0ustar zuulzuul00000000000000# Copyright 2013 OpenStack Foundation # Copyright 2013 Spanish National Research Council. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # E0202: An attribute inherited from %s hide this method # pylint: disable=E0202 import abc import argparse import os import six from stevedore import extension from muranoclient.apiclient import exceptions _discovered_plugins = {} def discover_auth_systems(): """Discover the available auth-systems. This won't take into account the old style auth-systems. """ global _discovered_plugins _discovered_plugins = {} def add_plugin(ext): _discovered_plugins[ext.name] = ext.plugin ep_namespace = "muranoclient.apiclient.auth" mgr = extension.ExtensionManager(ep_namespace) mgr.map(add_plugin) def load_auth_system_opts(parser): """Load options needed by the available auth-systems into a parser. This function will try to populate the parser with options from the available plugins. """ group = parser.add_argument_group("Common auth options") BaseAuthPlugin.add_common_opts(group) for name, auth_plugin in _discovered_plugins.items(): group = parser.add_argument_group( "Auth-system '%s' options" % name, conflict_handler="resolve") auth_plugin.add_opts(group) def load_plugin(auth_system): try: plugin_class = _discovered_plugins[auth_system] except KeyError: raise exceptions.AuthSystemNotFound(auth_system) return plugin_class(auth_system=auth_system) def load_plugin_from_args(args): """Load required plugin and populate it with options. Try to guess auth system if it is not specified. Systems are tried in alphabetical order. :type args: argparse.Namespace :raises: AuthPluginOptionsMissing """ auth_system = args.os_auth_system if auth_system: plugin = load_plugin(auth_system) plugin.parse_opts(args) plugin.sufficient_options() return plugin for plugin_auth_system in sorted(six.iterkeys(_discovered_plugins)): plugin_class = _discovered_plugins[plugin_auth_system] plugin = plugin_class() plugin.parse_opts(args) try: plugin.sufficient_options() except exceptions.AuthPluginOptionsMissing: continue return plugin raise exceptions.AuthPluginOptionsMissing(["auth_system"]) @six.add_metaclass(abc.ABCMeta) class BaseAuthPlugin(object): """Base class for authentication plugins. An authentication plugin needs to override at least the authenticate method to be a valid plugin. """ auth_system = None opt_names = [] common_opt_names = [ "auth_system", "username", "password", "tenant_name", "token", "auth_url", ] def __init__(self, auth_system=None, **kwargs): self.auth_system = auth_system or self.auth_system self.opts = dict((name, kwargs.get(name)) for name in self.opt_names) @staticmethod def _parser_add_opt(parser, opt): """Add an option to parser in two variants. :param opt: option name (with underscores) """ dashed_opt = opt.replace("_", "-") env_var = "OS_%s" % opt.upper() arg_default = os.environ.get(env_var, "") arg_help = "Defaults to env[%s]." % env_var parser.add_argument( "--os-%s" % dashed_opt, metavar="<%s>" % dashed_opt, default=arg_default, help=arg_help) parser.add_argument( "--os_%s" % opt, metavar="<%s>" % dashed_opt, help=argparse.SUPPRESS) @classmethod def add_opts(cls, parser): """Populate the parser with the options for this plugin.""" for opt in cls.opt_names: # use `BaseAuthPlugin.common_opt_names` since it is never # changed in child classes if opt not in BaseAuthPlugin.common_opt_names: cls._parser_add_opt(parser, opt) @classmethod def add_common_opts(cls, parser): """Add options that are common for several plugins.""" for opt in cls.common_opt_names: cls._parser_add_opt(parser, opt) @staticmethod def get_opt(opt_name, args): """Return option name and value. :param opt_name: name of the option, e.g., "username" :param args: parsed arguments """ return (opt_name, getattr(args, "os_%s" % opt_name, None)) def parse_opts(self, args): """Parse the actual auth-system options if any. This method is expected to populate the attribute `self.opts` with a dict containing the options and values needed to make authentication. """ self.opts.update(dict(self.get_opt(opt_name, args) for opt_name in self.opt_names)) def authenticate(self, http_client): """Authenticate using plugin defined method. The method usually analyses `self.opts` and performs a request to authentication server. :param http_client: client object that needs authentication :type http_client: HTTPClient :raises: AuthorizationFailure """ self.sufficient_options() self._do_authenticate(http_client) @abc.abstractmethod def _do_authenticate(self, http_client): """Protected method for authentication.""" def sufficient_options(self): """Check if all required options are present. :raises: AuthPluginOptionsMissing """ missing = [opt for opt in self.opt_names if not self.opts.get(opt)] if missing: raise exceptions.AuthPluginOptionsMissing(missing) @abc.abstractmethod def token_and_endpoint(self, endpoint_type, service_type): """Return token and endpoint. :param service_type: Service type of the endpoint :type service_type: string :param endpoint_type: Type of endpoint. Possible values: public or publicURL, internal or internalURL, admin or adminURL :type endpoint_type: string :returns: tuple of token and endpoint strings :raises: EndpointException """ python-muranoclient-1.0.1/muranoclient/apiclient/base.py0000666000175100017510000004104513231416510023512 0ustar zuulzuul00000000000000# Copyright 2010 Jacob Kaplan-Moss # Copyright 2011 OpenStack Foundation # Copyright 2012 Grid Dynamics # Copyright 2013 OpenStack Foundation # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Base utilities to build API operation managers and objects on top of. """ # E1102: %s is not callable # pylint: disable=E1102 import abc import copy from oslo_utils import strutils from oslo_utils import uuidutils import six from six.moves.urllib import parse from muranoclient.apiclient import exceptions from muranoclient.i18n import _ def getid(obj): """Return id if argument is a Resource. Abstracts the common pattern of allowing both an object or an object's ID (UUID) as a parameter when dealing with relationships. """ try: if obj.uuid: return obj.uuid except AttributeError: pass try: return obj.id except AttributeError: return obj # TODO(aababilov): call run_hooks() in HookableMixin's child classes class HookableMixin(object): """Mixin so classes can register and run hooks.""" _hooks_map = {} @classmethod def add_hook(cls, hook_type, hook_func): """Add a new hook of specified type. :param cls: class that registers hooks :param hook_type: hook type, e.g., '__pre_parse_args__' :param hook_func: hook function """ if hook_type not in cls._hooks_map: cls._hooks_map[hook_type] = [] cls._hooks_map[hook_type].append(hook_func) @classmethod def run_hooks(cls, hook_type, *args, **kwargs): """Run all hooks of specified type. :param cls: class that registers hooks :param hook_type: hook type, e.g., '__pre_parse_args__' :param args: args to be passed to every hook function :param kwargs: kwargs to be passed to every hook function """ hook_funcs = cls._hooks_map.get(hook_type) or [] for hook_func in hook_funcs: hook_func(*args, **kwargs) class BaseManager(HookableMixin): """Basic manager type providing common operations. Managers interact with a particular type of API (servers, flavors, images, etc.) and provide CRUD operations for them. """ resource_class = None def __init__(self, client): """Initializes BaseManager with `client`. :param client: instance of BaseClient descendant for HTTP requests """ super(BaseManager, self).__init__() self.client = client def _list(self, url, response_key, obj_class=None, json=None): """List the collection. :param url: a partial URL, e.g., '/servers' :param response_key: the key to be looked up in response dictionary, e.g., 'servers' :param obj_class: class for constructing the returned objects (self.resource_class will be used by default) :param json: data that will be encoded as JSON and passed in POST request (GET will be sent by default) """ if json: body = self.client.post(url, json=json).json() else: body = self.client.get(url).json() if obj_class is None: obj_class = self.resource_class data = body[response_key] # NOTE(ja): keystone returns values as list as {'values': [ ... ]} # unlike other services which just return the list... try: data = data['values'] except (KeyError, TypeError): pass return [obj_class(self, res, loaded=True) for res in data if res] def _get(self, url, response_key): """Get an object from collection. :param url: a partial URL, e.g., '/servers' :param response_key: the key to be looked up in response dictionary, e.g., 'server' """ body = self.client.get(url).json() return self.resource_class(self, body[response_key], loaded=True) def _head(self, url): """Retrieve request headers for an object. :param url: a partial URL, e.g., '/servers' """ resp = self.client.head(url) return resp.status_code == 204 def _post(self, url, json, response_key, return_raw=False): """Create an object. :param url: a partial URL, e.g., '/servers' :param json: data that will be encoded as JSON and passed in POST request (GET will be sent by default) :param response_key: the key to be looked up in response dictionary, e.g., 'servers' :param return_raw: flag to force returning raw JSON instead of Python object of self.resource_class """ body = self.client.post(url, json=json).json() if return_raw: return body[response_key] return self.resource_class(self, body[response_key]) def _put(self, url, json=None, response_key=None): """Update an object with PUT method. :param url: a partial URL, e.g., '/servers' :param json: data that will be encoded as JSON and passed in POST request (GET will be sent by default) :param response_key: the key to be looked up in response dictionary, e.g., 'servers' """ resp = self.client.put(url, json=json) # PUT requests may not return a body if resp.content: body = resp.json() if response_key is not None: return self.resource_class(self, body[response_key]) else: return self.resource_class(self, body) def _patch(self, url, json=None, response_key=None): """Update an object with PATCH method. :param url: a partial URL, e.g., '/servers' :param json: data that will be encoded as JSON and passed in POST request (GET will be sent by default) :param response_key: the key to be looked up in response dictionary, e.g., 'servers' """ body = self.client.patch(url, json=json).json() if response_key is not None: return self.resource_class(self, body[response_key]) else: return self.resource_class(self, body) def _delete(self, url): """Delete an object. :param url: a partial URL, e.g., '/servers/my-server' """ return self.client.delete(url) @six.add_metaclass(abc.ABCMeta) class ManagerWithFind(BaseManager): """Manager with additional `find()`/`findall()` methods.""" @abc.abstractmethod def list(self): pass def find(self, **kwargs): """Find a single item with attributes matching ``**kwargs``. This isn't very efficient: it loads the entire list then filters on the Python side. """ matches = self.findall(**kwargs) num_matches = len(matches) if num_matches == 0: msg = _("No %(name)s matching %(args)s.") % { 'name': self.resource_class.__name__, 'args': kwargs } raise exceptions.NotFound(msg) elif num_matches > 1: raise exceptions.NoUniqueMatch() else: return matches[0] def findall(self, **kwargs): """Find all items with attributes matching ``**kwargs``. This isn't very efficient: it loads the entire list then filters on the Python side. """ found = [] searches = kwargs.items() for obj in self.list(): try: if all(getattr(obj, attr) == value for (attr, value) in searches): found.append(obj) except AttributeError: continue return found class CrudManager(BaseManager): """Base manager class for manipulating entities. Children of this class are expected to define a `collection_key` and `key`. - `collection_key`: Usually a plural noun by convention (e.g. `entities`); used to refer collections in both URL's (e.g. `/v3/entities`) and JSON objects containing a list of member resources (e.g. `{'entities': [{}, {}, {}]}`). - `key`: Usually a singular noun by convention (e.g. `entity`); used to refer to an individual member of the collection. """ collection_key = None key = None def build_url(self, base_url=None, **kwargs): """Builds a resource URL for the given kwargs. Given an example collection where `collection_key = 'entities'` and `key = 'entity'`, the following URL's could be generated. By default, the URL will represent a collection of entities, e.g.:: /entities If kwargs contains an `entity_id`, then the URL will represent a specific member, e.g.:: /entities/{entity_id} :param base_url: if provided, the generated URL will be appended to it """ url = base_url if base_url is not None else '' url += '/%s' % self.collection_key # do we have a specific entity? entity_id = kwargs.get('%s_id' % self.key) if entity_id is not None: url += '/%s' % entity_id return url def _filter_kwargs(self, kwargs): """Drop null values and handle ids.""" for key, ref in kwargs.copy().items(): if ref is None: kwargs.pop(key) else: if isinstance(ref, Resource): kwargs.pop(key) kwargs['%s_id' % key] = getid(ref) return kwargs def create(self, **kwargs): kwargs = self._filter_kwargs(kwargs) return self._post( self.build_url(**kwargs), {self.key: kwargs}, self.key) def get(self, **kwargs): kwargs = self._filter_kwargs(kwargs) return self._get( self.build_url(**kwargs), self.key) def head(self, **kwargs): kwargs = self._filter_kwargs(kwargs) return self._head(self.build_url(**kwargs)) def list(self, base_url=None, **kwargs): """List the collection. :param base_url: if provided, the generated URL will be appended to it """ kwargs = self._filter_kwargs(kwargs) return self._list( '%(base_url)s%(query)s' % { 'base_url': self.build_url(base_url=base_url, **kwargs), 'query': '?%s' % parse.urlencode(kwargs) if kwargs else '', }, self.collection_key) def put(self, base_url=None, **kwargs): """Update an element. :param base_url: if provided, the generated URL will be appended to it """ kwargs = self._filter_kwargs(kwargs) return self._put(self.build_url(base_url=base_url, **kwargs)) def update(self, **kwargs): kwargs = self._filter_kwargs(kwargs) params = kwargs.copy() params.pop('%s_id' % self.key) return self._patch( self.build_url(**kwargs), {self.key: params}, self.key) def delete(self, **kwargs): kwargs = self._filter_kwargs(kwargs) return self._delete( self.build_url(**kwargs)) def find(self, base_url=None, **kwargs): """Find a single item with attributes matching ``**kwargs``. :param base_url: if provided, the generated URL will be appended to it """ kwargs = self._filter_kwargs(kwargs) rl = self._list( '%(base_url)s%(query)s' % { 'base_url': self.build_url(base_url=base_url, **kwargs), 'query': '?%s' % parse.urlencode(kwargs) if kwargs else '', }, self.collection_key) num = len(rl) if num == 0: msg = _("No %(name)s matching %(args)s.") % { 'name': self.resource_class.__name__, 'args': kwargs } raise exceptions.NotFound(404, msg) elif num > 1: raise exceptions.NoUniqueMatch else: return rl[0] class Extension(HookableMixin): """Extension descriptor.""" SUPPORTED_HOOKS = ('__pre_parse_args__', '__post_parse_args__') manager_class = None def __init__(self, name, module): super(Extension, self).__init__() self.name = name self.module = module self._parse_extension_module() def _parse_extension_module(self): self.manager_class = None for attr_name, attr_value in self.module.__dict__.items(): if attr_name in self.SUPPORTED_HOOKS: self.add_hook(attr_name, attr_value) else: try: if issubclass(attr_value, BaseManager): self.manager_class = attr_value except TypeError: pass def __repr__(self): return "" % self.name class Resource(object): """Base class for OpenStack resources (tenant, user, etc.). This is pretty much just a bag for attributes. """ HUMAN_ID = False NAME_ATTR = 'name' def __init__(self, manager, info, loaded=False): """Populate and bind to a manager. :param manager: BaseManager object :param info: dictionary representing resource attributes :param loaded: prevent lazy-loading if set to True """ self.manager = manager self._info = info self._add_details(info) self._loaded = loaded self._init_completion_cache() def _init_completion_cache(self): cache_write = getattr(self.manager, 'write_to_completion_cache', None) if not cache_write: return # NOTE(sirp): ensure `id` is already present because if it isn't we'll # enter an infinite loop of __getattr__ -> get -> __init__ -> # __getattr__ -> ... if 'id' in self.__dict__ and uuidutils.is_uuid_like(self.id): cache_write('uuid', self.id) if self.human_id: cache_write('human_id', self.human_id) def __repr__(self): reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and k != 'manager') info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) return "<%s %s>" % (self.__class__.__name__, info) @property def human_id(self): """Human-readable ID which can be used for bash completion.""" if self.HUMAN_ID: name = getattr(self, self.NAME_ATTR, None) if name is not None: return strutils.to_slug(name) return None def _add_details(self, info): for (k, v) in info.items(): try: setattr(self, k, v) self._info[k] = v except AttributeError: # In this case we already defined the attribute on the class pass def __getattr__(self, k): if k not in self.__dict__: # NOTE(bcwaldon): disallow lazy-loading if already loaded once if not self.is_loaded(): self.get() return self.__getattr__(k) raise AttributeError(k) else: return self.__dict__[k] def get(self): """Support for lazy loading details. Some clients, such as novaclient have the option to lazy load the details, details which can be loaded with this function. """ # set_loaded() first ... so if we have to bail, we know we tried. self.set_loaded(True) if not hasattr(self.manager, 'get'): return new = self.manager.get(self.id) if new: self._add_details(new._info) def __eq__(self, other): if not isinstance(other, Resource): return NotImplemented # two resources of different types are not equal if not isinstance(other, self.__class__): return False return self._info == other._info def __ne__(self, other): return not self.__eq__(other) def is_loaded(self): return self._loaded def set_loaded(self, val): self._loaded = val def to_dict(self): return copy.deepcopy(self._info) python-muranoclient-1.0.1/muranoclient/apiclient/client.py0000666000175100017510000003100113231416510024045 0ustar zuulzuul00000000000000# Copyright 2010 Jacob Kaplan-Moss # Copyright 2011 OpenStack Foundation # Copyright 2011 Piston Cloud Computing, Inc. # Copyright 2013 Alessio Ababilov # Copyright 2013 Grid Dynamics # Copyright 2013 OpenStack Foundation # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ OpenStack Client interface. Handles the REST calls and responses. """ # E0202: An attribute inherited from %s hide this method # pylint: disable=E0202 try: import simplejson as json except ImportError: import json import time from oslo_log import log as logging from oslo_utils import importutils import requests from muranoclient.apiclient import exceptions from muranoclient.i18n import _ _logger = logging.getLogger(__name__) class HTTPClient(object): """This client handles sending HTTP requests to OpenStack servers. Features: - share authentication information between several clients to different services (e.g., for compute and image clients); - reissue authentication request for expired tokens; - encode/decode JSON bodies; - raise exceptions on HTTP errors; - pluggable authentication; - store authentication information in a keyring; - store time spent for requests; - register clients for particular services, so one can use `http_client.identity` or `http_client.compute`; - log requests and responses in a format that is easy to copy-and-paste into terminal and send the same request with curl. """ user_agent = "muranoclient.apiclient" def __init__(self, auth_plugin, region_name=None, endpoint_type="publicURL", original_ip=None, verify=True, cert=None, timeout=None, timings=False, keyring_saver=None, debug=False, user_agent=None, http=None): self.auth_plugin = auth_plugin self.endpoint_type = endpoint_type self.region_name = region_name self.original_ip = original_ip self.timeout = timeout self.verify = verify self.cert = cert self.keyring_saver = keyring_saver self.debug = debug self.user_agent = user_agent or self.user_agent self.times = [] # [("item", starttime, endtime), ...] self.timings = timings # requests within the same session can reuse TCP connections from pool self.http = http or requests.Session() self.cached_token = None def _http_log_req(self, url, method, kwargs): if not self.debug: return string_parts = [ "curl -i", "-X '%s'" % method, "'%s'" % url, ] for element in kwargs['headers']: header = "-H '%s: %s'" % (element, kwargs['headers'][element]) string_parts.append(header) _logger.debug("REQ: %s" % " ".join(string_parts)) if 'data' in kwargs: _logger.debug("REQ BODY: %s\n" % (kwargs['data'])) def _http_log_resp(self, resp): if not self.debug: return _logger.debug( "RESP: [%s] %s\n", resp.status_code, resp.headers) if resp._content_consumed: _logger.debug( "RESP BODY: %s\n", resp.text) def serialize(self, kwargs): if kwargs.get('json') is not None: kwargs['headers']['Content-Type'] = 'application/json' kwargs['data'] = json.dumps(kwargs.pop('json')) def get_timings(self): return self.times def reset_timings(self): self.times = [] def request(self, url, method, **kwargs): """Send an http request with the specified characteristics. Wrapper around `requests.Session.request` to handle tasks such as setting headers, JSON encoding/decoding, and error handling. :param method: method of HTTP request :param url: URL of HTTP request :param kwargs: any other parameter that can be passed to requests.Session.request (such as `headers`) or `json` that will be encoded as JSON and used as `data` argument """ kwargs.setdefault("headers", kwargs.get("headers", {})) kwargs["headers"]["User-Agent"] = self.user_agent if self.original_ip: kwargs["headers"]["Forwarded"] = "for=%s;by=%s" % ( self.original_ip, self.user_agent) if self.timeout is not None: kwargs.setdefault("timeout", self.timeout) kwargs.setdefault("verify", self.verify) if self.cert is not None: kwargs.setdefault("cert", self.cert) self.serialize(kwargs) self._http_log_req(url, method, kwargs) if self.timings: start_time = time.time() resp = self.http.request(url, method, **kwargs) if self.timings: self.times.append(("%s %s" % (url, method), start_time, time.time())) self._http_log_resp(resp) if resp.status_code >= 400: _logger.debug( "Request returned failure status: %s", resp.status_code) raise exceptions.from_response(resp, url, method) return resp @staticmethod def concat_url(endpoint, url): """Concatenate endpoint and final URL. E.g., "http://keystone/v2.0/" and "/tokens" are concatenated to "http://keystone/v2.0/tokens". :param endpoint: the base URL :param url: the final URL """ return "%s/%s" % (endpoint.rstrip("/"), url.strip("/")) def client_request(self, client, url, method, **kwargs): """Send an http request using `client`'s endpoint and specified `url`. If request was rejected as unauthorized (possibly because the token is expired), issue one authorization attempt and send the request once again. :param client: instance of BaseClient descendant :param method: method of HTTP request :param url: URL of HTTP request :param kwargs: any other parameter that can be passed to `HTTPClient.request` """ filter_args = { "endpoint_type": client.endpoint_type or self.endpoint_type, "service_type": client.service_type, } token, endpoint = (self.cached_token, client.cached_endpoint) just_authenticated = False if not (token and endpoint): try: token, endpoint = self.auth_plugin.token_and_endpoint( **filter_args) except exceptions.EndpointException: pass if not (token and endpoint): self.authenticate() just_authenticated = True token, endpoint = self.auth_plugin.token_and_endpoint( **filter_args) if not (token and endpoint): raise exceptions.AuthorizationFailure( _("Cannot find endpoint or token for request")) old_token_endpoint = (token, endpoint) kwargs.setdefault("headers", {})["X-Auth-Token"] = token self.cached_token = token client.cached_endpoint = endpoint # Perform the request once. If we get Unauthorized, then it # might be because the auth token expired, so try to # re-authenticate and try again. If it still fails, bail. try: return self.request( method, self.concat_url(endpoint, url), **kwargs) except exceptions.Unauthorized as unauth_ex: if just_authenticated: raise self.cached_token = None client.cached_endpoint = None self.authenticate() try: token, endpoint = self.auth_plugin.token_and_endpoint( **filter_args) except exceptions.EndpointException: raise unauth_ex if (not (token and endpoint) or old_token_endpoint == (token, endpoint)): raise unauth_ex self.cached_token = token client.cached_endpoint = endpoint kwargs["headers"]["X-Auth-Token"] = token return self.request( method, self.concat_url(endpoint, url), **kwargs) def add_client(self, base_client_instance): """Add a new instance of :class:`BaseClient` descendant. `self` will store a reference to `base_client_instance`. Example: >>> def test_clients(): ... from keystoneclient.auth import keystone ... from openstack.common.apiclient import client ... auth = keystone.KeystoneAuthPlugin( ... username="user", password="pass", tenant_name="tenant", ... auth_url="http://auth:5000/v2.0") ... openstack_client = client.HTTPClient(auth) ... # create nova client ... from novaclient.v1_1 import client ... client.Client(openstack_client) ... # create keystone client ... from keystoneclient.v2_0 import client ... client.Client(openstack_client) ... # use them ... openstack_client.identity.tenants.list() ... openstack_client.compute.servers.list() """ service_type = base_client_instance.service_type if service_type and not hasattr(self, service_type): setattr(self, service_type, base_client_instance) def authenticate(self): self.auth_plugin.authenticate(self) # Store the authentication results in the keyring for later requests if self.keyring_saver: self.keyring_saver.save(self) class BaseClient(object): """Top-level object to access the OpenStack API. This client uses :class:`HTTPClient` to send requests. :class:`HTTPClient` will handle a bunch of issues such as authentication. """ service_type = None endpoint_type = None # "publicURL" will be used cached_endpoint = None def __init__(self, http_client, extensions=None): self.http_client = http_client http_client.add_client(self) # Add in any extensions... if extensions: for extension in extensions: if extension.manager_class: setattr(self, extension.name, extension.manager_class(self)) def client_request(self, url, method, **kwargs): return self.http_client.client_request( self, url, method, **kwargs) def head(self, url, **kwargs): return self.client_request(url, "HEAD", **kwargs) def get(self, url, **kwargs): return self.client_request(url, "GET", **kwargs) def post(self, url, **kwargs): return self.client_request(url, "POST", **kwargs) def put(self, url, **kwargs): return self.client_request(url, "PUT", **kwargs) def delete(self, url, **kwargs): return self.client_request(url, "DELETE", **kwargs) def patch(self, url, **kwargs): return self.client_request(url, "PATCH", **kwargs) @staticmethod def get_class(api_name, version, version_map): """Returns the client class for the requested API version :param api_name: the name of the API, e.g. 'compute', 'image', etc :param version: the requested API version :param version_map: a dict of client classes keyed by version :rtype: a client class for the requested API version """ try: client_path = version_map[str(version)] except (KeyError, ValueError): msg = _("Invalid %(api_name)s client version '%(version)s'. " "Must be one of: %(version_map)s") % { 'api_name': api_name, 'version': version, 'version_map': ', '.join(version_map.keys())} raise exceptions.UnsupportedVersion(msg) return importutils.import_class(client_path) python-muranoclient-1.0.1/muranoclient/apiclient/__init__.py0000666000175100017510000000000013231416510024321 0ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/apiclient/fake_client.py0000666000175100017510000001353213231416510025044 0ustar zuulzuul00000000000000# Copyright 2013 OpenStack Foundation # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ A fake server that "responds" to API methods with pre-canned responses. All of these responses come from the spec, so if for some reason the spec's wrong the tests might raise AssertionError. I've indicated in comments the places where actual behavior differs from the spec. """ # W0102: Dangerous default value %s as argument # pylint: disable=W0102 import json import requests import six from six.moves.urllib import parse from muranoclient.apiclient import client def assert_has_keys(dct, required=None, optional=None): if required is None: required = [] if optional is None: optional = [] for k in required: try: assert k in dct except AssertionError: extra_keys = set(dct.keys()).difference(set(required + optional)) raise AssertionError("found unexpected keys: %s" % list(extra_keys)) class TestResponse(requests.Response): """Wrap requests.Response and provide a convenient initialization.""" def __init__(self, data): super(TestResponse, self).__init__() self._content_consumed = True if isinstance(data, dict): self.status_code = data.get('status_code', 200) # Fake the text attribute to streamline Response creation text = data.get('text', "") if isinstance(text, (dict, list)): self._content = json.dumps(text) default_headers = { "Content-Type": "application/json", } else: self._content = text default_headers = {} if six.PY3 and isinstance(self._content, six.string_types): self._content = self._content.encode('utf-8', 'strict') self.headers = data.get('headers') or default_headers else: self.status_code = data def __eq__(self, other): return (self.status_code == other.status_code and self.headers == other.headers and self._content == other._content) def __ne__(self, other): return not self.__eq__(other) class FakeHTTPClient(client.HTTPClient): def __init__(self, *args, **kwargs): self.callstack = [] self.fixtures = kwargs.pop("fixtures", None) or {} if not args and "auth_plugin" not in kwargs: args = (None, ) super(FakeHTTPClient, self).__init__(*args, **kwargs) def assert_called(self, url, method, body=None, pos=-1): """Assert than an API method was just called.""" expected = (url, method) called = self.callstack[pos][0:2] assert self.callstack, \ "Expected %s %s but no calls were made." % expected assert expected == called, 'Expected %s %s; got %s %s' % \ (expected + called) if body is not None: if self.callstack[pos][3] != body: raise AssertionError('%r != %r' % (self.callstack[pos][3], body)) def assert_called_anytime(self, url, method, body=None): """Assert than an API method was called anytime in the test.""" expected = (url, method) assert self.callstack, \ "Expected %s %s but no calls were made." % expected found = False entry = None for entry in self.callstack: if expected == entry[0:2]: found = True break assert found, 'Expected %s %s; got %s' % \ (url, method, self.callstack) if body is not None: assert entry[3] == body, "%s != %s" % (entry[3], body) self.callstack = [] def clear_callstack(self): self.callstack = [] def authenticate(self): pass def client_request(self, client, url, method, **kwargs): # Check that certain things are called correctly if method in ["GET", "DELETE"]: assert "json" not in kwargs # Note the call self.callstack.append( (url, method, kwargs.get("headers") or {}, kwargs.get("json") or kwargs.get("data"))) try: fixture = self.fixtures[url][method] except KeyError: pass else: return TestResponse({"headers": fixture[0], "text": fixture[1]}) # Call the method args = parse.parse_qsl(parse.urlparse(url)[4]) kwargs.update(args) munged_url = url.rsplit('?', 1)[0] munged_url = munged_url.strip('/').replace('/', '_').replace('.', '_') munged_url = munged_url.replace('-', '_') callback = "%s_%s" % (method.lower(), munged_url) if not hasattr(self, callback): raise AssertionError('Called unknown API method: %s %s, ' 'expected fakes method name: %s' % (url, method, callback)) resp = getattr(self, callback)(**kwargs) if len(resp) == 3: status, headers, body = resp else: status, body = resp headers = {} return TestResponse({ "status_code": status, "text": body, "headers": headers, }) python-muranoclient-1.0.1/muranoclient/locale/0000775000175100017510000000000013231417024021510 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/locale/en_GB/0000775000175100017510000000000013231417024022462 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/locale/en_GB/LC_MESSAGES/0000775000175100017510000000000013231417024024247 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/locale/en_GB/LC_MESSAGES/muranoclient.po0000666000175100017510000000664313231416510027321 0ustar zuulzuul00000000000000# Andi Chandler , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: python-muranoclient 0.14.1.dev18\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2017-10-05 02:06+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-10-21 09:07+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en-GB\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #, python-format msgid "AmbiguousEndpoints: %s" msgstr "AmbiguousEndpoints: %s" msgid "" "Application catalog API version, default={0}(Env:" "OS_APPLICATION_CATALOG_API_VERSION)" msgstr "" "Application catalogue API version, default={0}(Env:" "OS_APPLICATION_CATALOG_API_VERSION)" #, python-format msgid "AuthSystemNotFound: %s" msgstr "AuthSystemNotFound: %s" #, python-format msgid "Authentication failed. Missing options: %s" msgstr "Authentication failed. Missing options: %s" msgid "Bad Gateway" msgstr "Bad Gateway" msgid "Bad Request" msgstr "Bad Request" msgid "Cannot find endpoint or token for request" msgstr "Cannot find endpoint or token for request" msgid "Conflict" msgstr "Conflict" msgid "Defaults to env[MURANO_URL]." msgstr "Defaults to env[MURANO_URL]." msgid "Error {0} occurred while setting image {1} public" msgstr "Error {0} occurred while setting image {1} public" msgid "Expectation Failed" msgstr "Expectation Failed" msgid "Forbidden" msgstr "Forbidden" msgid "Gateway Timeout" msgstr "Gateway Timeout" msgid "Gone" msgstr "Gone" msgid "HTTP Client Error" msgstr "HTTP Client Error" msgid "HTTP Error" msgstr "HTTP Error" msgid "HTTP Redirection" msgstr "HTTP Redirection" msgid "HTTP Server Error" msgstr "HTTP Server Error" msgid "HTTP Version Not Supported" msgstr "HTTP Version Not Supported" msgid "Internal Server Error" msgstr "Internal Server Error" #, python-format msgid "" "Invalid %(api_name)s client version '%(version)s'. Must be one of: " "%(version_map)s" msgstr "" "Invalid %(api_name)s client version '%(version)s'. Must be one of: " "%(version_map)s" msgid "Length Required" msgstr "Length Required" msgid "Method Not Allowed" msgstr "Method Not Allowed" #, python-format msgid "Missing arguments: %s" msgstr "Missing arguments: %s" msgid "Multiple Choices" msgstr "Multiple Choices" #, python-format msgid "No %(name)s matching %(args)s." msgstr "No %(name)s matching %(args)s." msgid "Not Acceptable" msgstr "Not Acceptable" msgid "Not Found" msgstr "Not Found" msgid "Not Implemented" msgstr "Not Implemented" msgid "Payment Required" msgstr "Payment Required" msgid "Precondition Failed" msgstr "Precondition Failed" msgid "Proxy Authentication Required" msgstr "Proxy Authentication Required" msgid "Request Entity Too Large" msgstr "Request Entity Too Large" msgid "Request Timeout" msgstr "Request Timeout" msgid "Request-URI Too Long" msgstr "Request-URI Too Long" msgid "Requested Range Not Satisfiable" msgstr "Requested Range Not Satisfiable" msgid "Service Unavailable" msgstr "Service Unavailable" #, python-format msgid "Some attributes are missing in %(pkg_name)s: %(attrs)s." msgstr "Some attributes are missing in %(pkg_name)s: %(attrs)s." msgid "Unauthorized" msgstr "Unauthorised" msgid "Unprocessable Entity" msgstr "Unprocessable Entity" msgid "Unsupported Media Type" msgstr "Unsupported Media Type" python-muranoclient-1.0.1/muranoclient/version.py0000666000175100017510000000127213231416510022313 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from pbr import version version_info = version.VersionInfo('python-muranoclient') python-muranoclient-1.0.1/muranoclient/shell.py0000666000175100017510000005362313231416510021744 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Command-line interface to the Murano Project. """ from __future__ import print_function import argparse import sys import glanceclient from keystoneclient.auth.identity.generic.cli import DefaultCLI from keystoneclient.auth.identity import v3 as identity from keystoneclient import discover from keystoneclient import exceptions as ks_exc from keystoneclient import session as ksession from oslo_log import handlers from oslo_log import log as logging from oslo_log import versionutils from oslo_utils import encodeutils from oslo_utils import importutils import six import six.moves.urllib.parse as urlparse import muranoclient from muranoclient.apiclient import exceptions as exc from muranoclient import client as murano_client from muranoclient.common import utils from muranoclient.glance import client as art_client logger = logging.getLogger(__name__) DEFAULT_REPO_URL = "http://apps.openstack.org/api/v1/murano_repo/liberty/" # quick local fix for keystoneclient bug which blocks built-in reauth # functionality in case of expired token. # bug: https://bugs.launchpad.net/python-keystoneclient/+bug/1551392 # fix: https://review.openstack.org/#/c/286236/ class AuthCLI(DefaultCLI): def invalidate(self): retval = super(AuthCLI, self).invalidate() if self._token: self._token = None retval = True return retval class MuranoShell(object): def _append_global_identity_args(self, parser): # Register the CLI arguments that have moved to the session object. ksession.Session.register_cli_options(parser) identity.Password.register_argparse_arguments(parser) def get_base_parser(self): parser = argparse.ArgumentParser( prog='murano', description=__doc__.strip(), epilog='See "murano help COMMAND" ' 'for help on a specific command.', add_help=False, formatter_class=HelpFormatter, ) # Global arguments parser.add_argument('-h', '--help', action='store_true', help=argparse.SUPPRESS, ) parser.add_argument('--version', action='version', version=muranoclient.__version__, help="Show program's version number and exit.") parser.add_argument('-d', '--debug', default=bool(utils.env('MURANOCLIENT_DEBUG')), action='store_true', help='Defaults to env[MURANOCLIENT_DEBUG].') parser.add_argument('-v', '--verbose', default=False, action="store_true", help="Print more verbose output.") # os-cert, os-key, insecure, ca-file are all added # by keystone session register_cli_opts later parser.add_argument('--cert-file', dest='os_cert', help='DEPRECATED! Use --os-cert.') parser.add_argument('--key-file', dest='os_key', help='DEPRECATED! Use --os-key.') parser.add_argument('--ca-file', dest='os_cacert', help='DEPRECATED! Use --os-cacert.') parser.add_argument('--api-timeout', help='Number of seconds to wait for an ' 'API response, ' 'defaults to system socket timeout.') parser.add_argument('--os-tenant-id', default=utils.env('OS_TENANT_ID'), help='Defaults to env[OS_TENANT_ID].') parser.add_argument('--os-tenant-name', default=utils.env('OS_TENANT_NAME'), help='Defaults to env[OS_TENANT_NAME].') parser.add_argument('--os-region-name', default=utils.env('OS_REGION_NAME'), help='Defaults to env[OS_REGION_NAME].') parser.add_argument('--os-auth-token', default=utils.env('OS_AUTH_TOKEN'), help='Defaults to env[OS_AUTH_TOKEN].') parser.add_argument('--os-no-client-auth', default=utils.env('OS_NO_CLIENT_AUTH'), action='store_true', help="Do not contact keystone for a token. " "Defaults to env[OS_NO_CLIENT_AUTH].") parser.add_argument('--murano-url', default=utils.env('MURANO_URL'), help='Defaults to env[MURANO_URL].') parser.add_argument('--glance-url', default=utils.env('GLANCE_URL'), help='Defaults to env[GLANCE_URL].') parser.add_argument('--glare-url', default=utils.env('GLARE_URL'), help='Defaults to env[GLARE_URL].') parser.add_argument('--murano-api-version', default=utils.env( 'MURANO_API_VERSION', default='1'), help='Defaults to env[MURANO_API_VERSION] ' 'or 1.') parser.add_argument('--os-service-type', default=utils.env('OS_SERVICE_TYPE'), help='Defaults to env[OS_SERVICE_TYPE].') parser.add_argument('--os-endpoint-type', default=utils.env('OS_ENDPOINT_TYPE'), help='Defaults to env[OS_ENDPOINT_TYPE].') parser.add_argument('--include-password', default=bool(utils.env('MURANO_INCLUDE_PASSWORD')), action='store_true', help='Send os-username and os-password to murano.') parser.add_argument('--murano-repo-url', default=utils.env( 'MURANO_REPO_URL', default=DEFAULT_REPO_URL), help=('Defaults to env[MURANO_REPO_URL] ' 'or {0}'.format(DEFAULT_REPO_URL))) parser.add_argument('--murano-packages-service', choices=['murano', 'glance', 'glare'], default=utils.env('MURANO_PACKAGES_SERVICE', default='murano'), help='Specifies if murano-api ("murano") or ' 'Glance Artifact Repository ("glare") ' 'should be used to store murano packages. ' 'Defaults to env[MURANO_PACKAGES_SERVICE] or ' 'to "murano"') self._append_global_identity_args(parser) return parser def get_subcommand_parser(self, version): parser = self.get_base_parser() self.subcommands = {} subparsers = parser.add_subparsers(metavar='') submodule = importutils.import_versioned_module('muranoclient', version, 'shell') self._find_actions(subparsers, submodule) self._find_actions(subparsers, self) return parser def _find_actions(self, subparsers, actions_module): for attr in (a for a in dir(actions_module) if a.startswith('do_')): # I prefer to be hypen-separated instead of underscores. command = attr[3:].replace('_', '-') callback = getattr(actions_module, attr) desc = callback.__doc__ or '' help = desc.strip().split('\n')[0] arguments = getattr(callback, 'arguments', []) subparser = subparsers.add_parser(command, help=help, description=desc, add_help=False, formatter_class=HelpFormatter) subparser.add_argument('-h', '--help', action='help', help=argparse.SUPPRESS) self.subcommands[command] = subparser for (args, kwargs) in arguments: subparser.add_argument(*args, **kwargs) subparser.set_defaults(func=callback) def _discover_auth_versions(self, session, auth_url): # discover the API versions the server is supporting base on the # given URL v2_auth_url = None v3_auth_url = None try: ks_discover = discover.Discover(session=session, auth_url=auth_url) v2_auth_url = ks_discover.url_for('2.0') v3_auth_url = ks_discover.url_for('3.0') except ks_exc.ClientException as e: # Identity service may not support discover API version. # Lets trying to figure out the API version from the original URL. url_parts = urlparse.urlparse(auth_url) (scheme, netloc, path, params, query, fragment) = url_parts path = path.lower() if path.startswith('/v3'): v3_auth_url = auth_url elif path.startswith('/v2'): v2_auth_url = auth_url else: # not enough information to determine the auth version msg = ('Unable to determine the Keystone version ' 'to authenticate with using the given ' 'auth_url. Identity service may not support API ' 'version discovery. Please provide a versioned ' 'auth_url instead. error=%s') % (e) raise exc.CommandError(msg) return (v2_auth_url, v3_auth_url) def _setup_logging(self, debug): # Output the logs to command-line interface color_handler = handlers.ColorHandler(sys.stdout) logger_root = logging.getLogger(None).logger logger_root.level = logging.DEBUG if debug else logging.WARNING logger_root.addHandler(color_handler) # Set the logger level of special library logging.getLogger('iso8601') \ .logger.setLevel(logging.WARNING) logging.getLogger('urllib3.connectionpool') \ .logger.setLevel(logging.WARNING) def main(self, argv): # Parse args once to find version parser = self.get_base_parser() (options, args) = parser.parse_known_args(argv) self._setup_logging(options.debug) # build available subcommands based on version api_version = options.murano_api_version subcommand_parser = self.get_subcommand_parser(api_version) self.parser = subcommand_parser keystone_session = None keystone_auth = None # Handle top-level --help/-h before attempting to parse # a command off the command line. if (not args and options.help) or not argv: self.do_help(options) return 0 # Parse args again and call whatever callback was selected. args = subcommand_parser.parse_args(argv) # Short-circuit and deal with help command right away. if args.func == self.do_help: self.do_help(args) return 0 elif args.func == self.do_bash_completion: self.do_bash_completion(args) return 0 if not args.os_username and not args.os_auth_token: raise exc.CommandError("You must provide a username via" " either --os-username or env[OS_USERNAME]" " or a token via --os-auth-token or" " env[OS_AUTH_TOKEN]") if args.murano_packages_service == 'glance': args.murano_packages_service = 'glare' # TODO(kzaitsev): remove in P cycle versionutils.report_deprecated_feature( logger, "'glance' is no longer a valid option for " "--murano-packages-service, please use 'glare' " "instead.") if args.os_no_client_auth: if not args.murano_url: raise exc.CommandError( "If you specify --os-no-client-auth" " you must also specify a Murano API URL" " via either --murano-url or env[MURANO_URL]") if (not args.glare_url and args.murano_packages_service == 'glare'): raise exc.CommandError( "If you specify --os-no-client-auth and" " set murano-packages-service to 'glare'" " you must also specify a glare API URL" " via either --glare-url or env[GLARE_API]") if (not any([args.os_tenant_id, args.os_project_id]) and args.murano_packages_service == 'glare'): # TODO(kzaitsev): see if we can use project's name here # NOTE(kzaitsev): glare v0.1 needs project_id to operate # correctly raise exc.CommandError( "If you specify --os-no-client-auth and" " set murano-packages-service to 'glare'" " you must also specify your project's id" " via either --os-project-id or env[OS_PROJECT_ID] or" " --os-tenant-id or env[OS_TENANT_ID]") else: # Tenant name or ID is needed to make keystoneclient retrieve a # service catalog, it's not required if os_no_client_auth is # specified, neither is the auth URL. if not any([args.os_tenant_name, args.os_tenant_id, args.os_project_id, args.os_project_name]): raise exc.CommandError("You must provide a project name or" " project id via --os-project-name," " --os-project-id, env[OS_PROJECT_ID]" " or env[OS_PROJECT_NAME]. You may" " use os-project and os-tenant" " interchangeably.") if not args.os_auth_url: raise exc.CommandError("You must provide an auth url via" " either --os-auth-url or via" " env[OS_AUTH_URL]") endpoint_type = args.os_endpoint_type or 'publicURL' endpoint = args.murano_url glance_endpoint = args.glance_url if args.os_no_client_auth: # Authenticate through murano, don't use session kwargs = { 'username': args.os_username, 'password': args.os_password, 'auth_token': args.os_auth_token, 'auth_url': args.os_auth_url, 'token': args.os_auth_token, 'insecure': args.insecure, 'timeout': args.api_timeout, 'tenant': args.os_project_id or args.os_tenant_id, } glance_kwargs = kwargs.copy() if args.os_region_name: kwargs['region_name'] = args.os_region_name glance_kwargs['region_name'] = args.os_region_name else: # Create a keystone session and keystone auth keystone_session = ksession.Session.load_from_cli_options(args) args.os_project_name = args.os_project_name or args.os_tenant_name args.os_project_id = args.os_project_id or args.os_tenant_id # make args compatible with DefaultCLI/AuthCLI args.os_token = args.os_auth_token args.os_endpoint = '' # avoid password prompt if no password given args.os_password = args.os_password or '' (v2_auth_url, v3_auth_url) = self._discover_auth_versions( keystone_session, args.os_auth_url) if v3_auth_url: if (not args.os_user_domain_id and not args.os_user_domain_name): args.os_user_domain_name = 'default' if (not args.os_project_domain_id and not args.os_project_domain_name): args.os_project_domain_name = 'default' keystone_auth = AuthCLI.load_from_argparse_arguments(args) service_type = args.os_service_type or 'application-catalog' if not endpoint: endpoint = keystone_auth.get_endpoint( keystone_session, service_type=service_type, interface=endpoint_type, region_name=args.os_region_name) kwargs = { 'session': keystone_session, 'auth': keystone_auth, 'service_type': service_type, 'region_name': args.os_region_name, } glance_kwargs = kwargs.copy() # glance doesn't need endpoint_type kwargs['endpoint_type'] = endpoint_type kwargs['tenant'] = keystone_auth.get_project_id(keystone_session) if args.api_timeout: kwargs['timeout'] = args.api_timeout if not glance_endpoint: try: glance_endpoint = keystone_auth.get_endpoint( keystone_session, service_type='image', interface=endpoint_type, region_name=args.os_region_name) except Exception: pass glance_client = None if glance_endpoint: try: # TODO(starodubcevna): switch back to glance APIv2 when it will # be ready for use. glance_client = glanceclient.Client( '1', glance_endpoint, **glance_kwargs) except Exception: pass if glance_client: kwargs['glance_client'] = glance_client else: logger.warning("Could not initialize glance client. " "Image creation will be unavailable.") kwargs['glance_client'] = None if args.murano_packages_service == 'glare': glare_endpoint = args.glare_url if not glare_endpoint: # no glare_endpoint and we requested to store packages in glare # let's check keystone try: glare_endpoint = keystone_auth.get_endpoint( keystone_session, service_type='artifact', interface=endpoint_type, region_name=args.os_region_name) except Exception: raise exc.CommandError( "You set murano-packages-service to {}" " but there is not 'artifact' endpoint in keystone" " Either register one or specify endpoint " " via either --glare-url or env[GLARE_API]".format( args.murano_packages_service)) auth_token = \ args.os_auth_token or keystone_auth.get_token(keystone_session) artifacts_client = art_client.Client(endpoint=glare_endpoint, type_name='murano', type_version=1, token=auth_token, insecure=args.insecure) kwargs['artifacts_client'] = artifacts_client client = murano_client.Client(api_version, endpoint, **kwargs) args.func(client, args) def do_bash_completion(self, args): """Prints all of the commands and options to stdout.""" commands = set() options = set() for sc_str, sc in self.subcommands.items(): commands.add(sc_str) for option in list(sc._optionals._option_string_actions): options.add(option) commands.remove('bash-completion') print(' '.join(commands | options)) @utils.arg('command', metavar='', nargs='?', help='Display help for ') def do_help(self, args): """Display help about this program or one of its subcommands.""" if getattr(args, 'command', None): if args.command in self.subcommands: self.subcommands[args.command].print_help() else: msg = "'%s' is not a valid subcommand" raise exc.CommandError(msg % args.command) else: self.parser.print_help() class HelpFormatter(argparse.HelpFormatter): def start_section(self, heading): # Title-case the headings heading = '%s%s' % (heading[0].upper(), heading[1:]) super(HelpFormatter, self).start_section(heading) def main(args=sys.argv[1:]): try: MuranoShell().main(args) except KeyboardInterrupt: print('... terminating murano client', file=sys.stderr) sys.exit(1) except Exception as e: if '--debug' in args or '-d' in args: raise else: print(encodeutils.safe_encode(six.text_type(e)), file=sys.stderr) sys.exit(1) if __name__ == "__main__": main() python-muranoclient-1.0.1/muranoclient/client.py0000666000175100017510000000161313231416510022103 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from oslo_utils import importutils def Client(version, *args, **kwargs): module = importutils.import_versioned_module('muranoclient', version, 'client') client_class = getattr(module, 'Client') return client_class(*args, **kwargs) python-muranoclient-1.0.1/muranoclient/v1/0000775000175100017510000000000013231417024020577 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/v1/categories.py0000666000175100017510000000363113231416510023302 0ustar zuulzuul00000000000000# Copyright (c) 2015 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from six.moves import urllib from muranoclient.common import base class Category(base.Resource): def __repr__(self): return "" % self._info def data(self, **kwargs): return self.manager.data(self, **kwargs) class CategoryManager(base.Manager): resource_class = Category def list(self, **kwargs): """Get category list with pagination support. :param sort_keys: an array of fields used to sort the list (string) :param sort_dir: 'asc' or 'desc' for ascending or descending sort :param limit: maximum number of categories to return :param marker: begin returning categories that appear later in the category list than that represented by this marker id """ params = {} for key, value in kwargs.items(): if value: params[key] = value url = '/v1/catalog/categories?{0}'.format( urllib.parse.urlencode(params, True)) return self._list(url, response_key='categories') def get(self, id): return self._get('/v1/catalog/categories/{0}'.format(id)) def add(self, data): return self._create('/v1/catalog/categories', data) def delete(self, id): return self._delete('/v1/catalog/categories/{0}'.format(id)) python-muranoclient-1.0.1/muranoclient/v1/services.py0000666000175100017510000000641413231416510023002 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import functools import posixpath from muranoclient.common import base def normalize_path(f): @functools.wraps(f) def f_normalize_path(*args, **kwargs): path = args[2] if len(args) >= 3 else kwargs['path'] # path formally is just absolute unix path if not posixpath.isabs(path): raise ValueError("Parameter 'path' should start with '/'") args = list(args) if len(args) >= 3: args[2] = args[2][1:] else: kwargs['path'] = kwargs['path'][1:] return f(*args, **kwargs) return f_normalize_path class Service(base.Resource): def __repr__(self): return '' % self._info def data(self, **kwargs): return self.manager.data(self, **kwargs) def _add_details(self, info): if isinstance(info, dict): for k, v in info.items(): setattr(self, k, v) class ServiceManager(base.Manager): resource_class = Service def list(self, environment_id, session_id=None): if session_id: headers = {'X-Configuration-Session': session_id} else: headers = {} return self._list("/v1/environments/{0}/services". format(environment_id), headers=headers) @normalize_path def get(self, environment_id, path, session_id=None): if session_id: headers = {'X-Configuration-Session': session_id} else: headers = {} return self._get('/v1/environments/{0}/services/{1}'. format(environment_id, path), headers=headers) @normalize_path def post(self, environment_id, path, data, session_id): headers = {'X-Configuration-Session': session_id} result = self._create('/v1/environments/{0}/services/{1}'. format(environment_id, path), data, headers=headers, return_raw=True) if isinstance(result, list): return [self.resource_class(self, item) for item in result] else: return self.resource_class(self, result) @normalize_path def put(self, environment_id, path, data, session_id): headers = {'X-Configuration-Session': session_id} return self._update('/v1/environments/{0}/services/{1}'. format(environment_id, path), data, headers=headers) @normalize_path def delete(self, environment_id, path, session_id): headers = {'X-Configuration-Session': session_id} path = '/v1/environments/{0}/services/{1}'.format(environment_id, path) return self._delete(path, headers=headers) python-muranoclient-1.0.1/muranoclient/v1/deployments.py0000666000175100017510000000355413231416510023524 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from muranoclient.common import base class Deployment(base.Resource): def __repr__(self): return '' % self._info def data(self, **kwargs): return self.manager.data(self, **kwargs) class Status(base.Resource): def __repr__(self): return '' % self._info def data(self, **kwargs): return self.manager.data(self, **kwargs) class DeploymentManager(base.Manager): resource_class = Deployment def list(self, environment_id, all_environments=False): if all_environments: return self._list('/v1/deployments', 'deployments') else: return self._list('/v1/environments/{id}/deployments'. format(id=environment_id), 'deployments') def reports(self, environment_id, deployment_id, *service_ids): path = '/v1/environments/{id}/deployments/{deployment_id}' path = path.format(id=environment_id, deployment_id=deployment_id) if service_ids: for service_id in service_ids: path += '?service_id={0}'.format(service_id) resp, body = self.api.json_request(path, 'GET') data = body.get('reports', []) return [Status(self, res, loaded=True) for res in data if res] python-muranoclient-1.0.1/muranoclient/v1/package_creator/0000775000175100017510000000000013231417024023711 5ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/v1/package_creator/mpl_package.py0000666000175100017510000001767613231416510026550 0ustar zuulzuul00000000000000# Copyright (c) 2014 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import os import shutil import tempfile import yaml import muranoclient from muranoclient.apiclient import exceptions from muranoclient.common import utils def prepare_package(args): """Prepare for application package Prepare all files and directories for that application package. Generates manifest file and all required parameters for that. :param args: list of command line arguments :returns: absolute path to directory with prepared files """ if args.type and args.type not in ['Application', 'Library']: raise exceptions.CommandError( "--type should be set to 'Application' or 'Library'") manifest = generate_manifest(args) if args.type == 'Application': if not args.ui: raise exceptions.CommandError("'--ui' is required parameter") if not os.path.exists(args.ui) or not os.path.isfile(args.ui): raise exceptions.CommandError( "{0} is not a file or doesn`t exist".format(args.ui)) temp_dir = tempfile.mkdtemp() manifest_file = os.path.join(temp_dir, 'manifest.yaml') classes_directory = os.path.join(temp_dir, 'Classes') resource_directory = os.path.join(temp_dir, 'Resources') with open(manifest_file, 'w') as f: f.write(yaml.dump(manifest, default_flow_style=False)) logo_file = os.path.join(temp_dir, 'logo.png') if not args.logo or(args.logo and not os.path.isfile(args.logo)): shutil.copyfile(muranoclient.get_resource('mpl_logo.png'), logo_file) else: shutil.copyfile(args.logo, logo_file) shutil.copytree(args.classes_dir, classes_directory) if args.resources_dir: if not os.path.isdir(args.resources_dir): raise exceptions.CommandError( "'--resources-dir' parameter should be a directory") shutil.copytree(args.resources_dir, resource_directory) if args.ui: ui_directory = os.path.join(temp_dir, 'UI') os.mkdir(ui_directory) shutil.copyfile(args.ui, os.path.join(ui_directory, 'ui.yaml')) return temp_dir def generate_manifest(args): """Generates application manifest file. If some parameters are missed - they we be generated automatically. :param args: :returns: dictionary, contains manifest file data """ if not os.path.isdir(args.classes_dir): raise exceptions.CommandError( "'--classes-dir' parameter should be a directory") args = update_args(args) if not args.type: raise exceptions.CommandError( "Too few arguments: --type and --full-name is required") if not args.author: args.author = args.os_username if not args.description: args.description = "Description for the application is not provided" if not args.full_name: raise exceptions.CommandError( "Please, provide --full-name parameter") manifest = { 'Format': 'MuranoPL/1.0', 'Type': args.type, 'FullName': args.full_name, 'Name': args.name, 'Description': args.description, 'Author': args.author, 'Classes': args.classes } if args.tags: manifest['Tags'] = args.tags return manifest def update_args(args): """Add and update arguments if possible. Some parameters are not required and would be guessed from muranoPL classes: thus, if class extends system application class fully qualified and require names could be calculated. Also, in that case type of a package could be set to 'Application'. """ classes = {} extends_from_application = False for root, dirs, files in os.walk(args.classes_dir): for class_file in files: class_file_path = os.path.join(root, class_file) try: with open(class_file_path) as f: content = yaml.load(f, utils.YaqlYamlLoader) if not content.get('Name'): raise exceptions.CommandError( "Error in class definition: 'Name' " "section is required") class_name = get_fqn_for_name(content.get('Namespaces'), content['Name']) if root == args.classes_dir: relative_path = class_file else: relative_path = os.path.join( root.replace(args.classes_dir, "")[1:], class_file) classes[class_name] = relative_path extends_from_application = check_derived_from_application( content, extends_from_application) if extends_from_application: if not args.type: args.type = 'Application' if not args.name: args.name = class_name.split('.')[-1] if not args.full_name: args.full_name = class_name except yaml.YAMLError: raise exceptions.CommandError( "MuranoPL class {0} should be" " a valid yaml file".format(class_file_path)) except IOError: raise exceptions.CommandError( "Could not open file {0}".format(class_file_path)) if not classes: raise exceptions.CommandError("Application should have " "at least one class") args.classes = classes return args def get_fqn_for_name(namespaces, name): """Analyze name for namespace reference. If namespaces are used - return a full name :param namespaces: content of 'Namespaces' section of muranoPL class :param name: name that should be checked :returns: generated name according to namespaces """ values = name.split(':') if len(values) == 1: if '=' in namespaces: return namespaces['='] + '.' + values[0] return values[0] if len(values) > 2: raise exceptions.CommandError( "Error in class definition: Wrong usage of ':' is " "reserved for namespace referencing and could " "be used only once " "for each name") if not namespaces: raise exceptions.CommandError( "Error in {0} class definition: " "'Namespaces' section is missed") result = namespaces.get(values[0]) if not result: raise exceptions.CommandError( "Error in class definition: namespaces " "reference is not correct at the 'Extends'" " section") return result + '.' + values[1] def check_derived_from_application(content, extends_from_application): """Look up for system 'io.murano.Application' class in extends section""" if content.get('Extends'): extends = content['Extends'] if not isinstance(extends, list): extends = [extends] for name in extends: parent_class_name = get_fqn_for_name( content.get('Namespaces'), name) if parent_class_name == 'io.murano.Application': if not extends_from_application: return True else: raise exceptions.CommandError( "Murano package should have only one class" " extends 'io.murano.Application' class") return False python-muranoclient-1.0.1/muranoclient/v1/package_creator/__init__.py0000666000175100017510000000000013231416510026011 0ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/v1/package_creator/hot_package.py0000666000175100017510000000676613231416510026550 0ustar zuulzuul00000000000000# Copyright (c) 2014 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import os import shutil import tempfile import yaml import muranoclient from muranoclient.apiclient import exceptions def generate_manifest(args): """Generates application manifest file. If some parameters are missed - they we be generated automatically. :param args: :returns: dictionary, contains manifest file data """ if not os.path.isfile(args.template): raise exceptions.CommandError( "Template '{0}' doesn`t exist".format(args.template)) filename = os.path.basename(args.template) if not args.name: args.name = os.path.splitext(filename)[0] if not args.full_name: prefix = 'io.murano.apps.generated' normalized_name = args.name.replace('_', ' ').replace('-', ' ') normalized_name = normalized_name.title().replace(' ', '') args.full_name = '{0}.{1}'.format(prefix, normalized_name) try: with open(args.template, 'rb') as heat_file: yaml_content = yaml.safe_load(heat_file) if not args.description: args.description = yaml_content.get( 'description', 'Heat-defined application for a template "{0}"'.format( filename)) except yaml.YAMLError: raise exceptions.CommandError( "Heat template, represented by --'template' parameter" " should be a valid yaml file") if not args.author: args.author = args.os_username if not args.tags: args.tags = ['Heat-generated'] manifest = { 'Format': 'Heat.HOT/1.0', 'Type': 'Application', 'FullName': args.full_name, 'Name': args.name, 'Description': args.description, 'Author': args.author, 'Tags': args.tags } return manifest def prepare_package(args): """Compose required files for murano application package. :param args: list of command line arguments :returns: absolute path to directory with prepared files """ manifest = generate_manifest(args) temp_dir = tempfile.mkdtemp() manifest_file = os.path.join(temp_dir, 'manifest.yaml') template_file = os.path.join(temp_dir, 'template.yaml') if args.resources_dir: if not os.path.isdir(args.resources_dir): raise exceptions.CommandError( "'--resources-dir' parameter should be a directory") resource_directory = os.path.join(temp_dir, 'Resources') shutil.copytree(args.resources_dir, resource_directory) logo_file = os.path.join(temp_dir, 'logo.png') if not args.logo: shutil.copyfile(muranoclient.get_resource('heat_logo.png'), logo_file) else: if os.path.isfile(args.logo): shutil.copyfile(args.logo, logo_file) with open(manifest_file, 'w') as f: f.write(yaml.dump(manifest, default_flow_style=False)) shutil.copyfile(args.template, template_file) return temp_dir python-muranoclient-1.0.1/muranoclient/v1/artifact_packages.py0000666000175100017510000003100213231416510024601 0ustar zuulzuul00000000000000# Copyright (c) 2015 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import collections from glanceclient import exc as glance_exc import yaml from muranoclient.common import exceptions as exc from muranoclient.common import utils from muranoclient.i18n import _ def rewrap_http_exceptions(func): def inner(*args, **kwargs): try: return func(*args, **kwargs) except glance_exc.HTTPException as e: raise exc.from_code(e.code) return inner class ArtifactRepo(object): def __init__(self, client, tenant=None): self.tenant = tenant self.client = client def create(self, fqn, data, **kwargs): package = utils.Package.from_file(data) manifest = package.manifest package_draft = { 'name': manifest.get('FullName', fqn), 'version': manifest.get('Version', '0.0.0'), 'description': manifest.get('Description'), 'display_name': manifest.get('Name', fqn), 'type': manifest.get('Type', 'Application'), 'author': manifest.get('Author'), 'tags': manifest.get('Tags', []), 'class_definitions': package.classes.keys() } for k, v in kwargs.items(): package_draft[k] = v inherits = self._get_local_inheritance(package.classes, package.resolvers) # check for global inheritance ancestor_queue = collections.deque(inherits.keys()) while ancestor_queue: ancestor_name = ancestor_queue.popleft() child_classes = inherits[ancestor_name] ancestors = self.list(class_definitions=ancestor_name) for ancestor in ancestors: # check if ancestor inherits anything ancestor_inherits = \ ancestor.type_specific_properties.get('inherits', {}) for name, value in ancestor_inherits.items(): # check if this is the class we actually inherit if ancestor_name in value: ancestor_queue.append(name) inherits[name] = child_classes package_draft['inherits'] = inherits keywords = self._keywords_from_display_name( package_draft['display_name']) keywords.extend(package_draft['tags']) package_draft['keywords'] = keywords # NOTE(ativelkov): this is very racy, but until we have a chance to # enforce uniqueness right in glance this is the only way to do it visibility = package_draft.get('visibility', 'private') if visibility == 'public': filters = {} else: filters = {'owner': self.tenant} existing = self.list(name=package_draft['name'], version=package_draft['version'], **filters) try: next(existing) raise exc.HTTPConflict("Package already exists") except StopIteration: pass res = self.client.artifacts.create(**package_draft) app_id = res.id self.client.artifacts.upload_blob(app_id, 'archive', package.file()) if package.logo is not None: self.client.artifacts.upload_blob(app_id, 'logo', package.logo) if package.ui is not None: self.client.artifacts.upload_blob(app_id, 'ui_definition', package.ui) package.file().close() self.client.artifacts.active(app_id) return self.client.artifacts.get(app_id) @staticmethod def _get_local_inheritance(classes, resolvers): result = {} for class_name, klass in classes.items(): if 'Extends' not in klass: continue ns = klass.get('Namespaces') if ns: resolver = utils.NamespaceResolver(ns) else: resolver = resolvers.get(class_name) if isinstance(klass['Extends'], list): bases = klass['Extends'] else: bases = [klass['Extends']] for base_class in bases: if resolver: base_fqn = resolver.resolve_name(base_class) else: base_fqn = base_class result.setdefault(base_fqn, []).append(class_name) return result @staticmethod def _keywords_from_display_name(display_name): return display_name.split()[:10] def list(self, sort_field='name', sort_dir='asc', type=None, tags=None, limit=None, page_size=None, **filters): sort = "%s:%s" % (sort_field, sort_dir) if type is not None: filters['type'] = type if tags is not None: filters['tag'] = tags return self.client.artifacts.list(sort=sort, limit=limit, page_size=page_size, filters=filters) def get(self, app_id): return self.client.artifacts.get(app_id) def delete(self, app_id): return self.client.artifacts.delete(app_id) def update(self, app_id, props_to_remove=None, **new_props): new_keywords = [] new_name = new_props.get('display_name') new_tags = new_props.get('tags') if new_name: new_keywords.extend(self._keywords_from_display_name(new_name)) if new_tags: new_keywords.extend(new_tags) if new_keywords: new_props['keywords'] = new_keywords visibility = new_props.get('visibility') if visibility == 'public': package = self.client.artifacts.get(app_id) # NOTE(ativelkov): this is very racy, but until we have a chance to # enforce uniqueness right in glance this is the only way to do it existing = self.list(name=package.name, version=package.version, visibility='public') try: while True: package = next(existing) if package.id == app_id: continue else: raise exc.HTTPConflict("Package already exists") except StopIteration: pass return self.client.artifacts.update(app_id, remove_props=props_to_remove, **new_props) def toggle_active(self, app_id): old_val = self.get(app_id).type_specific_properties['enabled'] return self.update(app_id, enabled=(not old_val)) def toggle_public(self, app_id): visibility = self.get(app_id).visibility if visibility == 'public': return self.update(app_id, visibility='private') else: return self.update(app_id, visibility='public') def download(self, app_id): return self.client.artifacts.download_blob(app_id, 'archive') def get_ui(self, app_id, loader_cls=None): ui_stream = "".join( self.client.artifacts.download_blob(app_id, 'ui_definition')) if loader_cls is None: loader_cls = yaml.SafeLoader return yaml.load(ui_stream, loader_cls) def get_logo(self, app_id): return self.client.artifacts.download_blob(app_id, 'logo') class PackageManagerAdapter(object): def __init__(self, legacy, glare): self.legacy = legacy self.glare = glare def categories(self): return self.legacy.categories() @rewrap_http_exceptions def create(self, data, files): is_public = data.pop('is_public', None) if is_public is not None: data['visibility'] = 'public' if is_public else 'private' fqn = list(files.keys())[0] pkg = self.glare.create(fqn, files[fqn], **data) return PackageWrapper(pkg) @rewrap_http_exceptions def filter(self, **kwargs): kwargs.pop('catalog', None) # NOTE(ativelkov): Glare ignores 'catalog' include_disabled = kwargs.pop('include_disabled', False) order_by = kwargs.pop('order_by', None) search = kwargs.pop('search', None) category = kwargs.pop('category', None) fqn = kwargs.pop('fqn', None) class_name = kwargs.pop('class_name', None) name = kwargs.pop('name', None) if category: kwargs['categories'] = category if search: kwargs['keywords'] = search if order_by: kwargs['sort_field'] = order_by if not include_disabled: kwargs['enabled'] = True if fqn: kwargs['name'] = fqn if class_name: kwargs['class_definitions'] = class_name if name: kwargs['display_name'] = name # if 'owned' is used there should be a filter with 'owner' parameter if kwargs.pop('owned', None): kwargs['owner'] = self.glare.tenant for pkg in self.glare.list(**kwargs): yield PackageWrapper(pkg) @rewrap_http_exceptions def list(self, include_disabled=False): return self.filter(include_disabled=include_disabled) @rewrap_http_exceptions def delete(self, app_id): return self.glare.delete(app_id) @rewrap_http_exceptions def get(self, app_id): return PackageWrapper(self.glare.get(app_id)) @rewrap_http_exceptions def update(self, app_id, body, operation='replace'): is_public = body.pop('is_public', None) name = body.pop('name', None) if is_public is not None: body['visibility'] = 'public' if is_public else 'private' if name is not None: body['display_name'] = name if operation == 'replace': return PackageWrapper(self.glare.update(app_id, None, **body)) @rewrap_http_exceptions def toggle_active(self, app_id): return self.glare.toggle_active(app_id) @rewrap_http_exceptions def toggle_public(self, app_id): return self.glare.toggle_public(app_id) @rewrap_http_exceptions def download(self, app_id): return "".join(self.glare.download(app_id)) @rewrap_http_exceptions def get_logo(self, app_id): return "".join(self.glare.get_logo(app_id)) @rewrap_http_exceptions def get_ui(self, app_id, loader_cls=None): return self.legacy.get_ui(app_id, loader_cls) class PackageWrapper(object): def __init__(self, item): self._item = item @property def updated(self): return self._item.updated_at @property def created(self): return self._item.created_at @property def is_public(self): return self._item.visibility == 'public' @property def name(self): return self._item.type_specific_properties['display_name'] @property def fully_qualified_name(self): return self._item.name @property def owner_id(self): return self._item.owner def __getstate__(self): return {"item": self._item} def __setstate__(self, state): self._item = state['item'] def __getattr__(self, name): if name in self._item.type_specific_properties: return self._item.type_specific_properties.get(name) else: return getattr(self._item, name) def to_dict(self): keys = ('author', 'categories', 'class_definitions', 'created', 'description', 'enabled', 'fully_qualified_name', 'id', 'is_public', 'name', 'owner_id', 'tags', 'type', 'updated') missing_keys = [key for key in keys if not hasattr(self, key)] if missing_keys: raise KeyError(_("Some attributes are missing in " "%(pkg_name)s: %(attrs)s.") % {'pkg_name': self.name, 'attrs': ", ".join(missing_keys)}) return {key: getattr(self, key) for key in keys} python-muranoclient-1.0.1/muranoclient/v1/static_actions.py0000666000175100017510000000262613231416510024167 0ustar zuulzuul00000000000000# Copyright (c) 2016 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. class StaticActionResult(object): def __init__(self, result, exception=None): self._result = result self._exception = exception def get_result(self): if self._exception: raise self._exception return self._result def check_result(self): return True # Not a true manager yet; should be changed to be one if CRUD # functionality becomes available for actions. class StaticActionManager(object): def __init__(self, api): self.api = api def call(self, arguments): url = '/v1/actions' try: resp, body = self.api.json_request(url, 'POST', data=arguments) return StaticActionResult(body) except Exception as e: if e.code >= 500: raise return StaticActionResult(None, exception=e) python-muranoclient-1.0.1/muranoclient/v1/request_statistics.py0000666000175100017510000000174613231416510025124 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from muranoclient.common import base class RequestStatistics(base.Resource): def __repr__(self): return "" % self._info def data(self, **kwargs): return self.manager.data(self, **kwargs) class RequestStatisticsManager(base.Manager): resource_class = RequestStatistics def list(self): return self._list('/v1/stats') python-muranoclient-1.0.1/muranoclient/v1/shell.py0000666000175100017510000014067113231416510022272 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import collections import functools import itertools import json import os import shutil import sys import tempfile import zipfile import jsonpatch from oslo_utils import strutils from oslo_utils import uuidutils import six.moves from muranoclient.apiclient import exceptions from muranoclient.common import exceptions as common_exceptions from muranoclient.common import utils from muranoclient.v1.package_creator import hot_package from muranoclient.v1.package_creator import mpl_package _bool_from_str_strict = functools.partial( strutils.bool_from_string, strict=True) @utils.arg('--all-tenants', action='store_true', default=False, help='Allows to list environments from all tenants' ' (admin only).') @utils.arg('--tenant', metavar="", default=None, help='Allows to list environments for a given tenant' ' (admin only).') def do_environment_list(mc, args=None): """List the environments.""" if args is None: args = {} all_tenants = getattr(args, 'all_tenants', False) tenant = getattr(args, 'tenant', None) environments = mc.environments.list(all_tenants, tenant) _print_environment_list(environments) def _print_environment_list(environments): field_labels = ['ID', 'Name', 'Status', 'Created', 'Updated'] fields = ['id', 'name', 'status', 'created', 'updated'] utils.print_list(environments, fields, field_labels, sortby=0) def _generate_join_existing_net(net, subnet): res = { 'defaultNetworks': { 'environment': { '?': { 'id': uuidutils.generate_uuid(dashed=False), 'type': 'io.murano.resources.ExistingNeutronNetwork' }, }, 'flat': None } } if net: res['defaultNetworks']['environment']['internalNetworkName'] = net if subnet: res['defaultNetworks']['environment']['internalSubnetworkName'] = \ subnet return res @utils.arg("--join-net-id", metavar="", help="Network id to join.",) @utils.arg("--join-subnet-id", metavar="", help="Subnetwork id to join.",) @utils.arg("--region", metavar="", help="Name of the target OpenStack region.",) @utils.arg("name", metavar="", help="Environment name.") def do_environment_create(mc, args): """Create an environment.""" body = {"name": args.name, "region": args.region} if args.join_net_id or args.join_subnet_id: body.update(_generate_join_existing_net( args.join_net_id, args.join_subnet_id)) environment = mc.environments.create(body) _print_environment_list([environment]) @utils.arg("id", metavar="", nargs="+", help="Id or name of environment(s) to delete.") @utils.arg('--abandon', action='store_true', default=False, help='If set will abandon environment without deleting any' ' of its resources.') def do_environment_delete(mc, args): """Delete an environment.""" abandon = getattr(args, 'abandon', False) failure_count = 0 for environment_id in args.id: try: environment = utils.find_resource(mc.environments, environment_id) mc.environments.delete(environment.id, abandon) except exceptions.NotFound: failure_count += 1 print("Failed to delete '{0}'; environment not found". format(environment_id)) if failure_count == len(args.id): raise exceptions.CommandError("Unable to find and delete any of the " "specified environments.") do_environment_list(mc) @utils.arg("id", metavar="", help="Environment ID or name.") @utils.arg("name", metavar="", help="A name to which the environment will be renamed.") def do_environment_rename(mc, args): """Rename an environment.""" try: environment = utils.find_resource(mc.environments, args.id) environment = mc.environments.update(environment.id, args.name) except exceptions.NotFound: raise exceptions.CommandError("Environment %s not found" % args.id) else: _print_environment_list([environment]) @utils.arg("id", metavar="", help="Environment ID or name.") @utils.arg("--session-id", metavar="", default='', help="Id of a config session.") @utils.arg("--only-apps", action='store_true', help="Only print apps of the environment (useful for automation).") def do_environment_show(mc, args): """Display environment details.""" try: environment = utils.find_resource( mc.environments, args.id, session_id=args.session_id) except exceptions.NotFound: raise exceptions.CommandError("Environment %s not found" % args.id) else: if getattr(args, 'only_apps', False): print(utils.json_formatter(environment.services)) else: formatters = { "id": utils.text_wrap_formatter, "created": utils.text_wrap_formatter, "name": utils.text_wrap_formatter, "tenant_id": utils.text_wrap_formatter, "services": utils.json_formatter, } utils.print_dict(environment.to_dict(), formatters=formatters) @utils.arg("id", metavar="", help="ID of Environment to deploy.") @utils.arg("--session-id", metavar="", required=True, help="ID of configuration session to deploy.") def do_environment_deploy(mc, args): """Start deployment of a murano environment session.""" mc.sessions.deploy(args.id, args.session_id) do_environment_show(mc, args) @utils.arg("id", help="ID of Environment to call action against.") @utils.arg("--action-id", metavar="", required=True, help="ID of action to run.") @utils.arg("--arguments", metavar='', nargs='*', help="Action arguments.") def do_environment_action_call(mc, args): """Call action `ACTION` in environment `ID`. Returns id of an asynchronous task, that executes the action. Actions can only be called on a `deployed` environment. To view actions available in a given environment use `environment-show` command. """ arguments = {} for argument in args.arguments or []: if '=' not in argument: raise exceptions.CommandError( "Argument should be in form of KEY=VALUE. Found: {0}".format( argument)) k, v = argument.split('=', 1) try: v = json.loads(v) except ValueError: # treat value as a string if it doesn't load as json pass arguments[k] = v task_id = mc.actions.call( args.id, args.action_id, arguments=arguments) print("Created task, id: {0}".format(task_id)) @utils.arg("id", metavar="", help="ID of Environment where task is being executed.") @utils.arg("--task-id", metavar="", required=True, help="ID of action to run.") def do_environment_action_get_result(mc, args): """Get result of `TASK` in environment `ID`.""" result = mc.actions.get_result(args.id, args.task_id) print("Task id result: {0}".format(result)) @utils.arg("class_name", metavar='', help="FQN of the class with static method") @utils.arg("method_name", metavar='', help="Static method to run") @utils.arg("--arguments", metavar='', nargs='*', help="Method arguments. No arguments by default") @utils.arg("--package-name", metavar='', default='', help='Optional FQN of the package to look for the class in') @utils.arg("--class-version", default='', help='Optional version of the class, otherwise version =0 is ' 'used ') def do_static_action_call(mc, args): """Call static method `METHOD` of the class `CLASS` with `ARGUMENTS`. Returns the result of the method execution. `PACKAGE` and `CLASS_VERSION` can be specified optionally to find class in a particular package and to look for the specific version of a class respectively. """ arguments = {} for argument in args.arguments or []: if '=' not in argument: raise exceptions.CommandError( "Argument should be in form of KEY=VALUE. Found: {0}".format( argument)) key, value = argument.split('=', 1) try: value = json.loads(value) except ValueError: # treat value as a string if it doesn't load as json pass arguments[key] = value request_body = { "className": args.class_name, "methodName": args.method_name, "packageName": args.package_name or None, "classVersion": args.class_version or '=0', "parameters": arguments } print("Waiting for result...") try: result = mc.static_actions.call(request_body).get_result() print("Static action result: {0}".format(result)) except Exception as e: print(str(e)) @utils.arg("id", metavar="", help="ID of Environment to add session to.") def do_environment_session_create(mc, args): """Creates a new configuration session for environment ID.""" environment_id = args.id session_id = mc.sessions.configure(environment_id).id print("Created new session:") formatters = {"id": utils.text_wrap_formatter} utils.print_dict({"id": session_id}, formatters=formatters) @utils.arg("id", metavar="", help="ID of Environment to edit.") @utils.arg("filename", metavar="FILE", nargs="?", help="File to read jsonpatch from (defaults to stdin).") @utils.arg("--session-id", metavar="", required=True, help="Id of a config session.") def do_environment_apps_edit(mc, args): """Edit environment's object model. `FILE` is path to a file, that contains jsonpatch, that describes changes to be made to environment's object-model. [ { "op": "add", "path": "/-", "value": { ... your-app object model here ... } }, { "op": "replace", "path": "/0/?/name", "value": "new_name" }, ] NOTE: Values '===id1===', '===id2===', etc. in the resulting object-model will be substituted with uuids. For more info on jsonpatch see RFC 6902 """ jp_obj = None if not args.filename: jp_obj = json.load(sys.stdin) else: with open(args.filename) as fpatch: jp_obj = json.load(fpatch) jpatch = jsonpatch.JsonPatch(jp_obj) environment_id = args.id session_id = args.session_id environment = mc.environments.get(environment_id, session_id) object_model = jpatch.apply(environment.services) utils.traverse_and_replace(object_model) mc.services.put( environment_id, path='/', data=jpatch.apply(environment.services), session_id=session_id) @utils.arg("id", metavar="", help="ID of Environment to show.") @utils.arg("--path", metavar="", default='/', help="Path to Environment model section. Defaults to '/'.") @utils.arg("--session-id", metavar="", help="Id of a config session.") def do_environment_model_show(mc, args): """Display an environment's object model.""" session_id = args.session_id or None path = six.moves.urllib.parse.quote(args.path) env_model = mc.environments.get_model(args.id, path, session_id) print(utils.json_formatter(env_model)) @utils.arg("id", metavar="", help="ID of Environment to edit.") @utils.arg("filename", metavar="", nargs="?", help="File to read JSON-patch from (defaults to stdin).") @utils.arg("--session-id", metavar="", required=True, help="Id of a config session.") def do_environment_model_edit(mc, args): """Edit an environment's object model.""" jp_obj = None if not args.filename: jp_obj = json.load(sys.stdin) else: with open(args.filename) as fpatch: jp_obj = json.load(fpatch) if not isinstance(jp_obj, list): raise exceptions.CommandError('JSON-patch must be a list of changes') for change in jp_obj: if 'op' not in change or 'path' not in change: raise exceptions.CommandError('Every change in JSON-patch must ' 'contain "op" and "path" keys') op = change['op'] if op not in ['add', 'replace', 'remove']: raise exceptions.CommandError('The value of "op" item must be ' '"add", "replace" or "remove", ' 'got {0}'.format(op)) if op != 'remove' and 'value' not in change: raise exceptions.CommandError('"add" or "replace" change in ' 'JSON-patch must contain "value" ' 'key') session_id = args.session_id new_model = mc.environments.update_model(args.id, jp_obj, session_id) print(utils.json_formatter(new_model)) def do_env_template_list(mc, args=None): """List the environments templates.""" if args is None: args = {} env_templates = mc.env_templates.list() _print_env_template_list(env_templates) def _print_env_template_list(env_templates): field_labels = ['ID', 'Name', 'Created', 'Updated', 'Is public'] fields = ['id', 'name', 'created', 'updated', 'is_public'] utils.print_list(env_templates, fields, field_labels, sortby=0) @utils.arg("name", metavar="", help="Environment template name.") @utils.arg("--is-public", action='store_true', default=False, help='Make the template available for users from other tenants.') def do_env_template_create(mc, args): """Create an environment template.""" env_template = mc.env_templates.create( {"name": args.name, "is_public": args.is_public}) _print_env_template_list([env_template]) @utils.arg("id", metavar="", help="Environment template ID.") @utils.arg("name", metavar="", help="New environment name.") @utils.arg("--region", metavar="", help="Name of the target OpenStack region.",) def do_env_template_create_env(mc, args): """Create a new environment from template.""" try: data = {} data["name"] = args.name if args.region: data["region"] = args.region template = mc.env_templates.create_env(args.id, data) except common_exceptions.HTTPNotFound: raise exceptions.CommandError("Environment template %s not found" % args.id) else: formatters = { "environment_id": utils.text_wrap_formatter, "session_id": utils.text_wrap_formatter } utils.print_dict(template.to_dict(), formatters=formatters) @utils.arg("id", metavar="", help="Environment template ID.") def do_env_template_show(mc, args): """Display environment template details.""" try: env_template = mc.env_templates.get(args.id) except common_exceptions.HTTPNotFound: raise exceptions.CommandError("Environment template %s not found" % args.id) else: formatters = { "id": utils.text_wrap_formatter, "created": utils.text_wrap_formatter, "name": utils.text_wrap_formatter, "tenant_id": utils.text_wrap_formatter, "services": utils.json_formatter, } utils.print_dict(env_template.to_dict(), formatters=formatters) @utils.arg("id", metavar="", help="Environment template ID.") @utils.arg('app_template_file', metavar='', help='Path to the template.') def do_env_template_add_app(mc, args): """Add application to the environment template.""" with open(args.app_template_file, "r") as app_file: app_templates = json.load(app_file) if not isinstance(app_templates, list): app_templates = [app_templates] for app_template in app_templates: mc.env_templates.create_app(args.id, app_template) do_env_template_show(mc, args) @utils.arg("id", metavar="", help="Environment template ID.") @utils.arg("app_id", metavar="", help="Application ID.") def do_env_template_del_app(mc, args): """Delete application from the environment template.""" mc.env_templates.delete_app(args.id, args.app_id) do_env_template_show(mc, args) @utils.arg("id", metavar="", help="Environment template ID.") @utils.arg("name", metavar="", help="Environment template name.") def do_env_template_update(mc, args): """Update an environment template.""" try: env_template = mc.env_templates.update(args.id, args.name) except common_exceptions.HTTPNotFound: raise exceptions.CommandError("Environment template %s not found" % args.id) _print_env_template_list([env_template]) @utils.arg("id", metavar="", nargs="+", help="ID of environment(s) template to delete.") def do_env_template_delete(mc, args): """Delete an environment template.""" failure_count = 0 for env_template_id in args.id: try: mc.env_templates.delete(env_template_id) except common_exceptions.HTTPNotFound: failure_count += 1 mns = "Failed to delete '{0}'; environment template not found".\ format(env_template_id) if failure_count == len(args.id): raise exceptions.CommandError(mns) do_env_template_list(mc) @utils.arg("id", metavar="", help="Environment template ID.") @utils.arg("name", metavar="", help="New environment template name.") def do_env_template_clone(mc, args): """Create a new template, cloned from template.""" try: env_template = mc.env_templates.clone(args.id, args.name) except common_exceptions.HTTPNotFound: raise exceptions.CommandError("Environment template %s not found" % args.id) else: formatters = { "id": utils.text_wrap_formatter, "created": utils.text_wrap_formatter, "updated": utils.text_wrap_formatter, "version": utils.text_wrap_formatter, "name": utils.text_wrap_formatter, "tenant_id": utils.text_wrap_formatter, "is_public": utils.text_wrap_formatter, "services": utils.json_formatter, } utils.print_dict(env_template.to_dict(), formatters=formatters) @utils.arg("id", metavar="", nargs='?', default=None, help="Environment ID for which to list deployments.") @utils.arg('--all-environments', action='store_true', default=False, help="Lists all deployments for all environments in user's tenant.") def do_deployment_list(mc, args): """List deployments for an environment or multiple environments.""" all_environments = getattr(args, 'all_environments', False) env_id = getattr(args, 'id', None) if env_id and all_environments: raise exceptions.CommandError( 'Environment ID and all-environments flag cannot both be set.') elif not env_id and not all_environments: raise exceptions.CommandError( 'Either environment ID or all-environments flag must be set.') try: if all_environments: deployments = mc.deployments.list(None, all_environments) else: environment = utils.find_resource(mc.environments, env_id) deployments = mc.deployments.list(environment.id) except exceptions.NotFound: if env_id: msg = "Environment %s not found" % env_id else: msg = "Environments not found" raise exceptions.CommandError(msg) else: field_labels = ["ID", "State", "Created", "Updated", "Finished"] fields = ["id", "state", "created", "updated", "finished"] utils.print_list(deployments, fields, field_labels, sortby=0) @utils.arg("--limit", type=int, default=0, help='Show limited number of packages') @utils.arg("--marker", default='', help='Show packages starting from package with id excluding it') @utils.arg("--include-disabled", default=False, action="store_true") @utils.arg("--owned", default=False, action="store_true") @utils.arg('--search', metavar='', dest='search', required=False, help='Show packages, that match search keys fuzzily') @utils.arg('--name', metavar='', dest='name', required=False, help='Show packages, whose name match parameter exactly') @utils.arg('--fqn', metavar="", dest='fqn', required=False, help='Show packages, ' 'whose fully qualified name match parameter exactly') @utils.arg('--type', metavar='', dest='type', required=False, help='Show packages, whose type match parameter exactly') @utils.arg('--category', metavar='', dest='category', required=False, help='Show packages, whose categories include parameter') @utils.arg('--class_name', metavar='', dest='class_name', required=False, help='Show packages, whose class name match parameter exactly') @utils.arg('--tag', metavar='', dest='tag', required=False, help='Show packages, whose tags include parameter') def do_package_list(mc, args=None): """List available packages.""" filter_args = { "include_disabled": getattr(args, 'include_disabled', False), "owned": getattr(args, 'owned', False), } if args: if args.limit < 0: raise exceptions.CommandError( '--limit parameter must be non-negative') if args.limit != 0: filter_args['limit'] = args.limit if args.marker: filter_args['marker'] = args.marker if args.search: filter_args['search'] = args.search if args.name: filter_args['name'] = args.name if args.fqn: filter_args['fqn'] = args.fqn if args.type: filter_args['type'] = args.type if args.category: filter_args['category'] = args.category if args.class_name: filter_args['class_name'] = args.class_name if args.tag: filter_args['tag'] = args.tag packages = mc.packages.filter(**filter_args) if not args or args.limit == 0: _print_package_list(packages) else: _print_package_list(itertools.islice(packages, args.limit)) def _print_package_list(packages): field_labels = ["ID", "Name", "FQN", "Author", "Active", "Is Public", "Type", "Version"] fields = ["id", "name", "fully_qualified_name", "author", "enabled", "is_public", "type", "version"] utils.print_list(packages, fields, field_labels, sortby=0) @utils.arg("id", metavar="", help="Package ID to download.") @utils.arg("filename", metavar="file", nargs="?", help="Filename to save package to. If it is not specified and " "there is no stdout redirection the package won't be saved.") def do_package_download(mc, args): """Download a package to a filename or stdout.""" def download_to_fh(package_id, fh): fh.write(mc.packages.download(package_id)) try: if args.filename: with open(args.filename, 'wb') as fh: download_to_fh(args.id, fh) print("Package downloaded to %s" % args.filename) elif not sys.stdout.isatty(): download_to_fh(args.id, sys.stdout) else: msg = ('No stdout redirection or local file specified for ' 'downloaded package. Please specify a local file to save ' 'downloaded package or redirect output to another source.') raise exceptions.CommandError(msg) except common_exceptions.HTTPNotFound: raise exceptions.CommandError("Package %s not found" % args.id) @utils.arg("id", metavar="", help="Package ID to show.") def do_package_show(mc, args): """Display details for a package.""" try: package = mc.packages.get(args.id) except common_exceptions.HTTPNotFound: raise exceptions.CommandError("Package %s not found" % args.id) else: to_display = dict( id=package.id, type=package.type, owner_id=package.owner_id, name=package.name, fully_qualified_name=package.fully_qualified_name, is_public=package.is_public, enabled=package.enabled, class_definitions=", ".join(package.class_definitions), categories=", ".join(package.categories), tags=", ".join(package.tags), description=package.description ) formatters = { 'class_definitions': utils.text_wrap_formatter, 'categories': utils.text_wrap_formatter, 'tags': utils.text_wrap_formatter, 'description': utils.text_wrap_formatter, } utils.print_dict(to_display, formatters) @utils.arg("id", metavar="", nargs='+', help="Package ID to delete.") def do_package_delete(mc, args): """Delete a package.""" failure_count = 0 for package_id in args.id: try: mc.packages.delete(package_id) print("Deleted package '{0}'".format(package_id)) except exceptions.NotFound: failure_count += 1 print("Failed to delete '{0}'; package not found". format(package_id)) if failure_count == len(args.id): raise exceptions.CommandError("Unable to find and delete any of the " "specified packages.") else: do_package_list(mc) def _handle_package_exists(mc, data, package, exists_action): name = package.manifest['FullName'] version = package.manifest.get('Version', '0') while True: print("Importing package {0}".format(name)) try: return mc.packages.create(data, {name: package.file()}) except common_exceptions.HTTPConflict: print("Importing package {0} failed. Package with the same" " name/classes is already registered.".format(name)) allowed_results = ['s', 'u', 'a'] res = exists_action if not res: while True: print("What do you want to do? (s)kip, (u)pdate, (a)bort") res = six.moves.input() if res in allowed_results: break if res == 's': print("Skipping.") return None elif res == 'a': print("Exiting.") sys.exit() elif res == 'u': pkgs = list(mc.packages.filter(fqn=name, version=version, owned=True)) if not pkgs: msg = ( "Got a conflict response, but could not find the " "package '{0}' in the current tenant.\nThis probably " "means the conflicting package is in another tenant.\n" "Please delete it manually." ).format(name) raise exceptions.CommandError(msg) elif len(pkgs) > 1: msg = ( "Got {0} packages with name '{1}'.\nI do not trust " "myself, please delete the package manually." ).format(len(pkgs), name) raise exceptions.CommandError(msg) print("Deleting package {0}({1})".format(name, pkgs[0].id)) mc.packages.delete(pkgs[0].id) continue @utils.arg('filename', metavar='', nargs='+', help='URL of the murano zip package, FQPN, path to zip package' ' or path to directory with package.') @utils.arg('-c', '--categories', metavar='', nargs='*', help='Category list to attach.') @utils.arg('--is-public', action='store_true', default=False, help='Make the package available for users from other tenants.') @utils.arg('--package-version', default='', help='Version of the package to use from repository ' '(ignored when importing with multiple packages).') @utils.arg('--exists-action', default='', choices=['a', 's', 'u'], help='Default action when a package already exists: ' '(s)kip, (u)pdate, (a)bort.') @utils.arg('--dep-exists-action', default='', choices=['a', 's', 'u'], help='Default action when a dependency package already exists: ' '(s)kip, (u)pdate, (a)bort.') def do_package_import(mc, args): """Import a package. `FILE` can be either a path to a zip file, url or a FQPN. You can use `--` to separate `FILE`s from other arguments. Categories have to be separated with a space and have to be already present in murano. """ data = {"is_public": args.is_public} exception_occurred = False version = args.package_version if version and len(args.filename) >= 2: print("Requested to import more than one package, " "ignoring version.") version = '' if args.categories: data["categories"] = args.categories total_reqs = collections.OrderedDict() main_packages_names = [] for filename in args.filename: if os.path.isfile(filename) or os.path.isdir(filename): _file = filename else: print("Package file '{0}' does not exist, attempting to download" "".format(filename)) _file = utils.to_url( filename, version=version, base_url=args.murano_repo_url, extension='.zip', path='apps/', ) try: package = utils.Package.from_file(_file) except Exception as e: print("Failed to create package for '{0}', reason: {1}".format( filename, e)) exception_occurred = True continue total_reqs.update(package.requirements(base_url=args.murano_repo_url)) main_packages_names.append(package.manifest['FullName']) imported_list = [] dep_exists_action = args.dep_exists_action if dep_exists_action == '': dep_exists_action = args.exists_action for name, package in total_reqs.items(): image_specs = package.images() if image_specs: print("Inspecting required images") try: imgs = utils.ensure_images( glance_client=mc.glance_client, image_specs=image_specs, base_url=args.murano_repo_url, is_package_public=args.is_public) for img in imgs: print("Added {0}, {1} image".format( img['name'], img['id'])) except Exception as e: print("Error {0} occurred while installing " "images for {1}".format(e, name)) exception_occurred = True if name in main_packages_names: exists_action = args.exists_action else: exists_action = dep_exists_action try: imported_package = _handle_package_exists( mc, data, package, exists_action) if imported_package: imported_list.append(imported_package) except Exception as e: print("Error {0} occurred while installing package {1}".format( e, name)) exception_occurred = True if imported_list: _print_package_list(imported_list) if exception_occurred: # NOTE(jose-phillips) Leave a Warning to users in case some packages # can be uploaded successfully. if imported_list: print("Warning: there were some errors during the operation.") sys.exit(1) else: sys.exit(1) @utils.arg("id", metavar="", help="Package ID to update.") @utils.arg('--is-public', type=_bool_from_str_strict, metavar='{true|false}', help='Make package available to users from other tenants.') @utils.arg('--enabled', type=_bool_from_str_strict, metavar='{true|false}', help='Make package active and available for deployments.') @utils.arg('--name', default=None, help='New name for the package.') @utils.arg('--description', default=None, help='New package description.') @utils.arg('--tags', metavar='', nargs='*', default=None, help='A list of keywords connected to the application.') def do_package_update(mc, args): """Update an existing package.""" data = {} parameters = ('is_public', 'enabled', 'name', 'description', 'tags') for parameter in parameters: param_value = getattr(args, parameter, None) if param_value is not None: data[parameter] = param_value mc.packages.update(args.id, data) do_package_show(mc, args) @utils.arg('filename', metavar='', nargs='+', help='Bundle URL, bundle name, or path to the bundle file.') @utils.arg('--is-public', action='store_true', default=False, help='Make packages available to users from other tenants.') @utils.arg('--exists-action', default='', choices=['a', 's', 'u'], help='Default action when a package already exists.') def do_bundle_import(mc, args): """Import a bundle. `FILE` can be either a path to a zip file, URL, or name from repo. If `FILE` is a local file, treat names of packages in a bundle as file names, relative to location of the bundle file. Requirements are first searched in the same directory. """ total_reqs = collections.OrderedDict() for filename in args.filename: local_path = None if os.path.isfile(filename): _file = filename local_path = os.path.dirname(os.path.abspath(filename)) else: print("Bundle file '{0}' does not exist, attempting to download" "".format(filename)) _file = utils.to_url( filename, base_url=args.murano_repo_url, path='bundles/', extension='.bundle', ) try: bundle_file = utils.Bundle.from_file(_file) except Exception as e: print("Failed to create bundle for '{0}', reason: {1}".format( filename, e)) continue data = {"is_public": args.is_public} for package in bundle_file.packages( base_url=args.murano_repo_url, path=local_path): requirements = package.requirements( base_url=args.murano_repo_url, path=local_path, ) total_reqs.update(requirements) imported_list = [] for name, dep_package in total_reqs.items(): image_specs = dep_package.images() if image_specs: print("Inspecting required images") try: imgs = utils.ensure_images( glance_client=mc.glance_client, image_specs=image_specs, base_url=args.murano_repo_url, local_path=local_path, is_package_public=args.is_public) for img in imgs: print("Added {0}, {1} image".format( img['name'], img['id'])) except Exception as e: print("Error {0} occurred while installing " "images for {1}".format(e, name)) try: imported_package = _handle_package_exists( mc, data, dep_package, args.exists_action) if imported_package: imported_list.append(imported_package) except exceptions.CommandError: raise except Exception as e: print("Error {0} occurred while " "installing package {1}".format(e, name)) if imported_list: _print_package_list(imported_list) def _handle_save_packages(packages, dst, base_url, no_images): downloaded_images = [] for name, pkg in packages.items(): if not no_images: image_specs = pkg.images() for image_spec in image_specs: if not image_spec["Name"]: print("Invalid image.lst file for {0} package. " "'Name' section is absent.".format(name)) continue if image_spec["Name"] not in downloaded_images: print("Package {0} depends on image {1}. " "Downloading...".format(name, image_spec["Name"])) try: utils.save_image_local(image_spec, base_url, dst) downloaded_images.append(image_spec["Name"]) except Exception as e: print("Error {0} occurred while saving image {1}". format(e, image_spec["Name"])) try: pkg.save(dst) print("Package {0} has been successfully saved".format(name)) except Exception as e: print("Error {0} occurred while saving package {1}".format( e, name)) @utils.arg('filename', metavar='', help='Bundle URL, bundle name, or path to the bundle file.') @utils.arg('-p', '--path', metavar='', help='Path to the directory to store packages. If not set will use ' 'current directory.') @utils.arg('--no-images', action='store_true', default=False, help='If set will skip images downloading.') def do_bundle_save(mc, args): """Save a bundle. This will download a bundle of packages with all dependencies to specified path. If path doesn't exist it will be created. """ bundle = args.filename base_url = args.murano_repo_url if args.path: if not os.path.exists(args.path): os.makedirs(args.path) dst = args.path else: dst = os.getcwd() total_reqs = collections.OrderedDict() if os.path.isfile(bundle): _file = bundle else: print("Bundle file '{0}' does not exist, attempting to download" .format(bundle)) _file = utils.to_url( bundle, base_url=base_url, path='bundles/', extension='.bundle', ) try: bundle_file = utils.Bundle.from_file(_file) except Exception as e: msg = "Failed to create bundle for {0}, reason: {1}".format(bundle, e) raise exceptions.CommandError(msg) for package in bundle_file.packages(base_url=base_url): requirements = package.requirements(base_url=base_url) total_reqs.update(requirements) no_images = getattr(args, 'no_images', False) _handle_save_packages(total_reqs, dst, base_url, no_images) try: bundle_file.save(dst, binary=False) print("Bundle file {0} has been successfully saved".format(bundle)) except Exception as e: print("Error {0} occurred while saving bundle {1}".format(e, bundle)) @utils.arg('package', metavar='', nargs='+', help='Package URL or name.') @utils.arg('-p', '--path', metavar='', help='Path to the directory to store package. If not set will use ' 'current directory.') @utils.arg('--package-version', default='', help='Version of the package to use from repository ' '(ignored when saving with multiple packages).') @utils.arg('--no-images', action='store_true', default=False, help='If set will skip images downloading.') def do_package_save(mc, args): """Save a package. This will download package(s) with all dependencies to specified path. If path doesn't exist it will be created. """ base_url = args.murano_repo_url if args.path: if not os.path.exists(args.path): os.makedirs(args.path) dst = args.path else: dst = os.getcwd() version = args.package_version if version and len(args.filename) >= 2: print("Requested to save more than one package, " "ignoring version.") version = '' total_reqs = collections.OrderedDict() for package in args.package: _file = utils.to_url( package, version=version, base_url=base_url, extension='.zip', path='apps/', ) try: pkg = utils.Package.from_file(_file) except Exception as e: print("Failed to create package for '{0}', reason: {1}".format( package, e)) continue total_reqs.update(pkg.requirements(base_url=base_url)) no_images = getattr(args, 'no_images', False) _handle_save_packages(total_reqs, dst, base_url, no_images) @utils.arg('id', metavar='', help='Environment ID to show applications from.') @utils.arg('-p', '--path', metavar='', help='Level of detalization to show. ' 'Leave empty to browse all applications in the environment.', default='/') def do_app_show(mc, args): """List applications, added to specified environment.""" if args.path == '/': apps = mc.services.list(args.id) formatters = {'id': lambda x: getattr(x, '?')['id'], 'type': lambda x: getattr(x, '?')['type']} field_labels = ['Id', 'Name', 'Type'] fields = ['id', 'name', 'type'] utils.print_list(apps, fields, field_labels, formatters=formatters) else: if not args.path.startswith('/'): args.path = '/' + args.path app = mc.services.get(args.id, args.path) # If app with specified path is not found, it is empty. if hasattr(app, '?'): formatters = {} for key in app.to_dict().keys(): formatters[key] = utils.json_formatter utils.print_dict(app.to_dict(), formatters) else: raise exceptions.CommandError("Could not find application at path" " %s" % args.path) @utils.arg('-t', '--template', metavar='', help='Path to the Heat template to import as ' 'an Application Definition.') @utils.arg('-c', '--classes-dir', metavar='', help='Path to the directory containing application classes.') @utils.arg('-r', '--resources-dir', metavar='', help='Path to the directory containing application resources.') @utils.arg('-n', '--name', metavar='', help='Display name of the Application in Catalog.') @utils.arg('-f', '--full-name', metavar='', help='Fully-qualified name of the Application in Catalog.') @utils.arg('-a', '--author', metavar='', help='Name of the publisher.') @utils.arg('--tags', help='A list of keywords connected to the application.', metavar='', nargs='*') @utils.arg('-d', '--description', metavar='', help='Detailed description for the Application in Catalog.') @utils.arg('-o', '--output', metavar='', help='The name of the output file archive to save locally.') @utils.arg('-u', '--ui', metavar='', help='Dynamic UI form definition.') @utils.arg('--type', help='Package type. Possible values: Application or Library.') @utils.arg('-l', '--logo', metavar='', help='Path to the package logo.') def do_package_create(mc, args): """Create an application package.""" if args.template and args.classes_dir: raise exceptions.CommandError( "Provide --template for a HOT-based package, OR" " --classes-dir for a MuranoPL-based package") if not args.template and not args.classes_dir: raise exceptions.CommandError( "Provide --template for a HOT-based package, OR at least" " --classes-dir for a MuranoPL-based package") directory_path = None try: archive_name = args.output if args.output else None if args.template: directory_path = hot_package.prepare_package(args) if not archive_name: archive_name = os.path.basename(args.template) archive_name = os.path.splitext(archive_name)[0] + ".zip" else: directory_path = mpl_package.prepare_package(args) if not archive_name: archive_name = tempfile.mkstemp( prefix="murano_", dir=os.getcwd())[1] + ".zip" _make_archive(archive_name, directory_path) print("Application package is available at " + os.path.abspath(archive_name)) finally: if directory_path: shutil.rmtree(directory_path) def _make_archive(archive_name, path): zip_file = zipfile.ZipFile(archive_name, 'w') for root, dirs, files in os.walk(path): for f in files: zip_file.write(os.path.join(root, f), arcname=os.path.join(os.path.relpath(root, path), f)) def do_category_list(mc, args=None): """List all available categories.""" if args is None: args = {} categories = mc.categories.list() _print_category_list(categories) def _print_category_list(categories): field_labels = ["ID", "Name"] fields = ["id", "name"] utils.print_list(categories, fields, field_labels) @utils.arg("id", metavar="", help="ID of a category(s) to show.") def do_category_show(mc, args): """Display category details.""" category = mc.categories.get(args.id) packages = mc.packages.filter(category=category.name) to_display = dict(id=category.id, name=category.name, packages=', '.join(p.name for p in packages)) formatters = {'packages': utils.text_wrap_formatter} utils.print_dict(to_display, formatters) @utils.arg("name", metavar="", help="Category name.") def do_category_create(mc, args): """Create a category.""" category = mc.categories.add({"name": args.name}) _print_category_list([category]) @utils.arg("id", metavar="", nargs="+", help="ID of a category(ies) to delete.") def do_category_delete(mc, args): """Delete a category.""" failure_count = 0 for category_id in args.id: try: mc.categories.delete(category_id) except common_exceptions.HTTPNotFound: failure_count += 1 print("Failed to delete '{0}'; category not found". format(category_id)) if failure_count == len(args.id): raise exceptions.CommandError("Unable to find and delete any of the " "specified categories.") do_category_list(mc) @utils.arg("class_name", metavar="", help="Class FQN") @utils.arg("method_names", metavar="", help="Method name", nargs='*') @utils.arg("--package-name", default=None, help="FQN of the package where the class is located") @utils.arg("--class-version", default='=0', help="Class version or version range (version spec)") def do_class_schema(mc, args): """Display class schema""" schema = mc.schemas.get(args.class_name, args.method_names, class_version=args.class_version, package_name=args.package_name) print(utils.json_formatter(schema.data)) python-muranoclient-1.0.1/muranoclient/v1/client.py0000666000175100017510000000605313231416510022434 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from muranoclient.common import http from muranoclient.v1 import actions from muranoclient.v1 import artifact_packages from muranoclient.v1 import categories from muranoclient.v1 import deployments from muranoclient.v1 import environments from muranoclient.v1 import instance_statistics from muranoclient.v1 import packages from muranoclient.v1 import request_statistics from muranoclient.v1 import schemas from muranoclient.v1 import services from muranoclient.v1 import sessions from muranoclient.v1 import static_actions from muranoclient.v1 import templates class Client(object): """Client for the Murano v1 API. :param string endpoint: A user-supplied endpoint URL for the service. :param string token: Token for authentication. :param integer timeout: Allows customization of the timeout for client http requests. (optional) """ def __init__(self, *args, **kwargs): """Initialize a new client for the Murano v1 API.""" self.glance_client = kwargs.pop('glance_client', None) tenant = kwargs.pop('tenant', None) artifacts_client = kwargs.pop('artifacts_client', None) self.http_client = http._construct_http_client(*args, **kwargs) self.environments = environments.EnvironmentManager(self.http_client) self.env_templates = templates.EnvTemplateManager(self.http_client) self.sessions = sessions.SessionManager(self.http_client) self.services = services.ServiceManager(self.http_client) self.deployments = deployments.DeploymentManager(self.http_client) self.schemas = schemas.SchemaManager(self.http_client) self.request_statistics = \ request_statistics.RequestStatisticsManager(self.http_client) self.instance_statistics = \ instance_statistics.InstanceStatisticsManager(self.http_client) pkg_mgr = packages.PackageManager(self.http_client) if artifacts_client: artifact_repo = artifact_packages.ArtifactRepo(artifacts_client, tenant) self.packages = artifact_packages.PackageManagerAdapter( pkg_mgr, artifact_repo) else: self.packages = pkg_mgr self.actions = actions.ActionManager(self.http_client) self.static_actions = static_actions.StaticActionManager( self.http_client) self.categories = categories.CategoryManager(self.http_client) python-muranoclient-1.0.1/muranoclient/v1/sessions.py0000666000175100017510000000326413231416510023025 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from muranoclient.common import base class Session(base.Resource): def __repr__(self): return '' % self._info def data(self, **kwargs): return self.manager.data(self, **kwargs) class SessionManager(base.Manager): resource_class = Session def get(self, environment_id, session_id): return self._get('/v1/environments/{id}/sessions/{session_id}'. format(id=environment_id, session_id=session_id)) def configure(self, environment_id): return self._create('/v1/environments/{id}/configure'. format(id=environment_id), None) def deploy(self, environment_id, session_id): path = '/v1/environments/{id}/sessions/{session_id}/deploy' self.api.json_request(path.format(id=environment_id, session_id=session_id), 'POST') def delete(self, environment_id, session_id): return self._delete("/v1/environments/{id}/sessions/{session_id}". format(id=environment_id, session_id=session_id)) python-muranoclient-1.0.1/muranoclient/v1/actions.py0000666000175100017510000000263713231416510022622 0ustar zuulzuul00000000000000# Copyright (c) 2014 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. # Not a true manager yet; should be changed to be one if CRUD # functionality becomes available for actions. class ActionManager(object): def __init__(self, api): self.api = api def call(self, environment_id, action_id, arguments=None): if arguments is None: arguments = {} url = '/v1/environments/{environment_id}/actions/{action_id}'.format( environment_id=environment_id, action_id=action_id) resp, body = self.api.json_request(url, 'POST', body=arguments) return body['task_id'] def get_result(self, environment_id, task_id): url = '/v1/environments/{environment_id}/actions/{task_id}'.format( environment_id=environment_id, task_id=task_id) resp, body = self.api.json_request(url, 'GET') return body or None python-muranoclient-1.0.1/muranoclient/v1/__init__.py0000666000175100017510000000000013231416510022677 0ustar zuulzuul00000000000000python-muranoclient-1.0.1/muranoclient/v1/templates.py0000666000175100017510000000704713231416510023160 0ustar zuulzuul00000000000000# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from muranoclient.common import base class Template(base.Resource): """Involves the template resource.""" def __repr__(self): return "