如何使用模板模块来应用不同的变量集?

118

我的使用情况是这样的:

我有一个模板文件,我想从该模板创建2个不同的文件,每个文件的变量由不同的变量集填充。

例如,假设我想要将包含以下行的文件设置为模板:

mkdir -p {{myTemplateVariable}}

我想找到一种合适的方法,将这个变量填充为"File1"和"File2"。类似这样:

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


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

我希望指定第一个模板使用的变量为a="File1",第二个模板使用的变量为b="File2"。


这正是我在所有食谱中所做的事情,看看这个评论https://dev59.com/vF0Z5IYBdhLWcg3wtSPr#40189525,希望这可以帮到你! - Tecnocat
8个回答

134

使用Ansible 2.x版本,你可以在任务中使用vars:

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

这将把不同的myTemplateVariable值传递到test.j2中。


9
最初我犯了一个错误,将变量(vars)和模板参数(如src:)一样缩进。我想这个缩进级别意味着变量(vars)是任务的一部分,而不是模板的一部分。因此,你可以在任何地方使用它,而不仅仅是在模板中。很好。 - Greg

77
对于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

对于Ansible 1.x版本:
不幸的是,template模块不支持向其传递变量,这些变量可以在模板中使用。曾经有一个功能请求,但被拒绝了。
我能想到两个解决办法: 1. 包含 include语句支持传递变量。因此,您可以将template任务放在一个额外的文件中,并使用适当的参数包含它两次:

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. 重新定义 myTemplateVariable

另一种方法是在每个 template 任务之前直接重新定义 myTemplateVariable。

- 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

谢谢您的回答。但是,真的没有办法不用变通方法吗?我目前正在尝试类似于:https://dev59.com/CYPba4cB1Zd3GeqPvrFp 的东西,但仍然存在一些错误(可能不直接相关)。 - Kestemont Max
是的,你也可以用循环来实现 - 不过这仍然是一种变通方法。 :) - udondan
15
不再需要。现在支持“vars”。请参见下面@konstantin-suvorov的回答。 - sonjz
感谢您提供 set_fact 的提示。 - Scofield

46

你可以很容易地做到这一点,看看我的监督者配方:

- 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

输出:

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

享受!


这应该被标记为正确答案。因为现在已经支持了。 - PoX

23

我正在使用的解决方案/技巧是:

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

运行此命令后,/tmp/templateA中将得到this is var_a,而/tmp/templateB中将得到this is var_b

基本上您可以滥用with_items,使用单项列表中的每个项目进行模板渲染。这样做的原因是在使用with_items时可以控制列表是什么。

缺点是您必须在模板中使用item作为变量名。

如果您想以这种方式传递多个变量,则可以将字典用作列表项,如下所示:

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'

然后在模板中像这样引用它们:

{{ item.var_1 }}
{{ item.var_2 }}

1
干净的解决方案,但必须使用 with_items: '{{ var_a }}' - Peter Ajtai

9

我用了这种方式。

在 tasks/main.yml 中。

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

并且在 vars/main.yml 文件中

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

还有在templates/myTemplateFile.j2文件中

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

希望这能解决你的问题。

with_dict 是更好的解决方案。 - zx1986

2

我有一个类似的问题需要解决,这里提供了一个简单的解决方案,可以将变量传递到模板文件中。关键在于利用变量编写模板文件。您需要创建一个字典(也可以是列表),其中包含与每个文件对应的变量集。然后在模板文件中访问它们。

请参考下面的示例:

the template file: test_file.j2
# {{ ansible_managed }} created by xbalaji@gmail.com

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

游戏规则

---
#
# file: template_test.yml
# author: xbalaji@gmail.com
#
# 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 }}"

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

重要提示:请注意,一个项目不仅仅可以是一个字符串,它可以是一个带有任意属性的对象,这样您就可以传递任意数量的变量。

在模板中,我有:

<VirtualHost *:80>
    ServerAdmin me@example.org
    ServerName {{ item }}
    DocumentRoot /vagrant/public


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

</VirtualHost>

1
我该如何将它变成一个对象? - camdixon

1

另一个使用列表的现实世界示例

用于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 %}

这是变量。
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" }

然后我使用这个部署。
- 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}}"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接