public inbox for kdevops@lists.linux.dev
 help / color / mirror / Atom feed
From: cel@kernel.org
To: Luis Chamberlain <mcgrof@kernel.org>,
	Daniel Gomez <da.gomez@kernel.org>,
	Scott Mayhew <smayhew@redhat.com>
Cc: <kdevops@lists.linux.dev>, Chuck Lever <chuck.lever@oracle.com>
Subject: [RFC PATCH 3/3] Experimental: Add a separate install_linux role
Date: Tue, 22 Apr 2025 11:49:06 -0400	[thread overview]
Message-ID: <20250422154906.526319-4-cel@kernel.org> (raw)
In-Reply-To: <20250422154906.526319-1-cel@kernel.org>

From: Chuck Lever <chuck.lever@oracle.com>

Add a role that can grab the artifacts in workflows/linux/artifacts
and install them on all guests/instances.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 playbooks/install_linux.yml                   |   4 +
 playbooks/roles/install_linux/README.md       | 136 ++++++++++++
 .../roles/install_linux/defaults/main.yml     |  43 ++++
 .../tasks/install-deps/debian/main.yml        |  44 ++++
 .../tasks/install-deps/redhat/main.yml        |  76 +++++++
 .../tasks/install-deps/suse/main.yml          |  31 +++
 playbooks/roles/install_linux/tasks/main.yml  | 142 +++++++++++++
 .../tasks/update-grub/debian.yml              |   8 +
 .../tasks/update-grub/install.yml             | 196 ++++++++++++++++++
 .../install_linux/tasks/update-grub/main.yml  |  15 ++
 .../tasks/update-grub/redhat.yml              |  36 ++++
 .../install_linux/tasks/update-grub/suse.yml  |  11 +
 workflows/linux/Makefile                      |   8 +
 13 files changed, 750 insertions(+)
 create mode 100644 playbooks/install_linux.yml
 create mode 100644 playbooks/roles/install_linux/README.md
 create mode 100644 playbooks/roles/install_linux/defaults/main.yml
 create mode 100644 playbooks/roles/install_linux/tasks/install-deps/debian/main.yml
 create mode 100644 playbooks/roles/install_linux/tasks/install-deps/redhat/main.yml
 create mode 100644 playbooks/roles/install_linux/tasks/install-deps/suse/main.yml
 create mode 100644 playbooks/roles/install_linux/tasks/main.yml
 create mode 100644 playbooks/roles/install_linux/tasks/update-grub/debian.yml
 create mode 100644 playbooks/roles/install_linux/tasks/update-grub/install.yml
 create mode 100644 playbooks/roles/install_linux/tasks/update-grub/main.yml
 create mode 100644 playbooks/roles/install_linux/tasks/update-grub/redhat.yml
 create mode 100644 playbooks/roles/install_linux/tasks/update-grub/suse.yml

