Ansible itera un diccionario con listas

15

Tengo la siguiente variable cargada a través de 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

Quiero alimentar esta información al shellcomando para establecer los permisos apropiados.

He probado algunas técnicas desde aquí: http://docs.ansible.com/playbooks_loops.html pero no pude encontrar una solución que funcione.

¿Es posible iterar esta estructura? Si no es así, ¿cómo lo reestructuro para que funcione? ¿Es posible hacer esto sin romper la regla DRY (por ejemplo, incluir el nombre de usuario en cada registro)?

Slava Fomin II
fuente

Respuestas:

21

En primer lugar, es posible que desee considerar el uso del filemódulo , en lugar de hacerlo shell. Es menos propenso a fallas, y aparentemente idempotente. Sin embargo, eso podría darle algunos problemas al mezclar directorios, archivos y archivos globales. YMMV.

En cuanto al meollo de la pregunta, configuraría sus variables de la siguiente manera:

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

La obra se vería así:

- 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
fuente
¡Gran idea! ¡Gracias! Funciona de maravilla. Por cierto, estoy usando el shellmódulo porque necesito hacer ACL recursiva y eso no es compatible con el aclmódulo.
Slava Fomin II
Lógica sólida Parece que shelles su mejor apuesta con ACL y recursividad.
Christopher Karel
Por cierto, ¿es posible ignorar la clave hash que falta como recursiveen mi ejemplo? Cuando trato de acceder y falta, Ansible detendrá la ejecución del libro de jugadas y lanzará una excepción. Prefiero no agregar recursive: falsea todos los registros.
Slava Fomin II
1
Creo que la sintaxis por defecto debería funcionar: {{ some_variable | default() }}. Entonces, en este caso: {{ item.1.recursive | default(false) }}
Christopher Karel
¿Cómo cambiaría la tarea si la clave "directorios" es solo una lista en lugar de un diccionario también?
Chris F
7

Este es un buen ejemplo de salida que puede probar usted mismo. Crea un nuevo libro de jugadas llamado 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

Luego ejecute el libro de jugadas de esta manera: ansible-playbook -i '172.16.222.131,' iteration_loop.yml

y la salida debería darle cómo se accede a los elementos:

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
fuente
1

Asumiendo eso dict={a:[1,2,3],b:[1,2]}y así sucesivamente:

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

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

Max Murphy
fuente
0

Reformatearé sus vars al siguiente formato:

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

y luego mi libro de jugadas como a continuación:

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
usuario42826
fuente