将变量传递给包含的剧本

时间:2016-10-22 10:20:37

标签: ansible ansible-playbook ansible-2.x

我在剧本中加入了另一本剧本。我需要传递一个名为required_node_version的变量。我在我的剧本中使用相同的变量,所以期待包含的剧本将继承它。但它不会导致“未定义”错误。所以我尝试使用这个不是很优雅的解决方案:

- hosts: localhost
  connection: local
  vars:
    required_node_version: v6.3.1

  ...    

- include: ../../base/ci/build.yml
  vars:
    required_node_version: "{{required_node_version}}"

导致{"failed": true, "msg": "ERROR! recursive loop detected in template string: {{required_node_version}}"}

对此有什么优雅的解决方案吗?

2 个答案:

答案 0 :(得分:3)

Ansible分别保持每个游戏的状态。一个游戏的可变范围也与其他游戏分开。您可以将播放中定义的变量范围视为有向非循环图,其中每个节点名称都是唯一的,并且值将在第二次写入时被覆盖。

当你在剧本中包含一些其他剧本(包括顶级剧本)时,所包含的剧本将拥有自己的变量范围,因为它是一个完全不同的剧本。因此,您将无法访问主游戏中定义的变量。实际错误不是递归循环检测错误,实际错误是变量未定义错误,因为您正在尝试访问在某些其他游戏中定义的变量。

试试这个:

<强> main.yml

---
- hosts: all
  vars:
    name: shasha

- include: included_playbook.yml
  vars:
    name1: "{{name}}""

现在您将收到以下实际错误:名称未定义,因为您尝试从名称分配名称时访问不同范围(不同游戏)的变量的 NAME1

现在用以下内容更改 main.yml

<强> main.yml

---
- hosts: all
  vars:
    name: shasha

- include: included_playbook.yml
  vars:
    name: shashank

虽然名称被定义了两次,但它们彼此不同,因为两者的范围不同(主要游戏的范围和所包含游戏的范围)。所以这没有任何问题。

一些替代解决方案:

<强> 1。在调用playbook时传递变量:

由于您所包含的剧本也可以作为主剧本运行,在这种情况下您将如何使用该变量?您可以在该剧本中定义变量,也可以从命令行传递它。

当您在调用playbook时传递变量时,它会自动在两个剧本的范围内创建该变量(主要剧本以及包含的剧本):

ansible-playbook -i hosts main.yml -e "required_node_version=v6.3.1"

或许您可以创建一个JSON文件,其中包含所有常用变量,这些变量在您包含的所有剧本中都很常见,然后在调用主要的ansible剧本时传递该JSON文件。

<强> 2。重新设计你的Ansible剧本:

如果您所包含的ansible剧本作为助手而不是以独立方式使用,那么您应该在任务级别包含此剧本。您仍将保持可重用性,并且只有一个范围,因此您不必担心明确传递变量。

关于递归循环检测错误背后的原因:

当您将变量赋值给变量时,Ansible实际上不使用rvalue的概念,而是执行两者之间的绑定。例如,您认为以下代码中变量 name1 的价值是什么:

<强> main.yml

---
- hosts: all
  vars:
   - name: old_val
   - name1: "{{name}}"
   - name: new_val

  tasks:
    - debug: msg="{{name1}}"

如果你的答案是 new_val ,你就明白了逻辑。考虑 name1 作为参考,指的是名称,而名称现在指的是new_val。因此,唯一的值是 new_value name1 名称只是引用 new_value 的引用。 old_value 的引用将丢失。

现在考虑以下脚本:

<强> main_recursive.yml

---
- hosts: all
  vars:
   - name: shasha
   - name1: "{{name}}"
   - name: "{{name1}}"

  tasks:
    - debug: msg="{{name}}"

现在让我们尝试重新名称的值。 名称指向 name1 name1 指向名称。那没关系,但我们怎样才能达到实际值?没办法,它是一个递归循环!!!

答案 1 :(得分:1)

有点documentation

  

Ansible有3个主要范围:

     

全局:这是由配置,环境变量和命令行设置的   播放:每个播放和包含的结构,变量条目,include_vars,角色默认值和变量。
  主机:与主机直接关联的变量,例如广告资源,事实或已注册的任务输出

因此,您为每个游戏定义的变量彼此不了解。

您有两种选择:

  • 全局设置required_node_version(通过-e开关),因此它将在任何地方定义

  • 为每个主机设置required_node_version(即通过./group_vars/all.yml文件),因此它将作为主机绑定事实在每个任务中可用。