从stdout_lines获取特定的输出并将其存储在列表中

时间:2019-05-03 08:17:01

标签: ansible

我正在致力于自动化F5 BIG IP配置停用,我需要从执行的任意bigip命令中获取池名称。我已将输出内容存储到寄存器中,并希望获取池名称并将其存储在列表中。

直到从执行的命令的输出中获得宽IP信息(其中包含池名称)为止,我已经实现。

预期输出:-

据我所知,我可以使用任何正则表达式来获取池信息吗,就我所知,我可以进行点走操作来从JSON中获取确切的内容。我非常确定当有多个池名时,输出将不会相同。如果也有多个池,逻辑是什么?

---
- name: Playbook to verify the Wideip and fetch the GTM configuration
  hosts: test-gtm.com
  connection: local
  gather_facts: no

  tasks:

    - name: Verify WideIP Exists
      bigip_command:
        user: admin
        password: admin
        commands: "list gtm wideip a wideip"
        validate_certs: no
      register: output
      delegate_to: localhost

    - debug:
        var: output

    - name: Fetch the Pool name from the WideIP
      set_fact:
        gtm_pool: "{{ output.stdout_lines[0][1].split()[0] }}"

``

Output without the dot walk :-

"stdout_lines": [
            [
                "gtm wideip a test.abc.com {", 
                "    pools {", 
                "        test-pool {", 
                "            order 0", 
                "        }", 
                "    }", 
                "}"
            ]


Whole  debug output :-



        "output": {
        "changed": false, 
        "deprecations": [
            {
                "msg": "Param 'server' is deprecated. See the module docs for more information", 
                "version": 2.9
            }, 
            {
                "msg": "Param 'user' is deprecated. See the module docs for more information", 
                "version": 2.9
            }, 
            {
                "msg": "Param 'password' is deprecated. See the module docs for more information", 
                "version": 2.9
            }, 
            {
                "msg": "Param 'validate_certs' is deprecated. See the module docs for more information", 
                "version": 2.9
            }
        ], 
        "executed_commands": [
            "tmsh -c \\\"list gtm wideip a wideip\\\""
        ], 
        "failed": false, 
        "stdout": [
            "gtm wideip a wideip {\n    pools {\n        test-pool {\n            order 0\n        }\n    }\n}"
        ], 
        "stdout_lines": [
            [
                "gtm wideip a wideip {", 
                "    pools {", 
                "        test-pool {", 
                "            order 0", 
                "        }", 
                "    }", 
                "}"
            ]
        ]
    }
}





Debug output consisting of more than single pool:-

