Merge "Add delete command to CLI"

This commit is contained in:
Jenkins 2015-10-23 14:28:22 +00:00 committed by Gerrit Code Review
commit 84a2b25e06
7 changed files with 116 additions and 28 deletions

View File

@ -26,6 +26,13 @@ OPTIONS
COMMANDS
========
Delete Command
--------------
``grafana-dashboard`` [options] delete <path>
Delete each specified dashboard from the parsed yaml files.
Update Command
--------------

View File

@ -54,6 +54,14 @@ class Builder(object):
url = 'http://localhost:8080'
return Grafana(url, key)
def delete_dashboard(self, path):
self.load_files(path)
dashboards = self.parser.data.get('dashboard', {})
for name in dashboards:
LOG.debug('Deleting grafana dashboard %s', name)
self.grafana.dashboard.delete(name)
self.cache.set(name, '')
def load_files(self, path):
files_to_process = []
if os.path.isdir(path):

View File

@ -27,6 +27,11 @@ LOG = logging.getLogger(__name__)
class Client(object):
def delete(self):
LOG.info('Deleting dashboards in %s', self.args.path)
builder = Builder(self.config)
builder.delete_dashboard(self.args.path)
def main(self):
self.parse_arguments()
self.read_config()
@ -51,6 +56,12 @@ class Client(object):
subparsers = parser.add_subparsers(
title='commands')
parser_delete = subparsers.add_parser('delete')
parser_delete.add_argument(
'path', help='colon-separated list of paths to YAML files or'
' directories')
parser_delete.set_defaults(func=self.delete)
parser_update = subparsers.add_parser('update')
parser_update.add_argument(
'path', help='colon-separated list of paths to YAML files or'
@ -87,6 +98,7 @@ class Client(object):
def validate(self):
LOG.info('Validating dashboards in %s', self.args.path)
builder = Builder(self.config)
try:
builder.load_files(self.args.path)
print('SUCCESS!')

View File

@ -28,17 +28,6 @@ class Dashboard(object):
self.url = url
self.session = session
def assert_dashboard_exists(self, name):
"""Raise an exception if dashboard does not exist
:param name: URL friendly title of the dashboard
:type name: str
:raises Exception: if dashboard does not exist
"""
if not self.is_dashboard(name):
raise Exception('dashboard[%s] does not exist' % name)
def create(self, name, data, overwrite=False):
"""Create a new dashboard
@ -62,9 +51,23 @@ class Dashboard(object):
res = self.session.post(
self.url, data=json.dumps(dashboard))
res.raise_for_status()
self.assert_dashboard_exists(name)
if not self.is_dashboard(name):
raise Exception('dashboard[%s] does not exist' % name)
def delete(self, name):
"""Delete a dashboard
:param name: URL friendly title of the dashboard
:type name: str
:raises Exception: if dashboard failed to delete
"""
url = urljoin(self.url, name)
self.session.delete(url)
if self.is_dashboard(name):
raise Exception('dashboard[%s] failed to delete' % name)
def get(self, name):
"""Get a dashboard

34
tests/cmd/test_delete.py Normal file
View File

@ -0,0 +1,34 @@
# 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 re
from testtools import matchers
from tests.cmd.base import TestCase
class TestCaseDelete(TestCase):
def test_delete_without_path(self):
required = [
'.*?^usage: grafana-dashboards delete \[-h\] path',
'.*?^grafana-dashboards delete: error: (too few arguments|the '
'following arguments are required: path)',
]
stdout, stderr = self.shell('delete', exitcodes=[2])
for r in required:
self.assertThat(
(stdout + stderr),
matchers.MatchesRegex(r, re.DOTALL | re.MULTILINE))

View File

@ -26,17 +26,34 @@ class TestCaseBuilder(TestCase):
super(TestCaseBuilder, self).setUp()
self.builder = builder.Builder(self.config)
@mock.patch('grafana_dashboards.grafana.Dashboard.create')
def test_update_dashboard(self, mock_grafana):
dashboard = os.path.join(
@mock.patch('grafana_dashboards.grafana.Dashboard.delete')
def test_delete_dashboard(self, mock_grafana):
path = os.path.join(
os.path.dirname(__file__), 'fixtures/builder/dashboard-0001.yaml')
self.builder.update_dashboard(dashboard)
# Cache is empty, so we should update grafana.
# Create a dashboard.
self._update_dashboard(path)
# Create a new builder to avoid duplicate dashboards.
builder2 = builder.Builder(self.config)
# Delete same dashboard, ensure we delete it from grafana.
builder2.delete_dashboard(path)
self.assertEqual(mock_grafana.call_count, 1)
@mock.patch('grafana_dashboards.grafana.Dashboard.create')
def test_update_dashboard(self, mock_grafana):
path = os.path.join(
os.path.dirname(__file__), 'fixtures/builder/dashboard-0001.yaml')
# Create a dashboard.
self._update_dashboard(path)
# Create a new builder to avoid duplicate dashboards.
builder2 = builder.Builder(self.config)
# Update again with same dashboard, ensure we don't update grafana.
builder2.update_dashboard(dashboard)
builder2.update_dashboard(path)
self.assertEqual(mock_grafana.call_count, 0)
@mock.patch('grafana_dashboards.grafana.Dashboard.create')
def _update_dashboard(self, path, mock_grafana):
self.builder.update_dashboard(path)
# Cache is empty, so we should update grafana.
self.assertEqual(mock_grafana.call_count, 1)

View File

@ -58,15 +58,6 @@ class TestCaseGrafana(TestCase):
self.assertIn('Authorization', headers)
self.assertEqual(headers['Authorization'], 'Bearer %s' % apikey)
@requests_mock.Mocker()
def test_assert_dashboard_exists_failure(self, mock_requests):
mock_requests.get(
'/api/dashboards/db/new-dashboard', json=DASHBOARD_NOT_FOUND,
status_code=404)
self.assertRaises(
Exception, self.grafana.dashboard.assert_dashboard_exists,
'new-dashboard')
@requests_mock.Mocker()
def test_create_dashboard_new(self, mock_requests):
def post_callback(request, context):
@ -120,3 +111,19 @@ class TestCaseGrafana(TestCase):
data=data['dashboard'], overwrite=False)
self.assertEqual(mock_requests.call_count, 1)
@requests_mock.Mocker()
def test_delete_dashboard(self, mock_requests):
mock_requests.delete('/api/dashboards/db/new-dashboard')
mock_requests.get(
'/api/dashboards/db/new-dashboard', json=DASHBOARD_NOT_FOUND,
status_code=404)
self.grafana.dashboard.delete('new-dashboard')
@requests_mock.Mocker()
def test_delete_dashboard_failure(self, mock_requests):
mock_requests.delete('/api/dashboards/db/new-dashboard')
mock_requests.get(
'/api/dashboards/db/new-dashboard', json=CREATE_NEW_DASHBOARD)
self.assertRaises(
Exception, self.grafana.dashboard.delete, name='new-dashboard')