从命令行覆盖Ansible剧本的主机变量


110

这是我正在使用(server.yml)的剧本的一部分:

- name: Determine Remote User
  hosts: web
  gather_facts: false
  roles:
    - { role: remote-user, tags: [remote-user, always] }

我的主机文件具有不同的服务器组,例如

[web]
x.x.x.x

[droplets]
x.x.x.x

现在,我想执行ansible-playbook -i hosts/<env> server.yml并覆盖hosts: webserver.yml以运行此剧本[droplets]

我可以直接覆盖一次,而不server.yml直接进行编辑吗?

谢谢。

Answers:


128

我认为Ansible不应该提供此功能。您可以执行以下操作:

hosts: "{{ variable_host | default('web') }}"

您可以variable_host从命令行或vars文件中传递,例如:

ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"

3
需要进行较小的更正。应该是hosts: "{{ variable_host | default('web')}}"
SPM 2015年

16
这是我认为可以解决这个问题的新手答案的完整说明:示例:ansible-playbook server.yml --extra-vars "variable_host=newtarget(s)"
Frobbit,2016年

1
WHEN(即以什么顺序)不ansible解析变量中的变量group_vars/all似乎是解析hosts:PlayBook的产品线。但是,in中的变量vars:和in vars_files:中的变量是hosts:在行之前解析的?注意不是在问优先级。
费利佩·阿尔瓦雷斯

2
您也可以使用-e代替--extra-vars
名词

再看其他的答案更多细节
阿南德VARKEY飞利浦

63

对于任何可能会寻找解决方案的人。
玩书

- hosts: '{{ host }}'
  tasks:
  - debug: msg="Host is {{ ansible_fqdn }}"

库存

[web]
x.x.x.x

[droplets]
x.x.x.x

命令: ansible-playbook deplyment.yml -i hosts --extra-vars "host=droplets" 因此您可以在extra-vars中指定组名


2
请注意,使用var命名时要小心。我正在使用进行测试play_hosts,但未获得预期的结果,因为我忘记了这play_hosts是当前游戏中所有主机的内部Ansible变量。
瑞安·费舍尔

我想默认值应设置为上述答案。
kakaz

19

这有点晚了,但是我认为您可以使用--limit or -l命令将模式限制为更特定的主机。(版本2.3.2.0)

你可以有 - hosts: all (or group) tasks: - some_task

然后ansible-playbook playbook.yml -l some_more_strict_host_or_pattern 使用该--list-hosts标志查看将在哪些主机上应用此配置。


3
我对ansible并不陌生,但我认为这是一种非常有效的解决方案,比其他解决方案更为紧凑。为什么要投票?
亚历山德罗·登特拉

16
这很危险。万一忘记limit受影响的主机列表,则剧本可能会造成很多损害。
亚历山大·谢布利金

3
我发现,--extra-vars "variable_host=newtarget(s)"像接受的解决方案那样使用是危险且更复杂的解决方案。它使用默认主机,web也可以在此处应用默认主机all。您可以使用严格的主机组作为默认设置,以避免出错,并使用该--list-hosts标志可以清楚地了解要影响的主机。
乔纳森·哈默尔

3
使用Extra-vars的解决方案可以将空组(或不存在的组)指定为默认值。因此,如果您忘记通过命令行提供变量,则不会发生任何不良情况。使用“ --limit”选项的解决方案更加危险,因为剧本无法将空组用作主机的默认值。选项“ --llmit”应用于主机值,因此它将应用于空组并提供空结果。因此,您必须使用“全部”或其他一些非空主机作为默认值。有一天,您会忘记提供“ --limit”参数,而剧本将应用于所有主机。
格雷戈里·佩图霍夫

4
这应该与@TmTron的答案结合起来,以了解调用者无法提供的情况--limit(否则它将影响所有可能的主机,这可能不是您想要的行为)
ncoghlan

14

我们使用一个简单的失败任务来强制用户指定Ansible limit选项,这样就不会默认/意外在所有主机上执行该任务。

我发现的最简单方法是:

---
- name: Force limit
  # 'all' is okay here, because the fail task will force the user to specify a limit on the command line, using -l or --limit
  hosts: 'all'

  tasks:
  - name: checking limit arg
    fail:
      msg: "you must use -l or --limit - when you really want to use all hosts, use -l 'all'"
    when: ansible_limit is not defined
    run_once: true

