cloud-init icon indicating copy to clipboard operation
cloud-init copied to clipboard

pip upgrade can fail in ansible install

Open TheRealFalcon opened this issue 10 months ago • 2 comments

The pip install --upgrade pip in the ansible module, can result in the following:

/usr/bin/python3 -m pip install --break-system-packages --upgrade pip
Requirement already satisfied: pip in /usr/lib/python3/dist-packages (25.0)
Collecting pip
  Using cached pip-25.0.1-py3-none-any.whl.metadata (3.7 kB)
Using cached pip-25.0.1-py3-none-any.whl (1.8 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 25.0
error: uninstall-no-record-file

× Cannot uninstall pip 25.0
╰─> The package's contents are unknown: no RECORD file was found for pip.

hint: The package was installed by debian. You should check if it can uninstall the package.

This will cause the module to exit with exception.

TheRealFalcon avatar Mar 05 '25 19:03 TheRealFalcon

@TheRealFalcon What do you think to do? Catch exception?

AliyevH avatar Mar 05 '25 22:03 AliyevH

@AliyevH , yes I'm thinking that in most cases we shouldn't need pip updated, so we can catch and log the exception.

TheRealFalcon avatar Mar 06 '25 01:03 TheRealFalcon

I created a pull request with the bug fix https://github.com/canonical/cloud-init/pull/6301

mostafaCamel avatar Jul 10 '25 03:07 mostafaCamel

Info dump for future first timers (like me):

What this module does

package_name in cc_ansible.py is almost always "ansible" or "ansible-core" (lightweight ansible), see package_name in schema-cloud-config-v1.json . The idea is to install/ either package/ ensure it is installed before pulling playbooks

Also note, that the modules in cloud-init usually run only once (at the first boot of the VM) and not per-boot (you can customize it)

Reproducing the bug:

  • This file /tmp/user-data on my local will be used later to setup my VM
cat >/tmp/user-data <<EOF
#cloud-config
ansible:
  package_name: ansible-core
  install_method: pip
  pull:
    url: "https://github.com/holmanb/vmboot.git"
    playbook_name: ubuntu.yml
EOF
  • Spin up a VM witht this config and with the noble (ubuntu 24) image multipass launch noble --name test-vm --cloud-init /tmp/user-data . Note: When I am done with the VM and no longer care about it, multipass delete test-vm --purge

  • Inspect the error

 multipass exec test-vm -- cloud-init status --long
status: error
extended_status: error - done
boot_status_code: enabled-by-generator
last_update: Thu, 01 Jan 1970 00:01:46 +0000
detail: DataSourceNoCloud [seed=/dev/vda]
errors:
	- ('ansible', ProcessExecutionError("Unexpected error while running command.\nCommand: ['/usr/bin/python3', '-m', 'pip', 'install', '--break-system-packages', '--upgrade', 'pip']\nExit code: 1\nReason: -\nStdout: Requirement already satisfied: pip in /usr/lib/python3/dist-packages (24.0)\n        Collecting pip\n          Downloading pip-25.1.1-py3-none-any.whl.metadata (3.6 kB)\n        Downloading pip-25.1.1-py3-none-any.whl (1.8 MB)\n           ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 601.8 kB/s eta 0:00:00\n        Installing collected packages: pip\n          Attempting uninstall: pip\n            Found existing installation: pip 24.0\nStderr: ERROR: Cannot uninstall pip 24.0, RECORD file not found. Hint: The package was installed by debian."))
recoverable_errors:
WARNING:
	- Running module ansible (<module 'cloudinit.config.cc_ansible' from '/usr/lib/python3/dist-packages/cloudinit/config/cc_ansible.py'>) failed

You can alternatively multipass shell test-vm to bash your way around inside the VM. Other log fields that you can look into /var/log/cloud-init-output.log /var/log/cloud-init.log

Testing the local changes

  • This comment discusses how to mount the local repo (before launching the VM) with lxd in order to test the python scripts (the script is used and not a wheel). Note that my change does not affect systemd so no need to build the apt package/ install it then rerun cloud-init with reboot as the comment explains for such cases.

  • I have a Mac and I had problems with lxc so I used multipass instead (which does not mount before launching the VM so I will need to rerun cloud-init to check my python script changes)

  • multipass launch noble --name test-vm --cloud-init user-data --mount /tmp/cloud-init/cloudinit:/usr/lib/python3/dist-packages/cloudinit

    • The most important thing to note is that I first dittoed my local repo into /tmp/cloud-init . This is due to the " Full Disk Access setting" in macOS. If this setting is not enabled for multipassd, then mounting will never be functional (Operation not permitted problems) when you mount for paths that are protected such as ~ , hence I just moved the local repo to /tmp to save myself the hassle. Even passing --uid-map 501:0 --gid-map 20:0 to the multipass command will not fix the issue.
  • There is a discrepancy between the cloud-init version (25.1.2) in noble and the version in the local repo (25.1.4) . So we need to rerun cloud-init (weirdly the rerun with reboot sudo cloud-init clean --logs --configs all --rebootz does not work and it still uses the old version while the rerun without reboot works zsudo cloud-init clean --logs && sudo cloud-init init --local && sudo cloud-init init && sudo cloud-init modules --mode=config && sudo cloud-init modules --mode=final)

In the VM, the entry-point bash script /usr/bin/cloud-init was using the old version (25.1.2). My guess is that it is generated when the debian package is built On the other hand, the python-script code (./cloudinit/version.py in the local repo mounted to /usr/lib/python3/dist-packages/cloudinit/version.py in the VM) points to 25.1.4. I did not have to edit the versions. It just worked:TM:

mostafaCamel avatar Jul 10 '25 04:07 mostafaCamel