【问题标题】:Ansible dynamic inventory script - odd behaviourAnsible 动态库存脚本 - 奇怪的行为
【发布时间】:2020-11-03 09:09:38
【问题描述】:

我正在尝试基于 JSON 输出为 ansible 创建一个基本的动态库存脚本。我是 jq 的新手,但我遇到了一个问题,即 ansible v2.9.14 和 2.9.15 上的动态脚本不喜欢输出,但是如果我将输出发送到文件然后针对输出运行 Ansible该文件,ansible 工作。

会发生这样的事情:

动态库存脚本输出:

{
  "all": {
      "hosts": {
"ip-172-31-39-30.eu-west-1.compute.internal": null,
"ip-172-31-44-224.eu-west-1.compute.internal": null,
"ip-172-31-42-6.eu-west-1.compute.internal": null,
"ip-172-31-32-68.eu-west-1.compute.internal": null,
    }
  }
}

Ansible 运行和错误:

$ ansible -i ./dynamic1.sh all -m ping -u ubuntu
[WARNING]:  * Failed to parse /home/ubuntu/dynamic1.sh with script plugin: failed to parse executable inventory script results from /home/ubuntu/dynamic1.sh:
Expecting property name enclosed in double quotes: line 8 column 5 (char 242)
[WARNING]:  * Failed to parse /home/ubuntu/dynamic1.sh with ini plugin: /home/ubuntu/dynamic1.sh:2: Expected key=value host variable assignment, got: {
[WARNING]: Unable to parse /home/ubuntu/dynamic1.sh as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

现在,如果我将动态脚本输出到文件中,然后再次运行 ansible,它就可以工作了:

$ ./dynamic1.sh > output.json

$ cat output.json
{
  "all": {
      "hosts": {
"ip-172-31-39-30.eu-west-1.compute.internal": null,
"ip-172-31-44-224.eu-west-1.compute.internal": null,
"ip-172-31-42-6.eu-west-1.compute.internal": null,
"ip-172-31-32-68.eu-west-1.compute.internal": null,
    }
  }
}

$ ansible -i output.json all -m ping -u ubuntu
[DEPRECATION WARNING]: Distribution Ubuntu 16.04 on host ip-172-31-42-6.eu-west-1.compute.internal should use /usr/bin/python3, but is using /usr/bin/python for
backward compatibility with prior Ansible releases. A future Ansible release will default to using the discovered platform python for this host. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information. This feature will be removed in version 2.12. Deprecation
warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
ip-172-31-42-6.eu-west-1.compute.internal | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
ip-172-31-39-30.eu-west-1.compute.internal | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
ip-172-31-32-68.eu-west-1.compute.internal | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
ip-172-31-44-224.eu-west-1.compute.internal | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

所以它起作用了......

这是dynamic1.sh的内容。我知道会有更好的方法来做到这一点,但我只需要一个基于 JSON 输出中 ansible 可以使用的匹配变量的服务器列表。

$ cat dynamic1.sh
#!/bin/bash
echo "{"
echo "  \"all\": {"
echo "      \"hosts\": {"
curl --silent -X GET https://url.com/api/servers -H "Authorization: Token $token" -H "Content-Type: text/json"  -H "Accept:application/json" | jq -r '.Result.servers[] | select(.ansible_local.local.local_facts.instance_type | tostring | contains("t2.micro")) | (.ansible_fqdn+"\": null,")' | sed 's/^/"/g'
echo "    }"
echo "  }"
echo "}"

谁能帮我解释为什么 ansible 接受文件而不接受脚本的输出?

【问题讨论】:

    标签: ubuntu dynamic ansible jq inventory


    【解决方案1】:

    Ansible inventory format相反,库存插件script.py期望属性hosts是一个list(例如hosts:[host1,host2 , host3 ]) 不是字典(例如hosts:{ host, host2, host3 })。


    库存插件yaml.py 与主机字典配合使用

    JSON(或 YAML,因为 JSON 是 YAML 的子集)清单工作正常

    shell> cat hosts.json
    {
        "all": {
            "hosts": {
                "ip-172-31-39-30.eu-west-1.compute.internal",
                "ip-172-31-44-224.eu-west-1.compute.internal",
                "ip-172-31-42-6.eu-west-1.compute.internal",
                "ip-172-31-32-68.eu-west-1.compute.internal"
            }
        }
    }
    
    shell> ansible-inventory -i hosts.json --list -vvv
    ...
    Parsed /scratch/tmp/hosts.json inventory source with yaml plugin
    {
        "_meta": {
            "hostvars": {}
        },
        "all": {
            "children": [
                "ungrouped"
            ]
        },
        "ungrouped": {
            "hosts": [
                "ip-172-31-32-68.eu-west-1.compute.internal",
                "ip-172-31-39-30.eu-west-1.compute.internal",
                "ip-172-31-42-6.eu-west-1.compute.internal",
                "ip-172-31-44-224.eu-west-1.compute.internal"
            ]
        }
    }
    

    但是,脚本提供的同一个文件会失败

    shell> cat hosts.sh 
    #!/bin/bash
    cat hosts.json
    
    shell> ansible-inventory -i hosts.sh --list -vvv
    ...
    Parsed /scratch/tmp/hosts.sh inventory source with script plugin
    

    [警告]:无法使用脚本插件解析 /scratch/tmp/hosts.sh:您 为主机列表定义了一个包含错误数据的组“所有”:{'hosts': {'ip-172-31-39-30.eu- west-1.compute.internal':无,'ip-172-31-44-224.eu-west-1.compute.internal':无, 'ip-172-31-42-6.eu-west-1.compute.internal':无,'ip-172-31-32-68.eu- west-1.compute.internal':无}} ...

    {
        "_meta": {
            "hostvars": {}
        },
        "all": {
            "children": [
                "ungrouped"
            ]
        }
    }
    

    库存插件script.py 与主机列表一起使用

    当属性 hosts 是 list

    时,库存插件 script.py 会按预期工作
    shell> cat hosts.json
    {
        "all": {
            "hosts": [
                "ip-172-31-39-30.eu-west-1.compute.internal",
                "ip-172-31-44-224.eu-west-1.compute.internal",
                "ip-172-31-42-6.eu-west-1.compute.internal",
                "ip-172-31-32-68.eu-west-1.compute.internal"
            ]
        }
    }
    
    shell> ansible-inventory -i hosts.sh --list -vvv
    ...
    Parsed /scratch/tmp/hosts.sh inventory source with script plugin
    {
        "_meta": {
           ...
        },
        "all": {
            "children": [
                "ungrouped"
            ]
        },
        "ungrouped": {
            "hosts": [
                "ip-172-31-32-68.eu-west-1.compute.internal",
                "ip-172-31-39-30.eu-west-1.compute.internal",
                "ip-172-31-42-6.eu-west-1.compute.internal",
                "ip-172-31-44-224.eu-west-1.compute.internal"
            ]
        }
    }
    

    注意事项

    • 脚本 hosts.sh 未正确实现,仅用于本示例的目的。引用script.py:

    说明: - 提供的源必须是返回 Ansible 清单 JSON 的可执行文件 - 源必须接受 C(--list) 和 C(--host ) 作为参数。 只有在没有 C(_meta) 键的情况下才会使用 C(--host)。

    【讨论】:

    • 不错的弗拉基米尔。我刚刚看了你的解释,我的动态库存脚本根据你所说的工作。感谢您花时间以我设法得到的方式解释它!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 1970-01-01
    • 2013-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    相关资源
    最近更新 更多