Ansible iteruje słownik z listami

15

Mam następującą zmienną załadowaną przez include_vars:

access:
    username-foo:
      - path: /
        permissions: rwX
        recursive: true

    username-bar:
      - path: /
        permissions: rX

      - path: /css
        permissions: rwX
        recursive: true

      - path: /data
        permissions: rX

      - path: /data/reviews.yml
        permissions: rw

      - path: /js
        permissions: rX

      - path: /js/*.js
        permissions: rw

Chcę podać te informacje do shellpolecenia, aby ustawić odpowiednie uprawnienia.

Próbowałem stąd kilku technik: http://docs.ansible.com/playbooks_loops.html, ale nie udało mi się znaleźć działającego rozwiązania.

Czy można iterować tę strukturę? Jeśli nie, to jak mam go przebudować, aby działał? Czy można to zrobić bez naruszenia reguły DRY (np. Dołącz nazwę użytkownika do każdego rekordu)?

Slava Fomin II
źródło

Odpowiedzi:

21

Po pierwsze, możesz rozważyć użycie filemodułu zamiast shell. Jest mniej podatny na awarie i pozornie idempotentny. Może to jednak powodować problemy z mieszaniem katalogów, plików i globów plików. YMMV.

Jeśli chodzi o sedno pytania, ustawiłbym twoje zmienne w następujący sposób:

users:
  - username: bar
    directories:
      - path: /data
        permissions: rX
      - path: /js
        permissions: rX
  - username: foo
    directories:
      - path: /
        permissions: rwX

Sztuka wyglądałaby następująco:

- name: Change mod/own
  shell: chown {{ item.0.username }} {{ item.1.path }};chmod u+{{ item.1.permissions }} {{ item.1.path }
  with_subelements:
    - users
    - directories
Christopher Karel
źródło
Świetny pomysł! Dzięki! Działa jak marzenie. BTW Korzystam z shellmodułu, ponieważ muszę wykonywać rekurencyjną listę ACL, która nie jest obsługiwana przez aclmoduł.
Slava Fomin II
Solidna logika. Wygląda na shellto, że jest to najlepszy zakład z listami ACL i rekurencją.
Christopher Karel
BTW, czy można zignorować brakujący klucz skrótu, jak recursivew moim przykładzie? Kiedy próbuję uzyskać do niego dostęp i brakuje go, Ansible przerwie wykonywanie podręcznika i wyrzuci wyjątek. Wolę nie dodawać recursive: falsedo każdego rekordu.
Slava Fomin II
1
Myślę, że składnia domyślna powinno działać: {{ some_variable | default() }}. Tak więc w tym przypadku: {{ item.1.recursive | default(false) }}
Christopher Karel
Jak zmieniłoby się zadanie, gdyby klawisz „katalogów” był tylko listą, a nie słownikiem?
Chris F
7

To dobry przykład wyjścia, którego możesz spróbować sam. Utwórz nowy podręcznik o nazwie iteration_loop.yml:

---

- name: Change mod/own
  hosts: all
  tasks:
  - name: show me the iterations
    debug: msg={{ item.0.username }} {{ item.1.path }} then {{ item.1.permissions }} {{ item.1.path }}
    with_subelements:
      - users
      - directories
  vars:
    users:
      - username: bar
        directories:
          - path: /data
            permissions: rX
          - path: /js
            permissions: rX
      - username: foo
        directories:
          - path: /
            permissions: rwX

Następnie uruchom podręcznik w następujący sposób: ansible-playbook -i '172.16.222.131,' iteration_loop.yml

a wynik powinien dać ci dostęp do elementów:

PLAY [Change mod/own] ********************************************************* 

GATHERING FACTS *************************************************************** 
ok: [172.16.222.131]

TASK: [show me the iterations] ************************************************ 
ok: [172.16.222.131] => (item=({'username': 'bar'}, {'path': '/data', 'permissions': 'rX'})) => {
    "item": [
        {
            "username": "bar"
        }, 
        {
            "path": "/data", 
            "permissions": "rX"
        }
    ], 
    "msg": "bar"
}
ok: [172.16.222.131] => (item=({'username': 'bar'}, {'path': '/js', 'permissions': 'rX'})) => {
    "item": [
        {
            "username": "bar"
        }, 
        {
            "path": "/js", 
            "permissions": "rX"
        }
    ], 
    "msg": "bar"
}
ok: [172.16.222.131] => (item=({'username': 'foo'}, {'path': '/', 'permissions': 'rwX'})) => {
    "item": [
        {
            "username": "foo"
        }, 
        {
            "path": "/", 
            "permissions": "rwX"
        }
    ], 
    "msg": "foo"
}

PLAY RECAP ******************************************************************** 
172.16.222.131             : ok=2    changed=0    unreachable=0    failed=0   
Egidijus
źródło
1

Zakładając, że dict={a:[1,2,3],b:[1,2]}i tak dalej:

- name: Flattened list
  set_fact:
    flattened: "{{ dict.values() | sum(start=[]) }}"

Teraz flattened == [1,2,3,1,2]

Max Murphy
źródło
0

Ponownie sformatuję twoje zmienne do poniższego formatu:

access:
- username: foo
  directories:
    - path: /
      permissions: rwX
      recursive: true

- username: bar
  directories:
    - path: /
      permissions: rX
      recursive: false

    - path: /css
      permissions: rwX
      recursive: true

    - path: /data
      permissions: rX
      recursive: false

    - path: /data/reviews.yml
      permissions: rw
      recursive: false

    - path: /js
      permissions: rX
      recursive: false

    - path: /js/*.js
      permissions: rw
      recursive: false

a następnie mój poradnik, jak poniżej:

tasks:
- name: Iterate the vars inside var4 when recursive
  debug: msg="username is {{ item.0.username }} and path is {{ item.1.path }} permission is {{ item.1.permissions }} and recursive"
  when: item.1.recursive
  ignore_errors: true
  with_subelements:
    - "{{ access }}"
    - directories
- name: Iterate the vars inside var4 when no recursive
  debug: msg="username is {{ item.0.username }} and path is {{ item.1.path }} permission is {{ item.1.permissions }}"
  when: not item.1.recursive
  ignore_errors: true
  with_subelements:
    - "{{ access }}"
    - directories
użytkownik42826
źródło