I am trying to automate the creation of VM cloud image templates on my Proxmox server using Ansible. If I execute the commands in a shell script it always works. If I execute the same commands (with multiple item expansion) in the Ansible shell module, it fails, and I'm not sure why, my guess is timing.
Test.sh:
#!/bin/bash
set -e
qm unlock 1003 || true
qm destroy 1003 || true
qm create 1003 \
--name test-template \
--tags test1,test2 \
--memory 4096 \
--cores 2 \
--net0 virtio,bridge=vmbr1 \
--scsihw virtio-scsi-pci \
--ciuser pieter \
--cipassword Password1 \
--searchdomain home.insanegenius.net \
--sshkeys /data/install/images/ssh_keys \
--ipconfig0 ip=dhcp \
--ostype l26 \
--agent 1
virt-customize -a /data/install/images/debian-12-genericcloud-amd64.qcow2 --install qemu-guest-agent
qm set 1003 --scsi0 vmdata:0,import-from=/data/install/images/debian-12-genericcloud-amd64.qcow2 --boot order=scsi0 --ide2 vmdata:cloudinit
qm resize 1003 scsi0 8G
qm template 1003
Run test.sh:
pieter@server-1:~/HomeAutomation$ sudo ./test.sh
[sudo] password for pieter:
[ 0.0] Examining the guest ...
[ 4.0] Setting a random seed
virt-customize: warning: random seed could not be set for this type of
guest
[ 4.0] Installing packages: qemu-guest-agent
[ 6.5] Finishing off
update VM 1003: -boot order=scsi0 -ide2 vmdata:cloudinit -scsi0 vmdata:0,import-from=/data/install/images/debian-12-genericcloud-amd64.qcow2
ide2: successfully created disk 'vmdata:vm-1003-cloudinit,media=cdrom'
transferred 0.0 B of 2.0 GiB (0.00%)
transferred 20.5 MiB of 2.0 GiB (1.00%)
...
transferred 2.0 GiB of 2.0 GiB (100.00%)
scsi0: successfully created disk 'vmdata:vm-1003-disk-0,size=2G'
generating cloud-init ISO
pieter@server-1:~/HomeAutomation$
Ansible playbook:
---
# Create Cloud-Init templates
# https://pve.proxmox.com/wiki/Cloud-Init_Support
# Install libguestfs
# https://docs.ansible.com/ansible/latest/modules/apt_module.html
- name: "Install libguestfs"
apt:
name: ["libguestfs-tools"]
state: latest
update_cache: yes
cache_valid_time: 3600
# https://docs.ansible.com/ansible/latest/modules/file_module.html
- name: "Create Cloud Init directory"
file:
path: "{{ item }}"
state: directory
mode: "ugo+rwx"
owner: nobody
group: users
recurse: true
with_items:
- "{{ cloud_init_dir }}"
# Download SSH keys and cloud images
# https://docs.ansible.com/ansible/latest/collections/ansible/builtin/get_url_module.html
- name: "Download cloud init artifacts"
# Register changes
register: download
get_url:
url: "{{ item.url }}"
dest: "{{ item.dest }}"
mode: "ugo+rwx"
owner: nobody
group: users
timeout: 120
with_items:
- {
url: "https://launchpad.net/~{{ launchpad_user }}/+sshkeys",
dest: "{{ cloud_init_dir }}/ssh_keys",
}
- {
url: "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img",
dest: "{{ cloud_init_dir }}/jammy-server-cloudimg-amd64.img",
}
- {
url: "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2",
dest: "{{ cloud_init_dir }}/debian-12-genericcloud-amd64.qcow2",
}
# Create templates
# https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html
- name: "Create cloud image templates"
# Recreate when images changed
# when: download.changed
ansible.builtin.shell: |
qm unlock {{ item.id }} || true
qm destroy {{ item.id }} || true
qm create {{ item.id }} \
--name {{ item.name }} \
--tags {{ item.tags }} \
--memory 4096 \
--cores 2 \
--net0 virtio,bridge=vmbr1 \
--scsihw virtio-scsi-pci \
--ciuser {{ cloud_init_user }} \
--cipassword {{ cloud_init_password }} \
--searchdomain {{ cloud_init_domain }} \
--sshkeys {{ cloud_init_dir }}/ssh_keys \
--ipconfig0 ip=dhcp \
--ostype l26 \
--agent 1
virt-customize -a {{ item.image }} --install qemu-guest-agent
qm set {{ item.id }} --scsi0 vmdata:0,import-from={{ item.image }} --boot order=scsi0 --ide2 vmdata:cloudinit
qm resize {{ item.id }} scsi0 8G
qm template {{ item.id }}
with_items:
- {
id: "9001",
name: "ubuntu-jammy-template",
tags: "ubuntu,jammy,cloud-image",
image: "{{ cloud_init_dir }}/jammy-server-cloudimg-amd64.img"
}
- {
id: "9002",
name: "debian-bookworm-template",
tags: "debian,bookworm,cloud-image",
image: "{{ cloud_init_dir }}/debian-12-genericcloud-amd64.qcow2"
}
Run playbook:
pieter@server-1:~/HomeAutomation$ ansible-playbook -vvv --ask-become-pass ~/HomeAutomation/Ansible/test.yml
ansible-playbook [core 2.15.2]
config file = None
configured module search path = ['/home/pieter/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.9/dist-packages/ansible
ansible collection location = /home/pieter/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible-playbook
python version = 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110] (/usr/bin/python3)
jinja version = 3.0.1
libyaml = True
No config file found; using defaults
BECOME password:
...
PLAYBOOK: test.yml ***********************************************************************************************************************************************************************************************************************************************************************************
1 plays in /home/pieter/HomeAutomation/Ansible/test.yml
...
TASK [Create cloud image templates] ******************************************************************************************************************************************************************************************************************************************************************
task path: /home/pieter/HomeAutomation/Ansible/tasks/cloud_init.yml:54
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: pieter
<127.0.0.1> EXEC /bin/sh -c 'echo ~pieter && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/pieter/.ansible/tmp `"&& mkdir "` echo /home/pieter/.ansible/tmp/ansible-tmp-1690944817.2016468-1824495-48439512100173 `" && echo ansible-tmp-1690944817.2016468-1824495-48439512100173="` echo /home/pieter/.ansible/tmp/ansible-tmp-1690944817.2016468-1824495-48439512100173 `" ) && sleep 0'
Using module file /usr/local/lib/python3.9/dist-packages/ansible/modules/command.py
<127.0.0.1> PUT /home/pieter/.ansible/tmp/ansible-local-18231187hwfn7n8/tmpt8mizpiv TO /home/pieter/.ansible/tmp/ansible-tmp-1690944817.2016468-1824495-48439512100173/AnsiballZ_command.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/pieter/.ansible/tmp/ansible-tmp-1690944817.2016468-1824495-48439512100173/ /home/pieter/.ansible/tmp/ansible-tmp-1690944817.2016468-1824495-48439512100173/AnsiballZ_command.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'sudo -H -S -p "[sudo via ansible, key=qqdobawkyyzlecwcixjocubtcgjgsaml] password:" -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-qqdobawkyyzlecwcixjocubtcgjgsaml ; /usr/bin/python3 /home/pieter/.ansible/tmp/ansible-tmp-1690944817.2016468-1824495-48439512100173/AnsiballZ_command.py'"'"' && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/pieter/.ansible/tmp/ansible-tmp-1690944817.2016468-1824495-48439512100173/ > /dev/null 2>&1 && sleep 0'
failed: [localhost] (item={'id': '9001', 'name': 'ubuntu-jammy-template', 'tags': 'ubuntu,jammy,cloud-image', 'image': '/data/install/images/jammy-server-cloudimg-amd64.img'}) => {
"ansible_loop_var": "item",
"changed": true,
"cmd": "qm unlock 9001 || true\nqm destroy 9001 || true\nqm create 9001 --name ubuntu-jammy-template --tags ubuntu,jammy,cloud-image --memory 4096 --cores 2 --net0 virtio,bridge=vmbr1 --scsihw virtio-scsi-pci --ciuser pieter --cipassword Password1 --searchdomain home.insanegenius.net --sshkeys /data/install/images/ssh_keys --ipconfig0 ip=dhcp --ostype l26 --agent 1\nvirt-customize -a /data/install/images/jammy-server-cloudimg-amd64.img --install qemu-guest-agent\nqm set 9001 --scsi0 vmdata:0,import-from=/data/install/images/jammy-server-cloudimg-amd64.img --boot order=scsi0 --ide2 vmdata:cloudinit\nqm resize 9001 scsi0 8G\nqm template 9001\n",
"delta": "0:00:12.984944",
"end": "2023-08-01 19:53:50.477484",
"invocation": {
"module_args": {
"_raw_params": "qm unlock 9001 || true\nqm destroy 9001 || true\nqm create 9001 --name ubuntu-jammy-template --tags ubuntu,jammy,cloud-image --memory 4096 --cores 2 --net0 virtio,bridge=vmbr1 --scsihw virtio-scsi-pci --ciuser pieter --cipassword Password1 --searchdomain home.insanegenius.net --sshkeys /data/install/images/ssh_keys --ipconfig0 ip=dhcp --ostype l26 --agent 1\nvirt-customize -a /data/install/images/jammy-server-cloudimg-amd64.img --install qemu-guest-agent\nqm set 9001 --scsi0 vmdata:0,import-from=/data/install/images/jammy-server-cloudimg-amd64.img --boot order=scsi0 --ide2 vmdata:cloudinit\nqm resize 9001 scsi0 8G\nqm template 9001\n",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true
}
},
"item": {
"id": "9001",
"image": "/data/install/images/jammy-server-cloudimg-amd64.img",
"name": "ubuntu-jammy-template",
"tags": "ubuntu,jammy,cloud-image"
},
"msg": "non-zero return code",
"rc": 25,
"start": "2023-08-01 19:53:37.492540",
"stderr": "failed to tcsetpgrp: Inappropriate ioctl for device\ngot no worker upid - start worker failed\nunable to create VM 9001 - VM 9001 already exists on node 'server-1'\nzfs error: cannot create 'ssdpool/vmdata/vm-9001-cloudinit': dataset already exists\nfailed to tcsetpgrp: Inappropriate ioctl for device\ngot no worker upid - start worker failed",
"stderr_lines": [
"failed to tcsetpgrp: Inappropriate ioctl for device",
"got no worker upid - start worker failed",
"unable to create VM 9001 - VM 9001 already exists on node 'server-1'",
"zfs error: cannot create 'ssdpool/vmdata/vm-9001-cloudinit': dataset already exists",
"failed to tcsetpgrp: Inappropriate ioctl for device",
"got no worker upid - start worker failed"
],
"stdout": "[ 0.0] Examining the guest ...\n[ 4.0] Setting a random seed\nvirt-customize: warning: random seed could not be set for this type of \nguest\n[ 4.0] Installing packages: qemu-guest-agent\n[ 7.2] Finishing off\nupdate VM 9001: -boot order=scsi0 -ide2 vmdata:cloudinit -scsi0 vmdata:0,import-from=/data/install/images/jammy-server-cloudimg-amd64.img",
"stdout_lines": [
"[ 0.0] Examining the guest ...",
"[ 4.0] Setting a random seed",
"virt-customize: warning: random seed could not be set for this type of ",
"guest",
"[ 4.0] Installing packages: qemu-guest-agent",
"[ 7.2] Finishing off",
"update VM 9001: -boot order=scsi0 -ide2 vmdata:cloudinit -scsi0 vmdata:0,import-from=/data/install/images/jammy-server-cloudimg-amd64.img"
]
}
<127.0.0.1> EXEC /bin/sh -c 'echo ~pieter && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /home/pieter/.ansible/tmp `"&& mkdir "` echo /home/pieter/.ansible/tmp/ansible-tmp-1690944830.5114603-1824495-279107019138629 `" && echo ansible-tmp-1690944830.5114603-1824495-279107019138629="` echo /home/pieter/.ansible/tmp/ansible-tmp-1690944830.5114603-1824495-279107019138629 `" ) && sleep 0'
Using module file /usr/local/lib/python3.9/dist-packages/ansible/modules/command.py
<127.0.0.1> PUT /home/pieter/.ansible/tmp/ansible-local-18231187hwfn7n8/tmpyct2nw3u TO /home/pieter/.ansible/tmp/ansible-tmp-1690944830.5114603-1824495-279107019138629/AnsiballZ_command.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /home/pieter/.ansible/tmp/ansible-tmp-1690944830.5114603-1824495-279107019138629/ /home/pieter/.ansible/tmp/ansible-tmp-1690944830.5114603-1824495-279107019138629/AnsiballZ_command.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'sudo -H -S -p "[sudo via ansible, key=gfciqiccesiblnfsfuarenctwdneivte] password:" -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-gfciqiccesiblnfsfuarenctwdneivte ; /usr/bin/python3 /home/pieter/.ansible/tmp/ansible-tmp-1690944830.5114603-1824495-279107019138629/AnsiballZ_command.py'"'"' && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /home/pieter/.ansible/tmp/ansible-tmp-1690944830.5114603-1824495-279107019138629/ > /dev/null 2>&1 && sleep 0'
failed: [localhost] (item={'id': '9002', 'name': 'debian-bookworm-template', 'tags': 'debian,bookworm,cloud-image', 'image': '/data/install/images/debian-12-genericcloud-amd64.qcow2'}) => {
"ansible_loop_var": "item",
"changed": true,
"cmd": "qm unlock 9002 || true\nqm destroy 9002 || true\nqm create 9002 --name debian-bookworm-template --tags debian,bookworm,cloud-image --memory 4096 --cores 2 --net0 virtio,bridge=vmbr1 --scsihw virtio-scsi-pci --ciuser pieter --cipassword Password1 --searchdomain home.insanegenius.net --sshkeys /data/install/images/ssh_keys --ipconfig0 ip=dhcp --ostype l26 --agent 1\nvirt-customize -a /data/install/images/debian-12-genericcloud-amd64.qcow2 --install qemu-guest-agent\nqm set 9002 --scsi0 vmdata:0,import-from=/data/install/images/debian-12-genericcloud-amd64.qcow2 --boot order=scsi0 --ide2 vmdata:cloudinit\nqm resize 9002 scsi0 8G\nqm template 9002\n",
"delta": "0:00:11.894339",
"end": "2023-08-01 19:54:02.562572",
"invocation": {
"module_args": {
"_raw_params": "qm unlock 9002 || true\nqm destroy 9002 || true\nqm create 9002 --name debian-bookworm-template --tags debian,bookworm,cloud-image --memory 4096 --cores 2 --net0 virtio,bridge=vmbr1 --scsihw virtio-scsi-pci --ciuser pieter --cipassword Password1 --searchdomain home.insanegenius.net --sshkeys /data/install/images/ssh_keys --ipconfig0 ip=dhcp --ostype l26 --agent 1\nvirt-customize -a /data/install/images/debian-12-genericcloud-amd64.qcow2 --install qemu-guest-agent\nqm set 9002 --scsi0 vmdata:0,import-from=/data/install/images/debian-12-genericcloud-amd64.qcow2 --boot order=scsi0 --ide2 vmdata:cloudinit\nqm resize 9002 scsi0 8G\nqm template 9002\n",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true
}
},
"item": {
"id": "9002",
"image": "/data/install/images/debian-12-genericcloud-amd64.qcow2",
"name": "debian-bookworm-template",
"tags": "debian,bookworm,cloud-image"
},
"msg": "non-zero return code",
"rc": 25,
"start": "2023-08-01 19:53:50.668233",
"stderr": "failed to tcsetpgrp: Inappropriate ioctl for device\ngot no worker upid - start worker failed\nunable to create VM 9002 - VM 9002 already exists on node 'server-1'\nzfs error: cannot create 'ssdpool/vmdata/vm-9002-cloudinit': dataset already exists\nfailed to tcsetpgrp: Inappropriate ioctl for device\ngot no worker upid - start worker failed",
"stderr_lines": [
"failed to tcsetpgrp: Inappropriate ioctl for device",
"got no worker upid - start worker failed",
"unable to create VM 9002 - VM 9002 already exists on node 'server-1'",
"zfs error: cannot create 'ssdpool/vmdata/vm-9002-cloudinit': dataset already exists",
"failed to tcsetpgrp: Inappropriate ioctl for device",
"got no worker upid - start worker failed"
],
"stdout": "[ 0.0] Examining the guest ...\n[ 3.8] Setting a random seed\nvirt-customize: warning: random seed could not be set for this type of \nguest\n[ 3.8] Installing packages: qemu-guest-agent\n[ 6.0] Finishing off\nupdate VM 9002: -boot order=scsi0 -ide2 vmdata:cloudinit -scsi0 vmdata:0,import-from=/data/install/images/debian-12-genericcloud-amd64.qcow2",
"stdout_lines": [
"[ 0.0] Examining the guest ...",
"[ 3.8] Setting a random seed",
"virt-customize: warning: random seed could not be set for this type of ",
"guest",
"[ 3.8] Installing packages: qemu-guest-agent",
"[ 6.0] Finishing off",
"update VM 9002: -boot order=scsi0 -ide2 vmdata:cloudinit -scsi0 vmdata:0,import-from=/data/install/images/debian-12-genericcloud-amd64.qcow2"
]
}
PLAY RECAP *******************************************************************************************************************************************************************************************************************************************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
pieter@server-1:~/HomeAutomation$
When the task fails, I am left with incomplete VM images, or VM images that are in a "locked (create)" state.
I did try to use /bin/bash
as shell, but it made no difference.