As the title says, I’m wondering if anyone has experience managing AUR packages with Ansible. I’m personally interested in nginx-passenger, but the question could really apply to any AUR package. Unlike official packages, AUR packages have to be built by the user, which introduces a slew of problems:
- knowing when to build the package. I’d say it’s pretty much a given that the package has to be built on the target system. However, I’m provisioning ARM single-board computers with Ansible, and compiling nginx on a system with a 1GHz processor and 1GB of memory is a painful experience. I don’t want to do it any more often than necessary.
- knowing whether or not the package is installed, and whether or not the installed version is up to date. The existing pacman module in Ansible (thumbs up for actually having a module, by the way. as an Arch user I was glad to see it) can query if a package is installed via state=present, but if the package isn’t installed then it will obviously try to install it. That will fail because AUR packages aren’t hosted on official repositories.
Any thoughts or suggestions? One thing I just thought of, while writing this, was to set up yaourt on the target system, since it would seamlessly integrate AUR installation, but I have literally zero experience with yaourt. Plus this kind of introduces a chicken-and-egg problem - to install one AUR package, I first have to install another AUR package, which goes right back to the original issue.
I do speak a little python, so I’m not averse to submitting a PR for this issue, if someone has a good idea for how to implement it. I’m at a loss for now.
For your first bullet point, consider running a command to see if “whatever” is installed/ready, using facts, or shell+register.
Then use “group_by” to select the machines that don’t have that criteria set that one way.
You can then skip configuration on those systems where things are already done.
Thanks for the suggestions, Michael. I’ve been thinking about the problem some more, and I think the most sound solution to bring all the logic together is to write an Ansible module and throw it in with any roles that require AUR package installation. I’m going to have a closer look at Ansible’s pacman module to get an idea of where to start, but in case anyone else is thinking about this problem, I’ll share my thoughts so far. Feel free to point out any holes or logical inconsistencies in my plan.
- tell the module where the PKGBUILD is on the target system. Presumably it would be placed there by the unarchive or copy modules.
- parse PKGBUILD for crucial variables (package name, epoch, rel, version). Luckily a PKGBUILD is a bash script, and whitespace is forbidden in those variables, so simple grep/regex is sufficient
- pacman -Q packagename to determine if the package is already installed and, if so, what version it is. If it’s not installed then we already know it has to be installed, otherwise we compare versions between the PKGBUILD and the installed version to see which one is newer. (pacman versions are epoch:version-rel syntax, similar to rpm and compared the same way) Technically it makes more sense to build the package and then use a standard arch linux script to query the tarball’s version, but we’re trying to avoid building the package until it’s clearly necessary. If the installed version is up to date then we can stop here.
- assuming the package has to be installed (either it’s not installed on the target, or our PKGBUILD is newer), we have to get a pkg.tar.xz for it. We can assemble the name of the package’s tarball from the PKGBUILD variables (I think it’s packagename-epoch:ver-rel-architecture.pkg.tar.xz but I can’t remember for sure) and check if that file already exists. If it does then we’ll assume it’s the package tarball. Skip to step 5. (More on this later)
- no tarball found? Guess we have to build it. makepkg -cs --asroot --noconfirm in the PKGBUILD directory. -c to clean sources and -s to install makedeps before building (I think we need to supply --noconfirm with -s but can’t remember). This is the most time consuming step so obviously we’re hoping we don’t have to do this, but one way or another this will put the tarball on our system.
- pacman -U --noconfirm on the tarball to install it. If we can’t find the tarball at this point then we assume it was a build failure. If the installation fails then the tarball must have been broken for some reason, install failure. If everything connects then the package has been successfully installed. Work complete!
Pros of this approach:
-
Don’t have to build the package on the target. We can build it somewhere else and then copy the tarball onto the target, and it’ll just use it as is. Huge savings for low-RAM ARM systems (build yourself with distcc cross compilation and then just drop the tarball on the Ansible slave).
-
Don’t have to leave the PKGBUILD on the system in a special directory. One of my earlier ideas was to copy your PKGBUILD to the same directory every time you run the playbook. If the copy action is skipped, you know that the PKGBUILD is unchanged, so no rebuild is required. But that requires a particular directory to store the PKGBUILD and other build artifacts, which is not needed for this system. (Bonus: you can still implement that behavior with the method I’ve described. Use unarchive or copy to move the PKGBUILD to the target, and if the action was skipped, then skip the AUR module as well.)
-
No rebuild for packages that are already up to date! This was the #1 requirement of my plan.
Anyway I will see what I can do to implement this behavior in the near future. Long term goal would be to get this merged into the pacman module, but let’s start small.
Hey there, any news on this? I’m looking into aura right now. It would be good if an Ansible module was created (In the meantime, I will try command: aura…)
I’m not doing much with Ansible right now, but when I was, I found that the pacman module could install local packages (ie the -U) flag, which greatly reduced the need for a custom AUR module. You can add a few commands to build the package if it doesn’t exist and then use that module instead of rolling your own, which is what I did.