diff --git a/.gitignore b/.gitignore index 45113a669..f51213a59 100644 --- a/.gitignore +++ b/.gitignore @@ -86,6 +86,8 @@ playbooks/roles/linux-mirror/linux-mirror-systemd/mirrors.yaml # yet. workflows/selftests/results/ +workflows/linux/artifacts/ + workflows/linux/refs/default/Kconfig.linus workflows/linux/refs/default/Kconfig.next workflows/linux/refs/default/Kconfig.stable diff --git a/playbooks/build_linux.yml b/playbooks/build_linux.yml new file mode 100644 index 000000000..094441d1b --- /dev/null +++ b/playbooks/build_linux.yml @@ -0,0 +1,4 @@ +--- +- hosts: all + roles: + - role: build_linux diff --git a/playbooks/install_linux.yml b/playbooks/install_linux.yml new file mode 100644 index 000000000..273ef4512 --- /dev/null +++ b/playbooks/install_linux.yml @@ -0,0 +1,4 @@ +--- +- hosts: all + roles: + - role: install_linux diff --git a/playbooks/roles/build_linux/README.md b/playbooks/roles/build_linux/README.md new file mode 100644 index 000000000..cbf9755ce --- /dev/null +++ b/playbooks/roles/build_linux/README.md @@ -0,0 +1,74 @@ +build_linux +=========== + +The build_linux role downloads and builds the Linux kernel. It also +lets you apply custom patches, remove kernels, etc.; anything you +have to do with regards to generic kernel development. + +By default, it tracks one of the latest stable kernels that are +still supported using the linux stable git tree. + +Requirements +------------ + +A separate block device is required on which to create the file +system where the test kernel is built. + +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 + +Dependencies +------------ + +None. + +Example Playbook +---------------- + +Below is an example playbook, say a build_linux.yml file: + +``` +--- +- hosts: all + roles: + - role: build_linux +``` + +License +------- + +copyleft-next-0.3.1 diff --git a/playbooks/roles/build_linux/defaults/main.yml b/playbooks/roles/build_linux/defaults/main.yml new file mode 100644 index 000000000..5ff5ece28 --- /dev/null +++ b/playbooks/roles/build_linux/defaults/main.yml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier copyleft-next-0.3.1 +--- +kdevops_bootlinux: false +infer_uid_and_group: false + +data_path: "/data" +data_user: "kdevops" +data_group: "kdevops" +data_device: "/dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_kdevops0" +data_fstype: "xfs" +data_label: "data" +data_fs_opts: "-L {{ disk_setup_label }}" + +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" +target_linux_make_cmd: "{{ make }} -j{{ ansible_processor_nproc }}" +target_linux_make_install_cmd: "{{ target_linux_make_cmd }} modules_install install" + +build_artifacts_dir: "{{ topdir_path }}/workflows/linux/artifacts/" + +uninstall_kernel_enable: false + +bootlinux_b4_am_this_host: false + +kdevops_workflow_enable_cxl: false +bootlinux_cxl_test: false + +bootlinux_tree_set_by_cli: false diff --git a/playbooks/roles/build_linux/tasks/install-deps/debian/main.yml b/playbooks/roles/build_linux/tasks/install-deps/debian/main.yml new file mode 100644 index 000000000..ef57dca75 --- /dev/null +++ b/playbooks/roles/build_linux/tasks/install-deps/debian/main.yml @@ -0,0 +1,46 @@ +--- +# Install dependencies for building linux on Debian + +- name: Update apt cache + become: true + become_method: ansible.builtin.sudo + ansible.builtin.apt: + update_cache: true + tags: + - linux + +# apt-get build-dep does not capture all requirements +- name: Install Linux kernel build dependencies + become: true + become_method: ansible.builtin.sudo + ansible.builtin.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/build_linux/tasks/install-deps/redhat/main.yml b/playbooks/roles/build_linux/tasks/install-deps/redhat/main.yml new file mode 100644 index 000000000..371e7f7f1 --- /dev/null +++ b/playbooks/roles/build_linux/tasks/install-deps/redhat/main.yml @@ -0,0 +1,102 @@ +--- +- name: Enable installation of packages from EPEL + ansible.builtin.include_role: + name: epel-release + when: + - ansible_distribution != "Fedora" + +- name: Install packages for building the Linux kernel + become: true + become_method: ansible.builtin.sudo + ansible.builtin.dnf: + name: "{{ packages }}" + state: present + update_cache: true + 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: + name: + - btrfs-progs + state: present + update_cache: true + retries: 3 + delay: 5 + register: btrfs_result + until: btrfs_result is succeeded + when: + - ansible_distribution == "Fedora" + +- name: Install rpmbuild + become: true + become_method: ansible.builtin.sudo + ansible.builtin.dnf: + name: + - rpmbuild + state: present + update_cache: true + retries: 3 + delay: 5 + register: rpmbuild_result + until: rpmbuild_result is succeeded + when: + - ansible_distribution != "Fedora" + +- name: Install rpmbuild + become: true + become_method: ansible.builtin.sudo + ansible.builtin.dnf: + name: + - perl-core + - rpm-build + - rsync + state: present + update_cache: true + retries: 3 + delay: 5 + register: rpmbuild_result + until: rpmbuild_result is succeeded + when: + - ansible_distribution == "Fedora" diff --git a/playbooks/roles/build_linux/tasks/install-deps/suse/main.yml b/playbooks/roles/build_linux/tasks/install-deps/suse/main.yml new file mode 100644 index 000000000..0260da5a9 --- /dev/null +++ b/playbooks/roles/build_linux/tasks/install-deps/suse/main.yml @@ -0,0 +1,31 @@ +--- +- name: Install Linux kernel build dependencies for SUSE + become: true + become_method: ansible.builtin.sudo + community.general.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: false diff --git a/playbooks/roles/build_linux/tasks/main.yml b/playbooks/roles/build_linux/tasks/main.yml new file mode 100644 index 000000000..a95b5ee98 --- /dev/null +++ b/playbooks/roles/build_linux/tasks/main.yml @@ -0,0 +1,295 @@ +--- +- 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 + +- name: Debian-specific set up + ansible.builtin.import_tasks: install-deps/debian/main.yml + when: + - ansible_os_family == "Debian" + +- name: Red Hat-specific set up + ansible.builtin.import_tasks: install-deps/redhat/main.yml + when: + - ansible_os_family == "RedHat" + +- name: Suse-specific set up + ansible.builtin.import_tasks: install-deps/suse/main.yml + when: + - ansible_os_family == "Suse" + +- name: Install b4 + become: true + become_method: ansible.builtin.sudo + ansible.builtin.pip: + name: + - b4 + when: + - target_linux_install_b4 is defined + - target_linux_install_b4 + - ansible_os_family == "Debian" + +- name: Create the /data partition + ansible.builtin.include_role: + name: create_data_partition + +- name: Wipe the build directory + ansible.builtin.file: + path: "{{ target_linux_dir_path }}" + state: absent + +- name: Clone {{ target_linux_tree }} + ansible.builtin.git: + repo: "{{ target_linux_git }}" + dest: "{{ target_linux_dir_path }}" + update: true + depth: "{{ target_linux_shallow_depth }}" + version: "{{ target_linux_ref }}" + retries: 3 + delay: 5 + register: git_result + until: not git_result.failed + +- name: Copy the kernel delta to the builder + ansible.builtin.template: + src: "{{ target_linux_extra_patch }}" + dest: "{{ target_linux_dir_path }}/{{ target_linux_extra_patch }}" + owner: "{{ data_user }}" + group: "{{ data_group }}" + mode: "u=rw,g=r,o=r" + when: + - target_linux_extra_patch is defined + +- name: Apply the kernel delta on the builder + ansible.builtin.command: + cmd: "git am {{ target_linux_extra_patch }}" # noqa: command-instead-of-module + chdir: "{{ target_linux_dir_path }}" + register: git_am + changed_when: not git_am.failed + when: + - target_linux_extra_patch is defined + +- name: Set git user name and email + ansible.builtin.shell: | + if ! $(git config --get user.email) ; then + git config --global user.email user@example.com + fi + if ! $(git config --get user.name) ; then + git config --global user.name user + fi + register: git_config + changed_when: not git_config.failed + when: + - target_linux_apply_patch_message_id is defined + - target_linux_apply_patch_message_id | length > 0 + - bootlinux_b4_am_this_host|bool + +- name: Apply a message patch set + ansible.builtin.shell: + cmd: | + set -o pipefail + b4 am -o - {{ target_linux_apply_patch_message_id }} | git am + chdir: "{{ target_linux_dir_path }}" + register: b4_am + changed_when: not b4_am.failed + when: + - target_linux_apply_patch_message_id is defined + - target_linux_apply_patch_message_id | length > 0 + - bootlinux_b4_am_this_host|bool + +- name: Set the pathname of the .config templates directory + ansible.builtin.set_fact: + template_path: "{{ topdir_path }}/playbooks/roles/bootlinux/templates" + +- name: Check whether config-kdevops exists + delegate_to: localhost + ansible.builtin.stat: + path: "{{ template_path }}/config-kdevops" + register: config_kdevops + +- name: Found config-kdevops, using it for template + ansible.builtin.set_fact: + linux_config: "config-kdevops" + when: config_kdevops.stat.exists + +- name: No config-kdevops, looking for {{ target_linux_config }} + ansible.builtin.set_fact: + linux_config: "{{ target_linux_config }}" + when: not config_kdevops.stat.exists + +- name: Check whether specific kernel config exists for {{ target_linux_ref }} + delegate_to: localhost + ansible.builtin.stat: + path: "{{ template_path }}/{{ target_linux_config }}" + register: kernel_config + +- name: Find all linux-next configs + delegate_to: localhost + ansible.builtin.find: + paths: "{{ template_path }}" + patterns: "config-next*" + file_type: file + recurse: false + register: found_configs + when: + - not config_kdevops.stat.exists + - not kernel_config.stat.exists + +- name: Extract the date from the filenames + ansible.builtin.set_fact: + configs_with_dates: "{{ configs_with_dates | default([]) + [{'file': item.path, 'date': (item.path | regex_search('config-next-(\\d{8})')).split('-')[-1]}] }}" + loop: "{{ found_configs.files }}" + no_log: true + when: + - not config_kdevops.stat.exists + - not kernel_config.stat.exists + - item.path is search('config-next-(\\d{8})') + +- name: Sort configs based on date extracted from filename + ansible.builtin.set_fact: + sorted_configs: "{{ configs_with_dates | selectattr('date', 'defined') | sort(attribute='date', reverse=True) | map(attribute='file') | list }}" + when: + - not config_kdevops.stat.exists + - not kernel_config.stat.exists + - configs_with_dates | length > 0 + +- name: Set latest linux-next config + ansible.builtin.set_fact: + latest_linux_next_config: "{{ sorted_configs[0] }}" + when: + - not config_kdevops.stat.exists and not kernel_config.stat.exists + - sorted_configs | length > 0 + +- name: Use the specific kernel config or fallback to the latest linux-next + ansible.builtin.set_fact: + linux_config: "{{ target_linux_config | default('') if kernel_config.stat.exists else (latest_linux_next_config | default('') | basename) }}" + when: + - not config_kdevops.stat.exists + - not kernel_config.stat.exists + - latest_linux_next_config is defined + +- name: Verify that the Linux configuration file exists + delegate_to: localhost + ansible.builtin.stat: + path: "{{ template_path }}/{{ linux_config }}" + register: config_stat + when: linux_config is defined + +- name: Fail if the configuration file does not exist + ansible.builtin.fail: + msg: "The configuration file {{ template_path }}/{{ linux_config }} does not exist." + when: not config_stat.stat.exists + +- name: Copy configuration for Linux {{ target_linux_tree }} + ansible.builtin.template: + src: "{{ template_path }}/{{ linux_config }}" + dest: "{{ target_linux_dir_path }}/.config" + owner: "{{ data_user }}" + group: "{{ data_group }}" + mode: "u=rw,g=r,o=r" + +- name: Set the kernel localversion + ansible.builtin.lineinfile: + path: "{{ target_linux_dir_path }}/localversion" + line: "{{ target_linux_localversion }}" + mode: "u=rw,g=r,o=r" + create: true + when: + - target_linux_localversion is defined and target_linux_localversion != "" + +- name: Configure Linux {{ target_linux_tree }} + community.general.make: + chdir: "{{ target_linux_dir_path }}" + target: "olddefconfig" + +- name: Build {{ target_linux_tree }} + community.general.make: + chdir: "{{ target_linux_dir_path }}" + target: "all" + jobs: "{{ ansible_processor_nproc }}" + +- name: Remove the artifacts directory + delegate_to: localhost + ansible.builtin.file: + path: "{{ build_artifacts_dir }}" + state: absent + +- name: Create an empty artifacts directory + delegate_to: localhost + ansible.builtin.file: + path: "{{ build_artifacts_dir }}" + state: directory + mode: "u=rwx,g=rx,o=rx" + +- name: Build kernel .deb packages + when: + - ansible_os_family == "Debian" + block: + - name: Make the bindeb-pkg target + community.general.make: + chdir: "{{ target_linux_dir_path }}" + target: "bindeb-pkg" + + - name: Find the build artifacts + ansible.builtin.find: + paths: "{{ target_linux_dir_path }}" + patterns: "*.deb" + file_type: file + recurse: true + register: found_debs + + - name: Fetch the build artifacts to the control host + ansible.builtin.fetch: + src: "{{ item.path }}" + dest: "{{ build_artifacts_dir }}" + flat: true + loop: "{{ found_debs.files }}" + loop_control: + label: "Fetching {{ item.path }}" + +- name: Build kernel .rpm packages + when: + - ansible_os_family == "RedHat" + block: + - name: Make the binrpm-pkg target + community.general.make: + chdir: "{{ target_linux_dir_path }}" + target: "binrpm-pkg" + + - name: Find the build artifacts + ansible.builtin.find: + paths: "{{ target_linux_dir_path }}/rpmbuild/RPMS" + patterns: "*.rpm" + file_type: file + recurse: true + register: found_rpms + + - name: Fetch the build artifacts to the control host + ansible.builtin.fetch: + src: "{{ item.path }}" + dest: "{{ build_artifacts_dir }}" + flat: true + loop: "{{ found_rpms.files }}" + loop_control: + label: "Fetching {{ item.path }}" + +- name: Extract the release information of the built kernel + community.general.make: + chdir: "{{ target_linux_dir_path }}" + target: "kernelrelease" + register: kernelrelease + +- name: Store the kernel release information with the build artifacts + delegate_to: localhost + ansible.builtin.lineinfile: + create: true + line: "{{ kernelrelease.stdout }}" + mode: "u=rw,g=r,o=r" + path: "{{ build_artifacts_dir }}/kernel.release" diff --git a/playbooks/roles/gen_hosts/defaults/main.yml b/playbooks/roles/gen_hosts/defaults/main.yml index f6ab9bcce..85afb3504 100644 --- a/playbooks/roles/gen_hosts/defaults/main.yml +++ b/playbooks/roles/gen_hosts/defaults/main.yml @@ -29,6 +29,8 @@ kdevops_workflow_enable_ltp: False kdevops_workflow_enable_nfstest: false kdevops_workflow_enable_sysbench: false +bootlinux_builder: false + is_fstests: False fstests_fstyp: "bogus" fs_config_role_path: "/dev/null" diff --git a/playbooks/roles/gen_hosts/tasks/main.yml b/playbooks/roles/gen_hosts/tasks/main.yml index a50355f72..9182ac46f 100644 --- a/playbooks/roles/gen_hosts/tasks/main.yml +++ b/playbooks/roles/gen_hosts/tasks/main.yml @@ -56,6 +56,18 @@ when: - is_fstests +- name: Generate the Ansible hosts file for a Linux kernel build + tags: [ 'hosts' ] + template: + src: "{{ kdevops_hosts_template }}" + dest: "{{ topdir_path }}/{{ kdevops_hosts }}" + force: yes + trim_blocks: True + lstrip_blocks: True + when: + - bootlinux_builder + - ansible_hosts_template.stat.exists + - name: Generate the Ansible hosts file tags: [ 'hosts' ] template: diff --git a/playbooks/roles/gen_hosts/templates/builder.j2 b/playbooks/roles/gen_hosts/templates/builder.j2 new file mode 100644 index 000000000..0c9ba1e8e --- /dev/null +++ b/playbooks/roles/gen_hosts/templates/builder.j2 @@ -0,0 +1,13 @@ +[all] +{{ kdevops_hosts_prefix }}-builder +[all:vars] +ansible_python_interpreter = "{{ kdevops_python_interpreter }}" + +[baseline] +{{ kdevops_hosts_prefix }}-builder +[baseline:vars] +ansible_python_interpreter = "{{ kdevops_python_interpreter }}" + +[dev] +[dev:vars] +ansible_python_interpreter = "{{ kdevops_python_interpreter }}" diff --git a/playbooks/roles/gen_nodes/defaults/main.yml b/playbooks/roles/gen_nodes/defaults/main.yml index 8ff9b8799..d5fa444c9 100644 --- a/playbooks/roles/gen_nodes/defaults/main.yml +++ b/playbooks/roles/gen_nodes/defaults/main.yml @@ -93,6 +93,8 @@ fstests_fstyp: "bogus" fs_config_role_path: "/dev/null" fs_config_data: "[section_1]" +bootlinux_builder: false +builder_nodes: [] bootlinux_9p: False bootlinux_9p_host_path: "/dev/null" bootlinux_9p_msize: 0 diff --git a/playbooks/roles/gen_nodes/tasks/main.yml b/playbooks/roles/gen_nodes/tasks/main.yml index d541dcbf1..e3d0127d1 100644 --- a/playbooks/roles/gen_nodes/tasks/main.yml +++ b/playbooks/roles/gen_nodes/tasks/main.yml @@ -43,6 +43,14 @@ when: - kdevops_baseline_and_dev +- name: Set builder nodes array + tags: vars + set_fact: + builder_nodes: + - "{{ kdevops_host_prefix + '-builder' }}" + when: + - bootlinux_builder + - name: Set iscsi_nodes list ansible.builtin.set_fact: iscsi_nodes: "{{ [kdevops_host_prefix + '-iscsi'] }}" @@ -138,6 +146,20 @@ - not kdevops_workflows_dedicated_workflow - ansible_nodes_template.stat.exists +- name: Generate the builder kdevops nodes file using {{ kdevops_nodes_template }} as jinja2 source template + tags: [ 'nodes' ] + vars: + node_template: "{{ kdevops_nodes_template | basename }}" + all_generic_nodes: "{{ builder_nodes }}" + nodes: "{{ all_generic_nodes }}" + template: + src: "{{ node_template }}" + dest: "{{ topdir_path }}/{{ kdevops_nodes }}" + force: yes + when: + - bootlinux_builder + - ansible_nodes_template.stat.exists + - name: Generate the pynfs kdevops nodes file using {{ kdevops_nodes_template }} as jinja2 source template tags: [ 'nodes' ] vars: diff --git a/playbooks/roles/install_linux/README.md b/playbooks/roles/install_linux/README.md new file mode 100644 index 000000000..0b440d213 --- /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 000000000..43edb3caf --- /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 000000000..51b216e47 --- /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 000000000..57a340979 --- /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 000000000..204a181b8 --- /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 000000000..a0da4c110 --- /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 000000000..3c7deea21 --- /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 000000000..17966af58 --- /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 000000000..a565e0ac2 --- /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 000000000..11a92f34b --- /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 000000000..1cb1fdc55 --- /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/Kconfig b/workflows/linux/Kconfig index 797469e60..8a26eb2e2 100644 --- a/workflows/linux/Kconfig +++ b/workflows/linux/Kconfig @@ -36,6 +36,16 @@ config BOOTLINUX_PURE_IOMAP endif # HAVE_SUPPORTS_PURE_IOMAP +config BOOTLINUX_BUILDER + bool "Build once, test many" + output yaml + default n + help + Enabling this option creates a separate guest/instance + where the Linux kernel is built. kdevops passes the + artifacts of this build to the test runner nodes to be + installed before each workflow runs. + config BOOTLINUX_9P bool "Use 9p to build Linux" depends on LIBVIRT && !GUESTFS_LACKS_9P diff --git a/workflows/linux/Makefile b/workflows/linux/Makefile index ecce273a4..06722d590 100644 --- a/workflows/linux/Makefile +++ b/workflows/linux/Makefile @@ -13,6 +13,10 @@ ifeq (y,$(CONFIG_BOOTLINUX_PURE_IOMAP)) TREE_CONFIG:=config-$(TREE_REF)-pure-iomap endif +ifeq (y,$(CONFIG_BOOTLINUX_BUILDER)) +KDEVOPS_HOSTS_TEMPLATE=builder.j2 +endif + # Describes the Linux clone BOOTLINUX_ARGS += target_linux_git=$(TREE_URL) # ifeq (y,$(CONFIG_BOOTLINUX_TREE_CUSTOM_NAME)) @@ -80,6 +84,8 @@ linux-help-menu: @echo "linux-clone - Only clones Linux" @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 @@ -155,6 +161,19 @@ linux-reboot: $(KDEVOPS_HOSTFILE) $(KDEVOPS_PLAYBOOKS_DIR)/bootlinux.yml \ --extra-vars="$(BOOTLINUX_ARGS)" $(LIMIT_HOSTS) --tags vars,reboot +PHONY += linux-packages +linux-packages: + $(Q)ansible-playbook $(ANSIBLE_VERBOSE) -i $(KDEVOPS_HOSTFILE) \ + $(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 \