解决方法

解决方法

我有一个作为 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

相关内容