Merge ~peppepetra/charm-canonical-livepatch:fix_linting into charm-canonical-livepatch:master

Proposed by Giuseppe Petralia
Status: Merged
Approved by: Giuseppe Petralia
Approved revision: 0013cc5cfeb311b76e921b73812a9bf0889e6f9a
Merged at revision: 7bf3fd86aca5fc26e02cbabffa9f047004a2e79e
Proposed branch: ~peppepetra/charm-canonical-livepatch:fix_linting
Merge into: charm-canonical-livepatch:master
Prerequisite: ~peppepetra/charm-canonical-livepatch:zaza_functests
Diff against target: 933 lines (+268/-203)
5 files modified
Makefile (+3/-3)
actions/actions.py (+31/-21)
files/check_canonical-livepatch.py (+54/-50)
reactive/canonical_livepatch.py (+149/-111)
tests/functional/tests/test_canonical_livepatch.py (+31/-18)
Reviewer Review Type Date Requested Status
Paul Goins Approve
Drew Freiberger (community) Needs Fixing
Review via email: mp+387846@code.launchpad.net

Commit message

Fix linting

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Drew Freiberger (afreiberger) wrote :

a couple minor nits inline.

Thanks for this!

review: Needs Fixing
Revision history for this message
Paul Goins (vultaire) wrote :

Pretty good, only minor stuff to fix.

review: Needs Fixing
Revision history for this message
Paul Goins (vultaire) wrote :

LGTM

