Comment utiliser le module de modèle avec différents ensembles de variables?

92

Mon cas d'utilisation est le suivant:

J'ai un fichier de modèle et je voudrais créer 2 fichiers différents à partir de ce modèle, les variables étant remplies par un ensemble différent de variables pour chaque fichier.

Par exemple, disons que je veux modéliser le fichier contenant la ligne:

mkdir -p {{myTemplateVariable}}

Je voudrais trouver une manière appropriée de remplir cette variable par "File1" et "File2". Quelque chose comme :

- name: template test 1
  template: 
        src=myTemplateFile
        dest=result1


- name: template test 2
  template: 
        src=myTemplateFile
        dest=result2

où je pourrais spécifier pour le premier modèle que la variable à utiliser est a = "File1" et pour le second, b = "File2".

Kestemont Max
la source
Est-ce exactement ce que je fais avec toutes mes recettes, regardez ce commentaire stackoverflow.com/a/40189525/1571310 , espérons cette aide!
Tecnocat

Réponses:

51

Pour Ansible 2.x:

- name: template test
  template: 
    src: myTemplateFile
    dest: result1
  vars:
    myTemplateVariable: File1

- name: template test
  template: 
    src: myTemplateFile
    dest: result2
  vars:
    myTemplateVariable: File2

Pour Ansible 1.x:

Malheureusement, le templatemodule ne prend pas en charge le passage de variables qui peuvent être utilisées dans le modèle. Il y a eu une demande de fonctionnalité, mais elle a été rejetée.

Je peux penser à deux solutions de contournement:

1. Inclure

L' includeinstruction prend en charge le passage de variables. Ainsi, vous pouvez avoir votre templatetâche dans un fichier supplémentaire et l'inclure deux fois avec les paramètres appropriés:

my_include.yml:

- name: template test
  template: 
        src=myTemplateFile
        dest=destination

main.yml:

- include: my_include.yml destination=result1 myTemplateVariable=File1

- include: my_include.yml destination=result2 myTemplateVariable=File2

2. Redéfinissez myTemplateVariable

Une autre façon serait de simplement redéfinir myTemplateVariable juste avant chaque templatetâche.

- set_fact:
     myTemplateVariable: File1

- name: template test 1
  template: 
        src=myTemplateFile
        dest=result1

- set_fact:
     myTemplateVariable: File2

- name: template test 2
  template: 
        src=myTemplateFile
        dest=result2
udondan
la source
Merci pour la réponse. Cependant, est-il vraiment impossible de se passer de solutions de contournement? J'essaye actuellement quelque chose comme: stackoverflow.com/questions/26020465/… , mais j'ai toujours des erreurs (peut-être pas directement liées).
Kestemont Max
Oui, vous pouvez également le faire avec une boucle - c'est toujours une solution de contournement. :)
udondan
14
n'est plus nécessaire. "vars" est désormais pris en charge. voir la réponse @ konstantin-suvorov ci-dessous.
sonjz
123

Avec Ansible 2.x, vous pouvez utiliser vars:avec des tâches.

Modèle test.j2:

mkdir -p {{myTemplateVariable}}

Playbook:

- template: src=test.j2 dest=/tmp/File1
  vars:
    myTemplateVariable: myDirName

- template: src=test.j2 dest=/tmp/File2
  vars:
    myTemplateVariable: myOtherDir

Cela passera différentes myTemplateVariablevaleurs dans test.j2.

Konstantin Suvorov
la source
9
Au départ, j'ai fait une erreur et j'ai eu vars: indenté comme le reste des arguments du modèle (comme src :). Je suppose que le niveau de retrait signifie vars: c'est de la tâche, pas du modèle. Vous pouvez donc le faire n'importe où, pas seulement des modèles. agréable.
Greg
37

Vous pouvez le faire très facilement, regardez ma recette de superviseur:

- name: Setup Supervisor jobs files
  template:
    src: job.conf.j2
    dest: "/etc/supervisor/conf.d/{{ item.job }}.conf"
    owner: root
    group: root
    force: yes
    mode: 0644
  with_items:
    - { job: bender, arguments: "-m 64", instances: 3 }
    - { job: mailer, arguments: "-m 1024", instances: 2 }
  notify: Ensure Supervisor is restarted

job.conf.j2:

[program:{{ item.job }}]
user=vagrant
command=/usr/share/nginx/vhosts/parclick.com/app/console rabbitmq:consumer {{ item.arguments }} {{ item.job }} -e prod
process_name=%(program_name)s_%(process_num)02d
numprocs={{ item.instances }}
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/{{ item.job }}.stderr.log
stdout_logfile=/var/log/supervisor/{{ item.job }}.stdout.log

Production:

TASK [Supervisor : Setup Supervisor jobs files] ********************************
changed: [loc.parclick.com] => (item={u'instances': 3, u'job': u'bender', u'arguments': u'-m 64'})
changed: [loc.parclick.com] => (item={u'instances': 2, u'job': u'mailer', u'arguments': u'-m 1024'})

Prendre plaisir!

Tecnocat
la source
Cela doit être marqué comme une bonne réponse. Depuis son support maintenant
PoX
23

C'est une solution / hack que j'utilise:

tâches / main.yml:

- name: parametrized template - a
  template:
    src: test.j2
    dest: /tmp/templateA
  with_items: var_a

