Ansible - 如何在剧本中有条件地反转变量

时间:2015-12-12 22:37:07

标签: ansible ansible-playbook

我需要能够反转存储在从命令行传递给playbook的JSON文件中的变量。

这些是我设置的任务(除了vars,它们相同),这是一个剧本片段:

- name: Prepare a .sql file
  delegate_to: 127.0.0.1
  mysql_db:
    name: "{{ source['database']['db_name'] }}"
    state: dump
    login_host: "{{ source['database']['host'] }}"
    login_user: "{{ source['database']['user'] }}"
    login_password: "{{ source['database']['password'] }}"
    target: test_db.sql
  when: invert is not defined

- name: Prepare a .sql file (inverted)
  delegate_to: 127.0.0.1
  mysql_db:
    name: "{{ target['database']['db_name'] }}"
    state: dump
    login_host: "{{ target['database']['host'] }}"
    login_user: "{{ target['database']['user'] }}"
    login_password: "{{ target['database']['password'] }}"
    target: test_db.sql
  when: invert is defined

因此,当我执行

ansible-playbook -i hosts playbook.yml --extra-vars "@dynamic_vars.json"

执行第一个任务。如果我执行

ansible-playbook -i hosts playbook.yml --extra-vars "@dynamic_vars.json" --extra-vars "invert-yes"

执行第二个任务,它接受与参数相同的哈希,但只交换目标的源(它基本上成为我的剧本中的源)。

正如你所看到的,这是一种非常简单的方法,有很多不必要的重复,我只是不喜欢它。但是,我想不出能够在命令行恢复变量而不构建更复杂的包含逻辑的更好方法。

也许你可以就如何做得更好来建议我?谢谢!

2 个答案:

答案 0 :(得分:1)

当谈到避免重复的话题时,我是YAML锚点和参考的忠实粉丝。由于内容是动态的,您可以利用with_items,可以用来传递如下参数:

- &sqldump
  name: Prepare a .sql file
  delegate_to: 127.0.0.1
  mysql_db:
    name: "{{ item['database']['db_name'] }}"
    state: dump
    login_host: "{{ item['database']['host'] }}"
    login_user: "{{ item['database']['user'] }}"
    login_password: "{{ item['database']['password'] }}"
    target: test_db.sql
  when: invert is not defined
  with_items:
    - source


- <<: *sqldump
  name: Prepare a .sql file (inverted)
  when: invert is defined
  with_items:
    - target

第二个任务是第一个任务的完美克隆,然后覆盖namecondition和循环with_items以传递target而不是source {1}}。

在阅读了你对@ydaetskcoR的回答后,听起来你在某些情况下需要使用来自其中一个或另一个dict的数据。也许在那种情况下,根据invert参数来全局定义var是有意义的。您的vars文件可能如下所示:

---

source:
  database: ...
  db_name: ...

target:
  database: ...
  db_name: ...

data: "{{ target if invert is defined else source }}"

然后,您可以在所有任务中使用data,而无需进一步处理条件。

- name: Prepare a .sql file
  delegate_to: 127.0.0.1
  mysql_db:
    name: "{{ data['database']['db_name'] }}"
    state: dump
    login_host: "{{ data['database']['host'] }}"
    login_user: "{{ data['database']['user'] }}"
    login_password: "{{ data['database']['password'] }}"
    target: test_db.sql

当然,这样你就有了一个固定的任务名称,它不随你传递的参数而改变。

答案 1 :(得分:0)

如果您尝试执行相同的操作但只想根据主机/组指定不同的变量,那么更好的方法可能是将这些变量设置为主机/组变量并将其作为单个任务运行。

如果我们设置库存文件有点像这样:

[source_and_target-nodes:children]
source-nodes
target-nodes

[source-nodes]
source database_name='source_db' database_login_user='source_user' database_login_pass='source_pass'

[target-nodes]
target database_name='target_db' database_login_user='target_user' database_login_pass='target_pass'

然后我们可以像source_and_target-nodes那样定位任务:

- name: Prepare a .sql file
  hosts: source_and_target-nodes
  mysql_db:
    name: "{{ database_name }}"
    state: dump
    login_host: "{{ inventory_hostname }}"
    login_user: "{{ database_login_user }}"
    login_password: "{{ database_login_pass }}"
    target: test_db.sql

如果您需要在问题中使用delegate_to,则无法轻松访问其他主机的主机变量但如果您只是需要在本地运行该游戏,则可以改为在主持人/群组变量中将ansible_connection设为local或在剧中设置connection: local