Merge ~xavpaice/charm-grafana:bug/1873105 into charm-grafana:master
- Git
- lp:~xavpaice/charm-grafana
- bug/1873105
- Merge into master
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Joe Guo | ||||
Approved revision: | 59f8c55d0d5cca497a0b8d7b64128cdf288ab883 | ||||
Merged at revision: | 2078b8c32cf6c26b0ad3e4444b69cf553039757c | ||||
Proposed branch: | ~xavpaice/charm-grafana:bug/1873105 | ||||
Merge into: | charm-grafana:master | ||||
Diff against target: |
517 lines (+86/-113) 8 files modified
.gitignore (+1/-0) Makefile (+1/-1) lib/charms/layer/grafana.py (+3/-8) reactive/grafana.py (+38/-66) tests/functional/tests/test_grafana.py (+10/-30) tests/unit/requirements.txt (+3/-0) tests/unit/test_grafana.py (+27/-4) tox.ini (+3/-4) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Joe Guo (community) | Approve | ||
Paul Goins | Approve | ||
Xav Paice (community) | Needs Resubmitting | ||
Alvaro Uria | Pending | ||
Peter Sabaini | Pending | ||
Review via email: mp+388019@code.launchpad.net |
This proposal supersedes a proposal from 2020-04-16.
Commit message
Replace the process monitoring with functional
Description of the change
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : Posted in a previous version of this proposal | # |
Peter Sabaini (peter-sabaini) wrote : Posted in a previous version of this proposal | # |
Two minor comments inline, otherwise lgtm, cheers
Alvaro Uria (aluria) wrote : Posted in a previous version of this proposal | # |
Hi, there are a few things to be reviewed:
* Makefile does not have a unittest target (probably because unit tests didn't exist). However, tox.ini does have a "unit" env. I think the Makefile misses the target, running "tox -e unit"
* Functional tests miss nagios-{{series}} and nrpe-{{series}} in the overlay.yaml.j2 template. It would be good to test when grafana gets related to nrpe, by checking that the check_grafana_
* Functional tests don't test a deployment of cs:grafana + juju upgrade-charm to the local version. I spotted a bug that can be seen at [1]. "nrpe-external-
On this 3rd test (upgrade-charm) it would be could to verify that the old checks (check_
Alvaro Uria (aluria) wrote : Posted in a previous version of this proposal | # |
BTW, when I tried to workaround the issue, by manually setting the nrpe-external-
Xav Paice (xavpaice) wrote : Posted in a previous version of this proposal | # |
Change needs a rebase, and rework to the tests. WIP.
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.
Joe Guo (guoqiao) wrote : | # |
made 2 trivial comments inline.
Paul Goins (vultaire) wrote : | # |
Replying to previous comments:
* Re: unit tests: presently "make unittest" calls "tox -e unit"; this may be because of the rebase that it does work now. That being said, the unit tests fail; one of them needs to be repaired.
* Re: functional tests:
i. NRPE-related tests exist; I'm guessing this is due to the rebase.
ii. I still don't see any upgrade-
iii. Uncertain re: check_grafana-
At a minimum, I think the unit tests should be fixed. I'm not 100% sure whether the upgrade-charm tests should be addressed now or perhaps after the next charm series release.
Xav Paice (xavpaice) wrote : | # |
Unit tests fixed, plus one or to minor lints.
"ii. I still don't see any upgrade-
Testing for upgrade-charm is way out of scope for this change, we don't run that test for a single one of the LMA charm stack right now - though it would be an excellent addition and make life a heck of a lot easier during the release process. I don't think we can reasonably block this change because of something so far out of scope.
Paul Goins (vultaire) wrote : | # |
LGTM (and agreed with scope sentiment)
Xav Paice (xavpaice) wrote : | # |
info: When running lint on this, Black wants to change a number of items, but I've not included that linting in this change since we're going to do a separate commit for lint changes.
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Change successfully merged at revision 2078b8c32cf6c26
Preview Diff
1 | diff --git a/.gitignore b/.gitignore | |||
2 | index 32e2995..34da750 100644 | |||
3 | --- a/.gitignore | |||
4 | +++ b/.gitignore | |||
5 | @@ -20,3 +20,4 @@ repo-info | |||
6 | 20 | 20 | ||
7 | 21 | # reports | 21 | # reports |
8 | 22 | report/* | 22 | report/* |
9 | 23 | .unit-state.db | ||
10 | diff --git a/Makefile b/Makefile | |||
11 | index 60f593c..1334496 100644 | |||
12 | --- a/Makefile | |||
13 | +++ b/Makefile | |||
14 | @@ -21,7 +21,7 @@ lint: | |||
15 | 21 | @echo "Running flake8" | 21 | @echo "Running flake8" |
16 | 22 | @tox -e lint | 22 | @tox -e lint |
17 | 23 | 23 | ||
19 | 24 | test: lint | 24 | unittest: |
20 | 25 | @echo "Running unit tests..." | 25 | @echo "Running unit tests..." |
21 | 26 | @tox -e unit | 26 | @tox -e unit |
22 | 27 | 27 | ||
23 | diff --git a/lib/charms/layer/grafana.py b/lib/charms/layer/grafana.py | |||
24 | index 9853dc2..cb7fd2c 100644 | |||
25 | --- a/lib/charms/layer/grafana.py | |||
26 | +++ b/lib/charms/layer/grafana.py | |||
27 | @@ -32,9 +32,7 @@ SNAP_CODENAME_MAP = { | |||
28 | 32 | 32 | ||
29 | 33 | def get_admin_password(): | 33 | def get_admin_password(): |
30 | 34 | """Get admin password from config, fall back to kv.""" | 34 | """Get admin password from config, fall back to kv.""" |
34 | 35 | return config("admin_password") or unitdata.kv().get( | 35 | return config("admin_password") or unitdata.kv().get("grafana.admin_password") |
32 | 36 | "grafana.admin_password" | ||
33 | 37 | ) | ||
35 | 38 | 36 | ||
36 | 39 | 37 | ||
37 | 40 | def import_dashboard(dashboard, name=None): | 38 | def import_dashboard(dashboard, name=None): |
38 | @@ -132,9 +130,7 @@ def check_snap_channel(snap_name, channel): | |||
39 | 132 | UNCHANGED: Channel unchanged | 130 | UNCHANGED: Channel unchanged |
40 | 133 | DOWNGRADE: Would result in downgrade of major version | 131 | DOWNGRADE: Would result in downgrade of major version |
41 | 134 | """ | 132 | """ |
45 | 135 | installed_ver = parse_snap_major_version( | 133 | installed_ver = parse_snap_major_version(snap.get_installed_channel(snap_name)) |
43 | 136 | snap.get_installed_channel(snap_name) | ||
44 | 137 | ) | ||
46 | 138 | new_ver = parse_snap_major_version(channel) | 134 | new_ver = parse_snap_major_version(channel) |
47 | 139 | is_refresh_available = snap.is_refresh_available(snap_name) | 135 | is_refresh_available = snap.is_refresh_available(snap_name) |
48 | 140 | if new_ver == -2: | 136 | if new_ver == -2: |
49 | @@ -163,8 +159,7 @@ def check_snap_channel(snap_name, channel): | |||
50 | 163 | return ChangeStatus.UNCHANGED | 159 | return ChangeStatus.UNCHANGED |
51 | 164 | if installed_ver < new_ver: | 160 | if installed_ver < new_ver: |
52 | 165 | msg = ( | 161 | msg = ( |
55 | 166 | "PACKAGE UPGRADE REQUIRES MANUAL INTERVENTION: see {} for " | 162 | "PACKAGE UPGRADE REQUIRES MANUAL INTERVENTION: see {} for more info" |
54 | 167 | "more info" | ||
56 | 168 | ).format(VERSION_CHANGE_URL) | 163 | ).format(VERSION_CHANGE_URL) |
57 | 169 | status_set("blocked", msg) | 164 | status_set("blocked", msg) |
58 | 170 | log(msg) | 165 | log(msg) |
59 | diff --git a/reactive/grafana.py b/reactive/grafana.py | |||
60 | index 17dfad1..4434b17 100644 | |||
61 | --- a/reactive/grafana.py | |||
62 | +++ b/reactive/grafana.py | |||
63 | @@ -97,6 +97,7 @@ from charms.reactive import ( | |||
64 | 97 | remove_state, | 97 | remove_state, |
65 | 98 | set_state, | 98 | set_state, |
66 | 99 | when, | 99 | when, |
67 | 100 | when_any, | ||
68 | 100 | when_not, | 101 | when_not, |
69 | 101 | ) | 102 | ) |
70 | 102 | from charms.reactive.helpers import ( | 103 | from charms.reactive.helpers import ( |
71 | @@ -184,8 +185,7 @@ def install_packages(): | |||
72 | 184 | 185 | ||
73 | 185 | if config.changed("install_file") and config.get("install_file"): | 186 | if config.changed("install_file") and config.get("install_file"): |
74 | 186 | hookenv.status_set( | 187 | hookenv.status_set( |
77 | 187 | "maintenance", | 188 | "maintenance", "Installing deb pkgs since install_file changed", |
76 | 188 | "Installing deb pkgs since install_file changed", | ||
78 | 189 | ) | 189 | ) |
79 | 190 | 190 | ||
80 | 191 | url = config.get("install_file") | 191 | url = config.get("install_file") |
81 | @@ -249,9 +249,7 @@ def install_plugins(): | |||
82 | 249 | 249 | ||
83 | 250 | if os.path.exists(plugins_dir): | 250 | if os.path.exists(plugins_dir): |
84 | 251 | hookenv.log("Cleaning up currently installed plugins") | 251 | hookenv.log("Cleaning up currently installed plugins") |
88 | 252 | hookenv.status_set( | 252 | hookenv.status_set("maintenance", "Cleaning up currently installed plugins") |
86 | 253 | "maintenance", "Cleaning up currently installed plugins" | ||
87 | 254 | ) | ||
89 | 255 | for entry in os.listdir(plugins_dir): | 253 | for entry in os.listdir(plugins_dir): |
90 | 256 | entry_path = os.path.join(plugins_dir, entry) | 254 | entry_path = os.path.join(plugins_dir, entry) |
91 | 257 | if os.path.isfile(entry_path): | 255 | if os.path.isfile(entry_path): |
92 | @@ -283,12 +281,12 @@ def install_plugins(): | |||
93 | 283 | @when_not("grafana.change-block") | 281 | @when_not("grafana.change-block") |
94 | 284 | def upgrade_charm(): | 282 | def upgrade_charm(): |
95 | 285 | hookenv.status_set( | 283 | hookenv.status_set( |
98 | 286 | "maintenance", | 284 | "maintenance", "Forcing package update and reconfiguration on upgrade-charm", |
97 | 287 | "Forcing package update and reconfiguration on upgrade-charm", | ||
99 | 288 | ) | 285 | ) |
100 | 289 | remove_state("grafana.installed") | 286 | remove_state("grafana.installed") |
101 | 290 | remove_state("grafana.backup.configured") | 287 | remove_state("grafana.backup.configured") |
102 | 291 | remove_state("grafana.configured") | 288 | remove_state("grafana.configured") |
103 | 289 | remove_state("grafana.nagios-setup.completed") | ||
104 | 292 | 290 | ||
105 | 293 | 291 | ||
106 | 294 | @hook("config-changed") | 292 | @hook("config-changed") |
107 | @@ -314,9 +312,7 @@ def config_changed(): | |||
108 | 314 | else: | 312 | else: |
109 | 315 | # Install from requested channel | 313 | # Install from requested channel |
110 | 316 | snap.install( | 314 | snap.install( |
114 | 317 | SNAP_NAME, | 315 | SNAP_NAME, channel=config["snap_channel"], force_dangerous=False, |
112 | 318 | channel=config["snap_channel"], | ||
113 | 319 | force_dangerous=False, | ||
115 | 320 | ) | 316 | ) |
116 | 321 | remove_state("grafana.configured") | 317 | remove_state("grafana.configured") |
117 | 322 | if config.changed("dashboards_backup_schedule") or config.changed( | 318 | if config.changed("dashboards_backup_schedule") or config.changed( |
118 | @@ -327,6 +323,7 @@ def config_changed(): | |||
119 | 327 | remove_state("grafana.admin_password.set") | 323 | remove_state("grafana.admin_password.set") |
120 | 328 | if config.changed("install_file") and config.get("install_file"): | 324 | if config.changed("install_file") and config.get("install_file"): |
121 | 329 | remove_state("grafana.installed") | 325 | remove_state("grafana.installed") |
122 | 326 | remove_state("grafana.nagios-setup.completed") | ||
123 | 330 | 327 | ||
124 | 331 | 328 | ||
125 | 332 | def check_ports(new_port): | 329 | def check_ports(new_port): |
126 | @@ -401,15 +398,11 @@ def add_backup_api_keys(): | |||
127 | 401 | "SELECT id FROM api_key WHERE org_id=? AND name=?", [org_id, name], | 398 | "SELECT id FROM api_key WHERE org_id=? AND name=?", [org_id, name], |
128 | 402 | ): | 399 | ): |
129 | 403 | hookenv.log( | 400 | hookenv.log( |
133 | 404 | "API key {} in org {} already exists, skipping".format( | 401 | "API key {} in org {} already exists, skipping".format(name, org_id) |
131 | 405 | name, org_id | ||
132 | 406 | ) | ||
134 | 407 | ) | 402 | ) |
135 | 408 | continue | 403 | continue |
136 | 409 | j = {"n": name, "k": passwd, "id": org_id} | 404 | j = {"n": name, "k": passwd, "id": org_id} |
140 | 410 | encoded = base64.b64encode(json.dumps(j).encode("ascii")).decode( | 405 | encoded = base64.b64encode(json.dumps(j).encode("ascii")).decode("ascii") |
138 | 411 | "ascii" | ||
139 | 412 | ) | ||
141 | 413 | stmt = ( | 406 | stmt = ( |
142 | 414 | "INSERT INTO api_key (org_id, name, key, role, created, updated)" | 407 | "INSERT INTO api_key (org_id, name, key, role, created, updated)" |
143 | 415 | + ' VALUES (?,?,?,"Viewer",?,?)' | 408 | + ' VALUES (?,?,?,"Viewer",?,?)' |
144 | @@ -473,9 +466,7 @@ def setup_backup_shedule(): | |||
145 | 473 | 466 | ||
146 | 474 | config = hookenv.config() | 467 | config = hookenv.config() |
147 | 475 | if config.get("dashboards_backup_schedule", False): | 468 | if config.get("dashboards_backup_schedule", False): |
151 | 476 | hookenv.status_set( | 469 | hookenv.status_set("maintenance", "Configuring grafana dashboard backup") |
149 | 477 | "maintenance", "Configuring grafana dashboard backup" | ||
150 | 478 | ) | ||
152 | 479 | hookenv.log("Setting up dashboards backup job...") | 470 | hookenv.log("Setting up dashboards backup job...") |
153 | 480 | host.rsync( | 471 | host.rsync( |
154 | 481 | "files/dashboards_backup", "/usr/local/bin/dashboards_backup", | 472 | "files/dashboards_backup", "/usr/local/bin/dashboards_backup", |
155 | @@ -494,9 +485,7 @@ def setup_backup_shedule(): | |||
156 | 494 | group="root", | 485 | group="root", |
157 | 495 | perms=0o640, | 486 | perms=0o640, |
158 | 496 | ) | 487 | ) |
162 | 497 | hookenv.status_set( | 488 | hookenv.status_set("active", "Completed configuring grafana dashboard backup") |
160 | 498 | "active", "Completed configuring grafana dashboard backup" | ||
161 | 499 | ) | ||
163 | 500 | set_state("grafana.backup.configured") | 489 | set_state("grafana.backup.configured") |
164 | 501 | 490 | ||
165 | 502 | 491 | ||
166 | @@ -518,9 +507,7 @@ def restart_grafana(): | |||
167 | 518 | hookenv.status_set("maintenance", msg) | 507 | hookenv.status_set("maintenance", msg) |
168 | 519 | hookenv.log(msg) | 508 | hookenv.log(msg) |
169 | 520 | host.service_start(svcname) | 509 | host.service_start(svcname) |
173 | 521 | elif any_file_changed([grafana_ini]) or is_state( | 510 | elif any_file_changed([grafana_ini]) or is_state("config.changed.install_plugins"): |
171 | 522 | "config.changed.install_plugins" | ||
172 | 523 | ): | ||
174 | 524 | msg = "Restarting {}".format(svcname) | 511 | msg = "Restarting {}".format(svcname) |
175 | 525 | hookenv.log(msg) | 512 | hookenv.log(msg) |
176 | 526 | hookenv.status_set("maintenance", msg) | 513 | hookenv.status_set("maintenance", msg) |
177 | @@ -531,30 +518,33 @@ def restart_grafana(): | |||
178 | 531 | 518 | ||
179 | 532 | 519 | ||
180 | 533 | @when("grafana.started") | 520 | @when("grafana.started") |
182 | 534 | @when("nrpe-external-master.available") | 521 | @when_any("nrpe-external-master.available", "nrpe-external-master.connected") |
183 | 535 | @when_not("grafana.change-block") | 522 | @when_not("grafana.change-block") |
192 | 536 | def update_nrpe_config(svc): | 523 | @when_not("grafana.nagios-setup.completed") |
193 | 537 | kv = unitdata.kv() | 524 | def update_nrpe_config(): |
186 | 538 | source = kv.get("install_method") | ||
187 | 539 | if source in ("snap", "apt"): | ||
188 | 540 | svcname = SVCNAME[source] | ||
189 | 541 | else: | ||
190 | 542 | hookenv.status_set("blocked", "Unsupported install_method") | ||
191 | 543 | return | ||
194 | 544 | # python-dbus is used by check_upstart_job | 525 | # python-dbus is used by check_upstart_job |
195 | 545 | fetch.apt_install("python-dbus", fatal=True) | 526 | fetch.apt_install("python-dbus", fatal=True) |
196 | 546 | hostname = nrpe.get_nagios_hostname() | 527 | hostname = nrpe.get_nagios_hostname() |
197 | 547 | current_unit = nrpe.get_nagios_unit_name() | ||
198 | 548 | nrpe_setup = nrpe.NRPE(hostname=hostname) | 528 | nrpe_setup = nrpe.NRPE(hostname=hostname) |
200 | 549 | nrpe.add_init_service_checks(nrpe_setup, [svcname], current_unit) | 529 | config = hookenv.config() |
201 | 530 | |||
202 | 531 | # write the http check | ||
203 | 532 | nrpe_setup.add_check( | ||
204 | 533 | "grafana_http", | ||
205 | 534 | "Grafana HTTP check", | ||
206 | 535 | "check_http -I 127.0.0.1 -p {} -u /login".format(config["port"]), | ||
207 | 536 | ) | ||
208 | 550 | nrpe_setup.write() | 537 | nrpe_setup.write() |
209 | 538 | set_state("grafana.nagios-setup.completed") | ||
210 | 551 | 539 | ||
211 | 552 | 540 | ||
213 | 553 | @when_not("nrpe-external-master.available") | 541 | @when_not("nrpe-external-master.connected") |
214 | 554 | def wipe_nrpe_checks(): | 542 | def wipe_nrpe_checks(): |
215 | 555 | checks = [ | 543 | checks = [ |
216 | 556 | "/etc/nagios/nrpe.d/check_grafana-server.cfg", | 544 | "/etc/nagios/nrpe.d/check_grafana-server.cfg", |
217 | 557 | "/etc/nagios/nrpe.d/check_grafana.cfg", | 545 | "/etc/nagios/nrpe.d/check_grafana.cfg", |
218 | 546 | "/etc/nagios/nrpe.d/check_grafana_http.cfg", | ||
219 | 547 | "/etc/nagios/nrpe.d/check_snap.grafana.grafana.cfg", | ||
220 | 558 | "/var/lib/nagios/export/service__*_grafana-server.cfg", | 548 | "/var/lib/nagios/export/service__*_grafana-server.cfg", |
221 | 559 | "/var/lib/nagios/export/service__*_grafana.cfg", | 549 | "/var/lib/nagios/export/service__*_grafana.cfg", |
222 | 560 | ] | 550 | ] |
223 | @@ -562,6 +552,7 @@ def wipe_nrpe_checks(): | |||
224 | 562 | for f in glob.glob(check): | 552 | for f in glob.glob(check): |
225 | 563 | if os.path.isfile(f): | 553 | if os.path.isfile(f): |
226 | 564 | os.unlink(f) | 554 | os.unlink(f) |
227 | 555 | remove_state("grafana.nagios-setup.completed") | ||
228 | 565 | 556 | ||
229 | 566 | 557 | ||
230 | 567 | @when("grafana.started") | 558 | @when("grafana.started") |
231 | @@ -602,8 +593,7 @@ def sources_gone(relation): | |||
232 | 602 | conn = sqlite3.connect("{}/grafana.db".format(data_dir), timeout=30) | 593 | conn = sqlite3.connect("{}/grafana.db".format(data_dir), timeout=30) |
233 | 603 | cur = conn.cursor() | 594 | cur = conn.cursor() |
234 | 604 | cur.execute( | 595 | cur.execute( |
237 | 605 | "DELETE FROM DATA_SOURCE WHERE type=? AND url=?", | 596 | "DELETE FROM DATA_SOURCE WHERE type=? AND url=?", (ds["type"], ds["url"]), |
236 | 606 | (ds["type"], ds["url"]), | ||
238 | 607 | ) | 597 | ) |
239 | 608 | conn.commit() | 598 | conn.commit() |
240 | 609 | cur.close() | 599 | cur.close() |
241 | @@ -668,16 +658,12 @@ def check_datasource(ds): | |||
242 | 668 | return | 658 | return |
243 | 669 | conn = sqlite3.connect("{}/grafana.db".format(data_dir), timeout=30) | 659 | conn = sqlite3.connect("{}/grafana.db".format(data_dir), timeout=30) |
244 | 670 | cur = conn.cursor() | 660 | cur = conn.cursor() |
248 | 671 | query = cur.execute( | 661 | query = cur.execute("SELECT id, type, name, url, is_default FROM DATA_SOURCE") |
246 | 672 | "SELECT id, type, name, url, is_default FROM DATA_SOURCE" | ||
247 | 673 | ) | ||
249 | 674 | rows = query.fetchall() | 662 | rows = query.fetchall() |
250 | 675 | ds_name = "{} - {}".format(ds["service_name"], ds["description"]) | 663 | ds_name = "{} - {}".format(ds["service_name"], ds["description"]) |
251 | 676 | for row in rows: | 664 | for row in rows: |
252 | 677 | if row[1] == ds["type"] and row[3] == ds["url"]: | 665 | if row[1] == ds["type"] and row[3] == ds["url"]: |
256 | 678 | hookenv.log( | 666 | hookenv.log("Datasource already exist, updating: {}".format(ds_name)) |
254 | 679 | "Datasource already exist, updating: {}".format(ds_name) | ||
255 | 680 | ) | ||
257 | 681 | stmt, values = generate_query(ds, row[4], id=row[0]) | 667 | stmt, values = generate_query(ds, row[4], id=row[0]) |
258 | 682 | print(stmt, values) | 668 | print(stmt, values) |
259 | 683 | cur.execute(stmt, values) | 669 | cur.execute(stmt, values) |
260 | @@ -705,16 +691,12 @@ def render_custom(source, context, **parameters): | |||
261 | 705 | template_folder = os.path.join( | 691 | template_folder = os.path.join( |
262 | 706 | hookenv.charm_dir(), "templates/dashboards/prometheus" | 692 | hookenv.charm_dir(), "templates/dashboards/prometheus" |
263 | 707 | ) | 693 | ) |
267 | 708 | environment = Environment( | 694 | environment = Environment(loader=FileSystemLoader(template_folder), **parameters) |
265 | 709 | loader=FileSystemLoader(template_folder), **parameters | ||
266 | 710 | ) | ||
268 | 711 | try: | 695 | try: |
269 | 712 | template = environment.get_template(source) | 696 | template = environment.get_template(source) |
270 | 713 | except exceptions.TemplateNotFound as e: | 697 | except exceptions.TemplateNotFound as e: |
271 | 714 | hookenv.log( | 698 | hookenv.log( |
275 | 715 | "Could not load template {} from {}".format( | 699 | "Could not load template {} from {}".format(source, template_folder) |
273 | 716 | source, template_folder | ||
274 | 717 | ) | ||
276 | 718 | ) | 700 | ) |
277 | 719 | raise e | 701 | raise e |
278 | 720 | return template.render(context) | 702 | return template.render(context) |
279 | @@ -817,9 +799,7 @@ def check_and_add_dashboard( | |||
280 | 817 | dashboard_changed = diff(new, curr) | 799 | dashboard_changed = diff(new, curr) |
281 | 818 | if not dashboard_changed: | 800 | if not dashboard_changed: |
282 | 819 | hookenv.log( | 801 | hookenv.log( |
286 | 820 | "Skipping Dashboard Template: already up to date: {}".format( | 802 | "Skipping Dashboard Template: already up to date: {}".format(filename) |
284 | 821 | filename | ||
285 | 822 | ) | ||
287 | 823 | ) | 803 | ) |
288 | 824 | return | 804 | return |
289 | 825 | 805 | ||
290 | @@ -835,15 +815,11 @@ def check_and_add_dashboard( | |||
291 | 835 | 815 | ||
292 | 836 | hookenv.log("Using Dashboard Template: {}".format(filename)) | 816 | hookenv.log("Using Dashboard Template: {}".format(filename)) |
293 | 837 | post_req = "http://127.0.0.1:{}/api/dashboards/db".format(port) | 817 | post_req = "http://127.0.0.1:{}/api/dashboards/db".format(port) |
297 | 838 | r = requests.post( | 818 | r = requests.post(post_req, json=dashboard_json, auth=("admin", gf_adminpasswd)) |
295 | 839 | post_req, json=dashboard_json, auth=("admin", gf_adminpasswd) | ||
296 | 840 | ) | ||
298 | 841 | 819 | ||
299 | 842 | if r.status_code != 200: | 820 | if r.status_code != 200: |
300 | 843 | hookenv.log( | 821 | hookenv.log( |
304 | 844 | "Posting template {} failed with error: {}".format( | 822 | "Posting template {} failed with error: {}".format(filename, r.text), |
302 | 845 | filename, r.text | ||
303 | 846 | ), | ||
305 | 847 | hookenv.ERROR, | 823 | hookenv.ERROR, |
306 | 848 | ) | 824 | ) |
307 | 849 | 825 | ||
308 | @@ -862,9 +838,7 @@ def generate_prometheus_dashboards(gf_adminpasswd, ds): | |||
309 | 862 | config = hookenv.config() | 838 | config = hookenv.config() |
310 | 863 | 839 | ||
311 | 864 | # https://prometheus.io/docs/prometheus/latest/querying/api/#querying-label-values | 840 | # https://prometheus.io/docs/prometheus/latest/querying/api/#querying-label-values |
315 | 865 | response = requests.get( | 841 | response = requests.get("{}/api/v1/label/__name__/values".format(ds["url"])) |
313 | 866 | "{}/api/v1/label/__name__/values".format(ds["url"]) | ||
314 | 867 | ) | ||
316 | 868 | if response.status_code != 200: | 842 | if response.status_code != 200: |
317 | 869 | hookenv.log( | 843 | hookenv.log( |
318 | 870 | "Could not reach prometheus API status code: " | 844 | "Could not reach prometheus API status code: " |
319 | @@ -1105,9 +1079,7 @@ def check_adminuser(): | |||
320 | 1105 | conn.commit() | 1079 | conn.commit() |
321 | 1106 | hookenv.log("[*] admin password updated on database") | 1080 | hookenv.log("[*] admin password updated on database") |
322 | 1107 | else: | 1081 | else: |
326 | 1108 | hookenv.log( | 1082 | hookenv.log("Could not update user table: hpwgen func failed") |
324 | 1109 | "Could not update user table: hpwgen func failed" | ||
325 | 1110 | ) | ||
327 | 1111 | break | 1083 | break |
328 | 1112 | conn.close() | 1084 | conn.close() |
329 | 1113 | except sqlite3.OperationalError as e: | 1085 | except sqlite3.OperationalError as e: |
330 | diff --git a/tests/functional/tests/test_grafana.py b/tests/functional/tests/test_grafana.py | |||
331 | index 31d3b4d..06a1942 100644 | |||
332 | --- a/tests/functional/tests/test_grafana.py | |||
333 | +++ b/tests/functional/tests/test_grafana.py | |||
334 | @@ -27,9 +27,7 @@ class BaseGrafanaTest(unittest.TestCase): | |||
335 | 27 | cls.lead_unit_name = model.get_lead_unit_name( | 27 | cls.lead_unit_name = model.get_lead_unit_name( |
336 | 28 | cls.application_name, model_name=cls.model_name | 28 | cls.application_name, model_name=cls.model_name |
337 | 29 | ) | 29 | ) |
341 | 30 | cls.units = model.get_units( | 30 | cls.units = model.get_units(cls.application_name, model_name=cls.model_name) |
339 | 31 | cls.application_name, model_name=cls.model_name | ||
340 | 32 | ) | ||
342 | 33 | cls.grafana_ip = model.get_app_ips(cls.application_name)[0] | 31 | cls.grafana_ip = model.get_app_ips(cls.application_name)[0] |
343 | 34 | 32 | ||
344 | 35 | def get_unit_status(self, unit): | 33 | def get_unit_status(self, unit): |
345 | @@ -84,9 +82,7 @@ class CharmOperationTest(BaseGrafanaTest): | |||
346 | 84 | We'll retry until the TEST_TIMEOUT. | 82 | We'll retry until the TEST_TIMEOUT. |
347 | 85 | """ | 83 | """ |
348 | 86 | test_command = "{} -I 127.0.0.1 -p {} -u {}".format( | 84 | test_command = "{} -I 127.0.0.1 -p {} -u {}".format( |
352 | 87 | "/usr/lib/nagios/plugins/check_http", | 85 | "/usr/lib/nagios/plugins/check_http", DEFAULT_API_PORT, DEFAULT_API_URL, |
350 | 88 | DEFAULT_API_PORT, | ||
351 | 89 | DEFAULT_API_URL, | ||
353 | 90 | ) | 86 | ) |
354 | 91 | timeout = time.time() + TEST_TIMEOUT | 87 | timeout = time.time() + TEST_TIMEOUT |
355 | 92 | while time.time() < timeout: | 88 | while time.time() < timeout: |
356 | @@ -94,9 +90,7 @@ class CharmOperationTest(BaseGrafanaTest): | |||
357 | 94 | if response["Code"] == "0": | 90 | if response["Code"] == "0": |
358 | 95 | return | 91 | return |
359 | 96 | logging.warning( | 92 | logging.warning( |
363 | 97 | "Unexpected check_http response: {}. Retrying in 30s.".format( | 93 | "Unexpected check_http response: {}. Retrying in 30s.".format(response) |
361 | 98 | response | ||
362 | 99 | ) | ||
364 | 100 | ) | 94 | ) |
365 | 101 | time.sleep(30) | 95 | time.sleep(30) |
366 | 102 | 96 | ||
367 | @@ -104,9 +98,7 @@ class CharmOperationTest(BaseGrafanaTest): | |||
368 | 104 | self.fail( | 98 | self.fail( |
369 | 105 | "http port didn't respond to the command \n" | 99 | "http port didn't respond to the command \n" |
370 | 106 | "'{test_command}' as expected.\n" | 100 | "'{test_command}' as expected.\n" |
374 | 107 | "Result: {result}".format( | 101 | "Result: {result}".format(test_command=test_command, result=response) |
372 | 108 | test_command=test_command, result=response | ||
373 | 109 | ) | ||
375 | 110 | ) | 102 | ) |
376 | 111 | 103 | ||
377 | 112 | def test_02_nrpe_http_check(self): | 104 | def test_02_nrpe_http_check(self): |
378 | @@ -114,21 +106,11 @@ class CharmOperationTest(BaseGrafanaTest): | |||
379 | 114 | logging.debug( | 106 | logging.debug( |
380 | 115 | "Verify the nrpe check is created and has the required content..." | 107 | "Verify the nrpe check is created and has the required content..." |
381 | 116 | ) | 108 | ) |
397 | 117 | # Check if this is snap or apt | 109 | expected_nrpe_check = ( |
398 | 118 | cmd = "config-get install_method" | 110 | "command[check_grafana_http]=/usr/lib/nagios/plugins/check_http " |
399 | 119 | install_method = model.run_on_unit(self.lead_unit_name, cmd) | 111 | "-I 127.0.0.1 -p 3000 -u /login" |
400 | 120 | if "apt" in install_method["Stdout"]: | 112 | ) |
401 | 121 | expected_nrpe_check = ( | 113 | cmd = "cat /etc/nagios/nrpe.d/check_grafana_http.cfg" |
387 | 122 | "command[check_grafana-server]=/usr/local/lib/nagios/" | ||
388 | 123 | "plugins/check_systemd.py grafana-server" | ||
389 | 124 | ) | ||
390 | 125 | cmd = "cat /etc/nagios/nrpe.d/check_grafana-server.cfg" | ||
391 | 126 | else: # must be snap | ||
392 | 127 | expected_nrpe_check = ( | ||
393 | 128 | "command[check_snap.grafana.grafana]=/usr/local/lib/" | ||
394 | 129 | "nagios/plugins/check_systemd.py snap.grafana.grafana" | ||
395 | 130 | ) | ||
396 | 131 | cmd = "cat /etc/nagios/nrpe.d/check_snap.grafana.grafana.cfg" | ||
402 | 132 | result = model.run_on_unit(self.lead_unit_name, cmd) | 114 | result = model.run_on_unit(self.lead_unit_name, cmd) |
403 | 133 | code = result.get("Code") | 115 | code = result.get("Code") |
404 | 134 | if code != "0": | 116 | if code != "0": |
405 | @@ -232,9 +214,7 @@ class SnappedGrafanaTest(BaseGrafanaTest): | |||
406 | 232 | model.block_until_unit_wl_status(self.lead_unit_name, "blocked") | 214 | model.block_until_unit_wl_status(self.lead_unit_name, "blocked") |
407 | 233 | model.block_until_all_units_idle() | 215 | model.block_until_all_units_idle() |
408 | 234 | status_message = self.get_unit_status(self.lead_unit_name) | 216 | status_message = self.get_unit_status(self.lead_unit_name) |
412 | 235 | self.assertTrue( | 217 | self.assertTrue("PACKAGE DOWNGRADES ARE NOT SUPPORTED" in status_message) |
410 | 236 | "PACKAGE DOWNGRADES ARE NOT SUPPORTED" in status_message | ||
411 | 237 | ) | ||
413 | 238 | model.set_application_config( # unblock unit again | 218 | model.set_application_config( # unblock unit again |
414 | 239 | self.application_name, {"snap_channel": "7/stable"} | 219 | self.application_name, {"snap_channel": "7/stable"} |
415 | 240 | ) | 220 | ) |
416 | diff --git a/tests/unit/requirements.txt b/tests/unit/requirements.txt | |||
417 | index 29f9318..cb975bd 100644 | |||
418 | --- a/tests/unit/requirements.txt | |||
419 | +++ b/tests/unit/requirements.txt | |||
420 | @@ -4,3 +4,6 @@ mock | |||
421 | 4 | pytest | 4 | pytest |
422 | 5 | pytest-cov | 5 | pytest-cov |
423 | 6 | requests | 6 | requests |
424 | 7 | jsondiff | ||
425 | 8 | pbkdf2 | ||
426 | 9 | pycrypto | ||
427 | diff --git a/tests/unit/test_grafana.py b/tests/unit/test_grafana.py | |||
428 | index 57e730d..0c8a658 100644 | |||
429 | --- a/tests/unit/test_grafana.py | |||
430 | +++ b/tests/unit/test_grafana.py | |||
431 | @@ -1,18 +1,18 @@ | |||
432 | 1 | from os.path import isfile | ||
433 | 2 | from unittest import mock | ||
434 | 3 | import sys | 1 | import sys |
435 | 4 | import unittest | 2 | import unittest |
437 | 5 | 3 | from os.path import isfile | |
438 | 4 | from unittest import mock | ||
439 | 5 | from unittest.mock import call | ||
440 | 6 | 6 | ||
441 | 7 | sys.modules["charms.layer.snap"] = mock.Mock() | 7 | sys.modules["charms.layer.snap"] = mock.Mock() |
442 | 8 | 8 | ||
443 | 9 | |||
444 | 10 | from charms.layer.grafana import ( # noqa E402 | 9 | from charms.layer.grafana import ( # noqa E402 |
445 | 11 | download_file, | 10 | download_file, |
446 | 12 | get_cmd_output, | 11 | get_cmd_output, |
447 | 13 | get_deb_package_version, | 12 | get_deb_package_version, |
448 | 14 | get_installed_package_version, | 13 | get_installed_package_version, |
449 | 15 | ) | 14 | ) |
450 | 15 | from reactive import grafana # noqa E402 | ||
451 | 16 | 16 | ||
452 | 17 | 17 | ||
453 | 18 | class GrafanaTestCase(unittest.TestCase): | 18 | class GrafanaTestCase(unittest.TestCase): |
454 | @@ -45,3 +45,26 @@ class GrafanaTestCase(unittest.TestCase): | |||
455 | 45 | self.assertTrue(isfile(path)) | 45 | self.assertTrue(isfile(path)) |
456 | 46 | version = get_deb_package_version(path) | 46 | version = get_deb_package_version(path) |
457 | 47 | self.assertEqual(version, "2.10-2") | 47 | self.assertEqual(version, "2.10-2") |
458 | 48 | |||
459 | 49 | @mock.patch("charmhelpers.fetch.apt_install") | ||
460 | 50 | @mock.patch("charmhelpers.contrib.charmsupport.nrpe.NRPE") | ||
461 | 51 | @mock.patch("charmhelpers.contrib.charmsupport.nrpe.get_nagios_hostname") | ||
462 | 52 | @mock.patch("charmhelpers.core.hookenv.config") | ||
463 | 53 | def test_update_nrpe_config( | ||
464 | 54 | self, mock_hookenv_config, mock_get_nagios_hostname, mock_nrpe, *args | ||
465 | 55 | ): | ||
466 | 56 | sys.modules["charms.layer"] = mock.MagicMock() | ||
467 | 57 | sys.modules["charms.layer.grafana"] = mock.MagicMock() | ||
468 | 58 | mock_hookenv_config.return_value = {"port": 1234} | ||
469 | 59 | mock_get_nagios_hostname.return_value = "testunit" | ||
470 | 60 | grafana.update_nrpe_config() | ||
471 | 61 | calls = [ | ||
472 | 62 | call(hostname="testunit"), | ||
473 | 63 | call().add_check( | ||
474 | 64 | "grafana_http", | ||
475 | 65 | "Grafana HTTP check", | ||
476 | 66 | "check_http -I 127.0.0.1 -p 1234 -u /login", | ||
477 | 67 | ), | ||
478 | 68 | call().write(), | ||
479 | 69 | ] | ||
480 | 70 | mock_nrpe.assert_has_calls(calls) | ||
481 | diff --git a/tox.ini b/tox.ini | |||
482 | index 486c489..c62ec88 100644 | |||
483 | --- a/tox.ini | |||
484 | +++ b/tox.ini | |||
485 | @@ -6,7 +6,7 @@ skip_missing_interpreters = True | |||
486 | 6 | [testenv] | 6 | [testenv] |
487 | 7 | basepython = python3 | 7 | basepython = python3 |
488 | 8 | setenv = | 8 | setenv = |
490 | 9 | PYTHONPATH = . | 9 | PYTHONPATH = .:lib |
491 | 10 | passenv = | 10 | passenv = |
492 | 11 | HOME | 11 | HOME |
493 | 12 | CHARM_BUILD_DIR | 12 | CHARM_BUILD_DIR |
494 | @@ -24,7 +24,6 @@ commands = pytest -v --ignore {toxinidir}/tests/functional \ | |||
495 | 24 | --cov-report=html:report/html | 24 | --cov-report=html:report/html |
496 | 25 | deps = -r{toxinidir}/tests/unit/requirements.txt | 25 | deps = -r{toxinidir}/tests/unit/requirements.txt |
497 | 26 | -r{toxinidir}/requirements.txt | 26 | -r{toxinidir}/requirements.txt |
498 | 27 | setenv = PYTHONPATH={toxinidir}/lib | ||
499 | 28 | 27 | ||
500 | 29 | [testenv:func] | 28 | [testenv:func] |
501 | 30 | changedir = {toxinidir}/tests/functional | 29 | changedir = {toxinidir}/tests/functional |
502 | @@ -39,7 +38,7 @@ deps = -r{toxinidir}/tests/functional/requirements.txt | |||
503 | 39 | 38 | ||
504 | 40 | [testenv:lint] | 39 | [testenv:lint] |
505 | 41 | commands = | 40 | commands = |
507 | 42 | black --check --line-length 79 reactive lib tests | 41 | black --check --line-length 88 reactive lib tests |
508 | 43 | flake8 | 42 | flake8 |
509 | 44 | deps = | 43 | deps = |
510 | 45 | black | 44 | black |
511 | @@ -75,5 +74,5 @@ exclude = | |||
512 | 75 | # I100: Import statements are in the wrong order | 74 | # I100: Import statements are in the wrong order |
513 | 76 | 75 | ||
514 | 77 | ignore = H405,D100,D101,D102,D103,D104,D105,D107,D200,D202,D203,D204,D205,D208,D400,D401,I100,I201,W503,W504 | 76 | ignore = H405,D100,D101,D102,D103,D104,D105,D107,D200,D202,D203,D204,D205,D208,D400,D401,I100,I201,W503,W504 |
516 | 78 | max-line-length = 79 | 77 | max-line-length = 88 |
517 | 79 | max-complexity = 10 | 78 | max-complexity = 10 |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.