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

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.

Related

Ansible get specific value from output

I have been pulling my hair out over something I thought would have been easy to do.
I have playbook:
- hosts: all
tasks:
- name: Get F5 connections
bigip_command:
commands: show ltm node /mypartition/myserver.domain.com
provider:
server: "F5server.domain.com"
user: ""
password: ""
validate_certs: "no"
server_port: 443
register: connections
delegate_to: localhost
- name: output
debug:
msg: "{{ connections }}"
When I run that playbook, it outputs this:
ok: [myserver.domain.com] => {
"msg": {
"changed": false,
"executed_commands": [
"tmsh -c \\\"show ltm node /mypartition/myserver.domain.com\\\""
],
"failed": false,
"stdout": [
"-------------------------------------------------------------\nLtm::Node: /mypartition/myserver.domain.com (123.45.67.89)\n-------------------------------------------------------------\nStatus \n Availability : available\n State : enabled\n Reason : Node address is available\n Monitor : /Common/gateway_icmp (default node monitor)\n Monitor Status : up\n Session Status : enabled\n \nTraffic ServerSide General\n Bits In 635.9M -\n Bits Out 2.8G -\n Packets In 102.8K -\n Packets Out 266.6K -\n Current Connections 7 -\n Maximum Connections 11 -\n Total Connections 6.5K -\n Total Requests - 13.0K\n Current Sessions - 0"
],
"stdout_lines": [
[
"-------------------------------------------------------------",
"Ltm::Node: /mypartition/myserver.domain.com (123.45.67.89)",
"-------------------------------------------------------------",
"Status ",
" Availability : available",
" State : enabled",
" Reason : Node address is available",
" Monitor : /Common/gateway_icmp (default node monitor)",
" Monitor Status : up",
" Session Status : enabled",
" ",
"Traffic ServerSide General",
" Bits In 635.9M -",
" Bits Out 2.8G -",
" Packets In 102.8K -",
" Packets Out 266.6K -",
" Current Connections 7 -",
" Maximum Connections 11 -",
" Total Connections 6.5K -",
" Total Requests - 13.0K",
" Current Sessions - 0"
]
]
}
}
My question is, how do I simply get the "Current Connections" value i.e. in this example it is 7 and store it in a variable.
I have tried various different solutions but nothing seems to work.
My Ansible version is 2.9
Can someone please help?
The task
- debug:
msg: "Current Connections: {{ item.split().2 }}"
loop: "{{ connections.stdout_lines.0 }}"
when: item is match('^ Current Connections(.*)$')
gives
"msg": "Current Connections: 7"
Use a regular expression to extract the value and set the variable "current_connections"
- name: Current Connections
vars:
pattern: '(?<=Current\sConnections)\s*\d+'
set_fact:
current_connections: "{{ connections.stdout | regex_search(pattern) }}"
- debug:
var: hostvars[inventory_hostname]['current_connections']

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

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

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') }}

Filter out lines from input file

I am trying to read a file with some key=value data. I am able to do it using file lookup feature of ansible. Now the problem is I want to exclude the comments from the input file.But not sure how to do it. How to negate '^#' (line starting with #). I tried using this command {{ input_parms.split("\n")|regex_search('^[^#]') }} but it did not worked as expected.
This is my input file
->cat mydata.cfg
#parms
name: 'foo'
place: 'bar'
id: 1
My playbook:
---
- hosts: localhost
vars:
parm_file: 'mydata.cfg'
input_parms: "{{ lookup('file', parm_file) }}"
tasks:
- debug: var=input_parms.split("\n")
Current output:
ok: [localhost] => {
"input_parms.split(\"\n\")": [
"#parms",
"name: 'foo'",
"place: 'bar'",
"id: 1"
]
}
My expected output, without the commented line(#parms):
ok: [localhost] => {
"input_parms.split(\"\n\")": [
"name: 'foo'",
"place: 'bar'",
"id: 1"
]
}
You can use the select and the match filter to select only lines that don't begin with #:
- debug:
var: input_parms.splitlines()|select('match', '^[^#]')|list
Which produces:
TASK [debug] *************************************************************************
ok: [localhost] => {
"input_parms.splitlines()|select('match', '^[^#]')|list": [
"name: 'foo'",
"place: 'bar'",
"id: 1"
]
}

failed_when do not work with telnet output

I will try to set a telnet task to failed if "instance" is in the output message, but it didn't work.
here is the log:
TASK [ISAM Log to log1 and log2] **************************************************************************************************************************************
task path: /Users/sascha.mueller/Downloads/isam_log.yml:9
changed: [1.2.3.4] => {
"changed": true,
"failed_when_result": false,
"output": [
"configure system syslog no route dslamlog msg-type all\r\n\r\nError : instance does not exist\r\n\r\nISAM-ISAM_7363_Labor_Zw>#",
"configure system syslog no destination dslamlog\r\n\r\nError : instance does not exist\r\n\r\nISAM-ISAM_7363_Labor_Zw>#"
]
}
TASK [fail the play if the previous command did not succeed] **********************************************************************************************************
task path: /Users/sascha.mueller/Downloads/isam_log.yml:27
skipping: [1.2.3.4] => {
"changed": false,
"skip_reason": "Conditional result was False"
}
I also tried command_output.stderr e.g. but all these values doesn't exist
---
-
hosts: all
connection: local
become: no
tasks:
- name: ISAM Log to log1 and log2
ignore_unreachable: yes
telnet:
user: bla
password: blubb
login_prompt: "login: "
password_prompt: "password: "
timeout: 5
prompts:
- "[#|$]"
command:
- configure system syslog no route dslamlog msg-type all
- configure system syslog no destination dslamlog
register: command_output
failed_when: "'instance' in command_output.output"
- name: fail the play if the previous command did not succeed
fail:
msg: "the command failed"
when: "'instance' in command_output.output"
Is it possible to check this with an telnet command or to direct check it with variable.output or only with variable.stderr?
You can see in your example that output is a list:
"output": [
"configure system syslog no route dslamlog msg-type all\r\n\r\nError : instance does not exist\r\n\r\nISAM-ISAM_7363_Labor_Zw>#",
"configure system syslog no destination dslamlog\r\n\r\nError : instance does not exist\r\n\r\nISAM-ISAM_7363_Labor_Zw>#"
]
When you ask if "'instance' in command_output.output", you are asking if there is an item in outout that is the string instance. That is, your expression would evaluate to true if output looked like this:
"output": [
"this item does not match",
"instance"
]
What you really want to ask is "does any item in output contain the string instance?". The simplest way to do that is probably by concatenating all the lines into a single string:
"'instance' in ''.join(command_output.output)"
You should be able to use this in either you failed_when condition:
- name: ISAM Log to log1 and log2
ignore_unreachable: yes
telnet:
user: bla
password: blubb
login_prompt: "login: "
password_prompt: "password: "
timeout: 5
prompts:
- "[#|$]"
command:
- configure system syslog no route dslamlog msg-type all
- configure system syslog no destination dslamlog
register: command_output
failed_when: "'instance' in ''.join(command_output.output)"
Or in the when statement on your fail task:
- name: fail the play if the previous command did not succeed
fail:
msg: "the command failed"
when: "'instance' in ''.join(command_output.output)"

Resources