Accessing AWS RDS Arn from aws rds describe-db-instances - ansible

I am using Ansible to access some RDS clusters in my account. I have the command working with this.
This is the input data.
"stdout_lines": [
"{",
" \"DBInstances\": [",
" {",
" \"PubliclyAccessible\": false, ",
" \"MasterUsername\": \"xxxxx\", ",
" \"MonitoringInterval\": 0, ",
" \"LicenseModel\": \"general-public-license\", ",
" \"VpcSecurityGroups\": [",
" {",
" \"Status\": \"active\", ",
" \"VpcSecurityGroupId\": \"xxxx\"",
" }",
" ], ",
" \"InstanceCreateTime\": \"xxxxxx\", ",
" \"CopyTagsToSnapshot\": false, ",
" \"OptionGroupMemberships\": [",
" {",
" \"Status\": \"in-sync\", ",
" \"OptionGroupName\": \"xxxxx\"",
........
" \"DBInstanceArn\": \"arn:aws:rds:region:xxxx:db:xxxx\", ",
.......
When running the command below targeting the [0[ item in the array I receive this output.
"{{ (registered.stdout_lines | from_json)['DBInstances'][0]['DBInstanceArn'] }}"
ok: [localhost] => {
"msg": "arn:aws:rds:region :xxxx:db:xxxx"
}
I can get down to the item I need by specifying it like this. I need the array ID in there as there are 3 of them. I have tried to run it this way. But I get all the data.
- name: Show
set_fact:
var: "item.db_instance_arn"
with_items: "{{rds.instances}}"
register: variable
I also get the fact that I want. I just cant output that individual fact.
Is there a way to hit all the items in the array and output the one variable I need?
Thanks in advance. Happy New Year!

You will want (registered.stdout | from_json), not (registered.stdout_lines | from_json) }}, because stdout_lines is a list of str, but from_json wants a str -- I'm surprised your question didn't include the error message that you experienced, because it for sure produces one
Then, once you have straightened out the JSON parsing, you will want to use the map filter, because as you observed, DBInstances is a list, meaning you need to effectively iterate over its objects like so:
- debug:
msg: my DB ARNs are {{
(registered.stdout | from_json).DBInstances
| map(attribute="DBInstanceArn")
| list }}
If you prefer, you can use the json_query filter which uses JMESPath syntax, although most of the time I find it more opaque than helpful:
- debug:
msg: my DB ARNs are {{ (registered.stdout | from_json)
| json_query('DBInstances[*].DBInstanceArn') }}

Related

copy list of set_fact output in csv column - ansible

i got the output with set_fact as below
"my_var": [
[
" iDRAC.Embedded.1",
" NIC.Integrated.1-1-1",
" NIC.Integrated.1-2-1",
" NIC.Integrated.1-3-1",
" NIC.Integrated.1-4-1",
" NIC.Slot.4-1-1",
" NIC.Slot.4-2-1",
" NIC.Slot.7-1-1",
" NIC.Slot.7-2-1",
" NIC.Slot.1-1-1",
" NIC.Slot.1-2-1",
" NIC.Slot.2-1-1",
" NIC.Slot.2-2-1"
],
[
" ABC",
" Not Supported",
" No Link",
" No Link",
" No Link",
" XYZ",
" XYZ",
" XYZ",
" XYZ",
" XYZ",
" XYZ",
" XYZ",
" XYZ"
]
]
}
now, i want this to be updated in csv file in column. for Example iDRAC.Embedded.1 in first column and ABC in next column. so on and so forth
For example
- copy:
dest: my_var.csv
content: |-
{% for line in csv %}
{{ line }}
{% endfor %}
vars:
csv: "{{ my_var.0|map('trim')|
zip(my_var.1|map('trim'))|
map('join', ',')|
list }}"
gives
shell> cat my_var.csv
iDRAC.Embedded.1,ABC
NIC.Integrated.1-1-1,Not Supported
NIC.Integrated.1-2-1,No Link
NIC.Integrated.1-3-1,No Link
NIC.Integrated.1-4-1,No Link
NIC.Slot.4-1-1,XYZ
NIC.Slot.4-2-1,XYZ
NIC.Slot.7-1-1,XYZ
NIC.Slot.7-2-1,XYZ
NIC.Slot.1-1-1,XYZ
NIC.Slot.1-2-1,XYZ
NIC.Slot.2-1-1,XYZ
NIC.Slot.2-2-1,XYZ

