diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c819f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,97 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +.idea/ +htmlcov/ +.tox/ +/.tox +.testrepository/ +.coverage/ +cover/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject + +# conf file +graphite.conf.yml diff --git a/HACKING.rst b/HACKING.rst new file mode 100644 index 0000000..1eb82f2 --- /dev/null +++ b/HACKING.rst @@ -0,0 +1,19 @@ +Style Commandments +================== + +- Tendrl coding style is inspired by one of the largest python projects, OpenStack + http://docs.openstack.org/developer/hacking/ (excluding the license and trademark sections) + + +Developer Workflow +------------------ +Refer: http://nvie.com/posts/a-successful-git-branching-model/ + + +Creating Unit Tests +------------------- +For every new feature, unit tests should be created that both test and +(implicitly) document the usage of said feature. If submitting a pull request for a +bug that had no unit test, a new passing unit test should be added. If a +submitted bug fix does have a unit test, be sure to add a new one that fails +without the patch and passes with the patch. diff --git a/README.md b/README.md deleted file mode 100644 index fb336c3..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# monitoring-integration -Component that enables integration with external monitoring services. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..72b3e37 --- /dev/null +++ b/README.rst @@ -0,0 +1,115 @@ + + +Monitoring-Integration +======================= + + +Functionalities +---------------- + +- Create a new dashboard in Grafana + + +Environment Setup +----------------- + +#. Clone the monitoring-integration repository + + :: + + $ git clone https://github.com/Tendrl/monitoring-integration.git + $ cd monitoring-integration + + +.. note:: + + All the commands mentioned below are run as a regular user that has ``sudo`` + privileges. + These commands are assumbed to be run from a single directory, which + contains the code of monitoring-integration. + +#. Install python pip + + + https://pip.pypa.io/en/stable/installing/ + + +#. Install python dependencies + + :: + + $ python setup.py install + + +#. Install Grafana + + + http://docs.grafana.org/installation/ + + +#. Configure grafana for anonymous login. + + :: + + $ cp etc/grafana/grafana.ini /etc/grafana/. + + .. note:: + + This will overwrite present grafana.ini. + +Prerequisites +-------------- + +* Grafana instance is set-up and running on the server node. + +* Graphite instance in set-up and running on the same server node. + +* Monitoring-Integration is installed on same server node. + + +Usage Details +-------------- + +.. note:: + + Configuration file needed by monitoring-integration is present under + + ' /etc/tendrl/monitoring-integration/monitoring-integration.conf.yaml' + + If configuration file is not present. + + :: + + $ cp etc/tendrl/monitoring-integration/monitoring-integration.conf.yaml.sample + /etc/tendrl/monitoring-integration/monitoring-integration.conf.yaml + + +* Development setup + + * Create a json file in tendrl/monitoring-integration/grafana/dashboards and provide json + for the dashboard that is to be created. + + * Provide the file-name of the json file created in above step under "dashboards" + in /etc/tendrl/monitoring-integration/monitoring-integration.conf.yaml. + + * Make one of the dashboards listed under "dashboards" as home_dashboard. + + * Provide grafana instance's credential under "credentials" in monitoring-integration.conf.yaml file + + * Provide name of datasource to be created in grafana under "datasource_name" in + monitoring-integration.conf.yaml file + + * Make sure a datasource with same name as given in monitoring-integration.conf.yaml file + doesnot exist in grafana. + + * By default true is passed under "isDefault" in monitoring-integration.conf.yaml + to set the datasource as the default datasource in grafana. + + * Follow the commands provided below to run __init__.py file to create dashboards and datasource + in grafana. + + :: + + $ cd tendrl/monitoring_integration/ + $ python __init__.py + diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/check_commit_msg.py b/check_commit_msg.py new file mode 100644 index 0000000..6b53237 --- /dev/null +++ b/check_commit_msg.py @@ -0,0 +1,45 @@ +#!/bin/python + +import os + +import requests + +commit_msg = str(os.environ['TRAVIS_COMMIT_MSG']) +tendrl_bug_id = None +tendrl_spec = None +github_base_url = "http://github.com" + + +# Extract "tendrl-bug-id" and "tendrl-spec" name from the commit message +for line in commit_msg.split("\n"): + if "tendrl-bug-id" in line: + try: + tendrl_bug_id = line.split("tendrl-bug-id:")[-1].strip() + except Exception as ex: + print(ex) + + if "tendrl-spec" in line: + try: + tendrl_spec = line.split("tendrl-spec:")[-1].strip() + except Exception as ex: + print(ex) + +if tendrl_bug_id is None: + raise Exception("Please add 'tendrl-bug-id:Tendrl/#issue_id'" + " to your commit msg") + +if tendrl_bug_id: + issue = "%s/%s" % (github_base_url, tendrl_bug_id.replace("#", "/issues/")) + if requests.get(issue).status_code != 200: + raise Exception("Tendrl Bug specified in git commit msg not " + "found!!\n" + "%s" % issue) + print("Tendrl Bug specified in git commit msg found!!\n%s" % issue) + +if tendrl_spec: + spec = "%s/%s.adoc" % ("https://github.com/Tendrl/specifications/tree" + "/master/specs", tendrl_spec) + if requests.get(spec).status_code != 200: + raise Exception("Tendrl Spec specified in git commit msg not found\n" + "%s" % spec) + print("Tendrl Spec specified in git commit msg found!!\n%s" % spec) diff --git a/etc/grafana/grafana.ini b/etc/grafana/grafana.ini new file mode 100644 index 0000000..0d4c701 --- /dev/null +++ b/etc/grafana/grafana.ini @@ -0,0 +1,407 @@ +##################### Grafana Configuration Example ##################### +# +# Everything has defaults so you only need to uncomment things you want to +# change + +# possible values : production, development +; app_mode = production + +# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty +; instance_name = ${HOSTNAME} + +#################################### Paths #################################### +[paths] +# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used) +# +;data = /var/lib/grafana +# +# Directory where grafana can store logs +# +;logs = /var/log/grafana +# +# Directory where grafana will automatically scan and look for plugins +# +;plugins = /var/lib/grafana/plugins + +# +#################################### Server #################################### +[server] +# Protocol (http, https, socket) +;protocol = http + +# The ip address to bind to, empty will bind to all interfaces +;http_addr = + +# The http port to use +;http_port = 3000 + +# The public facing domain name used to access grafana from a browser +;domain = localhost + +# Redirect to correct domain if host header does not match domain +# Prevents DNS rebinding attacks +;enforce_domain = false + +# The full public facing url you use in browser, used for redirects and emails +# If you use reverse proxy and sub path specify full url (with sub path) +;root_url = http://localhost:3000 + +# Log web requests +;router_logging = false + +# the path relative working path +;static_root_path = public + +# enable gzip +;enable_gzip = false + +# https certs & key file +;cert_file = +;cert_key = + +# Unix socket path +;socket = + +#################################### Database #################################### +[database] +# You can configure the database connection by specifying type, host, name, user and password +# as seperate properties or as on string using the url propertie. + +# Either "mysql", "postgres" or "sqlite3", it's your choice +;type = sqlite3 +;host = 127.0.0.1:3306 +;name = grafana +;user = root +# If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;""" +;password = + +# Use either URL or the previous fields to configure the database +# Example: mysql://user:secret@host:port/database +;url = + +# For "postgres" only, either "disable", "require" or "verify-full" +;ssl_mode = disable + +# For "sqlite3" only, path relative to data_path setting +;path = grafana.db + +# Max conn setting default is 0 (mean not set) +;max_idle_conn = +;max_open_conn = + + +#################################### Session #################################### +[session] +# Either "memory", "file", "redis", "mysql", "postgres", default is "file" +;provider = file + +# Provider config options +# memory: not have any config yet +# file: session dir path, is relative to grafana data_path +# redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=grafana` +# mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1:3306)/database_name` +# postgres: user=a password=b host=localhost port=5432 dbname=c sslmode=disable +;provider_config = sessions + +# Session cookie name +;cookie_name = grafana_sess + +# If you use session in https only, default is false +;cookie_secure = false + +# Session life time, default is 86400 +;session_life_time = 86400 + +#################################### Data proxy ########################### +[dataproxy] + +# This enables data proxy logging, default is false +;logging = false + + +#################################### Analytics #################################### +[analytics] +# Server reporting, sends usage counters to stats.grafana.org every 24 hours. +# No ip addresses are being tracked, only simple counters to track +# running instances, dashboard and error counts. It is very helpful to us. +# Change this option to false to disable reporting. +;reporting_enabled = true + +# Set to false to disable all checks to https://grafana.net +# for new vesions (grafana itself and plugins), check is used +# in some UI views to notify that grafana or plugin update exists +# This option does not cause any auto updates, nor send any information +# only a GET request to http://grafana.com to get latest versions +;check_for_updates = true + +# Google Analytics universal tracking code, only enabled if you specify an id here +;google_analytics_ua_id = + +#################################### Security #################################### +[security] +# default admin user, created on startup +;admin_user = admin + +# default admin password, can be changed before first start of grafana, or in profile settings +;admin_password = admin + +# used for signing +;secret_key = SW2YcwTIb9zpOOhoPsMm + +# Auto-login remember days +;login_remember_days = 7 +;cookie_username = grafana_user +;cookie_remember_name = grafana_remember + +# disable gravatar profile images +;disable_gravatar = false + +# data source proxy whitelist (ip_or_domain:port separated by spaces) +;data_source_proxy_whitelist = + +[snapshots] +# snapshot sharing options +;external_enabled = true +;external_snapshot_url = https://snapshots-origin.raintank.io +;external_snapshot_name = Publish to snapshot.raintank.io + +# remove expired snapshot +;snapshot_remove_expired = true + +# remove snapshots after 90 days +;snapshot_TTL_days = 90 + +#################################### Users #################################### +[users] +# disable user signup / registration +;allow_sign_up = true + +# Allow non admin users to create organizations +;allow_org_create = true + +# Set to true to automatically assign new users to the default organization (id 1) +;auto_assign_org = true + +# Default role new users will be automatically assigned (if disabled above is set to true) +;auto_assign_org_role = Viewer + +# Background text for the user field on the login page +;login_hint = email or username + +# Default UI theme ("dark" or "light") +;default_theme = dark + +[auth] +# Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false +;disable_login_form = true + +# Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false +;disable_signout_menu = false + +#################################### Anonymous Auth ########################## +[auth.anonymous] +# enable anonymous access +enabled = true + +# specify organization name that should be used for unauthenticated users +org_name = Main Org. + +# specify role for unauthenticated users +org_role = Admin + +#################################### Github Auth ########################## +[auth.github] +;enabled = false +;allow_sign_up = true +;client_id = some_id +;client_secret = some_secret +;scopes = user:email,read:org +;auth_url = https://github.com/login/oauth/authorize +;token_url = https://github.com/login/oauth/access_token +;api_url = https://api.github.com/user +;team_ids = +;allowed_organizations = + +#################################### Google Auth ########################## +[auth.google] +;enabled = false +;allow_sign_up = true +;client_id = some_client_id +;client_secret = some_client_secret +;scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email +;auth_url = https://accounts.google.com/o/oauth2/auth +;token_url = https://accounts.google.com/o/oauth2/token +;api_url = https://www.googleapis.com/oauth2/v1/userinfo +;allowed_domains = + +#################################### Generic OAuth ########################## +[auth.generic_oauth] +;enabled = false +;name = OAuth +;allow_sign_up = true +;client_id = some_id +;client_secret = some_secret +;scopes = user:email,read:org +;auth_url = https://foo.bar/login/oauth/authorize +;token_url = https://foo.bar/login/oauth/access_token +;api_url = https://foo.bar/user +;team_ids = +;allowed_organizations = + +#################################### Grafana.com Auth #################### +[auth.grafana_com] +;enabled = false +;allow_sign_up = true +;client_id = some_id +;client_secret = some_secret +;scopes = user:email +;allowed_organizations = + +#################################### Auth Proxy ########################## +[auth.proxy] +;enabled = false +;header_name = X-WEBAUTH-USER +;header_property = username +;auto_sign_up = true +;ldap_sync_ttl = 60 +;whitelist = 192.168.1.1, 192.168.2.1 + +#################################### Basic Auth ########################## +[auth.basic] +enabled = false + +#################################### Auth LDAP ########################## +[auth.ldap] +;enabled = false +;config_file = /etc/grafana/ldap.toml +;allow_sign_up = true + +#################################### SMTP / Emailing ########################## +[smtp] +;enabled = false +;host = localhost:25 +;user = +# If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;""" +;password = +;cert_file = +;key_file = +;skip_verify = false +;from_address = admin@grafana.localhost +;from_name = Grafana + +[emails] +;welcome_email_on_sign_up = false + +#################################### Logging ########################## +[log] +# Either "console", "file", "syslog". Default is console and file +# Use space to separate multiple modes, e.g. "console file" +;mode = console file + +# Either "debug", "info", "warn", "error", "critical", default is "info" +;level = info + +# optional settings to set different levels for specific loggers. Ex filters = sqlstore:debug +;filters = + + +# For "console" mode only +[log.console] +;level = + +# log line format, valid options are text, console and json +;format = console + +# For "file" mode only +[log.file] +;level = + +# log line format, valid options are text, console and json +;format = text + +# This enables automated log rotate(switch of following options), default is true +;log_rotate = true + +# Max line number of single file, default is 1000000 +;max_lines = 1000000 + +# Max size shift of single file, default is 28 means 1 << 28, 256MB +;max_size_shift = 28 + +# Segment log daily, default is true +;daily_rotate = true + +# Expired days of log file(delete after max days), default is 7 +;max_days = 7 + +[log.syslog] +;level = + +# log line format, valid options are text, console and json +;format = text + +# Syslog network type and address. This can be udp, tcp, or unix. If left blank, the default unix endpoints will be used. +;network = +;address = + +# Syslog facility. user, daemon and local0 through local7 are valid. +;facility = + +# Syslog tag. By default, the process' argv[0] is used. +;tag = + + +#################################### AMQP Event Publisher ########################## +[event_publisher] +;enabled = false +;rabbitmq_url = amqp://localhost/ +;exchange = grafana_events + +;#################################### Dashboard JSON files ########################## +[dashboards.json] +;enabled = false +;path = /var/lib/grafana/dashboards + +#################################### Alerting ############################ +[alerting] +# Disable alerting engine & UI features +;enabled = true +# Makes it possible to turn off alert rule execution but alerting UI is visible +;execute_alerts = true + +#################################### Internal Grafana Metrics ########################## +# Metrics available at HTTP API Url /api/metrics +[metrics] +# Disable / Enable internal metrics +;enabled = true + +# Publish interval +;interval_seconds = 10 + +# Send internal metrics to Graphite +[metrics.graphite] +# Enable by setting the address setting (ex localhost:2003) +;address = +;prefix = prod.grafana.%(instance_name)s. + +#################################### Grafana.com integration ########################## +# Url used to to import dashboards directly from Grafana.com +[grafana_com] +;url = https://grafana.com + +#################################### External image storage ########################## +[external_image_storage] +# Used for uploading images to public servers so they can be included in slack/email messages. +# you can choose between (s3, webdav) +;provider = + +[external_image_storage.s3] +;bucket_url = +;access_key = +;secret_key = + +[external_image_storage.webdav] +;url = +;public_url = +;username = +;password = diff --git a/etc/grafana/screenshots/Tendrl-Gluster-At-A-Glance.png b/etc/grafana/screenshots/Tendrl-Gluster-At-A-Glance.png new file mode 100644 index 0000000..6e8e24e Binary files /dev/null and b/etc/grafana/screenshots/Tendrl-Gluster-At-A-Glance.png differ diff --git a/etc/grafana/screenshots/Tendrl-Gluster-Bricks.png b/etc/grafana/screenshots/Tendrl-Gluster-Bricks.png new file mode 100644 index 0000000..adf94dc Binary files /dev/null and b/etc/grafana/screenshots/Tendrl-Gluster-Bricks.png differ diff --git a/etc/grafana/screenshots/Tendrl-Gluster-Hosts.png b/etc/grafana/screenshots/Tendrl-Gluster-Hosts.png new file mode 100644 index 0000000..47dc7be Binary files /dev/null and b/etc/grafana/screenshots/Tendrl-Gluster-Hosts.png differ diff --git a/etc/grafana/screenshots/Tendrl-Gluster-Volumes.png b/etc/grafana/screenshots/Tendrl-Gluster-Volumes.png new file mode 100644 index 0000000..2d45b9a Binary files /dev/null and b/etc/grafana/screenshots/Tendrl-Gluster-Volumes.png differ diff --git a/etc/tendrl/monitoring-integration/carbon.conf.sample b/etc/tendrl/monitoring-integration/carbon.conf.sample new file mode 100644 index 0000000..cf62efa --- /dev/null +++ b/etc/tendrl/monitoring-integration/carbon.conf.sample @@ -0,0 +1,409 @@ +[cache] +# Configure carbon directories. +# +# OS environment variables can be used to tell carbon where graphite is +# installed, where to read configuration from and where to write data. +# +# GRAPHITE_ROOT - Root directory of the graphite installation. +# Defaults to ../ +# GRAPHITE_CONF_DIR - Configuration directory (where this file lives). +# Defaults to $GRAPHITE_ROOT/conf/ +# GRAPHITE_STORAGE_DIR - Storage directory for whisper/rrd/log/pid files. +# Defaults to $GRAPHITE_ROOT/storage/ +# +# To change other directory paths, add settings to this file. The following +# configuration variables are available with these default values: +# +# STORAGE_DIR = $GRAPHITE_STORAGE_DIR +# LOCAL_DATA_DIR = STORAGE_DIR/whisper/ +# WHITELISTS_DIR = STORAGE_DIR/lists/ +# CONF_DIR = STORAGE_DIR/conf/ +# LOG_DIR = STORAGE_DIR/log/ +# PID_DIR = STORAGE_DIR/ +# +# For FHS style directory structures, use: +# +# STORAGE_DIR = /var/lib/carbon/ +# CONF_DIR = /etc/carbon/ +# LOG_DIR = /var/log/carbon/ +# PID_DIR = /var/run/ +# +#LOCAL_DATA_DIR = /opt/graphite/storage/whisper/ + +STORAGE_DIR = /var/lib/carbon/ +LOCAL_DATA_DIR = /var/lib/carbon/whisper/ +WHITELISTS_DIR = /var/lib/carbon/lists/ +CONF_DIR = /etc/carbon/ +LOG_DIR = /var/log/carbon/ +PID_DIR = /var/run/ + +# Enable daily log rotation. If disabled, carbon will automatically re-open +# the file if it's rotated out of place (e.g. by logrotate daemon) +ENABLE_LOGROTATION = False + +# Specify the user to drop privileges to +# If this is blank carbon runs as the user that invokes it +# This user must have write access to the local data directory +USER = carbon +# +# NOTE: The above settings must be set under [relay] and [aggregator] +# to take effect for those daemons as well + +# Limit the size of the cache to avoid swapping or becoming CPU bound. +# Sorts and serving cache queries gets more expensive as the cache grows. +# Use the value "inf" (infinity) for an unlimited cache size. +MAX_CACHE_SIZE = inf + +# Limits the number of whisper update_many() calls per second, which effectively +# means the number of write requests sent to the disk. This is intended to +# prevent over-utilizing the disk and thus starving the rest of the system. +# When the rate of required updates exceeds this, then carbon's caching will +# take effect and increase the overall throughput accordingly. +MAX_UPDATES_PER_SECOND = 500 + +# If defined, this changes the MAX_UPDATES_PER_SECOND in Carbon when a +# stop/shutdown is initiated. This helps when MAX_UPDATES_PER_SECOND is +# relatively low and carbon has cached a lot of updates; it enables the carbon +# daemon to shutdown more quickly. +# MAX_UPDATES_PER_SECOND_ON_SHUTDOWN = 1000 + +# Softly limits the number of whisper files that get created each minute. +# Setting this value low (e.g. 50) is a good way to ensure that your carbon +# system will not be adversely impacted when a bunch of new metrics are +# sent to it. The trade off is that any metrics received in excess of this +# value will be silently dropped, and the whisper file will not be created +# until such point as a subsequent metric is received and fits within the +# defined rate limit. Setting this value high (like "inf" for infinity) will +# cause carbon to create the files quickly but at the risk of increased I/O. +MAX_CREATES_PER_MINUTE = 50 + +# Set the interface and port for the line (plain text) listener. Setting the +# interface to 0.0.0.0 listens on all interfaces. Port can be set to 0 to +# disable this listener if it is not required. +LINE_RECEIVER_INTERFACE = 0.0.0.0 +LINE_RECEIVER_PORT = 2003 + +# Set the TCP backlog for the listen socket created by the line receiver. You +# shouldn't change this unless you know what you're doing. +# LINE_RECEIVER_BACKLOG = 1024 + +# Set this to True to enable the UDP listener. By default this is off +# because it is very common to run multiple carbon daemons and managing +# another (rarely used) port for every carbon instance is not fun. +ENABLE_UDP_LISTENER = False +UDP_RECEIVER_INTERFACE = 0.0.0.0 +UDP_RECEIVER_PORT = 2003 + +# Set the interface and port for the pickle listener. Setting the interface to +# 0.0.0.0 listens on all interfaces. Port can be set to 0 to disable this +# listener if it is not required. +PICKLE_RECEIVER_INTERFACE = 0.0.0.0 +PICKLE_RECEIVER_PORT = 2004 + +# Set the TCP backlog for the listen socket created by the pickle receiver. You +# shouldn't change this unless you know what you're doing. +# PICKLE_RECEIVER_BACKLOG = 1024 + +# Set to false to disable logging of successful connections +LOG_LISTENER_CONNECTIONS = True + +# Per security concerns outlined in Bug #817247 the pickle receiver +# will use a more secure and slightly less efficient unpickler. +# Set this to True to revert to the old-fashioned insecure unpickler. +USE_INSECURE_UNPICKLER = False + +CACHE_QUERY_INTERFACE = 0.0.0.0 +CACHE_QUERY_PORT = 7002 + +# Set the TCP backlog for the listen socket created by the cache query +# listener. You shouldn't change this unless you know what you're doing. +# CACHE_QUERY_BACKLOG = 1024 + +# Set this to False to drop datapoints received after the cache +# reaches MAX_CACHE_SIZE. If this is True (the default) then sockets +# over which metrics are received will temporarily stop accepting +# data until the cache size falls below 95% MAX_CACHE_SIZE. +USE_FLOW_CONTROL = True + +# By default, carbon-cache will log every whisper update and cache hit. This can be excessive and +# degrade performance if logging on the same volume as the whisper data is stored. +LOG_UPDATES = False +LOG_CACHE_HITS = False +LOG_CACHE_QUEUE_SORTS = True + +# The thread that writes metrics to disk can use on of the following strategies +# determining the order in which metrics are removed from cache and flushed to +# disk. The default option preserves the same behavior as has been historically +# available in version 0.9.10. +# +# sorted - All metrics in the cache will be counted and an ordered list of +# them will be sorted according to the number of datapoints in the cache at the +# moment of the list's creation. Metrics will then be flushed from the cache to +# disk in that order. +# +# max - The writer thread will always pop and flush the metric from cache +# that has the most datapoints. This will give a strong flush preference to +# frequently updated metrics and will also reduce random file-io. Infrequently +# updated metrics may only ever be persisted to disk at daemon shutdown if +# there are a large number of metrics which receive very frequent updates OR if +# disk i/o is very slow. +# +# naive - Metrics will be flushed from the cache to disk in an unordered +# fashion. This strategy may be desirable in situations where the storage for +# whisper files is solid state, CPU resources are very limited or deference to +# the OS's i/o scheduler is expected to compensate for the random write +# pattern. +# +CACHE_WRITE_STRATEGY = sorted + +# On some systems it is desirable for whisper to write synchronously. +# Set this option to True if you'd like to try this. Basically it will +# shift the onus of buffering writes from the kernel into carbon's cache. +WHISPER_AUTOFLUSH = False + +# By default new Whisper files are created pre-allocated with the data region +# filled with zeros to prevent fragmentation and speed up contiguous reads and +# writes (which are common). Enabling this option will cause Whisper to create +# the file sparsely instead. Enabling this option may allow a large increase of +# MAX_CREATES_PER_MINUTE but may have longer term performance implications +# depending on the underlying storage configuration. +# WHISPER_SPARSE_CREATE = False + +# Only beneficial on linux filesystems that support the fallocate system call. +# It maintains the benefits of contiguous reads/writes, but with a potentially +# much faster creation speed, by allowing the kernel to handle the block +# allocation and zero-ing. Enabling this option may allow a large increase of +# MAX_CREATES_PER_MINUTE. If enabled on an OS or filesystem that is unsupported +# this option will gracefully fallback to standard POSIX file access methods. +WHISPER_FALLOCATE_CREATE = True + +# Enabling this option will cause Whisper to lock each Whisper file it writes +# to with an exclusive lock (LOCK_EX, see: man 2 flock). This is useful when +# multiple carbon-cache daemons are writing to the same files +# WHISPER_LOCK_WRITES = False + +# Set this to True to enable whitelisting and blacklisting of metrics in +# CONF_DIR/whitelist and CONF_DIR/blacklist. If the whitelist is missing or +# empty, all metrics will pass through +# USE_WHITELIST = False + +# By default, carbon itself will log statistics (such as a count, +# metricsReceived) with the top level prefix of 'carbon' at an interval of 60 +# seconds. Set CARBON_METRIC_INTERVAL to 0 to disable instrumentation +CARBON_METRIC_PREFIX = collectd +CARBON_METRIC_INTERVAL = 600 + +# Enable AMQP if you want to receve metrics using an amqp broker +# ENABLE_AMQP = False + +# Verbose means a line will be logged for every metric received +# useful for testing +# AMQP_VERBOSE = False + +# AMQP_HOST = localhost +# AMQP_PORT = 5672 +# AMQP_VHOST = / +# AMQP_USER = guest +# AMQP_PASSWORD = guest +# AMQP_EXCHANGE = graphite +# AMQP_METRIC_NAME_IN_BODY = False + +# The manhole interface allows you to SSH into the carbon daemon +# and get a python interpreter. BE CAREFUL WITH THIS! If you do +# something like time.sleep() in the interpreter, the whole process +# will sleep! This is *extremely* helpful in debugging, assuming +# you are familiar with the code. If you are not, please don't +# mess with this, you are asking for trouble :) +# +# ENABLE_MANHOLE = False +# MANHOLE_INTERFACE = 127.0.0.1 +# MANHOLE_PORT = 7222 +# MANHOLE_USER = admin +# MANHOLE_PUBLIC_KEY = ssh-rsa AAAAB3NzaC1yc2EAAAABiwAaAIEAoxN0sv/e4eZCPpi3N3KYvyzRaBaMeS2RsOQ/cDuKv11dlNzVeiyc3RFmCv5Rjwn/lQ79y0zyHxw67qLyhQ/kDzINc4cY41ivuQXm2tPmgvexdrBv5nsfEpjs3gLZfJnyvlcVyWK/lId8WUvEWSWHTzsbtmXAF2raJMdgLTbQ8wE= + +# Patterns for all of the metrics this machine will store. Read more at +# http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol#Bindings +# +# Example: store all sales, linux servers, and utilization metrics +# BIND_PATTERNS = sales.#, servers.linux.#, #.utilization +# +# Example: store everything +# BIND_PATTERNS = # + +# To configure special settings for the carbon-cache instance 'b', uncomment this: +#[cache:b] +#LINE_RECEIVER_PORT = 2103 +#PICKLE_RECEIVER_PORT = 2104 +#CACHE_QUERY_PORT = 7102 +# and any other settings you want to customize, defaults are inherited +# from [carbon] section. +# You can then specify the --instance=b option to manage this instance + + + +[relay] +LINE_RECEIVER_INTERFACE = 0.0.0.0 +LINE_RECEIVER_PORT = 2013 +PICKLE_RECEIVER_INTERFACE = 0.0.0.0 +PICKLE_RECEIVER_PORT = 2014 + +# Set to false to disable logging of successful connections +LOG_LISTENER_CONNECTIONS = True + +# Carbon-relay has several options for metric routing controlled by RELAY_METHOD +# +# Use relay-rules.conf to route metrics to destinations based on pattern rules +#RELAY_METHOD = rules +# +# Use consistent-hashing for even distribution of metrics between destinations +#RELAY_METHOD = consistent-hashing +# +# Use consistent-hashing but take into account an aggregation-rules.conf shared +# by downstream carbon-aggregator daemons. This will ensure that all metrics +# that map to a given aggregation rule are sent to the same carbon-aggregator +# instance. +# Enable this for carbon-relays that send to a group of carbon-aggregators +#RELAY_METHOD = aggregated-consistent-hashing +RELAY_METHOD = rules + +# If you use consistent-hashing you can add redundancy by replicating every +# datapoint to more than one machine. +REPLICATION_FACTOR = 1 + +# For REPLICATION_FACTOR >=2, set DIVERSE_REPLICAS to True to guarantee replicas +# across distributed hosts. With this setting disabled, it's possible that replicas +# may be sent to different caches on the same host. This has been the default +# behavior since introduction of 'consistent-hashing' relay method. +# Note that enabling this on an existing pre-0.9.14 cluster will require rebalancing +# your metrics across the cluster nodes using a tool like Carbonate. +#DIVERSE_REPLICAS = False + +# This is a list of carbon daemons we will send any relayed or +# generated metrics to. The default provided would send to a single +# carbon-cache instance on the default port. However if you +# use multiple carbon-cache instances then it would look like this: +# +# DESTINATIONS = 127.0.0.1:2004:a, 127.0.0.1:2104:b +# +# The general form is IP:PORT:INSTANCE where the :INSTANCE part is +# optional and refers to the "None" instance if omitted. +# +# Note that if the destinations are all carbon-caches then this should +# exactly match the webapp's CARBONLINK_HOSTS setting in terms of +# instances listed (order matters!). +# +# If using RELAY_METHOD = rules, all destinations used in relay-rules.conf +# must be defined in this list +DESTINATIONS = 127.0.0.1:2004 + +# This defines the maximum "message size" between carbon daemons. +# You shouldn't need to tune this unless you really know what you're doing. +MAX_DATAPOINTS_PER_MESSAGE = 500 +MAX_QUEUE_SIZE = 10000 + +# This is the percentage that the queue must be empty before it will accept +# more messages. For a larger site, if the queue is very large it makes sense +# to tune this to allow for incoming stats. So if you have an average +# flow of 100k stats/minute, and a MAX_QUEUE_SIZE of 3,000,000, it makes sense +# to allow stats to start flowing when you've cleared the queue to 95% since +# you should have space to accommodate the next minute's worth of stats +# even before the relay incrementally clears more of the queue +QUEUE_LOW_WATERMARK_PCT = 0.8 + +# Set this to False to drop datapoints when any send queue (sending datapoints +# to a downstream carbon daemon) hits MAX_QUEUE_SIZE. If this is True (the +# default) then sockets over which metrics are received will temporarily stop accepting +# data until the send queues fall below QUEUE_LOW_WATERMARK_PCT * MAX_QUEUE_SIZE. +USE_FLOW_CONTROL = True + +# Set this to True to enable whitelisting and blacklisting of metrics in +# CONF_DIR/whitelist and CONF_DIR/blacklist. If the whitelist is missing or +# empty, all metrics will pass through +# USE_WHITELIST = False + +# By default, carbon itself will log statistics (such as a count, +# metricsReceived) with the top level prefix of 'carbon' at an interval of 60 +# seconds. Set CARBON_METRIC_INTERVAL to 0 to disable instrumentation +CARBON_METRIC_PREFIX = collectd +CARBON_METRIC_INTERVAL = 600 + + +[aggregator] +LINE_RECEIVER_INTERFACE = 0.0.0.0 +LINE_RECEIVER_PORT = 2023 + +PICKLE_RECEIVER_INTERFACE = 0.0.0.0 +PICKLE_RECEIVER_PORT = 2024 + +# Set to false to disable logging of successful connections +LOG_LISTENER_CONNECTIONS = True + +# If set true, metric received will be forwarded to DESTINATIONS in addition to +# the output of the aggregation rules. If set false the carbon-aggregator will +# only ever send the output of aggregation. Default value is set to false and will not forward +FORWARD_ALL = False + +# Filenames of the configuration files to use for this instance of aggregator. +# Filenames are relative to CONF_DIR. +# +# AGGREGATION_RULES = aggregation-rules.conf +# REWRITE_RULES = rewrite-rules.conf + +# This is a list of carbon daemons we will send any relayed or +# generated metrics to. The default provided would send to a single +# carbon-cache instance on the default port. However if you +# use multiple carbon-cache instances then it would look like this: +# +# DESTINATIONS = 127.0.0.1:2004:a, 127.0.0.1:2104:b +# +# The format is comma-delimited IP:PORT:INSTANCE where the :INSTANCE part is +# optional and refers to the "None" instance if omitted. +# +# Note that if the destinations are all carbon-caches then this should +# exactly match the webapp's CARBONLINK_HOSTS setting in terms of +# instances listed (order matters!). +DESTINATIONS = 127.0.0.1:2004 + +# If you want to add redundancy to your data by replicating every +# datapoint to more than one machine, increase this. +REPLICATION_FACTOR = 1 + +# This is the maximum number of datapoints that can be queued up +# for a single destination. Once this limit is hit, we will +# stop accepting new data if USE_FLOW_CONTROL is True, otherwise +# we will drop any subsequently received datapoints. +MAX_QUEUE_SIZE = 10000 + +# Set this to False to drop datapoints when any send queue (sending datapoints +# to a downstream carbon daemon) hits MAX_QUEUE_SIZE. If this is True (the +# default) then sockets over which metrics are received will temporarily stop accepting +# data until the send queues fall below 80% MAX_QUEUE_SIZE. +USE_FLOW_CONTROL = True + +# This defines the maximum "message size" between carbon daemons. +# You shouldn't need to tune this unless you really know what you're doing. +MAX_DATAPOINTS_PER_MESSAGE = 500 + +# This defines how many datapoints the aggregator remembers for +# each metric. Aggregation only happens for datapoints that fall in +# the past MAX_AGGREGATION_INTERVALS * intervalSize seconds. +MAX_AGGREGATION_INTERVALS = 5 + +# By default (WRITE_BACK_FREQUENCY = 0), carbon-aggregator will write back +# aggregated data points once every rule.frequency seconds, on a per-rule basis. +# Set this (WRITE_BACK_FREQUENCY = N) to write back all aggregated data points +# every N seconds, independent of rule frequency. This is useful, for example, +# to be able to query partially aggregated metrics from carbon-cache without +# having to first wait rule.frequency seconds. +# WRITE_BACK_FREQUENCY = 0 + +# Set this to True to enable whitelisting and blacklisting of metrics in +# CONF_DIR/whitelist and CONF_DIR/blacklist. If the whitelist is missing or +# empty, all metrics will pass through +# USE_WHITELIST = False + +# By default, carbon itself will log statistics (such as a count, +# metricsReceived) with the top level prefix of 'carbon' at an interval of 60 +# seconds. Set CARBON_METRIC_INTERVAL to 0 to disable instrumentation +CARBON_METRIC_PREFIX = collectd +CARBON_METRIC_INTERVAL = 600 diff --git a/etc/tendrl/monitoring-integration/graphite-web.conf.sample b/etc/tendrl/monitoring-integration/graphite-web.conf.sample new file mode 100644 index 0000000..5e1ddd8 --- /dev/null +++ b/etc/tendrl/monitoring-integration/graphite-web.conf.sample @@ -0,0 +1,42 @@ +# Graphite Web Basic mod_wsgi vhost + +Listen 10080 + + + ServerName graphite-web + DocumentRoot "/usr/share/graphite/webapp" + ErrorLog /var/log/httpd/graphite-web-error.log + CustomLog /var/log/httpd/graphite-web-access.log common + + Header set Access-Control-Allow-Origin "*" + Header set Access-Control-Allow-Methods "GET, OPTIONS" + Header set Access-Control-Allow-Headers "origin, authorization, accept" + Header set Access-Control-Allow-Credentials true + + WSGIScriptAlias / /usr/share/graphite/graphite-web.wsgi + WSGIImportScript /usr/share/graphite/graphite-web.wsgi process-group=%{GLOBAL} application-group=%{GLOBAL} + + + SetHandler None + + + Alias /media/ "/usr/lib/python2.7/site-packages/django/contrib/admin/media/" + + SetHandler None + + + + + # Apache 2.4 + Order Deny,Allow + Allow from all + Require all granted + + + # Apache 2.2 + Order Deny,Allow + Allow from all + Require all granted + + + diff --git a/etc/tendrl/monitoring-integration/monitoring-integration.conf.yaml.sample b/etc/tendrl/monitoring-integration/monitoring-integration.conf.yaml.sample new file mode 100644 index 0000000..353fa70 --- /dev/null +++ b/etc/tendrl/monitoring-integration/monitoring-integration.conf.yaml.sample @@ -0,0 +1,19 @@ +dashboards: + - tendrl-gluster-at-a-glance + - tendrl-gluster-hosts + - tendrl-gluster-volumes + - tendrl-gluster-bricks + +home_dashboard: tendrl-gluster-at-a-glance + +credentials: + user: admin + password: admin + +datasource_name: 'Graphite' + +access: direct + +isDefault: true + + diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e68ec50 --- /dev/null +++ b/setup.py @@ -0,0 +1,123 @@ +import re +from setuptools import Command +from setuptools import find_packages +from setuptools import setup +import subprocess +try: + # Python 2 backwards compat + from __builtin__ import raw_input as input +except ImportError: + pass + + +def read_module_contents(): + with open('version.py') as app_init: + return app_init.read() + + +def read_spec_contents(): + with open('monitoring-integration.spec') as spec: + return spec.read() + +module_file = read_module_contents() +metadata = dict(re.findall("__([a-z]+)__\s*=\s*'([^']+)'", module_file)) +version = metadata['version'] + + +class BumpVersionCommand(Command): + """Bump the __version__ number and commit all changes.""" + + user_options = [('version=', 'v', 'version number to use')] + + def initialize_options(self): + new_version = metadata['version'].split('.') + new_version[-1] = str(int(new_version[-1]) + 1) # Bump the final part + self.version = ".".join(new_version) + + def finalize_options(self): + pass + + def run(self): + + print('old version: %s new version: %s' % + (metadata['version'], self.version)) + try: + input('Press enter to confirm, or ctrl-c to exit >') + except KeyboardInterrupt: + raise SystemExit("\nNot proceeding") + + old = "__version__ = '%s'" % metadata['version'] + new = "__version__ = '%s'" % self.version + module_content = read_module_contents() + with open('version.py', 'w') as fileh: + fileh.write(module_content.replace(old, new)) + + old = 'Version: %s' % metadata['version'] + new = 'Version: %s' % self.version + spec_file = read_spec_contents() + with open('monitoring-integration.spec', 'w') as fileh: + fileh.write(spec_file.replace(old, new)) + + # Commit everything with a standard commit message + cmd = ['git', 'commit', '-a', '-m', 'version %s' % self.version] + print(' '.join(cmd)) + subprocess.check_call(cmd) + + +class ReleaseCommand(Command): + """Tag and push a new release.""" + + user_options = [('sign', 's', 'GPG-sign the Git tag and release files')] + + def initialize_options(self): + self.sign = False + + def finalize_options(self): + pass + + def run(self): + # Create Git tag + tag_name = 'v%s' % version + cmd = ['git', 'tag', '-a', tag_name, '-m', 'version %s' % version] + if self.sign: + cmd.append('-s') + print(' '.join(cmd)) + subprocess.check_call(cmd) + + # Push Git tag to origin remote + cmd = ['git', 'push', 'origin', tag_name] + print(' '.join(cmd)) + subprocess.check_call(cmd) + + # Push package to pypi + # cmd = ['python', 'setup.py', 'sdist', 'upload'] + # if self.sign: + # cmd.append('--sign') + # print(' '.join(cmd)) + # subprocess.check_call(cmd) +setup( + name="monitoring-integration", + version="1.0.0", + author="Rishubh Jain", + author_email="risjain@redhat.com", + description=("Integration of tendrl with grafana and" + " creating default dashboard in grafana"), + license="LGPL-2.1+", + keywords="", + packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", + "tests"]), + url="http://www.redhat.com", + namespace_packages=['tendrl'], + long_description="", + classifiers=[ + "Development Status :: 4 - Beta" + ], + zip_safe=False, + install_requires=[ + "ruamel.yaml", + "maps", + "requests" + ], + include_package_data=True, + cmdclass={'bumpversion': BumpVersionCommand, 'release': ReleaseCommand} +) diff --git a/tendrl/__init__.py b/tendrl/__init__.py new file mode 100644 index 0000000..de40ea7 --- /dev/null +++ b/tendrl/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/tendrl/monitoring_integration/__init__.py b/tendrl/monitoring_integration/__init__.py new file mode 100644 index 0000000..02cb9a4 --- /dev/null +++ b/tendrl/monitoring_integration/__init__.py @@ -0,0 +1,79 @@ +import __builtin__ +import traceback +import sys +import json + + +import maps + + +from tendrl.monitoring_integration.grafana import utils +from tendrl.monitoring_integration.grafana import exceptions +from tendrl.monitoring_integration.grafana import dashboard +from tendrl.monitoring_integration.grafana import datasource + + +def main(): + + # Creating Default Dashboards + dashboards = [] + config = utils.get_conf("/etc/tendrl/monitoring-integration/" + + "monitoring-integration.conf.yaml") + setattr(__builtin__, "NS", maps.NamedDict()) + setattr(NS, "conf", config) + + dashboards = dashboard.get_all_dashboards() + + title = [] + + for dashboard_json in dashboards: + title.append(dashboard_json["uri"].split('/')[1]) + + for dashboard_json in config.dashboards: + if dashboard_json in title: + sys.stdout.write('\n' + "Dashboard " + str(dashboard_json) + + " already exists" + '\n') + continue + response = dashboard.create_dashboard(dashboard_json) + + if response.status_code == 200: + sys.stdout.write('\n' + "Dashboard " + str(dashboard_json) + + " uploaded successfully" + '\n') + else: + sys.stdout.write('\n' + "Dashboard " + str(dashboard_json) + + " upload failed with error code " + + str(response.status_code) + '\n') + try: + dashboard_json = dashboard.get_dashboard(config.home_dashboard) + + if 'dashboard' in dashboard_json: + dashboard_id = dashboard_json.get('dashboard').get('id') + response = dashboard.set_home_dashboard(dashboard_id) + if response.status_code == 200: + sys.stdout.write('\n' + "Dashboard " + + str(config.home_dashboard) + + " is set as home dashboard" + '\n') + else: + sys.stdout.write('\n' + str(dashboard_json.get('message')) + '\n') + except exceptions.ConnectionFailedException: + traceback.print_exc() + raise exceptions.ConnectionFailedException + + # Creating datasource + response = datasource.create_datasource() + if response.status_code == 200: + sys.stdout.write('\n' + "Datasource " + + " uploaded successfully" + '\n') + else: + if isinstance(json.loads(response._content), list): + message = str(json.loads(response._content)[0]["message"]) + else: + message = str(json.loads(response._content)["message"]) + sys.stdout.write('\n' + "Datasource " + + " upload failed with" + '\n' + "Message \"" + + message + "\"" + + " and Error code " + str(response.status_code) + '\n') + + +if __name__ == '__main__': + main() diff --git a/tendrl/monitoring_integration/grafana/__init__.py b/tendrl/monitoring_integration/grafana/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tendrl/monitoring_integration/grafana/config.py b/tendrl/monitoring_integration/grafana/config.py new file mode 100644 index 0000000..7bdd3e3 --- /dev/null +++ b/tendrl/monitoring_integration/grafana/config.py @@ -0,0 +1,2 @@ +class Config(object): + pass diff --git a/tendrl/monitoring_integration/grafana/dashboard.py b/tendrl/monitoring_integration/grafana/dashboard.py new file mode 100644 index 0000000..c58df6d --- /dev/null +++ b/tendrl/monitoring_integration/grafana/dashboard.py @@ -0,0 +1,96 @@ +import __builtin__ +import os +import json +import traceback + + +from requests import get, post, put + +from tendrl.monitoring_integration.grafana import utils +from tendrl.monitoring_integration.grafana import exceptions + +HEADERS = {"Accept": "application/json", + "Content-Type": "application/json" + } + + +'''Create Dashboard''' + + +def post_dashboard(dashboard_json): + config = NS.conf + if utils.port_open(config.grafana_port, config.grafana_host): + upload_str = json.dumps(dashboard_json) + resp = post("http://{}:{}/api/dashboards/" + "db".format(config.grafana_host, + config.grafana_port), + headers=HEADERS, + auth=config.credentials, + data=upload_str) + else: + raise exceptions.ConnectionFailedException + + return resp + + +def get_dashboard(dashboard_name): + config = NS.conf + if utils.port_open(config.grafana_port, config.grafana_host): + resp = get("http://{}:{}/api/dashboards/" + "db/{}".format(config.grafana_host, + config.grafana_port, + dashboard_name), + auth=config.credentials) + else: + raise exceptions.ConnectionFailedException + return resp.json() + + +def get_all_dashboards(): + config = NS.conf + if utils.port_open(config.grafana_port, config.grafana_host): + resp = get("http://{}:{}/api/search/" + .format(config.grafana_host, + config.grafana_port), + auth=config.credentials) + else: + raise exceptions.ConnectionFailedException + return resp.json() + + +def set_home_dashboard(dash_id): + config = NS.conf + if utils.port_open(config.grafana_port, config.grafana_host): + resp = put('http://{}:{}/api/org/' + 'preferences'.format(config.grafana_host, + config.grafana_port), + headers=HEADERS, + auth=config.credentials, + data=json.dumps({"name": "Main Org.", + "theme": "light", + "homeDashboardId": dash_id})) + else: + raise exceptions.ConnectionFailedException + return resp + + +def create_dashboard(dashboard_name,dashboard_dir = None): + if not dashboard_dir: + dashboard_dir = os.path.join(os.path.dirname(__file__), "dashboards") + dashboard_path = os.path.join(dashboard_dir, + "{}.json".format(dashboard_name)) + if os.path.exists(dashboard_path): + + dashboard_data = utils.fread(dashboard_path) + + try: + dashboard_json = json.loads(dashboard_data) + response = post_dashboard(dashboard_json) + return response + + except exceptions.ConnectionFailedException: + traceback.print_stack() + raise exceptions.ConnectionFailedException + + else: + raise exceptions.FileNotFoundException diff --git a/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-at-a-glance.json b/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-at-a-glance.json new file mode 100644 index 0000000..0c365b9 --- /dev/null +++ b/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-at-a-glance.json @@ -0,0 +1,1547 @@ +{ + "dashboard":{ + "annotations": { + "list": [] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": true, + "id": null, + "links": [], + "refresh": "1m", + "rows": [ + { + "collapse": false, + "height": -1096, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Graphite", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "40px", + "id": 4, + "interval": null, + "links": [ + { + "dashUri": "db/tendrl-gluster-at-a-glance", + "dashboard": "Tendrl - Gluster - at-a -glance", + "includeVars": true, + "keepTime": true, + "title": "Gluster Overview", + "type": "dashboard" + } + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "minSpan": 1, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "" + } + ], + "thresholds": "", + "title": "", + "transparent": true, + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "Overview", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Graphite", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "40px", + "id": 1, + "interval": null, + "links": [ + { + "dashUri": "db/tendrl-gluster-hosts", + "dashboard": "Tendrl - Gluster - Hosts", + "includeVars": true, + "keepTime": true, + "targetBlank": false, + "title": "Hosts Overview", + "type": "dashboard" + } + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "minSpan": 1, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "" + } + ], + "thresholds": "", + "title": "", + "transparent": true, + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "Hosts", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Graphite", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "40", + "id": 2, + "interval": null, + "links": [ + { + "dashUri": "db/tendrl-gluster-volumes", + "dashboard": "Tendrl - Gluster - Volumes", + "includeVars": true, + "keepTime": true, + "params": "", + "targetBlank": false, + "title": "Tendrl - Gluster - Volumes", + "type": "dashboard" + } + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "minSpan": 1, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "" + } + ], + "thresholds": "", + "title": "", + "transparent": true, + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "Volumes", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Graphite", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "50px", + "id": 3, + "interval": null, + "links": [ + { + "dashUri": "db/tendrl-gluster-bricks", + "dashboard": "Tendrl - Gluster - Bricks", + "includeVars": true, + "keepTime": true, + "params": "", + "targetBlank": false, + "title": "Bricks Overview", + "type": "dashboard" + } + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "minSpan": 1, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "30%", + "prefix": "", + "prefixFontSize": "30%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "" + } + ], + "thresholds": "", + "title": "", + "transparent": true, + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "Bricks", + "value": "null" + } + ], + "valueName": "avg" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 155, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 7, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [], + "thresholds": "", + "title": "Status", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "" + } + ], + "thresholds": "", + "title": "Quorum Status", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.nodes_count.total" + } + ], + "thresholds": "", + "title": "Hosts", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 9, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.volume_count.total" + } + ], + "thresholds": "", + "title": "Volumes", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 10, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.brick_count.total" + } + ], + "thresholds": "", + "title": "Bricks", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 255, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Graphite", + "fill": 1, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "alias(averageSeries(tendrl.clusters.$cluster_id.volumes.*.nodes.*.bricks.*.utilization.percent-percent_bytes), '$cluster_id')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Cluster Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.nodes_count.up" + } + ], + "thresholds": "", + "title": "Hosts Up", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.nodes_count.down" + } + ], + "thresholds": "", + "title": "Hosts Down", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.volume_count.up" + } + ], + "thresholds": "", + "title": "Volumes Up", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 13, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.volume_count.down" + } + ], + "thresholds": "", + "title": "Volumes Down", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 16, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [], + "thresholds": "", + "title": "Bricks Up", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 17, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [], + "thresholds": "", + "title": "Bricks Down", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 289, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Graphite", + "fill": 1, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "alias(averageSeries(tendrl.clusters.$cluster_id.volumes.*.nodes.*.bricks.*.iops.gauge-read), '$cluster_id')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "IOPS Reads", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "alias(averageSeries(tendrl.clusters.$cluster_id.volumes.*.nodes.*.bricks.*.iops.gauge-write), '$cluster_id')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "IOPS Writes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Graphite", + "fill": 1, + "id": 19, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "alias(averageSeries(tendrl.clusters.$cluster_id.volumes.*.nodes.*.bricks.*.inode_utilization.percent-percent_bytes), '$cluster_id')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Inode Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "text": "No Data Found", + "value": "No Data Found" + }, + "datasource": "Graphite", + "hide": 0, + "includeAll": false, + "label": "Cluster Id", + "multi": false, + "name": "cluster_id", + "options": [], + "query": "tendrl.clusters.*", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now/d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Tendrl - Gluster - At - A - Glance", + "version": 188 +} +} diff --git a/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-bricks.json b/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-bricks.json new file mode 100644 index 0000000..223444d --- /dev/null +++ b/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-bricks.json @@ -0,0 +1,271 @@ +{ + "dashboard":{ + "annotations": { + "list": [] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [], + "refresh": "1m", + "rows": [ + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "alias(tendrl.clusters.$cluster_id.nodes.*.bricks.$brick_name.utilization.percent-percent_bytes, '$brick_name')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bricks Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "alias(tendrl.clusters.$cluster_id.nodes.*.bricks.$brick_name.inode_utilization.percent-percent_bytes, '$brick_name')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Inode Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "tags": [], + "text": "No Data Found", + "value": "No Data Found" + }, + "datasource": "Graphite", + "hide": 0, + "includeAll": false, + "label": "cluster Id", + "multi": false, + "name": "cluster_id", + "options": [], + "query": "tendrl.clusters.*", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": "All", + "current": { + "text": "No Data Found", + "value": "No Data Found" + }, + "datasource": "Graphite", + "hide": 0, + "includeAll": false, + "label": "Brick Name", + "multi": false, + "name": "brick_name", + "options": [], + "query": "tendrl.clusters.$cluster_id.nodes.*.bricks.*", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now/d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Tendrl - Gluster - Bricks", + "version": 59 +} +} diff --git a/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-hosts.json b/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-hosts.json new file mode 100644 index 0000000..4aebf12 --- /dev/null +++ b/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-hosts.json @@ -0,0 +1,869 @@ +{ + "dashboard":{ + "annotations": { + "list": [] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": true, + "id": null, + "links": [], + "refresh": "1m", + "rows": [ + { + "collapse": false, + "height": 106, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 6, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "10", + "text": "hello", + "to": "100" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "refId": "A", + "target": "sumSeries(tendrl.clusters.$cluster_id.nodes.$host_name.memory.memory-free)" + } + ], + "thresholds": "", + "title": "Memory Free", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 9, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "10", + "text": "hello", + "to": "100" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "hide": false, + "refId": "B", + "target": "sumSeries(tendrl.clusters.$cluster_id.nodes.$host_name.memory.memory-used)" + } + ], + "thresholds": "", + "title": "Memory Used", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "iii", + "value": "6.50" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": null, + "description": "", + "format": "decbytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "", + "format": "time_series", + "intervalFactor": 2, + "refId": "A", + "target": "sum(tendrl.clusters.$cluster_id.nodes.$host_name.df-*.df_complex-*) - sum(tendrl.clusters.$cluster_id..nodes.$host_name.df-*.df_complex-used)", + "textEditor": true + } + ], + "thresholds": "", + "title": "Storage Free", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": null, + "description": "", + "format": "decbytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 10, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "", + "format": "time_series", + "intervalFactor": 2, + "refId": "A", + "target": "sum(tendrl.clusters.$cluster_id.nodes.$host_name.df-*.df_complex-used)", + "textEditor": true + } + ], + "thresholds": "60, 80", + "title": "Storage Used", + "transparent": true, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 214, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode($my_app.clusters.$cluster_id.nodes.$host_name.memory.percent-used, 4)" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "hide": true, + "refId": "B", + "target": "sumSeries($my_app.clusters.$cluster_id.nodes.$host_name.df-*.df_complex-used)" + }, + { + "hide": true, + "refId": "C", + "target": "sumSeries($my_app.clusters.$cluster_id.nodes.$host_name.df-*.df_complex-*)" + }, + { + "hide": false, + "refId": "D", + "target": "alias(asPercent(#B, #C), '$host_name')", + "targetFull": "alias(asPercent(sumSeries($my_app.clusters.$cluster_id.nodes.$host_name.df-*.df_complex-used), sumSeries($my_app.clusters.$cluster_id.nodes.$host_name.df-*.df_complex-*)), '$host_name')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Storage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Graphite", + "fill": 1, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "aliasByNode($my_app.clusters.$cluster_id.nodes.$host_name.swap.percent-used, 4)" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Swap", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "hide": true, + "refId": "B", + "target": "sumSeries($my_app.clusters.$cluster_id.nodes.$host_name.cpu.percent-user)" + }, + { + "hide": true, + "refId": "C", + "target": "sumSeries($my_app.clusters.$cluster_id.nodes.$host_name.cpu.percent-system)" + }, + { + "refId": "A", + "target": "alias(sumSeries(#B, #C), '$host_name')", + "targetFull": "alias(sumSeries(sumSeries($my_app.clusters.$cluster_id.nodes.$host_name.cpu.percent-user), sumSeries($my_app.clusters.$cluster_id.nodes.$host_name.cpu.percent-system)), '$host_name')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 239, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "B", + "target": "alias($my_app.clusters.$cluster_id.nodes.$host_name.network_throughput-cluster_network.gauge-used, '$host_name')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Throughput - Cluster Network", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "text": "tendrl", + "value": "tendrl" + }, + "datasource": "Graphite", + "hide": 2, + "includeAll": false, + "label": "My App", + "multi": false, + "name": "my_app", + "options": [], + "query": "tendrl", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "No Data Found", + "value": "No Data Found" + }, + "datasource": "Graphite", + "hide": 0, + "includeAll": false, + "label": "Cluster Id", + "multi": false, + "name": "cluster_id", + "options": [], + "query": "tendrl.clusters.*", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "No Data Found", + "value": "No Data Found" + }, + "datasource": "Graphite", + "hide": 0, + "includeAll": false, + "label": "Host Name", + "multi": false, + "name": "host_name", + "options": [], + "query": "tendrl.clusters.$cluster_id.nodes.*", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now/d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Tendrl - Gluster - Hosts", + "version": 73 +} + +} diff --git a/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-volumes.json b/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-volumes.json new file mode 100644 index 0000000..8f9fa2c --- /dev/null +++ b/tendrl/monitoring_integration/grafana/dashboards/tendrl-gluster-volumes.json @@ -0,0 +1,431 @@ +{ + "dashboard":{ + "annotations": { + "list": [] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [], + "refresh": false, + "rows": [ + { + "collapse": false, + "height": 172, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 2, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 4, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.volumes.$volume_name.status" + } + ], + "thresholds": "", + "title": "Volume Status", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + }, + { + "op": "=", + "text": "Started", + "value": "0" + }, + { + "op": "=", + "text": "Degraded", + "value": "1" + }, + { + "op": "=", + "text": "Stopped", + "value": "2" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 3, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 4, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.volumes.$volume_name.brick_count.total" + } + ], + "thresholds": "", + "title": "Brick Count", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 4, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "tendrl.clusters.$cluster_id.volumes.$volume_name.connections_count" + } + ], + "thresholds": "", + "title": "Connection Count", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 317, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "target": "alias(averageSeries(tendrl.clusters.$cluster_id.volumes.$volume_name.nodes.*.bricks.*.utilization.percent-percent_bytes), '$volume_name')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Volume Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "text": "No Data Found", + "value": "No Data Found" + }, + "datasource": "Graphite", + "hide": 0, + "includeAll": false, + "label": "Cluster Id", + "multi": false, + "name": "cluster_id", + "options": [], + "query": "tendrl.clusters.*", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "No Data Found", + "value": "No Data Found" + }, + "datasource": "Graphite", + "hide": 0, + "includeAll": false, + "label": "Volume Name", + "multi": false, + "name": "volume_name", + "options": [], + "query": "tendrl.clusters.$cluster_id.volumes.*", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now/d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Tendrl - Gluster - Volumes", + "version": 30 +} +} diff --git a/tendrl/monitoring_integration/grafana/datasource.py b/tendrl/monitoring_integration/grafana/datasource.py new file mode 100644 index 0000000..078f019 --- /dev/null +++ b/tendrl/monitoring_integration/grafana/datasource.py @@ -0,0 +1,53 @@ +import __builtin__ +import json +import traceback + + +from requests import post + + +from tendrl.monitoring_integration.grafana import utils +from tendrl.monitoring_integration.grafana import exceptions + +HEADERS = {"Accept": "application/json", + "Content-Type": "application/json" + } + + +''' Create Datasource ''' + + +def post_datasource(datasource_json): + + if utils.port_open(NS.conf.grafana_port, NS.conf.grafana_host): + resp = post("http://{}:{}/api/datasources" + .format(NS.conf.grafana_host, + NS.conf.grafana_port), + headers=HEADERS, + auth=NS.conf.credentials, + data=datasource_json) + + else: + raise exceptions.ConnectionFailedException + + return resp + + +def create_datasource(): + + try: + config = NS.conf + url = "http://" + str(config.datasource_host) + ":" \ + + str(config.datasource_port) + datasource_json = {'name': config.datasource_name, + 'type': config.datasource_type, + 'url': url, + 'access': config.access, + 'basicAuth': config.basicAuth, + 'isDefault': config.isDefault} + response = post_datasource(json.dumps(datasource_json)) + return response + + except exceptions.ConnectionFailedException: + traceback.print_stack() + raise exceptions.ConnectionFailedException diff --git a/tendrl/monitoring_integration/grafana/exceptions.py b/tendrl/monitoring_integration/grafana/exceptions.py new file mode 100644 index 0000000..43df842 --- /dev/null +++ b/tendrl/monitoring_integration/grafana/exceptions.py @@ -0,0 +1,18 @@ +class ConfigNotFoundException(Exception): + pass + + +class DashboardException(Exception): + pass + + +class FileNotFoundException(Exception): + pass + + +class InvalidConfigurationException(Exception): + pass + + +class ConnectionFailedException(Exception): + pass diff --git a/tendrl/monitoring_integration/grafana/utils.py b/tendrl/monitoring_integration/grafana/utils.py new file mode 100644 index 0000000..7b36ba2 --- /dev/null +++ b/tendrl/monitoring_integration/grafana/utils.py @@ -0,0 +1,91 @@ +import os +import socket +import sys + + +from ruamel import yaml + + +from tendrl.monitoring_integration.grafana import exceptions +from tendrl.monitoring_integration.grafana import config + + +def get_conf(file_name): + + try: + yaml_config = load_config(file_name) + + conf = config.Config() + # Graphite and Grafana will be running on localhost + conf.grafana_host = yaml_config.get('grafana_host', "localhost") + conf.grafana_port = yaml_config.get('grafana_port', 3000) + conf.datasource_host = yaml_config.get('datasource_host', "localhost") + conf.datasource_port = yaml_config.get('datasource_port', 10080) + + # Datasource name in Grafana + conf.datasource_name = yaml_config.get('datasource_name', "Graphite") + + # Default values for graphite datasource + conf.datasource_type = yaml_config.get('datasource_type', "graphite") + conf.basicAuth = yaml_config.get('basicAuth', False) + + # Datasource configs + conf.access = yaml_config.get('access', "direct") + conf.isDefault = yaml_config.get('isDefault', True) + + # Grafana related configs + conf.dashboards = yaml_config.get('dashboards', []) + conf.datasource = yaml_config.get('datasource', []) + conf.auth = yaml_config.get('credentials', None) + if conf.auth: + conf.credentials = (conf.auth.get('user'), + conf.auth.get('password')) + conf.home_dashboard = yaml_config.get('home_dashboard', + 'home_dashboard') + conf.yaml = yaml_config + except exceptions.InvalidConfigException: + err = exceptions.InvalidConfigurationException( + "Error in configuration %s" % (file_name) + ) + sys.stderr.write(str(err)) + raise err + + return conf + + +def port_open(port, host='localhost'): + """ + Check a given port is accessible + :param port: (int) port number to check + :param host: (str)hostname to check, default is localhost + :return: (bool) true if the port is accessible + """ + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + sock.connect_ex((host, port)) + sock.shutdown(socket.SHUT_RDWR) + sock.close() + return True + except socket.error: + return False + + +def load_config(yaml_cfg_file_path): + + if not os.path.exists(yaml_cfg_file_path): + err = exceptions.ConfigNotFoundException( + "Configuration not found at %s" % + (yaml_cfg_file_path) + ) + sys.stderr.write(str(err)) + raise err + + with open(yaml_cfg_file_path, 'r') as ymlfile: + return yaml.safe_load(ymlfile) + + +def fread(file_name): + with open(file_name) as f: + f_data = f.read() + return f_data diff --git a/tendrl/monitoring_integration/tests/__init__.py b/tendrl/monitoring_integration/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tendrl/monitoring_integration/tests/fixtures/test_dashboard.json b/tendrl/monitoring_integration/tests/fixtures/test_dashboard.json new file mode 100644 index 0000000..8182dda --- /dev/null +++ b/tendrl/monitoring_integration/tests/fixtures/test_dashboard.json @@ -0,0 +1,15 @@ +{ + "dashboard": { + "id": null, + "title": "Production Overview", + "tags": [ "templated" ], + "timezone": "browser", + "rows": [ + { + } + ], + "schemaVersion": 6, + "version": 0 + }, + "overwrite": false +} diff --git a/tendrl/monitoring_integration/tests/fixtures/test_monitoring-integration.conf.yaml b/tendrl/monitoring_integration/tests/fixtures/test_monitoring-integration.conf.yaml new file mode 100644 index 0000000..f95f43b --- /dev/null +++ b/tendrl/monitoring_integration/tests/fixtures/test_monitoring-integration.conf.yaml @@ -0,0 +1,16 @@ +dashboards: + - test_dashboard + +home_dashboard: test_dashboard + +credentials: + user: admin + password: admin + +datasource_name: 'Graphite' + +access: direct + +isDefault: true + + diff --git a/tendrl/monitoring_integration/tests/test_create_dashboard.py b/tendrl/monitoring_integration/tests/test_create_dashboard.py new file mode 100644 index 0000000..d27d360 --- /dev/null +++ b/tendrl/monitoring_integration/tests/test_create_dashboard.py @@ -0,0 +1,24 @@ +import __builtin__ +import os + + +import maps +from mock import patch + + +from tendrl.monitoring_integration.grafana import utils +from tendrl.monitoring_integration.grafana import dashboard + + +def test_creat_dashboard(): + grafana_conf = os.path.join(os.path.dirname(__file__), "fixtures", + "test_monitoring-integration.conf.yml") + config = utils.get_conf(grafana_conf) + setattr(__builtin__, "NS", maps.NamedDict()) + setattr(NS, "conf", config) + with patch.object(dashboard, 'post_dashboard', + return_value=maps.NamedDict(status_code=200)): + dashboard_dir = os.path.join(os.path.dirname(__file__), "fixtures") + for dashboard_json in NS.conf.dashboards: + ret = create_dashboard(dashboard_json,dashboard_dir) + assert ret == 200 diff --git a/tendrl/monitoring_integration/tests/test_create_datasource.py b/tendrl/monitoring_integration/tests/test_create_datasource.py new file mode 100644 index 0000000..5b7f391 --- /dev/null +++ b/tendrl/monitoring_integration/tests/test_create_datasource.py @@ -0,0 +1,21 @@ +import __builtin__ +import os + + +import maps +from mock import patch + + +from tendrl.monitoring_integration.grafana import utils +from tendrl.monitoring_integration.grafana import datasource + + +def test_create_datasource(): + grafana_conf = os.path.join(os.path.dirname(__file__), "fixtures", + "test_monitoring-integration.conf.yml") + setattr(__builtin__, "NS", maps.NamedDict()) + setattr(NS, "conf", config) + with patch.object(datasource, 'post_datasource', + return_value=maps.NamedDict(status_code=200)): + ret = create_datasource() + assert ret == 200 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..cae3edf --- /dev/null +++ b/tox.ini @@ -0,0 +1,55 @@ +# This is configuration file of tox, which run unit tests and other checks. +# See: https://tox.readthedocs.io/en/latest/index.html + +[tox] +minversion = 2.0 +envlist = py27 + +# Test env defaults, runs unit tests via pytest. +# In this case, the "default" means that py27 or other test enviroment +# without explicit definition would use this configuration. + +[testenv] +passenv = + cover: CI TRAVIS TRAVIS_* +deps = + pytest + mock + coverage + pytest-cov + cover: codecov +commands = + python -m pytest --cov=tendrl tendrl/monitoring_integration/tests + cover: codecov + +# Runs PEP8 checks on the source code via flake8 tool +[testenv:pep8] +skip_install = true +deps = + flake8 +commands = flake8 tendrl + +# Runs Unused code checks on the source code via vulture tool +[testenv:vulture] +skip_install = true +deps = + vulture +commands = vulture tendrl + +# Runs check_commit_msg.py script (used by Travis CI, see .travis.yml) +[testenv:check_commit_msg] +skip_install = true +deps = requests +passenv = TRAVIS_COMMIT_MSG +commands = python check_commit_msg.py + +[flake8] +# see: http://flake8.readthedocs.io/en/latest/ +show-source = True +builtins = NS +exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build + +[pytest] +# pytest configuration +# see: http://docs.pytest.org/en/latest/customize.html#adding-default-options +# addopts = -v diff --git a/version.py b/version.py new file mode 100644 index 0000000..1f356cc --- /dev/null +++ b/version.py @@ -0,0 +1 @@ +__version__ = '1.0.0'