diff --git a/playbooks/install_linux.yml b/playbooks/install_linux.yml
new file mode 100644
index 000000000000..273ef4512f81
--- /dev/null
+++ b/playbooks/install_linux.yml
@@ -0,0 +1,4 @@
+---
+- hosts: all
+  roles:
+    - role: install_linux
diff --git a/playbooks/roles/install_linux/README.md b/playbooks/roles/install_linux/README.md
new file mode 100644
index 000000000000..0b440d2130b0
--- /dev/null
+++ b/playbooks/roles/install_linux/README.md
@@ -0,0 +1,136 @@
+bootlinux
+=========
+
+The ansible bootlinux lets you get, build and install Linux.  It also lets you
+apply custom patches, remove kernels, etc. Anything you have to do with regards
+to generic kernel development. The defaults it will track one of the latest
+stable kernels that are still supported, using the linux stable git tree.
+
+Requirements
+------------
+
+You are expected to have an extra partition
+
+Role Variables
+--------------
+
+  * infer_uid_and_group: defaults to False, if set to True, then we will ignore
+    the passed on data_user and data_group and instead try to infer this by
+    inspecting the `whoami` and getent on the logged in target system we are
+    provisioning. So if user sam is running able on a host, targetting a system
+    called foofighter and logging into that system using username pincho,
+    then the data_user will be set overwritten and set to pincho. We will then
+    also lookup for pincho's default group id and use that for data_group.
+    This is useful if you are targetting a slew of systems and don't really
+    want to deal with the complexities of the username and group, and the
+    default target username you use to ssh into a system suffices to use as
+    a base. This is set to False to remain compatible with old users of
+    this role.
+  * data_path: where to place the git trees we clone under
+  * data_user: the user to assign permissions to
+  * data_group: the group to assign permissions to
+
+  * data_device: the target device to use for the data partition
+  * data_fstype: the filesystem to store the data parition under
+  * data_label: the label to use
+  * data_fs_opts: the filesystem options to use, you want to ensure to add the
+    label
+
+  * target_linux_admin_name: your developer name
+  * target_linux_admin_email: your email
+  * target_linux_git: the git tree to clone, by default this is the linux-stable
+    tree
+  * target_linux_tree: the name of the tree
+  * target_linux_dir_path: where to place the tree on the target system
+
+  * target_linux_ref : the actual tag as used on linux, so v4.19.62
+  * target_linux_extra_patch: if defined an extra patch to apply with git
+     am prior to compilation
+  * target_linux_config: the configuration file to use
+  * make: the make command to use
+  * target_linux_make_cmd: the actual full make command and its arguments
+  * target_linux_make_install_cmd: the install command
+
+Dependencies
+------------
+
+None.
+
+Example Playbook
+----------------
+
+Below is an example playbook, say a bootlinux.yml file:
+
+```
+---
+- hosts: all
+  roles:
+    - role: bootlinux
+```
+
+Custom runs
+===========
+
+Say you want to boot compile a vanilla kernel and you have created a new
+section under the hosts file called [dev], with a subset of the [all] section.
+You can compile say a vanilla kernel v4.19.58 with an extra set of patches we'd
+`git am` for you on top by using the following:
+
+```
+cd ansible
+ansible-playbook -i hosts -l dev --extra-vars "target_linux_extra_patch=pend-v4.19.58-fixes-20190716-v2.patch" bootlinux.yml
+```
+
+You'd place the `pend-v4.19.58-fixes-20190716-v2.patch` file on the directory
+`ansible/roles/bootlinux/templates/`.
+
+Now say you wantd to be explicit about a tag of Linux you'd want to use:
+
+```
+ansible-playbook -i hosts -l dev --extra-vars "target_linux_ref=v4.19.21 "target_linux_extra_patch=try-v4.19.20-fixes-20190716-v1.patch" bootlinux.yml
+```
+
+To uninstall a kernel:
+
+```
+ansible-playbook -i hosts -l dev --tags uninstall-linux --extra-vars "uninstall_kernel_ver=4.19.58+" bootlinux.yml
+```
+
+To ensure you can get the grub prompt:
+
+```bash
+ansible-playbook -i hosts --tags console,vars,manual-update-grub playbooks/bootlinux.yml
+```
+
+The ansible bootlinux role relies on the create_partition role to create a data
+partition where we can stuff code, and compile it. To test that aspect of
+the bootlinux role you can run:
+
+```
+ansible-playbook -i hosts -l baseline --tags data_partition,partition bootlinux.yml
+```
+
+To reboot all hosts:
+
+```bash
+ansible-playbook -i hosts bootlinux.yml --tags reboot
+```
+
+For further examples refer to one of this role's users, the
+[https://github.com/mcgrof/kdevops](kdevops) project or the
+[https://github.com/mcgrof/oscheck](oscheck) project from where
+this code originally came from.
+
+# TODO
+
+## Avoiding carrying linux-next configs
+
+It seems a waste of space to be adding configurations for linux-next for all
+tags. It seems easier to just look for the latest linux-next and try that.
+We just symlink linux-next files when we really need to, and when something
+really needs a new config, we then just add a new file.
+
+License
+-------
+
+copyleft-next-0.3.1
diff --git a/playbooks/roles/install_linux/defaults/main.yml b/playbooks/roles/install_linux/defaults/main.yml
new file mode 100644
index 000000000000..43edb3cafd79
--- /dev/null
+++ b/playbooks/roles/install_linux/defaults/main.yml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier copyleft-next-0.3.1
+---
+kdevops_bootlinux: False
+infer_uid_and_group: False
+
+data_path: "/data"
+data_user: "vagrant"
+data_group: "vagrant"
+
+data_device: "/dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_kdevops0"
+data_fstype: "xfs"
+data_label: "data"
+data_fs_opts: "-L {{ disk_setup_label }}"
+
+# Linux target defaults
+target_linux_admin_name: "Hacker Amanda"
+target_linux_admin_email: "devnull@kernel.org"
+target_linux_git: "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"
+target_linux_shallow_depth: 0
+target_linux_tree: "linux-stable"
+target_linux_dir_path: "{{ data_path }}/{{ target_linux_tree }}"
+kdevops_baseline_and_dev: False
+
+target_linux_ref: "v4.19.133"
+target_linux_delta_file:
+target_linux_config: "config-{{ target_linux_ref }}"
+make: "make"
+# Once ansible v2.10 becomes available we can move on to using
+# ansible_processor_nproc but that was merged in 2020:
+# The commit is 34db57a47f875d11c4068567b9ec7ace174ec4cf
+# introduce fact "ansible_processor_nproc": number of usable vcpus #66569
+# https://github.com/ansible/ansible/pull/66569
+target_linux_make_cmd: "{{ make }} -j{{ ansible_processor_vcpus }}"
+target_linux_make_install_cmd: "{{ target_linux_make_cmd }} modules_install install"
+
+uninstall_kernel_enable: False
+
+build_artifacts_dir: "{{ topdir_path }}/workflows/linux/artifacts/"
+
+kdevops_workflow_enable_cxl: False
+
+bootlinux_cxl_test: False
+bootlinux_tree_set_by_cli: False
diff --git a/playbooks/roles/install_linux/tasks/install-deps/debian/main.yml b/playbooks/roles/install_linux/tasks/install-deps/debian/main.yml
new file mode 100644
index 000000000000..51b216e47b06
--- /dev/null
+++ b/playbooks/roles/install_linux/tasks/install-deps/debian/main.yml
@@ -0,0 +1,44 @@
+---
+# Install dependencies for building linux on Debian
+
+- name: Update apt cache
+  become: yes
+  become_method: sudo
+  apt:
+    update_cache: yes
+  tags: linux
+
+# apt-get build-dep does not capture all requirements
+- name: Install Linux kernel build dependencies
+  become: yes
+  become_method: sudo
+  apt:
+    name:
+      - bison
+      - flex
+      - git
+      - gcc
+      - make
+      - gawk
+      - bc
+      - dump
+      - indent
+      - sed
+      - libssl-dev
+      - libelf-dev
+      - liburcu-dev
+      - xfsprogs
+      - e2fsprogs
+      - btrfs-progs
+      - ntfs-3g
+      - mdadm
+      - rpcbind
+      - portmap
+      - hwinfo
+      - open-iscsi
+      - python3-pip
+      - zstd
+      - libncurses-dev
+      - b4
+    state: present
+  tags: linux
diff --git a/playbooks/roles/install_linux/tasks/install-deps/redhat/main.yml b/playbooks/roles/install_linux/tasks/install-deps/redhat/main.yml
new file mode 100644
index 000000000000..57a340979fcd
--- /dev/null
+++ b/playbooks/roles/install_linux/tasks/install-deps/redhat/main.yml
@@ -0,0 +1,76 @@
+---
+- name: Enable installation of packages from EPEL
+  ansible.builtin.include_role:
+    name: epel-release
+  when:
+    - ansible_distribution != "Fedora"
+
+- name: Install packages we care about
+  become: true
+  become_method: ansible.builtin.sudo
+  ansible.builtin.dnf:
+    update_cache: true
+    name: "{{ packages }}"
+  retries: 3
+  delay: 5
+  register: result
+  until: result is succeeded
+  vars:
+    packages:
+      - bison
+      - flex
+      - git-core
+      - e2fsprogs
+      - xfsprogs
+      - xfsdump
+      - lvm2
+      - gcc
+      - make
+      - gawk
+      - bc
+      - dump
+      - libtool
+      - psmisc
+      - sed
+      - vim
+      - fio
+      - libaio-devel
+      - diffutils
+      - net-tools
+      - ncurses-devel
+      - xfsprogs
+      - e2fsprogs
+      - elfutils-libelf-devel
+      - ntfs-3g
+      - mdadm
+      - rpcbind
+      - portmap
+      - hwinfo
+      - iscsi-initiator-utils
+      - openssl
+      - openssl-devel
+      - dwarves
+      - userspace-rcu
+      - zstd
+
+- name: Install btrfs-progs
+  become: true
+  become_method: ansible.builtin.sudo
+  ansible.builtin.dnf:
+    update_cache: true
+    name: "{{ packages }}"
+  retries: 3
+  delay: 5
+  register: result
+  until: result is succeeded
+  vars:
+    packages:
+      - btrfs-progs
+  when: ansible_distribution == 'Fedora'
+
+- name: Remove packages that mess with initramfs
+  become: true
+  become_method: ansible.builtin.sudo
+  ansible.builtin.dnf:
+    state: absent
+    name: dracut-config-generic
diff --git a/playbooks/roles/install_linux/tasks/install-deps/suse/main.yml b/playbooks/roles/install_linux/tasks/install-deps/suse/main.yml
new file mode 100644
index 000000000000..204a181b8237
--- /dev/null
+++ b/playbooks/roles/install_linux/tasks/install-deps/suse/main.yml
@@ -0,0 +1,31 @@
+---
+- name: Install Linux kernel build dependencies for SUSE sources
+  become: yes
+  become_method: sudo
+  zypper:
+    name:
+      - bison
+      - flex
+      - git-core
+      - gcc
+      - make
+      - gawk
+      - bc
+      - dump
+      - sed
+      - libopenssl-devel
+      - libelf-devel
+      - liburcu8
+      - diffutils
+      - net-tools
+      - ncurses-devel
+      - xfsprogs
+      - e2fsprogs
+      - btrfsprogs
+      - ntfs-3g
+      - mdadm
+      - rpcbind
+      - portmap
+      - hwinfo
+      - open-iscsi
+    disable_recommends: no
diff --git a/playbooks/roles/install_linux/tasks/main.yml b/playbooks/roles/install_linux/tasks/main.yml
new file mode 100644
index 000000000000..a0da4c110f6e
--- /dev/null
+++ b/playbooks/roles/install_linux/tasks/main.yml
@@ -0,0 +1,142 @@
+---
+- name: Include optional extra_vars
+  ansible.builtin.include_vars:
+    file: "{{ item }}"
+  with_first_found:
+    - files:
+        - "../extra_vars.yml"
+        - "../extra_vars.yaml"
+        - "../extra_vars.json"
+      skip: true
+  failed_when: false
+  tags: vars
+
+- name: Debian-specific set up
+  ansible.builtin.import_tasks: install-deps/debian/main.yml
+  when:
+    - ansible_os_family == "Debian"
+
+- name: Suse-specific set up
+  ansible.builtin.import_tasks: install-deps/suse/main.yml
+  when:
+    - ansible_os_family == "Suse"
+
+- name: Red Hat-specific set up
+  ansible.builtin.import_tasks: install-deps/redhat/main.yml
+  when:
+    - ansible_os_family == "RedHat"
+
+# We use "console serial" so to enable real consoles to be
+# preferred first, and fallback to the serial as secondary
+# option. This let's us work with hardware serial consoles
+# say on IPMIs and virtual guests ('virsh console').
+- name: Ensure we can get the GRUB prompt on reboot
+  become: true
+  become_flags: 'su - -c'
+  become_method: ansible.builtin.sudo
+  ansible.builtin.lineinfile:
+    path: /etc/default/grub
+    regexp: '^GRUB_TERMINAL='
+    line: GRUB_TERMINAL="console serial"
+  tags:
+    - linux
+    - git
+    - config
+    - console
+
+- name: Update the boot GRUB file
+  ansible.builtin.import_tasks: update-grub/main.yml
+  tags:
+    - linux
+    - uninstall-linux
+    - manual-update-grub
+    - console
+
+- name: Ensure DEFAULTDEBUG is set
+  become: true
+  become_flags: 'su - -c'
+  become_method: ansible.builtin.sudo
+  register: grub_default_saved_cmd
+  ansible.builtin.lineinfile:
+    path: /etc/sysconfig/kernel
+    regexp: '^DEFAULTDEBUG='
+    line: DEFAULTDEBUG=yes
+  when:
+    - ansible_os_family == "RedHat"
+  tags:
+    - linux
+    - git
+    - config
+    - saved
+
+- name: Install the built kernel RPMs on the target nodes
+  when:
+    - ansible_os_family == "RedHat"
+  tags:
+    - linux
+    - install-linux
+  block:
+    - name: Find the kernel build artifacts on the control host
+      delegate_to: localhost
+      ansible.builtin.find:
+        paths: "{{ build_artifacts_dir }}"
+        patterns: "*.rpm"
+        file_type: file
+        recurse: true
+      register: found_rpms
+
+    - name: Upload the kernel build artifacts to the target nodes
+      ansible.builtin.copy:
+        src: "{{ item.path }}"
+        dest: "/tmp"
+        mode: "u=rw,g=r,o=r"
+      loop: "{{ found_rpms.files }}"
+      loop_control:
+        label: "Uploading {{ item.path }}"
+
+    - name: Initialize list of packages to install
+      ansible.builtin.set_fact:
+        packages: []
+
+    - name: Build a list of packages to install
+      ansible.builtin.set_fact:
+        packages: "{{ packages + ['/tmp/' + item.path | basename ] }}"
+      loop: "{{ found_rpms.files }}"
+      loop_control:
+        label: "Adding {{ item.path }}"
+
+    - name: Install the kernel build artifacts on the target nodes
+      become: true
+      become_method: ansible.builtin.sudo
+      ansible.builtin.dnf:
+        name: "{{ packages }}"
+        state: present
+        disable_gpg_check: true
+
+- name: Set the default kernel on the target nodes
+  ansible.builtin.import_tasks: update-grub/install.yml
+  tags:
+    - linux
+    - git
+    - config
+    - saved
+
+- name: Reboot the target nodes into Linux {{ target_linux_tree }}
+  become: true
+  become_method: ansible.builtin.sudo
+  ansible.builtin.reboot:
+  tags:
+    - linux
+    - reboot
+
+- name: Refresh facts
+  ansible.builtin.gather_facts:
+
+- name: Check the uname on the target nodes
+  ansible.builtin.debug:
+    msg: "Target kernel {{ target_linux_ref }}; Running kernel {{ ansible_kernel }}"
+  tags:
+    - linux
+    - git
+    - config
+    - uname
diff --git a/playbooks/roles/install_linux/tasks/update-grub/debian.yml b/playbooks/roles/install_linux/tasks/update-grub/debian.yml
new file mode 100644
index 000000000000..3c7deea2161a
--- /dev/null
+++ b/playbooks/roles/install_linux/tasks/update-grub/debian.yml
@@ -0,0 +1,8 @@
+- name: Run update-grub
+  become: yes
+  become_flags: 'su - -c'
+  become_method: sudo
+  command: "update-grub"
+  register: grub_update
+  changed_when: "grub_update.rc == 0"
+  tags: [ 'linux', 'manual-update-grub', 'console' ]
diff --git a/playbooks/roles/install_linux/tasks/update-grub/install.yml b/playbooks/roles/install_linux/tasks/update-grub/install.yml
new file mode 100644
index 000000000000..17966af58210
--- /dev/null
+++ b/playbooks/roles/install_linux/tasks/update-grub/install.yml
@@ -0,0 +1,196 @@
+# There is slightly confusing user-experience and not complete documentation
+# about the requirements for using grub-set-default in light of the fact that
+# most Linux distributions use sub-menus. You need to use GRUB_DEFAULT=saved
+# there is a few caveats with its use which are not well documented anywhere
+# and I'm pretty sure tons of people are running into these issues.
+#
+# I'll document them here for posterity and so to justify the approach used
+# in kdevops to ensure we do boot the correct kernel.
+#
+# Some users erroneously claim that you also need GRUB_SAVEDEFAULT=true when
+# using GRUB_DEFAULT=saved but this is not true. The issue with using
+# GRUB_DEFAULT=saved which causes confusion is that most distributions
+# today use submenus folks do not take these into account when using
+# grub-set-default and the documentation about grub-set-default is not
+# clear about this requirement.
+#
+# Sadly, if you use a bogus kernel grub-set-default will not complain. For
+# example since most distributions use submenus, if you install a new kernel you
+# may end up in a situation as follows:
+#
+# menuentry 'Debian GNU/Linux' ... {
+#   ...
+# }
+# submenu 'Advanced options for Debian GNU/Linux' ... {
+#   menuentry 'Debian GNU/Linux, with Linux 5.16.0-4-amd64' ... {
+#     ...
+#   }
+#   menuentry 'Debian GNU/Linux, with Linux 5.16.0-4-amd64 (recovery mode)' ... {
+#     ...
+#   }
+#   menuentry 'Debian GNU/Linux, with Linux 5.10.105' ... {
+#     ...
+#   }
+#   ... etc ...
+# }
+#
+# So under this scheme the 5.10.105 kernel is actually "1>2" and so if
+# you used:
+#
+#   grub-set-default 3
+#
+# This would not return an error and you would expect it to work. This
+# is a bug in grub-set-default, it should return an error. The correct
+# way to set this with submenus would be:
+#
+#   grub-set-default "1>2"
+#
+# However doing the reverse mapping is something which can get complicated
+# and there is no upstream GRUB2 support to do this for you. We can simplify
+# this problem instead by disabling the submenus, with GRUB_DISABLE_SUBMENU=y,
+# making the menu flat and then just querying for the linear mapping using
+# ansible using awk | grep and tail.
+#
+# So for instance, using GRUB_DISABLE_SUBMENU=y results in the following
+# options:
+#
+# vagrant@kdevops-xfs-nocrc ~ $ awk -F\' '/menuentry / {print $2}' /boot/grub/grub.cfg |  awk '{print NR-1" ... "$0}'
+# 0 ... Debian GNU/Linux, with Linux 5.16.0-4-amd64
+# 1 ... Debian GNU/Linux, with Linux 5.16.0-4-amd64 (recovery mode)
+# 2 ... Debian GNU/Linux, with Linux 5.10.105
+# 3 ... Debian GNU/Linux, with Linux 5.10.105 (recovery mode)
+# 4 ... Debian GNU/Linux, with Linux 5.10.0-5-amd64
+# 5 ... Debian GNU/Linux, with Linux 5.10.0-5-amd64 (recovery mode)
+#
+# We have a higher degree of confidence with this structure when looking
+# for "5.10.105" that its respective boot entry 2 is the correct one. So we'd
+# now just use:
+#
+#   grub-set-default 2
+- name: Ensure we have GRUB_DEFAULT=saved
+  become: true
+  become_flags: 'su - -c'
+  become_method: ansible.builtin.sudo
+  ansible.builtin.lineinfile:
+    path: /etc/default/grub
+    regexp: '^GRUB_DEFAULT='
+    line: GRUB_DEFAULT=saved
+  register: grub_default_saved_cmd
+  tags:
+    - linux
+    - git
+    - config
+    - saved
+
+- name: Use GRUB_DISABLE_SUBMENU=y to enable grub-set-default use with one digit
+  become: true
+  become_flags: 'su - -c'
+  become_method: ansible.builtin.sudo
+  register: grub_disable_submenu_cmd
+  ansible.builtin.lineinfile:
+    path: /etc/default/grub
+    regexp: '^GRUB_DISABLE_SUBMENU='
+    line: GRUB_DISABLE_SUBMENU=y
+  tags:
+    - linux
+    - git
+    - config
+    - saved
+
+- name: Update your boot GRUB file if necessary to ensure GRUB flat earth
+  ansible.builtin.import_tasks: update-grub/main.yml
+  tags:
+    - linux
+    - uninstall-linux
+    - manual-update-grub
+    - console
+
+- name: Read the artifacts release file
+  delegate_to: localhost
+  vars:
+    release_file: "{{ topdir_path }}/workflows/linux/artifacts/kernel.release"
+  ansible.builtin.set_fact:
+    kernelrelease: "{{ lookup('file', release_file) }}"
+
+- name: Show kernel release information
+  ansible.builtin.debug:
+    var: kernelrelease
+
+- name: Construct command line to determine default kernel ID
+  ansible.builtin.set_fact:
+    determine_default_kernel_id: >-
+      awk -F\' '/menuentry / {print $2}'
+      /boot/grub/grub.cfg | awk '{print NR-1" ... "$0}' |
+      grep {{ kernelrelease }} | head -1 | awk '{print $1}'
+  when:
+    - ansible_os_family != 'RedHat' or ansible_distribution_major_version | int < 8
+
+- name: Construct command line to determine default kernel ID for RHEL >= 8
+  ansible.builtin.set_fact:
+    determine_default_kernel_id: >-
+      for f in $(ls -1 /boot/loader/entries/*.conf); do
+      cat $f;
+      done | grep title | awk '{ gsub("title ", "", $0); print }' | grep '{{ kernelrelease }}';
+  when:
+    - ansible_os_family == "RedHat" and ansible_distribution_major_version | int >= 8
+
+# If this fails then grub-set-default won't be run, and the assumption here
+# is either you do the work to enhance the heuristic or live happy with the
+# assumption that grub2's default of picking the latest kernel is the best
+# option.
+- name: Try to find your target kernel's GRUB boot entry number now that the menu is flattened for {{ target_linux_ref }} using inferred KERNELRELEASE {{ kernelrelease}}
+  become: true
+  become_flags: 'su - -c'
+  become_method: ansible.builtin.sudo
+  vars:
+    target_kernel: "{{ target_linux_ref | replace('v', '') }}"
+  ansible.builtin.shell: " {{ determine_default_kernel_id }} "
+  register: grub_boot_number_cmd
+  tags:
+    - linux
+    - git
+    - config
+    - saved
+
+- name: Obtain command to set default kernel to boot
+  ansible.builtin.set_fact:
+    grub_set_default_boot_kernel: grub-set-default
+  when:
+    - ansible_os_family != "RedHat" or ansible_distribution_major_version | int < 8
+
+- name: Obtain command to set default kernel to boot for RHEL >= 8
+  ansible.builtin.set_fact:
+    grub_set_default_boot_kernel: grub2-set-default
+  when:
+    - ansible_os_family == "RedHat" and ansible_distribution_major_version | int >= 8
+
+- name: Set the target kernel to be booted by default
+  become: true
+  become_flags: 'su - -c'
+  become_method: ansible.builtin.sudo
+  vars:
+    target_boot_entry: "{{ grub_boot_number_cmd.stdout_lines.0 }}"
+  ansible.builtin.command: "{{ grub_set_default_boot_kernel }} \"{{ target_boot_entry }}\""
+  when:
+    - grub_boot_number_cmd.rc == 0
+    - grub_boot_number_cmd.stdout != ""
+  tags:
+    - linux
+    - git
+    - config
+    - saved
+
+- name: Itemize kernel and GRUB entry we just selected
+  vars:
+    target_kernel: "{{ target_linux_ref | replace('v', '') }}"
+    target_boot_entry: "{{ grub_boot_number_cmd.stdout_lines.0 }}"
+  ansible.builtin.debug:
+    msg: "{{ target_kernel }} determined to be {{ target_boot_entry }} on the GRUB2 flat menu. Ran: grub-set-default {{ target_boot_entry }}"
+  when:
+    - grub_boot_number_cmd.rc == 0
+    - grub_boot_number_cmd.stdout != ""
+  tags:
+    - linux
+    - git
+    - config
+    - saved
diff --git a/playbooks/roles/install_linux/tasks/update-grub/main.yml b/playbooks/roles/install_linux/tasks/update-grub/main.yml
new file mode 100644
index 000000000000..a565e0ac26ac
--- /dev/null
+++ b/playbooks/roles/install_linux/tasks/update-grub/main.yml
@@ -0,0 +1,15 @@
+---
+- name: Debian-specific grub update
+  ansible.builtin.import_tasks: debian.yml
+  when:
+    - ansible_os_family == "Debian"
+
+- name: Red Hat-specific grub update
+  ansible.builtin.import_tasks: redhat.yml
+  when:
+    - ansible_os_family == "RedHat"
+
+- name: Suse-specific grub update
+  ansible.builtin.import_tasks: suse.yml
+  when:
+    - ansible_os_family == "Suse"
diff --git a/playbooks/roles/install_linux/tasks/update-grub/redhat.yml b/playbooks/roles/install_linux/tasks/update-grub/redhat.yml
new file mode 100644
index 000000000000..11a92f34bab6
--- /dev/null
+++ b/playbooks/roles/install_linux/tasks/update-grub/redhat.yml
@@ -0,0 +1,36 @@
+- name: Disable Grub menu auto-hide
+  become: true
+  become_flags: 'su - -c'
+  become_method: ansible.builtin.sudo
+  ansible.builtin.command: "grub2-editenv - unset menu_auto_hide"
+  register: grub_edit
+  changed_when: "grub_edit.rc == 0"
+
+- name: Determine if system was booted using UEFI
+  ansible.builtin.stat:
+    path: "/sys/firmware/efi/efivars"
+  register: efi_boot
+
+- name: Use /etc/grub2.cfg as the grub configuration file
+  ansible.builtin.set_fact:
+    grub_config_file: "/etc/grub2.cfg"
+  when:
+    - not efi_boot.stat.exists
+
+- name: Use /etc/grub2-efi.cfg as the configuration file
+  ansible.builtin.set_fact:
+    grub_config_file: "/etc/grub2-efi.cfg"
+  when:
+    - efi_boot.stat.exists
+
+- name: Run update-grub
+  become: true
+  become_flags: 'su - -c'
+  become_method: ansible.builtin.sudo
+  ansible.builtin.command: "grub2-mkconfig -o {{ grub_config_file }}"
+  register: grub_update
+  changed_when: "grub_update.rc == 0"
+  tags:
+    - linux
+    - manual-update-grub
+    - console
diff --git a/playbooks/roles/install_linux/tasks/update-grub/suse.yml b/playbooks/roles/install_linux/tasks/update-grub/suse.yml
new file mode 100644
index 000000000000..1cb1fdc55f58
--- /dev/null
+++ b/playbooks/roles/install_linux/tasks/update-grub/suse.yml
@@ -0,0 +1,11 @@
+- name: Run update-grub
+  become: true
+  become_flags: 'su - -c'
+  become_method: ansible.builtin.sudo
+  ansible.builtin.command: "update-bootloader --refresh"
+  register: grub_update
+  changed_when: "grub_update.rc == 0"
+  tags:
+    - linux
+    - manual-update-grub
+    - console
diff --git a/workflows/linux/Makefile b/workflows/linux/Makefile
index bb7441e71fda..06722d5903b3 100644
--- a/workflows/linux/Makefile
+++ b/workflows/linux/Makefile
@@ -85,6 +85,7 @@ linux-help-menu:
 	@echo "linux-grub-setup   - Ensures the appropriate target kernel is set to boot"
 	@echo "linux-reboot       - Reboot guests"
 	@echo "linux-packages     - Clones, builds, and packages a Linux kernel"
+	@echo "linux-artifacts    - Installs artifacts generated by 'linux-packages'"
 	@echo "uname              - Prints current running kernel"
 
 PHONY += linux-help-end
@@ -166,6 +167,13 @@ linux-packages:
 		$(KDEVOPS_PLAYBOOKS_DIR)/build_linux.yml \
 		--extra-vars="$(BOOTLINUX_ARGS)" $(LIMIT_HOSTS)
 
+PHONY += linux-artifacts
+linux-artifacts:
+	$(Q)ansible-playbook $(ANSIBLE_VERBOSE) \
+		-i $(KDEVOPS_HOSTFILE) \
+		$(KDEVOPS_PLAYBOOKS_DIR)/install_linux.yml \
+		--extra-vars="$(BOOTLINUX_ARGS)" $(LIMIT_HOSTS)
+
 PHONY += uname
 uname:
 	$(Q)ansible all -i hosts -b -m command -a "uname -r" -o \
-- 
2.49.0


  parent reply	other threads:[~2025-04-22 15:49 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-22 15:49 [RFC PATCH 0/3] Build once, test everywhere cel
2025-04-22 15:49 ` [RFC PATCH 1/3] Add a guest/instance for building the test kernel cel
2025-04-22 15:49 ` [RFC PATCH 2/3] playbooks: Add a build_linux role cel
2025-04-22 15:49 ` cel [this message]
2025-04-23  5:27 ` [RFC PATCH 0/3] Build once, test everywhere Luis Chamberlain
2025-04-23 12:34 ` Daniel Gomez
2025-04-23 13:36   ` Chuck Lever
2025-04-23 17:28     ` Daniel Gomez
2025-04-24 13:51       ` Chuck Lever

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250422154906.526319-4-cel@kernel.org \
    --to=cel@kernel.org \
    --cc=chuck.lever@oracle.com \
    --cc=da.gomez@kernel.org \
    --cc=kdevops@lists.linux.dev \
    --cc=mcgrof@kernel.org \
    --cc=smayhew@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox