How can I prompt the user for an inventory group and pass that variable to next plays in the same playbook?

huangapple go评论56阅读模式
英文:

How can I prompt the user for an inventory group and pass that variable to next plays in the same playbook?

问题

在这个手册中,我正在提示用户选择一个地区。用户选择了一个地区后,我希望对该特定的清单组运行操作。我还将该地区分配给一个事实,以便我可以在同一手册的另一个操作中使用它。

我的清单文件如下所示:

[ams]
device1
device2

[usa]
device1
device2

[jpn]
device1
device2

Playbook如下所示:

---
- name: Play 1
  hosts: "{{ region }}"
  gather_facts: false
  connection: network_cli
  
  vars_prompt:
    - name: region
      prompt: "Region (ams, usa, jpn)"
      private: no

  tasks:
    - name: Make vars persistent
      set_fact:
        region: "{{ region }}"

    - name: check var
      debug:
        msg: "{{ region }}"


- name: Play 2
  hosts: "{{ region }}"
  gather_facts: false
  connection: network_cli

  vars:
    region: "{{ hostvars['region'] }}"

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

但是,在启动“Play 2”时,我收到了以下错误消息:

错误!字段“hosts”具有无效值,其中包括未定义的变量。错误是:{{ hostvars['region'] }}:“hostvars['region']”未定义。hostvars['region']”未定义。{{ hostvars['region'] }}:“hostvars['region']”未定义。hostvars['region']”未定义。

我是不是在错误的方式下读取事实?

我还尝试了以下方式:

{{ hostvars['region']['region'] }}

但是,我收到相同的错误。

英文:

In this playbook, I'm prompting the user for a region. After the user selects a region, I want to run plays against that specific inventory group. I'm also assigning that region to a fact so I can use it on another play on the same playbook.

My inventory file looks like this:

[ams]
device1
device2

[usa]
device1
device2

[jpn]
device1
device2

Playbook looks like this:

---
- name:  Play 1
  hosts: "{{ region }}"
  gather_facts: false
  connection: network_cli
  
  vars_prompt:
    - name: region
      prompt: "Region (ams, usa, jpn)"
      private: no

  tasks:
    - name: Make vars persistent
      set_fact:
        region: "{{ region }}"

    - name: check var
      debug:
        msg: "{{ region }}"


- name:  Play 2
  hosts: "{{ region }}"
  gather_facts: false
  connection: network_cli

  vars:
    region: "{{ hostvars['region'] }}"

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

But I get the following error while starting "Play 2"

> ERROR! The field 'hosts' has an invalid value, which includes an undefined variable. The error was: {{ hostvars['region'] }}: "hostvars['region']" is undefined. "hostvars['region']" is undefined. {{ hostvars['region'] }}: "hostvars['region']" is undefined. "hostvars['region']" is undefined

Am I trying to read facts the wrong way?

I also tried with

{{ hostvars['region']['region'] }}"

, but I get the same error.

答案1

得分: 2

以下是翻译好的代码部分:

{{ hostvars['region']['region'] }}

请注意,这段代码似乎包含了HTML编码字符(&等)。如果需要更多帮助,请告诉我。

英文:
{{ hostvars['region']['region'] }}

Q: "Am I trying to read facts the wrong way?"

A: Yes. The first attribute should be the name of a host. Quoting from hostvars:

> "A dictionary/map with all the hosts in inventory and variables assigned to them"

{{ hostvars[name_of_host]['region'] }}

You can use for this purpose any of the hosts in the inventory (device1, device2, ...), but generally, it is not a good idea to hardcode in a playbook an inventory name that might be changed. You can use localhost for this purpose, but you'll have to include localhost in the inventory, for example

shell> cat hosts 
localhost

[ams]
device1
device2
...

But this may have side effects on localhost variables if you use ones. The best option for this purpose seems to be a dummy host. Put it into a separate file. Other hosts might be generated dynamically. Create a project for testing

shell> tree .
.
├── ansible.cfg
├── inventory
│   ├── 01-hosts
│   └── 02-hosts
└── pb.yml
shell> cat inventory/01-hosts 
dummy
shell> cat inventory/02-hosts 
[ams]
device1
device2

[usa]
device3
device4

[jpn]
device5
device6

Run the first play on all hosts. Set the variable region once and delegate to dummy. This way, the variable region will be put into the hostvars (instantiated/made persistent) of all hosts

<sup>

shell&gt; cat pb.yml
- name:  Play 1
  hosts: all
  
  vars_prompt:

    - name: region
      prompt: &quot;Region (ams, usa, jpn)&quot;
      private: no

  tasks:

    - block:
        - name: Make vars persistent
          set_fact:
            region: &quot;{{ region }}&quot;
        - name: Check var
          debug:
            var: dict(hostvars|dict2items|json_query(&#39;[].[key, value.region]&#39;))
      delegate_to: dummy
      run_once: true

- name:  Play 2
  hosts: &quot;{{ hostvars.dummy.region }}&quot;

  tasks:

    - debug: 
        var: region

gives

shell&gt; ansible-playbook -i inventory pb.yml
Region (ams, usa, jpn): usa

PLAY [Play 1] *********************************************************************************

TASK [Make vars persistent] *******************************************************************
ok: [dummy]

TASK [Check var] ******************************************************************************
ok: [dummy] =&gt; 
  dict(hostvars|dict2items|json_query(&#39;[].[key, value.region]&#39;)):
    device1: usa
    device2: usa
    device3: usa
    device4: usa
    device5: usa
    device6: usa
    dummy: usa

PLAY [Play 2] *********************************************************************************

TASK [debug] **********************************************************************************
ok: [device3] =&gt; 
  region: usa
ok: [device4] =&gt; 
  region: usa

PLAY RECAP ************************************************************************************
device3: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
device4: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
dummy: ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

</sup>

<hr>

Ansible module ansible.builtin.add_host

The simpler and more straightforward option is the usage of the module add_host. Create a group, for example, my_region in the first play and use it in the second one. Create a project for testing

shell&gt; tree .
.
├── ansible.cfg
├── hosts
└── pb.yml
shell&gt; cat hosts
[ams]
device1
device2

[usa]
device3
device4

[jpn]
device5
device6

<sup>

shell&gt; cat pb.yml 
- name:  Play 1
  hosts: localhost
  
  vars_prompt:

    - name: region
      prompt: &quot;Region (ams, usa, jpn)&quot;
      private: no

  tasks:

    - add_host:
        name: &quot;{{ item }}&quot;
        groups: my_region
        region: &quot;{{ region }}&quot;
      loop: &quot;{{ groups[region] }}&quot;

- name:  Play 2
  hosts: my_region

  tasks:

    - debug: 
        var: region

gives

shell&gt; ansible-playbook pb.yml 
Region (ams, usa, jpn): usa

PLAY [Play 1] *********************************************************************************

TASK [add_host] *******************************************************************************
changed: [localhost] =&gt; (item=device3)
changed: [localhost] =&gt; (item=device4)

PLAY [Play 2] *********************************************************************************

TASK [debug] **********************************************************************************
ok: [device3] =&gt; 
  region: usa
ok: [device4] =&gt; 
  region: usa

PLAY RECAP ************************************************************************************
device3: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
device4: ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
localhost: ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

</sup>

huangapple
  • 本文由 发表于 2023年6月5日 08:01:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76402880.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定