In my Ansible role I try to update the PHP version of all installed PHP packages. For this reason I read out all installed PHP packages into a list, manipulate the version number in every element in this list and after that I try to install all packages with the new PHP version out of this list.
my update-Debian.yml
(task): (not complete yet)
---
- name: get list of installed php packages
shell: "dpkg -l | grep php | awk '{print $2}'"
register: update_php_installed_packages
- name: set_fact php current package lists
set_fact:
php_packages_installed: "{{ update_php_installed_packages.stdout_lines }}"
- name: set_fact php wanted package list
set_fact:
php_packages_wanted: "{{ php_packages_wanted | default([]) + [item.replace( update_php_current_php_version , update_php_wanted_php_version )] }}"
loop: "{{ php_packages_installed }}"
- name: "Install new PHP{{ update_php_wanted_php_version }} Packages"
apt:
name: "{{ php_packages_wanted }}"
state: present
update_cache: true
- name: "Update-Alternatives from PHP{{ update_php_current_php_version }} to PHP{{ update_php_wanted_php_version }}"
alternatives:
name: php
path: "/usr/bin/php{{ update_php_wanted_php_version }}"
- name: "Set Apache2 default PHP-Version to {{ update_php_wanted_php_version }}"
command: "a2dismod php{{ update_php_current_php_version }}"
- command: "a2enmod php{{ update_php_wanted_php_version }}"
notify:
- restart httpd
- restart php-fpm
- name: "Install new PHP{{ update_php_wanted_php_version }} Packages"
apt:
name: "{{ php_packages_installed }}"
state: absent
Unfortunately at least the package php7.4-json
is a virtual package so the apt command runs into an error:
ASK [ansible-role-update-php : Install new PHP8.2 Packages]
***************************************************************
fatal: [nextcloud01]: FAILED! => {"cache_update_time": 1694096679, "cache_updated": true, "changed": false, "msg": "'/usr/bin/apt-get -y -o "Dpkg::Options::=--force-confdef" -o "Dpkg::Options::=--force-confold" install 'libapache2-mod-php8.2=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-apcu=5.1.22++-1+0~20230618.37+debian12~1.gbp7134d4' 'php8.2-bcmath=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-cli=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-common=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-curl=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-fpm=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-gd=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-gmp=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-igbinary=3.2.14-1+0~20230618.45+debian12~1.gbpcc1dca' 'php8.2-imagick=3.7.0-4+0~20230701.41+debian12~1.gbpbf7e27' 'php8.2-intl=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-json' 'php8.2-mbstring=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-mysql=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-opcache=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-pgsql=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-readline=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-redis=5.3.7++-1+0~20230619.51+debian12~1.gbp4ff337' 'php8.2-smbclient=1.1.1-1+0~20230612.24+debian12~1.gbp8be856' 'php8.2-xml=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-zip=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-cli=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-common=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-opcache=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c' 'php8.2-readline=8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c'' failed: E: Package 'php8.2-json' has no installation candidate\n", "rc": 100, "stderr": "E: Package 'php8.2-json' has no installation candidate\n", "stderr_lines": ["E: Package 'php8.2-json' has no installation candidate"], "stdout": "Reading package lists...\nBuilding dependency tree...\nReading state information...\nPackage php8.2-json is a virtual package provided by:\n php8.2-phpdbg 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c\n php8.2-fpm 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c\n php8.2-cli 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c\n php8.2-cgi 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c\n libphp8.2-embed 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c\n libapache2-mod-php8.2 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c\n\n", "stdout_lines": ["Reading package lists...", "Building dependency tree...", "Reading state information...", "Package php8.2-json is a virtual package provided by:", " php8.2-phpdbg 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c", " php8.2-fpm 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c", " php8.2-cli 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c", " php8.2-cgi 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c", " libphp8.2-embed 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c", " libapache2-mod-php8.2 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c", ""]}
If I try to install these package directly on the machine via apt package manager I get the following error:
root@nc01/# apt install php8.2-json
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package php8.2-json is a virtual package provided by:
php8.2-phpdbg 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c
php8.2-fpm 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c
php8.2-cli 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c
php8.2-cgi 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c
libphp8.2-embed 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c
libapache2-mod-php8.2 8.2.10-1+0~20230904.33+debian12~1.gbp2dc84c
You should explicitly select one to install.
E: Package 'php8.2-json' has no installation candidate
By hand, I would choose one of the suggested packages an that's it. In this case, there's already in my php-package-list
at least one of the suggested packages. But how to solve this problem in Ansible?
I have no idea how to manage this problem. Maybe there is a better solution than my way.
Preamble: when designing a flow with Ansible, try the best you can to forget what you know about executing the said task in the command line and try to focus on using existing Ansible module.
In your case, that means using the module package_facts
rather than dpkg
to get the list of installed packages, and then filter the list using Jinja filters, i.e. the select
one.
So:
- package_facts:
- set_fact:
php_packages_installed: >-
{{ ansible_facts.packages.keys() | select('contains', 'php') }}
Now, regarding the package you are looking for, this package exists in Debian 12, but without a PHP version, so the package is named php-json
.
For this, you could actually build a dictionary of known replacement, something like
packages_replacements:
php8.2-json: php-json
## you can further extends this dictionary if you find
## other packages that does not have a 1:1 replacement
## after swapping the PHP version
And use the replace
filter to replace those in your list of package.
Something like:
- set_fact:
php_packages_wanted: >-
{{
php_packages_wanted
| default(php_packages_installed)
| replace(item.key, item.value)
}}
loop: >-
{{
{update_php_current_php_version: update_php_wanted_php_version}
| combine(packages_replacements)
| dict2items
}}
vars:
packages_replacements:
php8.2-json: php-json
Given those tasks:
- package_facts:
- set_fact:
php_packages_installed: >-
{{ ansible_facts.packages.keys() | select('contains', 'php') }}
- set_fact:
php_packages_wanted: >-
{{
php_packages_wanted
| default(php_packages_installed)
| replace(item.key, item.value)
}}
loop: >-
{{
{update_php_current_php_version: update_php_wanted_php_version}
| combine(packages_replacements)
| dict2items
}}
vars:
update_php_current_php_version: 7.4
update_php_wanted_php_version: 8.2
packages_replacements:
php8.2-json: php-json
- debug:
msg:
php_packages_installed: "{{ php_packages_installed }}"
php_packages_wanted: "{{ php_packages_wanted }}"
It would yield:
ok: [ansible-debian-1] =>
msg:
php_packages_installed:
- php7.4-cli
- php7.4-common
- php7.4-curl
- php7.4-fpm
- php7.4-gd
- php7.4-gmp
- php7.4-igbinary
- php7.4-json
php_packages_wanted:
- php8.2-cli
- php8.2-common
- php8.2-curl
- php8.2-fpm
- php8.2-gd
- php8.2-gmp
- php8.2-igbinary
- php-json