如何在Ansible中识别目录是否被NFS挂载?

3
我需要为一个“毛茸茸”的应用程序设置一个应用目录。根据情况,该目录可能是每个参与的服务器本地的,或者通过NFS在多个服务器之间共享。
因此,我需要能够检测给定路径是本地还是NFS访问,并在后一种情况下跳过某些任务。
在Ansible角色中,最好的方法是什么?
我尝试使用stat模块,但device_type似乎在所有情况下都设置为0,包括NFS或本地(XFS)。
在Linux上,我可以调用stat -f /path--这将输出详细信息,包括类型(实用程序使用statfs系统调用)。但这是一种仅适用于Linux的方法,我宁愿避免这种微小的OS依赖性(对于mountpoint实用程序也是如此)。
我可以编写自定义库函数,但Python中没有os.statfs...
还剩下什么?

最近的Ansible版本也可以执行二进制模块。使用C或Go编写一个小型静态编译模块。 - Konstantin Suvorov
这甚至更依赖于操作系统...我需要为每个目标操作系统/版本/架构编写可执行文件 :( Ansible是否足够聪明,可以在不同的库/子目录中查找这些可执行文件? - Mikhail T.
在这里被排除掉的那些过于平台特定的解决方案,实际上对我起了作用!如果有人想尝试它们,我在这里发布了我的生产Ansible代码:https://stackoverflow.com/a/49615669/1268949 - Isac Casapu
2个回答

2
另一个方法可以利用Ansible事实。您可以过滤ansible_mounts数组以获取mount=<您的挂载点>并提取文件系统类型字段。有关示例,请参见我在此处收到的答案:https://stackoverflow.com/a/49662135/1268949
我的生产代码中的另一个示例:
- name: Determine shared-dir mount point
command: "/usr/bin/env stat -c '%m' {{ shared_dir_real_path }}"
register: shared_dir_mount_point
changed_when: False

- name: Determine the mount point's filesystem type and mount options
set_fact:
    "shared_dir_mount_{{ item }}": "{{ ansible_mounts | selectattr('mount', 'equalto', shared_dir_mount_point.stdout) | map(attribute = item) | join(',') }}"
with_items:
    - fstype
    - options

1
如果您的目标平台上可用GNU stat实用程序,则可以以不使用statfs调用的方式调用它来检测挂载点,然后在mount输出中搜索它,例如在Linux上:
$ mount | grep -F `stat -c %m /boot/grub` | cut -d' ' -f5
ext2

我核实了这个调用stat只使用了标准的系统调用(请参见stat(2)的man页面中的CONFORMING TO部分):
$ strace stat -c %m /boot/grub/ |& fgrep stat
execve("/usr/bin/stat", ["stat", "-c", "%m", "/boot/grub/"], [/* 65 vars */]) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=218501, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=130224, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=1868984, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=456632, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=14608, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=138696, ...}) = 0
statfs("/sys/fs/selinux", 0x7ffe62882ff0) = -1 ENOENT (No such file or directory)
statfs("/selinux", 0x7ffe62882ff0)      = -1 ENOENT (No such file or directory)
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=5152256, ...}) = 0
lstat("/boot/grub/", {st_mode=S_IFDIR|0755, st_size=1024, ...}) = 0
lstat("/boot", {st_mode=S_IFDIR|0755, st_size=3072, ...}) = 0
lstat("/boot/grub", {st_mode=S_IFDIR|0755, st_size=1024, ...}) = 0
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
stat("/boot/grub", {st_mode=S_IFDIR|0755, st_size=1024, ...}) = 0
stat("..", {st_mode=S_IFDIR|0755, st_size=3072, ...}) = 0
stat("..", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/boot", {st_mode=S_IFDIR|0755, st_size=3072, ...}) = 0
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0

谢谢,但这仍然只适用于Linux。在BSD上,例如,stat命令有所不同。而且mount命令的输出也不同 :( - Mikhail T.
GNU coreutils能在BSD上使用吗?似乎许多GNU实用程序都有适用于基于BSD的OS/X的端口,例如通过brew等。如果情况恶化,您始终可以拥有多个版本的步骤来确定这一点,并根据适当的“when”条件运行正确的步骤。 - Isac Casapu
1
在FreeBSD上,它们是可用的,但stat可执行文件安装为gnustat。这可能有效。可以使用stat -f --format=%T /path/of/interest而不是解析其输出并依赖于挂载的输出格式。我想,那就是我会做的...请更新您的答案,以便我可以“接受”它。 - Mikhail T.
%T 表示“十六进制的小型设备类型”,所以请确保您在这里依赖于文档化的接口... - Isac Casapu
1
不,当使用“-f”标志启动文件系统时,“%T”表示“以人类可读形式显示的文件系统类型”。 - Mikhail T.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接