0

I have a bash script which runs as a cronjob. This script runs several commands and one of them is the following virsh command:

/usr/bin/virsh list --all

When I run this script in the terminal (as root) or as a cronjob (as root also) the virsh command works as expected and lists all the virtual machines.

During my testing and debugging of this script, I noticed that if I send the script to the background or if I send it to the background and then disown it, the script hangs indefinitely at the virsh command. Below I provide some more details.

To illustrate the issue, let's assume a simple script "test.bash":

[root@kvm-host]# cat test.bash
#!/bin/bash

/usr/bin/virsh list --all

When I run the script test.bash in the foreground it works as expected:

[root@kvm-host]# bash -x test.bash
+ /usr/bin/virsh list --all
 Id   Name                    State
----------------------------------------
 27   slave1                  running
 29   ubuntu_discourse        running
 30   osticket                running
 31   lubuntu_desktop         running
 -    slave2                  shut off

When I run the script test.bash in the background it hangs indefinitely at the virsh command:

[root@kvm-host]# bash test.bash 2>stderr &
[1] 1119722
[root@kvm-host]# ps aux | grep virsh | grep -v grep
root     1119723  0.0  0.0 442660 16012 pts/4    Tl   17:07   0:00 /usr/bin/virsh list --all

[1]+  Stopped                 bash test.bash 2> stderr

If I send the script to the background and disown it, the script also hangs at the virsh command:

[root@kvm-host]# bash -x test.bash 2>stderr & disown
[1] 1119502
[root@kvm-host]# ps aux | grep virsh | grep -v grep
root     1119503  0.0  0.0 442656 15956 pts/4    Tl   17:05   0:00 /usr/bin/virsh list --all

I have tried running the virsh command with -c qemu:///system and the behaviour is the same when I send the script test.bash to the background. As you can see above, I have also tried running the script without "bash -x". I have also tried running the script redirecting both stderr and stdout to /dev/null. Finally, I have also tried running the script without redirecting stderr or stdout to any file. The issue is the same in all these cases.

Is it possible to run the virsh command in the background as described? Any comments would be highly appreciated. Thank you!

Here are some details about my system:

[root@kvm-host]# cat /etc/redhat-release
Rocky Linux release 8.6 (Green Obsidian)

[root@kvm-host]# virsh -V
Virsh command line tool of libvirt 8.0.0
See web site at https://libvirt.org/

Compiled with support for:
 Hypervisors: QEMU/KVM ESX Test
 Networking: Remote Network Bridging Interface netcf Nwfilter
 Storage: Dir Disk Filesystem SCSI Multipath iSCSI LVM RBD Gluster
 Miscellaneous: Daemon Nodedev SELinux Secrets Debug DTrace Readline
Esteban
  • 35
  • 7

2 Answers2

2

I guess that this happens because of pkttyagent.

This example shows, how the process is hanging in the background:

# virsh list &
[1] 2121077

#
[1]+  Stopped                 virsh list

# ps f
2039251 pts/11   S      0:00      \_ -bash
2121077 pts/11   Tl     0:00          \_ virsh list
2121079 pts/11   Tl     0:00          |   \_ /usr/bin/pkttyagent --process 2121077 --notify-fd 4 --fallback
2121760 pts/11   R+     0:00          \_ ps f

If the process is put into the foreground again, it finishes:

# fg
virsh list
 Id   Name       State
--------------------------
 2    docker     running
 3    test       running

#

I found the following unresolved issue: https://bugzilla.redhat.com/show_bug.cgi?id=1726714, which describes that this happens because of the signal SIGTTOU. A description if this signal can be found here: https://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html

mre
  • 36
  • 1
0

This issue occurs since libvirt version 7.10. In particular, since this commit which changes the check so that pkttyagent is run even without a TTY. See also the libvirt issue.

Workaround

We can work around this issue using setsid, like this:

# setsid virsh list &
[1] 247618
 Id   Name       State
--------------------------
 2    docker     running
 3    test       running

[1]+  Done                    setsid /usr/bin/virsh list

This works because the virPolkitAgentAvailable function in virsh checks whether the process has a controlling terminal. setsid starts virsh without a controlling terminal, so pkttyagent is not started.

We can even create a wrapper so that virsh is always started in this way:

sudo tee /usr/local/bin/virsh <<'EOF'
#!/bin/bash
setsid --wait /usr/bin/virsh "$@"
EOF
sudo chmod +x /usr/local/bin/virsh
JoelC
  • 1