Como usar o módulo de modelo com diferentes conjuntos de variáveis?

92

Meu caso de uso é o seguinte:

Eu tenho um arquivo de modelo e gostaria de criar 2 arquivos diferentes a partir desse modelo, com as variáveis ​​sendo preenchidas por um conjunto diferente de variáveis ​​para cada arquivo.

Por exemplo, digamos que eu queira modelar o arquivo que contém a linha:

mkdir -p {{myTemplateVariable}}

Gostaria de encontrar uma maneira adequada de preencher essa variável com "Arquivo1" e "Arquivo2". Algo como :

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


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

onde eu poderia especificar para o primeiro modelo que a variável a ser usada é a = "Arquivo1" e para o segundo, b = "Arquivo2".

Kestemont Max
fonte
É exatamente isso que faço com todas as minhas receitas, olha este comentário stackoverflow.com/a/40189525/1571310 , espero que ajude!
Tecnocat,

Respostas:

51

Para 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

Para Ansible 1.x:

Infelizmente, o templatemódulo não suporta a passagem de variáveis ​​para ele, que podem ser usadas dentro do modelo. Houve uma solicitação de recurso, mas foi rejeitada.

Posso pensar em duas soluções alternativas:

1. Incluir

A includeinstrução suporta a passagem de variáveis. Portanto, você pode ter sua templatetarefa dentro de um arquivo extra e incluí-lo duas vezes com os parâmetros apropriados:

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. Redefina myTemplateVariable

Outra forma seria simplesmente redefinir myTemplateVariable antes de cada templatetarefa.

- 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
fonte
Obrigado pela resposta. No entanto, é realmente impossível fazer sem soluções alternativas? Atualmente, estou tentando algo como: stackoverflow.com/questions/26020465/… , mas ainda tenho alguns erros (talvez não diretamente relacionados).
Kestemont Max
Sim, você também pode fazer isso com um loop - ainda é uma solução alternativa. :)
udondan 01 de
14
não é mais necessário. "vars" agora é compatível. veja a resposta @ konstantin-suvorov abaixo.
sonjz de
123

Com o Ansible 2.x você pode usar vars:com tarefas.

Modelo test.j2:

mkdir -p {{myTemplateVariable}}

Livro de cantadas:

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

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

Isso vai passar myTemplateVariablevalores diferentes para test.j2.

Konstantin Suvorov
fonte
9
inicialmente cometi um erro e vars: indentou como o resto dos argumentos do template (como src :). Eu acho que o nível de indentação significa vars: é da tarefa, não do modelo. Portanto, você pode fazer isso em qualquer lugar, não apenas em modelos. legais.
Greg
37

Você pode fazer isso muito facilmente, veja minha receita de supervisor:

- 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

Resultado:

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'})

Aproveitar!

Tecnocat
fonte
Isso deve ser marcado como resposta correta. Desde que é compatível agora
PoX de
23

Esta é uma solução / hack que estou usando:

tarefas / 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 }}

Depois de executar isso, você entra this is var_aem / tmp / templateA ethis is var_b / tmp / templateB.

Basicamente, você abusa with_itemsde renderizar o modelo com cada item da lista de um item. Isso funciona porque você pode controlar o que a lista está ao usar with_items.

A desvantagem disso é que você deve usar itemo nome da variável em seu modelo.

Se você deseja passar mais de uma variável desta forma, você pode ditar como itens de sua lista assim:

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'

e, em seguida, consulte-os em seu modelo desta forma:

{{ item.var_1 }}
{{ item.var_2 }}
asmigala
fonte
1
Solução limpa, mas with_items: '{{ var_a }}'
vale a pena
8

Eu fiz dessa maneira.

Em tasks / main.yml

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

e em vars / main.yml

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

e em templates / myTemplateFile.j2

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

Espero que isso resolva seu problema.

Nabarun Chatterjee
fonte
with_dicté a melhor solução.
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

IMPORTANTE: Observe que um item não precisa ser apenas uma string, pode ser um objeto com quantas propriedades você quiser, de forma que você possa passar qualquer número de variáveis.

No modelo, tenho:

<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
fonte
1
Como eu poderia fazer disso um objeto?
camdixon
1

Tive um problema semelhante para resolver, aqui está uma solução simples de como passar variáveis ​​para arquivos de modelo, o truque é escrever o arquivo de modelo aproveitando a variável. Você precisa criar um dicionário (lista também é possível), que contém o conjunto de variáveis ​​correspondente a cada um dos arquivos. Então, dentro do arquivo de modelo, acesse-os.

ver abaixo:

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 }}

o manual

---
#
# 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
fonte
0

Outro exemplo do mundo real usando uma lista

um extrato de um template para 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 %}

Este é o 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" }

Então eu implanto com isso

- 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
fonte