Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pacman: support yay as root #6713

Merged
merged 11 commits into from
Jul 8, 2023
2 changes: 2 additions & 0 deletions changelogs/fragments/6713-yay-become.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- pacman - module recognizes the output of ``yay`` running as ``root`` (https://github.com/ansible-collections/community.general/pull/6713).
36 changes: 24 additions & 12 deletions plugins/modules/pacman.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@
it is much more efficient to pass the list directly to the O(name) option.
- To use an AUR helper (O(executable) option), a few extra setup steps might be required beforehand.
For example, a dedicated build user with permissions to install packages could be necessary.
- >
In the tests, while using C(yay) as the O(executable) option, the module failed to install AUR packages
with the error: C(error: target not found: <pkg>).
"""

RETURN = """
Expand Down Expand Up @@ -263,6 +266,7 @@
reason_for: all
"""

import re
import shlex
from ansible.module_utils.basic import AnsibleModule
from collections import defaultdict, namedtuple
Expand Down Expand Up @@ -418,7 +422,7 @@ def _build_install_diff(pacman_verb, pkglist):
for p in name_ver:
# With Pacman v6.0.1 - libalpm v13.0.1, --upgrade outputs "loading packages..." on stdout. strip that.
# When installing from URLs, pacman can also output a 'nothing to do' message. strip that too.
if "loading packages" in p or "there is nothing to do" in p:
if "loading packages" in p or "there is nothing to do" in p or 'Avoid running' in p:
continue
name, version = p.split()
if name in self.inventory["installed_pkgs"]:
Expand Down Expand Up @@ -706,11 +710,12 @@ def _build_inventory(self):
installed_pkgs = {}
dummy, stdout, dummy = self.m.run_command([self.pacman_path, "--query"], check_rc=True)
# Format of a line: "pacman 6.0.1-2"
query_re = re.compile(r'^\s*(?P<pkg>\S+)\s+(?P<ver>\S+)\s*$')
for l in stdout.splitlines():
l = l.strip()
if not l:
query_match = query_re.match(l)
if not query_match:
continue
pkg, ver = l.split()
pkg, ver = query_match.groups()
installed_pkgs[pkg] = ver

installed_groups = defaultdict(set)
Expand All @@ -721,11 +726,12 @@ def _build_inventory(self):
# base-devel file
# base-devel findutils
# ...
query_groups_re = re.compile(r'^\s*(?P<group>\S+)\s+(?P<pkg>\S+)\s*$')
for l in stdout.splitlines():
l = l.strip()
if not l:
query_groups_match = query_groups_re.match(l)
if not query_groups_match:
continue
group, pkgname = l.split()
group, pkgname = query_groups_match.groups()
installed_groups[group].add(pkgname)

available_pkgs = {}
Expand All @@ -747,21 +753,27 @@ def _build_inventory(self):
# vim-plugins vim-airline-themes
# vim-plugins vim-ale
# ...
sync_groups_re = re.compile(r'^\s*(?P<group>\S+)\s+(?P<pkg>\S+)\s*$')
for l in stdout.splitlines():
l = l.strip()
if not l:
sync_groups_match = sync_groups_re.match(l)
if not sync_groups_match:
continue
group, pkg = l.split()
group, pkg = sync_groups_match.groups()
available_groups[group].add(pkg)

upgradable_pkgs = {}
rc, stdout, stderr = self.m.run_command(
[self.pacman_path, "--query", "--upgrades"], check_rc=False
)

stdout = stdout.splitlines()
if stdout and "Avoid running" in stdout[0]:
stdout = stdout[1:]
stdout = "\n".join(stdout)

# non-zero exit with nothing in stdout -> nothing to upgrade, all good
# stderr can have warnings, so not checked here
if rc == 1 and stdout == "":
if rc == 1 and not stdout:
pass # nothing to upgrade
elif rc == 0:
# Format of lines:
Expand All @@ -771,7 +783,7 @@ def _build_inventory(self):
l = l.strip()
if not l:
continue
if "[ignored]" in l:
if "[ignored]" in l or "Avoid running" in l:
continue
s = l.split()
if len(s) != 4:
Expand Down
23 changes: 23 additions & 0 deletions tests/integration/targets/pacman/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

- name: Remove user yaybuilder
ansible.builtin.user:
name: yaybuilder
state: absent

- name: Remove yay
ansible.builtin.package:
name: yay
state: absent

- name: Remove packages for yay-become
ansible.builtin.package:
name:
- base-devel
- yay
- git
- nmap
state: absent
1 change: 1 addition & 0 deletions tests/integration/targets/pacman/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
- include_tasks: 'update_cache.yml'
- include_tasks: 'locally_installed_package.yml'
- include_tasks: 'reason.yml'
- include_tasks: 'yay-become.yml'
66 changes: 66 additions & 0 deletions tests/integration/targets/pacman/tasks/yay-become.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

# This is more convoluted that one might expect, because:
# - yay is not available or installation in ArchLinux (as it is in Manjaro - issue 6184 reports using it)
# - to install yay in ArchLinux requires building the package
# - makepkg cannot be run as root, but the user running it must have sudo to install the resulting package

- name: create user
ansible.builtin.user:
name: yaybuilder
state: present
notify: Remove user yaybuilder

- name: grant sudo powers to builder
community.general.sudoers:
name: yaybuilder
user: yaybuilder
commands: ALL
nopassword: true

- name: Install base packages
ansible.builtin.package:
name:
- base-devel
- git
- go
state: present
notify: Remove packages for yay-become

- name: Hack permssions for the remote_tmp_dir
ansible.builtin.file:
path: "{{ remote_tmp_dir }}"
mode: '0777'

- name: Create temp directory for builder
ansible.builtin.file:
path: "{{ remote_tmp_dir }}/builder"
owner: yaybuilder
state: directory
mode: '0755'

- name: clone yay git repo
become: true
become_user: yaybuilder
ansible.builtin.git:
repo: https://aur.archlinux.org/yay.git
dest: "{{ remote_tmp_dir }}/builder/yay"
depth: 1

- name: make package
become: true
become_user: yaybuilder
ansible.builtin.command:
chdir: "{{ remote_tmp_dir }}/builder/yay"
cmd: makepkg -si --noconfirm
notify: Remove yay

- name: Install nmap
community.general.pacman:
name: nmap
state: present
executable: yay
extra_args: --builddir /var/cache/yay