Feeds
Evgeni Golov: Running Ansible Molecule tests in parallel
Or "How I've halved the execution time of our tests by removing ten lines". Catchy, huh? Also not exactly true, but quite close. Enjoy!
Molecule?!"Molecule project is designed to aid in the development and testing of Ansible roles."
No idea about the development part (I have vim and mkdir), but it's really good for integration testing. You can write different test scenarios where you define an environment (usually a container), a playbook for the execution and a playbook for verification. (And a lot more, but that's quite unimportant for now, so go read the docs if you want more details.)
If you ever used Beaker for Puppet integration testing, you'll feel right at home (once you've thrown away Ruby and DSLs and embraced YAML for everything).
I'd like to point out one thing, before we continue. Have another look at the quote above.
"Molecule project is designed to aid in the development and testing of Ansible roles."
That's right. The project was started in 2015 and was always about roles. There is nothing wrong about that, but given the Ansible world has moved on to collections (which can contain roles), you start facing challenges.
Challenges using Ansible Molecule in the Collections worldThe biggest challenge didn't change since the last time I looked at the topic in 2020: running tests for multiple roles in a single repository ("monorepo") is tedious.
Well, guess what a collection is? Yepp, a repository with multiple roles in it.
It did get a bit better though. There is pytest-ansible now, which has integration for Molecule. This allows the execution of Molecule and even provides reasonable logging with something as short as:
% pytest --molecule roles/That's much better than the shell script I used in 2020!
However, being able to execute tests is one thing. Being able to execute them fast is another one.
Given Molecule was initially designed with single roles in mind, it has switches to run all scenarios of a role (--all), but it has no way to run these in parallel. That's fine if you have one or two scenarios in your role repository. But what if you have 10 in your collection?
"No way?!" you say after quickly running molecule test --help, "But there is…"
% molecule test --help Usage: molecule test [OPTIONS] [ANSIBLE_ARGS]... … --parallel / --no-parallel Enable or disable parallel mode. Default is disabled. …Yeah, that switch exists, but it only tells Molecule to place things in separate folders, you still need to parallelize yourself with GNU parallel or pytest.
And here our actual journey starts!
Running Ansible Molecule tests in parallelTo run Molecule via pytest in parallel, we can use pytest-xdist, which allows pytest to run the tests in multiple processes.
With that, our pytest call becomes something like this:
% MOLECULE_OPTS="--parallel" pytest --numprocesses auto --molecule roles/What does that mean?
- MOLECULE_OPTS passes random options to the Molecule call pytest does, and we need to add --parallel there.
- --numprocesses auto tells pytest-xdist to create as many workers as you have CPUs and balance the work across those.
However, once we actually execute it, we see:
% MOLECULE_OPTS="--parallel" pytest --numprocesses auto --molecule roles/ … WARNING Driver podman does not provide a schema. INFO debian scenario test matrix: dependency, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy INFO Performing prerun with role_name_check=0... WARNING Retrying execution failure 250 of: ansible-galaxy collection install -vvv --force ../.. ERROR Command returned 250 code: … OSError: [Errno 39] Directory not empty: 'roles' … FileExistsError: [Errno 17] File exists: b'/home/user/namespace.collection/collections/ansible_collections/namespace/collection' … FileNotFoundError: [Errno 2] No such file or directory: b'/home/user/namespace.collection//collections/ansible_collections/namespace/collection/roles/my_role/molecule/debian/molecule.yml'You might see other errors, other paths, etc, but they all will have one in common: they indicate that either files or directories are present, while the tool expects them not to be, or vice versa.
Ah yes, that fine smell of race conditions.
I'll spare you the wild-goose chase I went on when trying to find out what the heck was calling ansible-galaxy collection install here. Instead, I'll just point at the following line:
INFO Performing prerun with role_name_check=0...What is this "prerun" you ask? Well… "To help Ansible find used modules and roles, molecule will perform a prerun set of actions. These involve installing dependencies from requirements.yml specified at the project level, installing a standalone role or a collection."
Turns out, this step is not --parallel-safe (yet?).
Luckily, it can easily be disabled, for all our roles in the collection:
% mkdir -p .config/molecule % echo 'prerun: false' >> .config/molecule/config.ymlThis works perfectly, as long as you don't have any dependencies.
And we don't have any, right? We didn't define any in a molecule/collections.yml, our collection has none.
So let's push a PR with that and see what our CI thinks.
OSError: [Errno 39] Directory not empty: 'tests'Huh?
FileExistsError: [Errno 17] File exists: b'remote.sh' -> b'/home/runner/work/namespace.collection/namespace.collection/collections/ansible_collections/ansible/posix/tests/utils/shippable/aix.sh'What?
ansible_compat.errors.InvalidPrerequisiteError: Found collection at '/home/runner/work/namespace.collection/namespace.collection/collections/ansible_collections/ansible/posix' but missing MANIFEST.json, cannot get info.Okay, okay, I get the idea… But why?
Well, our collection might not have any dependencies, BUT MOLECULE HAS! When using Docker containers, it uses community.docker, when using Podman containers.podman, etc…
So we have to install those before running Molecule, and everything should be fine. We even can use Molecule to do this!
$ molecule dependency --scenario <scenario>And with that knowledge, the patch to enable parallel Molecule execution on GitHub Actions using pytest-xdist becomes:
diff --git a/.config/molecule/config.yml b/.config/molecule/config.yml new file mode 100644 index 0000000..32ed66d --- /dev/null +++ b/.config/molecule/config.yml @@ -0,0 +1 @@ +prerun: false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0f9da0d..df55a15 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,9 +58,13 @@ jobs: - name: Install Ansible run: pip install --upgrade https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz - name: Install dependencies - run: pip install molecule molecule-plugins pytest pytest-ansible + run: pip install molecule molecule-plugins pytest pytest-ansible pytest-xdist + - name: Install collection dependencies + run: cd roles/repository && molecule dependency -s suse - name: Run tests - run: pytest -vv --molecule roles/ + run: pytest -vv --numprocesses auto --molecule roles/ + env: + MOLECULE_OPTS: --parallel ansible-lint: runs-on: ubuntu-latestBut you promised us to delete ten lines, that's just a +7-2 patch!
Oh yeah, sorry, the +10-20 (so a net -10) is the foreman-operations-collection version of the patch, that also migrates from an ugly bash script to pytest-ansible.
And yes, that cuts down the execution from ~26 minutes to ~13 minutes.
In the collection I originally tested this with, it's a more moderate "from 8-9 minutes to 5-6 minutes", which is still good though :)
Russell Coker: Galaxy Note 9 Droidian
Droidian only supported the version of this phone with the Exynos chipset. The GSM Arena specs page for the Note 9 shows that it’s the SM-N960F part number [1]. In Australia all Note 9 phones should have the Exynos but it doesn’t hurt to ask for the part number before buying.
The status of the Note9 in Droidian went from fully supported to totally unsupported in the time I was working on this blog post. Such a rapid change is disappointing, it would be good if they at least kept the old data online. It would also be good if they didn’t require a hash character in the URL for each phone which breaks the archive.org mirroring.
Installing DroidianFirstly Power+VolumeDown will reboot in some situations where Power button on it’s own won’t. The Note 9 hardware keys are:
- Power – Right side
- Volume up/down – long button top of the left side
- Bixby – key for Samsung assistant that’s below the volume on the left
The Droidian install document for the Galaxy Note 9 9 now deleted is a bit confusing and unclear. Here is the install process that worked for me.
- The doc says to start by installing “Android 10 (Q) stock firmware”, but apparently a version of Android 10 that’s already on the phone will do for that.
- Download the rescue.img file and the “Droidian’s image” files from the Droidian page and extract the “Droidian’s image” zip.
- Connect your phone to your workstation by USB, preferably USB 3 because it will take a few minutes to transfer the image at USB 2 speed. Install the Debian package adb on the workstation.
- To “Unlock the bootloader” you can apparently use a PC and the Samsung software but the unlock option in the Android settings gives the same result without proprietary software, here’s how to do it:
- Connect the phone to Wifi. Then in settings go to “Software update”, then click on “Download and install”. Refuse to install if it offers you a new version (the unlock menu item will never appear unless you do this, so you can’t unlock without Internet access).
- In settings go to “About phone”, then “Software information”, then tap on “Build number” repeatedly until “Developer mode” is enabled.
- In settings go to the new menu “Developer options” then turn on the “OEM unlocking” option, this does a factory reset of the phone.
- To flash the recovery.img you apparently use Odin on Windows. I used the heimdall-flash package on Debian. On your Linux workstation run the commands:
adb reboot download
heimdall flash --RECOVERY recovery.img
Then press VOLUME-UP+BIXBY+POWER as soon as it reboots to get into the recovery image. If you don’t do it soon enough it will do a default Android boot which will wipe the recovery.img you installed and also do a factory reset which will disable “Developer mode” and you will need to go back to step 4.
- If the above step works correctly you will have a RECOVERY menu where the main menu has options “Reboot system now”, “Apply update”, “Factory reset”, and “Advanced” in a large font. If you failed to install recovery.img then you would get a similar menu but with a tiny font which is the Samsung recovery image which won’t work so reboot and try again.
- When at the main recovery menu select “Advanced” and then “Enter fastboot”. Note that this doesn’t run a different program or do anything obviously different, just gives a menu – that’s OK we want it at this menu.
- Run “./flash_all.sh” on your workstation.
- Then it should boot Droidian! This may take a bit of time.
The battery and it’s charge and discharge rates are very important to me, it’s what made the PinePhonePro and Librem5 unusable as daily driver phones.
After running for about 100 minutes of which about 40 minutes were playing with various settings the phone was at 89% battery. The output of “upower -d” isn’t very accurate as it reported power use ranging from 0W to 25W! But this does suggest that the phone might last for 400 minutes of real use that’s not CPU intensive, such as reading email, document editing, and web browsing. I don’t think that 6.5 hours of doing such things non-stop without access to a power supply or portable battery is something I’m ever going to do. Samsung when advertising the phone claimed 17 hours of video playback which I don’t think I’m ever going to get – or want.
After running for 11 hours it was at 58% battery. Then after just over 21 hours of running it had 13% battery. Generally I don’t trust the upower output much but the fact that it ran for over 21 hours shows that it’s battery life is much better than the PinePhonePro and the Librem5. During that 21 hours I’ve had a ssh session open with the client set to send ssh keep-alive messages every minute. So it had to remain active. There is an option to suspend on Droidian but they recommend you don’t use it. There is no need for the “caffeine mode” that you have on Mobian. For comparison my previous tests suggested that when doing nothing a PinePhonePro might last for 30 hours on battery while the Liberem5 might only list 10 hours [2]. This test with Droidian was done with the phone within my reach for much of that time and subject to my desire to fiddle with new technology – so it wasn’t just sleeping all the time.
When charging from the USB port on my PC it went from 13% to 27% charge in half an hour and then after just over an hour it claimed to be at 33%. It ended up taking just over 7 hours to fully charge from empty that’s not great but not too bad for a PC USB port. This is the same USB port that my Librem5 couldn’t charge from. Also the discharge:charge ratio of 21:7 is better than I could get from the PinePhonePro with Caffeine mode enabled.
rndis0The rndis0 interface used for IP over USB doesn’t work. Droidian bug #36 [3].
Other HardwareThe phone I bought for testing is the model with 6G of RAM and 128G of storage, has a minor screen crack and significant screen burn-in. It’s a good test system for $109. The screen burn-in is very obvious when running the default Android setup but when running the default Droidian GNOME setup set to the Dark theme (which is a significant power saving with an AMOLED screen) I can’t see it at all. Buying a cheap phone with screen burn-in is something I recommend.
The stylus doesn’t work, this isn’t listed on the Droidian web page. I’m not sure if I tested the stylus when the phone was running Android, I think I did.
D State ProcessesI get a kernel panic early in the startup for unknown reasons and some D state kernel threads which may or may not be related to that. Droidian bug #37 [4].
Second Phone The PhoneI ordered a second Note9 on ebay, it had been advertised at $240 for a month and the seller accepted my offer of $200. With postage that’s $215 for a Note9 in decent condition with 8G of RAM and 512G of storage. But Droidian dropped support for the Note9 before I got to install it. At the moment I’m not sure what I’ll do with this, maybe I’ll keep it on Android.
I also bought four phone cases for $16. I got spares because of the high price of postage relative to the case cost and the fact that they may be difficult to get in a few years.
The TestsFor the next phone my plan was to do more tests on Android before upgrading it to Debian. Here are the ones I can think of now, please suggest any others I should do.
- Log output of “ps auxf” equivalent.
- Make notes on what they are doing with SE Linux.
- Test the stylus.
- Test USB networking to my workstation and my laptop.
- Make a copy of the dmesg output. Also look for D state processes and other signs of problems.
When I tell technical people about Droidian a common reaction is “great you can get a cheap powerful phone and have better security than Android”. This is wrong in several ways. Firstly Android has quite decent security. Android runs most things in containers and uses SE Linux. Droidian has the Debian approach for most software (IE it all runs under the same UID without any special protections) and the developers have no plans to use SE Linux. I’ve previously blogged about options for Sandboxing for Debian phone use, my blog post is NOT a solution to the problem but an analysis of the different potential ways of going about solving it [5].
The next issue is that Droidian has no way to update the kernel and the installation instructions often advise downgrading Android (running a less secure kernel) before the installation. The Android Generic Kernel Image project [6] addresses this by allowing a separation between drivers supplied by the hardware vendor and the kernel image supplied by Google. This also permits running the hardware vendor’s drivers with a GKI kernel released by Google after the hardware vendor dropped security support. But this only applies to Android 11 and later, so Android 10 devices (like the Note 9 image for Droidian) miss out on this.
- [1] https://www.gsmarena.com/samsung_galaxy_note9-9163.php
- [2] https://etbe.coker.com.au/2023/06/06/pinephonepro-first-impression/
- [3] https://github.com/droidian/droidian/issues/36
- [4] https://github.com/droidian/droidian/issues/37
- [5] https://etbe.coker.com.au/2023/07/08/sandboxing-phone-apps/
- [6] https://tinyurl.com/236bjztz
Related posts:
- Samsung Galaxy Note 2 A few weeks ago I bought a new Samsung Galaxy...
- Samsung Galaxy Note 3 In June last year I bought a Samsung Galaxy Note...
- Samsung Galaxy Note 10.1 2014 In May 2014 I bought a Samsung Galaxy Note 10.1...
Russell Coker: Kitty and Mpv
6 months ago I switched to Kitty for terminal emulation [1]. So far there’s only been one thing that I couldn’t effectively do with Kitty that I did with Konsole in the past, that is watching a music video in 1/4 of the screen while using the rest for terminals. I could setup multiple Kitty windows taking up the rest of the screen but I wanted to keep using a single Kitty with multiple terminals and just have mpv go over one of them. Kitty supports it’s own graphical interface so “mpv –vo=kitty” works but took 6* the CPU power in my tests which isn’t good for a laptop.
For X11 there’s a –ontop option for mpv that does what you expect, but that doesn’t work on Wayland. Not working is mostly Wayland’s fault as there is a long tail of less commonly used graphical operations that work in X11 but aren’t yet implemented in Wayland. I have filed a Debian bug report about this, the mpv man page should note that it’s only going to work on X11 on Linux.
I have discovered a solution to that, in the KDE settings there’s a “Window Rules” section, I created an entry for “Window class” exactly matching “mpv” and then added a rule “Keep above other windows” and set it for “force” and “yes”.
After that I can just resize mpv to occlude just one terminal and keep using the rest. Also one noteworthy thing with this is that it makes mpv go on top of the KDE taskbar, which can be a feature.
Related posts:
- Hello Kitty I’ve just discovered a new xterm replacement named Kitty [1]....
- Thinkpad X1 Yoga Gen3 I just bought myself a Thinkpad X1 Yoga Gen3 for...
- Wayland in Bookworm We are getting towards the freeze for Debian/Bookworm so the...