我正在致力于自动化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",
" }",
" }",
"}"
]
]
答案 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"
]
]