Ansible构建列表字典,包含字符串列表

问题描述 投票:0回答:1

我有一个在stdout_lines中看起来像这样的命令输出:

        "stdout_lines": [
            "Keystore type: jks",
            "Keystore provider: SUN",
            "",
            "Your keystore contains 6 entries",
            "",
            "Alias name: alias1",
            "Creation date: Oct 16, 2015",
            "Entry type: PrivateKeyEntry",
            "Certificate chain length: 1",
            "Certificate[1]:",
            "Owner: CN=*.example.com, O=Example, L=Some, ST=Where, C=DE",
            "Issuer: CN=some issuer cert",
            "Valid from: Wed Oct 14 02:00:00 CEST 2015 until: Thu Oct 18 14:00:00 CEST 2018",
            "Signature algorithm name: SHA256withRSA",
            "Subject Public Key Algorithm: 2048-bit RSA key",
            "Version: 3",
            "" ]

因此,从存储了多个证书的密钥库中,我喜欢将信息提取到字典列表中,如下所示:

"keystore_values": [
    {"Alias name": "alias1", "Owner": "CN=*.example.com",
     "Valid until": "Thu Oct 18 14:00:00 CEST 2018" },
    {"Alias name": "alias2", "Owner": "CN=*.example2.com",
     "Valid until": "Thu Oct 18 14:00:00 CEST 2018" },
    {"Alias name": "alias3", "Owner": "CN=*.example3.com",
     "Valid until": "Thu Oct 18 14:00:00 CEST 2018" }]

现在我觉得我应该用regex_findall来检查“stdout”,在那里我定义了我需要的所有部件然后我可以拉链它们

ansible
1个回答
1
投票

我对你的问题做了一些假设:

  • 我假设你正在处理来自keytool -list -v命令的输出,因为这就是它的样子。
  • 我假设你运行它时命令的输出看起来像我运行时的输出。由于您没有在问题中提供完整的输出,包括列出多个键时的外观,我需要生成自己的数据进行测试。

Ansible对于复杂的文本转换来说并不是一个很好的工具,这实际上就是你在这里所做的。我想建议两种不同的解决方案,都依靠某种外部工具来完成繁重的工作。

使用awk

在这个例子中,我们使用awk来读取keytool的输出并生成JSON输出。

我已经将一些输出硬编码到这本剧本中进行测试;显然你会在实践中用command任务替换它:

---
- hosts: localhost
  gather_facts: false
  vars:
    storepass: secret
  tasks:
    - command: keytool -list -v -storepass {{ storepass }}
      register: keytool
      changed_when: false

    - command:
      args:
        argv:
          - "awk"
          - "-F"
          - ": "
          - |
            # this function prints out a single key as a JSON
            # object
            function print_key(key) {
              if (not_first_key) print ","
              not_first_key=1
              print "{"
              not_first_line=0
              for (i in key) {
                if (not_first_line) print ","
                not_first_line=1
                printf "\"%s\": \"%s\"\n", i, key[i]
              }
              print "}"
            }
            BEGIN {
              split("", key)
              print "["
            }

            # We recognize the start of a new key by the Alias name
            # field. When we see it, we will (a) check if we have data
            # for a prior key and print it out and then (b) reset the
            # key array and start collecting new data.
            /^Alias name/ {
              if (length(key) > 0) {
                print_key(key)
                delete(key)
              }
              key["Alias name"] = $2
            }

            # The "Valid from" line requires special parsing.
            /^Valid from/ {
              key["Valid from"] = substr($2, 0, length($2)-6)
              key["Valid until"] = $3
            }

            # Simple fields that we're interested in
            /^(Owner|Issuer|Creation date)/ {
              key[$1] = $2
            }

            END {
              if (length(key) > 0) {
                print_key(key)
              }
              print "]"
            }
        stdin: "{{ keytool.stdout }}"
      register: keytool_json
      changed_when: false

    - set_fact:
        key_list_1: "{{ keytool_json.stdout|from_json }}"

    - debug:
        var: key_list_1

运行上面的剧本将产生:

TASK [debug] **********************************************************************************
ok: [localhost] => {
    "key_list_1": [
        {
            "Alias name": "alias1", 
            "Creation date": "Apr 25, 2019", 
            "Issuer": "CN=Alice McHacker, OU=Unknown, O=Example Company, Inc., L=Boston, ST=MA, C=US", 
            "Owner": "CN=Alice McHacker, OU=Unknown, O=Example Company, Inc., L=Boston, ST=MA, C=US", 
            "Valid from": "Thu Apr 25 19:14:01 EDT 2019", 
            "Valid until": "Wed Jul 24 19:14:01 EDT 2019"
        }, 
        {
            "Alias name": "alias2", 
            "Creation date": "Apr 25, 2019", 
            "Issuer": "CN=Mallory Root, OU=Unknown, O=Example Company, Inc., L=New York, ST=NY, C=US", 
            "Owner": "CN=Mallory Root, OU=Unknown, O=Example Company, Inc., L=New York, ST=NY, C=US", 
            "Valid from": "Thu Apr 25 19:17:03 EDT 2019", 
            "Valid until": "Wed Jul 24 19:17:03 EDT 2019"
        }
    ]
}

...我认为产生你想要的数据。

使用自定义过滤器插件

或者 - 可能更强大 - 您可以将逻辑移动到自定义过滤器插件中。如果我们在filter_plugins/keys_to_list.py中添加以下内容:

#!/usr/bin/python


def filter_keys_to_list(v):
    key_list = []
    key = {}
    for line in v.splitlines():
        # Just skip lines that don't look like a Key: Value line.
        if ': ' not in line:
            continue

        # Same logic as the awk script: "Alias name" identifies the
        # start of key data.
        if line.startswith('Alias name'):
            if key:
                key_list.append(key)
                key = {}

        field, value = line.split(': ', 1)
        if field in ['Alias name', 'Owner', 'Issuer', 'Creation date']:
            key[field] = value
        elif field == 'Valid from':
            key['Valid from'], key['Valid until'] = value.split(' until: ')

    if key:
        key_list.append(key)

    return key_list


class FilterModule(object):
    filter_map = {
        'keys_to_list': filter_keys_to_list,
    }

    def filters(self):
        return self.filter_map

然后我们的剧本变得更加简单:

---
- hosts: localhost
  gather_facts: false
  vars:
    storepass: secret
  tasks:
    - command: keytool -list -v -storepass {{ storepass }}
      register: keytool
      changed_when: false

    - set_fact:
        key_list_2: "{{ keytool.stdout|keys_to_list }}"

    - debug:
        var: key_list_2

这产生了相同的最终输出:

TASK [debug] **********************************************************************************
ok: [localhost] => {
    "key_list_2": [
        {
            "Alias name": "alias1", 
            "Creation date": "Apr 25, 2019", 
            "Issuer": "CN=Lars Kellogg-Stedman, OU=Unknown, O=The Odd Bit, L=Boston, ST=MA, C=US", 
            "Owner": "CN=Lars Kellogg-Stedman, OU=Unknown, O=The Odd Bit, L=Boston, ST=MA, C=US", 
            "Valid from": "Thu Apr 25 19:14:01 EDT 2019", 
            "Valid until": "Wed Jul 24 19:14:01 EDT 2019"
        }, 
        {
            "Alias name": "alias2", 
            "Creation date": "Apr 25, 2019", 
            "Issuer": "CN=Mallory Root, OU=Unknown, O=The Odd Bit, L=New York, ST=NY, C=US", 
            "Owner": "CN=Mallory Root, OU=Unknown, O=The Odd Bit, L=New York, ST=NY, C=US", 
            "Valid from": "Thu Apr 25 19:17:03 EDT 2019", 
            "Valid until": "Wed Jul 24 19:17:03 EDT 2019"
        }
    ]
}
© www.soinside.com 2019 - 2024. All rights reserved.