How to reboot server using Ansible if stdout result equal failed?

I write tasks for jboss, but i don't know how to restart server if stdout result equal failed.
My task:
- name: Server
become: true
check_deployments:
server: 111.111.111.111:8888
command: /deployment=*:read-attribute(name=status)
cli_path: /testusers/wildfly/bin
user: admin
password: admin
register: command
- name: wf_debug
debug:
msg: "{{ command.stdout_lines}}"
Output:
TASK [check_wf_status : wf_debug] ******************************************************************************************************************************************
ok: [111.111.111.111] => {
"msg": [
"{",
" \"outcome\" => \"success\",",
" \"result\" => [",
" {",
" \"address\" => [(\"deployment\" => \"test-module1\")],",
" \"outcome\" => \"success\",",
" \"result\" => \"OK\"",
" },",
" {",
" \"address\" => [(\"deployment\" => \"test-module2\")],",
" \"outcome\" => \"success\",",
" \"result\" => \"FAILED\"",
" },",
" ]",
"}"
]
}
How to reboot server using Ansible if result = FAILED ?
How to reboot server using Ansible if result = FAILED ?
This should work, as to the docs:
- name: Unconditionally reboot the machine with all defaults, when the check_deployments task has failed
reboot:
when: "'FAILED' in command.stdout_lines"
Please note, that you're registering "command". This is also an ansible module, which could cause confusion. It's better to register it with another name, e.g. register: check_deploy.

Ansible looping with conditions

I have bit problems to understand conditions looping.
I'm getting REST API response from Ambari server.
This response contains JSON with service names on host.
I'd like to iterate over service names to do some tasks.
Here are my steps in Ansible:
## This gets http api responce.
## in components I'm getting full `json`
- name: Get Hadoop services
uri:
url: ' {{ Ambari_link }}/{{ clustername }}/hosts/{{ ansible_host }}/host_components/ '
method: GET
headers:
X-Requested-By: ambari
user: "{{ Ambari_Admin_User}}"
password: "{{ Ambari_Admin_Pass }}"
force_basic_auth: yes
register: components
Here is step that outputs service names
## Here I'm simply list all services on host in cluster.
- name: "Display all services"
debug:
msg: " {{ Ambari_link }}/{{ clustername }}/host_components/{{ item }} "
loop: "{{ components.json | json_query('items[*].HostRoles.component_name') }}"
Example output
ok: [slave] => (item=DATANODE) => {
"msg": " https://ambari-server:8443/api/v1/clusters/test_cluster/host_components/DATANODE "
}
ok: [slave] => (item=HDFS_CLIENT) => {
"msg": " https://ambari-server:8443/api/v1/clusters/test_cluster/host_components/HDFS_CLIENT "
}
ok: [slave] => (item=NODEMANAGER) => {
"msg": " https://ambari-server:8443/api/v1/clusters/test_cluster/host_components/NODEMANAGER "
}
ok: [slave] => (item=YARN_CLIENT) => {
"msg": " https://ambari-server:8443/api/v1/clusters/test_cluster/host_components/YARN_CLIENT "
}
Now part that i don't understand how to implement.
I'd like to iterate over all service names.
If service name contains _CLIENT ansible should proceed with new item.
If service name does not contains _CLIENT in should print debug message.
But this step is simply skipped
- name: Filter Clients
debug:
msg: "{{ item }}"
loop: "{{ components.json | json_query('items[*].HostRoles.component_name') }}"
when: " item.find('CLIENT') == 'CLIENT' "
I also tried to search only for DATANODE but it was also skipped step.
when: " item.find('DATANODE') == 'DATANODE' "
Can some one please explain how to search in item for _CLIENT and why it is skipped?
I have as usual over complicated simplest part.
Instead of
when: " item.find('DATANODE') == 'DATANODE' "
It is possible to use
when: not '_CLIENT' in item
=> returns DATANODE, NODEMANAGER
Or more generic
# item contains [foo,bar]
when: not 'oo' in item
=> Returns all that not contains oo

