diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..6996891 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,7 @@ +[run] +branch = True +source = broadview_collector +omit = broadview_collector/openstack/* + +[report] +ignore_errors = True diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..516ae6f --- /dev/null +++ b/.mailmap @@ -0,0 +1,3 @@ +# Format is: +# +# diff --git a/.testr.conf b/.testr.conf new file mode 100644 index 0000000..6d83b3c --- /dev/null +++ b/.testr.conf @@ -0,0 +1,7 @@ +[DEFAULT] +test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ + OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ + OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ + ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION +test_id_option=--load-list $IDFILE +test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..e15494e --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,17 @@ +If 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/broadview-collector diff --git a/HACKING.rst b/HACKING.rst new file mode 100644 index 0000000..e25f38e --- /dev/null +++ b/HACKING.rst @@ -0,0 +1,4 @@ +broadview-collector Style Commandments +=============================================== + +Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..68c771a --- /dev/null +++ b/LICENSE @@ -0,0 +1,176 @@ + + 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. + diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..c978a52 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,6 @@ +include AUTHORS +include ChangeLog +exclude .gitignore +exclude .gitreview + +global-exclude *.pyc diff --git a/README.md b/README.md new file mode 100644 index 0000000..d443d83 --- /dev/null +++ b/README.md @@ -0,0 +1,434 @@ +# Overview + +`broadview-collector` is a service capable of receiving and publishing +BroadView data received from a network device that is running Broadcom's +BroadView agent. It is built on top of +[broadview-lib](https://github.com/openstack/broadview-lib/tree/master/broadview_lib). +broadview-collector is designed to support multiple metrics-gathering +infrastructures via a plugin architecture. + +## Publisher Plugins + +broadview-collector is designed to accept plugins that are capable of +publishing BroadView data received by the collector to metric-collecting +services such as OpenStack Monasca. These plugins are in the +form of Python classes. These classes inherit from a base class that +defines the interface the collector will invoke when data is received +from the BroadView agent. + +A serializer takes BroadView data and converts it into a playload that +is suitable for a given publisher plugin. + +Data coming into the collector from a BroadView agent is passed to a +list of handlers. Each handler is designed to convert the payload +that was received by the agent into an object form (currently, only BST +data is supported, but handlers for additional BroadView components will +be developed). This object form is canonical in the sense that it is +independent of any publisher plugin. + +Once the payload is in an object form, a list of publisher plugins is +iterated. Each publisher is given a chance to serialize the data (it +does this by instantiating a serializer object, described below). If +the serialization is successful, then the publisher plugin will write +the data to the service that it directly supports. + +## Creating Publisher Plugins + +Publisher plugins are simply python source files that exist in the directory +broadview_collector/plugins. A single class inheriting BroadViewPublisherBase +is implemented in this file. This base class defines a single method, +publish(), which accepts a data object from the collector. The plugin +must provide an override to this method. + +Addition directories can be configured to hold plugins. These directories, +if configured, will be searched for plugins at startup in addition to +broadview_collector/plugins. See the documentation on the searchpath config +variable in /etc/broadviewcollector.conf, below, for details and an +example. + +The name of the class implemented by the plugin must be BroadViewPlublisher. + +The set of plugins used at runtime is defined in configuration, and only +configured plugins will be invoked by the collector. Simply placing a +python source file in the plugins directory will not cause it to be +recognized by broadview-collector. Further details on configuration is +provided below. + +The job of the publish() method is to (optionally) call a serializer to +convert the data into payload (e.g., JSON) understandable to the service +that the publisher plugin targets, and to publish the data using whatever +API that the target service provides for doing so. + +Two example publishers are provided: + +* monascapublisher: targets the OpenStack Monasca Python metric publishing API +* logpublisher: appends data to a configured text file + +To use a publisher, it must be added to the comma-separated list of publishers +listed in /etc/broadviewcollector.conf, and the collector must be restarted. + +## Serializers + +Serializers are python source files that are located in the directory +broadview_collector/serializers. The broadview-collector is not directly +aware of these serializers, nor are they required to be configured in order +to be used. They are aggregated in the serializers directory simply to make +them available for whatever plugins wish to use (or not use) them. + +A serializer should inherit from BroadViewSerializerBase. The intent is to +promote a uniform API among the serializers. If the target of a +publisher plugin requires a new serializer be written, consider creating a +serializer that inherits BroadViewSerializerBase and locating it in the +serializers directory so that it might be of use to developers of other +publisher plugins. + +The monasca and log publishers both use the BSTToMonasca serializer located +in serializers/bst_to_monasca.py to illustrate this concept of reuse. If you +don't like the format of the messages that are written by an existing +publisher, you can write your own serializer (if one of the existing ones +does not fit your needs) and hack the publisher to import and use it instead. + +## Handlers + +A handler is designed to take traffic incoming to the collector, parse it, +and return an object (of some type) that represents the parsed data. The +returned object (or list of objects perhaps) is then sent to each registered +publisher. + +Handlers map to BroadView components. Handlers, like publisher plugins and +serializers, inherit a base class, in this case BroadViewHandlerBase. This +class, and the handlers themselves, are located in +broadview_collector/handlers. + +Handlers directly correspond to BroadView components that are supported in +broadview-lib. See https://github.com/openstack/broadview-lib for more +information on the BroadView components supported by broadview-lib. + +To use a handler, it must be listed in the comma-separated list of handlers +in /etc/broadviewcollector.conf, and it must be located in the handlers +directory. + +The name of the handler class must be BroadViewHandler. + +See broadview_collector/handlers/bsthandler.py for an example. Handlers have +a tight coupling to parsers provided in broadview-lib, and normally they will +be added (or updated) as parsers are added (or updated) in the broadview-lib +project. + +# Installing BroadView Collector + +## Basic Installation and Configuration + +Installation requires the following steps: + +1. Install OpenStack, including the services to which you intend to publish +data to. We discuss below Monasca-based publishing in more detail. Steps for +other services are currently not supported, but will be similar in scope. +Your OpenStack vendor/supplier may have installation instructions specific to +products that they support, contact your supplier for more details. + +2. Install broadview-lib: + + $ git clone https://github.com/openstack/broadview-lib.git + $ cd broadview-lib + $ python setup.py install + +3. Install broadview-collector + + $ git clone https://github.com/openstack/broadview-collector.git + $ cd broadview-collector + $ python setup.py install + +4. Copy the file broadview_collector/config/broadviewcollector.conf to /etc + + $ sudo cp broadview_collector/config/broadviewcollector.conf /etc + +5. Edit /etc/broadviewcollector.conf as needed + + $ sudo vi /etc/broadviewcollector.conf + +6. Copy broadview collector application to /usr/local/bin: + + $ sudo cp broadview_collector/bin/bvcollect.py /usr/local/bin + $ sudo chmod 755 /usr/local/bin/bvcollect.py + +7. Start the collector (assuming /usr/local/bin is in your PATH): + + $ bvcollect.py & + +In addition, you must configure the broadview agent. This involves two +steps: editing the device configuration so that the agent knows the IP +address and port where the collector is listening, and configuring the +agent to publish desired statistics. + +To configure the agent, refer to instructions provided by your vendor. +The IP address and port of the collector is in the [network] section of +/etc/broadviewcollector.conf, for example: + + [network] + + ip_address: 10.14.244.143 + port: 8082 + +Once the agent is up and running on the networking device, you can use +bv-bstclt (included in broadview-lib) to configure BST. + +## Detailed Installation: Monasca API + +This section details how to set up and configure a devstack-based install +of broadview-collector that publishes to Monasca API. + +The following assumes you are on a host running Ubuntu 14.04. Later versions +of Ubuntu may work, but as of this writing, are not tested or supported. + +1. Follow the directions for bringing up Monasca with devstack which are +located here: +https://github.com/openstack/monasca-api/blob/master/devstack/README.txt + +If you already have OpenStack and Monasca working, then you probably can +skip the above step. + +2. Follow the instructions above in [Basic Installation and +Configuration](#basicinstall) + +3. Add monascapublisher to the list of publishers in +/etc/broadviewcollector.conf + +4. Add a section, [monasca], to /etc/broadviewcollector.conf, as in the +following: + + [monasca] + + username: mini-mon + password: password + project_name: mini-mon + auth_url: http://10.14.245.57:35357/v3 + endpoint: http://10.14.245.57:8070/v2.0 + api_version: 2_0 + +A /etc/broadviewcollector.conf known to work with monasca-api devstack looks +like the following (you'll need to change the IP addresses to match the one +of your host system): + + [plugins] + + # comma separated list of plugin modules + + publishers: monascapublisher, logpublisher + + # handlers map to broadview components, e.g., bst, packet trace + + handlers: bsthandler + + [logging] + + # this section sets prefs for the logging handler. + + file: /tmp/broadview-bstlogging.log + + [network] + + ip_address: 10.14.245.57 + port: 8082 + + [monasca] + + username: mini-mon + password: password + project_name: mini-mon + auth_url: http://10.14.245.57:35357/v3 + endpoint: http://10.14.245.57:8070/v2.0 + api_version: 2_0 + +# Configuration File Syntax + +This section describes the syntax of the configuration file +/etc/broadviewcollector.conf. + +## [DEFAULT] + +The [DEFAULT] section defines logging parameters. Refer to the example +in config/broadviewcollector.conf for details. Logs in the default +configuration are written to the file +/var/log/broadview-collector/broadview-collector.log + +## [plugins] + +The [plugins] section supports the following settings related to publisher +plugins: + +### publishers + +publishers is a list of comma-separated python modules that are located in +the plugins directory, or the plugins searchpath (see searchpath, below). + +Example: + +publishers: monascapublisher, logpublisher, syslogpublisher + +### searchpath + +searchpath is a comma-separated list of prefixes that are preprended to the +publisher names when the collector attempts to load plugins. + +A search order is defined by the order of items in this comma-separated list. +The "plugins" directory associated with broadview-collector is searched +last. Each plugin is searched for in each directory, in order. If the plugin +is successfully loaded using an entry in the search path, the search ceases. +Otherwise, the search will continue in the next directory defined in the +search path. + +Note: the python searchpath (e.g., PYTHONPATH) is not modified by the value +of this variable. + +Items in the searchpath must be for the form a.b.c + +Example: + +searchpath: tmp, home.broadview.plugins + +## [misc] + +### handlers + +The handlers setting is a list of handlers of broadview payload sent by an +agent. This setting generally is defined to reflect the capabilities of +broadview-lib. If you are only interested in a subset of the functions that +BroadView supports, reducing the list of handlers to contain only those +BroadView components you are interested in can increase the performance of +the collector, and reduce the burden on your metric collection/analytics +pipeline. Items in this setting are comma-separated. + +Example: + +handlers: bsthandler + +## [logging] + +This section supports the logpublisher publisher plugin. + +### file + +This setting is the absolute path of the logfile written by the publisher +plugin + +Example: + +file: /tmp/broadview-bstlogging.log + +## [network] + +This section contains the networking configuration of the collector + +### ip_address + +The IP address (IPV4) that the collector will listen for connections on + +Example: + +ip_address: 10.14.245.57 + +### port + +The port that the collector will listen for connections on + +Example: + +port: 8082 + +## [monasca] + +This section supports the monascapublisher publisher plugin. These settings +are passed by the monasca publisher as arguments to the monasca python client +constructor. An example of how a python app creates a client object: + + from monascaclient import client + import monascaclient.exc as exc + + api_version = '2_0' + endpoint = 'http://192.168.10.4:8080/v2.0' + + auth_kwargs = {'username': 'mini-mon', + 'password': 'password', + 'project_name': 'mini-mon', + 'auth_url': 'http://192.168.10.5:35357/v3/'} + monasca_client = client.Client(api_version, endpoint, **auth_kwargs) + +The settings in this section directory correspond (in name and purpose) with +the arguments pass to the Client constructor above. + +### username + +The username to authenticate + +Example: + +username: mini-mon + +### password + +The password associated with the user being authenticated + +Example: + +password: password + +### project_name + +The project name for which the above user is authenticated + +Example: + +project_name: mini-mon + +### auth_url + +The URL of the authentication service (keystone) + +example: + +auth_url: http://10.14.245.57:35357/v3 + +### endpoint + +The URL that defines where monasca API is running + +Example: + +endpoint: http://10.14.245.57:8070/v2.0 + +### api_version + +The version of the Monasca API + +Example: + +api_version: 2_0 + +## DevStack Support + +Devstack support is provided by the files located in the directory +broadview_controller/devstack. Devstack is probably the easiest way +to experiment with BroadView Collector. + +Refer to the README.txt file in broadview_controller/devstack for +details on how to setup a devstack-based environment for executing +BroadView Collector. + +# License + +# (C) Copyright Broadcom Corporation 2016 +# +# 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. + + diff --git a/babel.cfg b/babel.cfg new file mode 100644 index 0000000..15cd6cb --- /dev/null +++ b/babel.cfg @@ -0,0 +1,2 @@ +[python: **.py] + diff --git a/broadview_collector/__init__.py b/broadview_collector/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/broadview_collector/bin/bvcollect.py b/broadview_collector/bin/bvcollect.py new file mode 100644 index 0000000..7b21193 --- /dev/null +++ b/broadview_collector/bin/bvcollect.py @@ -0,0 +1,11 @@ +#!/usr/bin/python + +import re +import sys +import time + +from broadview_collector.broadview_collector import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/broadview_collector/broadview_collector.py b/broadview_collector/broadview_collector.py new file mode 100644 index 0000000..a7ec28d --- /dev/null +++ b/broadview_collector/broadview_collector.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python + +# (C) Copyright Broadcom Corporation 2016 +# +# 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 BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer +from SocketServer import ThreadingMixIn +import threading +import argparse +import re +import cgi +import datetime +import json +from time import sleep +import ConfigParser +import os +import sys +from importlib import import_module +import ast +from oslo_log import log as logging +from oslo_config import cfg + +LOG = logging.getLogger(__name__) + +class BroadViewCollector(object): + def __init__(self): + logging.register_options(cfg.CONF) + logging.set_defaults() + cfg.CONF(args=[], + project="broadview_collector", + default_config_files=["/etc/broadviewcollector.conf"]) + logging.setup(cfg.CONF, 'broadview_collector') + self._publishers = [] + self._handlers = [] + + def readConfig(self): + LOG.info("broadview_collector: readConfig") + try: + cfg = ConfigParser.ConfigParser() + cfg.read("/etc/broadviewcollector.conf") + x = cfg.get("plugins", "publishers") + self._publisherNames = [y.strip() for y in x.split(',')] + LOG.info("publishers {}".format(self._publisherNames)) + self._searchpath = [] + try: + x = cfg.get("plugins", "searchpath") + self._searchpath = [y.strip() for y in x.split(',')] + except: + LOG.info("plugin searchpath missing or malformed") + + if not self._searchpath or len(self._searchpath) == 0: + self._searchpath = ["broadview_collector.plugins"] + else: + self._searchpath.append("broadview_collector.plugins") + LOG.info("plugin searchpath {}".format(self._searchpath)) + + x = cfg.get("plugins", "handlers") + self._handlerNames = [y.strip() for y in x.split(',')] + LOG.info("plugin handlers {}".format(self._handlerNames)) + self._ip_address = cfg.get("network", "ip_address") + self._port = int(cfg.get("network", "port")) + + except: + LOG.error("Unable to open or read /etc/broadviewcollector.conf") + exit() + + def loadPublishers(self): + LOG.info("broadview_collector: loadPublishers") + self._publishers = [] + for x in self._publisherNames: + for y in self._searchpath: + try: + path = "{}.{}".format(y, x) + mod = import_module(path) + classattr = getattr(mod, "BroadViewPublisher") + self._publishers.append(classattr()) + LOG.info("loaded plugin %s" % (path)) + break + except: + e = sys.exc_info()[0] + LOG.info("Unable to load plugin %s: %s" % (path, e)) + + def loadHandlers(self): + LOG.info("broadview_collector: loadHandlers") + self._handlers = [] + for x in self._handlerNames: + try: + mod = import_module("broadview_collector.handlers." + x) + classattr = getattr(mod, "BroadViewHandler") + self._handlers.append(classattr()) + LOG.info("imported handler %s" % ("broadview_collector.handlers." + x)) + except: + e = sys.exc_info()[0] + LOG.info("Unable to load handler %s: %s" % (x, e)) + exit() + + def handlePOST(self, path, ctype, length, data): + ''' + find a handler that can handle the request, and then if + successful, send it to all publishers + ''' + + handled = False + retcode = 404 + LOG.info("broadview_collector: handlePOST") + + for x in self._handlers: + o, handled = x.handlePOST(path, ctype, length, data) + if handled: + for y in self._publishers: + code = y.publish(o) + if not code == 200: + LOG.info("handlePOST: {} failed to publish, code: {}".format(y, code)) + retcode = 200 + break + LOG.info("broadview_collector: handlePOST returns %d" % (retcode)) + return retcode + +collector = BroadViewCollector() + +class HTTPRequestHandler(BaseHTTPRequestHandler): + def do_PUT(self): + pass + + def do_POST(self): + ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) + length = int(self.headers.getheader('content-length')) + data = ast.literal_eval(json.loads(self.rfile.read(length))) + code = collector.handlePOST(self.path, ctype, length, data) + data = json.dumps({}) + self.send_response(code) + self.send_header('Content-Type', 'application/json') + self.end_headers() + self.wfile.write(data) + + return + +class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): + allow_reuse_address = True + + def shutdown(self): + self.socket.close() + HTTPServer.shutdown(self) + +class SimpleHttpServer(): + def __init__(self, ip, port): + self.server = ThreadedHTTPServer((ip,port), HTTPRequestHandler) + + def start(self): + self.server_thread = threading.Thread(target=self.server.serve_forever) + self.server_thread.daemon = True + self.server_thread.start() + + def waitForThread(self): + self.server_thread.join() + + def stop(self): + self.server.shutdown() + self.waitForThread() + +def main(): + collector.readConfig() + collector.loadPublishers() + collector.loadHandlers() + server = SimpleHttpServer(collector._ip_address, collector._port) + LOG.info('HTTP Server Running...........') + server.start() + server.waitForThread() + +if __name__=='__main__': + main() diff --git a/broadview_collector/config/broadviewcollector.conf b/broadview_collector/config/broadviewcollector.conf new file mode 100644 index 0000000..81f5aa7 --- /dev/null +++ b/broadview_collector/config/broadviewcollector.conf @@ -0,0 +1,46 @@ +[DEFAULT] +# logging, make sure that the user under whom the server runs has permission +# to write to the directory + +log_file = broadview-collector.log +log_dir = /var/log/broadview-collector +debug = True + +[plugins] + +# comma separated list of plugin modules + +# publishers receive JSON encoded reports and write them somewhere + +# uncomment for monasca API + +#publishers: logpublisher, monascapublisher +publishers: logpublisher + +#searchpath: tmp + +# handlers map to broadview components, e.g., bst, packet trace + +handlers: bsthandler + +[logging] + +# this section sets prefs for the logging handler. + +file: /tmp/broadview-bstlogging.log + +[network] + +ip_address: 127.0.0.1 +port: 8082 + +# uncomment for monasca API + +#[monasca] +# +#username: mini-mon +#password: password +#project_name: mini-mon +#auth_url: http://127.0.0.1:35357/v3 +#endpoint: http://127.0.0.1:8070/v2.0 +#api_version: 2_0 diff --git a/broadview_collector/handlers/__init__.py b/broadview_collector/handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/broadview_collector/handlers/broadviewhandlerbase.py b/broadview_collector/handlers/broadviewhandlerbase.py new file mode 100644 index 0000000..c626163 --- /dev/null +++ b/broadview_collector/handlers/broadviewhandlerbase.py @@ -0,0 +1,30 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class BroadViewHandlerBase(object): + def __init__(self): + pass + + def handlePOST(self, path, ctype, length, data): + ''' + return a 2-tuple (data, handled) + + where data is understandable by a downstream serializer + (in the case of BST, this would be a bst_parser object), + and handled is a boolean, True if the POST was recognized, + and False if not. + + ''' + + raise NotImplementedError diff --git a/broadview_collector/handlers/bsthandler.py b/broadview_collector/handlers/bsthandler.py new file mode 100644 index 0000000..1e570c3 --- /dev/null +++ b/broadview_collector/handlers/bsthandler.py @@ -0,0 +1,33 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# 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 broadviewhandlerbase import BroadViewHandlerBase +from broadview_lib.bst.bst_parser import BSTParser + +class BroadViewHandler(BroadViewHandlerBase): + def __init__(self): + pass + + def handlePOST(self, path, ctype, length, data): + parser = BSTParser() + try: + handled = parser.process(data) + except: + handled = False + print handled + return (parser, handled) + + def __repr__(self): + return "BST Handler" + diff --git a/broadview_collector/plugins/__init__.py b/broadview_collector/plugins/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/broadview_collector/plugins/broadviewpublisherbase.py b/broadview_collector/plugins/broadviewpublisherbase.py new file mode 100644 index 0000000..629a3f1 --- /dev/null +++ b/broadview_collector/plugins/broadviewpublisherbase.py @@ -0,0 +1,21 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class BroadViewPublisherBase(object): + def __init__(self): + pass + + def publish(self, data): + raise NotImplementedError + diff --git a/broadview_collector/plugins/logpublisher.py b/broadview_collector/plugins/logpublisher.py new file mode 100644 index 0000000..13355fb --- /dev/null +++ b/broadview_collector/plugins/logpublisher.py @@ -0,0 +1,66 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# 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 broadviewpublisherbase import BroadViewPublisherBase + +# the Monasca serializer format is suitable for logging output, +# so use it. + +from broadview_collector.serializers.bst_to_monasca import BSTToMonasca +import json +from oslo_log import log +import ConfigParser + +LOG = log.getLogger(__name__) + +class BroadViewPublisher(BroadViewPublisherBase): + def readConfig(self): + try: + cfg = ConfigParser.ConfigParser() + cfg.read("/etc/broadviewcollector.conf") + self._logfile = cfg.get("logging", "file") + except: + LOG.info("log publisher: unable to process log file") + + try: + self._f = open(self._logfile, "w+") + except: + LOG.info("log publisher: unable to open log file {}".format(self.__logfile)) + + def __init__(self): + LOG.info("log publisher: init") + self._f = None + self._logfile = "/tmp/broadview-bstlogging.log" + self.readConfig() + + def __del__(self): + if self._f: + self._f.close() + + def publish(self, data): + LOG.info("log publisher: publish") + code = 200 + success, sdata = BSTToMonasca().serialize(data) + sdata = json.loads(sdata) + if success: + for x in sdata: + print >>self._f, json.dumps(x) + self._f.flush() + else: + code = 500 + return code + + def __repr__(self): + return "BroadView Log Publisher" + diff --git a/broadview_collector/plugins/monascapublisher.py b/broadview_collector/plugins/monascapublisher.py new file mode 100644 index 0000000..df51dbd --- /dev/null +++ b/broadview_collector/plugins/monascapublisher.py @@ -0,0 +1,83 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# 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 broadviewpublisherbase import BroadViewPublisherBase +from monascaclient import client +import monascaclient.exc as exc +from broadview_collector.serializers.bst_to_monasca import BSTToMonasca +import json +import ConfigParser + +from oslo_log import log + +LOG = log.getLogger(__name__) + +class BroadViewPublisher(BroadViewPublisherBase): + + def readConfig(self): + try: + bvcfg = ConfigParser.ConfigParser() + bvcfg.read("/etc/broadviewcollector.conf") + self._endpoint = bvcfg.get("monasca", "endpoint") + self._username = bvcfg.get("monasca", "username") + self._password = bvcfg.get("monasca", "password") + self._project_name = bvcfg.get("monasca", "project_name") + self._auth_url = bvcfg.get("monasca", "auth_url") + self._endpoint = bvcfg.get("monasca", "endpoint") + self._api_version = bvcfg.get("monasca", "api_version") + except: + LOG.error("BroadViewPublisher: unable to read configuration") + + def __init__(self): + + self.readConfig() + + try: + self._auth_kwargs = { + 'username': self._username, + 'password': self._password, + 'auth_url': self._auth_url, + 'project_name': self._project_name, + } + + + self._monasca_client = client.Client(self._api_version, \ + self._endpoint, \ + **self._auth_kwargs) + except: + LOG.error("BroadViewPublisher: failed to parse config") + self._monasca_client = None + + def publish(self, data): + code = 500 + if self._monasca_client: + code = 200 + success, sdata = BSTToMonasca().serialize(data) + sdata = json.loads(sdata) + if success: + for x in sdata: + try: + resp = self._monasca_client.metrics.create(**x) + if not resp.status_code == 200 and not resp.status_code == 204: + code = resp.status_code + break + except exc.HTTPException as he: + LOG.error('HTTPException code=%s message=%s' % (he.code, he.message)) + code = he.code + break + return code + + def __repr__(self): + return "BroadView Monasca Publisher {_endpoint} {_api_version}".format(**__dict__(self)) + diff --git a/broadview_collector/serializers/__init__.py b/broadview_collector/serializers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/broadview_collector/serializers/broadviewserializerbase.py b/broadview_collector/serializers/broadviewserializerbase.py new file mode 100644 index 0000000..9a8efce --- /dev/null +++ b/broadview_collector/serializers/broadviewserializerbase.py @@ -0,0 +1,31 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class BroadViewSerializerBase(object): + def __init__(self): + pass + + def serialize(self, data): + ''' + return a 2-tuple (ret, jsonret) + + where coderet is True for success and False for failure, + jsonret is a json string that holds the serialized data. + + For example, on success: + + return (True, "{\"foo\": \"bar\"}") + ''' + + raise NotImplementedError diff --git a/broadview_collector/serializers/bst_to_monasca.py b/broadview_collector/serializers/bst_to_monasca.py new file mode 100644 index 0000000..2bb54a7 --- /dev/null +++ b/broadview_collector/serializers/bst_to_monasca.py @@ -0,0 +1,2415 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# 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 broadviewserializerbase import BroadViewSerializerBase +from broadview_lib.bst.bst_parser import BSTParser, ReportTypes +import json +import unittest +import datetime +import time + +class BSTToMonasca(BroadViewSerializerBase): + def __init__(self): + pass + + def __serializeToJSON(self, report, data): + ret = [] + timestamp = time.mktime(data.getTimestamp()) * 1000 + asic = data.getASICId() + x = data.getDeviceData() + + if x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["value"] = x.getValue() + ret.append(m) + + d = data.getIngressPortPriorityGroup() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["port"] = y.getPort() + m["dimensions"]["priority-group"] = y.getPriorityGroup() + m["dimensions"]["stat"] = "um-share-buffer-count" + m["value"] = y.getUmShareBufferCount() + ret.append(m) + + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["port"] = y.getPort() + m["dimensions"]["priority-group"] = y.getPriorityGroup() + m["dimensions"]["stat"] = "um-headroom-buffer-count" + m["value"] = y.getUmHeadroomBufferCount() + ret.append(m) + + d = data.getIngressPortServicePool() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["port"] = y.getPort() + m["dimensions"]["service-pool"] = y.getServicePool() + m["dimensions"]["stat"] = "um-share-buffer-count" + m["value"] = y.getUmShareBufferCount() + ret.append(m) + + d = data.getIngressServicePool() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["service-pool"] = y.getServicePool() + m["dimensions"]["stat"] = "um-share-buffer-count" + m["value"] = y.getUmShareBufferCount() + ret.append(m) + + d = data.getEgressCPUQueue() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["queue"] = y.getQueue() + m["dimensions"]["stat"] = "cpu-buffer-count" + m["value"] = y.getCPUBufferCount() + ret.append(m) + + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["queue"] = y.getQueue() + m["dimensions"]["stat"] = "cpu-queue-entries" + m["value"] = y.getCPUQueueEntries() + ret.append(m) + + d = data.getEgressMcQueue() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["port"] = y.getPort() + m["dimensions"]["queue"] = y.getQueue() + m["dimensions"]["stat"] = "mc-buffer-count" + m["value"] = y.getMCBufferCount() + ret.append(m) + + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["port"] = y.getPort() + m["dimensions"]["queue"] = y.getQueue() + m["dimensions"]["stat"] = "mc-queue-entries" + m["value"] = y.getMCQueueEntries() + ret.append(m) + + d = data.getEgressPortServicePool() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["port"] = y.getPort() + m["dimensions"]["service-pool"] = y.getServicePool() + m["dimensions"]["stat"] = "um-share-buffer-count" + m["value"] = y.getUmShareBufferCount() + ret.append(m) + + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["port"] = y.getPort() + m["dimensions"]["service-pool"] = y.getServicePool() + m["dimensions"]["stat"] = "mc-share-buffer-count" + m["value"] = y.getMCShareBufferCount() + ret.append(m) + + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["port"] = y.getPort() + m["dimensions"]["service-pool"] = y.getServicePool() + m["dimensions"]["stat"] = "mc-share-queue-entries" + m["value"] = y.getMCShareQueueEntries() + ret.append(m) + + d = data.getEgressRQEQueue() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["queue"] = y.getQueue() + m["dimensions"]["stat"] = "rqe-buffer-count" + m["value"] = y.getRQEBufferCount() + ret.append(m) + + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["queue"] = y.getQueue() + m["dimensions"]["stat"] = "rqe-queue-entries" + m["value"] = y.getRQEQueueEntries() + ret.append(m) + + d = data.getEgressServicePool() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["service-pool"] = y.getServicePool() + m["dimensions"]["stat"] = "um-share-buffer-count" + m["value"] = y.getUmShareBufferCount() + ret.append(m) + + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["service-pool"] = y.getServicePool() + m["dimensions"]["stat"] = "mc-share-buffer-count" + m["value"] = y.getMCShareBufferCount() + ret.append(m) + + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["service-pool"] = y.getServicePool() + m["dimensions"]["stat"] = "mc-share-queue-entries" + m["value"] = y.getMCShareQueueEntries() + ret.append(m) + + d = data.getEgressUcQueue() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["port"] = y.getPort() + m["dimensions"]["queue"] = y.getQueue() + m["dimensions"]["stat"] = "uc-queue-buffer-count" + m["value"] = y.getUcQueueBufferCount() + ret.append(m) + + d = data.getEgressUcQueueGroup() + for x in d: + for y in x: + m = {} + m["name"] = "broadview.bst." + repr(x) + m["timestamp"] = timestamp + m["dimensions"] = {} + m["dimensions"]["asic-id"] = asic + m["dimensions"]["queue-group"] = y.getQueueGroup() + m["dimensions"]["stat"] = "uc-buffer-count" + m["value"] = y.getUcBufferCount() + ret.append(m) + + return json.dumps(ret) + + def _toReport(self, data): + return self.__serializeToJSON("bst-report", data) + + def _toTrigger(self, data): + return self.__serializeToJSON("bst-trigger", data) + + def _toThreshold(self, data): + return self.__serializeToJSON("bst-thresholds", data) + + def serialize(self, data): + # serialize a parsed BST report to Monasca metrics + ret = (False, None) + + rpt = data.getReportType() + + s = None + if rpt == ReportTypes.Report: + s = self._toReport(data) + elif rpt == ReportTypes.Trigger: + s = self._toTrigger(data) + elif rpt == ReportTypes.Threshold: + s = self._toThreshold(data) + + if s: + ret = (True, s) + + return ret + + def __repr__(self): + return "BST To Monasca Serializer" + +class TestSerializer(unittest.TestCase): + + def setUp(self): + self.bst_report1 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "device", + "data": 46 + }] + } + + self.bst_report2 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "ingress-port-priority-group", + "data": [{ + "port": "2", + "data": [[5, 45500, 44450]] + }, { + "port": "3", + "data": [[6, 25500, 24450]] + }] + }] + } + + self.bst_report3 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "ingress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 324]] + }, { + "port": "3", + "data": [[6, 366]] + }] + }] + } + + self.bst_report4 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "ingress-service-pool", + "data": [[1, 3240], [2, 3660]] + }] + } + + self.bst_report5 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "egress-cpu-queue", + "data": [[3, 4566, 0]] + }] + } + + self.bst_report6 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "egress-mc-queue", + "data": [[1, "1", 34, 89], [2, "4", 1244, 0], [3, "5", 0, +3]] + }] + } + + self.bst_report7 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "egress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 0, 324, 0]] + }, { + "port": "3", + "data": [[6, 0, 366, 0]] + }] + }] + } + + self.bst_report8 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "egress-rqe-queue", + "data": [[2, 3333, 4444], [5, 25, 45]] + }] + } + + self.bst_report9 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "egress-service-pool", + "data": [[2, 0, 0, 3240], [3, 3660, 0, 0]] + }] + } + + self.bst_report10 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "egress-uc-queue", + "data": [[6, "0", 1111]] + }] + } + + self.bst_report11 = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:15:04 ", + "report": [ + { + "realm": "egress-uc-queue-group", + "data": [[6, 2222]] + }] + } + + + self.trigger1 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "device", + "data": 46 + }] + } + + self.trigger2 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "ingress-port-priority-group", + + "data": [{ + "port": "2", + "data": [[5, 45500, 44450]] + }, { + "port": "3", + "data": [[6, 25500, 24450]] + }] + }] + } + + self.trigger3 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "ingress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 324]] + }, { + "port": "3", + "data": [[6, 366]] + }] + }] + } + + self.trigger4 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "ingress-service-pool", + "data": [[1, 3240], [2, 3660]] + }] + } + + self.trigger5 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "egress-cpu-queue", + "data": [[3, 4566, 0]] + }] + } + + self.trigger6 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "egress-mc-queue", + "data": [[1, "1", 34, 89], [2, "4", 1244, 0], [3, "5", 0, +3]] + }] + } + + self.trigger7 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "egress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 0, 324, 0]] + }, { + "port": "3", + "data": [[6, 0, 366, 0]] + }] + }] + } + + self.trigger8 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "egress-rqe-queue", + "data": [[2, 3333, 4444], [5, 25, 45]] + }] + } + + self.trigger9 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "egress-service-pool", + "data": [[2, 0, 0, 3240], [3, 3660, 0, 0]] + }] + } + + self.trigger10 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "egress-uc-queue", + "data": [[6, "0", 1111]] + }] + } + + self.trigger11 = { + "jsonrpc": "2.0", + "method": "trigger-report", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-18 - 00:13:08 ", + "realm": "ingress-port-priority-group", + "counter": "um-share-buffer-count", + "port": "2", + "priority-group": "5", + "report": [ + { + "realm": "egress-uc-queue-group", + "data": [[6, 2222]] + }] + } + + + self.thresholds1 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "device", + "data": 46 + }] + } + + self.thresholds2 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "ingress-port-priority-group", + "data": [{ + "port": "2", + "data": [[5, 45500, 44450]] + }, { + "port": "3", + "data": [[6, 25500, 24450]] + }] + }] + } + + self.thresholds3 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "ingress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 324]] + }, { + "port": "3", + "data": [[6, 366]] + }] + }] + } + + self.thresholds4 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "ingress-service-pool", + "data": [[1, 3240], [2, 3660]] + }] + } + + self.thresholds5 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "egress-cpu-queue", + "data": [[3, 4566, 0]] + }] + } + + self.thresholds6 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "egress-mc-queue", + "data": [[1, "1", 34, 89], [2, "4", 1244, 0], [3, "5", 0, 3]] + }] + } + + self.thresholds7 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "egress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 0, 324, 0]] + }, { + "port": "3", + "data": [[6, 0, 366, 0]] + }] + }] + } + + self.thresholds8 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "egress-rqe-queue", + "data": [[2, 3333, 4444], [5, 25, 45]] + }] + } + + self.thresholds9 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "egress-service-pool", + "data": [[2, 0, 0, 3240], [3, 3660, 0, 0]] + }] + } + + self.thresholds10 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "egress-uc-queue", + "data": [[6, "0", 1111]] + }] + } + + self.thresholds11 = { + "jsonrpc": "2.0", + "method": "get-bst-thresholds", + "asic-id": "20", + "version": "1", + "time-stamp": "2014-11-14 - 00:15:04 ", + "report": [ + { + "realm": "egress-uc-queue-group", + "data": [[6, 2222]] + }] + } + + + def test_bst_report1(self): + rep = BSTParser() + rep.process(self.bst_report1) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 1) + data = data[0] + self.assertTrue("timestamp" in data) + data["timestamp"] = data["timestamp"] / 1000 + self.assertTrue("name" in data) + self.assertTrue("value" in data) + self.assertTrue("dimensions" in data) + t1 = datetime.datetime.fromtimestamp(int(data["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = self.bst_report1["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(data["name"], "broadview.bst.device") + self.assertEqual(data["value"], 46) + dim = data["dimensions"] + self.assertTrue("asic-id" in dim) + self.assertEqual(dim["asic-id"], self.bst_report1["asic-id"]) + + + def test_bst_report2(self): + rep = BSTParser() + rep.process(self.bst_report2) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 4) + i = 0 + y = self.bst_report2 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.ingress-port-priority-group") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("priority-group" in dim) + self.assertTrue("port" in dim) + if dim["port"] == "2": + self.assertEqual(dim["priority-group"], 5) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 45500) + elif dim["stat"] == "um-headroom-buffer-count": + self.assertTrue(x["value"] == 44450) + else: + self.assertTrue(dim["stat"] == True) + elif dim["port"] == "3": + self.assertEqual(dim["priority-group"], 6) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 25500) + elif dim["stat"] == "um-headroom-buffer-count": + self.assertTrue(x["value"] == 24450) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["port"] == True) + + + def test_bst_report3(self): + rep = BSTParser() + rep.process(self.bst_report3) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 2) + i = 0 + y = self.bst_report3 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + x["timestamp"] = x["timestamp"] / 1000 + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.ingress-port-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + self.assertTrue("port" in dim) + if dim["port"] == "2": + self.assertEqual(dim["service-pool"], 5) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 324) + else: + self.assertTrue(dim["stat"] == True) + elif dim["port"] == "3": + self.assertEqual(dim["service-pool"], 6) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 366) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["port"] == True) + + def test_bst_report4(self): + rep = BSTParser() + rep.process(self.bst_report4) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 2) + i = 0 + y = self.bst_report4 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.ingress-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + if dim["service-pool"] == 1: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 3240) + else: + self.assertTrue(dim["stat"] == True) + elif dim["service-pool"] == 2: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 3660) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["service-pool"] == True) + + + def test_bst_report5(self): + rep = BSTParser() + rep.process(self.bst_report5) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 2) + i = 0 + y = self.bst_report5 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-cpu-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + if dim["queue"] == 3: + if dim["stat"] == "cpu-buffer-count": + self.assertTrue(x["value"] == 4566) + elif dim["stat"] == "cpu-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_bst_report6(self): + rep = BSTParser() + rep.process(self.bst_report6) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 6) + i = 0 + y = self.bst_report6 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-mc-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + self.assertTrue("port" in dim) + if dim["queue"] == 1: + self.assertTrue(dim["port"] == "1") + if dim["stat"] == "mc-buffer-count": + self.assertTrue(x["value"] == 34) + elif dim["stat"] == "mc-queue-entries": + self.assertTrue(x["value"] == 89) + else: + self.assertTrue(dim["stat"] == True) + elif dim["queue"] == 2: + self.assertTrue(dim["port"] == "4") + if dim["stat"] == "mc-buffer-count": + self.assertTrue(x["value"] == 1244) + elif dim["stat"] == "mc-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + elif dim["queue"] == 3: + self.assertTrue(dim["port"] == "5") + if dim["stat"] == "mc-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-queue-entries": + self.assertTrue(x["value"] == 3) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_bst_report7(self): + rep = BSTParser() + rep.process(self.bst_report7) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 6) + i = 0 + y = self.bst_report7 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-port-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + self.assertTrue("port" in dim) + if dim["service-pool"] == 5: + self.assertTrue(dim["port"] == "2") + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 324) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + elif dim["service-pool"] == 6: + self.assertTrue(dim["port"] == "3") + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 366) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["service-pool"] == True) + + def test_bst_report8(self): + rep = BSTParser() + rep.process(self.bst_report8) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 4) + i = 0 + y = self.bst_report8 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-rqe-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + if dim["queue"] == 2: + if dim["stat"] == "rqe-buffer-count": + self.assertTrue(x["value"] == 3333) + elif dim["stat"] == "rqe-queue-entries": + self.assertTrue(x["value"] == 4444) + else: + self.assertTrue(dim["stat"] == True) + elif dim["queue"] == 5: + if dim["stat"] == "rqe-buffer-count": + self.assertTrue(x["value"] == 25) + elif dim["stat"] == "rqe-queue-entries": + self.assertTrue(x["value"] == 45) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_bst_report9(self): + rep = BSTParser() + rep.process(self.bst_report9) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 6) + i = 0 + y = self.bst_report9 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + if dim["service-pool"] == 2: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 3240) + else: + self.assertTrue(dim["stat"] == True) + elif dim["service-pool"] == 3: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 3660) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["service-pool"] == True) + + def test_bst_report10(self): + rep = BSTParser() + rep.process(self.bst_report10) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 1) + i = 0 + y = self.bst_report10 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-uc-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + self.assertTrue("port" in dim) + if dim["queue"] == 6: + self.assertEqual(dim["port"], "0") + if dim["stat"] == "uc-queue-buffer-count": + self.assertTrue(x["value"] == 1111) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_bst_report11(self): + rep = BSTParser() + rep.process(self.bst_report11) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 1) + i = 0 + y = self.bst_report11 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-uc-queue-group") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue-group" in dim) + if dim["queue-group"] == 6: + if dim["stat"] == "uc-buffer-count": + self.assertTrue(x["value"] == 2222) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue-group"] == True) + + def test_trigger1(self): + rep = BSTParser() + rep.process(self.trigger1) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 1) + data = data[0] + self.assertTrue("timestamp" in data) + data["timestamp"] = data["timestamp"] / 1000 + self.assertTrue("name" in data) + self.assertTrue("value" in data) + self.assertTrue("dimensions" in data) + t1 = datetime.datetime.fromtimestamp(int(data["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = self.trigger1["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(data["name"], "broadview.bst.device") + self.assertEqual(data["value"], 46) + dim = data["dimensions"] + self.assertTrue("asic-id" in dim) + self.assertEqual(dim["asic-id"], self.trigger1["asic-id"]) + + + def test_trigger2(self): + rep = BSTParser() + rep.process(self.trigger2) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 4) + i = 0 + y = self.trigger2 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.ingress-port-priority-group") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("priority-group" in dim) + self.assertTrue("port" in dim) + if dim["port"] == "2": + self.assertEqual(dim["priority-group"], 5) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 45500) + elif dim["stat"] == "um-headroom-buffer-count": + self.assertTrue(x["value"] == 44450) + else: + self.assertTrue(dim["stat"] == True) + elif dim["port"] == "3": + self.assertEqual(dim["priority-group"], 6) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 25500) + elif dim["stat"] == "um-headroom-buffer-count": + self.assertTrue(x["value"] == 24450) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["port"] == True) + + + def test_trigger3(self): + rep = BSTParser() + rep.process(self.trigger3) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 2) + i = 0 + y = self.trigger3 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.ingress-port-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + self.assertTrue("port" in dim) + if dim["port"] == "2": + self.assertEqual(dim["service-pool"], 5) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 324) + else: + self.assertTrue(dim["stat"] == True) + elif dim["port"] == "3": + self.assertEqual(dim["service-pool"], 6) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 366) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["port"] == True) + + def test_trigger4(self): + rep = BSTParser() + rep.process(self.trigger4) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 2) + i = 0 + y = self.trigger4 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.ingress-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + if dim["service-pool"] == 1: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 3240) + else: + self.assertTrue(dim["stat"] == True) + elif dim["service-pool"] == 2: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 3660) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["service-pool"] == True) + + + def test_trigger5(self): + rep = BSTParser() + rep.process(self.trigger5) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 2) + i = 0 + y = self.trigger5 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-cpu-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + if dim["queue"] == 3: + if dim["stat"] == "cpu-buffer-count": + self.assertTrue(x["value"] == 4566) + elif dim["stat"] == "cpu-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_trigger6(self): + rep = BSTParser() + rep.process(self.trigger6) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 6) + i = 0 + y = self.trigger6 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-mc-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + self.assertTrue("port" in dim) + if dim["queue"] == 1: + self.assertTrue(dim["port"] == "1") + if dim["stat"] == "mc-buffer-count": + self.assertTrue(x["value"] == 34) + elif dim["stat"] == "mc-queue-entries": + self.assertTrue(x["value"] == 89) + else: + self.assertTrue(dim["stat"] == True) + elif dim["queue"] == 2: + self.assertTrue(dim["port"] == "4") + if dim["stat"] == "mc-buffer-count": + self.assertTrue(x["value"] == 1244) + elif dim["stat"] == "mc-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + elif dim["queue"] == 3: + self.assertTrue(dim["port"] == "5") + if dim["stat"] == "mc-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-queue-entries": + self.assertTrue(x["value"] == 3) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_trigger7(self): + rep = BSTParser() + rep.process(self.trigger7) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 6) + i = 0 + y = self.trigger7 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-port-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + self.assertTrue("port" in dim) + if dim["service-pool"] == 5: + self.assertTrue(dim["port"] == "2") + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 324) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + elif dim["service-pool"] == 6: + self.assertTrue(dim["port"] == "3") + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 366) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["service-pool"] == True) + + def test_trigger8(self): + rep = BSTParser() + rep.process(self.trigger8) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 4) + i = 0 + y = self.trigger8 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-rqe-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + if dim["queue"] == 2: + if dim["stat"] == "rqe-buffer-count": + self.assertTrue(x["value"] == 3333) + elif dim["stat"] == "rqe-queue-entries": + self.assertTrue(x["value"] == 4444) + else: + self.assertTrue(dim["stat"] == True) + elif dim["queue"] == 5: + if dim["stat"] == "rqe-buffer-count": + self.assertTrue(x["value"] == 25) + elif dim["stat"] == "rqe-queue-entries": + self.assertTrue(x["value"] == 45) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_trigger9(self): + rep = BSTParser() + rep.process(self.trigger9) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 6) + i = 0 + y = self.trigger9 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + if dim["service-pool"] == 2: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 3240) + else: + self.assertTrue(dim["stat"] == True) + elif dim["service-pool"] == 3: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 3660) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["service-pool"] == True) + + def test_trigger10(self): + rep = BSTParser() + rep.process(self.trigger10) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 1) + i = 0 + y = self.trigger10 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-uc-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + self.assertTrue("port" in dim) + if dim["queue"] == 6: + self.assertEqual(dim["port"], "0") + if dim["stat"] == "uc-queue-buffer-count": + self.assertTrue(x["value"] == 1111) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_trigger11(self): + rep = BSTParser() + rep.process(self.trigger11) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 1) + i = 0 + y = self.trigger11 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-uc-queue-group") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue-group" in dim) + if dim["queue-group"] == 6: + if dim["stat"] == "uc-buffer-count": + self.assertTrue(x["value"] == 2222) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue-group"] == True) + + def test_thresholds1(self): + rep = BSTParser() + rep.process(self.thresholds1) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 1) + data = data[0] + self.assertTrue("timestamp" in data) + data["timestamp"] = data["timestamp"] / 1000 + self.assertTrue("name" in data) + self.assertTrue("value" in data) + self.assertTrue("dimensions" in data) + t1 = datetime.datetime.fromtimestamp(int(data["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = self.thresholds1["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(data["name"], "broadview.bst.device") + self.assertEqual(data["value"], 46) + dim = data["dimensions"] + self.assertTrue("asic-id" in dim) + self.assertEqual(dim["asic-id"], self.thresholds1["asic-id"]) + + + def test_thresholds2(self): + rep = BSTParser() + rep.process(self.thresholds2) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 4) + i = 0 + y = self.thresholds2 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.ingress-port-priority-group") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("priority-group" in dim) + self.assertTrue("port" in dim) + if dim["port"] == "2": + self.assertEqual(dim["priority-group"], 5) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 45500) + elif dim["stat"] == "um-headroom-buffer-count": + self.assertTrue(x["value"] == 44450) + else: + self.assertTrue(dim["stat"] == True) + elif dim["port"] == "3": + self.assertEqual(dim["priority-group"], 6) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 25500) + elif dim["stat"] == "um-headroom-buffer-count": + self.assertTrue(x["value"] == 24450) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["port"] == True) + + + def test_thresholds3(self): + rep = BSTParser() + rep.process(self.thresholds3) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 2) + i = 0 + y = self.thresholds3 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.ingress-port-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + self.assertTrue("port" in dim) + if dim["port"] == "2": + self.assertEqual(dim["service-pool"], 5) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 324) + else: + self.assertTrue(dim["stat"] == True) + elif dim["port"] == "3": + self.assertEqual(dim["service-pool"], 6) + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 366) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["port"] == True) + + def test_thresholds4(self): + rep = BSTParser() + rep.process(self.thresholds4) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 2) + i = 0 + y = self.thresholds4 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.ingress-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + if dim["service-pool"] == 1: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 3240) + else: + self.assertTrue(dim["stat"] == True) + elif dim["service-pool"] == 2: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 3660) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["service-pool"] == True) + + + def test_thresholds5(self): + rep = BSTParser() + rep.process(self.thresholds5) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 2) + i = 0 + y = self.thresholds5 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-cpu-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + if dim["queue"] == 3: + if dim["stat"] == "cpu-buffer-count": + self.assertTrue(x["value"] == 4566) + elif dim["stat"] == "cpu-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_thresholds6(self): + rep = BSTParser() + rep.process(self.thresholds6) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 6) + i = 0 + y = self.thresholds6 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-mc-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + self.assertTrue("port" in dim) + if dim["queue"] == 1: + self.assertTrue(dim["port"] == "1") + if dim["stat"] == "mc-buffer-count": + self.assertTrue(x["value"] == 34) + elif dim["stat"] == "mc-queue-entries": + self.assertTrue(x["value"] == 89) + else: + self.assertTrue(dim["stat"] == True) + elif dim["queue"] == 2: + self.assertTrue(dim["port"] == "4") + if dim["stat"] == "mc-buffer-count": + self.assertTrue(x["value"] == 1244) + elif dim["stat"] == "mc-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + elif dim["queue"] == 3: + self.assertTrue(dim["port"] == "5") + if dim["stat"] == "mc-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-queue-entries": + self.assertTrue(x["value"] == 3) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_thresholds7(self): + rep = BSTParser() + rep.process(self.thresholds7) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 6) + i = 0 + y = self.thresholds7 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-port-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + self.assertTrue("port" in dim) + if dim["service-pool"] == 5: + self.assertTrue(dim["port"] == "2") + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 324) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + elif dim["service-pool"] == 6: + self.assertTrue(dim["port"] == "3") + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 366) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["service-pool"] == True) + + def test_thresholds8(self): + rep = BSTParser() + rep.process(self.thresholds8) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 4) + i = 0 + y = self.thresholds8 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-rqe-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + if dim["queue"] == 2: + if dim["stat"] == "rqe-buffer-count": + self.assertTrue(x["value"] == 3333) + elif dim["stat"] == "rqe-queue-entries": + self.assertTrue(x["value"] == 4444) + else: + self.assertTrue(dim["stat"] == True) + elif dim["queue"] == 5: + if dim["stat"] == "rqe-buffer-count": + self.assertTrue(x["value"] == 25) + elif dim["stat"] == "rqe-queue-entries": + self.assertTrue(x["value"] == 45) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_thresholds9(self): + rep = BSTParser() + rep.process(self.thresholds9) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 6) + i = 0 + y = self.thresholds9 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-service-pool") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("service-pool" in dim) + if dim["service-pool"] == 2: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 3240) + else: + self.assertTrue(dim["stat"] == True) + elif dim["service-pool"] == 3: + if dim["stat"] == "um-share-buffer-count": + self.assertTrue(x["value"] == 3660) + elif dim["stat"] == "mc-share-buffer-count": + self.assertTrue(x["value"] == 0) + elif dim["stat"] == "mc-share-queue-entries": + self.assertTrue(x["value"] == 0) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["service-pool"] == True) + + def test_thresholds10(self): + rep = BSTParser() + rep.process(self.thresholds10) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 1) + i = 0 + y = self.thresholds10 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-uc-queue") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue" in dim) + self.assertTrue("port" in dim) + if dim["queue"] == 6: + self.assertEqual(dim["port"], "0") + if dim["stat"] == "uc-queue-buffer-count": + self.assertTrue(x["value"] == 1111) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue"] == True) + + def test_thresholds11(self): + rep = BSTParser() + rep.process(self.thresholds11) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + self.assertTrue(len(data) == 1) + i = 0 + y = self.thresholds11 + for x in data: + i = i + 1 + self.assertTrue("timestamp" in x) + x["timestamp"] = x["timestamp"] / 1000 + self.assertTrue("name" in x) + self.assertTrue("value" in x) + self.assertTrue("dimensions" in x) + t1 = datetime.datetime.fromtimestamp(int(x["timestamp"])) + t1 = t1.strftime("%Y-%m-%d - %H:%M:%S") + t2 = y["time-stamp"].strip() + self.assertEqual(t1, t2) + self.assertEqual(x["name"], "broadview.bst.egress-uc-queue-group") + dim = x["dimensions"] + self.assertEqual(dim["asic-id"], y["asic-id"]) + self.assertTrue("stat" in dim) + self.assertTrue("queue-group" in dim) + if dim["queue-group"] == 6: + if dim["stat"] == "uc-buffer-count": + self.assertTrue(x["value"] == 2222) + else: + self.assertTrue(dim["stat"] == True) + else: + self.assertTrue(dim["queue-group"] == True) + ''' + + def test_bst_trigger1(self): + rep = BSTParser() + rep.process(self.trigger1) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger2(self): + rep = BSTParser() + rep.process(self.trigger2) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger3(self): + rep = BSTParser() + rep.process(self.trigger3) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger4(self): + rep = BSTParser() + rep.process(self.trigger4) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger5(self): + rep = BSTParser() + rep.process(self.trigger5) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger6(self): + rep = BSTParser() + rep.process(self.trigger6) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger7(self): + rep = BSTParser() + rep.process(self.trigger7) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger8(self): + rep = BSTParser() + rep.process(self.trigger8) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger9(self): + rep = BSTParser() + rep.process(self.trigger9) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger10(self): + rep = BSTParser() + rep.process(self.trigger10) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_trigger11(self): + rep = BSTParser() + rep.process(self.trigger11) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds1(self): + rep = BSTParser() + rep.process(self.thresholds1) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds2(self): + rep = BSTParser() + rep.process(self.thresholds2) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds3(self): + rep = BSTParser() + rep.process(self.thresholds3) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds4(self): + rep = BSTParser() + rep.process(self.thresholds4) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds5(self): + rep = BSTParser() + rep.process(self.thresholds5) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds6(self): + rep = BSTParser() + rep.process(self.thresholds6) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds7(self): + rep = BSTParser() + rep.process(self.thresholds7) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds8(self): + rep = BSTParser() + rep.process(self.thresholds8) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds9(self): + rep = BSTParser() + rep.process(self.thresholds9) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds10(self): + rep = BSTParser() + rep.process(self.thresholds10) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + + def test_bst_thresholds11(self): + rep = BSTParser() + rep.process(self.thresholds11) + serializer = BSTToMonasca() + ret = serializer.serialize(rep) + self.assertEqual(ret[0], True) + data = json.loads(ret[1]) + print data + print + ''' + +if __name__ == "__main__": + unittest.main() + diff --git a/broadview_collector/tests/__init__.py b/broadview_collector/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/broadview_collector/tests/base.py b/broadview_collector/tests/base.py new file mode 100644 index 0000000..1c30cdb --- /dev/null +++ b/broadview_collector/tests/base.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +# Copyright 2010-2011 OpenStack Foundation +# 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. + +from oslotest import base + + +class TestCase(base.BaseTestCase): + + """Test case base class for all unit tests.""" diff --git a/broadview_collector/tests/bst_report.py b/broadview_collector/tests/bst_report.py new file mode 100644 index 0000000..874a54d --- /dev/null +++ b/broadview_collector/tests/bst_report.py @@ -0,0 +1,318 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# 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 json +import requests +import datetime +import unittest + +# Change these to the host and port the collector is listening on + +host = "10.14.245.57" +port = 8082 + +''' +To see list of metrics in Monasca after this test is run (assuming +the Monasca plugin is enabled (see the README.md file)): + +$ monasca --os-username mini-mon --os-password password metric-list | grep broadview + +To view an individual statistic, use metric-statistics, as this example: + +#monasca --os-username mini-mon --os-password password metric-statistics --dimensions "stat=um-share-buffer-count, service-pool=6, port=3" broadview.bst.ingress-port-service-pool MIN "2016-03-01T00:00:00Z" + +This program will display the UTC time associated with the metric, which +can be used to determine an appropriate time argument for the +metric-statistics command. +''' + +class TestBSTCollector(unittest.TestCase): + + def setUp(self): + # convert datetime string to monasca timestamp + + print("{} UTC".format(datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"))) + d = str(datetime.datetime.now()).split(" ") + t = d[1].split(".")[0] + d = "{} - {}".format(d[0], t) + print("Setting timestamp to {}".format(d)) + self.bst_report = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": d, + "report": [ + { + "realm": "device", + "data": 46 + }, { + "realm": "ingress-port-priority-group", + "data": [{ + "port": "2", + "data": [[5, 45500, 44450]] + }, { + "port": "3", + "data": [[6, 25500, 24450]] + }] + }, { + "realm": "ingress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 324]] + }, { + "port": "3", + "data": [[6, 366]] + }] + }, { + "realm": "ingress-service-pool", + "data": [[1, 3240], [2, 3660]] + }, { + "realm": "egress-cpu-queue", + "data": [[3, 4566, 0]] + }, { + "realm": "egress-mc-queue", + "data": [[1, "1", 34, 89], [2, "4", 1244, 0], [3, "5", 0, 3]] + + }, { + "realm": "egress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 0, 324, 0]] + }, { + "port": "3", + "data": [[6, 0, 366, 0]] + }] + }, { + "realm": "egress-rqe-queue", + "data": [[2, 3333, 4444], [5, 25, 45]] + }, { + "realm": "egress-service-pool", + "data": [[2, 0, 0, 3240], [3, 3660, 0, 0]] + }, { + "realm": "egress-uc-queue", + "data": [[6, "0", 1111]] + }, { + "realm": "egress-uc-queue-group", + "data": [[6, 2222]] + }] + } + + self.bst_report_unknown_method = { + "jsonrpc": "2.0", + "method": "get-foo-report", + "asic-id": "20", + "version": "1", + "time-stamp": d, + "report": [ + { + "realm": "device", + "data": 46 + }, { + "realm": "ingress-port-priority-group", + "data": [{ + "port": "2", + "data": [[5, 45500, 44450]] + }, { + "port": "3", + "data": [[6, 25500, 24450]] + }] + }, { + "realm": "ingress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 324]] + }, { + "port": "3", + "data": [[6, 366]] + }] + }, { + "realm": "ingress-service-pool", + "data": [[1, 3240], [2, 3660]] + }, { + "realm": "egress-cpu-queue", + "data": [[3, 4566, 0]] + }, { + "realm": "egress-mc-queue", + "data": [[1, "1", 34, 89], [2, "4", 1244, 0], [3, "5", 0, 3]] + + }, { + "realm": "egress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 0, 324, 0]] + }, { + "port": "3", + "data": [[6, 0, 366, 0]] + }] + }, { + "realm": "egress-rqe-queue", + "data": [[2, 3333, 4444], [5, 25, 45]] + }, { + "realm": "egress-service-pool", + "data": [[2, 0, 0, 3240], [3, 3660, 0, 0]] + }, { + "realm": "egress-uc-queue", + "data": [[6, "0", 1111]] + }, { + "realm": "egress-uc-queue-group", + "data": [[6, 2222]] + }] + } + + self.bst_report_unknown_realm = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": d, + "report": [ + { + "realm": "mustard", + "data": 46 + }] + } + + + self.bst_report_bad_timestamp = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": "xxxxxx ", + "report": [ + { + "realm": "device", + "data": 46 + }, { + "realm": "ingress-port-priority-group", + "data": [{ + "port": "2", + "data": [[5, 45500, 44450]] + }, { + "port": "3", + "data": [[6, 25500, 24450]] + }] + }, { + "realm": "ingress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 324]] + }, { + "port": "3", + "data": [[6, 366]] + }] + }, { + "realm": "ingress-service-pool", + "data": [[1, 3240], [2, 3660]] + }, { + "realm": "egress-cpu-queue", + "data": [[3, 4566, 0]] + }, { + "realm": "egress-mc-queue", + "data": [[1, "1", 34, 89], [2, "4", 1244, 0], [3, "5", 0, 3]] + + }, { + "realm": "egress-port-service-pool", + "data": [{ + "port": "2", + "data": [[5, 0, 324, 0]] + }, { + "port": "3", + "data": [[6, 0, 366, 0]] + }] + }, { + "realm": "egress-rqe-queue", + "data": [[2, 3333, 4444], [5, 25, 45]] + }, { + "realm": "egress-service-pool", + "data": [[2, 0, 0, 3240], [3, 3660, 0, 0]] + }, { + "realm": "egress-uc-queue", + "data": [[6, "0", 1111]] + }, { + "realm": "egress-uc-queue-group", + "data": [[6, 2222]] + }] + } + + + self.bst_report_report_dict = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": d, + "report": {} + } + + + self.bst_report_empty_report = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": d, + "report": [] + } + + + self.bst_report_missing_report = { + "jsonrpc": "2.0", + "method": "get-bst-report", + "asic-id": "20", + "version": "1", + "time-stamp": d, + } + + + def test_good_bst(self): + j = json.dumps(self.bst_report) + r = requests.post('http://{}:{}'.format(host, port), json=j) + self.assertEqual(r.status_code, 200) + + def test_unknown_method_bst(self): + j = json.dumps(self.bst_report_unknown_method) + r = requests.post('http://{}:{}'.format(host, port), json=j) + self.assertEqual(r.status_code, 404) + + def test_unknown_realm(self): + j = json.dumps(self.bst_report_unknown_realm) + r = requests.post('http://{}:{}'.format(host, port), json=j) + self.assertEqual(r.status_code, 404) + + def test_bad_timestamp(self): + j = json.dumps(self.bst_report_bad_timestamp) + r = requests.post('http://{}:{}'.format(host, port), json=j) + self.assertEqual(r.status_code, 404) + + def test_report_dict(self): + j = json.dumps(self.bst_report_report_dict) + r = requests.post('http://{}:{}'.format(host, port), json=j) + self.assertEqual(r.status_code, 404) + + def test_empty_report(self): + j = json.dumps(self.bst_report_empty_report) + r = requests.post('http://{}:{}'.format(host, port), json=j) + self.assertEqual(r.status_code, 404) + + def test_missing_report(self): + j = json.dumps(self.bst_report_missing_report) + r = requests.post('http://{}:{}'.format(host, port), json=j) + self.assertEqual(r.status_code, 404) + +if __name__ == "__main__": + unittest.main() + + diff --git a/broadview_collector/tests/test_broadview_collector.py b/broadview_collector/tests/test_broadview_collector.py new file mode 100644 index 0000000..0130a4e --- /dev/null +++ b/broadview_collector/tests/test_broadview_collector.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +test_broadview_collector +---------------------------------- + +Tests for `broadview_collector` module. +""" + +from broadview_collector.tests import base + + +class TestBroadview_collector(base.TestCase): + + def test_something(self): + pass diff --git a/devstack/README.txt b/devstack/README.txt new file mode 100644 index 0000000..3f2dd10 --- /dev/null +++ b/devstack/README.txt @@ -0,0 +1,153 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# 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. + +The broadview-collector DevStack plugin currently only works on Ubuntu 14.04 +(Trusty). It may work elsewhere, we just haven't tried :-) + +Directions for installing an running Devstack can be found here: + + http://docs.openstack.org/developer/devstack/ + +To run broadview-collector in DevStack, perform the following steps: + +1. Clone the DevStack repo. + + git clone https://git.openstack.org/openstack-dev/devstack + +2. Add the following to the end of the DevStack local.conf file in the + root of the devstack directory. You may need to create the local.conf if + it does not already exist. + + # The following will enable broadview-collector + + enable_plugin broadview-collector git://github.com/openstack/broadview-collector + +4. Run './stack.sh' from the root of the devstack directory. + +The default configuration enables the logfile publisher plugin. You can +view/modify the configuration by editing /etc/broadviewcolector.conf and +then restarting the collector. + +Minimal Devstack local.conf +--------------------------- + +The following minimal local.conf should be all that is needed to bring +up the BroadView Collector: + +[[local|localrc]] +MYSQL_PASSWORD=secretmysql +DATABASE_PASSWORD=secretdatabase +RABBIT_PASSWORD=secretrabbit +ADMIN_PASSWORD=secretadmin +SERVICE_PASSWORD=secretservice +SERVICE_TOKEN=111222333444 + +LOGFILE=$DEST/logs/stack.sh.log +LOGDIR=$DEST/logs +LOG_COLOR=False + +disable_all_services +enable_service rabbit mysql key tempest + +enable_plugin broadview-collector git://git.openstack.org/openstack/broadview-collector + +Restarting the Collector +------------------------ + +To restart the collector: + +$ sudo service broadview_collector restart + +Stopping the Collector +--------------------- + +To stop the collector: + +$ sudo service broadview_collector stop + +Starting the Collector +---------------------- + +To start the collector: + +$ sudo service broadview_collector start + +Exercising The Collector +------------------------ + +A simple python script in broadview_collector/tests named bst_report.py can +be used to simulate data incoming from a BroadView agent. Combined with +configuration that enables the log publisher plugin (or any other plugin +for that matter), you can validate that the installation and configuration +is valid. To run it, edit the script by changing the host and port that +the collector is listening on: + +# Change these to the host and port the collector is listening on + +host = "172.16.170.175" +port = 8082 + +And then run the script: + +$ python bst_report + +You can then look at the configured plugin publishing targets to validate +that the data was published as expected. The script sends the data to the +collector and looks at the return code to verify the response is 200 (OK). +The Python unittest module is used to validate the return code and determine +a pass or fail status. + +Enabling Monasca +---------------- + +Follow these steps: + +1. Follow the instructions for devstack in the Monasca API project. The +README.txt file in https://github.com/openstack/monasca-api has all the +details. + +2. Add the following the end of their local.conf: + +enable_plugin broadview-collector git://git.openstack.org/openstack/broadview-collector + +3. Run devstack as usual with ./stack.sh + +4. Stop the collector + +$ sudo service broadview_collector stop + +5. Edit /etc/broadviewcollector.conf and add monascapublisher as a publisher +in the plugins section, e.g., + +[plugins] + +# comma separated list of plugin modules + +# publishers receive JSON encoded reports and write them somewhere + +publishers: logpublisher, monascapublisher + + +6. Restart the broadview collector: + +$ sudo service broadview_collector start + +7. Send some metrics using the bst simulator bst_report.py + +8. View the metric list in monasca + +$ monasca --os-username mini-mon --os-password password metric-list + +You should see some bst statistics in the report that is dislayed. +$ diff --git a/devstack/files/broadview-collector/broadview_collector.conf b/devstack/files/broadview-collector/broadview_collector.conf new file mode 100644 index 0000000..2a41f9d --- /dev/null +++ b/devstack/files/broadview-collector/broadview_collector.conf @@ -0,0 +1,22 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# 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. +# Startup script for the BroadView collector + +description "BroadView Collector Python app" +start on runlevel [2345] + +console log +respawn + +exec /opt/broadview-collector/bin/bvcollect.py diff --git a/devstack/files/env.sh b/devstack/files/env.sh new file mode 100644 index 0000000..609b7ca --- /dev/null +++ b/devstack/files/env.sh @@ -0,0 +1,25 @@ +# +# (C) Copyright 2015 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. +# + +# Environment variables for use with broadview collector. This script +# allows us to run under a virtual environment + +#. /opt/broadview-collector/bin/activate +#export OS_USERNAME=mini-mon +#export OS_PASSWORD=password +#export OS_PROJECT_NAME=mini-mon +#export OS_AUTH_URL=http://127.0.0.1:35357/v3/ diff --git a/devstack/plugin.sh b/devstack/plugin.sh new file mode 100644 index 0000000..8780735 --- /dev/null +++ b/devstack/plugin.sh @@ -0,0 +1,308 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# 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. + +# BroadView Collector DevStack plugin +# +# Install and start BroadView Collector service in devstack +# +# To enable broadview-collector in devstack add an entry to local.conf that +# looks like +# +# [[local|localrc]] +# enable_plugin broadview-collector git://github.com/openstack/broadview-collector +# + +# Save trace setting +XTRACE=$(set +o | grep xtrace) +set -o xtrace + +ERREXIT=$(set +o | grep errexit) +set -o errexit + +# Determine if we are running in devstack-gate or devstack. +if [[ $DEST ]]; then + + # We are running in devstack-gate. + export BROADVIEW_COLLECTOR_BASE=${BROADVIEW_COLLECTOR_BASE:-"${DEST}"} + +else + + # We are running in devstack. + export BROADVIEW_COLLECTOR_BASE=${BROADVIEW_COLLECTOR_BASE:-"/opt/stack"} + +fi + +function pre_install_broadview_collector { +: +} + +function install_broadview_collector { + + install_broadview_collector_env + + install_git + + install_broadview_lib + + install_broadview_collector_python +} + +function post_config_broadview_collector { +: +} + +function unstack_broadview_collector { + sudo service broadview_collector stop || true +} + +function clean_broadview_collector { + + set +o errexit + + unstack_broadview_collector + +# XXX this comnes later... +# if is_service_enabled horizon; then +# +# clean_broadview_horizon_ui +# +# fi + + clean_broadview_collector_python + + clean_broadview_lib + + clean_broadview_collector_env + + #Restore errexit + set -o errexit +} + +function install_broadview_collector_env { + + echo_summary "Install BroadView Collector Virtual Environment" + + sudo groupadd --system broadview_collector || true + + sudo mkdir -p /opt/broadview-collector || true + + sudo chown $STACK_USER:broadview_collector /opt/broadview-collector +} + +function clean_broadview_collector_env { + + echo_summary "Clean BroadView Collector Virtual Environment" + + sudo rm -rf /opt/broadview-collector + + sudo groupdel broadview_collector + +} + +function install_git { + + echo_summary "Install git" + + sudo apt-get -y install git + +} + +function install_broadview_lib { + + echo_summary "Install broadview_lib" + + if [[ ! -d /opt/broadview-lib ]]; then + + sudo git clone https://git.openstack.org/openstack/broadview-lib.git /opt/broadview-lib + + fi + + (cd /opt/broadview-lib; sudo python setup.py sdist) + + BROADVIEW_LIB_SRC_DIST=$(ls -td /opt/broadview-lib/dist/broadview-lib-*.tar.gz) + + pip_install $BROADVIEW_LIB_SRC_DIST +} + +function clean_broadview_lib { + echo_summary "Clean broadview_lib" +} + +function install_broadview_collector_python { + + echo_summary "Install broadview_collector_python" + + sudo mkdir -p /opt/broadview-collector/bin + + sudo chown $STACK_USER:broadview_collector /opt/broadview-collector + sudo chown $STACK_USER:broadview_collector /opt/broadview-collector/bin + + (cd "${BROADVIEW_COLLECTOR_BASE}"/broadview-collector; sudo python setup.py install) + + sudo cp -f "${BROADVIEW_COLLECTOR_BASE}"/broadview-collector/broadview_collector/bin/bvcollect.py /opt/broadview-collector/bin + + sudo chown root:broadview_collector /opt/broadview-collector/bin/bvcollect.py + sudo chmod 755 /opt/broadview-collector/bin/bvcollect.py + + sudo cp -f "${BROADVIEW_COLLECTOR_BASE}"/broadview-collector/devstack/files/broadview-collector/broadview_collector.conf /etc/init/broadview_collector.conf + + sudo chown root:broadview_collector /etc/init/broadview_collector.conf + + sudo chmod 0755 /etc/init/broadview_collector.conf + + sudo mkdir -p /var/log/broadview-collector || true + + sudo chown root:broadview_collector /var/log/broadview-collector + + sudo chmod 0755 /var/log/broadview-collector + + sudo cp -f "${BROADVIEW_COLLECTOR_BASE}"/broadview-collector/broadview_collector/config/broadviewcollector.conf /etc/broadviewcollector.conf + + sudo chown root:broadview_collector /etc/broadviewcollector.conf + + sudo chmod 0755 /etc/broadviewcollector.conf + + if [[ ${SERVICE_HOST} ]]; then + + sudo sed -i "s/127\.0\.0\.1/${SERVICE_HOST}/g" /etc/broadviewcollector.conf + fi + + if [[ ${SERVICE_HOST} ]]; then + + # set broadview_collector server listening ip address + sudo sed -i "s/host = 127\.0\.0\.1/host = ${SERVICE_HOST}/g" /etc/broadviewcollector.conf + + fi + + sudo start broadview_collector || sudo restart broadview_collector +} + +function clean_broadview_collector_python { + + echo_summary "Clean broadview_collector_python" + + sudo rm /etc/init/broadview_collector.conf + + sudo rm /etc/broadviewcollector.conf + + sudo rm -rf /var/log/broadview-collector + + sudo rm /var/log/upstart/broadview_collector.log* + + sudo rm -rf /opt/broadview-collector + +} + + +function install_broadview_collector_horizon_ui { + + echo_summary "Install BroadView Collector Horizon UI" + + sudo mkdir -p /opt/broadview_collector-horizon-ui || true + + sudo chown $STACK_USER:broadview_collector /opt/broadview_collector-horizon-ui + + (cd /opt/broadview_collector-horizon-ui ; virtualenv .) + + (cd /opt/broadview_collector-horizon-ui ; sudo -H ./bin/pip install broadview_collector-ui) + + sudo ln -sf /opt/broadview_collector-horizon-ui/lib/python2.7/site-packages/monitoring/enabled/_50_admin_add_monitoring_panel.py "${BROADVIEW_COLLECTOR_BASE}"/horizon/openstack_dashboard/local/enabled/_50_admin_add_monitoring_panel.py + + sudo ln -sf /opt/broadview_collector-horizon-ui/lib/python2.7/site-packages/monitoring/static/monitoring "${BROADVIEW_COLLECTOR_BASE}"/horizon/monitoring + + sudo PYTHONPATH=/opt/broadview_collector-horizon-ui/lib/python2.7/site-packages python "${BROADVIEW_COLLECTOR_BASE}"/horizon/manage.py compress --force + + sudo service apache2 restart + +} + +function extra_broadview_collector { +: +} + +function clean_broadview_collector_horizon_ui { + + echo_summary "Clean BroadView Collector Horizon UI" + + sudo rm -f "${BROADVIEW_COLLECTOR_BASE}"/horizon/openstack_dashboard/local/enabled/_50_admin_add_monitoring_panel.py + + sudo rm -f "${BROADVIEW_COLLECTOR_BASE}"/horizon/monitoring + + sudo rm -rf /opt/broadview_collector-horizon-ui + +} + +# Allows this script to be called directly outside of +# the devstack infrastructure code. Uncomment to use. +#if [[ $(type -t is_service_enabled) != 'function' ]]; then +# +# function is_service_enabled { +# +# return 0 +# +# } +#fi +#if [[ $(type -t echo_summary) != 'function' ]]; then +# +# function echo_summary { +# +# echo "$*" +# +# } +# +#fi + +# check for service enabled +if is_service_enabled broadview-collector; then + + if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then + # Set up system services + echo_summary "Configuring BroadView Collector system services" + pre_install_broadview_collector + + elif [[ "$1" == "stack" && "$2" == "install" ]]; then + # Perform installation of service source + echo_summary "Installing BroadView Collector" + install_broadview_collector + + elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then + # Configure after the other layer 1 and 2 services have been configured + echo_summary "Configuring BroadView Collector" + post_config_broadview_collector + + elif [[ "$1" == "stack" && "$2" == "extra" ]]; then + # Initialize and start the BroadView Collector service + echo_summary "Initializing BroadView Collector" + extra_broadview_collector + fi + + if [[ "$1" == "unstack" ]]; then + # Shut down BroadView Collector services + echo_summary "Unstacking BroadView Collector" + unstack_broadview_collector + fi + + if [[ "$1" == "clean" ]]; then + # Remove state and transient data + # Remember clean.sh first calls unstack.sh + echo_summary "Cleaning BroadView Collector" + clean_broadview_collector + fi +fi + +#Restore errexit +$ERREXIT + +# Restore xtrace +$XTRACE diff --git a/devstack/post_test_hook.sh b/devstack/post_test_hook.sh new file mode 100644 index 0000000..e69de29 diff --git a/devstack/pre_test_hook.sh b/devstack/pre_test_hook.sh new file mode 100644 index 0000000..e69de29 diff --git a/devstack/settings b/devstack/settings new file mode 100644 index 0000000..ef46dbe --- /dev/null +++ b/devstack/settings @@ -0,0 +1,15 @@ +# (C) Copyright Broadcom Corporation 2016 +# +# 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. + +enable_service broadview-collector diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 0000000..8538790 --- /dev/null +++ b/doc/source/conf.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import sys + +sys.path.insert(0, os.path.abspath('../..')) +# -- General configuration ---------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + 'sphinx.ext.autodoc', + #'sphinx.ext.intersphinx', + 'oslosphinx' +] + +# autodoc generation is a bit aggressive and a nuisance when doing heavy +# text edit cycles. +# execute "export SPHINX_DEBUG=1" in your terminal to disable + +# The suffix of source filenames. +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'broadview-collector' +copyright = u'2013, OpenStack Foundation' + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +add_module_names = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# -- Options for HTML output -------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +# html_theme_path = ["."] +# html_theme = '_theme' +# html_static_path = ['static'] + +# Output file base name for HTML help builder. +htmlhelp_basename = '%sdoc' % project + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass +# [howto/manual]). +latex_documents = [ + ('index', + '%s.tex' % project, + u'%s Documentation' % project, + u'OpenStack Foundation', 'manual'), +] + +# Example configuration for intersphinx: refer to the Python standard library. +#intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst new file mode 100644 index 0000000..1728a61 --- /dev/null +++ b/doc/source/contributing.rst @@ -0,0 +1,4 @@ +============ +Contributing +============ +.. include:: ../../CONTRIBUTING.rst diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 0000000..df6c932 --- /dev/null +++ b/doc/source/index.rst @@ -0,0 +1,25 @@ +.. broadview-collector documentation master file, created by + sphinx-quickstart on Tue Jul 9 22:26:36 2013. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to broadview-collector's documentation! +======================================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + readme + installation + usage + contributing + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/source/installation.rst b/doc/source/installation.rst new file mode 100644 index 0000000..6215444 --- /dev/null +++ b/doc/source/installation.rst @@ -0,0 +1,6 @@ +============ +Installation +============ + +Refer to README.md for directions on installing this software. + diff --git a/doc/source/readme.rst b/doc/source/readme.rst new file mode 100644 index 0000000..7592303 --- /dev/null +++ b/doc/source/readme.rst @@ -0,0 +1 @@ +.. include:: ../../README.md diff --git a/doc/source/usage.rst b/doc/source/usage.rst new file mode 100644 index 0000000..3cab662 --- /dev/null +++ b/doc/source/usage.rst @@ -0,0 +1,6 @@ +======== +Usage +======== + +Refer to README.md for documentation on how to use broadview-collector + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..30806d5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +# The order of packages is significant, because pip processes them in the order +# of appearance. Changing the order has an impact on the overall integration +# process, which may cause wedges in the gate later. + +pbr>=1.6 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..3b3fb99 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,43 @@ +[metadata] +name = broadview-collector +summary = broadview-collector is a plugin-based service that collects and publishes network underlay data to services such as Monasca. +description-file = + README.md +author = OpenStack +author-email = openstack-dev@lists.openstack.org +home-page = http://www.openstack.org/ +classifier = + Environment :: OpenStack + 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 + +[files] +packages = + broadview_collector + +[build_sphinx] +source-dir = doc/source +build-dir = doc/build +all_files = 1 + +[upload_sphinx] +upload-dir = doc/build/html + +[compile_catalog] +directory = broadview_collector/locale +domain = broadview_collector + +[update_catalog] +domain = broadview_collector +output_dir = broadview_collector/locale +input_file = broadview_collector/locale/broadview_collector.pot + +[extract_messages] +keywords = _ gettext ngettext l_ lazy_gettext +mapping_file = babel.cfg +output_file = broadview_collector/locale/broadview_collector.pot diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..056c16c --- /dev/null +++ b/setup.py @@ -0,0 +1,29 @@ +# 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'], + pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..21a7e3b --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,14 @@ +# The order of packages is significant, because pip processes them in the order +# of appearance. Changing the order has an impact on the overall integration +# process, which may cause wedges in the gate later. + +hacking<0.11,>=0.10.0 + +coverage>=3.6 +python-subunit>=0.0.18 +sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 +oslosphinx>=2.5.0 # Apache-2.0 +oslotest>=1.10.0 # Apache-2.0 +testrepository>=0.0.18 +testscenarios>=0.4 +testtools>=1.4.0 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..d4cd6e3 --- /dev/null +++ b/tox.ini @@ -0,0 +1,60 @@ +[tox] +minversion = 2.0 +envlist = py34-constraints,py27-constraints,pypy-constraints,pep8-constraints +skipsdist = True + +[testenv] +usedevelop = True +install_command = + constraints: {[testenv:common-constraints]install_command} + pip install -U {opts} {packages} +setenv = + VIRTUAL_ENV={envdir} +deps = -r{toxinidir}/test-requirements.txt +commands = python setup.py test --slowest --testr-args='{posargs}' + +[testenv:common-constraints] +install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} + +[testenv:pep8] +commands = flake8 {posargs} + +[testenv:pep8-constraints] +install_command = {[testenv:common-constraints]install_command} +commands = flake8 {posargs} + +[testenv:venv] +commands = {posargs} + +[testenv:venv-constraints] +install_command = {[testenv:common-constraints]install_command} +commands = {posargs} + +[testenv:cover] +commands = python setup.py test --coverage --testr-args='{posargs}' + +[testenv:cover-constraints] +install_command = {[testenv:common-constraints]install_command} +commands = python setup.py test --coverage --testr-args='{posargs}' + +[testenv:docs] +commands = python setup.py build_sphinx + +[testenv:docs-constraints] +install_command = {[testenv:common-constraints]install_command} +commands = python setup.py build_sphinx + +[testenv:debug] +commands = oslo_debug_helper {posargs} + +[testenv:debug-constraints] +install_command = {[testenv:common-constraints]install_command} +commands = oslo_debug_helper {posargs} + +[flake8] +# E123, E125 skipped as they are invalid PEP-8. + +show-source = True +ignore = E123,E125 +builtins = _ +exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build