Ansible expect when command asks twice the same question - ansible

I'm trying to automate VirtualGL configuration using command vglserver_config. This script uses this menu :
1) Configure server for use with VirtualGL (GLX + EGL back ends)
2) Unconfigure server for use with VirtualGL (GLX + EGL back ends)
3) Configure server for use with VirtualGL (EGL back end only)
4) Unconfigure server for use with VirtualGL (EGL back end only)
X) Exit
Choose:
I need to feed two different answers to the "Choose:" question :
'1' first time, to configure VirtualGL, followed by actual responses of configuration script (see below)
'x' when exiting the command
Here's the task I've come to:
- name: configure VirtualGL (vglserver_config)
ansible.builtin.expect:
command: "{{ vglserver_config_cmd }}"
responses:
(.*)Choose:(.*): 1
(.*)Continue?(.*): y
(.*)Restrict 3D X server access to vglusers group (recommended)?(.*): y
(.*)Restrict framebuffer device access to vglusers group (recommended)?(.*): y
(.*)Disable XTEST extension (recommended)?(.*): y
(.*)Choose:(.*): x
This does not work: as the entry (.*)Choose!(.*): is duplicated (Ansible complains about that), the command is answered 'X' by expect module, and thus nothing happen.
I tried an alternative code:
- name: configure VirtualGL (vglserver_config)
ansible.builtin.expect:
command: "{{ vglserver_config_cmd }}"
responses:
Question:
- 1
- y
- y
- y
- y
- x
But this syntax is incorrect. Ansible throws an error.
How can I solve this issue ?
Thx !
Jose
PS. Edited the 2nd code example to reflect the exact one I also tested (same error raised by Ansible)

Ok...
Why would I want to use expect module for a command that has unattended mode parameters...
I'm so dumb.
I've changed the "expect" task to a "command" with proper parameters.

Related

AnsibleUnsafeText enhancement to an existing playbook