review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 7bf3fd86aca5fc26e02cbabffa9f047004a2e79e

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/Makefile b/Makefile
2index e5fd995..fa5236f 100644
3--- a/Makefile
4+++ b/Makefile
5@@ -30,9 +30,9 @@ clean:
6
7 submodules:
8 @echo "Cloning submodules"
9- @git submodule update --init --recursive --remote --merge
10+ @git submodule update --init --recursive
11
12-build: submodules
13+build:
14 @echo "Building charm to directory ${CHARM_BUILD_DIR}/${CHARM_NAME}"
15 @-git describe --tags > ./repo-info
16 @CHARM_LAYERS_DIR=${CHARM_LAYERS_DIR} CHARM_INTERFACES_DIR=${CHARM_INTERFACES_DIR} \
17@@ -56,7 +56,7 @@ functional: build
18 @echo "Executing functional tests in ${CHARM_BUILD_DIR}"
19 @CHARM_BUILD_DIR=${CHARM_BUILD_DIR} tox -e func
20
21-test: proof unittests functional
22+test: lint proof unittests functional
23 @echo "Tests completed for charm ${CHARM_NAME}."
24
25 # The targets below don't depend on a file
26diff --git a/actions/actions.py b/actions/actions.py
27index 6c956cd..e3930d1 100755
28--- a/actions/actions.py
29+++ b/actions/actions.py
30@@ -1,76 +1,86 @@
31 #!/usr/local/sbin/charm-env python3
32+"""Charm actions."""
33
34 import os.path
35 import sys
36 import traceback
37-from subprocess import check_output, CalledProcessError
38+from subprocess import CalledProcessError, check_output
39+
40 from charmhelpers.core import hookenv
41
42
43 def activate(params):
44+ """Execure activate action."""
45 config = hookenv.config()
46- livepatch_key = config.get('livepatch_key')
47+ livepatch_key = config.get("livepatch_key")
48
49 if livepatch_key:
50 # disable prior to enabling to work around LP#1628823
51- cmd = ['/snap/bin/canonical-livepatch', 'disable']
52+ cmd = ["/snap/bin/canonical-livepatch", "disable"]
53 try:
54 check_output(cmd, universal_newlines=True)
55 except CalledProcessError as e:
56- hookenv.log('Unable to deactivate: {}'.format(str(e)))
57+ hookenv.log("Unable to deactivate: {}".format(str(e)))
58 # but let's soldier on...
59- cmd = ['/snap/bin/canonical-livepatch', 'enable', '{}'.format(livepatch_key.strip())]
60+ cmd = [
61+ "/snap/bin/canonical-livepatch",
62+ "enable",
63+ "{}".format(livepatch_key.strip()),
64+ ]
65 try:
66 check_output(cmd, universal_newlines=True)
67 except CalledProcessError as e:
68- hookenv.action_fail('Unable to activate: {}'.format(str(e)))
69+ hookenv.action_fail("Unable to activate: {}".format(str(e)))
70 return
71 else:
72- hookenv.action_set(dict(result='Activated'))
73+ hookenv.action_set(dict(result="Activated"))
74
75 else:
76- hookenv.action_fail('Unable to activate as no key has been set')
77+ hookenv.action_fail("Unable to activate as no key has been set")
78
79
80 def deactivate(params):
81- cmd = ['/snap/bin/canonical-livepatch', 'disable']
82+ """Execute deactivate action."""
83+ cmd = ["/snap/bin/canonical-livepatch", "disable"]
84 try:
85 check_output(cmd, universal_newlines=True)
86 except CalledProcessError as e:
87- hookenv.action_fail('Unable to deactivate: {}'.format(str(e)))
88+ hookenv.action_fail("Unable to deactivate: {}".format(str(e)))
89 return
90- hookenv.action_set(dict(result='Deactivated'))
91+ hookenv.action_set(dict(result="Deactivated"))
92
93
94 def refresh(params):
95- cmd = ['/snap/bin/canonical-livepatch', 'refresh']
96+ """Execute refresh action."""
97+ cmd = ["/snap/bin/canonical-livepatch", "refresh"]
98 try:
99 check_output(cmd, universal_newlines=True)
100 except CalledProcessError as e:
101- hookenv.action_fail('Unable to refresh: {}'.format(str(e)))
102+ hookenv.action_fail("Unable to refresh: {}".format(str(e)))
103 return
104- hookenv.action_set(dict(result='Refreshed'))
105+ hookenv.action_set(dict(result="Refreshed"))
106
107
108 def main(argv):
109+ """Select the appropriate action."""
110 action = os.path.basename(argv[0])
111 params = hookenv.action_get()
112 try:
113- if action == 'activate':
114+ if action == "activate":
115 activate(params)
116- elif action == 'deactivate':
117+ elif action == "deactivate":
118 deactivate(params)
119- elif action == 'refresh':
120+ elif action == "refresh":
121 refresh(params)
122 else:
123- hookenv.action_fail('Action {} not implemented'.format(action))
124+ hookenv.action_fail("Action {} not implemented".format(action))
125 except Exception:
126- hookenv.action_fail('Unhandled exception')
127+ hookenv.action_fail("Unhandled exception")
128 tb = traceback.format_exc()
129 hookenv.action_set(dict(traceback=tb))
130- hookenv.log('Unhandled exception in action {}'.format(action))
131+ hookenv.log("Unhandled exception in action {}".format(action))
132 print(tb)
133
134
135-if __name__ == '__main__':
136+if __name__ == "__main__":
137 main(sys.argv)
138diff --git a/files/check_canonical-livepatch.py b/files/check_canonical-livepatch.py
139index cafd472..f7ce127 100755
140--- a/files/check_canonical-livepatch.py
141+++ b/files/check_canonical-livepatch.py
142@@ -1,75 +1,78 @@
143 #!/usr/bin/env python3
144+"""Check canonical-livepatch and alert."""
145
146 # Copyright (C) 2016 Canonical Ltd.
147
148 import os
149+from subprocess import call, check_output
150+
151 import nagios_plugin3
152-from subprocess import check_output, call
153+
154 from yaml import safe_load
155
156-supported_archs = ['x86_64']
157+supported_archs = ["x86_64"]
158
159
160 def check_snap_installed():
161- """Confirm the snap is installed, raise an error if not"""
162- cmd = ['snap', 'list', 'canonical-livepatch']
163+ """Confirm the snap is installed, raise an error if not."""
164+ cmd = ["snap", "list", "canonical-livepatch"]
165 try:
166- check_output(cmd).decode('UTF-8')
167+ check_output(cmd).decode("UTF-8")
168 except Exception:
169- raise nagios_plugin3.CriticalError('canonical-livepatch snap is not installed')
170+ raise nagios_plugin3.CriticalError("canonical-livepatch snap is not installed")
171
172
173 def load_status():
174- """Load the cached status from disk, return it as a string"""
175- livepatch_output_path = '/var/lib/nagios/canonical-livepatch-status.txt'
176+ """Load the cached status from disk, return it as a string."""
177+ livepatch_output_path = "/var/lib/nagios/canonical-livepatch-status.txt"
178
179- with open(livepatch_output_path, 'r') as canonical_livepatch_log:
180+ with open(livepatch_output_path, "r") as canonical_livepatch_log:
181 livepatch_status = canonical_livepatch_log.read()
182
183 return livepatch_status.strip()
184
185
186 def check_serious_errors():
187- """In serious error cases, the output will not be YAML"""
188+ """Check serious error cases, the output will not be YAML."""
189 livepatch_status = load_status()
190
191 # if it's empty, something's definitely wrong
192- if livepatch_status == '':
193- raise nagios_plugin3.CriticalError('No output from canonical-livepatch status')
194+ if livepatch_status == "":
195+ raise nagios_plugin3.CriticalError("No output from canonical-livepatch status")
196
197 # in some cases, it's obviously not valid YAML
198 try:
199 livepatch_yaml = safe_load(livepatch_status)
200 except Exception:
201- raise nagios_plugin3.CriticalError(livepatch_status.replace('\n', ' '))
202+ raise nagios_plugin3.CriticalError(livepatch_status.replace("\n", " "))
203
204 # in other cases, it's less obvious until we try to parse
205 try:
206- livepatch_yaml['status']
207+ livepatch_yaml["status"]
208 except TypeError:
209- raise nagios_plugin3.CriticalError(livepatch_status.replace('\n', ' '))
210+ raise nagios_plugin3.CriticalError(livepatch_status.replace("\n", " "))
211
212
213 def active_kernel_version():
214- """Return the active kernel version, from livepatch's perspective"""
215+ """Return the active kernel version, from livepatch's perspective."""
216 livepatch_status = load_status()
217 status_yaml = safe_load(livepatch_status)
218- for kernel in status_yaml.get('status'):
219- if kernel.get('running') is True:
220- return kernel.get('kernel')
221+ for kernel in status_yaml.get("status"):
222+ if kernel.get("running") is True:
223+ return kernel.get("kernel")
224
225
226 def check_status():
227- """Check the cached status, raise an error if we find any issues"""
228+ """Check the cached status, raise an error if we find any issues."""
229 livepatch_status = load_status()
230 errors = []
231
232 status_yaml = safe_load(livepatch_status)
233
234- for kernel in status_yaml.get('status'):
235- if kernel.get('running') is True:
236- check_state = kernel.get('livepatch').get('checkState')
237- patch_state = kernel.get('livepatch').get('patchState')
238+ for kernel in status_yaml.get("status"):
239+ if kernel.get("running") is True:
240+ check_state = kernel.get("livepatch").get("checkState")
241+ patch_state = kernel.get("livepatch").get("patchState")
242
243 check_state_error = check_check_state(check_state)
244 patch_state_error = check_patch_state(patch_state)
245@@ -80,66 +83,67 @@ def check_status():
246 errors.append(patch_state_error)
247
248 if errors:
249- raise nagios_plugin3.CriticalError(' '.join(errors))
250+ raise nagios_plugin3.CriticalError(" ".join(errors))
251
252
253 def check_check_state(check_state):
254- """Check for issues with checkState, including unexpected output"""
255- if check_state in ['checked', 'needs-check']:
256+ """Check for issues with checkState, including unexpected output."""
257+ if check_state in ["checked", "needs-check"]:
258 pass
259- elif check_state == 'check-failed':
260- return 'Livepatch failed to check the remote service for patches.'
261+ elif check_state == "check-failed":
262+ return "Livepatch failed to check the remote service for patches."
263 else:
264- return 'Unknown check state: {}'.format(check_state)
265+ return "Unknown check state: {}".format(check_state)
266
267
268 def check_patch_state(patch_state):
269- """Check for issues with patchState, including unexpected output"""
270- if patch_state in ['applied', 'applying', 'nothing-to-apply']:
271+ """Check for issues with patchState, including unexpected output."""
272+ if patch_state in ["applied", "applying", "nothing-to-apply"]:
273 pass
274- elif patch_state == 'unapplied':
275- return 'Livepatch has not applied the downloaded patches.'
276- elif patch_state == 'applied-with-bug':
277- return 'Livepatch has detected a kernel bug while applying patches.'
278- elif patch_state == 'apply-failed':
279- return 'Livepatch failed to apply patches.'
280- elif patch_state == 'kernel-upgrade-required':
281- return 'A kernel upgrade (and reboot) is required.'
282+ elif patch_state == "unapplied":
283+ return "Livepatch has not applied the downloaded patches."
284+ elif patch_state == "applied-with-bug":
285+ return "Livepatch has detected a kernel bug while applying patches."
286+ elif patch_state == "apply-failed":
287+ return "Livepatch failed to apply patches."
288+ elif patch_state == "kernel-upgrade-required":
289+ return "A kernel upgrade (and reboot) is required."
290 else:
291- return 'Unknown patch state: {}'.format(patch_state)
292+ return "Unknown patch state: {}".format(patch_state)
293
294
295 def lsb_release():
296- """Return /etc/lsb-release in a dict"""
297+ """Return /etc/lsb-release in a dict."""
298 d = {}
299- with open('/etc/lsb-release', 'r') as lsb:
300- for l in lsb:
301- k, v = l.split('=')
302+ with open("/etc/lsb-release", "r") as lsb:
303+ for line in lsb:
304+ k, v = line.split("=")
305 d[k.strip()] = v.strip()
306 return d
307
308
309 def init_is_systemd():
310 """Return True if the host system uses systemd, False otherwise."""
311- if lsb_release()['DISTRIB_CODENAME'] == 'trusty':
312+ if lsb_release()["DISTRIB_CODENAME"] == "trusty":
313 return False
314- return os.path.isdir('/run/systemd/system')
315+ return os.path.isdir("/run/systemd/system")
316
317
318 def is_container():
319- """Determine whether unit is running in a container
320+ """Determine whether unit is running in a container.
321
322 @return: boolean indicating if unit is in a container
323 """
324 if init_is_systemd():
325 # Detect using systemd-detect-virt
326- return call(['systemd-detect-virt', '--container', '--quiet']) == 0
327+ return call(["systemd-detect-virt", "--container", "--quiet"]) == 0
328 else:
329 # Detect using upstart container file marker
330- return os.path.exists('/run/container_type')
331+ return os.path.exists("/run/container_type")
332
333
334 def main():
335+ """Run all the checks."""
336 arch = os.uname()[4]
337 if arch not in supported_archs:
338 raise nagios_plugin3.CriticalError(
339diff --git a/reactive/canonical_livepatch.py b/reactive/canonical_livepatch.py
340index 25f1f3c..b3a0dcd 100644
341--- a/reactive/canonical_livepatch.py
342+++ b/reactive/canonical_livepatch.py
343@@ -1,264 +1,303 @@
344-from charms.layer import snap
345-from charms.reactive import when, when_not, set_flag, clear_flag, hook
346-from charms.reactive.flags import register_trigger
347-from charmhelpers.core.host import write_file, is_container
348-from charmhelpers.core import hookenv
349-from charmhelpers.contrib.charmsupport import nrpe
350+"""Charm hooks."""
351+
352 from distutils.version import LooseVersion
353 from os import environ, mkdir, path, uname
354-from subprocess import check_call, check_output, CalledProcessError
355+from subprocess import CalledProcessError, check_call, check_output
356 from time import sleep
357+
358+from charmhelpers.contrib.charmsupport import nrpe
359+from charmhelpers.core import hookenv
360+from charmhelpers.core.host import is_container, write_file
361+
362+from charms.layer import snap
363+from charms.reactive import clear_flag, hook, set_flag, when, when_not
364+from charms.reactive.flags import register_trigger
365+
366 from yaml import safe_load
367
368
369 def file_to_units(local_path, unit_path):
370- """ copy a file from the charm onto our unit(s) """
371- if local_path[-3:] == '.py':
372+ """Copy a file from the charm onto our unit(s)."""
373+ if local_path[-3:] == ".py":
374 perms = 0o755
375 else:
376 perms = 0o644
377
378- fh = open(local_path, 'r')
379+ fh = open(local_path, "r")
380 write_file(
381- path=unit_path,
382- content=fh.read().encode(),
383- owner='root',
384- perms=perms,
385+ path=unit_path, content=fh.read().encode(), owner="root", perms=perms,
386 )
387
388
389 def wait_for_path(file_path, timeout=30):
390- hookenv.log('Waiting for up to {}s for {}'.format(timeout, file_path))
391+ """Wait until path exists or timeout."""
392+ hookenv.log("Waiting for up to {}s for {}".format(timeout, file_path))
393 seconds_waited = 0
394 interval = 1
395 while not (path.exists(file_path)):
396- hookenv.log('{} does not exist - waiting {}s'.format(file_path, interval))
397+ hookenv.log("{} does not exist - waiting {}s".format(file_path, interval))
398 sleep(interval)
399 seconds_waited += interval
400 if seconds_waited >= timeout:
401- hookenv.log('Giving up waiting for {}'.format(file_path), hookenv.ERROR)
402+ hookenv.log("Giving up waiting for {}".format(file_path), hookenv.ERROR)
403 return
404 return
405
406
407 def wait_for_livepatch():
408- wait_for_path('/var/snap/canonical-livepatch/current/livepatchd-priv.sock')
409+ """Wait until canonical-livepatch socket is created."""
410+ wait_for_path("/var/snap/canonical-livepatch/current/livepatchd-priv.sock")
411
412
413 def unit_update(status=None, message=None):
414+ """Update status message."""
415 if status and message:
416 hookenv.status_set(status, message)
417 else:
418 patch_details = get_patch_details()
419- hookenv.status_set('active', 'Running kernel {}, patchState: {}'.format(*patch_details))
420+ hookenv.status_set(
421+ "active", "Running kernel {}, patchState: {}".format(*patch_details)
422+ )
423
424
425 def get_livepatch_status():
426- cmd = ['/snap/bin/canonical-livepatch', 'status', '--format', 'yaml']
427- livepatch_status = ''
428+ """Get livepatch status."""
429+ cmd = ["/snap/bin/canonical-livepatch", "status", "--format", "yaml"]
430+ livepatch_status = ""
431 try:
432 livepatch_status = check_output(cmd, universal_newlines=True)
433 except FileNotFoundError:
434 # If the snap's not installed yet, don't crash out
435 pass
436 except CalledProcessError:
437- # If the service hasn't been enabled yet, we'll get a process error - this is fine
438+ # If the service hasn't been enabled yet,
439+ # we'll get a process error - this is fine
440 pass
441 return livepatch_status
442
443
444 def write_status_to_disk():
445+ """Write livepatch status to disk."""
446 # In a race with nrpe, create /var/lib/nagios if nrpe didn't do it yet
447- if not path.exists('/var/lib/nagios'):
448- mkdir('/var/lib/nagios')
449+ if not path.exists("/var/lib/nagios"):
450+ mkdir("/var/lib/nagios")
451
452 current_status = get_livepatch_status()
453 perms = 0o644
454 write_file(
455- path='/var/lib/nagios/canonical-livepatch-status.txt',
456+ path="/var/lib/nagios/canonical-livepatch-status.txt",
457 content=current_status,
458- owner='root',
459+ owner="root",
460 perms=perms,
461 )
462
463
464 def get_patch_details():
465- kernel = 'unknown'
466- patch_state = 'unknown'
467+ """Get patch details.
468+
469+ :return: a tuple containing kernel version and patch state.
470+ """
471+ kernel = "unknown"
472+ patch_state = "unknown"
473 raw_status = get_livepatch_status()
474
475 # status will usually pass YAML (but not always!)
476 try:
477 status = safe_load(raw_status)
478 except Exception:
479- hookenv.log('Unable to parse status yaml', hookenv.ERROR)
480+ hookenv.log("Unable to parse status yaml", hookenv.ERROR)
481 return kernel, raw_status
482
483 # even if we got YAML, be paranoid
484 try:
485- for k in status['status']:
486- if k['running'] is True:
487- kernel = k['kernel']
488- patch_state = k['livepatch']['patchState']
489+ for k in status["status"]:
490+ if k["running"] is True:
491+ kernel = k["kernel"]
492+ patch_state = k["livepatch"]["patchState"]
493 except Exception:
494- hookenv.log('Unable to find patching details in status yaml', hookenv.ERROR)
495+ hookenv.log("Unable to find patching details in status yaml", hookenv.ERROR)
496 return kernel, patch_state
497
498 return kernel, patch_state
499
500
501 def configure_proxies(proxy=None):
502- for proto in ('http-proxy', 'https-proxy'):
503+ """Configure proxies."""
504+ for proto in ("http-proxy", "https-proxy"):
505 if proxy is None:
506- proxy = ''
507- cmd = ['/snap/bin/canonical-livepatch', 'config', '{}={}'.format(proto, proxy)]
508- hookenv.log('Configuring {} as {}'.format(proto, proxy))
509+ proxy = ""
510+ cmd = ["/snap/bin/canonical-livepatch", "config", "{}={}".format(proto, proxy)]
511+ hookenv.log("Configuring {} as {}".format(proto, proxy))
512 try:
513 check_call(cmd, universal_newlines=True)
514 except CalledProcessError:
515- hookenv.log('Failed to set proxy', hookenv.ERROR)
516+ hookenv.log("Failed to set proxy", hookenv.ERROR)
517
518
519 def activate_livepatch():
520- unit_update('maintenance', 'Updating API key')
521+ """Activate livepatch."""
522+ unit_update("maintenance", "Updating API key")
523 config = hookenv.config()
524
525- livepatch_key = config.get('livepatch_key')
526+ livepatch_key = config.get("livepatch_key")
527 if livepatch_key:
528 # disable prior to enabling to work around LP#1628823
529- cmd = ['/snap/bin/canonical-livepatch', 'disable']
530- hookenv.log('Disabling canonical-livepatch ahead of key change to work around LP#1628823')
531+ cmd = ["/snap/bin/canonical-livepatch", "disable"]
532+ hookenv.log(
533+ "Disabling canonical-livepatch ahead "
534+ "of key change to work around LP#1628823"
535+ )
536 try:
537 check_output(cmd, universal_newlines=True)
538 except CalledProcessError as e:
539- hookenv.log('Unable to deactivate: {}'.format(str(e)), hookenv.ERROR)
540-
541- cmd = ['/snap/bin/canonical-livepatch', 'enable', '{}'.format(livepatch_key.strip())]
542- hookenv.log('Activating canonical-livepatch with your key')
543+ hookenv.log("Unable to deactivate: {}".format(str(e)), hookenv.ERROR)
544+
545+ cmd = [
546+ "/snap/bin/canonical-livepatch",
547+ "enable",
548+ "{}".format(livepatch_key.strip()),
549+ ]
550+ hookenv.log("Activating canonical-livepatch with your key")
551 try:
552 check_output(cmd, universal_newlines=True)
553 except CalledProcessError as e:
554- hookenv.log('Unable to activate: {}'.format(str(e)), hookenv.ERROR)
555- clear_flag('canonical-livepatch.active')
556- unit_update('blocked', 'Activation failed')
557+ hookenv.log("Unable to activate: {}".format(str(e)), hookenv.ERROR)
558+ clear_flag("canonical-livepatch.active")
559+ unit_update("blocked", "Activation failed")
560 else:
561- set_flag('canonical-livepatch.active')
562+ set_flag("canonical-livepatch.active")
563 unit_update()
564 else:
565- hookenv.log('Unable to activate canonical-livepatch as no key has been set', hookenv.ERROR)
566- cmd = ['/snap/bin/canonical-livepatch', 'disable']
567+ hookenv.log(
568+ "Unable to activate canonical-livepatch as no key has been set",
569+ hookenv.ERROR,
570+ )
571+ cmd = ["/snap/bin/canonical-livepatch", "disable"]
572 try:
573 check_output(cmd, universal_newlines=True)
574 except CalledProcessError as e:
575- hookenv.log('Unable to deactivate: {}'.format(str(e)), hookenv.ERROR)
576- clear_flag('canonical-livepatch.active')
577- unit_update('blocked', 'Service disabled, please set livepatch_key to activate')
578+ hookenv.log("Unable to deactivate: {}".format(str(e)), hookenv.ERROR)
579+ clear_flag("canonical-livepatch.active")
580+ unit_update("blocked", "Service disabled, please set livepatch_key to activate")
581
582
583-register_trigger(when='config.changed.livepatch_proxy', clear_flag='livepatch-proxy.configured')
584+register_trigger(
585+ when="config.changed.livepatch_proxy", clear_flag="livepatch-proxy.configured"
586+)
587
588
589-@when_not('canonical-livepatch.supported')
590+@when_not("canonical-livepatch.supported")
591 def livepatch_supported():
592+ """Check if livepatch is supported and set flag."""
593 arch = uname()[4]
594- supported_archs = ['x86_64', ]
595+ supported_archs = ["x86_64"]
596+
597 if arch not in supported_archs:
598- hookenv.log('Livepatch does not currently support {} architecture'.format(arch))
599- unit_update('blocked', 'Architecture {} is not supported by livepatch'.format(arch))
600+ hookenv.log("Livepatch does not currently support {} architecture".format(arch))
601+ unit_update(
602+ "blocked", "Architecture {} is not supported by livepatch".format(arch)
603+ )
604 elif is_container() and not hookenv.config()["enable_container"]:
605- hookenv.log('OS container detected, livepatch is not needed')
606- unit_update('blocked', 'Livepatch is not needed in OS containers')
607+ hookenv.log("OS container detected, livepatch is not needed")
608+ unit_update("blocked", "Livepatch is not needed in OS containers")
609 else:
610- set_flag('canonical-livepatch.supported')
611+ set_flag("canonical-livepatch.supported")
612
613
614-@when('canonical-livepatch.supported')
615-@when_not('snap.installed.canonical-livepatch')
616+@when("canonical-livepatch.supported")
617+@when_not("snap.installed.canonical-livepatch")
618 def install_livepatch():
619+ """Install livepatch."""
620 config = hookenv.config()
621- snap_channel = config.get('snap_channel')
622- snap.install('canonical-livepatch', **{'channel': snap_channel, })
623+ snap_channel = config.get("snap_channel")
624+ snap.install("canonical-livepatch", **{"channel": snap_channel})
625
626
627-@when('snap.installed.canonical-livepatch')
628-@when_not('livepatch-proxy.configured')
629+@when("snap.installed.canonical-livepatch")
630+@when_not("livepatch-proxy.configured")
631 def proxy_settings():
632+ """Get proxy settings and configure it."""
633 # Configure proxies early, if required - LP#1761661
634
635 preferred_proxy = None # default to None
636
637 for key, value in environ.items():
638 # use environment's https_proxy or http_proxy if either are set
639- if key == 'https_proxy':
640+ if key == "https_proxy":
641 preferred_proxy = value
642- elif key == 'http_proxy':
643+ elif key == "http_proxy":
644 preferred_proxy = value
645
646 # but if we have a charm configured proxy, prefer that
647 config = hookenv.config()
648- charm_config_proxy = config.get('livepatch_proxy')
649+ charm_config_proxy = config.get("livepatch_proxy")
650 if charm_config_proxy:
651 preferred_proxy = charm_config_proxy
652
653 # whatever we prefer (or None), configure it!
654 configure_proxies(preferred_proxy)
655
656- set_flag('livepatch-proxy.configured')
657+ set_flag("livepatch-proxy.configured")
658
659
660-@when('snap.installed.canonical-livepatch')
661-@when('livepatch-proxy.configured')
662-@when_not('canonical-livepatch.connected')
663+@when("snap.installed.canonical-livepatch")
664+@when("livepatch-proxy.configured")
665+@when_not("canonical-livepatch.connected")
666 def canonical_livepatch_connect():
667+ """Check if livepatch socket is created and update unit."""
668 # So if we've just installed snapd on a trusty system, we will not be on
669 # the HWE kernel yet and unfortunately need to reboot first!
670 current = LooseVersion(uname()[2])
671- required = LooseVersion('4.4')
672- uptrack_path = '/usr/sbin/uptrack-upgrade'
673+ required = LooseVersion("4.4")
674+ uptrack_path = "/usr/sbin/uptrack-upgrade"
675 if path.exists(uptrack_path):
676- hookenv.log('Ksplice/Uptrack detected, please remove it and reboot')
677- unit_update('blocked', 'Remove ksplice and then reboot')
678+ hookenv.log("Ksplice/Uptrack detected, please remove it and reboot")
679+ unit_update("blocked", "Remove ksplice and then reboot")
680 elif current < required:
681- hookenv.log('Reboot required, kernel {} is too old'.format(current))
682- unit_update('blocked', 'A reboot is required')
683+ hookenv.log("Reboot required, kernel {} is too old".format(current))
684+ unit_update("blocked", "A reboot is required")
685 else:
686- unit_update('maintenance', 'Connecting to the livepatch service')
687+ unit_update("maintenance", "Connecting to the livepatch service")
688 # Make sure the service is ready for us
689 wait_for_livepatch()
690- set_flag('canonical-livepatch.connected')
691- unit_update('blocked', 'Service disabled, please set livepatch_key to activate')
692+ set_flag("canonical-livepatch.connected")
693+ unit_update("blocked", "Service disabled, please set livepatch_key to activate")
694
695
696-@when('canonical-livepatch.connected')
697-@when_not('config.changed.livepatch_key', 'canonical-livepatch.active')
698+@when("canonical-livepatch.connected")
699+@when_not("config.changed.livepatch_key", "canonical-livepatch.active")
700 def init_key():
701+ """Activate livepatch."""
702 # If deployed under Trusty before rebooting into the HWE kernel
703 # the config-changed hook won't fire post-reboot as the state
704 # isn't tracked, but we didn't initialise yet! So, handle it here
705 activate_livepatch()
706
707
708-@when('canonical-livepatch.connected', 'config.changed.livepatch_key')
709+@when("canonical-livepatch.connected", "config.changed.livepatch_key")
710 def update_key():
711+ """Activate livepatch and write status to disk."""
712 # handle regular config-changed hooks for the livepatch key
713 activate_livepatch()
714 write_status_to_disk()
715
716
717-@when('snap.installed.canonical-livepatch', 'config.changed.snap_channel')
718+@when("snap.installed.canonical-livepatch", "config.changed.snap_channel")
719 def change_channel():
720+ """Update snap channel."""
721 config = hookenv.config()
722- snap_channel = config.get('snap_channel')
723+ snap_channel = config.get("snap_channel")
724 # refresh to the given channel
725- snap.refresh('canonical-livepatch', **{'channel': snap_channel, })
726+ snap.refresh("canonical-livepatch", **{"channel": snap_channel})
727
728
729 # Set up Nagios checks when the nrpe-external-master subordinate is related
730-@when('nrpe-external-master.available')
731-@when_not('canonical-livepatch.nagios-setup.complete')
732-@when('canonical-livepatch.supported')
733+@when("nrpe-external-master.available")
734+@when_not("canonical-livepatch.nagios-setup.complete")
735+@when("canonical-livepatch.supported")
736 def configure_nagios(nagios):
737- if hookenv.hook_name() == 'update-status':
738+ """Configure nagios checks."""
739+ if hookenv.hook_name() == "update-status":
740 return
741
742 # Ask charmhelpers.contrib.charmsupport's nrpe to work out our hostname
743@@ -267,44 +306,43 @@ def configure_nagios(nagios):
744
745 # install nagios support files
746 file_to_units(
747- 'files/check_canonical-livepatch.cron',
748- '/etc/cron.d/check_canonical-livepatch',
749+ "files/check_canonical-livepatch.cron", "/etc/cron.d/check_canonical-livepatch",
750 )
751 file_to_units(
752- 'files/check_canonical-livepatch.py',
753- '/usr/lib/nagios/plugins/check_canonical-livepatch.py',
754+ "files/check_canonical-livepatch.py",
755+ "/usr/lib/nagios/plugins/check_canonical-livepatch.py",
756 )
757
758 # write current status to disk to satisfy the nagios check
759 write_status_to_disk()
760
761 # remove check from previous release with poorly formed name
762- nrpe_setup.remove_check(
763- shortname='check_canonical-livepatch'
764- )
765+ nrpe_setup.remove_check(shortname="check_canonical-livepatch")
766
767 # use charmhelpers to create the check
768 nrpe_setup.add_check(
769- 'canonical-livepatch',
770- 'Verify canonical-livepatch is working',
771- '/usr/lib/nagios/plugins/check_canonical-livepatch.py'
772+ "canonical-livepatch",
773+ "Verify canonical-livepatch is working",
774+ "/usr/lib/nagios/plugins/check_canonical-livepatch.py",
775 )
776
777 nrpe_setup.write()
778
779 # Remove obsolete state from older charm, if present
780- clear_flag('canonical-livepatch.nagios-configured')
781+ clear_flag("canonical-livepatch.nagios-configured")
782 # Set our preferred state
783- set_flag('canonical-livepatch.nagios-setup.complete')
784+ set_flag("canonical-livepatch.nagios-setup.complete")
785
786
787-@when('snap.installed.canonical-livepatch', 'canonical-livepatch.active')
788+@when("snap.installed.canonical-livepatch", "canonical-livepatch.active")
789 def update_kernel_version():
790+ """Update kernel version."""
791 unit_update()
792
793
794 # This is triggered on any config-changed, and after an upgrade-charm - you
795 # don't get the latter with @when('config.changed')
796-@hook('config-changed')
797+@hook("config-changed")
798 def set_nrpe_flag():
799- clear_flag('canonical-livepatch.nagios-setup.complete')
800+ """Run config changed."""
801+ clear_flag("canonical-livepatch.nagios-setup.complete")
802diff --git a/tests/functional/tests/test_canonical_livepatch.py b/tests/functional/tests/test_canonical_livepatch.py
803index 684cb2a..e87e876 100644
804--- a/tests/functional/tests/test_canonical_livepatch.py
805+++ b/tests/functional/tests/test_canonical_livepatch.py
806@@ -1,22 +1,24 @@
807+"""Zaza functional tests."""
808+import logging
809 import unittest
810+
811 import yaml
812+
813 import zaza.model as model
814-import logging
815
816
817 class TestBase(unittest.TestCase):
818- """Base Class for charm functional tests"""
819+ """Base Class for charm functional tests."""
820+
821 @classmethod
822 def setUpClass(cls):
823- """ Run setup for tests. """
824+ """Run setup for tests."""
825 cls.model_name = model.get_juju_model()
826 cls.application_name = "canonical-livepatch"
827 cls.lead_unit_name = model.get_lead_unit_name(
828 cls.application_name, model_name=cls.model_name
829 )
830- cls.units = model.get_units(
831- cls.application_name, model_name=cls.model_name
832- )
833+ cls.units = model.get_units(cls.application_name, model_name=cls.model_name)
834
835 cls.lead_unit = cls.units[0]
836
837@@ -24,9 +26,13 @@ class TestBase(unittest.TestCase):
838
839
840 class TestCanonicalLivepatch(TestBase):
841+ """Class for charm functional tests."""
842+
843 def test_01_install(self):
844- if self.lead_unit.workload_status_message == ("Livepatch "
845- "is not needed in OS containers"):
846+ """Verify that the snap is installed."""
847+ if self.lead_unit.workload_status_message == (
848+ "Livepatch is not needed in OS containers"
849+ ):
850 model.set_application_config(
851 self.application_name, {"enable_container": "true"}
852 )
853@@ -37,6 +43,7 @@ class TestCanonicalLivepatch(TestBase):
854 self.assertEqual(code, "0")
855
856 def test_02_status(self):
857+ """Verify canonical-livepatch status."""
858 # run a status check - we expect this to return 1 due to no access key
859 cmd = "sudo canonical-livepatch status"
860 result = model.run_on_unit(self.lead_unit_name, cmd)
861@@ -44,10 +51,11 @@ class TestCanonicalLivepatch(TestBase):
862 self.assertEqual(code, "1")
863
864 def test_03_nagios_init(self):
865+ """Verify nagios plugins are rendered."""
866 for path in [
867- '/etc/cron.d/check_canonical-livepatch',
868- '/usr/lib/nagios/plugins/check_canonical-livepatch.py',
869- '/var/lib/nagios/canonical-livepatch-status.txt'
870+ "/etc/cron.d/check_canonical-livepatch",
871+ "/usr/lib/nagios/plugins/check_canonical-livepatch.py",
872+ "/var/lib/nagios/canonical-livepatch-status.txt",
873 ]:
874 logging.info("Checking that file '{}' exists".format(path))
875 cmd = "stat {}".format(path)
876@@ -56,20 +64,24 @@ class TestCanonicalLivepatch(TestBase):
877 self.assertEqual(code, "0")
878
879 def test_04_nagios_context_update(self):
880+ """Update nagios context and verify."""
881 test_context_name = "new_context"
882 model.set_application_config(
883 self.application_name, {"nagios_context": test_context_name}
884 )
885 model.block_until_all_units_idle()
886
887- cmd = "grep {} /var/lib/nagios/export/" \
888- "service__*_check_canonical-livepatch.cfg".format(test_context_name)
889+ cmd = (
890+ "grep {} /var/lib/nagios/export/"
891+ "service__*_check_canonical-livepatch.cfg".format(test_context_name)
892+ )
893
894 result = model.run_on_unit(self.lead_unit_name, cmd)
895 code = result.get("Code")
896 self.assertEqual(code, "0")
897
898 def test_05_channel_update(self):
899+ """Update snap channel and verify."""
900 # verify the current channel
901 cmd = "snap info canonical-livepatch"
902 result = model.run_on_unit(self.lead_unit_name, cmd)
903@@ -83,9 +95,7 @@ class TestCanonicalLivepatch(TestBase):
904 self.assertIn("stable", channel)
905
906 # change channel to 'beta'
907- model.set_application_config(
908- self.application_name, {"snap_channel": "beta"}
909- )
910+ model.set_application_config(self.application_name, {"snap_channel": "beta"})
911 model.block_until_all_units_idle()
912
913 # verify the current channel
914@@ -101,14 +111,17 @@ class TestCanonicalLivepatch(TestBase):
915 self.assertIn("beta", channel)
916
917 def test_06_nagios_servicegroup_update(self):
918+ """Update nagios service group and verify."""
919 test_servicegroup_name = "new_servicegroup"
920 model.set_application_config(
921 self.application_name, {"nagios_servicegroups": test_servicegroup_name}
922 )
923 model.block_until_all_units_idle()
924
925- cmd = "grep {} /var/lib/nagios/export/" \
926- "service__*_check_canonical-livepatch.cfg".format(test_servicegroup_name)
927+ cmd = (
928+ "grep {} /var/lib/nagios/export/"
929+ "service__*_check_canonical-livepatch.cfg".format(test_servicegroup_name)
930+ )
931
932 result = model.run_on_unit(self.lead_unit_name, cmd)
933 code = result.get("Code")

Subscribers

People subscribed via source and target branches

to all changes: