Skip to content
This repository was archived by the owner on Feb 28, 2023. It is now read-only.

Commit 6441d82

Browse files
committed
Add Debian/Ubuntu support.
1 parent c648050 commit 6441d82

File tree

6 files changed

+219
-15
lines changed

6 files changed

+219
-15
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Requirements
1010

1111
The role requires to be run as root on the target host.
1212

13+
The system requires to be rebooted to apply the kernel change.
14+
1315
The specified Kernel version must be supported by OS repositories (This include "Vault" repositories for Red hat based distributions).
1416

1517
Role Variables
@@ -28,6 +30,16 @@ Example Playbook
2830
- role: accelize.linux_kernel
2931
vars:
3032
kernel_version: 3.10.0-693
33+
34+
tasks:
35+
# Reboot to apply the kernel change
36+
- name: Ensure system is rebooted
37+
reboot:
38+
# If kernel version is required in a following step, update facts to get
39+
# the new kernel version
40+
- name: Ensure Ansible facts are up to date
41+
setup:
42+
3143
```
3244

3345
Dependencies

filter_plugins/main.py

Lines changed: 134 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""Extra Ansible filters"""
22

33

4-
def _rhel_kernel_info(packages, kernel_version, *_, **__):
4+
def _rhel_kernel_info(packages, kernel_version):
55
"""
6-
Return kernel and associated repository.
6+
Return kernel to install with associated repository.
77
88
Args:
99
packages (dict): DNF/YUM list output.
@@ -17,8 +17,8 @@ def _rhel_kernel_info(packages, kernel_version, *_, **__):
1717
# List all available kernel version and associated repository
1818
for line in packages['stdout'].splitlines():
1919
if line.startswith('kernel.') and not line.startswith('kernel.src'):
20-
yum_package = line.strip().split()
21-
kernels.append(dict(version=yum_package[1], repo=yum_package[2]))
20+
package = line.strip().split()
21+
kernels.append(dict(version=package[1], repo=package[2]))
2222

2323
# Return more recent kernel version that match version requirement
2424
for kernel in reversed(kernels):
@@ -31,9 +31,9 @@ def _rhel_kernel_info(packages, kernel_version, *_, **__):
3131
', '.join(kernel['version'] for kernel in kernels)))
3232

3333

34-
def rhel_kernel(packages, kernel_version, *_, **__):
34+
def rhel_kernel(packages, kernel_version):
3535
"""
36-
Return matching kernel version.
36+
Return matching kernel version to install.
3737
3838
Args:
3939
packages (dict): DNF/YUM list output.
@@ -45,7 +45,7 @@ def rhel_kernel(packages, kernel_version, *_, **__):
4545
return _rhel_kernel_info(packages, kernel_version)['version']
4646

4747

48-
def rhel_repo(packages, kernel_version, *_, **__):
48+
def rhel_repo(packages, kernel_version):
4949
"""
5050
Return repository where found specified kernel version.
5151
@@ -59,10 +59,136 @@ def rhel_repo(packages, kernel_version, *_, **__):
5959
return _rhel_kernel_info(packages, kernel_version)['repo']
6060

6161

62+
def _deb_kernel_info(packages, kernel_version):
63+
"""
64+
Return best matching kernel version.
65+
66+
Args:
67+
packages (dict): apt-cache showpkg output.
68+
kernel_version (str): Kernel version to install.
69+
70+
Returns:
71+
str: kernel version.
72+
"""
73+
kernels = set()
74+
75+
# List all available kernel version and associated repository
76+
for line in packages['stdout'].splitlines():
77+
line = line.strip()
78+
if line.startswith('Package: ') and (
79+
line.endswith('-common') or # Debian
80+
line.endswith('-generic')): # Ubuntu
81+
kernel = line.split()[1]
82+
83+
for string in ('linux-headers-', 'common', 'generic'):
84+
kernel = kernel.replace(string, '')
85+
kernel = kernel.strip('-')
86+
87+
if kernel:
88+
kernels.add(kernel)
89+
90+
# Sort Kernel versions
91+
versions = {}
92+
for kernel in kernels:
93+
try:
94+
version, build = kernel.split('-', 1)
95+
except ValueError:
96+
version = kernel
97+
build = ''
98+
versions[kernel] = list(
99+
int(ver) for ver in version.split('.')) + [build]
100+
kernels = sorted(versions.keys(), key=versions.get, reverse=True)
101+
102+
# Return more recent kernel package that match version requirement
103+
for kernel in kernels:
104+
if kernel.startswith(kernel_version):
105+
return kernel
106+
107+
raise RuntimeError(
108+
'No kernel matching to "%s". Available kernel versions: %s' % (
109+
kernel_version, ', '.join(reversed(kernels))))
110+
111+
112+
def _deb_kernel_package(kernel, dist, arch, name):
113+
"""
114+
Return kernel package name.
115+
116+
Args:
117+
kernel (str): Kernel version.
118+
dist (str): Distribution.
119+
arch (str): Architecture.
120+
name (str): Package name.
121+
122+
Returns:
123+
str: kernel package.
124+
"""
125+
# Define package suffix
126+
if dist == 'Ubuntu':
127+
suffix = 'generic'
128+
elif name == 'linux-image':
129+
suffix = arch.replace('x86_64', 'amd64')
130+
else:
131+
suffix = 'common'
132+
133+
return '-'.join((name, kernel, suffix))
134+
135+
136+
def deb_kernel(packages, kernel_version, dist, arch, name):
137+
"""
138+
Return kernel package to install.
139+
140+
Args:
141+
packages (dict): apt-cache showpkg output.
142+
kernel_version (str): Kernel version to install.
143+
dist (str): Distribution.
144+
arch (str): Architecture.
145+
name (str): Package name.
146+
147+
Returns:
148+
str: kernel package to install.
149+
"""
150+
return _deb_kernel_package(
151+
_deb_kernel_info(packages, kernel_version), dist, arch, name)
152+
153+
154+
def deb_installed_kernel(installed, packages, kernel_version):
155+
"""
156+
Return old kernel packages to remove.
157+
158+
Args:
159+
installed (dict): dpkg -l output.
160+
packages (dict): apt-cache showpkg output.
161+
kernel_version (str): Kernel version to install.
162+
163+
Returns:
164+
list of str: Kernel packages to remove.
165+
"""
166+
# Filter installed package to keep
167+
to_keep = _deb_kernel_info(packages, kernel_version)
168+
169+
# Return installed package to remove
170+
to_remove = []
171+
for line in installed['stdout'].splitlines():
172+
if ' linux-' not in line:
173+
continue
174+
175+
package = line.split()[1]
176+
if ((package.startswith('linux-image-') or
177+
package.startswith('linux-headers-')) and not (
178+
package.startswith('linux-image-' + to_keep) or
179+
package.startswith('linux-headers-' + to_keep))):
180+
to_remove.append(package)
181+
182+
return to_remove
183+
184+
62185
class FilterModule(object):
63186
"""Return filter plugin"""
64187

65188
@staticmethod
66189
def filters():
67190
"""Return filter"""
68-
return {'rhel_kernel': rhel_kernel, 'rhel_repo': rhel_repo}
191+
return {'rhel_kernel': rhel_kernel,
192+
'rhel_repo': rhel_repo,
193+
'deb_kernel': deb_kernel,
194+
'deb_installed_kernel': deb_installed_kernel}

meta/main.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ galaxy_info:
1515
versions:
1616
- 29
1717
- 30
18+
- name: Ubuntu
19+
versions:
20+
- xenial
21+
- bionic
22+
- name: Debian
23+
versions:
24+
- stretch
25+
- buster
1826
galaxy_tags:
1927
- linux
2028
- kernel

molecule/default/molecule.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ platforms:
1111
image: centos:7
1212
- name: fedora_30
1313
image: fedora:30
14+
- name: debian_buster
15+
image: debian:buster
16+
- name: ubuntu_bionic
17+
image: ubuntu:bionic
1418
provisioner:
1519
name: ansible
1620
lint:
@@ -19,6 +23,8 @@ provisioner:
1923
host_vars:
2024
centos_7:
2125
kernel_version: 3.10.0-693
26+
ubuntu_bionic:
27+
kernel_version: 4.15.0
2228
verifier:
2329
name: testinfra
2430
lint:

molecule/default/tests/test_default.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22

3+
from pytest import skip
34
import testinfra.utils.ansible_runner
45

56
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
@@ -12,13 +13,18 @@ def test_packages_installed(host):
1213
"""
1314
installed = False
1415
for name in ("kernel", "kernel-common",
15-
"kernel-devel", "kernel-headers", "linux-headers"):
16+
"kernel-devel", "kernel-headers",
17+
"linux-headers", "linux-image"):
1618
package = host.package(name)
1719
if not package.is_installed:
1820
continue
19-
assert f'{package.version}-{package.release}'.startswith(
21+
22+
version = '-'.join(ver for ver in (
23+
package.version, package.release) if ver)
24+
assert version.startswith(
2025
host.ansible.get_variables().get('kernel_version', ''))
2126
installed = True
2227

2328
if not installed:
24-
raise RuntimeError('No kernel package found')
29+
# Packages names does not match for Debian/Ubuntu packages
30+
skip('No kernel package found')

tasks/main.yml

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
---
22

3-
- name: Get available kernel versions
3+
- name: Get available kernel versions with YUM
44
command: yum list --enablerepo=C7.* --showduplicates kernel
55
changed_when: false
6+
args:
7+
warn: false
68
when:
79
- ansible_os_family == 'RedHat'
810
- ansible_distribution_major_version == "7"
911
register: yum_kernel_list
1012

11-
- name: Install kernel
13+
- name: Install kernel with YUM
1214
yum:
1315
name: "{{ item.name }}-{{ yum_kernel_list | rhel_kernel(kernel_version) }}"
1416
enablerepo: "{{ yum_kernel_list | rhel_repo(kernel_version) }}"
@@ -25,15 +27,17 @@
2527
- name: kernel-headers
2628
when: install_kernel_headers | bool
2729

28-
- name: Get available kernel versions
30+
- name: Get available kernel versions with DNF
2931
command: dnf list --enablerepo=* --showduplicates kernel
3032
changed_when: false
33+
args:
34+
warn: false
3135
when:
3236
- ansible_os_family == 'RedHat'
3337
- ansible_distribution_major_version != "7"
3438
register: dnf_kernel_list
3539

36-
- name: Install kernel
40+
- name: Install kernel with DNF
3741
dnf:
3842
name: "{{ item.name }}-{{ dnf_kernel_list | rhel_kernel(kernel_version) }}"
3943
enablerepo: "{{ dnf_kernel_list | rhel_repo(kernel_version) }}"
@@ -49,3 +53,45 @@
4953
when: install_kernel_headers | bool
5054
- name: kernel-headers
5155
when: install_kernel_headers | bool
56+
57+
- name: Ensure APT cache is up to date
58+
apt:
59+
update_cache: true
60+
changed_when: false
61+
when: ansible_os_family == 'Debian'
62+
63+
- name: Get available kernel versions with APT
64+
command: apt-cache showpkg linux-headers-*
65+
changed_when: false
66+
when:
67+
- ansible_os_family == 'Debian'
68+
register: apt_kernel_list
69+
70+
- name: Get installed packages with APT
71+
command: dpkg -l
72+
changed_when: false
73+
when:
74+
- ansible_os_family == 'Debian'
75+
register: apt_packages_list
76+
77+
- name: Install kernel with APT
78+
apt:
79+
name: "{{ apt_kernel_list | deb_kernel(
80+
kernel_version, ansible_distribution, ansible_architecture,
81+
item.name) }}"
82+
when:
83+
- ansible_os_family == 'Debian'
84+
- item.when
85+
with_items:
86+
- name: linux-image
87+
when: true
88+
- name: linux-headers
89+
when: install_kernel_headers | bool
90+
91+
- name: Remove previous kernels with APT
92+
apt:
93+
name: "{{ apt_packages_list | deb_installed_kernel(
94+
apt_kernel_list, kernel_version) }}"
95+
state: absent
96+
purge: true
97+
when: ansible_os_family == 'Debian'

0 commit comments

Comments
 (0)