我有一个作为 cronjob 运行的 bash 脚本。此脚本运行多个命令,其中一个是以下 virsh 命令:
/usr/bin/virsh list --all
当我在终端(作为 root)或作为 cronjob(也作为 root)运行此脚本时,virsh 命令按预期工作并列出所有虚拟机。
在测试和调试此脚本的过程中,我注意到,如果我将脚本发送到后台,或者将其发送到后台然后放弃它,则脚本会无限期地挂起在 virsh 命令上。下面我提供了更多详细信息。
为了说明这个问题,我们假设一个简单的脚本“test.bash”:
[root@kvm-host]# cat test.bash
#!/bin/bash
/usr/bin/virsh list --all
当我在前台运行脚本 test.bash 时,它按预期工作:
[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
当我在后台运行脚本 test.bash 时,它会无限期地挂起在 virsh 命令上:
[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
如果我将脚本发送到后台并放弃它,脚本也会挂在 virsh 命令上:
[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
我尝试使用以下命令运行 virsh-c qemu:///系统当我将脚本 test.bash 发送到后台时,行为也是一样的。如上所示,我也尝试过在不使用“bash -x”的情况下运行脚本。我还尝试过将 stderr 和 stdout 重定向到 /dev/null 来运行脚本。最后,我还尝试过在不将 stderr 或 stdout 重定向到任何文件的情况下运行脚本。在所有这些情况下,问题都是一样的。
是否可以按照描述在后台运行 virsh 命令?任何评论都将不胜感激。谢谢!
以下是有关我的系统的一些详细信息:
[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
答案1
我猜测这是由于 pkttyagent 引起的。
此示例显示了进程如何在后台挂起:
# 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
如果该进程再次被放到前台,它将完成:
# fg
virsh list
Id Name State
--------------------------
2 docker running
3 test running
#
我发现以下未解决的问题:https://bugzilla.redhat.com/show_bug.cgi?id=1726714,描述了这种情况是由于信号 SIGTTOU 而发生的。此信号的描述可在此处找到:https://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html
答案2
此问题自 libvirt 版本 7.10 开始出现。具体来说,自这次提交这会改变检查,以便pkttyagent
即使没有 TTY 也可以运行。另请参阅libvirt 问题。
解决方法
我们可以使用 来解决这个问题setsid
,如下所示:
# setsid virsh list &
[1] 247618
Id Name State
--------------------------
2 docker running
3 test running
[1]+ Done setsid /usr/bin/virsh list
这是有效的,因为virPolkitAgentAvailable
中的函数virsh
检查进程是否具有控制终端。如果setsid
启动virsh
时没有控制终端,则pkttyagent
无法启动。
我们甚至可以创建一个包装器,以便virsh
始终以这种方式启动:
sudo tee /usr/local/bin/virsh <<'EOF'
#!/bin/bash
setsid --wait /usr/bin/virsh "$@"
EOF
sudo chmod +x /usr/local/bin/virsh
答案3
这个问题之所以复杂是有原因的,但应该妥善处理。我在这里发布了修复方法:
https://gitlab.freedesktop.org/polkit/polkit/-/merge_requests/139