python-monascaclient-2.0.0/0000775000175000017500000000000013620561132015671 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/HACKING.rst0000664000175000017500000000024013620561064017467 0ustar zuulzuul00000000000000python-monascaclient Style Commandments ======================================= Read the OpenStack Style Commandments http://docs.openstack.org/hacking/latest python-monascaclient-2.0.0/releasenotes/0000775000175000017500000000000013620561132020362 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/releasenotes/locale/0000775000175000017500000000000013620561132021621 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/releasenotes/locale/.gitkeep0000664000175000017500000000000013620561064023244 0ustar zuulzuul00000000000000python-monascaclient-2.0.0/releasenotes/source/0000775000175000017500000000000013620561132021662 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/releasenotes/source/stein.rst0000664000175000017500000000022113620561064023535 0ustar zuulzuul00000000000000=================================== Stein Series Release Notes =================================== .. release-notes:: :branch: stable/stein python-monascaclient-2.0.0/releasenotes/source/train.rst0000664000175000017500000000017613620561064023541 0ustar zuulzuul00000000000000========================== Train Series Release Notes ========================== .. release-notes:: :branch: stable/train python-monascaclient-2.0.0/releasenotes/source/unreleased.rst0000664000175000017500000000016013620561064024544 0ustar zuulzuul00000000000000============================== Current Series Release Notes ============================== .. release-notes:: python-monascaclient-2.0.0/releasenotes/source/index.rst0000664000175000017500000000026413620561064023531 0ustar zuulzuul00000000000000============================ Monitoring API Release Notes ============================ Contents: .. toctree:: :maxdepth: 1 unreleased train stein rocky queens python-monascaclient-2.0.0/releasenotes/source/queens.rst0000664000175000017500000000022313620561064023715 0ustar zuulzuul00000000000000=================================== Queens Series Release Notes =================================== .. release-notes:: :branch: stable/queens python-monascaclient-2.0.0/releasenotes/source/rocky.rst0000664000175000017500000000022113620561064023542 0ustar zuulzuul00000000000000=================================== Rocky Series Release Notes =================================== .. release-notes:: :branch: stable/rocky python-monascaclient-2.0.0/releasenotes/source/conf.py0000664000175000017500000000427613620561064023176 0ustar zuulzuul00000000000000# -*- coding: utf-8 -*- # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. needs_sphinx = '1.6' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'openstackdocstheme', 'reno.sphinxext' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. repository_name = u'openstack/python-monascaclient' project = u'Monasca Client ReleaseNotes Docs' # Release notes do not need a version number in the title, they # cover multiple releases. version = '' release = '' bug_project = u'880' bug_tag = u'' copyright = u'2014-present, OpenStack Foundation' author = u'OpenStack Foundation' # 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. See the documentation for # a list of builtin themes. html_theme = 'openstackdocs' # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%Y-%m-%d %H:%M' # Output file base name for HTML help builder. htmlhelp_basename = 'MonascaClientReleaseNotesDoc' # -- Options for LaTeX output --------------------------------------------- latex_documents = [( master_doc, 'MonascaClientReleaseNotes.tex', u'Monasca Client Release Notes', [author], 'manual' )] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'monascaclientreleasenotes', u'Monasca Client Release Notes', [author], 1) ] # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] python-monascaclient-2.0.0/releasenotes/notes/0000775000175000017500000000000013620561132021512 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/releasenotes/notes/drop-py-2-7-1c41855c5edc5ba3.yaml0000664000175000017500000000031613620561064026566 0ustar zuulzuul00000000000000--- upgrade: - | Python 2.7 support has been dropped. Last release of python-monascaclient to support python 2.7 is OpenStack Train. The minimum version of Python now supported is Python 3.6. python-monascaclient-2.0.0/releasenotes/notes/openstack_docs-5cfec48411370070.yaml0000664000175000017500000000046113620561064027450 0ustar zuulzuul00000000000000--- prelude: > Documentation done right by Openstack process. issues: - | Removed the case where command documentation (held previously in markdown) is out-of-sync with the command itself. upgrade: - | Added details about using the CLI variant. Documented the usage of Python API. python-monascaclient-2.0.0/PKG-INFO0000664000175000017500000000423413620561132016771 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-monascaclient Version: 2.0.0 Summary: Monasca API Client Library Home-page: https://docs.openstack.org/python-monascaclient/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/python-monascaclient.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on Python bindings to the Monasca API ================================== .. image:: https://img.shields.io/pypi/v/python-monascaclient.svg :target: https://pypi.python.org/pypi/python-monascaclient/ :alt: Latest Version This is a client library for Monasca built to interface with the Monasca API. It provides a Python API (the ``monascaclient`` module) and a command-line tool (``monasca``). * License: Apache License, Version 2.0 * `PyPi`_ - package installation * `Online Documentation`_ * `Bugs`_ - issue tracking (we use *bug* tag to differentiate from new features) * `Source`_ .. _PyPi: https://pypi.python.org/pypi/python-monascaclient .. _Online Documentation: https://docs.openstack.org/python-monascaclient/latest/ .. _Bugs: https://storyboard.openstack.org/#!/project/880 .. _Source: https://opendev.org/openstack/python-monascaclient Platform: UNKNOWN Classifier: Environment :: Console 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.6 Classifier: Programming Language :: Python :: 3.7 python-monascaclient-2.0.0/docker/0000775000175000017500000000000013620561132017140 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/docker/start.sh0000775000175000017500000000031013620561064020632 0ustar zuulzuul00000000000000#!/bin/sh # Test services we need before starting our service. echo "Start script: waiting for needed services" python3 /kafka_wait_for_topics.py python3 /mysql_check.py ./wait_for.sh "$MONASCA_URI"python-monascaclient-2.0.0/docker/README.rst0000664000175000017500000000350513620561064020636 0ustar zuulzuul00000000000000=============================== Docker image for Monasca Client =============================== The Monasca Client image is based on the monasca-base image. Building monasca-base image =========================== See https://github.com/openstack/monasca-common/tree/master/docker/README.rst Building Monasca Client image ============================= Example: $ ./build_image.sh Requirements from monasca-base image ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ health_check.py This file will be used for checking the status of the Monasca API application. Scripts ~~~~~~~ start.sh In this starting script provide all steps that lead to the proper service start. Including usage of wait scripts and templating of configuration files. You also could provide the ability to allow running container after service died for easier debugging. build_image.sh Please read detailed build description inside the script. Docker Compose ~~~~~~~~~~~~~~ When you want to use docker-compose add it as a new service and be sure that property 'tty' is set to true to avoid exiting of container after startup. Example: * monasca-client: * image: monasca/client:master * tty: true Running ~~~~~~~ If you don't want to use docker-compose mechanism, you can run container manually and connect it to existing docker Monasca network. Example: docker network --network= You can also use docker run option to start a container and connect it to a network immediately: Example: docker run -itd --network= Inside of container it is possible to run 'monasca' shell commands, e.g. to list all metrics. Example: monasca metric-list Links ~~~~~ https://docs.openstack.org/python-monascaclient/latest/ python-monascaclient-2.0.0/docker/build_image.sh0000775000175000017500000001317713620561064021755 0ustar zuulzuul00000000000000#!/bin/bash # 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. # TODO(Dobroslaw): move this script to monasca-common/docker folder # and leave here small script to download it and execute using env variables # to minimize code duplication. set -x # Print each script step. set -eo pipefail # Exit the script if any statement returns error. # This script is used for building Docker image with proper labels # and proper version of monasca-common. # # Example usage: # $ ./build_image.sh # # Everything after `./build_image.sh` is optional and by default configured # to get versions from `Dockerfile`. # # To build from master branch (default): # $ ./build_image.sh # To build specific version run this script in the following way: # $ ./build_image.sh stable/queens # Building from specific commit: # $ ./build_image.sh cb7f226 # When building from a tag monasca-common will be used in version available # in upper constraint file: # $ ./build_image.sh 2.5.0 # To build image from Gerrit patch sets that is targeting branch stable/queens: # $ ./build_image.sh refs/changes/51/558751/1 stable/queens # # If you want to build image with custom monasca-common version you need # to provide it as in the following example: # $ ./build_image.sh master master refs/changes/19/595719/3 # Go to folder with Docker files. REAL_PATH=$(python -c "import os,sys; print(os.path.realpath('$0'))") cd "$(dirname "$REAL_PATH")/../docker/" [ -z "$DOCKER_IMAGE" ] && \ DOCKER_IMAGE=$(\grep DOCKER_IMAGE Dockerfile | cut -f2 -d"=") : "${REPO_VERSION:=$1}" [ -z "$REPO_VERSION" ] && \ REPO_VERSION=$(\grep REPO_VERSION Dockerfile | cut -f2 -d"=") # Let's stick to more readable version and disable SC2001 here. # shellcheck disable=SC2001 REPO_VERSION_CLEAN=$(echo "$REPO_VERSION" | sed 's|/|-|g') [ -z "$APP_REPO" ] && APP_REPO=$(\grep APP_REPO Dockerfile | cut -f2 -d"=") GITHUB_REPO=$(echo "$APP_REPO" | sed 's/review.opendev.org/github.com/' | \ sed 's/ssh:/https:/') if [ -z "$CONSTRAINTS_FILE" ]; then CONSTRAINTS_FILE=$(\grep CONSTRAINTS_FILE Dockerfile | cut -f2 -d"=") || true : "${CONSTRAINTS_FILE:=https://opendev.org/openstack/requirements/raw/branch/master/upper-constraints.txt}" fi : "${CONSTRAINTS_BRANCH:=$2}" [ -z "$CONSTRAINTS_BRANCH" ] && \ CONSTRAINTS_BRANCH=$(\grep CONSTRAINTS_BRANCH Dockerfile | cut -f2 -d"=") # When using stable version of repository use same stable constraints file. case "$REPO_VERSION" in *stable*) CONSTRAINTS_BRANCH_CLEAN="$REPO_VERSION" CONSTRAINTS_FILE=${CONSTRAINTS_FILE/master/$CONSTRAINTS_BRANCH_CLEAN} # Get monasca-common version from stable upper constraints file. CONSTRAINTS_TMP_FILE=$(mktemp) wget --output-document "$CONSTRAINTS_TMP_FILE" \ $CONSTRAINTS_FILE UPPER_COMMON=$(\grep 'monasca-common' "$CONSTRAINTS_TMP_FILE") # Get only version part from monasca-common. UPPER_COMMON_VERSION="${UPPER_COMMON##*===}" rm -rf "$CONSTRAINTS_TMP_FILE" ;; *) CONSTRAINTS_BRANCH_CLEAN="$CONSTRAINTS_BRANCH" ;; esac # Monasca-common variables. if [ -z "$COMMON_REPO" ]; then COMMON_REPO=$(\grep COMMON_REPO Dockerfile | cut -f2 -d"=") || true : "${COMMON_REPO:=https://review.opendev.org/openstack/monasca-common}" fi : "${COMMON_VERSION:=$3}" if [ -z "$COMMON_VERSION" ]; then COMMON_VERSION=$(\grep COMMON_VERSION Dockerfile | cut -f2 -d"=") || true if [ "$UPPER_COMMON_VERSION" ]; then # Common from upper constraints file. COMMON_VERSION="$UPPER_COMMON_VERSION" fi fi # Clone project to temporary directory for getting proper commit number from # branches and tags. We need this for setting proper image labels. # Docker does not allow to get any data from inside of system when building # image. TMP_DIR=$(mktemp -d) ( cd "$TMP_DIR" # This many steps are needed to support gerrit patch sets. git init git remote add origin "$APP_REPO" git fetch origin "$REPO_VERSION" git reset --hard FETCH_HEAD ) GIT_COMMIT=$(git -C "$TMP_DIR" rev-parse HEAD) [ -z "${GIT_COMMIT}" ] && echo "No git commit hash found" && exit 1 rm -rf "$TMP_DIR" # Do the same for monasca-common. COMMON_TMP_DIR=$(mktemp -d) ( cd "$COMMON_TMP_DIR" # This many steps are needed to support gerrit patch sets. git init git remote add origin "$COMMON_REPO" git fetch origin "$COMMON_VERSION" git reset --hard FETCH_HEAD ) COMMON_GIT_COMMIT=$(git -C "$COMMON_TMP_DIR" rev-parse HEAD) [ -z "${COMMON_GIT_COMMIT}" ] && echo "No git commit hash found" && exit 1 rm -rf "$COMMON_TMP_DIR" CREATION_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") docker build --no-cache \ --build-arg CREATION_TIME="$CREATION_TIME" \ --build-arg GITHUB_REPO="$GITHUB_REPO" \ --build-arg APP_REPO="$APP_REPO" \ --build-arg REPO_VERSION="$REPO_VERSION" \ --build-arg GIT_COMMIT="$GIT_COMMIT" \ --build-arg CONSTRAINTS_FILE="$CONSTRAINTS_FILE" \ --build-arg COMMON_REPO="$COMMON_REPO" \ --build-arg COMMON_VERSION="$COMMON_VERSION" \ --build-arg COMMON_GIT_COMMIT="$COMMON_GIT_COMMIT" \ --tag "$DOCKER_IMAGE":"$REPO_VERSION_CLEAN" . python-monascaclient-2.0.0/docker/Dockerfile0000664000175000017500000000122113620561064021132 0ustar zuulzuul00000000000000ARG DOCKER_IMAGE=monasca/client ARG APP_REPO=https://review.opendev.org/openstack/python-monascaclient # Branch, tag or git hash to build from. ARG REPO_VERSION=master ARG CONSTRAINTS_BRANCH=master # Always start from `monasca-base` image and use specific tag of it. ARG BASE_TAG=master FROM monasca/base:$BASE_TAG # Environment variables used for our service or wait scripts. ENV \ MONASCA_URI=monasca:8070 \ OS_AUTH_URL=http://keystone:35357/v3 \ OS_USERNAME=mini-mon \ OS_PASSWORD=password \ OS_TENANT_NAME=mini-mon \ OS_DOMAIN_NAME=Default RUN monasca --version # Implement start script in `start.sh` file. CMD ["/start.sh"]python-monascaclient-2.0.0/docker/health_check.py0000775000175000017500000000143413620561064022125 0ustar zuulzuul00000000000000#!/usr/bin/env python # coding=utf-8 # (C) Copyright 2018 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Health check will returns 0 when service is working properly.""" def main(): """No health check for python client""" return 0 if __name__ == '__main__': main() python-monascaclient-2.0.0/test-requirements.txt0000664000175000017500000000110613620561064022134 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>=1.1.0,<1.2.0 # Apache-2.0 bandit>=1.1.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0 oslotest>=3.2.0 # Apache-2.0 stestr>=1.0.0 testscenarios>=0.4 # Apache-2.0/BSD testtools>=2.2.0 # MIT # documentation doc8>=0.6.0 # Apache-2.0 sphinx!=1.6.6,!=1.6.7,!=2.1.0,>=1.6.5;python_version>='3.4' # BSD reno>=2.5.0 # Apache-2.0 openstackdocstheme>=1.18.1 # Apache-2.0 python-monascaclient-2.0.0/monascaclient/0000775000175000017500000000000013620561132020511 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/shell.py0000664000175000017500000000771113620561064022204 0ustar zuulzuul00000000000000# (C) Copyright 2014-2015 Hewlett Packard Enterprise Development Company LP # Copyright 2017 Fujitsu LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. """ Command-line interface to the monasca-client API. """ import argparse import locale import sys from osc_lib.api import auth from osc_lib.cli import client_config as cloud_config from osc_lib import shell from osc_lib import utils from oslo_utils import importutils import six from monascaclient.osc import migration from monascaclient import version as mc_version class MonascaShell(shell.OpenStackShell): def __init__(self): super(MonascaShell, self).__init__( description=__doc__.strip(), version=mc_version.version_string ) self.cloud_config = None def initialize_app(self, argv): super(MonascaShell, self).initialize_app(argv) self.cloud_config = cloud_config.OSC_Config( override_defaults={ 'interface': None, 'auth_type': self._auth_type, }, ) def build_option_parser(self, description, version): parser = super(MonascaShell, self).build_option_parser( description, version ) parser.set_defaults(cloud=None) parser = auth.build_auth_plugins_option_parser(parser) parser = self._append_monasca_args(parser) return parser @staticmethod def _append_monasca_args(parser): parser.add_argument('--monasca-api-url', default=utils.env('MONASCA_API_URL'), help='Defaults to env[MONASCA_API_URL].') parser.add_argument('--monasca_api_url', help=argparse.SUPPRESS) parser.add_argument('--monasca-api-version', default=utils.env( 'MONASCA_API_VERSION', default='2_0'), help='Defaults to env[MONASCA_API_VERSION] or 2_0') parser.add_argument('--monasca_api_version', help=argparse.SUPPRESS) return parser def _load_commands(self): version = self.options.monasca_api_version submodule = importutils.import_versioned_module('monascaclient', version, 'shell') self._find_actions(submodule) def _find_actions(self, actions_module): for attr in (a for a in dir(actions_module) if a.startswith('do_')): name, clazz = migration.create_command_class(attr, actions_module) if 'help' == name: # help requires no auth clazz.auth_required = False self.command_manager.add_command(name, clazz) def main(args=None): try: if args is None: args = sys.argv[1:] if six.PY2: # Emulate Py3, decode argv into Unicode based on locale so that # commands always see arguments as text instead of binary data encoding = locale.getpreferredencoding() if encoding: args = map(lambda arg: arg.decode(encoding), args) return MonascaShell().run(args) except Exception as e: if '--debug' in args or '-d' in args: raise else: print(e) sys.exit(1) if __name__ == "__main__": sys.exit(main(sys.argv[1:])) python-monascaclient-2.0.0/monascaclient/__init__.py0000664000175000017500000000445513620561064022636 0ustar zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ Patches method that transforms error responses. That is required to handle different format monasca follows. """ from keystoneauth1 import exceptions as exc from keystoneauth1.exceptions import http def mon_exc_from_response(response, method, url): req_id = response.headers.get('x-openstack-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): if isinstance(body.get('error'), dict): error = body['error'] kwargs['message'] = error.get('message') kwargs['details'] = error.get('details') elif {'description', 'title'} <= set(body): # monasca-api error response structure kwargs['message'] = body.get('title') kwargs['details'] = body.get('description') elif content_type.startswith('text/'): kwargs['details'] = response.text try: cls = http._code_map[response.status_code] except KeyError: if 500 <= response.status_code < 600: cls = exc.HttpServerError elif 400 <= response.status_code < 500: cls = exc.HTTPClientError else: cls = exc.HttpError return cls(**kwargs) exc.from_response = mon_exc_from_response python-monascaclient-2.0.0/monascaclient/v2_0/0000775000175000017500000000000013620561132021257 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/v2_0/shell.py0000664000175000017500000017024413620561064022754 0ustar zuulzuul00000000000000# (C) Copyright 2014-2017 Hewlett Packard Enterprise Development LP # Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import datetime import numbers import time from keystoneauth1 import exceptions as k_exc from osc_lib import exceptions as osc_exc from monascaclient.common import utils from oslo_serialization import jsonutils # Alarm valid types severity_types = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] state_types = ['UNDETERMINED', 'ALARM', 'OK'] enabled_types = ['True', 'true', 'False', 'false'] group_by_types = ['alarm_definition_id', 'name', 'state', 'severity', 'link', 'lifecycle_state', 'metric_name', 'dimension_name', 'dimension_value'] allowed_notification_sort_by = {'id', 'name', 'type', 'address', 'created_at', 'updated_at'} allowed_alarm_sort_by = {'alarm_id', 'alarm_definition_id', 'alarm_definition_name', 'state', 'severity', 'lifecycle_state', 'link', 'state_updated_timestamp', 'updated_timestamp', 'created_timestamp'} allowed_definition_sort_by = {'id', 'name', 'severity', 'updated_at', 'created_at'} # Notification valid types notification_types = ['EMAIL', 'WEBHOOK', 'PAGERDUTY'] @utils.arg('name', metavar='', help='Name of the metric to create.') @utils.arg('--dimensions', metavar='', help='key value pair used to create a metric dimension. ' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'Dimensions need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('--value-meta', metavar='', help='key value pair for extra information about a value. ' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'value_meta need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('--time', metavar='', default=time.time() * 1000, type=int, help='Metric timestamp in milliseconds. Default: current timestamp.') @utils.arg('--project-id', metavar='', help='The Project ID to create metric on behalf of. ' 'Requires monitoring-delegate role in keystone.') @utils.arg('value', metavar='', type=float, help='Metric value.') def do_metric_create(mc, args): '''Create metric.''' fields = {} fields['name'] = args.name if args.dimensions: fields['dimensions'] = utils.format_parameters(args.dimensions) fields['timestamp'] = args.time fields['value'] = args.value if args.value_meta: fields['value_meta'] = utils.format_parameters(args.value_meta) if args.project_id: fields['tenant_id'] = args.project_id try: mc.metrics.create(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print('Successfully created metric') @utils.arg('jsonbody', metavar='', type=jsonutils.loads, help='The raw JSON body in single quotes. See api doc.') def do_metric_create_raw(mc, args): '''Create metric from raw json body.''' try: mc.metrics.create(**args.jsonbody) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print('Successfully created metric') @utils.arg('--dimensions', metavar='', help='key value pair used to specify a metric dimension. ' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'Dimensions need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') @utils.arg('--tenant-id', metavar='', help="Retrieve data for the specified tenant/project id instead of " "the tenant/project from the user's Keystone credentials.") def do_metric_name_list(mc, args): '''List names of metrics.''' fields = {} if args.dimensions: fields['dimensions'] = utils.format_dimensions_query(args.dimensions) if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset if args.tenant_id: fields['tenant_id'] = args.tenant_id try: metric_names = mc.metrics.list_names(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(metric_names)) return if isinstance(metric_names, list): utils.print_list(metric_names, ['Name'], formatters={'Name': lambda x: x['name']}) @utils.arg('--name', metavar='', help='Name of the metric to list.') @utils.arg('--dimensions', metavar='', help='key value pair used to specify a metric dimension. ' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'Dimensions need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('--starttime', metavar='', help='measurements >= UTC time. format: 2014-01-01T00:00:00Z. OR' ' Format: -120 (previous 120 minutes).') @utils.arg('--endtime', metavar='', help='measurements <= UTC time. format: 2014-01-01T00:00:00Z.') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') @utils.arg('--tenant-id', metavar='', help="Retrieve data for the specified tenant/project id instead of " "the tenant/project from the user's Keystone credentials.") def do_metric_list(mc, args): '''List metrics for this tenant.''' fields = {} if args.name: fields['name'] = args.name if args.dimensions: fields['dimensions'] = utils.format_dimensions_query(args.dimensions) if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset if args.starttime: _translate_starttime(args) fields['start_time'] = args.starttime if args.endtime: fields['end_time'] = args.endtime if args.tenant_id: fields['tenant_id'] = args.tenant_id try: metric = mc.metrics.list(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(metric)) return cols = ['name', 'dimensions'] formatters = { 'name': lambda x: x['name'], 'dimensions': lambda x: utils.format_dict(x['dimensions']), } if isinstance(metric, list): # print the list utils.print_list(metric, cols, formatters=formatters) else: # add the dictionary to a list, so print_list works metric_list = list() metric_list.append(metric) utils.print_list( metric_list, cols, formatters=formatters) @utils.arg('--metric-name', metavar='', help='Name of the metric to report dimension name list.', action='append') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum ' 'limit.') @utils.arg('--tenant-id', metavar='', help="Retrieve data for the specified tenant/project id instead of " "the tenant/project from the user's Keystone credentials.") def do_dimension_name_list(mc, args): '''List names of metric dimensions.''' fields = {} if args.metric_name: fields['metric_name'] = args.metric_name if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset if args.tenant_id: fields['tenant_id'] = args.tenant_id try: dimension_names = mc.metrics.list_dimension_names(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) if args.json: print(utils.json_formatter(dimension_names)) return if isinstance(dimension_names, list): utils.print_list(dimension_names, ['Dimension Names'], formatters={ 'Dimension Names': lambda x: x['dimension_name']}) @utils.arg('dimension_name', metavar='', help='Name of the dimension to list dimension values.') @utils.arg('--metric-name', metavar='', help='Name of the metric to report dimension value list.', action='append') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum ' 'limit.') @utils.arg('--tenant-id', metavar='', help="Retrieve data for the specified tenant/project id instead of " "the tenant/project from the user's Keystone credentials.") def do_dimension_value_list(mc, args): '''List names of metric dimensions.''' fields = {} fields['dimension_name'] = args.dimension_name if args.metric_name: fields['metric_name'] = args.metric_name if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset if args.tenant_id: fields['tenant_id'] = args.tenant_id try: dimension_values = mc.metrics.list_dimension_values(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) if args.json: print(utils.json_formatter(dimension_values)) return if isinstance(dimension_values, list): utils.print_list(dimension_values, ['Dimension Values'], formatters={ 'Dimension Values': lambda x: x['dimension_value']}) def format_measure_timestamp(measurements): # returns newline separated times for the timestamp column return '\n'.join([str(m[0]) for m in measurements]) def format_measure_value(measurements): # returns newline separated values for the value column return '\n'.join(['{:12.3f}'.format(m[1]) for m in measurements]) def format_value_meta(measurements): # returns newline separated values for the value column measure_string_list = list() for measure in measurements: if len(measure) < 3: measure_string = "" else: meta_string_list = [] for k, v in measure[2].items(): if isinstance(v, numbers.Number): m_str = k + ': ' + str(v) else: m_str = k + ': ' + v meta_string_list.append(m_str) measure_string = ','.join(meta_string_list) measure_string_list.append(measure_string) return '\n'.join(measure_string_list) def format_statistic_timestamp(statistics, columns, name): # returns newline separated times for the timestamp column time_index = 0 if statistics: time_index = columns.index(name) time_list = list() for timestamp in statistics: time_list.append(str(timestamp[time_index])) return '\n'.join(time_list) def format_statistic_value(statistics, columns, stat_type): # find the index for column name stat_index = 0 if statistics: stat_index = columns.index(stat_type) value_list = list() for stat in statistics: value_str = '{:12.3f}'.format(stat[stat_index]) value_list.append(value_str) return '\n'.join(value_list) def format_metric_name(metrics): # returns newline separated metric names for the column metric_string_list = list() for metric in metrics: metric_name = metric['name'] metric_dimensions = metric['dimensions'] metric_string_list.append(metric_name) # need to line up with dimensions column rng = len(metric_dimensions) for i in range(rng): if i == rng - 1: # last one break metric_string_list.append(" ") return '\n'.join(metric_string_list) def format_metric_dimensions(metrics): # returns newline separated dimension key values for the column metric_string_list = list() for metric in metrics: metric_dimensions = metric['dimensions'] for k, v in metric_dimensions.items(): if isinstance(v, numbers.Number): d_str = k + ': ' + str(v) else: d_str = k + ': ' + v metric_string_list.append(d_str) return '\n'.join(metric_string_list) @utils.arg('name', metavar='', help='Name of the metric to list measurements.') @utils.arg('--dimensions', metavar='', help='key value pair used to specify a metric dimension. ' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'Dimensions need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('starttime', metavar='', help='measurements >= UTC time. format: 2014-01-01T00:00:00Z.' ' OR Format: -120 (previous 120 minutes).') @utils.arg('--endtime', metavar='', help='measurements <= UTC time. format: 2014-01-01T00:00:00Z.') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') @utils.arg('--merge_metrics', action='store_const', const=True, help='Merge multiple metrics into a single result.') @utils.arg('--group_by', metavar='', help='Select which keys to use for grouping. A \'*\' groups by all keys.') @utils.arg('--tenant-id', metavar='', help="Retrieve data for the specified tenant/project id instead of " "the tenant/project from the user's Keystone credentials.") def do_measurement_list(mc, args): '''List measurements for the specified metric.''' fields = {} fields['name'] = args.name if args.dimensions: fields['dimensions'] = utils.format_dimensions_query(args.dimensions) _translate_starttime(args) fields['start_time'] = args.starttime if args.endtime: fields['end_time'] = args.endtime if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset if args.merge_metrics: fields['merge_metrics'] = args.merge_metrics if args.group_by: fields['group_by'] = args.group_by if args.tenant_id: fields['tenant_id'] = args.tenant_id try: metric = mc.metrics.list_measurements(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(metric)) return cols = ['name', 'dimensions', 'timestamp', 'value', 'value_meta'] formatters = { 'name': lambda x: x['name'], 'dimensions': lambda x: utils.format_dict(x['dimensions']), 'timestamp': lambda x: format_measure_timestamp(x['measurements']), 'value': lambda x: format_measure_value(x['measurements']), 'value_meta': lambda x: format_value_meta(x['measurements']), } if isinstance(metric, list): # print the list utils.print_list(metric, cols, formatters=formatters) else: # add the dictionary to a list, so print_list works metric_list = list() metric_list.append(metric) utils.print_list( metric_list, cols, formatters=formatters) @utils.arg('name', metavar='', help='Name of the metric to report measurement statistics.') @utils.arg('statistics', metavar='', help='Statistics is one or more (separated by commas) of ' '[AVG, MIN, MAX, COUNT, SUM].') @utils.arg('--dimensions', metavar='', help='key value pair used to specify a metric dimension. ' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'Dimensions need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('starttime', metavar='', help='measurements >= UTC time. format: 2014-01-01T00:00:00Z. OR' ' Format: -120 (previous 120 minutes).') @utils.arg('--endtime', metavar='', help='measurements <= UTC time. format: 2014-01-01T00:00:00Z.') @utils.arg('--period', metavar='', help='number of seconds per interval (default is 300)') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') @utils.arg('--merge_metrics', action='store_const', const=True, help='Merge multiple metrics into a single result.') @utils.arg('--group_by', metavar='', help='Select which keys to use for grouping. A \'*\' groups by all keys.') @utils.arg('--tenant-id', metavar='', help="Retrieve data for the specified tenant/project id instead of " "the tenant/project from the user's Keystone credentials.") def do_metric_statistics(mc, args): '''List measurement statistics for the specified metric.''' statistic_types = ['AVG', 'MIN', 'MAX', 'COUNT', 'SUM'] statlist = args.statistics.split(',') for stat in statlist: if stat.upper() not in statistic_types: errmsg = ('Invalid type, not one of [' + ', '.join(statistic_types) + ']') raise osc_exc.CommandError(errmsg) fields = {} fields['name'] = args.name if args.dimensions: fields['dimensions'] = utils.format_dimensions_query(args.dimensions) _translate_starttime(args) fields['start_time'] = args.starttime if args.endtime: fields['end_time'] = args.endtime if args.period: fields['period'] = args.period fields['statistics'] = args.statistics if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset if args.merge_metrics: fields['merge_metrics'] = args.merge_metrics if args.group_by: fields['group_by'] = args.group_by if args.tenant_id: fields['tenant_id'] = args.tenant_id try: metric = mc.metrics.list_statistics(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(metric)) return cols = ['name', 'dimensions'] # add dynamic column names if metric: column_names = metric[0]['columns'] for name in column_names: cols.append(name) else: # when empty set, print_list needs a col cols.append('timestamp') formatters = { 'name': lambda x: x['name'], 'dimensions': lambda x: utils.format_dict(x['dimensions']), 'timestamp': lambda x: format_statistic_timestamp(x['statistics'], x['columns'], 'timestamp'), 'avg': lambda x: format_statistic_value(x['statistics'], x['columns'], 'avg'), 'min': lambda x: format_statistic_value(x['statistics'], x['columns'], 'min'), 'max': lambda x: format_statistic_value(x['statistics'], x['columns'], 'max'), 'count': lambda x: format_statistic_value(x['statistics'], x['columns'], 'count'), 'sum': lambda x: format_statistic_value(x['statistics'], x['columns'], 'sum'), } if isinstance(metric, list): # print the list utils.print_list(metric, cols, formatters=formatters) else: # add the dictionary to a list, so print_list works metric_list = list() metric_list.append(metric) utils.print_list( metric_list, cols, formatters=formatters) def _validate_notification_period(period, notification_type): if notification_type != 'WEBHOOK' and period != 0: print("Invalid period, can only be non zero for webhooks") return False return True @utils.arg('name', metavar='', help='Name of the notification to create.') @utils.arg('type', metavar='', help='The notification type. Type must be EMAIL, WEBHOOK, or PAGERDUTY.') @utils.arg('address', metavar='
', help='A valid EMAIL Address, URL, or SERVICE KEY.') @utils.arg('--period', metavar='', type=int, default=0, help='A period for the notification method. Can only be non zero with webhooks') def do_notification_create(mc, args): '''Create notification.''' fields = {} fields['name'] = args.name fields['type'] = args.type fields['address'] = args.address if args.period: if not _validate_notification_period(args.period, args.type.upper()): return fields['period'] = args.period try: notification = mc.notifications.create(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print(jsonutils.dumps(notification, indent=2)) @utils.arg('id', metavar='', help='The ID of the notification.') def do_notification_show(mc, args): '''Describe the notification.''' fields = {} fields['notification_id'] = args.id try: notification = mc.notifications.get(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(notification)) return formatters = { 'name': utils.json_formatter, 'id': utils.json_formatter, 'type': utils.json_formatter, 'address': utils.json_formatter, 'period': utils.json_formatter, 'links': utils.format_dictlist, } utils.print_dict(notification, formatters=formatters) @utils.arg('--sort-by', metavar='', help='Fields to sort by as a comma separated list. Valid values are id, ' 'name, type, address, created_at, updated_at. ' 'Fields may be followed by "asc" or "desc", ex "address desc", ' 'to set the direction of sorting.') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') def do_notification_list(mc, args): '''List notifications for this tenant.''' fields = {} if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset if args.sort_by: sort_by = args.sort_by.split(',') for field in sort_by: field_values = field.lower().split() if len(field_values) > 2: print("Invalid sort_by value {}".format(field)) if field_values[0] not in allowed_notification_sort_by: print("Sort-by field name {} is not in [{}]".format(field_values[0], allowed_notification_sort_by)) return if len(field_values) > 1 and field_values[1] not in ['asc', 'desc']: print("Invalid value {}, must be asc or desc".format(field_values[1])) fields['sort_by'] = args.sort_by try: notification = mc.notifications.list(**fields) except osc_exc.ClientException as he: raise osc_exc.CommandError( 'ClientException code=%s message=%s' % (he.code, he.message)) else: if args.json: print(utils.json_formatter(notification)) return cols = ['name', 'id', 'type', 'address', 'period'] formatters = { 'name': lambda x: x['name'], 'id': lambda x: x['id'], 'type': lambda x: x['type'], 'address': lambda x: x['address'], 'period': lambda x: x['period'], } if isinstance(notification, list): utils.print_list( notification, cols, formatters=formatters) else: notif_list = list() notif_list.append(notification) utils.print_list(notif_list, cols, formatters=formatters) @utils.arg('id', metavar='', help='The ID of the notification.') def do_notification_delete(mc, args): '''Delete notification.''' fields = {} fields['notification_id'] = args.id try: mc.notifications.delete(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print('Successfully deleted notification') @utils.arg('id', metavar='', help='The ID of the notification.') @utils.arg('name', metavar='', help='Name of the notification.') @utils.arg('type', metavar='', help='The notification type. Type must be either EMAIL, WEBHOOK, or PAGERDUTY.') @utils.arg('address', metavar='
', help='A valid EMAIL Address, URL, or SERVICE KEY.') @utils.arg('period', metavar='', type=int, help='A period for the notification method. Can only be non zero with webhooks') def do_notification_update(mc, args): '''Update notification.''' fields = {} fields['notification_id'] = args.id fields['name'] = args.name fields['type'] = args.type fields['address'] = args.address if not _validate_notification_period(args.period, args.type.upper()): return fields['period'] = args.period try: notification = mc.notifications.update(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print(jsonutils.dumps(notification, indent=2)) @utils.arg('id', metavar='', help='The ID of the notification.') @utils.arg('--name', metavar='', help='Name of the notification.') @utils.arg('--type', metavar='', help='The notification type. Type must be either EMAIL, WEBHOOK, or PAGERDUTY.') @utils.arg('--address', metavar='
', help='A valid EMAIL Address, URL, or SERVICE KEY.') @utils.arg('--period', metavar='', type=int, help='A period for the notification method. Can only be non zero with webhooks') def do_notification_patch(mc, args): '''Patch notification.''' fields = {} fields['notification_id'] = args.id if args.name: fields['name'] = args.name if args.type: fields['type'] = args.type if args.address: fields['address'] = args.address if args.period or args.period == 0: if args.type and not _validate_notification_period( args.period, args.type.upper()): return fields['period'] = args.period try: notification = mc.notifications.patch(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print(jsonutils.dumps(notification, indent=2)) def _validate_severity(severity): if severity.upper() not in severity_types: errmsg = ('Invalid severity, not one of [' + ', '.join(severity_types) + ']') print(errmsg) return False return True @utils.arg('name', metavar='', help='Name of the alarm definition to create.') @utils.arg('--description', metavar='', help='Description of the alarm.') @utils.arg('expression', metavar='', help='The alarm expression to evaluate. Quoted.') @utils.arg('--severity', metavar='', help='Severity is one of [LOW, MEDIUM, HIGH, CRITICAL].') @utils.arg('--match-by', metavar='', help='The metric dimensions to use to create unique alarms. ' 'One or more dimension key names separated by a comma. ' 'Key names need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.') @utils.arg('--alarm-actions', metavar='', help='The notification method to use when an alarm state is ALARM. ' 'This param may be specified multiple times.', action='append') @utils.arg('--ok-actions', metavar='', help='The notification method to use when an alarm state is OK. ' 'This param may be specified multiple times.', action='append') @utils.arg('--undetermined-actions', metavar='', help='The notification method to use when an alarm state is ' 'UNDETERMINED. This param may be specified multiple times.', action='append') def do_alarm_definition_create(mc, args): '''Create an alarm definition.''' fields = {} fields['name'] = args.name if args.description: fields['description'] = args.description fields['expression'] = args.expression if args.alarm_actions: fields['alarm_actions'] = args.alarm_actions if args.ok_actions: fields['ok_actions'] = args.ok_actions if args.undetermined_actions: fields['undetermined_actions'] = args.undetermined_actions if args.severity: if not _validate_severity(args.severity): return fields['severity'] = args.severity if args.match_by: fields['match_by'] = args.match_by.split(',') try: alarm = mc.alarm_definitions.create(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print(jsonutils.dumps(alarm, indent=2)) @utils.arg('id', metavar='', help='The ID of the alarm definition.') def do_alarm_definition_show(mc, args): '''Describe the alarm definition.''' fields = {} fields['alarm_id'] = args.id try: alarm = mc.alarm_definitions.get(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(alarm)) return # print out detail of a single alarm formatters = { 'name': utils.json_formatter, 'id': utils.json_formatter, 'expression': utils.json_formatter, 'expression_data': utils.format_expression_data, 'match_by': utils.json_formatter, 'actions_enabled': utils.json_formatter, 'alarm_actions': utils.json_formatter, 'ok_actions': utils.json_formatter, 'severity': utils.json_formatter, 'undetermined_actions': utils.json_formatter, 'description': utils.json_formatter, 'links': utils.format_dictlist, } utils.print_dict(alarm, formatters=formatters) @utils.arg('--name', metavar='', help='Name of the alarm definition.') @utils.arg('--dimensions', metavar='', help='key value pair used to specify a metric dimension. ' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'Dimensions need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('--severity', metavar='', help='Severity is one of ["LOW", "MEDIUM", "HIGH", "CRITICAL"].') @utils.arg('--sort-by', metavar='', help='Fields to sort by as a comma separated list. Valid values are id, ' 'name, severity, created_at, updated_at. ' 'Fields may be followed by "asc" or "desc", ex "severity desc", ' 'to set the direction of sorting.') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') def do_alarm_definition_list(mc, args): '''List alarm definitions for this tenant.''' fields = {} if args.name: fields['name'] = args.name if args.dimensions: fields['dimensions'] = utils.format_dimensions_query(args.dimensions) if args.severity: if not _validate_severity(args.severity): return fields['severity'] = args.severity if args.sort_by: sort_by = args.sort_by.split(',') for field in sort_by: field_values = field.split() if len(field_values) > 2: print("Invalid sort_by value {}".format(field)) if field_values[0] not in allowed_definition_sort_by: print("Sort-by field name {} is not in [{}]".format(field_values[0], allowed_definition_sort_by)) return if len(field_values) > 1 and field_values[1] not in ['asc', 'desc']: print("Invalid value {}, must be asc or desc".format(field_values[1])) fields['sort_by'] = args.sort_by if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset try: alarm = mc.alarm_definitions.list(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(alarm)) return cols = ['name', 'id', 'expression', 'match_by', 'actions_enabled'] formatters = { 'name': lambda x: x['name'], 'id': lambda x: x['id'], 'expression': lambda x: x['expression'], 'match_by': lambda x: utils.format_list(x['match_by']), 'actions_enabled': lambda x: x['actions_enabled'], } if isinstance(alarm, list): # print the list utils.print_list(alarm, cols, formatters=formatters) else: # add the dictionary to a list, so print_list works alarm_list = list() alarm_list.append(alarm) utils.print_list(alarm_list, cols, formatters=formatters) @utils.arg('id', metavar='', help='The ID of the alarm definition.') def do_alarm_definition_delete(mc, args): '''Delete the alarm definition.''' fields = {} fields['alarm_id'] = args.id try: mc.alarm_definitions.delete(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print('Successfully deleted alarm definition') @utils.arg('id', metavar='', help='The ID of the alarm definition.') @utils.arg('name', metavar='', help='Name of the alarm definition.') @utils.arg('description', metavar='', help='Description of the alarm.') @utils.arg('expression', metavar='', help='The alarm expression to evaluate. Quoted.') @utils.arg('alarm_actions', metavar='', help='The notification method(s) to use when an alarm state is ALARM ' 'as a comma separated list.') @utils.arg('ok_actions', metavar='', help='The notification method(s) to use when an alarm state is OK ' 'as a comma separated list.') @utils.arg('undetermined_actions', metavar='', help='The notification method(s) to use when an alarm state is UNDETERMINED ' 'as a comma separated list.') @utils.arg('actions_enabled', metavar='', help='The actions-enabled boolean is one of [true,false]') @utils.arg('match_by', metavar='', help='The metric dimensions to use to create unique alarms. ' 'One or more dimension key names separated by a comma. ' 'Key names need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.') @utils.arg('severity', metavar='', help='Severity is one of [LOW, MEDIUM, HIGH, CRITICAL].') def do_alarm_definition_update(mc, args): '''Update the alarm definition.''' fields = {} fields['alarm_id'] = args.id fields['name'] = args.name fields['description'] = args.description fields['expression'] = args.expression fields['alarm_actions'] = _arg_split_patch_update(args.alarm_actions) fields['ok_actions'] = _arg_split_patch_update(args.ok_actions) fields['undetermined_actions'] = _arg_split_patch_update(args.undetermined_actions) if args.actions_enabled not in enabled_types: errmsg = ('Invalid value, not one of [' + ', '.join(enabled_types) + ']') print(errmsg) return fields['actions_enabled'] = args.actions_enabled in ['true', 'True'] fields['match_by'] = _arg_split_patch_update(args.match_by) if not _validate_severity(args.severity): return fields['severity'] = args.severity try: alarm = mc.alarm_definitions.update(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print(jsonutils.dumps(alarm, indent=2)) @utils.arg('id', metavar='', help='The ID of the alarm definition.') @utils.arg('--name', metavar='', help='Name of the alarm definition.') @utils.arg('--description', metavar='', help='Description of the alarm.') @utils.arg('--expression', metavar='', help='The alarm expression to evaluate. Quoted.') @utils.arg('--alarm-actions', metavar='', help='The notification method to use when an alarm state is ALARM. ' 'This param may be specified multiple times.', action='append') @utils.arg('--ok-actions', metavar='', help='The notification method to use when an alarm state is OK. ' 'This param may be specified multiple times.', action='append') @utils.arg('--undetermined-actions', metavar='', help='The notification method to use when an alarm state is ' 'UNDETERMINED. This param may be specified multiple times.', action='append') @utils.arg('--actions-enabled', metavar='', help='The actions-enabled boolean is one of [true,false].') @utils.arg('--severity', metavar='', help='Severity is one of [LOW, MEDIUM, HIGH, CRITICAL].') def do_alarm_definition_patch(mc, args): '''Patch the alarm definition.''' fields = {} fields['alarm_id'] = args.id if args.name: fields['name'] = args.name if args.description: fields['description'] = args.description if args.expression: fields['expression'] = args.expression if args.alarm_actions: fields['alarm_actions'] = _arg_split_patch_update(args.alarm_actions, patch=True) if args.ok_actions: fields['ok_actions'] = _arg_split_patch_update(args.ok_actions, patch=True) if args.undetermined_actions: fields['undetermined_actions'] = _arg_split_patch_update(args.undetermined_actions, patch=True) if args.actions_enabled: if args.actions_enabled not in enabled_types: errmsg = ('Invalid value, not one of [' + ', '.join(enabled_types) + ']') print(errmsg) return fields['actions_enabled'] = args.actions_enabled in ['true', 'True'] if args.severity: if not _validate_severity(args.severity): return fields['severity'] = args.severity try: alarm = mc.alarm_definitions.patch(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print(jsonutils.dumps(alarm, indent=2)) @utils.arg('--alarm-definition-id', metavar='', help='The ID of the alarm definition.') @utils.arg('--metric-name', metavar='', help='Name of the metric.') @utils.arg('--metric-dimensions', metavar='', help='key value pair used to specify a metric dimension or ' 'just key to select all values of that dimension.' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'Dimensions need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('--state', metavar='', help='ALARM_STATE is one of [UNDETERMINED, OK, ALARM].') @utils.arg('--severity', metavar='', help='Severity is one of ["LOW", "MEDIUM", "HIGH", "CRITICAL"].') @utils.arg('--state-updated-start-time', metavar='', help='Return all alarms whose state was updated on or after the time specified.') @utils.arg('--lifecycle-state', metavar='', help='The lifecycle state of the alarm.') @utils.arg('--link', metavar='', help='The link to external data associated with the alarm.') @utils.arg('--sort-by', metavar='', help='Fields to sort by as a comma separated list. Valid values are alarm_id, ' 'alarm_definition_id, state, severity, lifecycle_state, link, ' 'state_updated_timestamp, updated_timestamp, created_timestamp. ' 'Fields may be followed by "asc" or "desc", ex "severity desc", ' 'to set the direction of sorting.') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') def do_alarm_list(mc, args): '''List alarms for this tenant.''' fields = {} if args.alarm_definition_id: fields['alarm_definition_id'] = args.alarm_definition_id if args.metric_name: fields['metric_name'] = args.metric_name if args.metric_dimensions: fields['metric_dimensions'] = utils.format_dimensions_query(args.metric_dimensions) if args.state: if args.state.upper() not in state_types: errmsg = ('Invalid state, not one of [' + ', '.join(state_types) + ']') print(errmsg) return fields['state'] = args.state if args.severity: if not _validate_severity(args.severity): return fields['severity'] = args.severity if args.state_updated_start_time: fields['state_updated_start_time'] = args.state_updated_start_time if args.lifecycle_state: fields['lifecycle_state'] = args.lifecycle_state if args.link: fields['link'] = args.link if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset if args.sort_by: sort_by = args.sort_by.split(',') for field in sort_by: field_values = field.lower().split() if len(field_values) > 2: print("Invalid sort_by value {}".format(field)) if field_values[0] not in allowed_alarm_sort_by: print("Sort-by field name {} is not in [{}]".format(field_values[0], allowed_alarm_sort_by)) return if len(field_values) > 1 and field_values[1] not in ['asc', 'desc']: print("Invalid value {}, must be asc or desc".format(field_values[1])) fields['sort_by'] = args.sort_by try: alarm = mc.alarms.list(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(alarm)) return cols = ['id', 'alarm_definition_id', 'alarm_definition_name', 'metric_name', 'metric_dimensions', 'severity', 'state', 'lifecycle_state', 'link', 'state_updated_timestamp', 'updated_timestamp', "created_timestamp"] formatters = { 'id': lambda x: x['id'], 'alarm_definition_id': lambda x: x['alarm_definition']['id'], 'alarm_definition_name': lambda x: x['alarm_definition']['name'], 'metric_name': lambda x: format_metric_name(x['metrics']), 'metric_dimensions': lambda x: format_metric_dimensions(x['metrics']), 'severity': lambda x: x['alarm_definition']['severity'], 'state': lambda x: x['state'], 'lifecycle_state': lambda x: x['lifecycle_state'], 'link': lambda x: x['link'], 'state_updated_timestamp': lambda x: x['state_updated_timestamp'], 'updated_timestamp': lambda x: x['updated_timestamp'], 'created_timestamp': lambda x: x['created_timestamp'], } if isinstance(alarm, list): # print the list utils.print_list(alarm, cols, formatters=formatters) else: # add the dictionary to a list, so print_list works alarm_list = list() alarm_list.append(alarm) utils.print_list(alarm_list, cols, formatters=formatters) @utils.arg('id', metavar='', help='The ID of the alarm.') def do_alarm_show(mc, args): '''Describe the alarm.''' fields = {} fields['alarm_id'] = args.id try: alarm = mc.alarms.get(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(alarm)) return # print out detail of a single alarm formatters = { 'id': utils.json_formatter, 'alarm_definition': utils.json_formatter, 'metrics': utils.json_formatter, 'state': utils.json_formatter, 'links': utils.format_dictlist, } utils.print_dict(alarm, formatters=formatters) @utils.arg('id', metavar='', help='The ID of the alarm.') @utils.arg('state', metavar='', help='ALARM_STATE is one of [UNDETERMINED, OK, ALARM].') @utils.arg('lifecycle_state', metavar='', help='The lifecycle state of the alarm.') @utils.arg('link', metavar='', help='A link to an external resource with information about the alarm.') def do_alarm_update(mc, args): '''Update the alarm state.''' fields = {} fields['alarm_id'] = args.id if args.state.upper() not in state_types: errmsg = ('Invalid state, not one of [' + ', '.join(state_types) + ']') print(errmsg) return fields['state'] = args.state fields['lifecycle_state'] = args.lifecycle_state fields['link'] = args.link try: alarm = mc.alarms.update(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print(jsonutils.dumps(alarm, indent=2)) @utils.arg('id', metavar='', help='The ID of the alarm.') @utils.arg('--state', metavar='', help='ALARM_STATE is one of [UNDETERMINED, OK, ALARM].') @utils.arg('--lifecycle-state', metavar='', help='The lifecycle state of the alarm.') @utils.arg('--link', metavar='', help='A link to an external resource with information about the alarm.') def do_alarm_patch(mc, args): '''Patch the alarm state.''' fields = {} fields['alarm_id'] = args.id if args.state: if args.state.upper() not in state_types: errmsg = ('Invalid state, not one of [' + ', '.join(state_types) + ']') print(errmsg) return fields['state'] = args.state if args.lifecycle_state: fields['lifecycle_state'] = args.lifecycle_state if args.link: fields['link'] = args.link try: alarm = mc.alarms.patch(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print(jsonutils.dumps(alarm, indent=2)) @utils.arg('id', metavar='', help='The ID of the alarm.') def do_alarm_delete(mc, args): '''Delete the alarm.''' fields = {} fields['alarm_id'] = args.id try: mc.alarms.delete(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: print('Successfully deleted alarm') def output_alarm_history(args, alarm_history): if args.json: print(utils.json_formatter(alarm_history)) return # format output cols = ['alarm_id', 'new_state', 'old_state', 'reason', 'reason_data', 'metric_name', 'metric_dimensions', 'timestamp'] formatters = { 'alarm_id': lambda x: x['alarm_id'], 'new_state': lambda x: x['new_state'], 'old_state': lambda x: x['old_state'], 'reason': lambda x: x['reason'], 'reason_data': lambda x: x['reason_data'], 'metric_name': lambda x: format_metric_name(x['metrics']), 'metric_dimensions': lambda x: format_metric_dimensions(x['metrics']), 'timestamp': lambda x: x['timestamp'], } if isinstance(alarm_history, list): # print the list utils.print_list(alarm_history, cols, formatters=formatters) else: # add the dictionary to a list, so print_list works alarm_list = list() alarm_list.append(alarm_history) utils.print_list(alarm_list, cols, formatters=formatters) @utils.arg('--alarm-definition-id', metavar='', help='The ID of the alarm definition.') @utils.arg('--metric-name', metavar='', help='Name of the metric.') @utils.arg('--metric-dimensions', metavar='', help='key value pair used to specify a metric dimension or ' 'just key to select all values of that dimension.' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'Dimensions need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('--state', metavar='', help='ALARM_STATE is one of [UNDETERMINED, OK, ALARM].') @utils.arg('--severity', metavar='', help='Severity is one of ["LOW", "MEDIUM", "HIGH", "CRITICAL"].') @utils.arg('--state-updated-start-time', metavar='', help='Return all alarms whose state was updated on or after the time specified.') @utils.arg('--lifecycle-state', metavar='', help='The lifecycle state of the alarm.') @utils.arg('--link', metavar='', help='The link to external data associated with the alarm.') @utils.arg('--group-by', metavar='', help='Comma separated list of one or more fields to group the results by. ' 'Group by is one or more of [alarm_definition_id, name, state, link, ' 'lifecycle_state, metric_name, dimension_name, dimension_value].') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') def do_alarm_count(mc, args): '''Count alarms.''' fields = {} if args.alarm_definition_id: fields['alarm_definition_id'] = args.alarm_definition_id if args.metric_name: fields['metric_name'] = args.metric_name if args.metric_dimensions: fields['metric_dimensions'] = utils.format_dimensions_query(args.metric_dimensions) if args.state: if args.state.upper() not in state_types: errmsg = ('Invalid state, not one of [' + ', '.join(state_types) + ']') print(errmsg) return fields['state'] = args.state if args.severity: if not _validate_severity(args.severity): return fields['severity'] = args.severity if args.state_updated_start_time: fields['state_updated_start_time'] = args.state_updated_start_time if args.lifecycle_state: fields['lifecycle_state'] = args.lifecycle_state if args.link: fields['link'] = args.link if args.group_by: group_by = args.group_by.split(',') if not set(group_by).issubset(set(group_by_types)): errmsg = ('Invalid group-by, one or more values not in [' + ','.join(group_by_types) + ']') print(errmsg) return fields['group_by'] = args.group_by if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset try: counts = mc.alarms.count(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(counts)) return cols = counts['columns'] utils.print_list(counts['counts'], [i for i in range(len(cols))], field_labels=cols) @utils.arg('id', metavar='', help='The ID of the alarm.') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') def do_alarm_history(mc, args): '''Alarm state transition history.''' fields = {} fields['alarm_id'] = args.id if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset try: alarm = mc.alarms.history(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: output_alarm_history(args, alarm) @utils.arg('--dimensions', metavar='', help='key value pair used to specify a metric dimension. ' 'This can be specified multiple times, or once with parameters ' 'separated by a comma. ' 'Dimensions need quoting when they contain special chars [&,(,),{,},>,<] ' 'that confuse the CLI parser.', action='append') @utils.arg('--starttime', metavar='', help='measurements >= UTC time. format: 2014-01-01T00:00:00Z. OR' ' format: -120 (previous 120 minutes).') @utils.arg('--endtime', metavar='', help='measurements <= UTC time. format: 2014-01-01T00:00:00Z.') @utils.arg('--offset', metavar='', help='The offset used to paginate the return data.') @utils.arg('--limit', metavar='', help='The amount of data to be returned up to the API maximum limit.') def do_alarm_history_list(mc, args): '''List alarms state history.''' fields = {} if args.dimensions: fields['dimensions'] = utils.format_parameters(args.dimensions) if args.starttime: _translate_starttime(args) fields['start_time'] = args.starttime if args.endtime: fields['end_time'] = args.endtime if args.limit: fields['limit'] = args.limit if args.offset: fields['offset'] = args.offset try: alarm = mc.alarms.history_list(**fields) except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: output_alarm_history(args, alarm) def do_notification_type_list(mc, args): '''List notification types supported by monasca.''' try: notification_types = mc.notificationtypes.list() except (osc_exc.ClientException, k_exc.HttpError) as he: raise osc_exc.CommandError('%s\n%s' % (he.message, he.details)) else: if args.json: print(utils.json_formatter(notification_types)) return else: formatters = {'types': lambda x: x["type"]} # utils.print_list(notification_types['types'], ["types"], formatters=formatters) utils.print_list(notification_types, ["types"], formatters=formatters) def _translate_starttime(args): if args.starttime[0] == '-': deltaT = time.time() + (int(args.starttime) * 60) utc = str(datetime.datetime.utcfromtimestamp(deltaT)) utc = utc.replace(" ", "T")[:-7] + 'Z' args.starttime = utc def _arg_split_patch_update(arg, patch=False): if patch: arg = ','.join(arg) if not arg or arg == "[]": arg_split = [] else: arg_split = arg.split(',') return arg_split python-monascaclient-2.0.0/monascaclient/v2_0/metrics.py0000664000175000017500000000411213620561064023301 0ustar zuulzuul00000000000000# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP # Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from monascaclient.common import monasca_manager class MetricsManager(monasca_manager.MonascaManager): base_url = '/metrics' def create(self, **kwargs): """Create a metric.""" url_str = self.base_url if 'tenant_id' in kwargs: url_str = url_str + '?tenant_id=%s' % kwargs['tenant_id'] del kwargs['tenant_id'] data = kwargs['jsonbody'] if 'jsonbody' in kwargs else kwargs body = self.client.create(url=url_str, json=data) return body def list(self, **kwargs): """Get a list of metrics.""" return self._list('', 'dimensions', **kwargs) def list_names(self, **kwargs): """Get a list of metric names.""" return self._list('/names', 'dimensions', **kwargs) def list_measurements(self, **kwargs): """Get a list of measurements based on metric definition filters.""" return self._list('/measurements', 'dimensions', **kwargs) def list_statistics(self, **kwargs): """Get a list of measurement statistics based on metric def filters.""" return self._list('/statistics', 'dimensions', **kwargs) def list_dimension_names(self, **kwargs): """Get a list of metric dimension names.""" return self._list('/dimensions/names', **kwargs) def list_dimension_values(self, **kwargs): """Get a list of metric dimension values.""" return self._list('/dimensions/names/values', **kwargs) python-monascaclient-2.0.0/monascaclient/v2_0/notifications.py0000664000175000017500000000441513620561064024512 0ustar zuulzuul00000000000000# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP # Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from monascaclient.common import monasca_manager class NotificationsManager(monasca_manager.MonascaManager): base_url = '/notification-methods' def create(self, **kwargs): """Create a notification.""" body = self.client.create(url=self.base_url, json=kwargs) return body def get(self, **kwargs): """Get the details for a specific notification.""" # NOTE(trebskit) should actually be find_one, but # monasca does not support expected response format url = '%s/%s' % (self.base_url, kwargs['notification_id']) resp = self.client.list(path=url) return resp def list(self, **kwargs): """Get a list of notifications.""" return self._list('', **kwargs) def delete(self, **kwargs): """Delete a notification.""" url = self.base_url + '/%s' % kwargs['notification_id'] resp = self.client.delete(url=url) return resp def update(self, **kwargs): """Update a notification.""" url_str = self.base_url + '/%s' % kwargs['notification_id'] del kwargs['notification_id'] resp = self.client.create(url=url_str, method='PUT', json=kwargs) return resp def patch(self, **kwargs): """Patch a notification.""" url_str = self.base_url + '/%s' % kwargs['notification_id'] del kwargs['notification_id'] resp = self.client.create(url=url_str, method='PATCH', json=kwargs) return resp python-monascaclient-2.0.0/monascaclient/v2_0/__init__.py0000664000175000017500000000125613620561064023400 0ustar zuulzuul00000000000000# (C) Copyright 2014 Hewlett Packard Enterprise Development Company LP # # 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 monascaclient.v2_0.client import Client __all__ = ['Client'] python-monascaclient-2.0.0/monascaclient/v2_0/client.py0000664000175000017500000000270113620561064023113 0ustar zuulzuul00000000000000# (C) Copyright 2014-2015 Hewlett Packard Enterprise Development Company LP # Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from osc_lib.api import api from monascaclient.v2_0 import alarm_definitions as ad from monascaclient.v2_0 import alarms from monascaclient.v2_0 import metrics from monascaclient.v2_0 import notifications from monascaclient.v2_0 import notificationtypes as nt class Client(object): def __init__(self, *args, **kwargs): """Initialize a new http client for the monasca API.""" client = MonascaApi(*args, **kwargs) self.metrics = metrics.MetricsManager(client) self.notifications = notifications.NotificationsManager(client) self.alarms = alarms.AlarmsManager(client) self.alarm_definitions = ad.AlarmDefinitionsManager(client) self.notificationtypes = nt.NotificationTypesManager(client) class MonascaApi(api.BaseAPI): SERVICE_TYPE = "monitoring" python-monascaclient-2.0.0/monascaclient/v2_0/alarm_definitions.py0000664000175000017500000000446213620561064025332 0ustar zuulzuul00000000000000# (C) Copyright 2014-2015 Hewlett Packard Enterprise Development Company LP # Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from monascaclient.common import monasca_manager class AlarmDefinitionsManager(monasca_manager.MonascaManager): base_url = '/alarm-definitions' def create(self, **kwargs): """Create an alarm definition.""" resp = self.client.create(url=self.base_url, json=kwargs) return resp def get(self, **kwargs): """Get the details for a specific alarm definition.""" # NOTE(trebskit) should actually be find_one, but # monasca does not support expected response format url = '%s/%s' % (self.base_url, kwargs['alarm_id']) resp = self.client.list(path=url) return resp def list(self, **kwargs): """Get a list of alarm definitions.""" return self._list('', 'dimensions', **kwargs) def delete(self, **kwargs): """Delete a specific alarm definition.""" url_str = self.base_url + '/%s' % kwargs['alarm_id'] resp = self.client.delete(url_str) return resp def update(self, **kwargs): """Update a specific alarm definition.""" url_str = self.base_url + '/%s' % kwargs['alarm_id'] del kwargs['alarm_id'] resp = self.client.create(url=url_str, method='PUT', json=kwargs) return resp def patch(self, **kwargs): """Patch a specific alarm definition.""" url_str = self.base_url + '/%s' % kwargs['alarm_id'] del kwargs['alarm_id'] resp = self.client.create(url=url_str, method='PATCH', json=kwargs) return resp python-monascaclient-2.0.0/monascaclient/v2_0/notificationtypes.py0000664000175000017500000000162613620561064025415 0ustar zuulzuul00000000000000# (C) Copyright 2016 Hewlett Packard Enterprise Development LP # Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from monascaclient.common import monasca_manager class NotificationTypesManager(monasca_manager.MonascaManager): base_url = '/notification-methods/types' def list(self, **kwargs): """Get a list of notifications.""" return self._list('', **kwargs) python-monascaclient-2.0.0/monascaclient/v2_0/alarms.py0000664000175000017500000000650513620561064023122 0ustar zuulzuul00000000000000# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development Company LP # Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from six.moves.urllib import parse from monascaclient.common import monasca_manager class AlarmsManager(monasca_manager.MonascaManager): base_url = '/alarms' def get(self, **kwargs): """Get the details for a specific alarm.""" # NOTE(trebskit) should actually be find_one, but # monasca does not support expected response format url = '%s/%s' % (self.base_url, kwargs['alarm_id']) resp = self.client.list(path=url) return resp def list(self, **kwargs): """Get a list of alarms.""" return self._list('', 'metric_dimensions', **kwargs) def delete(self, **kwargs): """Delete a specific alarm.""" url_str = self.base_url + '/%s' % kwargs['alarm_id'] resp = self.client.delete(url_str) return resp def update(self, **kwargs): """Update a specific alarm.""" url_str = self.base_url + '/%s' % kwargs['alarm_id'] del kwargs['alarm_id'] body = self.client.create(url=url_str, method='PUT', json=kwargs) return body def patch(self, **kwargs): """Patch a specific alarm.""" url_str = self.base_url + '/%s' % kwargs['alarm_id'] del kwargs['alarm_id'] resp = self.client.create(url=url_str, method='PATCH', json=kwargs) return resp def count(self, **kwargs): url_str = self.base_url + '/count' if 'metric_dimensions' in kwargs: dimstr = self.get_dimensions_url_string( kwargs['metric_dimensions']) kwargs['metric_dimensions'] = dimstr if kwargs: url_str = url_str + '?%s' % parse.urlencode(kwargs, True) body = self.client.list(url_str) return body def history(self, **kwargs): """History of a specific alarm.""" url_str = self.base_url + '/%s/state-history' % kwargs['alarm_id'] del kwargs['alarm_id'] if kwargs: url_str = url_str + '?%s' % parse.urlencode(kwargs, True) resp = self.client.list(url_str) return resp['elements'] if type(resp) is dict else resp def history_list(self, **kwargs): """History list of alarm state.""" url_str = self.base_url + '/state-history/' if 'dimensions' in kwargs: dimstr = self.get_dimensions_url_string(kwargs['dimensions']) kwargs['dimensions'] = dimstr if kwargs: url_str = url_str + '?%s' % parse.urlencode(kwargs, True) resp = self.client.list(url_str) return resp['elements'] if type(resp) is dict else resp python-monascaclient-2.0.0/monascaclient/version.py0000664000175000017500000000136613620561064022562 0ustar zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from pbr import version __all__ = ['version_info', 'version_string'] version_info = version.VersionInfo('python-monascaclient') version_string = version_info.version_string() python-monascaclient-2.0.0/monascaclient/osc/0000775000175000017500000000000013620561132021275 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/osc/__init__.py0000664000175000017500000000000013620561064023400 0ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/osc/migration.py0000664000175000017500000001234113620561064023645 0ustar zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging import six from osc_lib.command import command from osc_lib import utils from monascaclient import version LOG = logging.getLogger(__name__) # NOTE(trebskit) this will be moved to another module # once initial migration is up # the point is to show how many code can we spare # in order to get the client working with minimum effort needed VERSION_MAP = { '2_0': 'monascaclient.v2_0.client.Client' } def make_client(api_version, session=None, endpoint=None, service_type='monitoring'): """Returns an monitoring API client.""" client_cls = utils.get_client_class('monitoring', api_version, VERSION_MAP) c = client_cls( session=session, service_type=service_type, endpoint=endpoint, app_name='monascaclient', app_version=version.version_string, ) return c def create_command_class(name, func_module): """Dynamically creates subclass of MigratingCommand. Method takes name of the function, module it is part of and builds the subclass of :py:class:`MigratingCommand`. Having a subclass of :py:class:`cliff.command.Command` is mandatory for the osc-lib integration. :param name: name of the function :type name: basestring :param func_module: the module function is part of :type func_module: module :return: command name, subclass of :py:class:`MigratingCommand` :rtype: tuple(basestring, class) """ cmd_name = name[3:].replace('_', '-') callback = getattr(func_module, name) desc = callback.__doc__ or '' help = desc.strip().split('\n')[0] arguments = getattr(callback, 'arguments', []) body = { '_args': arguments, '_callback': staticmethod(callback), '_description': desc, '_epilog': desc, '_help': help } claz = type('%sCommand' % cmd_name.title().replace('-', ''), (MigratingCommand,), body) return cmd_name, claz class MigratingCommandMeta(command.CommandMeta): """Overwrite module name based on osc_lib.CommandMeta requirements.""" def __new__(mcs, name, bases, cls_dict): # NOTE(trebskit) little dirty, but should suffice for migration period cls_dict['__module__'] = 'monascaclient.v2_0.shell' return super(MigratingCommandMeta, mcs).__new__(mcs, name, bases, cls_dict) @six.add_metaclass(MigratingCommandMeta) class MigratingCommand(command.Command): """MigratingCommand is temporary command. MigratingCommand allows to map function defined shell commands from :py:module:`monascaclient.v2_0.shell` into :py:class:`command.Command` instances. Note: This class is temporary solution during migrating to osc_lib and will be removed when all shell commands are migrated to cliff commands. """ _help = None _args = None _callback = None def __init__(self, app, app_args, cmd_name=None): super(MigratingCommand, self).__init__(app, app_args, cmd_name) self._client = None self._endpoint = None def take_action(self, parsed_args): return self._callback(self.mon_client, parsed_args) def get_parser(self, prog_name): parser = super(MigratingCommand, self).get_parser(prog_name) for (args, kwargs) in self._args: parser.add_argument(*args, **kwargs) parser.add_argument('-j', '--json', action='store_true', help='output raw json response') return parser @property def mon_client(self): if not self._client: self.log.debug('Initializing mon-client') self._client = make_client(api_version=self.mon_version, endpoint=self.mon_url, session=self.app.client_manager.session) return self._client @property def mon_version(self): return self.app_args.monasca_api_version @property def mon_url(self): if self._endpoint: return self._endpoint app_args = self.app_args cm = self.app.client_manager endpoint = app_args.monasca_api_url if not endpoint: req_data = { 'service_type': 'monitoring', 'region_name': cm.region_name, 'interface': cm.interface, } LOG.debug('Discovering monasca endpoint using %s' % req_data) endpoint = cm.get_endpoint_for_service_type(**req_data) else: LOG.debug('Using supplied endpoint=%s' % endpoint) self._endpoint = endpoint return self._endpoint python-monascaclient-2.0.0/monascaclient/client.py0000664000175000017500000001235013620561064022346 0ustar zuulzuul00000000000000# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP # Copyright 2017 Fujitsu LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import logging import warnings from keystoneauth1 import identity from keystoneauth1 import session as k_session from monascaclient.osc import migration from monascaclient import version LOG = logging.getLogger(__name__) _NO_VALUE_MARKER = object() def Client(api_version, *args, **kwargs): handle_deprecated(args, kwargs) client = migration.make_client( api_version=api_version, session=_session(kwargs), endpoint=kwargs.get('endpoint'), service_type=kwargs.get('service_type', 'monitoring') ) return client def _session(kwargs): """Returns or reuses session. Method takes care of providing instance of session object for the client. :param kwargs: all params (without api_version) client was initialized with :type kwargs: dict :returns: session object :rtype keystoneauth1.session.Session """ if 'session' in kwargs: LOG.debug('Reusing session') sess = kwargs.get('session') if not isinstance(sess, k_session.Session): msg = ('session should be an instance of %s' % k_session.Session) LOG.error(msg) raise RuntimeError(msg) else: LOG.debug('Initializing new session') auth = _get_auth_handler(kwargs) sess = _get_session(auth, kwargs) return sess def handle_deprecated(args, kwargs): """Handles all deprecations. Method goes through passed args and kwargs and handles all values that are invalid from POV of current client but: * has their counterparts * are candidates to be dropped """ kwargs.update(_handle_deprecated_args(args)) _handle_deprecated_kwargs(kwargs) def _handle_deprecated_kwargs(kwargs): depr_map = { 'tenant_name': ('project_name', lambda x: x), 'insecure': ('verify', lambda x: not x) } for key, new_key_transform in depr_map.items(): val = kwargs.get(key, _NO_VALUE_MARKER) if val != _NO_VALUE_MARKER: new_key = new_key_transform[0] new_handler = new_key_transform[1] warnings.warn( 'Usage of {old_key} has been deprecated in favour ' 'of {new_key}. monascaclient will place value of {old_key} ' 'under {new_key}'.format(old_key=key, new_key=new_key), DeprecationWarning ) kwargs[new_key] = new_handler(val) del kwargs[key] def _handle_deprecated_args(args): kwargs_update = {} if args is not None and len(args) > 0: warnings.warn( 'Usage or args is deprecated for the sake of ' 'explicit configuration of the client using ' 'named arguments (**kwargs). ' 'That argument will be removed in future releases.', DeprecationWarning ) # have all permissible args set here kwargs_update.update({ 'endpoint': args[0] }) return kwargs_update def _get_session(auth, kwargs): return k_session.Session(auth=auth, app_name='monascaclient', app_version=version.version_string, cert=kwargs.get('cert', None), timeout=kwargs.get('timeout', None), verify=kwargs.get('verify', True)) def _get_auth_handler(kwargs): if 'token' in kwargs: auth = identity.Token( auth_url=kwargs.get('auth_url', None), token=kwargs.get('token', None), project_id=kwargs.get('project_id', None), project_name=kwargs.get('project_name', None), project_domain_id=kwargs.get('project_domain_id', None), project_domain_name=kwargs.get('project_domain_name', None) ) elif {'username', 'password'} <= set(kwargs): auth = identity.Password( auth_url=kwargs.get('auth_url', None), username=kwargs.get('username', None), password=kwargs.get('password', None), project_id=kwargs.get('project_id', None), project_name=kwargs.get('project_name', None), project_domain_id=kwargs.get('project_domain_id', None), project_domain_name=kwargs.get('project_domain_name', None), user_domain_id=kwargs.get('user_domain_id', None), user_domain_name=kwargs.get('user_domain_name', None) ) else: raise Exception('monascaclient can be configured with either ' '"token" or "username:password" but neither of ' 'them was found in passed arguments.') return auth python-monascaclient-2.0.0/monascaclient/common/0000775000175000017500000000000013620561132022001 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/common/utils.py0000664000175000017500000001337713620561064023532 0ustar zuulzuul00000000000000# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development Company LP # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import print_function import numbers import prettytable import six import yaml from osc_lib import exceptions as exc from oslo_serialization import jsonutils supported_formats = { "json": lambda x: jsonutils.dumps(x, indent=2), "yaml": yaml.safe_dump } # Decorator for cli-args def arg(*args, **kwargs): def _decorator(func): # Because of the semantics of decorator composition if we just append # to the options list positional options will appear to be backwards. func.__dict__.setdefault('arguments', []).insert(0, (args, kwargs)) return func return _decorator def json_formatter(js): formatter = (jsonutils.dumps(js, indent=2, ensure_ascii=False)) return formatter if six.PY3 else formatter.encode('utf-8') def print_list(objs, fields, field_labels=None, formatters=None, sortby=None): if formatters is None: formatters = {} field_labels = field_labels or fields pt = prettytable.PrettyTable([f for f in field_labels], caching=False, print_empty=False) pt.align = 'l' for o in objs: row = [] for field in fields: if field in formatters: row.append(formatters[field](o)) elif isinstance(field, int): row.append(o[field]) else: data = getattr(o, field, None) or '' row.append(data) pt.add_row(row) field_to_sort_by = field_labels[sortby] if sortby else None pt_string = pt.get_string(sortby=field_to_sort_by) print(pt_string if six.PY3 else pt_string.encode('utf-8')) def print_dict(d, formatters=None): if formatters is None: formatters = {} pt = prettytable.PrettyTable(['Property', 'Value'], caching=False, print_empty=False) pt.align = 'l' for field in d: if field in formatters: pt.add_row([field, formatters[field](d[field])]) else: pt.add_row([field, d[field]]) pt_string = pt.get_string(sortby='Property') print(pt_string if six.PY3 else pt_string.encode('utf-8')) def format_parameters(params): '''Reformat parameters into dict of format expected by the API.''' if not params: return {} # expect multiple invocations of --parameters but fall back # to ; delimited if only one --parameters is specified if len(params) == 1: if params[0].find(';') != -1: # found params = params[0].split(';') else: params = params[0].split(',') parameters = {} for p in params: try: (n, v) = p.split('=', 1) except ValueError: msg = '%s(%s). %s.' % ('Malformed parameter', p, 'Use the key=value format') raise exc.CommandError(msg) if n not in parameters: parameters[n] = v else: if not isinstance(parameters[n], list): parameters[n] = [parameters[n]] parameters[n].append(v) return parameters def format_dimensions_query(dims): if not dims: return {} # expect multiple invocations of --parameters but fall back # to ; delimited if only one --parameters is specified if len(dims) == 1: if dims[0].find(';') != -1: # found dims = dims[0].split(';') else: dims = dims[0].split(',') dimensions = {} for p in dims: try: (n, v) = p.split('=', 1) except ValueError: n = p v = "" dimensions[n] = v return dimensions def format_dimensions(dict): return 'dimensions: {\n' + format_dict(dict) + '\n}' def format_expression_data(data): # takes an dictionary containing a dict string_list = list() for k, v in data.items(): if k == 'dimensions': dim_str = format_dimensions(v) string_list.append(dim_str) else: if isinstance(v, numbers.Number): d_str = k + ': ' + str(v) else: d_str = k + ': ' + v string_list.append(d_str) return '\n'.join(string_list) def format_dictlist(dict_list): # takes list of dictionaries to format for output string_list = list() for mdict in dict_list: kv_list = list() for k, v in sorted(mdict.items()): kv_str = k + ':' + str(v) kv_list.append(kv_str) # a string of comma separated k:v this_dict_str = ','.join(kv_list) string_list.append(this_dict_str) return '\n'.join(string_list) def format_dict(dict): # takes a dictionary to format for output dstring_list = list() for k, v in dict.items(): if isinstance(v, numbers.Number): d_str = k + ': ' + str(v) else: d_str = k + ': ' + v dstring_list.append(d_str) return '\n'.join(dstring_list) def format_list(in_list): string_list = list() for k in in_list: if isinstance(k, six.text_type): key = k.encode('utf-8') else: key = k string_list.append(key) return b'\n'.join(string_list) python-monascaclient-2.0.0/monascaclient/common/__init__.py0000664000175000017500000000000013620561064024104 0ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/common/monasca_manager.py0000664000175000017500000000373113620561064025476 0ustar zuulzuul00000000000000# (C) Copyright 2014, 2015 Hewlett Packard Enterprise Development Company LP # Copyright 2017 Fujitsu LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from six.moves.urllib import parse class MonascaManager(object): base_url = None def __init__(self, client): self.client = client def _parse_body(self, body): if type(body) is dict: self.next = None for link in body['links']: if link['rel'] == 'next': self.next = link['href'] return body['elements'] else: return body def _list(self, path, dim_key=None, **kwargs): """Get a list of metrics.""" url_str = self.base_url + path if dim_key and dim_key in kwargs: dim_str = self.get_dimensions_url_string(kwargs[dim_key]) kwargs[dim_key] = dim_str if kwargs: url_str += '?%s' % parse.urlencode(kwargs, True) body = self.client.list( path=url_str ) return self._parse_body(body) @staticmethod def get_dimensions_url_string(dimensions): dim_list = list() for k, v in dimensions.items(): # In case user specifies a dimension multiple times if isinstance(v, (list, tuple)): v = v[-1] if v: dim_str = k + ':' + v else: dim_str = k dim_list.append(dim_str) return ','.join(dim_list) python-monascaclient-2.0.0/monascaclient/tests/0000775000175000017500000000000013620561132021653 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/tests/__init__.py0000664000175000017500000000000013620561064023756 0ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/tests/test_client.py0000664000175000017500000001472013620561064024552 0ustar zuulzuul00000000000000# (C) Copyright 2014-2017 Hewlett Packard Enterprise Development LP # Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import warnings import mock from oslotest import base from monascaclient import client class TestMonascaClient(base.BaseTestCase): @mock.patch('monascaclient.client.migration') @mock.patch('monascaclient.client._get_auth_handler') @mock.patch('monascaclient.client._get_session') def test_should_warn_when_passing_args(self, _, __, ___): api_version = mock.Mock() endpoint = mock.Mock() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') client.Client(api_version, endpoint) self.assertEqual(1, len(w)) self.assertEqual(DeprecationWarning, w[0].category) self.assertRegex( str(w[0].message), 'explicit configuration of the client using' ) @mock.patch('monascaclient.client.migration') @mock.patch('monascaclient.client._get_auth_handler') @mock.patch('monascaclient.client._get_session') def test_should_not_warn_when_passing_no_args(self, _, __, ___): api_version = mock.Mock() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') client.Client(api_version) self.assertEqual(0, len(w)) @mock.patch('monascaclient.client.migration') @mock.patch('monascaclient.client._get_auth_handler') @mock.patch('monascaclient.client._get_session') def test_should_override_endpoint_if_passed_as_arg(self, get_session, get_auth, _): api_version = mock.Mock() endpoint = mock.Mock() endpoint_fake = mock.Mock() auth_val = mock.Mock() get_auth.return_value = auth_val with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') client.Client(api_version, endpoint, endpoint=endpoint_fake) self.assertEqual(1, len(w)) get_auth.assert_called_once_with({ 'endpoint': endpoint }) get_session.assert_called_once_with(auth_val, { 'endpoint': endpoint }) @mock.patch('monascaclient.client.migration') @mock.patch('monascaclient.client._get_auth_handler') @mock.patch('monascaclient.client._get_session') def test_should_override_tenant_name_with_project_name(self, _, get_auth, __): api_version = mock.Mock() auth_val = mock.Mock() tenant_name = mock.Mock() project_name = tenant_name get_auth.return_value = auth_val with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') client.Client(api_version, tenant_name=tenant_name) self.assertEqual(1, len(w)) self.assertEqual(DeprecationWarning, w[0].category) self.assertRegex( str(w[0].message), 'Usage of tenant_name has been deprecated in favour ' ) get_auth.assert_called_once_with({ 'project_name': project_name }) @mock.patch('monascaclient.client.migration') @mock.patch('monascaclient.client._get_auth_handler') @mock.patch('monascaclient.client._get_session') def test_should_override_insecure_with_negated_verify(self, _, get_auth, __): api_version = mock.Mock() auth_val = mock.Mock() get_auth.return_value = auth_val for insecure in [True, False]: warnings.resetwarnings() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') client.Client(api_version, insecure=insecure) self.assertEqual(1, len(w)) self.assertEqual(DeprecationWarning, w[0].category) self.assertRegex( str(w[0].message), 'Usage of insecure has been deprecated in favour of' ) get_auth.assert_called_once_with({ 'verify': not insecure }) get_auth.reset_mock() @mock.patch('monascaclient.client.migration') @mock.patch('monascaclient.client._get_auth_handler') @mock.patch('monascaclient.client._get_session') def test_should_reuse_the_session_if_initialized_with_one(self, get_session, get_auth, _): from keystoneauth1 import session as k_session api_version = mock.Mock() session = mock.Mock(spec=k_session.Session) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') client.Client(api_version, session=session) self.assertEqual(0, len(w)) get_auth.assert_not_called() get_session.assert_not_called() @mock.patch('monascaclient.client.migration') @mock.patch('monascaclient.client._get_auth_handler') @mock.patch('monascaclient.client._get_session') def test_should_error_if_session_is_not_in_correct_type(self, _, __, ___): api_version = mock.Mock() for cls in [str, int, float]: session = mock.Mock(spec=cls) self.assertRaises(RuntimeError, client.Client, api_version, session=session) python-monascaclient-2.0.0/monascaclient/tests/v2_0/0000775000175000017500000000000013620561132022421 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/tests/v2_0/__init__.py0000664000175000017500000000000013620561064024524 0ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/tests/v2_0/shell/0000775000175000017500000000000013620561132023530 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/tests/v2_0/shell/test_metrics.py0000664000175000017500000000556313620561064026624 0ustar zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from oslotest import base from monascaclient.osc import migration as migr from monascaclient.v2_0 import metrics from monascaclient.v2_0 import shell class FakeV2Client(object): def __init__(self): super(FakeV2Client, self).__init__() self.metrics = mock.Mock(spec=metrics.MetricsManager) class TestMetricsShellV2(base.BaseTestCase): def test_bad_metrics(self): raw_args_list = [ ['metric1'], ['123'], [''] ] name, cmd_clazz = migr.create_command_class('do_metric_create', shell) for raw_args in raw_args_list: cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) self.assertRaises(SystemExit, parser.parse_args, raw_args) @mock.patch('monascaclient.osc.migration.make_client') def test_metric_create(self, mc): mc.return_value = c = FakeV2Client() raw_args = 'metric1 123 --time 1395691090'.split(' ') name, cmd_clazz = migr.create_command_class('do_metric_create', shell) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) data = {'timestamp': 1395691090, 'name': 'metric1', 'value': 123.0} c.metrics.create.assert_called_once_with(**data) @mock.patch('monascaclient.osc.migration.make_client') def test_metric_create_with_project_id(self, mc): mc.return_value = c = FakeV2Client() project_id = 'd48e63e76a5c4e05ba26a1185f31d4aa' raw_args = ('metric1 123 --time 1395691090 --project-id %s' % project_id).split(' ') name, cmd_clazz = migr.create_command_class('do_metric_create', shell) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) data = {'timestamp': 1395691090, 'name': 'metric1', 'tenant_id': project_id, 'value': 123.0} c.metrics.create.assert_called_once_with(**data) python-monascaclient-2.0.0/monascaclient/tests/v2_0/shell/__init__.py0000664000175000017500000000000013620561064025633 0ustar zuulzuul00000000000000python-monascaclient-2.0.0/monascaclient/tests/v2_0/shell/test_notifications.py0000664000175000017500000001321413620561064030017 0ustar zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from oslotest import base from monascaclient.osc import migration as migr from monascaclient.v2_0 import notifications from monascaclient.v2_0 import shell class FakeV2Client(object): def __init__(self): super(FakeV2Client, self).__init__() self.notifications = mock.Mock(spec=notifications.NotificationsManager) class TestNotificationsShellV2(base.BaseTestCase): @mock.patch('monascaclient.osc.migration.make_client') def test_notification_create_email(self, mc): mc.return_value = c = FakeV2Client() raw_args = ['email1', 'EMAIL', 'john.doe@hp.com'] name, cmd_clazz = migr.create_command_class('do_notification_create', shell) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) data = {'name': 'email1', 'type': 'EMAIL', 'address': 'john.doe@hp.com'} c.notifications.create.assert_called_once_with(**data) @mock.patch('monascaclient.osc.migration.make_client') def test_notification_create_webhook(self, mc): mc.return_value = c = FakeV2Client() raw_args = ['mypost', 'WEBHOOK', 'http://localhost:8080'] name, cmd_clazz = migr.create_command_class('do_notification_create', shell) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) data = {'name': 'mypost', 'type': 'WEBHOOK', 'address': 'http://localhost:8080'} c.notifications.create.assert_called_once_with(**data) @mock.patch('monascaclient.osc.migration.make_client') def test_good_notifications_patch(self, mc): args = '--type EMAIL --address john.doe@hpe.com --period 0' data = {'type': 'EMAIL', 'address': 'john.doe@hpe.com', 'period': 0} self._patch_test(mc, args, data) @mock.patch('monascaclient.osc.migration.make_client') def test_good_notifications_patch_just_name(self, mc): name = 'fred' args = '--name ' + name data = {'name': name} self._patch_test(mc, args, data) @mock.patch('monascaclient.osc.migration.make_client') def test_good_notifications_patch_just_address(self, mc): address = 'fred@fl.com' args = '--address ' + address data = {'address': address} self._patch_test(mc, args, data) @mock.patch('monascaclient.osc.migration.make_client') def test_good_notifications_patch_just_period(self, mc): period = 0 args = '--period ' + str(period) data = {'period': period} self._patch_test(mc, args, data) @mock.patch('monascaclient.osc.migration.make_client') def test_bad_notifications_patch(self, mc): mc.return_value = c = FakeV2Client() id_str = '0495340b-58fd-4e1c-932b-5e6f9cc96490' raw_args = ('{0} --type EMAIL --address john.doe@hpe.com ' '--period 60').format(id_str).split(' ') name, cmd_clazz = migr.create_command_class('do_notification_patch', shell) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) c.notifications.patch.assert_not_called() @mock.patch('monascaclient.osc.migration.make_client') def test_good_notifications_update(self, mc): mc.return_value = c = FakeV2Client() id_str = '0495340b-58fd-4e1c-932b-5e6f9cc96491' raw_args = ('{0} notification_updated_name ' 'EMAIL john.doe@hpe.com 0').format(id_str).split(' ') name, cmd_clazz = migr.create_command_class('do_notification_update', shell) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) data = { 'name': 'notification_updated_name', 'type': 'EMAIL', 'address': 'john.doe@hpe.com', 'period': 0, 'notification_id': id_str } c.notifications.update.assert_called_once_with(**data) @staticmethod def _patch_test(mc, args, data): mc.return_value = c = FakeV2Client() id_str = '0495340b-58fd-4e1c-932b-5e6f9cc96490' raw_args = '{0} {1}'.format(id_str, args).split(' ') name, cmd_clazz = migr.create_command_class('do_notification_patch', shell) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) # add notification_id to data data['notification_id'] = id_str c.notifications.patch.assert_called_once_with(**data) python-monascaclient-2.0.0/monascaclient/tests/v2_0/shell/test_alarm_definitions.py0000664000175000017500000001315713620561064030643 0ustar zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from oslotest import base from monascaclient.osc import migration as migr from monascaclient.v2_0 import alarm_definitions as ad from monascaclient.v2_0 import shell class FakeV2Client(object): def __init__(self): super(FakeV2Client, self).__init__() self.alarm_definitions = mock.Mock( spec=ad.AlarmDefinitionsManager) class TestAlarmDefinitionShellV2(base.BaseTestCase): @mock.patch('monascaclient.osc.migration.make_client') def test_should_update(self, mc): mc.return_value = c = FakeV2Client() ad_id = '0495340b-58fd-4e1c-932b-5e6f9cc96490' ad_name = 'alarm_name' ad_desc = 'test_alarm_definition' ad_expr = 'avg(Test_Metric_1)>=10' ad_action_id = '16012650-0b62-4692-9103-2d04fe81cc93' ad_action_enabled = 'True' ad_match_by = 'hostname' ad_severity = 'CRITICAL' raw_args = [ ad_id, ad_name, ad_desc, ad_expr, ad_action_id, ad_action_id, ad_action_id, ad_action_enabled, ad_match_by, ad_severity ] name, cmd_clazz = migr.create_command_class( 'do_alarm_definition_update', shell ) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) c.alarm_definitions.update.assert_called_once_with( actions_enabled=True, alarm_actions=[ad_action_id], alarm_id=ad_id, description=ad_desc, expression=ad_expr, match_by=[ad_match_by], name=ad_name, ok_actions=[ad_action_id], severity=ad_severity, undetermined_actions=[ad_action_id] ) @mock.patch('monascaclient.osc.migration.make_client') def test_alarm_definitions_list(self, mc): mc.return_value = c = FakeV2Client() c.alarm_definitions.list.return_value = [{ "name": "ntp_sync_check", "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "expression": "(max(ntp.offset{}, deterministic)>=1)", "match_by": ['hostname'], "description": "NTP time sync check", "actions_enabled": True, "deterministic": True, "alarm_actions": ['aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'], "ok_actions": [], "undetermined_actions": [], "severity": "HIGH", }] name, cmd_class = migr.create_command_class( 'do_alarm_definition_list', shell ) cmd = cmd_class(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) raw_args = [] parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) c.alarm_definitions.list.assert_called_once() @mock.patch('monascaclient.osc.migration.make_client') def test_should_patch_name(self, mc): ad_id = '0495340b-58fd-4e1c-932b-5e6f9cc96490' ad_name = 'patch_name' raw_args = '{0} --name {1}'.format(ad_id, ad_name).split(' ') self._patch_test(mc, raw_args, alarm_id=ad_id, name=ad_name) @mock.patch('monascaclient.osc.migration.make_client') def test_should_patch_actions(self, mc): ad_id = '0495340b-58fd-4e1c-932b-5e6f9cc96490' ad_action_id = '16012650-0b62-4692-9103-2d04fe81cc93' actions = ['alarm-actions', 'ok-actions', 'undetermined-actions'] for action in actions: raw_args = ('{0} --{1} {2}'.format(ad_id, action, ad_action_id) .split(' ')) self._patch_test(mc, raw_args, **{ 'alarm_id': ad_id, action.replace('-', '_'): [ad_action_id] }) @mock.patch('monascaclient.osc.migration.make_client') def test_should_patch_severity(self, mc): ad_id = '0495340b-58fd-4e1c-932b-5e6f9cc96490' severity_types = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] for st in severity_types: raw_args = ('{0} --severity {1}'.format(ad_id, st) .split(' ')) self._patch_test(mc, raw_args, alarm_id=ad_id, severity=st) @mock.patch('monascaclient.osc.migration.make_client') def test_should_not_patch_unknown_severity(self, mc): ad_id = '0495340b-58fd-4e1c-932b-5e6f9cc96490' st = 'foo' raw_args = ('{0} --severity {1}'.format(ad_id, st) .split(' ')) self._patch_test(mc, raw_args, called=False) @staticmethod def _patch_test(mc, args, called=True, **kwargs): mc.return_value = c = FakeV2Client() name, cmd_clazz = migr.create_command_class( 'do_alarm_definition_patch', shell ) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(args) cmd.run(parsed_args) if called: c.alarm_definitions.patch.assert_called_once_with(**kwargs) else: c.alarm_definitions.patch.assert_not_called() python-monascaclient-2.0.0/monascaclient/tests/v2_0/shell/test_notification_types.py0000664000175000017500000000326313620561064031063 0ustar zuulzuul00000000000000# Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from oslotest import base from monascaclient.osc import migration as migr from monascaclient.v2_0 import notificationtypes from monascaclient.v2_0 import shell class FakeV2Client(object): def __init__(self): super(FakeV2Client, self).__init__() self.notificationtypes = mock.Mock( spec=notificationtypes.NotificationTypesManager) class TestNotificationsTypesShellV2(base.BaseTestCase): @mock.patch('monascaclient.osc.migration.make_client') def test_notification_types_list(self, mc): mc.return_value = c = FakeV2Client() c.notificationtypes.list.return_value = [ {"type": "WEBHOOK"}, {"type": "EMAIL"}, {"type": "PAGERDUTY"} ] raw_args = [] name, cmd_clazz = migr.create_command_class('do_notification_type_list', shell) cmd = cmd_clazz(mock.Mock(), mock.Mock()) parser = cmd.get_parser(name) parsed_args = parser.parse_args(raw_args) cmd.run(parsed_args) c.notificationtypes.list.assert_called_once() python-monascaclient-2.0.0/monascaclient/tests/test_shell.py0000664000175000017500000000367513620561064024412 0ustar zuulzuul00000000000000# (C) Copyright 2014-2017 Hewlett Packard Enterprise Development LP # Copyright 2017 FUJITSU LIMITED # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import mock from oslotest import base from monascaclient import shell class TestMonascaShell(base.BaseTestCase): @mock.patch('monascaclient.shell.auth') def test_should_use_auth_plugin_option_parser(self, auth): auth.build_auth_plugins_option_parser = apop = mock.Mock() shell.MonascaShell().run([]) apop.assert_called_once() def test_should_specify_monasca_args(self): expected_args = [ '--monasca-api-url', '--monasca-api-version', '--monasca_api_url', '--monasca_api_version', ] parser = mock.Mock() parser.add_argument = aa = mock.Mock() shell.MonascaShell._append_monasca_args(parser) aa.assert_called() for mc in aa.mock_calls: name = mc[1][0] self.assertIn(name, expected_args) @mock.patch('monascaclient.shell.importutils') def test_should_load_commands_based_on_api_version(self, iu): iu.import_versioned_module = ivm = mock.Mock() instance = shell.MonascaShell() instance.options = mock.Mock() instance.options.monasca_api_version = version = mock.Mock() instance._find_actions = mock.Mock() instance._load_commands() ivm.assert_called_once_with('monascaclient', version, 'shell') python-monascaclient-2.0.0/setup.cfg0000664000175000017500000000205513620561132017514 0ustar zuulzuul00000000000000[metadata] name = python-monascaclient summary = Monasca API Client Library description-file = README.rst author = OpenStack author-email = openstack-discuss@lists.openstack.org home-page = https://docs.openstack.org/python-monascaclient/latest/ classifier = Environment :: Console 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.6 Programming Language :: Python :: 3.7 [files] packages = monascaclient [entry_points] console_scripts = monasca = monascaclient.shell:main [build_sphinx] source-dir = doc/source build-dir = doc/build all_files = 1 warning-is-error = 1 [build_releasenotes] all_files = 1 build-dir = releasenotes/build source-dir = releasenotes/source [wheel] universal = 1 [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 python-monascaclient-2.0.0/AUTHORS0000664000175000017500000000662413620561132016751 0ustar zuulzuul0000000000000098k <18552437190@163.com> Adrian Czarnecki Amir Mofakhar Andreas Jaeger Angelo Mendonca Anh Tran Arseni Lipinski Artur Basiak Cao Xuan Hoang Charles Short Christian Berendt Cindy O Neill Corey Bryant Craig Bryant Craig Bryant Dao Cong Tien Deepak Denis Poisson Dexter Fryar Dirk Mueller Dobroslaw Zybort Doug Hellmann Doug Szumski Eyal Flavio Percoco Ghanshyam Mann Haiwei Xu Ian Wienand Igor Ataide Jamie Lennox Jeremy Liu Jeremy Stanley Joachim Barheine Joe Keen Joe Keen KATO Tomoyuki Kaiyan Sheng Longgeek Luong Anh Tuan Mark Reynolds Michael James Hoppal Michał Piotrowski Nguyen Hai Truong Nguyen Tuong Thanh Ondřej Nový OpenStack Release Bot Paulo Ewerton Rob Raymond Roland Hochmuth Ronald Bradford Ryan Bak Ryan Brandt SamKirsch10 Sean McGinnis Shinya Kawabata Stefan Caraiman Steve Martinelli Sumit Jamgade Swapnil Kulkarni (coolsvap) Thomas Goirand Tim Kuhlman Tomasz Trębski Tomasz Trębski Tony Breeds Victor Ion Munteanu Vieri <15050873171@163.com> Vu Cong Tuan Witold Bedyk ZhiQiang Fan ZhijunWei bklei cao.yuan cindy oneill gecong1973 gengchc2 haali1 henriquetruta howardlee jacky06 kangyufei kornicameister lingyongxu melissaml oneilcin pengyuesheng qingszhao rajat29 ricolin tushargite96 venkatamahesh xhzhf python-monascaclient-2.0.0/.zuul.yaml0000664000175000017500000000466613620561064017652 0ustar zuulzuul00000000000000- project: templates: - openstack-cover-jobs - openstack-lower-constraints-jobs - openstack-python3-ussuri-jobs - publish-openstack-docs-pti - check-requirements - release-notes-jobs-python3 check: jobs: - docker-build-monasca-service post: jobs: - publish-monasca-client-docker-image periodic: jobs: - publish-monasca-client-docker-image release: jobs: - publish-monasca-client-docker-image - job: name: publish-monasca-client-docker-image parent: build-monasca-docker-image post-run: playbooks/docker-publish.yml required-projects: - openstack/monasca-common vars: publisher: true secrets: - doker_hub_login_client - secret: name: doker_hub_login_client data: user: !encrypted/pkcs1-oaep - QdHgQ9lGfeOypCKTX9funuwbHCVRhUGfyswosl9whSskzy1EhztLSPpP5PPHg/ZM0Ag8o VAHT6La7oroTDeWYcDJmN8Zc5mslQlcskwoq9TN/VWEhY36+OF3k938Zr78URwOT5Hqm4 ch+itjmydrQOrqcCwJ3ROrrJ2XpIMainz567U1HYuUari9B3zOUTW3xJfqbJ8UJIn/Irj qEHn4Rn/RT3fOBcLwZfWJOcuwes8dsQykXNufLxXy2UGpdcHlE6lAAnRBgN/EPBxtqpAB j+TO3s3yJLCIXDPIV+nST8z6EbvYc+woM4O1PN0AQ/tfyulFGvDTJNIdKenUBD99rBBJS RCBZ0hhVgqDE4y4fcHh6STde0UHUQgwdX9lbdC2MGZah0bjUWG67QMwdtiiBwktbz3nza a7yjd6/6di3zstDDGRLvZ5+vJ0cE/4eeWUmXcq2c0dtggaFDXYhOIoM1xfHKNvMN6QjM1 kETvG2aw/PyNYIJkNic19Qk7UbOrgKduZUA6K17xQ5lqIJn/JfRVQyvoi0pLMCsa1NSe+ wlpg9acJ46l0licRJ8o+QA02cFcrl9gBY5x0WwO3N/+LOxc40L+hHJi2vzduQO0ikCYa4 Lerew8vrpf2EZ3JV5JEuIQ0/q5V5ZXhCeJQ6JBdLusYF3LzHRkX+7DCt3UMgaU= password: !encrypted/pkcs1-oaep - uZOFnKJzCV26Ea3KtPmK0WaTCV6YqLgS0Y5BolGq4MahKftVXxDbWRtVMQWnwx8mMugmh A8mtchoyvrIvH5gjU7SmvVYAyH5KJGdKnb/9jbYTJ/Zq9f2CFd10hlomIUIlbDixAIMmV rbcexomEY5b15lF9F4I3ovwPEsqu0YcGMW7ABPdZaZx5JGDgYXXGWpy3CFvVV/MIzLbV+ wgByN7RsBNEFY44/xLTBkjN4RHOWTo1hFLeblI2pRJ40fzPw6fuUpeG1oPV/l4h9cjTgq KMr4RuxxvCI3D0nWmq8SrIJ446erEldolJtpKRLqn1GTcGgyQbUgiXA0Nd44sFAcmwTBz vK4rgD9Akhz/bsV6P8P5x25YoU6oS8Vws4mKu+iw3TWn0e+467oFvw+PD4e3+JbSSofyh 6gVRsXK+Ls7YMNdnoAe8XXh76IBfC639olAgFU7ewtcsOLAiVrqIIynWmprBJZ2apEBxs jRNQpBgkTtUaaBcb3uGY3Fcip7PDcjcApYoaLHAUi2P2+o5gatsmySLb64g4O3rddn7Wf 8uSWv123X4zvXIk3V7FmCeSXgamVuZKpRHbFIeq9S+13ze1HBce6s36egoiGTfCMq5wLr XwRwytGr8JoI4c8YIQXffYxJhhbgA9Qn+FalsrJIQNR03GnA2oUKKNsZExwcPs= python-monascaclient-2.0.0/doc/0000775000175000017500000000000013620561132016436 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/doc/source/0000775000175000017500000000000013620561132017736 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/doc/source/reference/0000775000175000017500000000000013620561132021674 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/doc/source/reference/index.rst0000664000175000017500000000535013620561064023544 0ustar zuulzuul00000000000000================ Using Python API ================ Python bindings to the OpenStack Monasca API ============================================ This is a client for the OpenStack Monasca API. It includes a Python API (the :mod:`monascaclient` module) and a command-line script (installed as :program:`monasca`). Python API ========== To use python-monascaclient in a project, you need to create a client instance first. There are couple ways of doing this properly. With session ------------ A pseudo-code would be similar to this:: from keystoneauth1 import identity from keystoneauth1 import session from monascaclient import client auth = identity.Password( auth_url='http://my.keystone.com/identity', username='mini-mon', password='password', project_name='mini-mon', user_domain_id='default', project_domain_id='default' ) sess = session.Session(auth=auth) endpoint = 'http://monasca:8070/v2.0' api_version = '2_0' c = client.Client( api_version=api_version, endpoint=endpoint, session=sess ) c.alarms.list() For more information on keystoneauth API, see `Using Sessions`_. We also suggest taking closer look at `Keystone Auth Plugins`_. Each of the plugin can be used to properly instantiate new session and pass it into the client. .. note:: This is recommended way to setup a client. Other cases, described below, create sessions internally. Without session --------------- If you do not want to use a session or simply prefer client to instantiate one on its own, there are two supported ways With token ~~~~~~~~~~ A pseudo-code would be similar to this:: from monascaclient import client c = client.Client( api_version='2_0', endpoint='http://monasca:8070/v2.0', token='3bcc3d3a03f44e3d8377f9247b0ad155', project_name='mini-mon', auth_url='http://my.keystone.com/identity' ) c.alarms.list() With username & password ~~~~~~~~~~~~~~~~~~~~~~~~ A pseudo-code would be similar to this:: from monascaclient import client c = client.Client( api_version='2_0', endpoint='http://monasca:8070/v2.0', username='mini-mon', password='password', project_name='mini-mon', auth_url='http://my.keystone.com/identity' ) c.alarms.list() Examples ======== * `Monasca Agent Example`_ - with session * `Monasca UI Example`_ - with token .. _Monasca Agent Example: https://github.com/openstack/monasca-agent/blob/master/monasca_agent/forwarder/api/monasca_api.py .. _Monasca UI Example: https://github.com/openstack/monasca-ui/blob/master/monitoring/api/client.py .. _Using Sessions: https://docs.openstack.org/keystoneauth/latest/using-sessions.html .. _Keystone Auth Plugins: https://docs.openstack.org/keystoneauth/latest/authentication-plugins.html python-monascaclient-2.0.0/doc/source/index.rst0000664000175000017500000000236313620561064021607 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. ================================== python-monascaclient documentation ================================== This is a client for OpenStack Monitoring API. It provides :doc:`Python API bindings ` (the monascaclient module) and :doc:`command-line interface (CLI) `. User Documentation ------------------ .. toctree:: :maxdepth: 2 installation cli/index reference/index Usage ----- In the :doc:`Usage `, you will find information on possible ways to use python-monascaclient. .. toctree:: :maxdepth: 2 usage/index History ------- Release notes is available at http://docs.openstack.org/releasenotes/python-monascaclient/. python-monascaclient-2.0.0/doc/source/installation.rst0000664000175000017500000000074113620561064023177 0ustar zuulzuul00000000000000============ Installation ============ At the command line, from PyPI:: $ pip install python-monascaclient Or, if you have virtualenvwrapper installed:: $ mkvirtualenv python-monascaclient $ pip install python-monascaclient Or, you can build it manually:: $ mkvirtualenv python-monascaclient $ git clone https://opendev.org/openstack/python-monascaclient $ cd python-monascaclient $ pip install -r ./requirements.txt $ python setup.py install python-monascaclient-2.0.0/doc/source/cli/0000775000175000017500000000000013620561132020505 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/doc/source/cli/index.rst0000664000175000017500000005225013620561064022356 0ustar zuulzuul00000000000000========= Using CLI ========= monasca CLI ----------- .. toctree:: :maxdepth: 2 monasca CLI guide monasca CLI formatting monasca CLI debugging Usage ----- You'll find complete documentation on the shell by running ``monasca help``:: usage: monasca [--version] [-v | -q] [--log-file LOG_FILE] [-h] [--debug] [--os-cloud ] [--os-region-name ] [--os-cacert ] [--os-cert ] [--os-key ] [--verify | --insecure] [--os-default-domain ] [--os-interface ] [--timing] [--os-beta-command] [--os-auth-type ] [--os-code ] [--os-protocol ] [--os-project-name ] [--os-trust-id ] [--os-domain-name ] [--os-user-domain-id ] [--os-access-token-type ] [--os-default-domain-name ] [--os-access-token-endpoint ] [--os-access-token ] [--os-domain-id ] [--os-user-domain-name ] [--os-openid-scope ] [--os-user-id ] [--os-identity-provider ] [--os-username ] [--os-auth-url ] [--os-client-secret ] [--os-default-domain-id ] [--os-discovery-endpoint ] [--os-client-id ] [--os-project-domain-name ] [--os-project-domain-id ] [--os-password ] [--os-redirect-uri ] [--os-endpoint ] [--os-token ] [--os-passcode ] [--os-project-id ] [--monasca-api-url MONASCA_API_URL] [--monasca-api-version MONASCA_API_VERSION] Command-line interface to the OpenStack APIs optional arguments: --version show program's version number and exit -v, --verbose Increase verbosity of output. Can be repeated. -q, --quiet Suppress output except warnings and errors. --log-file LOG_FILE Specify a file to log output. Disabled by default. -h, --help Show help message and exit. --debug Show tracebacks on errors. --os-cloud Cloud name in clouds.yaml (Env: OS_CLOUD) --os-region-name Authentication region name (Env: OS_REGION_NAME) --os-cacert CA certificate bundle file (Env: OS_CACERT) --os-cert Client certificate bundle file (Env: OS_CERT) --os-key Client certificate key file (Env: OS_KEY) --verify Verify server certificate (default) --insecure Disable server certificate verification --os-default-domain Default domain ID, default=default. (Env: OS_DEFAULT_DOMAIN) --os-interface Select an interface type. Valid interface types: [admin, public, internal]. (Env: OS_INTERFACE) --timing Print API call timing info --os-beta-command Enable beta commands which are subject to change --os-auth-type Select an authentication type. Available types: v2token, admin_token, v3oidcauthcode, v2password, v3password, v3oidcaccesstoken, v3oidcpassword, token, v3oidcclientcredentials, v3tokenlessauth, v3token, v3totp, password. Default: selected based on --os- username/--os-token (Env: OS_AUTH_TYPE) --os-code With v3oidcauthcode: OAuth 2.0 Authorization Code (Env: OS_CODE) --os-protocol With v3oidcauthcode: Protocol for federated plugin With v3oidcaccesstoken: Protocol for federated plugin With v3oidcpassword: Protocol for federated plugin With v3oidcclientcredentials: Protocol for federated plugin (Env: OS_PROTOCOL) --os-project-name With v3oidcauthcode: Project name to scope to With v3password: Project name to scope to With v3oidcaccesstoken: Project name to scope to With v3oidcpassword: Project name to scope to With token: Project name to scope to With v3oidcclientcredentials: Project name to scope to With v3tokenlessauth: Project name to scope to With v3token: Project name to scope to With v3totp: Project name to scope to With password: Project name to scope to (Env: OS_PROJECT_NAME) --os-trust-id With v2token: Trust ID With v3oidcauthcode: Trust ID With v2password: Trust ID With v3password: Trust ID With v3oidcaccesstoken: Trust ID With v3oidcpassword: Trust ID With token: Trust ID With v3oidcclientcredentials: Trust ID With v3token: Trust ID With v3totp: Trust ID With password: Trust ID (Env: OS_TRUST_ID) --os-domain-name With v3oidcauthcode: Domain name to scope to With v3password: Domain name to scope to With v3oidcaccesstoken: Domain name to scope to With v3oidcpassword: Domain name to scope to With token: Domain name to scope to With v3oidcclientcredentials: Domain name to scope to With v3tokenlessauth: Domain name to scope to With v3token: Domain name to scope to With v3totp: Domain name to scope to With password: Domain name to scope to (Env: OS_DOMAIN_NAME) --os-user-domain-id With v3password: User's domain id With v3totp: User's domain id With password: User's domain id (Env: OS_USER_DOMAIN_ID) --os-access-token-type With v3oidcauthcode: OAuth 2.0 Authorization Server Introspection token type, it is used to decide which type of token will be used when processing token introspection. Valid values are: "access_token" or "id_token" With v3oidcpassword: OAuth 2.0 Authorization Server Introspection token type, it is used to decide which type of token will be used when processing token introspection. Valid values are: "access_token" or "id_token" With v3oidcclientcredentials: OAuth 2.0 Authorization Server Introspection token type, it is used to decide which type of token will be used when processing token introspection. Valid values are: "access_token" or "id_token" (Env: OS_ACCESS_TOKEN_TYPE) --os-default-domain-name With token: Optional domain name to use with v3 API and v2 parameters. It will be used for both the user and project domain in v3 and ignored in v2 authentication. With password: Optional domain name to use with v3 API and v2 parameters. It will be used for both the user and project domain in v3 and ignored in v2 authentication. (Env: OS_DEFAULT_DOMAIN_NAME) --os-access-token-endpoint With v3oidcauthcode: OpenID Connect Provider Token Endpoint. Note that if a discovery document is being passed this option will override the endpoint provided by the server in the discovery document. With v3oidcpassword: OpenID Connect Provider Token Endpoint. Note that if a discovery document is being passed this option will override the endpoint provided by the server in the discovery document. With v3oidcclientcredentials: OpenID Connect Provider Token Endpoint. Note that if a discovery document is being passed this option will override the endpoint provided by the server in the discovery document. (Env: OS_ACCESS_TOKEN_ENDPOINT) --os-access-token With v3oidcaccesstoken: OAuth 2.0 Access Token (Env: OS_ACCESS_TOKEN) --os-domain-id With v3oidcauthcode: Domain ID to scope to With v3password: Domain ID to scope to With v3oidcaccesstoken: Domain ID to scope to With v3oidcpassword: Domain ID to scope to With token: Domain ID to scope to With v3oidcclientcredentials: Domain ID to scope to With v3tokenlessauth: Domain ID to scope to With v3token: Domain ID to scope to With v3totp: Domain ID to scope to With password: Domain ID to scope to (Env: OS_DOMAIN_ID) --os-user-domain-name With v3password: User's domain name With v3totp: User's domain name With password: User's domain name (Env: OS_USER_DOMAIN_NAME) --os-openid-scope With v3oidcauthcode: OpenID Connect scope that is requested from authorization server. Note that the OpenID Connect specification states that "openid" must be always specified. With v3oidcpassword: OpenID Connect scope that is requested from authorization server. Note that the OpenID Connect specification states that "openid" must be always specified. With v3oidcclientcredentials: OpenID Connect scope that is requested from authorization server. Note that the OpenID Connect specification states that "openid" must be always specified. (Env: OS_OPENID_SCOPE) --os-user-id With v2password: User ID to login with With v3password: User ID With v3totp: User ID With password: User id (Env: OS_USER_ID) --os-identity-provider With v3oidcauthcode: Identity Provider's name With v3oidcaccesstoken: Identity Provider's name With v3oidcpassword: Identity Provider's name With v3oidcclientcredentials: Identity Provider's name (Env: OS_IDENTITY_PROVIDER) --os-username With v2password: Username to login with With v3password: Username With v3oidcpassword: Username With v3totp: Username With password: Username (Env: OS_USERNAME) --os-auth-url With v2token: Authentication URL With v3oidcauthcode: Authentication URL With v2password: Authentication URL With v3password: Authentication URL With v3oidcaccesstoken: Authentication URL With v3oidcpassword: Authentication URL With token: Authentication URL With v3oidcclientcredentials: Authentication URL With v3tokenlessauth: Authentication URL With v3token: Authentication URL With v3totp: Authentication URL With password: Authentication URL (Env: OS_AUTH_URL) --os-client-secret With v3oidcauthcode: OAuth 2.0 Client Secret With v3oidcpassword: OAuth 2.0 Client Secret With v3oidcclientcredentials: OAuth 2.0 Client Secret (Env: OS_CLIENT_SECRET) --os-default-domain-id With token: Optional domain ID to use with v3 and v2 parameters. It will be used for both the user and project domain in v3 and ignored in v2 authentication. With password: Optional domain ID to use with v3 and v2 parameters. It will be used for both the user and project domain in v3 and ignored in v2 authentication. (Env: OS_DEFAULT_DOMAIN_ID) --os-discovery-endpoint With v3oidcauthcode: OpenID Connect Discovery Document URL. The discovery document will be used to obtain the values of the access token endpoint and the authentication endpoint. This URL should look like https://idp.example.org/.well-known/openid- configuration With v3oidcpassword: OpenID Connect Discovery Document URL. The discovery document will be used to obtain the values of the access token endpoint and the authentication endpoint. This URL should look like https://idp.example.org/.well-known/openid- configuration With v3oidcclientcredentials: OpenID Connect Discovery Document URL. The discovery document will be used to obtain the values of the access token endpoint and the authentication endpoint. This URL should look like https://idp.example.org/.well-known /openid-configuration (Env: OS_DISCOVERY_ENDPOINT) --os-client-id With v3oidcauthcode: OAuth 2.0 Client ID With v3oidcpassword: OAuth 2.0 Client ID With v3oidcclientcredentials: OAuth 2.0 Client ID (Env: OS_CLIENT_ID) --os-project-domain-name With v3oidcauthcode: Domain name containing project With v3password: Domain name containing project With v3oidcaccesstoken: Domain name containing project With v3oidcpassword: Domain name containing project With token: Domain name containing project With v3oidcclientcredentials: Domain name containing project With v3tokenlessauth: Domain name containing project With v3token: Domain name containing project With v3totp: Domain name containing project With password: Domain name containing project (Env: OS_PROJECT_DOMAIN_NAME) --os-project-domain-id With v3oidcauthcode: Domain ID containing project With v3password: Domain ID containing project With v3oidcaccesstoken: Domain ID containing project With v3oidcpassword: Domain ID containing project With token: Domain ID containing project With v3oidcclientcredentials: Domain ID containing project With v3tokenlessauth: Domain ID containing project With v3token: Domain ID containing project With v3totp: Domain ID containing project With password: Domain ID containing project (Env: OS_PROJECT_DOMAIN_ID) --os-password With v2password: Password to use With v3password: User's password With v3oidcpassword: Password With password: User's password (Env: OS_PASSWORD) --os-redirect-uri With v3oidcauthcode: OpenID Connect Redirect URL (Env: OS_REDIRECT_URI) --os-endpoint With admin_token: The endpoint that will always be used (Env: OS_ENDPOINT) --os-token With v2token: Token With admin_token: The token that will always be used With token: Token to authenticate with With v3token: Token to authenticate with (Env: OS_TOKEN) --os-passcode With v3totp: User's TOTP passcode (Env: OS_PASSCODE) --os-project-id With v3oidcauthcode: Project ID to scope to With v3password: Project ID to scope to With v3oidcaccesstoken: Project ID to scope to With v3oidcpassword: Project ID to scope to With token: Project ID to scope to With v3oidcclientcredentials: Project ID to scope to With v3tokenlessauth: Project ID to scope to With v3token: Project ID to scope to With v3totp: Project ID to scope to With password: Project ID to scope to (Env: OS_PROJECT_ID) --monasca-api-url MONASCA_API_URL Defaults to env[MONASCA_API_URL]. --monasca-api-version MONASCA_API_VERSION Defaults to env[MONASCA_API_VERSION] or 2_0 Commands: alarm-count Count alarms. alarm-definition-create Create an alarm definition. alarm-definition-delete Delete the alarm definition. alarm-definition-list List alarm definitions for this tenant. alarm-definition-patch Patch the alarm definition. alarm-definition-show Describe the alarm definition. alarm-definition-update Update the alarm definition. alarm-delete Delete the alarm. alarm-history Alarm state transition history. alarm-history-list List alarms state history. alarm-list List alarms for this tenant. alarm-patch Patch the alarm state. alarm-show Describe the alarm. alarm-update Update the alarm state. complete print bash completion command dimension-name-list List names of metric dimensions. dimension-value-list List names of metric dimensions. help print detailed help for another command measurement-list List measurements for the specified metric. metric-create Create metric. metric-create-raw Create metric from raw json body. metric-list List metrics for this tenant. metric-name-list List names of metrics. metric-statistics List measurement statistics for the specified metric. notification-create Create notification. notification-delete Delete notification. notification-list List notifications for this tenant. notification-patch Patch notification. notification-show Describe the notification. notification-type-list List notification types supported by monasca. notification-update Update notification. Bash Completion --------------- Basic command tab completion can be enabled by sourcing the bash completion script. :: monasca completion >> /usr/local/share/monasca.bash_completion python-monascaclient-2.0.0/doc/source/cli/monasca.rst0000664000175000017500000003042413620561064022667 0ustar zuulzuul00000000000000================= Using monasca CLI ================= The **monasca** shell utility interacts with OpenStack Monitoring API from the command-line. It supports the entire features of OpenStack Monitoring API. Basic Usage ----------- In order to use the CLI, you must provide your OpenStack username, password, project, domain information for both user and project, and auth endpoint. Use the corresponding configuration options (``--os-username``, ``--os-password``, ``--os-project-name``, ``--os-user-domain-id``, ``os-project-domain-id``, and ``--os-auth-url``), but it is easier to set them in environment variables. .. code-block:: shell export OS_USERNAME=mini-mon export OS_PASSWORD=password export OS_PROJECT_NAME=mini-mon export OS_USER_DOMAIN_ID=default export OS_PROJECT_DOMAIN_ID=default export OS_AUTH_URL=http://keystone:5000/v3 If you are using Identity v2.0 API (DEPRECATED), you don't need to pass domain information. .. code-block:: shell export OS_USERNAME=mini-mon export OS_PASSWORD=password export OS_TENANT_NAME=mini-mon export OS_AUTH_URL=http://keystone:5000/v2.0 Once you've configured your authentication parameters, you can run **monasca** commands. All commands take the form of: .. code-block:: text monasca [arguments...] Run **monasca help** to get a full list of all possible commands, and run **monasca help ** to get detailed help for that command. Using with os-client-config ~~~~~~~~~~~~~~~~~~~~~~~~~~~ `os-client-config `_ provides more convenient way to manage a collection of client configurations and you can easily switch multiple OpenStack-based configurations. To use os-client-config, you first need to prepare ``~/.config/openstack/clouds.yaml`` like the following. .. code-block:: yaml clouds: monitoring: auth: auth_url: http://keystone:5000 password: password project_domain_id: default project_name: mini-mon user_domain_id: default username: mini-mon identity_api_version: '3' region_name: RegionOne Then, you need to specify a configuration name defined in the above clouds.yaml. .. code-block:: shell export OS_CLOUD=monitoring For more detail information, see the `os-client-config `_ documentation. Using with keystone token ~~~~~~~~~~~~~~~~~~~~~~~~~ The command-line tool will attempt to re-authenticate using your provided credentials for every request. You can override this behavior by manually supplying an auth token using ``--os-url`` and ``--os-auth-token``. You can alternatively set these environment variables. .. code-block:: shell export OS_URL=http://monasca.example.org:8070/ export OS_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155 Usage Examples ---------------- metric-create:: monasca metric-create cpu1 123.40 monasca metric-create metric1 1234.56 --dimensions instance_id=123,service=ourservice monasca metric-create metric1 2222.22 --dimensions instance_id=123,service=ourservice monasca metric-create metric1 3333.33 --dimensions instance_id=222,service=ourservice monasca metric-create metric1 4444.44 --dimensions instance_id=222 --value-meta rc=404 metric-list:: monasca metric-list +---------+--------------------+ | name | dimensions | +---------+--------------------+ | cpu1 | | | metric1 | instance_id:123 | | | service:ourservice | +---------+--------------------+ measurement-list:: monasca measurement-list metric1 2014-01-01T00:00:00Z +---------+--------------------+----------------+----------------------+--------------+-------------+ | name | dimensions | measurement_id | timestamp | value | value_meta | +---------+--------------------+----------------+----------------------+--------------+-------------+ | metric1 | instance_id:123 | 723885 | 2014-05-08T21:46:32Z | 1234.56 | | | | service:ourservice | 725951 | 2014-05-08T21:48:50Z | 2222.22 | | | metric1 | instance_id:222 | 726837 | 2014-05-08T21:49:47Z | 3333.33 | | | | service:ourservice | 726983 | 2014-05-08T21:50:27Z | 4444.44 | rc: 404 | +---------+--------------------+----------------+----------------------+--------------+-------------+ monasca measurement-list metric1 2014-01-01T00:00:00Z --dimensions instance_id=123 +---------+--------------------+----------------+----------------------+--------------+-------------+ | name | dimensions | measurement_id | timestamp | value | value_meta | +---------+--------------------+----------------+----------------------+--------------+-------------+ | metric1 | instance_id:123 | 723885 | 2014-05-08T21:46:32Z | 1234.56 | | | | service:ourservice | 725951 | 2014-05-08T21:48:50Z | 2222.22 | | +---------+--------------------+----------------+----------------------+--------------+-------------+ Notifications Examples ~~~~~~~~~~~~~~~~~~~~~~ Note: To see complete usage: 'monasca help' and 'monasca help ' notification-create:: monasca notification-create cindyemail1 EMAIL cindy.employee@hp.com monasca notification-create myapplication WEBHOOK http://localhost:5000 monasca notification-create mypagerduty PAGERDUTY nzH2LVRdMzun11HNC2oD notification-list:: monasca notification-list +---------------+--------------------------------------+-------+----------------------+ | name | id | type | address | +---------------+--------------------------------------+-------+----------------------+ | cindyemail1 | 5651406c-447d-40bd-b868-b2b3e6b59e32 | EMAIL |cindy.employee@hp.com | | myapplication | 55905ce2-91e3-41ce-b45a-de7032f8d718 | WEBHOOK |http://localhost:5000 | mypagerduty | 5720ccb5-6a3d-22ba-545g-ce467a5b41a2 | PAGERDUTY |nzH2LVRdMzun11HNC2oD +---------------+--------------------------------------+-------+----------------------+ Alarms Examples ~~~~~~~~~~~~~~~ Note: To see complete usage: 'monasca help' and 'monasca help ' alarm-definition-create:: monasca alarm-definition-create alarmPerHost "max(cpu.load_avg_1_min) > 0" --match-by hostname alarm-definition-list:: +--------------+--------------------------------------+-----------------------------+----------+-----------------+ | name | id | expression | match_by | actions_enabled | +--------------+--------------------------------------+-----------------------------+----------+-----------------+ | alarmPerHost | 4bf6bfc2-c5ac-4d57-b7db-cf5313b05412 | max(cpu.load_avg_1_min) > 0 | hostname | True | +--------------+--------------------------------------+-----------------------------+----------+-----------------+ alarm-definition-show:: monasca alarm-definition-show 4bf6bfc2-c5ac-4d57-b7db-cf5313b05412 +----------------------+----------------------------------------------------------------------------------------------------+ | Property | Value | +----------------------+----------------------------------------------------------------------------------------------------+ | actions_enabled | true | | alarm_actions | [] | | description | "" | | expression | "max(cpu.load_avg_1_min) > 0" | | id | "4bf6bfc2-c5ac-4d57-b7db-cf5313b05412" | | links | href:http://192.168.10.4:8070/v2.0/alarm-definitions/4bf6bfc2-c5ac-4d57-b7db-cf5313b05412,rel:self | | match_by | [ | | | "hostname" | | | ] | | name | "alarmPerHost" | | ok_actions | [] | | severity | "LOW" | | undetermined_actions | [] | +----------------------+----------------------------------------------------------------------------------------------------+ alarm-definition-delete:: monasca alarm-definition-delete 4bf6bfc2-c5ac-4d57-b7db-cf5313b05412 alarm-list:: monasca alarm-list +--------------------------------------+--------------------------------------+----------------+---------------+---------------------+----------+-------+--------------------------+--------------------------+ | id | alarm_definition_id | alarm_name | metric_name | metric_dimensions | severity | state | state_updated_timestamp | created_timestamp | +--------------------------------------+--------------------------------------+----------------+---------------+---------------------+----------+-------+--------------------------+--------------------------+ | 11e8c15d-0263-4b71-a8b8-4ecdaeb2902c | af1f347b-cddb-46da-b7cc-924261eeecdf | High CPU usage | cpu.idle_perc | hostname: devstack | LOW | OK | 2015-03-26T21:45:15.000Z | 2015-03-26T21:41:50.000Z | | e5797cfe-b66e-4d44-98cd-3c7fc62d4c33 | af1f347b-cddb-46da-b7cc-924261eeecdf | High CPU usage | cpu.idle_perc | hostname: mini-mon | LOW | OK | 2015-03-26T21:43:15.000Z | 2015-03-26T21:41:47.000Z | | | | | | service: monitoring | | | | | +--------------------------------------+--------------------------------------+----------------+---------------+---------------------+----------+-------+--------------------------+--------------------------+ alarm-history:: monasca alarm-history 9d748b72-939b-45e7-a807-c0c5ad88d3e4 +--------------------------------------+-----------+--------------+------------------------------------------------------------------------------+-------------+--------------------+---------------------+--------------------------+ | alarm_id | new_state | old_state | reason | reason_data | metric_name | metric_dimensions | timestamp | +--------------------------------------+-----------+--------------+------------------------------------------------------------------------------+-------------+--------------------+---------------------+--------------------------+ | 9d748b72-939b-45e7-a807-c0c5ad88d3e4 | ALARM | UNDETERMINED | Thresholds were exceeded for the sub-alarms: [max(cpu.load_avg_1_min) > 0.0] | {} | cpu.load_avg_1_min | hostname: mini-mon | 2014-10-14T21:14:11.000Z | | | | | | | | service: monitoring | | +--------------------------------------+-----------+--------------+------------------------------------------------------------------------------+-------------+--------------------+---------------------+--------------------------+ alarm-patch:: monasca alarm-patch fda5537b-1550-435f-9d6c-262b7e05065b --state OK python-monascaclient-2.0.0/doc/source/cli/monasca-formatting.rst0000664000175000017500000000236513620561064025042 0ustar zuulzuul00000000000000=================== Changing formatting =================== Changing displayed columns -------------------------- If you want displayed columns in a list operation, ``-c`` option can be used. ``-c`` can be specified multiple times and the column order will be same as the order of ``-c`` options. Changing format --------------- If you want to change the format data is displayed in, you can use ``-f`` option for that. Format can be specified just once and it affects they way the data is printed to the ``STDOUT``. The available formats, data can be presented in, can be checked with: .. code-block:: text monasca --help Look for section **output formatters** and the flag ``--format`` or ``-f``. In most of the cases you will be able to pick one out of ``csv``, ``json``, ``table``, ``value``, ``yaml``. Affecting the width ------------------- If, for some reason, you are not happy with the width the output has taken, you can use ```--max-width {number}``` flag and set the value to match your preference. Without that output will not be constrained by the terminal width. Alternatively you may want to pass ``--fit-width`` to fit the output to display width. Remember that these flags affect the output only if ``table`` formatter is used. python-monascaclient-2.0.0/doc/source/cli/monasca-debug.rst0000664000175000017500000000075013620561064023752 0ustar zuulzuul00000000000000========= Debugging ========= ``-v`` (or ``--verbose``), as well as ``--debug``, option can be used to increase amount of low-level details regarding all the steps that client takes in order to execute the CLI command. While ``--verbose`` does not dramatically increase the output by displaying only basic information about the execution, ``--debug`` can be used to additionally display low-level interactions **monascaclient** make with **keystone** server and/or **monasca** server. python-monascaclient-2.0.0/doc/source/usage/0000775000175000017500000000000013620561132021042 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/doc/source/usage/index.rst0000664000175000017500000000124713620561064022713 0ustar zuulzuul00000000000000===== Usage ===== Devstack -------- python-monascaclient is bundled inside `Monasca API Devstack Plugin`_ and is available right after the devstack finished stacking up. It is always built from the **master** branch, unless specified otherwise. Docker ------ The client is also part of `monasca-docker`_, a community effort to put **monasca** into containers. The image is available as **monasca/client** and can be used as drop-in replacement for traditional way of deploying the clients. .. _Monasca API Devstack Plugin: https://github.com/openstack/monasca-api/tree/master/devstack .. _monasca-docker: https://github.com/monasca/monasca-docker/tree/master/monasca-client python-monascaclient-2.0.0/doc/source/conf.py0000664000175000017500000000742113620561064021245 0ustar zuulzuul00000000000000# -*- coding: utf-8 -*- import os import sys from monascaclient.version import version_info sys.path = [ os.path.abspath('../..'), os.path.abspath('../../bin') ] + sys.path # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. needs_sphinx = '1.6' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.coverage', 'sphinx.ext.ifconfig', 'sphinx.ext.graphviz', 'sphinx.ext.viewcode', 'openstackdocstheme' ] # geeneral information about project repository_name = u'openstack/python-monascaclient' project = u'Monasca Client Dev Docs' version = version_info.canonical_version_string() release = version_info.version_string_with_vcs() bug_project = u'880' bug_tag = u'' copyright = u'2014-present, OpenStack Foundation' author = u'OpenStack Foundation' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. source_suffix = '.rst' # The encoding of source files. source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [ 'common', 'doc', 'documentation', 'etc', 'java' ] # 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 = 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. See the documentation for # a list of builtin themes. html_theme = 'openstackdocs' # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%Y-%m-%d %H:%M' # If false, no index is generated. html_use_index = True # If false, no module index is generated. html_use_modindex = True # Output file base name for HTML help builder. htmlhelp_basename = 'python-monascaclientdoc' # -- Options for LaTeX output --------------------------------------------- # 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 = [ (master_doc, 'python-monascaclient.tex', u'python-monascaclient Documentation', u'Openstack Foundation \\textless{}monasca@lists.launchpad.net\\textgreater{}', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'python-monascaclient', u'python-monascaclient Documentation', [author], 1) ] # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'python-monascaclient', u'python-monascaclient Documentation', author, 'python-monascaclient', 'Rest-API to collect logs from your cloud.', 'Miscellaneous'), ] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://doc.python.org/': None} python-monascaclient-2.0.0/requirements.txt0000664000175000017500000000072713620561064021167 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. osc-lib>=1.8.0 # Apache-2.0 oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 oslo.utils>=3.33.0 # Apache-2.0 Babel!=2.4.0,>=2.3.4 # BSD iso8601>=0.1.11 # MIT pbr!=2.1.0,>=2.0.0 # Apache-2.0 PrettyTable<0.8,>=0.7.2 # BSD PyYAML>=3.12 # MIT six>=1.10.0 # MIT python-monascaclient-2.0.0/CONTRIBUTING.rst0000664000175000017500000000121313620561064020333 0ustar zuulzuul00000000000000If you would like to contribute to the development of OpenStack, you must follow the steps in this page: http://docs.openstack.org/infra/manual/developers.html If you already have a good understanding of how the system works and your OpenStack accounts are set up, you can skip to the development workflow section of this documentation to learn how changes to OpenStack should be submitted for review via the Gerrit tool: http://docs.openstack.org/infra/manual/developers.html#development-workflow Pull requests submitted through GitHub will be ignored. Bugs should be filed on Launchpad, not GitHub: https://bugs.launchpad.net/monasca python-monascaclient-2.0.0/python_monascaclient.egg-info/0000775000175000017500000000000013620561132023604 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/python_monascaclient.egg-info/requires.txt0000664000175000017500000000025713620561132026210 0ustar zuulzuul00000000000000osc-lib>=1.8.0 oslo.serialization!=2.19.1,>=2.18.0 oslo.utils>=3.33.0 Babel!=2.4.0,>=2.3.4 iso8601>=0.1.11 pbr!=2.1.0,>=2.0.0 PrettyTable<0.8,>=0.7.2 PyYAML>=3.12 six>=1.10.0 python-monascaclient-2.0.0/python_monascaclient.egg-info/PKG-INFO0000664000175000017500000000423413620561132024704 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-monascaclient Version: 2.0.0 Summary: Monasca API Client Library Home-page: https://docs.openstack.org/python-monascaclient/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/python-monascaclient.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on Python bindings to the Monasca API ================================== .. image:: https://img.shields.io/pypi/v/python-monascaclient.svg :target: https://pypi.python.org/pypi/python-monascaclient/ :alt: Latest Version This is a client library for Monasca built to interface with the Monasca API. It provides a Python API (the ``monascaclient`` module) and a command-line tool (``monasca``). * License: Apache License, Version 2.0 * `PyPi`_ - package installation * `Online Documentation`_ * `Bugs`_ - issue tracking (we use *bug* tag to differentiate from new features) * `Source`_ .. _PyPi: https://pypi.python.org/pypi/python-monascaclient .. _Online Documentation: https://docs.openstack.org/python-monascaclient/latest/ .. _Bugs: https://storyboard.openstack.org/#!/project/880 .. _Source: https://opendev.org/openstack/python-monascaclient Platform: UNKNOWN Classifier: Environment :: Console 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.6 Classifier: Programming Language :: Python :: 3.7 python-monascaclient-2.0.0/python_monascaclient.egg-info/not-zip-safe0000664000175000017500000000000113620561132026032 0ustar zuulzuul00000000000000 python-monascaclient-2.0.0/python_monascaclient.egg-info/entry_points.txt0000664000175000017500000000006613620561132027104 0ustar zuulzuul00000000000000[console_scripts] monasca = monascaclient.shell:main python-monascaclient-2.0.0/python_monascaclient.egg-info/SOURCES.txt0000664000175000017500000000417513620561132025477 0ustar zuulzuul00000000000000.stestr.conf .zuul.yaml AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE README.rst lower-constraints.txt requirements.txt setup.cfg setup.py test-requirements.txt tox.ini doc/source/conf.py doc/source/index.rst doc/source/installation.rst doc/source/cli/index.rst doc/source/cli/monasca-debug.rst doc/source/cli/monasca-formatting.rst doc/source/cli/monasca.rst doc/source/reference/index.rst doc/source/usage/index.rst docker/Dockerfile docker/README.rst docker/build_image.sh docker/health_check.py docker/start.sh monascaclient/__init__.py monascaclient/client.py monascaclient/shell.py monascaclient/version.py monascaclient/common/__init__.py monascaclient/common/monasca_manager.py monascaclient/common/utils.py monascaclient/osc/__init__.py monascaclient/osc/migration.py monascaclient/tests/__init__.py monascaclient/tests/test_client.py monascaclient/tests/test_shell.py monascaclient/tests/v2_0/__init__.py monascaclient/tests/v2_0/shell/__init__.py monascaclient/tests/v2_0/shell/test_alarm_definitions.py monascaclient/tests/v2_0/shell/test_metrics.py monascaclient/tests/v2_0/shell/test_notification_types.py monascaclient/tests/v2_0/shell/test_notifications.py monascaclient/v2_0/__init__.py monascaclient/v2_0/alarm_definitions.py monascaclient/v2_0/alarms.py monascaclient/v2_0/client.py monascaclient/v2_0/metrics.py monascaclient/v2_0/notifications.py monascaclient/v2_0/notificationtypes.py monascaclient/v2_0/shell.py playbooks/docker-publish.yml python_monascaclient.egg-info/PKG-INFO python_monascaclient.egg-info/SOURCES.txt python_monascaclient.egg-info/dependency_links.txt python_monascaclient.egg-info/entry_points.txt python_monascaclient.egg-info/not-zip-safe python_monascaclient.egg-info/pbr.json python_monascaclient.egg-info/requires.txt python_monascaclient.egg-info/top_level.txt releasenotes/locale/.gitkeep releasenotes/notes/drop-py-2-7-1c41855c5edc5ba3.yaml releasenotes/notes/openstack_docs-5cfec48411370070.yaml releasenotes/source/conf.py releasenotes/source/index.rst releasenotes/source/queens.rst releasenotes/source/rocky.rst releasenotes/source/stein.rst releasenotes/source/train.rst releasenotes/source/unreleased.rstpython-monascaclient-2.0.0/python_monascaclient.egg-info/pbr.json0000664000175000017500000000005613620561132025263 0ustar zuulzuul00000000000000{"git_version": "2504eed", "is_release": true}python-monascaclient-2.0.0/python_monascaclient.egg-info/top_level.txt0000664000175000017500000000001613620561132026333 0ustar zuulzuul00000000000000monascaclient python-monascaclient-2.0.0/python_monascaclient.egg-info/dependency_links.txt0000664000175000017500000000000113620561132027652 0ustar zuulzuul00000000000000 python-monascaclient-2.0.0/LICENSE0000664000175000017500000002363613620561064016714 0ustar zuulzuul00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. python-monascaclient-2.0.0/setup.py0000664000175000017500000000200613620561064017405 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-monascaclient-2.0.0/README.rst0000664000175000017500000000214413620561064017365 0ustar zuulzuul00000000000000======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/python-monascaclient.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on Python bindings to the Monasca API ================================== .. image:: https://img.shields.io/pypi/v/python-monascaclient.svg :target: https://pypi.python.org/pypi/python-monascaclient/ :alt: Latest Version This is a client library for Monasca built to interface with the Monasca API. It provides a Python API (the ``monascaclient`` module) and a command-line tool (``monasca``). * License: Apache License, Version 2.0 * `PyPi`_ - package installation * `Online Documentation`_ * `Bugs`_ - issue tracking (we use *bug* tag to differentiate from new features) * `Source`_ .. _PyPi: https://pypi.python.org/pypi/python-monascaclient .. _Online Documentation: https://docs.openstack.org/python-monascaclient/latest/ .. _Bugs: https://storyboard.openstack.org/#!/project/880 .. _Source: https://opendev.org/openstack/python-monascaclient python-monascaclient-2.0.0/playbooks/0000775000175000017500000000000013620561132017674 5ustar zuulzuul00000000000000python-monascaclient-2.0.0/playbooks/docker-publish.yml0000664000175000017500000000061513620561064023340 0ustar zuulzuul00000000000000--- - hosts: all tasks: - name: Login to Dockerhub command: "docker login -u {{ doker_hub_login_client.user }} -p {{ doker_hub_login_client.password }}" no_log: true - name: List images shell: "docker images --format '{% raw %}{{ .Repository }}:{{ .Tag }}{% endraw %}' | grep monasca" - name: Push to Docker Hub all tags shell: "docker push monasca/client" python-monascaclient-2.0.0/tox.ini0000664000175000017500000000475013620561064017216 0ustar zuulzuul00000000000000[tox] envlist = py37,pypy,cover,pep8 minversion = 3.1.1 skipsdist = True ignore_basepython_conflict = True [testenv] basepython = python3 setenv = VIRTUAL_ENV={envdir} OS_TEST_PATH=monascaclient/tests PYTHONWARNINGS=default::DeprecationWarning passenv = *_proxy *_PROXY usedevelop = True install_command = pip install {opts} {packages} deps = -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt whitelist_externals = bash find rm commands = find {toxinidir} -type f -name "*.pyc" -delete stestr run {posargs} [testenv:cover] setenv = PYTHON=coverage run --source monascaclient --parallel-mode commands = coverage erase stestr run {posargs} coverage combine coverage html -d cover coverage xml -o cover/coverage.xml coverage report [testenv:debug] commands = oslo_debug_helper -t {env:OS_TEST_PATH} {posargs} [testenv:pep8] skip_install = True usedevelop = False commands = {[testenv:flake8]commands} {[testenv:bandit]commands} {[testenv:checkniceness]commands} [testenv:flake8] skip_install = True usedevelop = False commands = flake8 monascaclient [testenv:bandit] skip_install = True usedevelop = False commands = bandit -r monascaclient -n5 -x {env:OS_TEST_PATH} [testenv:docs] description = Builds full monascaclient documentation commands = {[testenv:devdocs]commands} {[testenv:releasenotes]commands} [testenv:devdocs] description = Builds developer documentation commands = rm -rf {toxinidir}/doc/build {toxinidir}/doc/source/contributor/api python setup.py build_sphinx [testenv:releasenotes] description = Called from CI script to test and publish the Release Notes commands = rm -rf releasenotes/build sphinx-build -a -E -d {toxinidir}/releasenotes/build/doctrees -b html \ {toxinidir}/releasenotes/source {toxinidir}/releasenotes/build/html [testenv:checkniceness] description = Validates (pep-like) documenation commands = doc8 --file-encoding utf-8 {toxinidir}/doc doc8 --file-encoding utf-8 {toxinidir}/releasenotes [testenv:venv] commands = {posargs} [hacking] import_exceptions = six.moves [flake8] show-source = True max-line-length = 100 builtins = _ exclude=.venv,.git,.tox,dist,client_api_example.py,*lib/python*,*egg,build [testenv:lower-constraints] deps = -c{toxinidir}/lower-constraints.txt -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt python-monascaclient-2.0.0/lower-constraints.txt0000664000175000017500000000244013620561064022133 0ustar zuulzuul00000000000000alabaster==0.7.10 appdirs==1.3.0 Babel==2.3.4 bandit==1.4.0 chardet==3.0.4 cliff==2.8.0 cmd2==0.8.0 coverage==4.0 debtcollector==1.2.0 decorator==3.4.0 deprecation==1.0 doc8==0.6.0 docutils==0.11 dogpile.cache==0.6.2 dulwich==0.15.0 extras==1.0.0 fixtures==3.0.0 flake8==2.5.5 future==0.16.0 gitdb==0.6.4 GitPython==1.0.1 hacking==1.1.0 imagesize==0.7.1 iso8601==0.1.11 Jinja2==2.10 jmespath==0.9.0 jsonpatch==1.16 jsonpointer==1.13 keystoneauth1==3.4.0 linecache2==1.0.0 MarkupSafe==1.0 mccabe==0.2.1 mock==2.0.0 monotonic==0.6 mox3==0.20.0 msgpack-python==0.4.0 munch==2.1.0 netaddr==0.7.18 netifaces==0.10.4 openstackdocstheme==1.18.1 openstacksdk==0.11.2 os-client-config==1.28.0 os-service-types==1.2.0 os-testr==1.0.0 osc-lib==1.8.0 oslo.i18n==3.15.3 oslo.serialization==2.18.0 oslo.utils==3.33.0 oslotest==3.2.0 pbr==2.0.0 pep8==1.5.7 prettytable==0.7.2 pyflakes==0.8.1 Pygments==2.2.0 pyparsing==2.1.0 pyperclip==1.5.27 python-mimeparse==1.6.0 python-subunit==1.0.0 pytz==2013.6 PyYAML==3.12 reno==2.5.0 requests==2.14.2 requestsexceptions==1.2.0 restructuredtext-lint==1.1.1 simplejson==3.5.1 six==1.10.0 smmap==0.9.0 snowballstemmer==1.2.1 Sphinx==1.6.5 sphinxcontrib-websupport==1.0.1 stestr==1.0.0 stevedore==1.20.0 testscenarios==0.4 testtools==2.2.0 traceback2==1.4.0 unittest2==1.1.0 wrapt==1.7.0 python-monascaclient-2.0.0/.stestr.conf0000664000175000017500000000010613620561064020143 0ustar zuulzuul00000000000000[DEFAULT] test_path=${OS_TEST_PATH:-./monascaclient/tests} top_dir=./ python-monascaclient-2.0.0/ChangeLog0000664000175000017500000003045013620561132017445 0ustar zuulzuul00000000000000CHANGES ======= 2.0.0 ----- * [ussuri][goal] Drop python 2.7 support and testing * Switch to Ussuri jobs * Sync Sphinx requirement * Update the constraints url * Update master for stable/train 1.16.0 ------ * Add Python 3 Train unit tests * Switch python3 versions of test jobs to match Train PTI * Change repository links usage in Dockerfile and build image * Replace git.openstack.org URLs with opendev.org URLs * Dropping the py35 testing * OpenDev Migration Patch * Push Docker image to Docker Hub * Create Docker image and build in Zuul * Fix metric list formatting with Python 3 * Replace openstack.org git:// URLs with https:// * Update master for stable/stein 1.14.0 ------ * Update hacking version * Update json module to jsonutils * add python 3.7 unit test job 1.13.0 ------ * Fix alarm-definition-list in Python 3 * Return status from running command * Change openstack-dev to openstack-discuss * Add Python 3.6 classifier to setup.cfg * Add python 3.6 unit test job * Remove setup.py check from pep8 job * Don't quote {posargs} in tox.ini * fix tox python3 overrides * Use templates for docs, cover and lower-constraints * Add using requirements.txt to tox tests run * add python 3.6 unit test job * switch documentation job to new PTI * import zuul job settings from project-config * Update reno for stable/rocky 1.12.1 ------ * Clean up README.rst * Move CLI usage examples to doc/cli directory * Add syntax check for reStructuredText * Restore old content of reference/index.rst 1.12.0 ------ * Fix rst errors in README * Remove unused TimingSession class * Remove testrepository and .testr.conf * Remove the duplicated word * fix tox python3 overrides * replace unicode with six.text\_type * Switch to using stestr * Redistribute README to doc/source * Trivial: Update pypi url to new url 1.11.0 ------ * Update pep8 checks * Clean up tox.ini * add lower-constraints job * Updated from global requirements * Update links in README * Updated from global requirements * Updated from global requirements * Update reno for stable/queens 1.10.0 ------ * Updated from global requirements * Updated from global requirements * Updated from global requirements * Update usage examples * TrivialFix: remove redundant import alias * Updated from global requirements 1.9.0 ----- * Updated from global requirements * Updated from global requirements * Avoid tox\_install.sh for constraints support * Enable client documentation 1.8.0 ----- * Fix auth version detection * Updated from global requirements * Updated from global requirements * Cleanup repo and update documentation * Allow to reuse the session * Exclude tests from coverage * Update the documentation link for doc migration 1.7.0 ----- * Bringing back backward compatybility * Updated from global requirements * Integrate client with osc-lib * Updated from global requirements * Updated from global requirements * Updated from global requirements 1.6.0 ----- * Added support for os\_auth\_version when os\_auth\_url is unversiond * Added support for os\_tenant\_{name,id} after os\_project\_ * Optimize the link address * Updated from global requirements * Replacing six.iteritems() with .items() * Updated from global requirements * Migrate fully to ostestr * Updated from global requirements * Remove unused requirements * Fix notification-patch CLI fails if type not given * Fix: CLI metric-create using project-id fails * Updated from global requirements * Turn on bandit check as part of pep8 1.5.0 ----- * Typo fix: recieve => receive * Remove support for py33 * Updated from global requirements * Don't send X-Auth- headers in requests * Use requests-mock instead of custom fakes * H803 hacking have been deprecated 1.4.0 ----- * Updated from global requirements * Delete deprecated Hacking in tox.ini * Add py35 tox environment * Use the new copy of tox\_install.sh for global constraints support * Correct reraising of exception * Add \_\_ne\_\_ built-in function * Show team and repo badges on README * Add list\_next for pagination * Add CONTRIBUTING.rst 1.3.0 ----- * Fix LOG.warn to LOG.warning * move old apiclient code out of openstack/common * remove unused openstack/common/gettextutils.py * use six.moves.urllib.parse instead of py3kcompat * Use correct ENV variables for scoping * Changed author and author-email * Remove a space of Docstring * Add state-updated-timestamp filter to alarm count CLI * Sample nagios plugin and examples directory * Remove white space between print and () * Dimension value list doesn't recognize dimension name input * Change LOG.warn to LOG.warning * Add list dimension names and values in CLI * Use constraints everywhere * Sync tools/tox\_install.sh * Add support for new rest api notification-type-list * Remove discover from test-requirements * Fix dimension validation and help message for alarm count * Patch-notification failed with period=0 * Prevent potentially destructive updates on data * Fix monasca enpoint port in example and README * Fix \_\_str\_\_ not returning a String for KeystoneException * Fix monasca notification-show help message * Fixes H904: wrapping using parantheses * Add notification-patch into CLI 1.2.0 ----- * Add metric-name-list help command description * Revert 'Adding keystoneauth sessions support' * Sort by alarm\_definition\_name 1.1.0 ----- * Remove the debian folder * Oslo.utils safe\_decode * Update copyright in monascaclient * Adding keystoneauth sessions support * Graduate to oslo.utils strutils * Graduate to using oslo.utils importutils * Graduate to oslo.serialization jsonutils * [python-monascaclient] Change tox to use https instead of git * Add period field to notification methods * code compatibility with py3 * Constraint tox targets with upper-constraints.txt * Fix the homepage in setup.cfg * Add support for group\_by to measurements and statistics resources * Manually sync with global-requirements * [Trivial] Remove executable privilege of setup.py * Add --tenant-id option for some commands * Specify match\_by in alarm-definition-update help message * Alarm def update/patch failed with empty param * Change tox file * Implement monasca metric-name-list * Fix metric dimensions having only key 1.0.30 ------ * Fix argument name bug * Allow sorting notifications * Fixes typo in help messages for Monasca client * Convert to lower case before validating sort-by * Allow filtering by severity * Check Status Code in Monasca Client * Add in HPE Copyrights * Add missing spaces in help message 1.0.29 ------ * Enhanced dimension filtering * Allow sorting alarms 1.0.28 ------ * Unlocking requirements for Mitaka compatibility * Add alarm-count command * Remove MANIFEST.in * remove python 2.6 trove classifier * Return monasca specific error on conneciton refused * Deprecated tox -downloadcache option removed 1.0.27 ------ * Adding oslo.concurrency to requirements 1.0.26 ------ * Further restrictions on oslo.service 1.0.25 ------ * Adding liberty versions of oslo to requirements.txt * Fix documentation for creating metrics * Add start and end time optional parms to metric list * Delete python bytecode before every test run * Require all fields alarm definition update * use last specified value for duplicate dimension * Adding thousandths column to value output * mask X-Auth-Key for log\_curl\_request * Remove default environment variable string * Add the ability to use env variables 1.0.24 ------ * Update .gitreview for new namespace * Fix unicode output format * X-Auth-Key should not be required in the header 1.0.23 ------ * Pinning version of keystone client * Add timeout to keystone requests * Obfuscate Token in Debug Mode * Enable optional timeouts for http get or post requests 1.0.22 ------ * Add HP copyright to files that HP has changed * Force oslo.utils<2.0 * support users in domains other than Default (KSv3) 1.0.21 ------ * Make sure that we do not output token 1.0.20 ------ * Moved pbr requirements to a newer constraint * Removed output sorting in client * changed alarm-list output to match expected 1.0.19 ------ * added relative start time feature * Fixed README for Python API - about re-athenticate * replace v2.0 auth\_url with v3 * re-authenticates (once) with keystone to handle token expiration * Add lifecycle fields to CLI * The ERROR word was removed from the HttpException 2015.1 ------ * Moved CLI specific error message from ksclient to shell 1.0.18 ------ * Correctly selects endpoint based on region * added link to pypi versions * Fixed display problem with value\_meta * Add metric name list to the client library 1.0.17 ------ * Fixed readme with line feeds * Adjusted formatting functions for new measurement data * Made metric name required for measurement-list command * Expose state\_updated\_timestamp and created\_timestamp in alarm table 1.0.16 ------ * Adjusted client for influx 0.9 * Made name parameter for measurement-list optional * Fixed suppression of HTTP exceptions * Added offset and limit for list based commands 1.0.15 ------ 1.0.14 ------ * Handle API returning dict instead of list 1.0.13 ------ * Add measurement valueMeta * Conversion to milliseconds * Added development package and install instructions 1.0.12 ------ * No longer send application/json-patch+json as Content-Type * remove ChangeLog file so pbr can generate it from git * help for metric-create, and updated README * Fixed missing Pagerduty refs in docs and cli messages * Added pagerduty to the valid set of notifications 1.0.11 ------ * Remove match-by argument for alarm-definition-patch 1.0.10 ------ * Put the keystone auth in its own class * Enabling the support of Webhook notification on client * Allow service\_type to be overwritten * Pass the --os-service-type argument to keystone 1.0.8 ----- * Use relative path for monasca.bash\_completion 1.0.7 ----- * Update ChangeLog * Removing support for SMS on client * Need to pass the ca-file arg to keystone, too 1.0.6 ----- * Use keystone v3 and get a project scoped token 1.0.5 ----- * alarm formatting changes 1.0.4 ----- * Alarmed metrics API changes supported * updated README.rst for API clients 1.0.3 ----- * Added cross domain tenant param to metric POST * fixed unicode decode problem when printing exception * use keystone endpoint when api url is not input 1.0.2 ----- * Updated Changelog * help for dimensions mentions need for quoting * supports unicode 1.0.1 ----- * Fix several bashate issues * user pbr.version, update ChangeLog * Add .gitreview file * Bump hacking to 0.9.x series * removed transform dimension calls for alarm commands * quote alarm expression dimension values to allow special chars 1.0.0 ----- * renaming monclient to monascaclient, alarm-update fix * GET alarms by name, Client replace\_token, help fixes, id size * Add .gitreview file. pep8 fixes * README update for bash completion * added bash completion script to the install * pep8 changes * fixed timestamp ordering in measurement-list, alarm-history. renamed enabled to actions-enabled * Fixed enabled parms for alarm-patch, alarm-update * 1.0.3 * Add babel as a dependency * Updated version info * Updated README * Added metric-statistics command * Modified the auth token to match dev env * Added severity to alarm commands, Added alarm-list by state option * 1.0.1 changelog * new metric-create-raw command to support raw json body * Temporary fix for version problems in the egg/wheel * Added ChangeLog and .idea to the .gitignore * Modified README.rst * Improved the README.rst * alarm-list supports optional dimensions * Removed personal info from example and tests * Updated setup.cfg * Added HP copyright and Apache 2.0 license header. Added HACKING.rst and LICENSE file * Simplified exception handling by catching HTTPException * Updated client\_api\_example.py * removed runlocal args from resource commands, added example for api * support for alarm-history, fixed timestamp format measurement-list * Support for PUT,PATCH alarms, PUT notification-methods * Fixed measurement-list, alarm-list * added -j,--json output parameter, supported multi-dimensions in single parameter * Improved dict and dictlist formatting - put this in utils.py * fixed help formatting. metric-list formatting changed * added -l option, pep8 spacing * Latest changes to clean up the list commands * list and show implemented for alarms and notifications * Notification create working * Initial debian package setup * Unit tests working * metrics-create working * Initial monclient files. Help, and versioning is working