I have a playbook that includes a set of tasks to obtain the status of an IBM MQ Channel. The playbook is passed the Channel name and I run the runmqsc command on each server
and register the output which unfortunately is on many lines, so i need to get this onto one line
echo "DISPLAY CHS('{{CHANNEL_NAME}}') STATUS RQMNAME"| runmqsc {{QMGR}}|grep -v DISPLAY|sed 's/^[^ ].*$/%/g' | tr -s " " | tr -d "\n" | tr "%" "\n"|grep CHANNEL|sed 's/ CURRENT//g' | sed 's/^ //g'|sed 's/ *$//g'
which gave the output
CHANNEL(CHANNEL) CHLTYPE(CLUSSDR) CONNAME(1.2.3.4(1414)) RQMNAME(QMGR) STATUS(RUNNING) SUBSTATE(MQGET) XMITQ(XMIT_QUEUE)
this I parsed to create a list CHSstatus (when CHANNEL_NAME is a wildcard I can have more than one result). From this list I then set variables to the STATUS of the channel.
- set_fact:
allStopped: "{%if splitStatus.STATUS == 'STOPPED'%}{{allStopped + [splitStatus.CHANNEL]}}{%else%}{{allStopped}}{%endif%}"
allRunning: "{%if splitStatus.STATUS == 'RUNNING'%}{{allRunning + [splitStatus.CHANNEL]}}{%else%}{{allRunning}}{%endif%}"
mixedState: "{%if splitStatus.STATUS != 'STOPPED' and splitStatus.STATUS != 'RUNNING'%}{{mixedState + [splitStatus.CHANNEL]}}{%else%}{{mixedState}}{%endif%}"
with_items: "{{CHSstatus}}"
loop_control:
loop_var: splitStatus
This has been working fine for a while with no issues. The problem with this is that you actually need to know the Channel name and as I wanted to enhance it to get the status of all the channels in a CLUSTER I put a 'wrapper' task in front of it to collect the channel names and use these to pass them.
My playbook now calls the MQ command to get these channel names, we can pass the CLUSTER name and register the result in clusterChannels, and include the previously working task with each channel name
- name: Status of Cluster channels
include: channelstatus.yml CHANNEL_NAME={{item}}
with_items: "{{clusterChannels.stdout_lines}}"
This now fails when trying to access the CHSStatus list, I get the error is ERROR! Unexpected Exception: unhashable type: 'dict'
I have tried both methods and compared some variables for each call of the original tasks
Original
"CHSstatus = [{'STATUS': u'RUNNING', 'CHANNEL': u'CHANNEL1'}]",
"CHSstatus Type = list",
"CHANNEL_NAME = CHANNEL1",
"CHANNEL_NAME type = AnsibleUnicode"
with the wrapper
"CHSstatus = [{'STATUS': u'RUNNING', 'CHANNEL': u'CHANNEL1'}]",
"CHSstatus Type = list",
"CHANNEL_NAME = CHANNEL1",
"CHANNEL_NAME type = AnsibleUnsafeText"
I have tried to find information about what AnsibleUnsafeText variable is and found that
'Since you are registering the result of a command in a variable, Ansible can't know what will be the content which becomes delivered. Therefore the registered Text output is marked as Unsafe.'
This has confused me a bit as I am running two commands, one to get the list of Channels in the wrapper and another to get the status of each individual channel in the original unchanged code. The registered variable is of type list but when I pass each channel from the wrapper it becomes an AnsibleUnsafeText type, I noticed that each of the registered variables for both commands when run with_items do indeed have an AnsibleUnsafeText type.
Can i convert this in any way? I have seen answers on how to convert to int, and i have tried item|string but this did not work either.
My original playbook used roles and i created a cutdown version of this using tasks only, this included cut down versions of channelstatus.yml and this worked OK, i then converted this to a role again including the same file and this failed.
One thing i notices in both cases of my MQ command registered results gets parsed successfully but the error occurs when I try to use this list of dict.
Example below is a list which contains a single dict, this can be a list of multiple dict's when run
CHSstatus = [{'STATUS': u'RUNNING', 'CHANNEL': u'CHANNEL1'}]
and a simple debug command is enough for this error to fail the playbook...
- debug:
msg:
- "{{item.CHANNEL}}"
- "{{item.STATUS}}"
with_items: "{{CHSstatus}}"
ERROR! Unexpected Exception: unhashable type: 'dict'
however
- debug:
msg:
- "{{CHSstatus[0].CHANNEL}}"
- "{{CHSstatus[0].STATUS}}"
works fine, which really does not make sense
Any help appreciated

why does sysctl show failed to access a file when using Ansbile

I have hit this a few times and never figured it out/ it resolved itself.
Running below playbook gives an error but it does make the change requested. . . .
If I run the same play again it does show the message but that is cause it is not updating the sysctl.
---
- hosts: "{{ target }}"
gather_facts: yes
become: yes
become_user: root
tasks:
- name: add a vm.overcommit_memory setting at the end of the sysctl.conf
sysctl: name=vm.overcommit_memory value=0 state=present reload=yes
The error is:
fatal: [testbox.local]: FAILED! => {"changed": false, "msg": "Failed to reload sysctl: net.ipv4.tcp_syncookies = 1\nnet.ipv4.tcp_synack_retries = 2\nnet.ipv4.conf.all.accept_redirects = 0\nnet.ipv4.conf.default.accept_redirects = 0\nnet.ipv6.conf.all.accept_ra = 0\nnet.ipv6.conf.default.accept_ra = 0\nnet.ipv4.icmp_ignore_bogus_error_responses = 1\nnet.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\nkernel.randomize_va_space = 0\nvm.swappiness = 5\nvm.overcommit_memory = 0\nkernel.shmmni = 15872\nkernel.shmmax = 67546587136\nkernel.shmall = 32981732\nkernel.sem = 250 256000 32 15872\nkernel.msgmni = 64417\nkernel.msgmax = 65536\nkernel.msgmnb = 65536\nsysctl: setting key \"kernel.msgmni\": Invalid argument\nsysctl: cannot stat /proc/sys/randomize_va_space: No such file or directory\nsysctl: cannot stat /proc/sys/“vm/overcommit_memory”: No such file or directory\n"}
There is likely problem with /etc/sysctl.conf prior the change applied by play. If you look at error message there is typo in kernel.msgmni (which should be really kernel.msgmin) and also double quotes around the path to vm.overcommit_memory. From that I suspect there are bad lines in file from previous attempts? Try to comment out these or try again with vanilla file obtained from your distribution.
On reload, good lines are still applied by sysctl; but there are some wrong lines in file which sysctl fails to apply, report and also why it exits with non-zero exit code - which makes play to fail.
According the error message
No such file or directory\nsysctl: cannot stat /proc/sys/“vm/overcommit_memory”: No such file or directory\n"
it seems you are running into a barely documented issue. The file path isn't constructed correctly. For possible reasons you may a look into #blami's answer, since there is also a correct entry in the message with vm.overcommit_memory = 0.
Furthermore may need to use use the YAML notation like
- name: Add a 'vm.overcommit_memory' setting at the end of the 'sysctl.conf'
sysctl:
name: vm.overcommit_memory
value: 0
state: present
reload: yes
which is also used in linux-system-roles/kernel_settings for vm. settings.
Further Q&A
Using Ansible, can we edit kernel level setting?

