简体   繁体   中英

SubString in Ansible and/or Jinja2

I'm trying to unmout all mountpoints, excepted if they are part of the current list:

excluded: ['home', 'cdrom', 'tmpfs', 'sys', 'run', 'dev', 'root']

Sample fstab only devices:

  • /dev/mapper/vgroot-local_home
  • devtmpfs
  • tmpfs

/dev/mapper/vgroot-local_home should be excluded from unmounting because the substring home is present on the array and the same for devtmpfs substring tmpfs . For tmpfs we have a perfect match. The goal is to check against devices.

After checking all Ansible filters and the Jinja2 documentation , I didn't find a solution to this problem. All Ansible facts are collected.

- name: Ensure the mountpoint is on the excluded list
  ansible.posix.mount:
    path: '{{ mount.device }}'
    state: unmounted
  when: {{ ??? }}
  with_items: '{{ ??? }}'
  become: true
  tags: mountpoints

To test if a string contains a substring in Jinja, we use the in test, much like Python:

"somestring" in somevariable

In your case, you want to check if a given string contains any substring from the excluded list. Conceptually, what we want is something like the Python expression

if any(x in mount.device for x in excluded)

Using Jinja filters, we need to reverse our logic a little bit. We can use the select filter to get a list of strings from the excluded list that are contained in a given target string (such as mount.device ) like this:

excluded|select('in', item)

If item matches anything in the excluded list, the above expression will result in a non-empty list (which evaluates to true when used in a boolean context).

Used in a playbook, it would look like this:

- hosts: localhost
  gather_facts: false
  vars:
    excluded: ['home', 'cdrom', 'tmpfs', 'sys', 'run', 'dev', 'root']
    mounts:
      - /dev/mapper/vgroot-local_home
      - devtmpfs
      - tmpfs
      - something/else
  tasks:
    - debug:
        msg: "unmount {{ item }}"
      when: not excluded|select('in', item)
      loop: "{{ mounts }}"

The above playbook produces as output:

TASK [debug] *******************************************************************
skipping: [localhost] => (item=/dev/mapper/vgroot-local_home) 
skipping: [localhost] => (item=devtmpfs) 
skipping: [localhost] => (item=tmpfs) 
ok: [localhost] => (item=something/else) => {
    "msg": "unmount something/else"
}

That is, it skips the task when the current loop item contains a substring from the excluded list.

Assuming that your goal is "unmount all filesystems except those for which the device name contains a substring from the excluded list", you might write:

- name: Unmount filesystems that aren't excluded
  ansible.posix.mount:
    path: '{{ mount.device }}'
    state: unmounted
  when: not excluded|select('in', item.device)
  loop: "{{ ansible_mounts }}"
  become: true
  tags: mountpoints

Iterate basename if you don't want to exclude the items of mounts because of matching the path, eg if you don't want to exclude /dev/mapper/vgroot-local_home because of dev in the excluded list

    - debug:
        msg: "Unmount {{ item }}"
      loop: "{{ mounts|map('basename') }}"
      when: not excluded|select('in', item)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM