axil
axil

Reputation: 797

Ansible create directories from a list

I want to create some directories from a list I have in my vars/main.yml.

- app_root:
    network_prod:   "/var/www/prod/network/app"
    database_prod:  "/var/www/prod/db/app"

My tasks/main.yml so far has this:

- name: Create application directory structure
  file: 
    path: "{{ item }}"
    state: directory
    mode: 755
  with_items:
    - app_root

but doesn't work. I thought this could be achieved using with_dict and I also tried:

- name: Create application directory structure
  file: 
    path: "{{ item.value }}"
    state: directory
    mode: 755
  with_dict:
    - app_root

but I got: fatal: [vagrant.dev] => with_dict expects a dict.

I've read all about looping-over-hashes, but this doesn't seem to work.

The reason I'm using this notation is because I use these variables elsewhere as well and I need to know how to call them.

Upvotes: 4

Views: 7625

Answers (3)

olluch
olluch

Reputation: 416

I think that the approach with with_dict was correct and I believe that the only issue here is the dash - in front of app_root variable. Instead of:

- name: Create application directory structure
  file: 
    path: "{{ item.value }}"
    state: directory
    mode: 755
  with_dict:
    - app_root

It should be:

- name: Create application directory structure
  file: 
    path: "{{ item.value }}"
    state: directory
    mode: 755
  with_dict: app_root

See the difference on the way the variable app_root is passed to with_dict.

A dash in YAML starts a list and the elements are not treated as variables but as literals, think of it as if you were passing an immutable string 'app_root' to with_dict (not exactly true but it helps me to think it this way) so when_dict fails to parse it because it is given a list instead of the expected dictionary. However, without a dash, with_dict is populated with the variable app_root instead and it will parse it without issues.

Upvotes: 0

jbgo
jbgo

Reputation: 103

In vars/main.yml, try removing the dash in front of app_root.

app_root:
  network_prod:   "/var/www/prod/network/app"
  database_prod:  "/var/www/prod/db/app"

Upvotes: 0

Bruce P
Bruce P

Reputation: 20719

I personally find it a bit easier to convert yaml to json to make sure I'm understanding it properly. Take your example:

- app_root:
    network_prod:   "/var/www/prod/network/app"
    database_prod:  "/var/www/prod/db/app"

What you have here is not a list, but a nested dictionary. If you converted this to json it would look like this:

[
  {
    "app_root": {
      "network_prod": "/var/www/prod/network/app",
      "database_prod": "/var/www/prod/db/app"
    }
  }
]

In order to loop through this in Ansible you would need to dereference two levels of a dictionary, the first being app_root and the second being the path elements. Unfortunately I don't think Ansible supports looping through nested dictionaries, only through nested loops.

Your best bet is probably to redo the way you're defining your paths so that you're not creating as complex a data structure. If all you're doing in this case is iterating over a list of paths in order to ensure the directories exist then I'd suggest something like this in your vars/main.yml file:

network_prod:   "/var/www/prod/network/app"
database_prod:  "/var/www/prod/db/app"

app_root:
  - network_prod
  - database_prod

Then you can have a task like this:

file: path={{ item }}
      state=directory 
with_items: app_root

Upvotes: 1

Related Questions