]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/ci/check_grafana_uids.py
import 15.2.0 Octopus source
[ceph.git] / ceph / src / pybind / mgr / dashboard / ci / check_grafana_uids.py
CommitLineData
92f5a8d4
TL
1# -*- coding: utf-8 -*-
2# pylint: disable=F0401
3"""
4This script does:
5* Scan through Angular html templates and extract <cd-grafana> tags
6* Check if every tag has a corresponding Grafana dashboard by `uid`
7
8Usage:
9 python <script> <angular_app_dir> <grafana_dashboard_dir>
10
11e.g.
12 cd /ceph/src/pybind/mgr/dashboard
13 python ci/<script> frontend/src/app /ceph/monitoring/grafana/dashboards
14"""
15import argparse
16import codecs
17import copy
18import json
19import os
20
21import six
22from six.moves.html_parser import HTMLParser
23
24
25class TemplateParser(HTMLParser):
26
27 def __init__(self, _file, search_tag):
28 if six.PY3:
29 super(TemplateParser, self).__init__()
30 else:
31 # HTMLParser is not a new-style class in py2
32 HTMLParser.__init__(self)
33 self.search_tag = search_tag
34 self.file = _file
35 self.parsed_data = []
36
37 def parse(self):
38 with codecs.open(self.file, encoding='UTF-8') as f:
39 self.feed(f.read())
40
41 def handle_starttag(self, tag, attrs):
42 if tag != self.search_tag:
43 return
44 tag_data = {
45 'file': self.file,
46 'attrs': dict(attrs),
47 'line': self.getpos()[0]
48 }
49 self.parsed_data.append(tag_data)
50
51 def error(self, message):
52 error_msg = 'fail to parse file {} (@{}): {}'.\
53 format(self.file, self.getpos(), message)
54 exit(error_msg)
55
56
57def stdout(msg):
58 six.print_(msg)
59
60
61def get_files(base_dir, file_ext):
62 result = []
63 for root, _, files in os.walk(base_dir):
64 for _file in files:
65 if _file.endswith('.{}'.format(file_ext)):
66 result.append(os.path.join(root, _file))
67 return result
68
69
70def get_tags(base_dir, tag='cd-grafana'):
71 templates = get_files(base_dir, 'html')
72 tags = []
73 for templ in templates:
74 parser = TemplateParser(templ, tag)
75 parser.parse()
76 if parser.parsed_data:
77 tags.extend(parser.parsed_data)
78 return tags
79
80
81def get_grafana_dashboards(base_dir):
82 json_files = get_files(base_dir, 'json')
83 dashboards = {}
84 for json_file in json_files:
85 with open(json_file) as f:
86 dashboard_config = json.load(f)
87 uid = dashboard_config.get('uid')
9f95a23c
TL
88
89 # Grafana dashboard checks
90 title = dashboard_config['title']
91 assert len(title) > 0, \
92 "Title not found in '{}'".format(json_file)
93 assert len(dashboard_config.get('links', [])) == 0, \
94 "Links found in '{}'".format(json_file)
92f5a8d4
TL
95 if not uid:
96 continue
97 if uid in dashboards:
98 # duplicated uids
99 error_msg = 'Duplicated UID {} found, already defined in {}'.\
100 format(uid, dashboards[uid]['file'])
101 exit(error_msg)
9f95a23c 102
92f5a8d4
TL
103 dashboards[uid] = {
104 'file': json_file,
9f95a23c 105 'title': title
92f5a8d4
TL
106 }
107 return dashboards
108
109
110def parse_args():
111 long_desc = ('Check every <cd-grafana> component in Angular template has a'
112 ' mapped Grafana dashboard.')
113 parser = argparse.ArgumentParser(description=long_desc)
114 parser.add_argument('angular_app_dir', type=str,
115 help='Angular app base directory')
116 parser.add_argument('grafana_dash_dir', type=str,
117 help='Directory contains Grafana dashboard JSON files')
118 parser.add_argument('--verbose', action='store_true',
119 help='Display verbose mapping information.')
120 return parser.parse_args()
121
122
123def main():
124 args = parse_args()
125 tags = get_tags(args.angular_app_dir)
126 grafana_dashboards = get_grafana_dashboards(args.grafana_dash_dir)
127 verbose = args.verbose
128
129 if not tags:
130 error_msg = 'Can not find any cd-grafana component under {}'.\
131 format(args.angular_app_dir)
132 exit(error_msg)
133
134 if verbose:
135 stdout('Found mappings:')
136 no_dashboard_tags = []
137 for tag in tags:
138 uid = tag['attrs']['uid']
139 if uid not in grafana_dashboards:
140 no_dashboard_tags.append(copy.copy(tag))
141 continue
142 if verbose:
143 msg = '{} ({}:{}) \n\t-> {} ({})'.\
144 format(uid, tag['file'], tag['line'],
145 grafana_dashboards[uid]['title'],
146 grafana_dashboards[uid]['file'])
147 stdout(msg)
148
149 if no_dashboard_tags:
150 title = ('Checking Grafana dashboards UIDs: ERROR\n'
151 'Components that have no mapped Grafana dashboards:\n')
152 lines = ('{} ({}:{})'.format(tag['attrs']['uid'],
153 tag['file'],
154 tag['line'])
155 for tag in no_dashboard_tags)
156 error_msg = title + '\n'.join(lines)
157 exit(error_msg)
158 else:
159 stdout('Checking Grafana dashboards UIDs: OK')
160
161
162if __name__ == '__main__':
163 main()