Looping through a dictionary to create links

30 views
Skip to first unread message

Aaron Hicks

unread,
Jul 25, 2019, 11:37:07 PM7/25/19
to Ansible Project
Hello the list,

I have  a bunch of machines with some shared file systems. Some of the file systems are not mounted on all the machines. For the filesystems that are mounted, I'd like to check/create a bunch of symbolic links to those filesystems from various places in the filesystem. Some filesystems do not have links (yet) but we may do some other things with them later.

So given a YAML inventory file:

all:
  vars:
    filesystems:
      /sharedfs1:
        - source: /sharedfs1/filesets/home
          target: /home
        - source: /sharedfs1/filesets/foo
          target: /opt/foo
        - source: /sharedfs1/filesets/baa
          target: /opt/baa
        - source: /sharedfs1/filesets/lmod
          target: /opt/lmod
        - source: /scale_wlg_persistent/filesets/baz
          target: /quack/baz
     /sharedfs2:
        - source: /sharedfs2/filesets/scratch
          target: /quack/scratch
      /sharedfs3:
      /sharedfs4:
  children:
    hostlist:
      hosts:
        host1:
        host2:

And the following play, which checks the mount point exists

---
- name: Create links to filesets from shared filesystems
  hosts: all
  tasks:
    - name: Check filesystems are mounted
      stat:
        path: "{{ item.key }}"
      register: fsstat
      loop: "{{ filesystems|dict2items }}"

    - name: Which filesystem mount exists?
      debug:
        var: fsstat.stat.path
      when: item.0.stat.path == item.1.key
      loop: "{{ fsstat.results|product(filesystems|dict2items)|list }}"

Now what I want to do for each filesystem mount that exists, I'd like to create a link from source to target for each list of link hashes associated with each filesystem. Doing this in Python is almost trivial, but a massive pain in Ansible/Jinja2

Regards,

Aaron



Aaron Hicks

unread,
Jul 25, 2019, 11:44:27 PM7/25/19
to Ansible Project
The Python equivalent I'm trying to make is:

for sharedfs in filesystems:
    if os.path.exists(sharedfs):
        for link in filesystems[sharedfs]:
            os.symlink(link['source']. link['target'])

Aaron Hicks

unread,
Jul 28, 2019, 10:33:15 PM7/28/19
to Ansible Project
Well, I have a solution but it's very https://www.goodreads.com/quotes/7053458-but-i-am-very-poorly-today-very-stupid

I've had to restructure the inventory:

all:
  vars:
    filesystems:
      - path: /sharedfs1
        links:
          - src: /sharedfs1/filesets/home
            dest: /home
          - src: /sharedfs1/filesets/foo
            dest: /opt/foo
          - src: /sharedfs1/filesets/baa
            dest: /opt/baa
          - src: /sharedfs1/filesets/lmod
            dest: /opt/lmod
          - src: /sharedfs1/filesets/baz
            dest: /quack/baz
      - path: /sharedfs2
        links:
          - src: /sharedfs2/filesets/nobackup
            dest: /quack/nobackup
      - path: /sharefds3
      - path: /sharedfs4
  children:
    hostlist:
      hosts:
        host1:
        host2:

And then the playbook looks like, which does a bit more should/shouldn't testing than initially asked for

---
- name: Create links to filesets from GPFS filesystems
  hosts: all
  vars:
    ansible_become_user: root
    ansible_become_method: sudo
  tasks:
    - name: Check which Spectrum Scale filesystems are mounted
      stat:
        path: "{{ item.path }}"
      register: fsstat
      loop: "{{ filesystems }}"

    # It should be possible to remove this debug and use the filter directly
    - name: Which filesystem mount exists?
      debug:
        msg: "src: {{ item.0.1.src }} dest:{{ item.0.1.dest }}"
      register: linkslist
      when:
        - item.1.stat.exists
        - item.1.stat.path == item.0.0.path
      loop: "{{ filesystems|subelements('links', skip_missing=True)|product(fsstat.results)|list }}"

    - name: Stat filesystem link destinations
      stat:
        path: "{{ item.item.0.1.dest }}"
      become: true
      register: linksstat
      when:
        - item is not skipped
      loop: "{{ linkslist.results }}"

    - name: Remove link destintations (if not a link)
      file:
       path: "{{ item.stat.path }}"
       state: absent
      become: true
      when:
        - item is not skipped
        - item.stat.isdir is defined
        - item.stat.isdir
      loop: "{{ linksstat.results }}"

    - name: Check link destination parent directories
      file:
        path: "{{ item.item.0.1.dest | dirname }}"
        state: directory
      become: true
      when:
        - item is not skipped
        - item.item.0.1.dest | dirname is not match("/")
      loop: "{{ linkslist.results }}"

    - name: Create Scale filesystem links
      file:
        src: "{{ item.item.0.1.src }}"
        dest: "{{ item.item.0.1.dest }}"
        state: link
      become: true
      when:
        - item is not skipped
      loop: "{{ linkslist.results }}"

Reply all
Reply to author
Forward
0 new messages