Ansible - 在运行时定义库存

Posted

技术标签:

【中文标题】Ansible - 在运行时定义库存【英文标题】:Ansible - Define Inventory at run time 【发布时间】:2014-10-09 04:29:36 【问题描述】:

我是 ansible 的新手,所以如果我的问题有点基本,请多多包涵。

场景:

我有几组远程主机,例如 [EPCs] [Clients] 和 [Testers] 我能够按照我想要的方式配置它们。

问题:

我需要编写一个剧本,当它运行时,它会在运行时向用户询问库存。 例如,当运行 playbook 时,应按以下方式提示用户: “输入您要配置的 EPC 数量” “输入您要配置的客户端数量” "输入您要配置的测试人员数量"

应该发生什么:

例如,现在用户分别输入 2,5 和 8。 现在 playbook 应该只处理组 [EPCs] 中的前 2 个节点、组 [Clients] 中的前 5 个节点和组 [Testers] 中的前 7 个节点。 我不想创建大量子组,例如,如果我有 20 个 EPC,那么我不想为我的 EPC 定义 20 个组,我想要一些动态库存,它应该自动配置根据用户在运行时输入的机器使用 vars_prompt 选项或类似的东西

让我发布我的剧本的部分内容,以便更好地了解将要发生的事情:

---
- hosts: epcs # Now this is the part where I need a lot of flexibility

  vars_prompt:
    name: "what is your name?"
    quest: "what is your quest?"

  gather_facts: no

  tasks:

  - name: Check if path exists
    stat: path=/home/khan/Desktop/tobefetched/file1.txt
    register: st

  - name: It exists
    debug: msg='Path existence verified!'
    when: st.stat.exists

   - name: It doesn't exist
     debug: msg="Path does not exist"
     when: st.stat.exists == false

   - name: Copy file2 if it exists
     fetch: src=/home/khan/Desktop/tobefetched/file2.txt dest=/home/khan/Desktop/fetched/   flat=yes
     when: st.stat.exists

   - name: Run remotescript.sh and save the output of script to output.txt on the Desktop
     shell: cd /home/imran/Desktop; ./remotescript.sh > output.txt

   - name: Find and replace a word in a file placed on the remote node using variables
     shell: cd /home/imran/Desktop/tobefetched; sed -i 's/name/quest/g' file1.txt

    tags:
       - replace

@gli 我尝试了您的解决方案,我的库存中有一个名为 test 的组,其中有两个节点。当我输入 0..1 我得到:

TASK: [echo sequence] ********************************************************* 
changed: [vm2] => (item=some_prefix0)
changed: [vm1] => (item=some_prefix0)
changed: [vm1] => (item=some_prefix1)
changed: [vm2] => (item=some_prefix1)

同样,当我输入 1..2 我得到:

TASK: [echo sequence] ********************************************************* 
changed: [vm2] => (item=some_prefix1)
changed: [vm1] => (item=some_prefix1)
changed: [vm2] => (item=some_prefix2)
changed: [vm1] => (item=some_prefix2)

同样,当我输入 4..5 时(节点甚至不存在于清单中,我得到:

TASK: [echo sequence] ********************************************************* 
changed: [vm1] => (item=some_prefix4)
changed: [vm2] => (item=some_prefix4)
changed: [vm1] => (item=some_prefix5)
changed: [vm2] => (item=some_prefix5)

任何帮助将不胜感激。谢谢!

【问题讨论】:

【参考方案1】:

您应该使用vars_prompt 从用户那里获取信息,add_host 用于动态更新主机,with_sequence 用于循环:

$ cat aaa.yml
---
- hosts: localhost
  gather_facts: False
  vars_prompt:
    - name: range
      prompt: Enter range of EPCs (e.g. 1..5)
      private: False
      default: "1"
  pre_tasks:
    - name: Set node id variables
      set_fact:
        start: " range.split('..')[0] "
        stop: " range.split('..')[-1] "
    - name: "Add hosts:"
      add_host: name="host_item" groups=just_created
      with_sequence: "start=start end=stop "

- hosts: just_created
  gather_facts: False
  tasks:
    - name: echo sequence
      shell: echo "cmd"

输出将是:

$ ansible-playbook aaa.yml -i 'localhost,'

Enter range of EPCs (e.g. 1..5) [1]: 0..1

PLAY [localhost] **************************************************************

TASK: [Set node id variables] *************************************************
ok: [localhost]

TASK: [Add hosts:] ************************************************************
ok: [localhost] => (item=0)
ok: [localhost] => (item=1)

PLAY [just_created] ***********************************************************

TASK: [echo sequence] *********************************************************
fatal: [host_0] => SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue
fatal: [host_1] => SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue

FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************************************************************
           to retry, use: --limit @/Users/gli/aaa.retry

host_0                     : ok=0    changed=0    unreachable=1    failed=0
host_1                     : ok=0    changed=0    unreachable=1    failed=0
localhost                  : ok=2    changed=0    unreachable=0    failed=0

在这里,它失败了,因为 host_0 和 host_1 无法访问,对你来说它会正常工作。

顺便说一句,我使用了更强大的概念“节点范围”。如果你不需要它,在提示符中设置“start=0”并只要求“stop”值是很简单的。

【讨论】:

我发现了一些非常有趣的东西。如果我在 mainplaybook.yml 中调用 playbook.yml 并传递 target 参数,那么我可以在 playbook.yml -hosts 中指定类似以下内容:localhost[target] 然后递增 target 直到达到用户指定的值。有这样的可能吗?? 我没听明白,抱歉。你想达到什么目的? 您发布的代码 sn-p 无助于根据用户输入包含库存。我只是发布了您的代码的结果 首先你不应该从 playbook 调用 playbook,而应该使用 roles。在角色任务中,您可以使用循环。和我用的方法一样。因此,您可以将我的答案分成两个文件,一个用于主要剧本,第二个(带循环)用于角色。 啊,我明白了,您不想为主机创建循环,您需要动态主机数组。让我想一想。【参考方案2】:

我认为您不能在运行时定义库存。您可以做的一件事是,在 Ansible 上编写一个包装脚本,该脚本将首先提示用户输入主机,然后动态构建 ansible-playbook 命令。

我更喜欢使用 python 来执行此操作,但您可以使用您选择的任何语言。

$ cat ansible_wrapper.py 
import ConfigParser
import os

nodes = ''
inv = 

hosts =  raw_input("Enter hosts: ")
hosts = hosts.split(",")

config = ConfigParser.ConfigParser(allow_no_value=True)
config.readfp(open('hosts'))
sections = config.sections()

for i in range(len(sections)):
    inv[sections[i]] = hosts[i]


for key, value in inv.items():
    for i in range(int(value)):
        nodes = nodes + config.items(key)[i][0] + ";"


command = 'ansible-playbook -i hosts myplaybook.yml -e "nodes=%s"' % (nodes)
print "Running command: ", command
os.system(command)

注意:我试过只使用 python2.7 运行这个脚本

【讨论】:

谢谢 Ramesh,但我需要一些内置到 ansible 中的东西来为我工作,因为我必须将剧本传递给某人

以上是关于Ansible - 在运行时定义库存的主要内容,如果未能解决你的问题,请参考以下文章

如何在库存文件中使用ansible-vault加密密码?

Ansible 学习笔记

Ansible - 标记 Azure 运行的虚拟机

来自 MySQL 数据库的 Ansible 库存

如何在Ansible中使用静态和动态库存

将剧本运行中的变量保存到 ansible 主机本地文件