How to if/else properly in Ansible and registering variables parallelly

what I am trying to do is to register variables accordingdly. I am pinging an interface and then I try to verify if the ping was successful or not. However my code is not working the way I have imagined. I simplify it to following sample:
- name: Verify ping
ansible.builtin.shell: echo "yes it is online"
register: tmp
when: ping_output is search("5/5")
- name: Verify ping
ansible.builtin.shell: echo "no it is offline"
register: tmp
when: ping_output is search("0/5")
The variable ping_output was registered before in the previous tasks. Well what I have observed during my tests is that when I want to evaluate my variable tmp it is not set sometimes. This happens when the first conditional is true. Then tmp.stdout is set to "yes its online". Even if ansible is skipping the next conditional ("the else statement"), however it unsets the variable tmp.stdout and at some point I receive tmp.stdout is not defined. Do you have better suggestions how to solve it?
Thanks in advance
EDIT:
Hi, thanks for the review. I'm trying to store information into variables and yes right, later I reference to tmp.stdout. I actually ping from a Cisco device and save the output. There are several pings, so several outputs. Then there are tasks which evaluate these outputs. The goal is to prepare an appropriate description which I send via JSON as an API call. What the enduser sees in the end, is a description in an external trouble ticketing system with information like which interfaces were pingable, which were not etc

How do I check the succesfull retry with separate command in ansible?

Ansible 2.9.6
There is standard way to use retry in Ansible.
- name: run my command
register: result
retries: 5
delay: 60
until: result.rc == 0
shell:
cmd: >
mycommand.sh
until is a passive check here.
How can I do the check with the separate command? Like "retry command A several times until command B return 0"
Of cause I may put both commands inside shell execution "commandA ; commandB" and I will get exit status of the second one for the result.rc. But is any Ansible way to do this?
The ansible way would point towards retries over a block or include that contains a command task for each script. However, that's not supported. You can use a modified version of the workaround described here, though, but it starts to get complicated. Therefore, you may prefer to take Zeitounator's suggestion.

How to check a log for a string and verify app status?

I am a newbie to Ansible and I want to verify if an application (non service) is running, if not, start it. So basically look for the output of "splunkd is running".
Output of 'status' command is
splunkd is running (PID: 15111).
splunk helpers are running (PIDs: 15214 15420 15431 15500).
Also want to check said app's log file for a string "does not exists!" and if it exists restart app (until that string no longer exists in log - the log currently does rotate upon restart). The servers in question only exists in Production and I don't feel too comfortable executing code there for the 1st time. Below is what I have so far, I feel like the 1st block and 3rd block need editing. Thanks for any assistance and feedback!
- name: Splunk status
command: sudo /splunk/bin/splunk status
changed_when: false
- name: Read log
shell: cat /splunk/log/splunkd.log
register: splunk_log
- name: Restart if "does not exists!", exists
command: sudo /splunk/bin/splunk restart
until: splunk_log.stdout.find('does not exists!') == 0
#when: splunk_log.stdout.find('does not exists!') != -1
debug: msg="does not exists! exists, restarting"
retries: 5
delay: 60
I don't understand the first task but I think you're trying to do something like this example of changed_when. Also, for task three follow this when-statement.

Resources