带字符串列表的Ansible构建列表字典

时间:2019-04-25 16:00:16

标签: ansible

我在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”,在其中定义所需的所有部分,然后也许可以将其压缩

1 个答案:

答案 0 :(得分:1)

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

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

Ansible并不是真正用于复杂文本转换的好工具,这实际上就是您在这里所做的。我想提出两种不同的解决方案,都依靠某种外部工具来完成。

使用awk

在此示例中,我们使用awkkeytool读取输出并生成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"
        }
    ]
}