I've made some assumptions about your question:
- I'm assuming you're dealing with output from the
keytool -list -v command, because that's what it looks like.
- I'm assuming that the output of the command when you run it looks like the output when I run it. Since you didn't provide complete output in your question, including what it looks like when listing multiple keys, I needed to produce my own data for testing.
Ansible isn't really a great tool for complex text transformations, which is effectively what you're doing here. I'd like to suggest two different solutions, both relying on some sort of external tool to perform the heavy lifting.
Using awk
In this example, we use awk to read the output from keytool and generate JSON output.
I've hardcoded some output into this playbook for testing; obviously you would replace this in practice with a command task:
---
- 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
Running the above playbook will produce:
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"
}
]
}
...which I think produces the data you want.
Using a custom filter plugin
Alternatively -- and probably more robustly -- you could move the logic into a custom filter plugin. If we put the following in 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
Then our playbook becomes much simpler:
---
- 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
And that produces the same final output:
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"
}
]
}