2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
1 |
#!/usr/bin/python
|
2 |
||
3 |
from __future__ import print_function |
|
4 |
||
5 |
import optparse |
|
6 |
import datetime |
|
7 |
import distro_info |
|
8 |
import os |
|
9 |
import re |
|
10 |
import subprocess |
|
11 |
import sys |
|
12 |
||
13 |
import apt |
|
14 |
from UpdateManager.Core.utils import twrap, get_dist |
|
15 |
||
16 |
# set locale early so that the subsequent imports have localized
|
|
17 |
# strings
|
|
18 |
import locale |
|
19 |
try: |
|
20 |
locale.setlocale(locale.LC_ALL, "") |
|
21 |
except: |
|
22 |
pass
|
|
23 |
||
24 |
from gettext import gettext as _ |
|
25 |
import gettext |
|
26 |
gettext.textdomain("update-manager") |
|
27 |
||
28 |
||
29 |
from HweSupportStatus.consts import ( |
|
30 |
Messages, |
|
31 |
LTS_EOL_DATE, |
|
32 |
HWE_EOL_DATE, |
|
33 |
NEXT_LTS_DOT1_DATE, |
|
34 |
)
|
|
35 |
||
36 |
||
37 |
# HWE stack with a short support period
|
|
38 |
HWE_UNSUPPORTED_BACKPORTS = ( |
|
39 |
"-lts-utopic", |
|
40 |
"-lts-vivid", |
|
41 |
"-lts-wily"
|
|
42 |
)
|
|
43 |
# from https://wiki.ubuntu.com/Kernel/LTSEnablementStack
|
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
44 |
UNSUPPORTED_KERNEL_IMAGE_REGEX = \ |
45 |
r'linux-image.*-(3\.16|3\.19|4\.2)(\.[0-9]+)?-.*' |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
46 |
|
47 |
# HWE stack with a long support period
|
|
2946
by Łukasz 'sil2100' Zemczak
Adjust dates in hwe-support-status for jammy. |
48 |
HWE_SUPPORTED_BACKPORT = "-hwe-22.04" |
2879
by Łukasz 'sil2100' Zemczak
Adjust dates in hwe-support-status for focal. |
49 |
SUPPORTED_KERNEL_IMAGE_REGEX = r'^$' # No fixed backported kernel yet |
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
50 |
|
51 |
||
52 |
KERNEL_METAPKGS = ( |
|
53 |
"linux-generic", |
|
54 |
"linux-image-generic", |
|
55 |
"linux-signed-generic", |
|
56 |
"linux-signed-image-generic", |
|
57 |
)
|
|
58 |
XORG_METAPKGS = ( |
|
59 |
"xserver-xorg", |
|
60 |
"libgl1-mesa-glx", |
|
2739
by Brian Murray
add libwayland-egl1-mesa to the list of metapackages. |
61 |
# LP: #1610434 - Ubuntu GNOME needed libwayland
|
62 |
"libwayland-egl1-mesa", |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
63 |
)
|
2740
by Brian Murray
utilize a virtualbox metapackage set. |
64 |
VBOX_METAPKGS = ( |
65 |
"virtualbox-guest-utils", |
|
66 |
"virtualbox-guest-source"
|
|
67 |
)
|
|
68 |
METAPKGS = KERNEL_METAPKGS + XORG_METAPKGS + VBOX_METAPKGS |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
69 |
|
70 |
||
71 |
class Package: |
|
72 |
"""A lightweight apt package """
|
|
73 |
def __init__(self, name, version, arch, foreign=False): |
|
74 |
self.name = name |
|
75 |
self.installed_version = version |
|
76 |
self.arch = arch |
|
77 |
self.foreign = foreign |
|
78 |
||
79 |
||
80 |
def find_hwe_packages(installed_packages): |
|
81 |
unsupported_hwe_packages = set() |
|
82 |
supported_hwe_packages = set() |
|
83 |
for pkg in installed_packages: |
|
84 |
# metapackages and X are marked with the -lts-$distro string
|
|
85 |
for name in HWE_UNSUPPORTED_BACKPORTS: |
|
86 |
if pkg.name.endswith(name): |
|
87 |
unsupported_hwe_packages.add(pkg) |
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
88 |
# The individual backported kernels have names like
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
89 |
# linux-image-3.11.0-17-generic
|
90 |
# so we match via a regexp.
|
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
91 |
#
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
92 |
# The linux-image-generic-lts-$distro metapkg has additional
|
93 |
# dependencies (like linux-firmware) so we can't just walk the
|
|
94 |
# dependency chain.
|
|
95 |
if re.match(UNSUPPORTED_KERNEL_IMAGE_REGEX, pkg.name): |
|
96 |
unsupported_hwe_packages.add(pkg) |
|
97 |
# SUPPORTED
|
|
98 |
if pkg.name.endswith(HWE_SUPPORTED_BACKPORT): |
|
99 |
supported_hwe_packages.add(pkg) |
|
100 |
if re.match(SUPPORTED_KERNEL_IMAGE_REGEX, pkg.name): |
|
101 |
supported_hwe_packages.add(pkg) |
|
102 |
return unsupported_hwe_packages, supported_hwe_packages |
|
103 |
||
104 |
||
105 |
def is_unsupported_hwe_kernel_running(unsupported_hwe_package): |
|
106 |
# kernels do not conflict with each other, so we need to check
|
|
107 |
# what version is actually running
|
|
108 |
running_kernel_ver = os.uname()[2] |
|
109 |
# the running kernel without the abi or buildver
|
|
110 |
running_kernel_ver = running_kernel_ver.split("-")[0] |
|
111 |
for pkg in unsupported_hwe_package: |
|
112 |
if not pkg.name.startswith("linux-"): |
|
113 |
continue
|
|
114 |
# we only care about the version, not abi or build
|
|
115 |
if pkg.installed_version.startswith(running_kernel_ver): |
|
116 |
return True |
|
117 |
return False |
|
118 |
||
119 |
||
120 |
def is_unsupported_xstack_running(unsupported_hwe_packages): |
|
121 |
# the HWE xstacks conflict with each other, so we can simply test
|
|
122 |
# for existence in the installed unsupported hwe packages
|
|
123 |
for pkg in unsupported_hwe_packages: |
|
124 |
for xorg_meta in XORG_METAPKGS: |
|
125 |
if pkg.name.startswith(xorg_meta): |
|
126 |
return True |
|
127 |
return False |
|
128 |
||
129 |
||
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
130 |
def find_supported_replacement_hwe_packages(unsupported_hwe_packages, |
131 |
installed_packages): |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
132 |
unsupported_metapkg_names = set() |
133 |
replacement_names = set() |
|
134 |
for metapkg in METAPKGS: |
|
135 |
for unsupported_backport in HWE_UNSUPPORTED_BACKPORTS: |
|
136 |
metapkg_name = metapkg + unsupported_backport |
|
137 |
for pkg in unsupported_hwe_packages: |
|
138 |
if pkg.name == metapkg_name: |
|
139 |
replacement_name = metapkg + HWE_SUPPORTED_BACKPORT |
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
140 |
if (replacement_name, pkg.arch) not in \ |
141 |
[(p.name, p.arch) for p in installed_packages]: |
|
142 |
if pkg.foreign: |
|
143 |
replacement_name += ':' + pkg.arch |
|
144 |
replacement_names.add(replacement_name) |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
145 |
unsupported_metapkg_names.add(metapkg_name) |
146 |
return unsupported_metapkg_names, replacement_names |
|
147 |
||
148 |
||
149 |
def is_unsupported_hwe_running(unsupported_hwe_packages): |
|
150 |
return (is_unsupported_hwe_kernel_running(unsupported_hwe_packages) or |
|
151 |
is_unsupported_xstack_running(unsupported_hwe_packages)) |
|
152 |
||
153 |
||
154 |
def advice_about_hwe_status(unsupported_hwe_packages, supported_hwe_packages, |
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
155 |
installed_packages, has_update_manager, today, |
156 |
verbose): |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
157 |
unsupported_hwe_stack_running = is_unsupported_hwe_running( |
158 |
unsupported_hwe_packages) |
|
159 |
unsupported_hwe_metapkgs, supported_replacement_hwe = \ |
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
160 |
find_supported_replacement_hwe_packages(unsupported_hwe_packages, |
161 |
installed_packages) |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
162 |
# we need the "-p" option until the next LTS point release is available
|
163 |
if today < NEXT_LTS_DOT1_DATE: |
|
164 |
do_release_upgrade_option = "-p" |
|
165 |
else: |
|
166 |
do_release_upgrade_option = "" |
|
167 |
||
168 |
if unsupported_hwe_stack_running: |
|
169 |
if today < HWE_EOL_DATE: |
|
170 |
s = Messages.HWE_SUPPORT_ENDS |
|
171 |
else: |
|
172 |
s = Messages.HWE_SUPPORT_HAS_ENDED |
|
173 |
if has_update_manager: |
|
174 |
print(s + Messages.UM_UPGRADE) |
|
175 |
else: |
|
176 |
# bug #1341320 - if no metapkg is left we need to show
|
|
177 |
# what is no longer supported
|
|
178 |
if supported_replacement_hwe: |
|
179 |
print(s + Messages.APT_UPGRADE % ( |
|
180 |
do_release_upgrade_option, |
|
181 |
" ".join(supported_replacement_hwe))) |
|
182 |
else: |
|
183 |
print(s + Messages.APT_SHOW_UNSUPPORTED % ( |
|
184 |
" ".join([pkg.name for pkg in unsupported_hwe_packages]))) |
|
185 |
||
186 |
# some unsupported package installed but not running and not superseded
|
|
187 |
# - this is worth reporting
|
|
188 |
elif (unsupported_hwe_packages and |
|
189 |
not supported_hwe_packages and |
|
190 |
not unsupported_hwe_stack_running): |
|
191 |
s = _(""" |
|
192 |
You have packages from the Hardware Enablement Stack (HWE) installed that
|
|
193 |
are going out of support on %s. |
|
194 |
""") % HWE_EOL_DATE |
|
195 |
if has_update_manager: |
|
196 |
print(s + Messages.UM_UPGRADE) |
|
197 |
else: |
|
198 |
print(s + Messages.APT_UPGRADE % ( |
|
199 |
do_release_upgrade_option, |
|
200 |
" ".join(supported_replacement_hwe))) |
|
201 |
elif supported_hwe_packages: |
|
202 |
print(Messages.HWE_SUPPORTED) |
|
203 |
elif verbose: |
|
204 |
print( |
|
205 |
_("You are not running a system with a Hardware Enablement Stack. " |
|
206 |
"Your system is supported until %(month)s %(year)s.") % { |
|
207 |
'month': LTS_EOL_DATE.strftime("%B"), |
|
208 |
'year': LTS_EOL_DATE.year}) |
|
209 |
||
210 |
||
211 |
if __name__ == "__main__": |
|
212 |
parser = optparse.OptionParser(description=_("Check HWE support status")) |
|
213 |
parser.add_option('--quiet', action='store_true', default=False, |
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
214 |
help="No output, exit code 10 on unsupported HWE " |
215 |
"packages") |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
216 |
parser.add_option('--verbose', action='store_true', default=False, |
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
217 |
help="more verbose output") |
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
218 |
parser.add_option('--show-all-unsupported', action='store_true', |
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
219 |
default=False, |
220 |
help="Show unsupported HWE packages") |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
221 |
parser.add_option('--show-replacements', action='store_true', |
222 |
default=False, |
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
223 |
help="show what packages need installing to be " |
224 |
"supported") |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
225 |
# hidden, only useful for testing
|
226 |
parser.add_option( |
|
227 |
'--disable-hwe-check-semaphore-file', |
|
228 |
default="/var/lib/update-notifier/disable-hwe-eol-messages", |
|
229 |
help=optparse.SUPPRESS_HELP) |
|
230 |
options, args = parser.parse_args() |
|
231 |
||
232 |
if options.quiet: |
|
233 |
nullfd = os.open(os.devnull, os.O_WRONLY) |
|
234 |
os.dup2(nullfd, sys.stdout.fileno()) |
|
235 |
||
236 |
# Check to see if we are an LTS release
|
|
237 |
di = distro_info.UbuntuDistroInfo() |
|
238 |
codename = get_dist() |
|
239 |
lts = di.is_lts(codename) |
|
240 |
if not lts: |
|
241 |
if options.verbose: |
|
242 |
print("Only LTS releases have Hardware Enablement stacks", |
|
243 |
file=sys.stderr) |
|
244 |
sys.exit(0) |
|
245 |
||
246 |
# request from PSE to be able to disable the hwe check via a special
|
|
247 |
# semaphore file
|
|
248 |
HWE_CHECK_DISABLED_FILE = options.disable_hwe_check_semaphore_file |
|
249 |
if os.path.exists(HWE_CHECK_DISABLED_FILE): |
|
250 |
if options.verbose: |
|
251 |
print("Forcefully disabled hwe-support-status via file %s" % |
|
252 |
HWE_CHECK_DISABLED_FILE, file=sys.stderr) |
|
253 |
sys.exit(0) |
|
254 |
||
255 |
foreign_archs = set(subprocess.check_output( |
|
2738
by Brian Murray
hwe-support-status: decode output when checking for foreign architectures |
256 |
['dpkg', '--print-foreign-architectures'], |
257 |
universal_newlines=True).split()) |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
258 |
|
259 |
# do the actual check
|
|
260 |
installed_packages = set() |
|
261 |
today = datetime.date.today() |
|
262 |
tagf = apt.apt_pkg.TagFile("/var/lib/dpkg/status") |
|
263 |
while tagf.step(): |
|
264 |
if tagf.section.find("Status", "") != "install ok installed": |
|
265 |
continue
|
|
266 |
pkgname = tagf.section.find("Package") |
|
267 |
version = tagf.section.find("Version") |
|
268 |
arch = tagf.section.find("Architecture") |
|
269 |
foreign = arch in foreign_archs |
|
270 |
installed_packages.add(Package(pkgname, version, arch, foreign)) |
|
271 |
||
272 |
has_update_manager = "update-manager" in [ |
|
273 |
pkg.name for pkg in installed_packages] |
|
274 |
unsupported_hwe_packages, supported_hwe_packages = find_hwe_packages( |
|
275 |
installed_packages) |
|
276 |
||
277 |
if options.show_all_unsupported: |
|
278 |
if today > HWE_EOL_DATE: |
|
279 |
print(twrap(" ".join([ |
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
280 |
pkg.foreign and pkg.name + ':' + pkg.arch or pkg.name |
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
281 |
for pkg in unsupported_hwe_packages]))) |
282 |
||
283 |
if options.show_replacements: |
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
284 |
unsupported, replacements = find_supported_replacement_hwe_packages( |
285 |
unsupported_hwe_packages, installed_packages) |
|
286 |
if replacements: |
|
287 |
print(" ".join(replacements)) |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
288 |
|
289 |
if not options.show_all_unsupported and not options.show_replacements: |
|
290 |
advice_about_hwe_status( |
|
291 |
unsupported_hwe_packages, supported_hwe_packages, |
|
2736
by Brian Murray
fix passing of installed_packages |
292 |
installed_packages, has_update_manager, today, |
293 |
options.verbose) |
|
2735
by Brian Murray
hwe-support-status: Do not show replacements that are already installed on |
294 |
if is_unsupported_hwe_running(unsupported_hwe_packages) and \ |
295 |
today > HWE_EOL_DATE: |
|
2727.1.1
by Brian Murray
Include HWE support tools and information. (LP: #1498059) |
296 |
sys.exit(10) |
297 |
||
298 |
sys.exit(0) |