【问题标题】:Ansible: Access host/group vars from within custom moduleAnsible:从自定义模块中访问主机/组变量
【发布时间】:2015-05-15 13:44:47
【问题描述】:

有没有一种方法可以从custom written module 中访问主机/组变量?我想避免将所有必需的变量作为模块参数传递。

我的模块是用 Python 编写的,我使用样板。我检查了几乎所有可用的变量,但它们没有存储在任何地方:

def main():
    pprint(dir())
    pprint(globals())
    pprint(locals())
    for name in vars().keys():
        print(name)

现在我唯一的希望是它们可以通过未记录的模块工具以某种方式访问​​。

我想这是不可能的,因为模块在目标机器上运行,并且可能事实/主机/组变量没有与模块一起传输......

编辑:现在找到了module utils,但看起来并不乐观。

【问题讨论】:

    标签: python ansible ansible-playbook


    【解决方案1】:

    我认为您在这里的想法几乎一针见血:

    我想这是不可能的,因为模块在目标机器上运行,并且可能事实/主机/组变量没有与模块一起传输......

    但是,话虽如此,如果您真的需要这样做,那么可能会有一种稍微混乱的方式。从 Ansible 1.8 开始,您可以设置 fact caching,它使用 redis 在运行之间缓存事实。由于 redis 非常易于使用并且具有clients for most popular programming languages,因此您可以让您的模块查询 redis 服务器以获取您需要的任何事实。这并不是最干净的方法,但它可能会奏效。

    【讨论】:

    • 这很有趣!现在它不是一个选项,因为它需要一个可以从本地机器和远程机器访问的额外 redis 主机。这有点太多的开销。但是当我们使用 Ansible 完成更多自动化时,我们可能会以这种方式实现它。事实缓存是我们以后可能想要的东西。我会接受你的回答 - 虽然它不是最佳解决方案,但它似乎是最好的解决方案。
    • 你可以简单的在现有的ansible服务器上安装redis。 redis 非常轻量级,因此不需要额外的服务器。
    • 嗯,这里有点复杂。处理 8 个 colos 中的数千台主机,每个主机都有多个独立的 vlan。我们刚刚开始使用 Ansible。现在这需要付出太多的努力,但很明显,我们需要在未来不久的事实缓存,然后这应该很容易实现。
    【解决方案2】:

    有没有一种方法可以从自定义中访问主机/组变量 写模块?

    不是内置的。

    你必须自己通过一种或另一种方式:

    • 模块参数。
    • 序列化到本地文件系统(使用pickleyaml.dump()json 或...)并发送文件。
    • 您能想到的任何其他创新点子。

    不幸的是,您不能按原样发送整个 host/groupvar 文件,因为您必须实现 ansible 的可变范围/优先级解析算法,它是未定义的(定义这样的小事不是 Zen philosophy of ansible事情:P)。

    【讨论】:

      【解决方案3】:

      根据您在your answer here 中的建议,我确实设法通过自定义Action Plugin 读取了host_vars 和本地播放变量。

      我发布这个答案是为了完整起见,并给出一个明确的例子来说明如何使用这种方法,尽管你最初给出了这个想法:)

      注意 - 就功能齐全的插件而言,此示例是不完整的。它只是展示了如何访问变量。

      from ansible.template import is_template
      from ansible.plugins.action import ActionBase
      
      
      class ActionModule(ActionBase):
      
          def run(self, tmp=None, task_vars=None):
      
              # some boilerplate ...
              
              # init
              result = super(ActionModule, self).run(tmp, task_vars)
      
              # more boilerplate ...
      
              # check the arguments passed to the task, where if missing, return None
              self._task.args.get('<TASK ARGUMENT NAME>', None)
              # or
              # check if the play has vars defined
              task_vars['vars']['<ARGUMENT NAME>']
              # or
              # check if the host vars has something defined
              task_vars['hostvars']['<HOST NAME FORM HOSTVARS>']['<ARGUMENT NAME>']
      
              # again boilerplate...
      
              # build arguments to pass to the module
              some_module_args = dict(
                  arg1=arg1,
                  arg2=arg2
              )
      
              # call the module with the above arguments...
      

      如果您的剧本变量带有 jinja 2 模板,您可以在插件中解析这些模板,如下所示:

      from ansible.template import is_template
      
      # check if the variable is a template through 'is_template'
      if is_template(var, self._templar.environment):
          # access the internal `_templar` object to resolve the template
          resolved_arg = self._templar.template(var_arg)
      

      一些注意事项:

        1. 如果您在剧本中定义了如下变量
      # things ...
      #
            vars:
              - pkcs12_path: '{{ pkcs12_full_path }}'
              - pkcs12_pass: '{{ pkcs12_password }}'
      

      变量pkcs12_path不得与 host_vars 名称匹配。

      例如,如果您有pkcs12_path: '{{ pkcs12_path }}',那么使用上述代码解析模板将导致递归异常...这对某些人来说可能很明显,但对我来说,host_vars 变量和 playbook 变量令人惊讶必须同名。

        1. 您也可以通过task_vars['&lt;ARG_NAME&gt;'] 访问变量,但我不确定它是从哪里读取的。此外,它也没有从 task_vars['vars']['&lt;ARG_NAME&gt;'] 或主机变量中获取变量那么明确。

      PS - 在撰写本文时,该示例遵循 Ansible 认为的动作插件的基本结构。将来,run 方法可能会更改其签名...

      【讨论】:

      • 太棒了,谢谢你把这个放在一起。我再也没有回去测试我的想法。很高兴它起作用了:)
      猜你喜欢
      • 1970-01-01
      • 2022-11-07
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      • 2014-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多