ok: [device.abc.com] => {
    "output": {
        "changed": false, 
        "deprecations": [
            {
                "msg": "Param 'server' is deprecated. See the module docs for more information", 
                "version": 2.9
            }, 
            {
                "msg": "Param 'user' is deprecated. See the module docs for more information", 
                "version": 2.9
            }, 
            {
                "msg": "Param 'password' is deprecated. See the module docs for more information", 
                "version": 2.9
            }, 
            {
                "msg": "Param 'validate_certs' is deprecated. See the module docs for more information", 
                "version": 2.9
            }
        ], 
        "executed_commands": [
            "tmsh -c \\\"list gtm wideip a wideip\\\""
        ], 
        "failed": false, 
        "stdout": [
            "gtm wideip a wideip {\n    description wideip\n    pool-lb-mode topology\n    pools {\n        test1-pool {\n            order 1\n        }\n        test2-pool {\n            order 0\n        }\n    }\n}"
        ], 
        "stdout_lines": [
            [
                "gtm wideip a wideip {", 
                "    description wideip", 
                "    pool-lb-mode topology", 
                "    pools {", 
                "        test1-pool {", 
                "            order 1", 
                "        }", 
                "        test2-pool {", 
                "            order 0", 
                "        }", 
                "    }", 
                "}"
            ]
        ]

2 个答案:

答案 0 :(得分:0)

可靠地解析输出 会很棘手,因为它实际上是专有的序列化格式。如果有一种方法可以让该交换机仅提供给您JSON,这将使您的生活更轻松(我知道有些Cisco交换机具有此选项)。

要执行此操作,您需要编写一个能够理解输出格式的解析器。但是我们可以作弊,并做出许多假设,并使用几个正则表达式解决这个问题。

我认为在任何情况下,我们都需要使用Ansible以外的工具来解析此输出。在这种情况下,我通常只用Python写一个过滤器模块,尽管有时“管道到awk”也可以。

为了解析此输出,我将以下内容砍在一起(并将其放入了剧本旁边的filter_plugins/bigip.py中):

import re

# Recall that "\s+" means "one or more whitespace characters"
re_pools = re.compile('''
gtm \s+ wideip \s+ a \s+ (\S+) \s+ { \s+
(?P<parameters>(\S+ \s+ \S+ \s+)*)
pools \s+ { \s+ (?P<pools>
(?:
\S+ \s+ {  \s+
[^}]* \s+
} \s+
)+ \s+
)
}
''', flags=re.VERBOSE)

re_pool = re.compile('''
(\S+) \s+ { \s+ [^}]* \s+ } \s+
''', flags=re.VERBOSE)


def filter_get_pool_names(v):
    combined = ' '.join(v.splitlines())
    res = re_pools.match(combined)

    if not res or not res.group('pools'):
        pools = []
    else:
        pools = re_pool.findall(res.group('pools'))

    return pools


class FilterModule(object):
    filter_map = {
        'get_pool_names': filter_get_pool_names,
    }

    def filters(self):
        return self.filter_map

上面定义了一个get_pool_names过滤器。如果我在这样的剧本中使用它:

---
- hosts: localhost
  gather_facts: false
  vars:
    output:
      stdout: ["gtm wideip a test.abc.com {\n    pools {\n        test-pool1 {\n            order 0\n        }\n        test-pool2 {\n            order 1\n        }\n        test-pool3 {\n            order 2\n        }\n    }\n}"]

  tasks:
    - debug:
        msg: "{{ output.stdout.0 | get_pool_names }}"

我得到结果:

TASK [debug] **********************************************************************************
ok: [localhost] => {
    "msg": [
        "test-pool1", 
        "test-pool2", 
        "test-pool3"
    ]
}

请注意,我在这里对输出的格式进行了假设,并且在过滤器中进行错误检查的方式实际上并没有太多。但是我认为这是解决此问题的一种方法。

更新

关于:

  

当我尝试将这些池名称传递给连续的剧本时,我可以看到它正在将其传递为“ [u \'test1-pool']”。但是我只需要“ test1-pool”即可。有什么建议吗?

过滤器的结果是一个名称列表。您正在尝试将其视为字符串。您需要像这样循环遍历结果:

- set_fact:
    pool_names: "{{ output.stdout.0 | get_pool_names }}"

- debug:
    msg: "processing pool: {{ item }}"
  loop: "{{ pool_names }}"

或参考列表中的各个元素:

- debug:
    msg: "the first pool is {{ pool_names.0 }}"

答案 1 :(得分:-1)

问题的内容是一系列的行,甚至都不是JSON,因此您不能简单地对其进行反序列化。有效的JSON是

{ "gtm wideip a test.abc.com": { "pools": { "test-pool": { "order": 0 }}}}

例如,如果有这样的数据,请在下面播放

vars:
  my_stdout_lines:
    gtm wideip a test.abc.com: 
      pools: 
        test-pool: 
          order: 0
        test-pool1: 
          order: 0
        test-pool2: 
          order: 0
tasks:
  - set_fact:
      my_list: "{{ my_stdout_lines|json_query('*.pools.keys(@)') }}"
  - debug:
      var: my_list

给予(节略):

"my_list": [
    [
        "test-pool2", 
        "test-pool", 
        "test-pool1"
    ]
]