Add grafana-dashboards cli client

This is the first attempt at the CLI client.  Right now, we just support the
update function, which will blindly create a dashboard in grafana with ZERO
validation.  Additionally, we blindly override any existing dashboard that has
been created.

Signed-off-by: Paul Belanger <pabelanger@redhat.com>
This commit is contained in:
Paul Belanger 2015-05-06 13:02:55 -04:00
parent deea0b6f5a
commit e117767f9b
10 changed files with 240 additions and 0 deletions

View File

@ -0,0 +1,61 @@
# Copyright 2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import requests
import yaml
from oslo_config import cfg
grafana_opts = [
cfg.StrOpt(
'url', default='http://grafana.example.org',
help='URL for grafana server.'),
cfg.StrOpt(
'apikey', default='',
help='API key for access grafana.'),
]
grafana_group = None
list_opts = lambda: [(grafana_group, grafana_opts), ]
CONF = cfg.CONF
CONF.register_opts(grafana_opts)
class Grafana(object):
def __init__(self, url, key):
self.url = url
self.session = requests.Session()
self.session.headers.update({
'Authorization': 'Bearer %s' % key,
})
def create_dashboard(self, data, overwrite=False):
data['overwrite'] = overwrite
headers = {
'Content-Type': 'application/json',
}
res = self.session.post(
self.url, data=json.dumps(data), headers=headers)
res.raise_for_status()
class Builder(object):
def __init__(self):
self.grafana = Grafana(CONF.url, CONF.apikey)
def update_dashboard(self, path):
data = yaml.load(open(path))
self.grafana.create_dashboard(data, overwrite=True)

57
grafana_dashboards/cmd.py Normal file
View File

@ -0,0 +1,57 @@
# Copyright 2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import inspect
import sys
from oslo_config import cfg
from grafana_dashboards.builder import Builder
from grafana_dashboards import config
CONF = cfg.CONF
class Commands(object):
def __init__(self):
self.builder = Builder()
def execute(self):
exec_method = getattr(self, CONF.action.name)
args = inspect.getargspec(exec_method)
args.args.remove('self')
kwargs = {}
for arg in args.args:
kwargs[arg] = getattr(CONF.action, arg)
exec_method(**kwargs)
def update(self, path):
self.builder.update_dashboard(path)
def main():
def add_command_parsers(subparsers):
parser_update = subparsers.add_parser('update')
parser_update.add_argument(
'path', help='colon-separated list of paths to YAML files or'
' directories')
CONF.register_cli_opt(
cfg.SubCommandOpt('action', handler=add_command_parsers))
config.prepare_args(sys.argv)
Commands().execute()
sys.exit(0)

View File

@ -0,0 +1,22 @@
# Copyright 2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from grafana_dashboards import version
def prepare_args(argv):
cfg.CONF(
argv[1:], project='grafana_dashboards', version=version.version_info)

View File

@ -0,0 +1,29 @@
# Copyright 2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import voluptuous as v
class Dashboard(object):
def validate(self, data):
dashboard = {
v.Required('title'): v.All(str, v.Length(min=1)),
v.Optional('id'): int,
}
schema = v.Schema({
'dashboard': dashboard,
})
return schema(data)

View File

@ -0,0 +1,17 @@
# Copyright 2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from pbr.version import VersionInfo
version_info = VersionInfo('grafana-dashboards')

View File

@ -5,5 +5,6 @@
pbr>=0.6,!=0.7,<1.0
Babel>=1.3
oslo.config>=1.11.0
PyYAML>=3.1.0
voluptuous>=0.7

View File

@ -29,6 +29,12 @@ source-dir = doc/source
build-dir = doc/build
all_files = 1
[entry_points]
console_scripts =
grafana-dashboard=grafana_dashboards.cmd:main
oslo.config.opts =
grafyaml = grafana_dashboards.builder:list_opts
[upload_sphinx]
upload-dir = doc/build/html

View File

@ -0,0 +1,2 @@
dashboard:
title: New dashboard

View File

@ -0,0 +1,41 @@
# Copyright 2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import re
import yaml
from testtools import TestCase
from grafana_dashboards.schema import dashboard
FIXTURE_DIR = os.path.join(os.path.dirname(__file__),
'fixtures')
LAYOUT_RE = re.compile(r'^(dashboard)-.*\.yaml$')
class TestCaseSchemaDashboard(TestCase):
def test_layouts(self):
for fn in os.listdir(os.path.join(FIXTURE_DIR)):
schema = None
m = LAYOUT_RE.match(fn)
if not m:
continue
layout = os.path.join(FIXTURE_DIR, fn)
data = yaml.load(open(layout))
if m.group(1) == 'dashboard':
schema = dashboard.Dashboard()
schema.validate(data)

View File

@ -12,6 +12,10 @@ deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands = python setup.py test --slowest --testr-args='{posargs}'
[testenv:genconfig]
commands =
oslo-config-generator --namespace=grafyaml --config-file=etc/grafyaml/grafyaml.conf
[testenv:pep8]
commands = flake8