- name: parametrized template - b
  template:
    src: test.j2
    dest: /tmp/templateB
  with_items: var_b

vars / main.yml

var_a:
  - 'this is var_a'
var_b:
  - 'this is var_b'

templates / test.j2:

{{ item }}

Après avoir exécuté ceci, vous obtenez this is var_adans / tmp / templateA et this is var_bdans / tmp / templateB.

Fondamentalement, vous abusez with_itemsde rendre le modèle avec chaque élément de la liste à un élément. Cela fonctionne car vous pouvez contrôler la liste lors de son utilisation with_items.

L'inconvénient est que vous devez utiliser itemcomme nom de variable dans votre modèle.

Si vous souhaitez passer plus d'une variable de cette façon, vous pouvez dicter les éléments de votre liste comme ceci:

var_a:
  -
    var_1: 'this is var_a1'
    var_2: 'this is var_a2'
var_b:
  -
    var_1: 'this is var_b1'
    var_2: 'this is var_b2'

puis faites-y référence dans votre modèle comme ceci:

{{ item.var_1 }}
{{ item.var_2 }}
asmigala
la source
1
Solution propre, mais chapeau à utiliserwith_items: '{{ var_a }}'
Peter Ajtai
8

Je l'ai fait de cette façon.

Dans tasks / main.yml

- name: template test
  template: 
        src=myTemplateFile.j2
        dest={{item}}
   with_dict: some_dict

et dans vars / main.yml

some_dict:
  /path/to/dest1:
    var1: 1
    var2: 2
  /path/to/dest2:
    var1: 3
    var2: 4

et dans templates / myTemplateFile.j2

some_var = {{ item.value.var1 }}
some_other_var = {{ item.value.var2 }}

J'espère que ceci résoudra votre problème.

Nabarun Chatterjee
la source
with_dictest la meilleure solution.
zx1986
1
- name: copy vhosts
  template: src=site-vhost.conf dest=/etc/apache2/sites-enabled/{{ item }}.conf
  with_items:
    - somehost.local
    - otherhost.local
  notify: restart apache

IMPORTANT: Notez qu'un élément ne doit pas être une simple chaîne, il peut s'agir d'un objet avec autant de propriétés que vous le souhaitez, de cette façon vous pouvez passer n'importe quel nombre de variables.

Dans le modèle j'ai:

<VirtualHost *:80>
    ServerAdmin [email protected]
    ServerName {{ item }}
    DocumentRoot /vagrant/public


    ErrorLog ${APACHE_LOG_DIR}/error-{{ item }}.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>
Bart McLeod
la source
1
Comment pourrais-je en faire un objet?
camdixon du
1

J'ai eu un problème similaire à résoudre, voici une solution simple de la façon de passer des variables aux fichiers modèles, l'astuce est d'écrire le fichier modèle en tirant parti de la variable. Vous devez créer un dictionnaire (une liste est également possible), qui contient l'ensemble des variables correspondant à chacun des fichiers. Ensuite, dans le fichier modèle, accédez-y.

voir ci-dessous:

the template file: test_file.j2
# {{ ansible_managed }} created by [email protected]

{% set dkey  = (item | splitext)[0]  %}
{% set fname = test_vars[dkey].name  %}
{% set fip   = test_vars[dkey].ip    %}
{% set fport = test_vars[dkey].port  %}
filename: {{ fname }}
ip address: {{ fip }}
port: {{ fport }}

le playbook

---
#
# file: template_test.yml
# author: [email protected]
#
# description: playbook to demonstrate passing variables to template files
#
# this playbook will create 3 files from a single template, with different
# variables passed for each of the invocation
#
# usage:
# ansible-playbook -i "localhost," template_test.yml

- name: template variables testing
  hosts: all
  gather_facts: false

  vars:
    ansible_connection: local
    dest_dir: "/tmp/ansible_template_test/"
    test_files:
      - file_01.txt
      - file_02.txt
      - file_03.txt
    test_vars:
      file_01:
        name: file_01.txt
        ip: 10.0.0.1
        port: 8001
      file_02:
        name: file_02.txt
        ip: 10.0.0.2
        port: 8002
      file_03:
        name: file_03.txt
        ip: 10.0.0.3
        port: 8003

  tasks:
    - name: copy the files
      template:
        src: test_file.j2
        dest: "{{ dest_dir }}/{{ item }}"
      with_items:
        - "{{ test_files }}"
xbalaji
la source
0

Un autre exemple du monde réel utilisant une liste

un extrait d'un modèle pour php.ini

{% if 'cli/php.ini' in item.d %}
max_execution_time = 0
memory_limit = 1024M
{% else %}
max_execution_time = 300
memory_limit = 512M
{% endif %}

C'est le var

php_templates:
  - { s: 'php.ini.j2', d: "/etc/php/{{php_version}}/apache2/php.ini" }
  - { s: 'php.ini.j2', d: "/etc/php/{{php_version}}/cli/php.ini" }

Puis je déploie avec ça

- name: push templated files
  template:
    src: "{{item.s}}"
    dest: "{{item.d}}"
    mode: "{{item.m | default(0644) }}"
    owner: "{{item.o | default('root') }}"
    group: "{{item.g | default('root') }}"
    backup: yes
  with_items: "{{php_templates}}"
krad
la source