现在,我们在运行剧本时必须使用-l(= --limit选项),例如

ansible-playbook playbook.yml -l www.example.com

限制选项文档

限制为一台或多台主机当要针对某个主机组但仅针对该组的一个或多个成员运行一本剧本时,这是必需的。

仅限一台主机

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit "host1"

限制到多个主机

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit "host1,host2"

负数限制。
注意:必须使用单引号防止bash插值。

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit 'all:!host1'

仅限主机组

ansible-playbook playbooks/PLAYBOOK_NAME.yml --limit 'group1'


7

我正在使用不需要任何库存的另一种方法,并且可以使用以下简单命令:

ansible-playbook site.yml -e working_host=myhost

为此,您需要一本包含两个剧本的剧本:

  • 第一次播放在localhost上运行,并在内存清单中的已知组中添加主机(来自给定变量)
  • 第二场比赛在这个已知的团体上进行

一个有效的示例(将其复制并使用先前的命令运行):

- hosts: localhost
  connection: local
  tasks:
  - add_host:
      name: "{{ working_host }}"
      groups: working_group
    changed_when: false

- hosts: working_group
  gather_facts: false
  tasks:
  - debug:
      msg: "I'm on {{ ansible_host }}"

我正在使用Ansible 2.4.3和2.3.3


7

我将我的默认值更改为无主​​机,并进行了检查以将其捕获。这样,用户或cron被迫提供单个主机或组等。我喜欢@wallydrag注释中的逻辑。该empty_group包含在库存没有主机。

-主机:“ {{variable_host | default('empty_group')}}”

然后添加签入任务:

   任务:
   -名称:如果缺少必需的variable_host参数,则失败脚本
     失败:
       msg:“您必须添加--extra-vars ='variable_host ='”
     何时:(未定义variable_host)或(variable_host ==“”)

5

刚遇到这个谷歌搜索解决方案。实际上,Ansible 2.5中只有一个。您可以使用来指定库存文件--inventory,如下所示:ansible --inventory configs/hosts --list-hosts all


我相信这是2019年“我们的主年”中最正确的答案。来自Ansible 2.8.4的-h:-i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY specify inventory host path or comma separated host list. --inventory-file is deprecated
pyansharp

3

如果要运行与主机关联但在其他主机上的任务,则应尝试使用proxy_to

在您的情况下,您应该委托给本地主机(可使用的主机)并调用ansible-playbook命令


2

我正在使用ansible 2.5(确切地是2.5.3),并且似乎在执行hosts参数之前已加载vars文件。因此,您可以将主机设置在vars.yml文件中,然后只写hosts: {{ host_var }}在剧本中

例如,在我的playbook.yml中:

---
- hosts: "{{ host_name }}"
  become: yes
  vars_files:
    - vars/project.yml
  tasks:
    ... 

在vars / project.yml中:

---

# general
host_name: your-fancy-host-name

0

这是我通过--limit选项安全地指定主机的一个很酷的解决方案。在此示例中,如果在未通过--limit选项指定任何主机的情况下执行了剧本,则该剧结束。

已在Ansible版本2.7.10上进行了测试

---
- name: Playbook will fail if hosts not specified via --limit option.
  # Hosts must be set via limit. 
  hosts: "{{ play_hosts }}"
  connection: local
  gather_facts: false
  tasks:
  - set_fact:
      inventory_hosts: []
  - set_fact:
      inventory_hosts: "{{inventory_hosts + [item]}}"
    with_items: "{{hostvars.keys()|list}}"

  - meta: end_play
    when: "(play_hosts|length) == (inventory_hosts|length)"

  - debug:
      msg: "About to execute tasks/roles for {{inventory_hostname}}"

0

另一种解决方案是使用特殊变量ansible_limit,该变量是--limit当前Ansible执行的CLI选项的内容。

- hosts: "{{ ansible_limit | default(omit) }}"

如果--limit省略该选项,则Ansible会发出警告,但不会执行任何操作,因为没有主机匹配。

[WARNING]: Could not match supplied host pattern, ignoring: None

PLAY ****************************************************************
skipping: no hosts matched
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.