是否有一种优雅的方法可以使用 ansible 通过 UUID 设置给定挂载点的挂载选项?
我想要完成的是像这样的 fstab 条目:
UUID=d5e3a2e2-a113-4a27-b8d7-801dbf4c6134 / ext4 errors=remount-ro,noatime,user_xattr,acl 0 1
所以基本上我想告诉 ansible:“为 / 上的设备设置这些选项。”src
但是安装模块是当前状态所必需的,我想使用 UUID 作为源。
我当前的解决方案作为答案发布在下面,但它将循环遍历所有现有挂载并检查路径是否存在/
,因此会产生大量skipping
输出。
我目前正在做的事情是:
- name: "mount options for /"
mount:
path: "/"
src: "UUID={{ item.uuid }}"
fstype: "ext4"
opts: "errors=remount-ro,noatime,user_xattr,acl"
state: "present"
with_items:
- "{{ ansible_mounts }}"
when: "item.mount == '/'"
这符合我的意图,但它检查全部主机的挂载点,因此产生很多skipping
输出:
TASK [node : mount options for /] ************************************************************************************************************************
ok: [node001] => (item={u'uuid': u'N/A', u'size_total': 291684016128, u'mount': u'/', u'size_available': 215996313600, u'fstype': u'ext4', u'device': u'/dev/sda2', u'options': u'rw,noatime,nodiratime,errors=remount-ro,user_xattr,acl'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 527433728, u'mount': u'/boot/efi', u'size_available': 523894784, u'fstype': u'vfat', u'device': u'/dev/sda1', u'options': u'rw'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 10908480831488, u'mount': u'/scr', u'size_available': 2431928762368, u'fstype': u'nfs4', u'device': u'192.168.31.3:/scratch', u'options': u'rw,vers=4,sec=sys,addr=192.168.31.3,clientaddr=192.168.31.41,_netdev'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 10908480831488, u'mount': u'/homes', u'size_available': 2431928762368, u'fstype': u'nfs4', u'device': u'192.168.31.3:/u', u'options': u'rw,vers=4,sec=sys,addr=192.168.31.3,clientaddr=192.168.31.41,_netdev'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 48378511622144, u'mount': u'/mnt/bigdata3', u'size_available': 5786707165184, u'fstype': u'nfs', u'device': u'192.168.31.1:/DATA3/bigdata3', u'options': u'ro,noatime,vers=3,addr=192.168.31.1,_netdev'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 48378511622144, u'mount': u'/mnt/bigdata4', u'size_available': 18173101342720, u'fstype': u'nfs', u'device': u'192.168.31.1:/DATA4/bigdata4', u'options': u'ro,noatime,vers=3,addr=192.168.31.1,_netdev'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 38764865912832, u'mount': u'/mnt/groupdata2', u'size_available': 7847016398848, u'fstype': u'nfs', u'device': u'192.168.31.1:/DATA2/groupdata2', u'options': u'rw,noatime,vers=3,addr=192.168.31.1,_netdev'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 14776486854656, u'mount': u'/mnt/bigdata1', u'size_available': 3801819906048, u'fstype': u'nfs', u'device': u'192.168.31.1:/DATA1/bigdata1', u'options': u'ro,noatime,vers=3,addr=192.168.31.1,_netdev'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 23931377418240, u'mount': u'/mnt/groupdata', u'size_available': 3801819906048, u'fstype': u'nfs', u'device': u'192.168.31.1:/DATA1/groupdata', u'options': u'rw,noatime,vers=3,addr=192.168.31.1,_netdev'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 12593077944320, u'mount': u'/mnt/transfer', u'size_available': 8260916609024, u'fstype': u'nfs', u'device': u'nas:/DATA5/transfer', u'options': u'ro,noatime,vers=4.1,acl,addr=192.168.31.2,clientaddr=192.168.31.41,_netdev'})
skipping: [node001] => (item={u'uuid': u'N/A', u'size_total': 40888277401600, u'mount': u'/mnt/transfer2', u'size_available': 25068068405248, u'fstype': u'nfs', u'device': u'nas:/DATA5/transfer2', u'options': u'ro,noatime,vers=4.1,acl,addr=192.168.31.2,clientaddr=192.168.31.41,_netdev'})
我认为这很丑陋,我想知道是否有更好的方法来做到这一点。
编辑
我找到了过滤器json_query
它应该能够完成我想要的工作。但是我无法让它工作。
在他们的示例网站我尝试了这个数据结构(复制自ansible_facts
):
{
"ansible_mounts": [
{
"device": "/dev/sda2",
"fstype": "ext4",
"mount": "/",
"options": "rw,noatime,nodiratime,errors=remount-ro,user_xattr,acl",
"size_available": 215995777024,
"size_total": 291684016128,
"uuid": "N/A"
},
{
"device": "/dev/sda1",
"fstype": "vfat",
"mount": "/boot/efi",
"options": "rw",
"size_available": 523894784,
"size_total": 527433728,
"uuid": "N/A"
}
]
}
使用以下查询:
ansible_mounts[?mount == `/`]
并得到了期望的输出:
[
{
"device": "/dev/sda2",
"fstype": "ext4",
"mount": "/",
"options": "rw,noatime,nodiratime,errors=remount-ro,user_xattr,acl",
"size_available": 215995777024,
"size_total": 291684016128,
"uuid": "N/A"
}
]
因此我在剧本中尝试了这个:
src: "UUID={{ item.uuid }}"
with_items:
- "{{ ansible_mounts|json_query('ansible_mounts[?mount == `/`]') }}"
但失败并显示以下消息:
The error was: 'ansible.vars.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'uuid'
答案1
我设法得到了我想要的东西json_query
筛选:
- name: "mount options for /"
mount:
path: "/"
src: "UUID={{ ansible_mounts | json_query('[?mount == `/`] | [0].uuid') }}"
fstype: "ext4"
opts: "errors=remount-ro,noatime,user_xattr,acl"
state: "present"
您将需要安装该软件包python-jmespath
。
答案2
Ansible 的输出是预期的。您指示 Ansible 循环遍历 中列出的挂载ansible_mounts
。我看到的唯一选项是grep
根设备的 UUID 并注册输出。类似这样的操作应该可以解决问题:
- name: Get root device UUID.
shell: cat /etc/fstab | grep "/\s" | cut -f1 | cut -d = -f2
register: root_uuid
- debug:
msg: "{{ root_uuid.stdout }}"
- name: "mount options for /"
mount:
path: "/"
src: "{{ root_uuid }}"
fstype: "ext4"
opts: "errors=remount-ro,noatime,user_xattr,acl"
state: "present"
但这种尝试可能不稳定,并且为了减少 Ansible 的输出噪音,我不建议这样做。
答案3
- name: add nodev mount option for all LVM mounts exept root part
mount:
name: '{{ item.mount }}'
src: '{{ item.device }}' # UUID not needed when LVM
state: mounted
fstype: '{{ item.fstype }}'
opts: "{{ item.options |regex_replace(',nodev','') }},nodev" # Fix duplicate
when: item.options.find("nodev") != -1 and item.device.find("mapper") != -1 and not item.mount in [ "/" ]
with_items: '{{ ansible_mounts }}'
- name: add nodev mount option for all non-LVM mounts exept root part
mount:
name: '{{ item.mount }}'
src: 'UUID={{ item.uuid }}'
state: mounted
fstype: '{{ item.fstype }}'
opts: "{{ item.options |regex_replace(',nodev','') }},nodev" # Fix duplicate
when: item.options.find("nodev") != -1 and item.device.find("mapper") == -1 and not item.mount in [ "/" ]
with_items: '{{ ansible_mounts }}'
答案4
您可以使用“选择属性”过滤器,这样您就只得到您想要看到的内容。为了清楚起见,我仅使用调试语句来显示输出。
- name: Check mount
debug:
msg:
- item mount is {{ item.mount }}
- item size_available is {{ item.size_available }}
with_items: "{{ ansible_mounts|selectattr('mount', 'equalto', '/boot') }}"
when: item.mount in [ "/boot" ]
输出
TASK [Check mount] ****************************************************************************************************************************************
ok: [myserver] => (item={'mount': '/boot', 'device': '/dev/sda1', 'fstype': 'xfs', 'options': 'rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota', 'size_total': 1063256064, 'size_available': 729972736, 'block_size': 4096, 'block_total': 259584, 'block_available': 178216, 'block_used': 81368, 'inode_total': 524288, 'inode_available': 523922, 'inode_used': 366, 'uuid': '6e01d6a0-9357-4d8e-be41-51cc8fa5965b'}) => {
"msg": [
"item mount is /boot",
"item size_available is 729972736"
]
}