Ansible is it possible to use variable in template src

ansibleansible-playbook

In ansible we are trying to access different templates based on variable.

We have following template files like:

templates
    app1.conf.j2
    app2.conf.j2
    app3.conf.j2

taks
    app.yml

In tasks we need to copy template file based on the app name. for eg: we will specify a variable named "instance_name" to either app1 or app2 or app3.

Now based on the variable we need to copy the app file to /opt/(( instance_name }}/conf.d/.

we created ansbile task as follows but its not working.

- name: 'Copy {{ instance_name }} file to /opt/conf.d/ Directory'
    template:
      src: "{{ instance_name }}.conf.j2"
      dest: "/opt/{{ instance_name }}/conf.d/"
      owner: root
      group: root
      mode: 0644

     

When we hard code "src" to app1.conf.j2 its working for app1.

From this url https://docs.ansible.com/ansible/latest/modules/template_module.html#parameter-src it specifies value can be a relative or an absolute path.

Please let us know is it possible with this method? We are having around 20 apps and whats the best method to simplify the ansible playbook to specify only the variable.

Best Answer

There are no best practices, only opinions on how elegant a solution is for a particular problem. Especially true for Ansible, given the flexibility in how it allows you to do things how you want.


Roles are great. Could make a role per app group, and each contains config templates it needs, such as roles/app1/templates/app1.conf.j2 Possibly it has multiple tasks and templates, say if the app starts some process via the service manager, ensures host firewall allows it, and also hooks things up via some service mesh.

app1's defaults/main.yml might contain

instance_name: app1

Which can then get used by tasks/main.yml (some parameters omitted for brevity, perhaps they were moved to module defaults on a block.)

- name: 'Copy config to /opt/conf.d/'
    template:
      src: "{{ instance_name }}.conf.j2"
      dest: "/opt/{{ instance_name }}/conf.d/"

If this all were in one tree alongside your playbook (not required, roles in particular could be stored elsewhere), it might look like the content organization example in the documentation:

playbook.yml
roles/
  app1/
    tasks/
      main.yml
    templates/
      app1.conf.j2
  app2/
    tasks/
      main.yml
    templates/
      app2.conf.j2 

And the playbook then just needs to list them:

roles:
- app1
- app2

Implementation of such roles can be repetitive as every role needs to do the same thing. If roles only differ by a couple variables, make a generic role and call it multiple times with different role parameters.

roles:
- role: appgeneric
  vars:
    instance_name: app1 
- role: appgeneric
  vars:
    instance_name: app2

Variables for module parameters is great, the answer to your question is yes. However, variable task names doesn't really work. Task names are global and parsed early, so maybe --extra-vars cli arguments but not say a loop iteration or a host specific variable.

So what to do if you have a generic named role and a generic named task going through 20 app deploys? Errors should be informative, if template cannot load a file it will tell you which file name. Increasing verbosity a bit with ansible-playbook -vv helps understand what's going on, but is messy and verbose. Consider playbook logging software on top of Ansible, like ARA or AWX/Tower. Reports those have showing which execution loaded which variables can provide context.

Related Topic