Ansible search string in stdout_lines and user later as variable

I Have below ansible output in stdout_lines
"test.stdout_lines": [
"Get VM Power State Script",
"Loading vmware.vimautomation.core",
"",
"Attempting to connect to server1. Please wait.",
"",
"Connected to server1",
"\tGathering VM Info...",
"",
"Attempting to connect to serevr2. Please wait.",
"",
"Connected to server2.",
"\tGathering VM Info...",
"File Exported to D:\\Scripts\\Exports\\VM_State_201907151824.csv . Please verify the content",
"",
"Complete."
I want to store the file location in last line of the output as variable,i.e., location:- D:\Scripts\Exports\VM_State_201907151824.csv. How can it be done?
Does this work for you?
{{ test.stdout_lines | join(' ') | regex_replace( '^.*File Exported to (.*) \. Please .*$', '\\1') }}
Try below
- name: Get the file_path
set_fact:
file_path: "{{ test.stdout_lines | select('match', 'File Exported to.+') | list | regex_replace( '^.*File Exported to (.*) \\. Please .*$', '\\1') }}"
- name: debug
debug:
msg: "{{ file_path }}"

Fetch specific output from stdout_lines and store it in a list

I'm working on automating F5 BIG IP configuration decommission.I need to fetch the pool names from the executed arbitrary bigip command. I have stored the content of the output to a register and wanted to fetch the pool name and store it in a list.
I have achieved till obtaining the wide ip information (which contains Pool name) from the output of the executed command.
Expected output :-
Can i use any Regular expression to fetch the pool information , as far as i know i can do a dot walk to fetch the exact content from JSON . I'm pretty much sure that the output won't be same when there are multiple pool names . What would be the logic if there are multiple pools as well ?
---
- 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",
" }",
" }",
"}"
]
]
Parsing that output robustly will be tricky, because it is effectively a proprietary serialization format. If there's a way to get the switch to just give you JSON that would make your life easier (I know some Cisco switches have this option).
To do this The Right Way you would want to write a parser that understood the output format. But we can cheat, and make lots of assumptions, and solve this with a couple of regular expressions.
I think that in any case we're going to need to parse this output in a tool other than Ansible. I generally just write a filter module in Python in situations like this, although sometimes "pipe to awk" also works.
For parsing this output, I hacked together the following (and dropped it into filter_plugins/bigip.py adjacent to my playbook):
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
The above defines a get_pool_names filter. If I use it in a playbook like this:
---
- 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 }}"
I get the result:
TASK [debug] **********************************************************************************
ok: [localhost] => {
"msg": [
"test-pool1",
"test-pool2",
"test-pool3"
]
}
Note that I've made assumptions about the format of the output here, and there's really not much in the way of error checking in the filter. But I think it demonstrates one way of tackling this problem.
Update
Regarding:
while i was trying to pass these pool names to the consecutive playbook i could see it is passing this as "[u\'test1-pool']" . But i just need "test1-pool" . Any suggestions ?
The result of the filter is a list of names. You are trying to treat it as a string. You need to either loop over the result, like this:
- set_fact:
pool_names: "{{ output.stdout.0 | get_pool_names }}"
- debug:
msg: "processing pool: {{ item }}"
loop: "{{ pool_names }}"
Or refer to individual elements in the list:
- debug:
msg: "the first pool is {{ pool_names.0 }}"
The content in the question is a series of lines, and it's not even JSON so you can't simply deserialize it. Valid JSON would be
{ "gtm wideip a test.abc.com": { "pools": { "test-pool": { "order": 0 }}}}
As an example, if such data is available, the play below
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
gives (abridged):
"my_list": [
[
"test-pool2",
"test-pool",
"test-pool1"
]
]

Resources