Merge ~barryprice/charm-canonical-livepatch/+git/canonical-livepatch-charm:master into ~livepatch-charmers/charm-canonical-livepatch:master

Proposed by Barry Price
Status: Merged
Approved by: Barry Price
Approved revision: 62416fa29784df12e2a9842449ae5673dbe8f997
Merged at revision: 6308443772e8c506cde9b2b61caec86c443cae6f
Proposed branch: ~barryprice/charm-canonical-livepatch/+git/canonical-livepatch-charm:master
Merge into: ~livepatch-charmers/charm-canonical-livepatch:master
Diff against target: 187 lines (+90/-54)
1 file modified
files/check_canonical-livepatch.py (+90/-54)
Reviewer Review Type Date Requested Status
Stuart Bishop (community) Approve
Review via email: mp+355822@code.launchpad.net

Commit message

Clearer check output, and warn if the client output format changes (i.e. if checkState or patchState go away).

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
Stuart Bishop (stub) wrote :

Seems ok. Some comments inline.

review: Approve
Revision history for this message
Stuart Bishop (stub) wrote :

Yup, but see comments.

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

Change successfully merged at revision 6308443772e8c506cde9b2b61caec86c443cae6f

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/files/check_canonical-livepatch.py b/files/check_canonical-livepatch.py
index 7878169..87c7204 100755
--- a/files/check_canonical-livepatch.py
+++ b/files/check_canonical-livepatch.py
@@ -5,70 +5,108 @@
5import os5import os
6import nagios_plugin6import nagios_plugin
7from subprocess import check_output, call7from subprocess import check_output, call
8from yaml import safe_load
89
9supported_archs = ['x86_64']10supported_archs = ['x86_64']
1011
1112
12##############################################################################13def check_snap_installed():
1314 """Confirm the snap is installed, raise an error if not"""
14def check_package_installed():
15 cmd = ['snap', 'list', 'canonical-livepatch']15 cmd = ['snap', 'list', 'canonical-livepatch']
16 try:16 try:
17 check_output(cmd, universal_newlines=True)17 check_output(cmd, universal_newlines=True)
18 except Exception:18 except Exception:
19 raise nagios_plugin.CriticalError("canonical-livepatch snap is not installed")19 raise nagios_plugin.CriticalError('canonical-livepatch snap is not installed')
2020
2121
22##############################################################################22def load_status():
23 """Load the cached status from disk, return it as a string"""
24 livepatch_output_path = '/var/lib/nagios/canonical-livepatch-status.txt'
2325
24def check_vmlinuz():26 with open(livepatch_output_path, 'r') as canonical_livepatch_log:
25 vmlinuz = '/vmlinuz'27 livepatch_status = canonical_livepatch_log.read()
26 if os.path.exists(vmlinuz):28
27 full_kernel_path = os.path.realpath(vmlinuz)29 return livepatch_status
28 elif os.path.exists('/boot' + vmlinuz):30
29 vmlinuz = '/boot' + vmlinuz31
30 full_kernel_path = os.path.realpath(vmlinuz)32def check_serious_errors():
31 else:33 """In serious error cases, the output will not be YAML"""
32 return 'no /vmlinuz or /boot/vmlinuz'34 livepatch_status = load_status()
33 kernel_filename = os.path.basename(full_kernel_path)35
34 # remove 'vmlinuz'-' from start:36 # if it's empty, something's definitely wrong
35 kernel_version = '-'.join(kernel_filename.split('-', 1)[1:])37 if livepatch_status == '':
36 # check for '-generic-pae' kernels that need two removes:38 raise nagios_plugin.CriticalError('No output from canonical-livepatch status')
37 if '-generic-pae' in kernel_version:39
38 kernel_version = '-'.join(kernel_version.split('-')[:-1])40 # in some cases, it's obviously not valid YAML
39 # remove e.g. '-generic' from end:41 try:
40 kernel_version = '-'.join(kernel_version.split('-')[:-1])42 livepatch_yaml = safe_load(livepatch_status)
41 return kernel_version.strip()43 except Exception:
44 raise nagios_plugin.CriticalError(livepatch_status.replace('\n', ' '))
45
46 # in other cases, it's less obvious until we try to parse
47 try:
48 livepatch_yaml['status']
49 except KeyError:
50 raise nagios_plugin.CriticalError(livepatch_status.replace('\n', ' '))
4251
4352
44##############################################################################53def active_kernel_version():
54 """Return the active kernel version, from livepatch's perspective"""
55 livepatch_status = load_status()
56 status_yaml = safe_load(livepatch_status)
57 for kernel in status_yaml.get('status'):
58 if kernel.get('running') is True:
59 return kernel.get('kernel')
60
4561
46def check_status():62def check_status():
47 livepatch_output_path = '/var/lib/nagios/canonical-livepatch-status.txt'63 """Check the cached status, raise an error if we find any issues"""
48 err_lines = []64 livepatch_status = load_status()
49 wrn_lines = []65 errors = []
5066
51 with open(livepatch_output_path, 'r') as canonical_livepatch_log:67 status_yaml = safe_load(livepatch_status)
52 for line in canonical_livepatch_log:68
53 line = line.strip()69 for kernel in status_yaml.get('status'):
54 if 'State:' in line:70 if kernel.get('running') is True:
55 if 'apply-failed' in line:71 check_state = kernel.get('livepatch').get('checkState')
56 err_lines.append('Livepatch failed to apply patches.')72 patch_state = kernel.get('livepatch').get('patchState')
57 elif 'check-failed' in line:73
58 err_lines.append('Livepatch failed to check the remote service for patches.')74 check_state_error = check_check_state(check_state)
59 elif 'unknown' in line:75 patch_state_error = check_patch_state(patch_state)
60 err_lines.append('Livepatch reports an unknown error.')76
61 elif 'kernel-upgrade-required' in line:77 if check_state_error:
62 err_lines.append('A kernel upgrade (and reboot) is required.')78 errors.append(check_state_error)
63 elif 'Machine is not enabled' in line:79 if patch_state_error:
64 err_lines.append('Machine is not enabled.')80 errors.append(patch_state_error)
6581
66 if err_lines:82 if errors:
67 err = " ".join(err_lines)83 raise nagios_plugin.CriticalError(' '.join(errors))
68 raise nagios_plugin.CriticalError(err)84
69 elif wrn_lines:85
70 wrn = " ".join(wrn_lines)86def check_check_state(check_state):
71 raise nagios_plugin.WarnError(wrn)87 """Check for issues with checkState, including unexpected output"""
88 if check_state in ['checked', 'needs-check']:
89 pass
90 elif check_state == 'check-failed':
91 return 'Livepatch failed to check the remote service for patches.'
92 else:
93 return 'Unknown check state: {}'.format(check_state)
94
95
96def check_patch_state(patch_state):
97 """Check for issues with patchState, including unexpected output"""
98 if patch_state in ['applied', 'nothing-to-apply']:
99 pass
100 elif patch_state == 'unapplied':
101 return 'Livepatch has not applied the downloaded patches.'
102 elif patch_state == 'applied-with-bug':
103 return 'Livepatch has detected a kernel bug while applying patches.'
104 elif patch_state == 'apply-failed':
105 return 'Livepatch failed to apply patches.'
106 elif patch_state == 'kernel-upgrade-required':
107 return 'A kernel upgrade (and reboot) is required.'
108 else:
109 return 'Unknown patch state: {}'.format(patch_state)
72110
73111
74def lsb_release():112def lsb_release():
@@ -101,8 +139,6 @@ def is_container():
101 return os.path.exists('/run/container_type')139 return os.path.exists('/run/container_type')
102140
103141
104##############################################################################
105
106def main():142def main():
107 arch = os.uname()[4]143 arch = os.uname()[4]
108 if arch not in supported_archs:144 if arch not in supported_archs:
@@ -112,12 +148,12 @@ def main():
112 elif is_container():148 elif is_container():
113 print("canonical-livepatch not needed in OS containers.")149 print("canonical-livepatch not needed in OS containers.")
114 else:150 else:
115 nagios_plugin.try_check(check_package_installed)151 nagios_plugin.try_check(check_snap_installed)
152 nagios_plugin.try_check(check_serious_errors)
116 nagios_plugin.try_check(check_status)153 nagios_plugin.try_check(check_status)
117 print("OK - canonical-livepatch seems to be installed and working")154 kernel_version = active_kernel_version()
118155 print("OK - canonical-livepatch is active on kernel {}".format(kernel_version))
119156
120##############################################################################
121157
122if __name__ == "__main__":158if __name__ == "__main__":
123 main()159 main()

Subscribers

People subscribed via source and target branches