Ansible Expect module handling duplicate keys/questions in flow - ansible

Trying to get the expect module to configure a Jira set-up - the module seems to work until the question is repeated - essentially the last two entires.
See the script questions below (With redacted data)
----------------------
JIRA Configurator v1.1
----------------------
--- Main Menu ---
[H] Configure JIRA Home
[D] Database Selection
[W] Web Server (incl. HTTP/HTTPs configuration)
[A] Advanced Settings
[S] Save and Exit
[X] Exit without Saving
Main Menu> D
--- Database Selection ---
Database Type : H2
Instance : (unused)
Connect As : sa / (no password)
* [H] H2 (not for production use)
[M] MySQL 8.0
[N] MySQL 5.7
[O] Oracle
[P] PostgreSQL
[A] Aurora PostgreSQL 9.6 (DC Only)
[S] SQL Server (MS-SQL)
[X] Return to Main Menu
Database Selection [H]> M
MySQL 8.0 Database Configuration.
Hostname (jira.company.com)>
Port (3306)>
Database (jiradb)>
Username (jirauser)>
Password ()>
Test Connection ([Y]/N)? > y
Attempting to connect to jira.company.com:3306/jiradb
Connection successful!
--- Database Selection ---
Database Type : MySQL 8.0
Instance : jira.company.com:3306/jiradb
Connect As : jirauser / *****
[H] H2 (not for production use)
* [M] MySQL 8.0
[N] MySQL 5.7
[O] Oracle
[P] PostgreSQL
[A] Aurora PostgreSQL 9.6 (DC Only)
[S] SQL Server (MS-SQL)
[X] Return to Main Menu
Database Selection [M]> X
--- Main Menu ---
[H] Configure JIRA Home
[D] Database Selection
[W] Web Server (incl. HTTP/HTTPs configuration)
[A] Advanced Settings
[S] Save and Exit
[X] Exit without Saving
Main Menu> S
Question Order with answers below:
Main Menu:
- D
Database Selection [H]:
- M
Hostname:
- jira.company.com
Port:
- 3306
Database:
- jiradb
Username:
- jirauser
Password:
-
Test Connection ([Y]/N)?:
- Y
Database Selection [M]:
- X
Main Menu>:
- S
The last two questions are where it fails - I have also tried to put the second response under the top questions and it fails as well. If you note - I tried to use some different notation to separate the questions and it did not recognize the differences.
Ansible code:
- name: Set-up DBCONFIG.XML
ansible.builtin.expect:
command: /opt/atlassian/jira/latest/bin/config.sh
responses:
Main Menu:
- D
Database Selection:
- M
Hostname:
- jira.company.com
Port:
- 3306
Database:
- jiradb
Username:
- jirauser
Password:
- <PW>
Test Connection ([Y]/N)?:
- Y
Return to Main Menu:
- X
Save and Exit:
- S
Error received by ansible:
The full traceback is:
File "/tmp/ansible_ansible.builtin.expect_payload_4tipe507/ansible_ansible.builtin.expect_payload.zip/ansible/modules/expect.py", line 130, in wrapped
fatal: [dc2-tl8-jira]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"chdir": null,
"command": "/opt/atlassian/jira/latest/bin/config.sh",
"creates": null,
"echo": false,
"removes": null,
"responses": {
"Database": [
"jiradb"
],
"Database Selection": [
"M"
],
"Hostname": [
"jira.company.com"
],
"Main Menu": [
"D"
],
"Password": [
"<PW>"
],
"Port": [
3306
],
"Return to Main Menu": [
"X"
],
"Save and Exit": [
"S"
],
"Test Connection ([Y]/N)?": [
"Y"
],
"Username": [
"jirauser"
]
},
"timeout": 30
}
},
"msg": "No remaining responses for 'Main Menu', output was 'b'\\r\\n [X] Exit without Saving\\r\\n\\r\\nMain Menu''"
}
How do you address and get the module to answer similar questions or the same question later in the sequence? As this seems to go through until it returns to previous questions and the module doesn't pull the next set of question/answers for the question? Just for clarity - I placed the other responses in the code as defined below and received the following error:
Example of adding the other responses and the error received:
- name: Set-up DBCONFIG.XML
ansible.builtin.expect:
command: /opt/atlassian/jira/latest/bin/config.sh
responses:
Main Menu:
- D
- S
Database Selection:
- M
- X
Hostname:
- jira.company.com
Port:
- 3306
Database:
- jiradb
Username:
- jirauser
Password:
- <PW>
Test Connection ([Y]/N)?:
- Y
error:
The full traceback is:
File "/tmp/ansible_ansible.builtin.expect_payload_rzouxmbc/ansible_ansible.builtin.expect_payload.zip/ansible/modules/expect.py", line 130, in wrapped
fatal: [dc2-tl8-jira]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"chdir": null,
"command": "/opt/atlassian/jira/latest/bin/config.sh",
"creates": null,
"echo": false,
"removes": null,
"responses": {
"Database": [
"jiradb"
],
"Database Selection": [
"M",
"X"
],
"Hostname": [
"jira.company.com"
],
"Main Menu": [
"D",
"S"
],
"Password": [
"<PW>"
],
"Port": [
3306
],
"Test Connection ([Y]/N)?": [
"Y"
],
"Username": [
"jira-test"
]
},
"timeout": 30
}
},
"msg": "No remaining responses for 'Main Menu', output was 'b' Type : H2\\r\\n Instance : (unused)\\r\\n Connect As : sa / (no password)\\r\\n\\r\\n* [H] H2 (not for production use)\\r\\n [M] MySQL 8.0\\r\\n [N] MySQL 5.7\\r\\n [O] Oracle\\r\\n [P] PostgreSQL\\r\\n [A] Aurora PostgreSQL 9.6 (DC Only)\\r\\n [S] SQL Server (MS-SQL)\\r\\n\\r\\n [X] Return to Main Menu''"
}

Related

Google workflow http.get url_encode to Cloud Run function returns 403

I have a CloudRun function that accepts multiple URL inputs and this works fine via cURL from Google Shell, e.g
curl https://myapp.a.run.app/function1/input1/input2
and where input1 is an email address, input2 a string with no spaces, input3 and int and input4 a filename with spaces, e.g
curl https://myapp.a.run.app/function2/input1/input2/input3/input4
I have a Cloud worklow that calls this function in a few steps, building up a URL from previous responses. The calls to the function in steps before are working fine, however when I attempt to call the function via a URL where the email address/filename inputs are text.url_encoded prior, the workflow fails with a 403 error.
- step3_assign_input1:
assign:
- step3_URL: '${"https://myapp.a.run.app/function1/" + step2result.body.field1.field2["b:input1"]}'
- step4_get_input1:
try:
call: http.get
args:
url: ${step3_URL}
result: step4result
retry:
predicate: ${custom_predicate}
max_retries: 10
backoff:
initial_delay: 2
max_delay: 60
multiplier: 2
- step4a_sleep:
call: sys.sleep
args:
seconds: 5
- step5_assign_input2:
assign:
- step5_URL: '${"https://myapp.a.run.app/function2/" + step4result.body.field1.field2["a:input2"]}'
- step6_get_input2:
try:
call: http.get
args:
url: ${step5_URL}
result: step6result
retry:
predicate: ${custom_predicate}
max_retries: 10
backoff:
initial_delay: 2
max_delay: 60
multiplier: 2
- step7a_encode_email:
call: text.url_encode
args:
source: ${args.email}
result: encode_email
- step7b_encode_filename:
call: text.url_encode
args:
source: '${step6result.body.field1.field2["a:FileName"]}'
result: encode_filename
- step8_assign_emailURL:
assign:
- emailURL: '${"https://myapp.a.run.app/email/" + encode_email + "/" + args.type + "/" + args.serial + "/" + encode_filename}'
- step9_get_emailURL:
try:
call: http.get
args:
url: ${emailURL}
result: step9result
retry:
predicate: ${custom_predicate}
max_retries: 10
backoff:
initial_delay: 2
max_delay: 60
multiplier: 2
- returnOutput:
return: ${step9result}
custom_predicate:
params: [e]
steps:
- what_to_repeat:
switch:
- condition: ${e.code in [429, 500, 502, 503, 504]}
return: true
- otherwise:
return: false
From the workflow logs I can see the URL is being constructed as
https://myapp.a.run.app/email/someone%40email.com/String/12345678/THIS%20File%20Name%01.pdf
which if I call via cURL GET in CloudShell it returns with a 200 response code.
In the Workflow logs I get a HTTP server responded with error code 403, and Error: Forbidden\u003c/h1\u003e\n\u003ch2\u003eAccess is forbidden.
{
"insertId": "sl7uy9bd1",
"jsonPayload": {
"activityTime": "2023-01-06T05:44:39Z",
"state": "FAILED",
"#type": "type.googleapis.com/google.cloud.workflows.type.ExecutionsSystemLog",
"failure": {
"source": "main.step9_get_emailURL, line: 76",
"exception": "HTTP server responded with error code 403\nin step \"step9_get_emailURL\", routine \"main\", line: 76: {\"body\":\"\\n\\u003chtml\\u003e\\u003chead\\u003e\\n\\u003cmeta http-equiv=\\\"content-type\\\" content=\\\"text/html;charset=utf-8\\\"\\u003e\\n\\u003ctitle\\u003e403 Forbidden\\u003c/title\\u003e\\n\\u003c/head\\u003e\\n\\u003cbody text=#000000 bgcolor=#ffffff\\u003e\\n\\u003ch1\\u003eError: Forbidden\\u003c/h1\\u003e\\n\\u003ch2\\u003eAccess is forbidden.\\u003c/h2\\u003e\\n\\u003ch2\\u003e\\u003c/h2\\u003e\\n\\u003c/body\\u003e\\u003c/html\\u003e\\n\",\"code\":403,\"headers\":{\"Alt-Svc\":\"h3=\\\":443\\\"; ma=2592000,h3-29=\\\":443\\\"; ma=2592000,h3-Q050=\\\":443\\\"; ma=2592000,h3-Q046=\\\":443\\\"; ma=2592000,h3-Q043=\\\":443\\\"; ma=2592000,quic=\\\":443\\\"; ma=2592000; v=\\\"46,43\\\"\",\"Content-Length\":\"235\",\"Content-Type\":\"text/html; charset=UTF-8\",\"Date\":\"Fri, 06 Jan 2023 05:44:38 GMT\",\"X-Appengine-Country\":\"ZZ\"},\"message\":\"HTTP server responded with error code 403\",\"tags\":[\"HttpError\"]}"
}
},
"resource": {
"type": "workflows.googleapis.com/Workflow",
"labels": {
"workflow_id": "myworkflow",
"location": "australia-southeast1",
"resource_container": "323152299552"
}
},
"timestamp": "2023-01-06T05:44:39.101297442Z",
"severity": "ERROR",
"labels": {
"workflows.googleapis.com/revision_id": "000036-15c",
"workflows.googleapis.com/execution_id": "f2175706-7e8a-4321-916b-487231a10d6b"
},
"logName": "projects/myproject/logs/workflows.googleapis.com%2Fexecutions_system",
"receiveTimestamp": "2023-01-06T05:44:40.026366626Z"
}
If I look at the logs of the CloudRun function, I see successful logs from the earlier steps in the workflow. but, no logs from the step that is failing.
Hopefully someone can provide some insight why this fails via a workflow steps.

Ansible WinRM: Unknown failure when polling update result - attempting to cancel task: pop from empty list

Linux Ubuntu 18
Ansile 2.9.27
Python 3.6
pywinrm 0.4.2
Remote host: Microsoft Windows 10 Enterprise
How to fix the error pop from empty list ?
Ansible playbook code:
- win_updates:
category_names:
- CriticalUpdates
reboot: no
reboot_timeout: 1000
Ansible console log showing Warning:
<1.2.3.4> Running win_updates - round 1
<1.2.3.4> Starting update task
Using module file /somewhere/collections/ansible_collections/ansible/windows/plugins/modules/win_updates.ps1
Pipelining is enabled.
EXEC (via pipeline wrapper)
<1.2.3.4> Starting polling for update results
EXEC (via pipeline wrapper)
[WARNING]: Unknown failure when polling update result - attempting to cancel task: pop from empty list
EXEC (via pipeline wrapper)
EXEC (via pipeline wrapper)
Error printed to console:
IndexError: pop from empty list
fatal: [1.2.3.4]: FAILED! => {
"changed": false,
"failed_update_count": 0,
"filtered_updates": {},
"found_update_count": 0,
"installed_update_count": 0,
"invocation": {
"module_args": {
"accept_list": null,
"category_names": [
"CriticalUpdates"
],
"log_path": null,
"reboot": false,
"reboot_timeout": 1000,
"reject_list": null,
"server_selection": "default",
"skip_optional": false,
"state": "installed",
"use_scheduled_task": false
}
},
"msg": "pop from empty list",
"updates": {}
}
Potential workaround
The code fails in win_updates.py --> offset = int(lines.pop(-1)) , when lines is empty. Is lines = stdout.splitlines() expected to return something always? Otherwise, we can just ignore the pop(-1) when it's empty.

Why doesn't Ansible win_regedit change a Windows registry value?

I'm trying to enable RDP on a Windows 11 machine with Ansible and its win_regedit module. The idea is to set a value that is to change a value from its default of 1 to 0, which enables RDP.
The task in my playbook looks like this:
- name: Set Registry key
ansible.windows.win_regedit:
path: 'HKLM:\System\CurrentControlSet\Control\Terminal Server'
name: 'fDenyTSConnections'
value: 0
type: dword
However, when I run it, Ansible doesn't change anything and reports it as OK. -vvv output for ansible-playbook looks like this (I have verified the value is set to '1', i.e. the undesired state):
ok: [win11test] => {
"changed": false,
"data_changed": false,
"data_type_changed": false,
"invocation": {
"module_args": {
"data": null,
"delete_key": true,
"hive": null,
"name": "0",
"path": "HKLM:\\System\\CurrentControlSet\\Control\\Terminal Server",
"state": "present",
"type": "dword",
"value": 0
}
}
}
I'm a bit stumped here. There's nothing in the docs to suggest I'm doing anything wrong.
The WinRM connection to the host seems to allow this just fine - I can run a PSSession from a Windows host, using the same credentials, and run the equivalent Powershell just fine. The code is:
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -value 0
Anyone got an idea why Ansible thinks there's nothing to do here, and what I need to change about my task?
Not an answer to this specific question, but i found this on Google while researching my similar problem, as might others.
If the name value is surrounded by { and } like a lot of keys are, its essential to double-quote the name, otherwise Ansible tries to expand it as a variable, and it hits the wrong key.
- name: Show My Computer (1)
ansible.windows.win_regedit:
path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu
name: "{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
data: 0
type: dword
is good.
- name: Show My Computer (1)
ansible.windows.win_regedit:
path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu
name: {20D04FE0-3AEA-1069-A2D8-08002B30309D}
data: 0
type: dword
is bad.

JSNAPY: Is there a way to test on xpath node attributes

I am trying to determine how to test on the node attributes that junos occasionally uses. In this particular case, I want to find all BGP sessions that are down between 20w and 1y. The seconds value is contained in the node attribute, but I have not been able to figure out how to access it for the test.
I have tried various methods using the entire explicit xpath, all the way to what I have below in the code.
Here is the xpath I am trying to access (edited for brevity):
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/18.2R3/junos">
<bgp-information xmlns="http://xml.juniper.net/junos/18.2R3/junos-routing">
<bgp-peer junos:style="terse" heading="Peer AS InPkt OutPkt OutQ Flaps Last Up/Dwn State|#Active/Received/Accepted/Damped...">
<elapsed-time junos:seconds="263788">3d 1:16:28</elapsed-time>
</bgp-peer>
</bgp-information>
</rpc-reply>
test_bgp_summ:
- rpc: get-bgp-summary-information
- iterate:
xpath: /bgp-information/bgp-peer
id: ./peer-address
tests:
- in-range: //#junos:seconds, 12096000, 31449600
err: ""
info: 'Peer session <{{id_0}}> is likely stale'
You need to include the elapsed-time node in your test:
show_bgp_sum:
- command: show bgp summary
- iterate:
xpath: '//bgp-information/bgp-peer'
id: ./peer-address
tests:
- exists: elapsed-time/#seconds
err: "elpased-time doesn't exist"
info: "Elapsed-time is: <{{post['elapsed-time/#seconds']}}>"
and the output:
"passed": [
{
"actual_node_value": "1309804",
"id": {
"./peer-address": "10.10.12.100"
},
"message": "Elapsed-time is: <1309804>",
"post": {
"elapsed-time/#seconds": "1309804"
},
"pre": {
"elapsed-time/#seconds": "1309802"
}
},

How do i know the service status in ansible?

In my ansible coding i want to know the status of the service like service httpd status (service is runngin or not) the result would be store in to variable. Using that status i will use some other code in ansible.
I am using ansible service module there is no option for status. If i use the shell module i got this warning
[WARNING]: Consider using service module rather than running service
so is it any other module doing to get service status?
No, there is no standard module to get services' statuses.
But you can suppress warning for specific command task if you know what are you doing:
- command: service httpd status
args:
warn: false
I've posted a quick note about this trick a while ago.
You can use the service_facts module.
For example, say I want to see the status of Apache.
- name: Check for apache status
service_facts:
- debug:
var: ansible_facts.services.apache2.state
The output is:
ok: [192.168.blah.blah] => {
"ansible_facts.services.apache2.state": "running"
}
If you would like to see all of them, you can do that by just going two levels up in the array:
var: ansible_facts.services
The output will list all the services, and will look like this (truncated for the sake of brevity):
"apache2": {
"name": "apache2",
"source": "sysv",
"state": "running"
},
"apache2.service": {
"name": "apache2.service",
"source": "systemd",
"state": "running"
},
"apparmor": {
"name": "apparmor",
"source": "sysv",
"state": "running"
},
etc,
etc
I am using Ansible 2.7. Here are the docs for that module: Click here
here is an example of starting a service and then checking status using service facts, in my example you have to register the variable then output it using debug var and pointing to the correct format in the json chain resulting output:
## perform start service for alertmanager
- name: Start service alertmanager if not started
become: yes
service:
name: alertmanager
state: started
## check to see the state of the alertmanager service status
- name: Check status of alertmanager service
service_facts:
register: service_state
- debug:
var: service_state.ansible_facts.services["alertmanager.service"].state
Hopefully service: allow user to query service status #3316 will be merged into the core module soon.
You can patch it by hand using this diff to system/service.py
Here's my diff using ansible 2.2.0.0. I've run this on my mac/homebrew install and it works for me.
This is the file that I edited: /usr/local/Cellar/ansible/2.2.0.0_2/libexec/lib/python2.7/site-packages/ansible/modules/core/system/service.py
## -36,11 +36,12 ##
- Name of the service.
state:
required: false
- choices: [ started, stopped, restarted, reloaded ]
+ choices: [ started, stopped, status, restarted, reloaded ]
description:
- C(started)/C(stopped) are idempotent actions that will not run
- commands unless necessary. C(restarted) will always bounce the
- service. C(reloaded) will always reload. B(At least one of state
+ commands unless necessary. C(status) would report the status of
+ the service C(restarted) will always bounce the service.
+ C(reloaded) will always reload. B(At least one of state
and enabled are required.)
sleep:
required: false
## -1455,7 +1456,7 ##
module = AnsibleModule(
argument_spec = dict(
name = dict(required=True),
- state = dict(choices=['running', 'started', 'stopped', 'restarted', 'reloaded']),
+ state = dict(choices=['running', 'started', 'stopped', 'status', 'restarted', 'reloaded']),
sleep = dict(required=False, type='int', default=None),
pattern = dict(required=False, default=None),
enabled = dict(type='bool'),
## -1501,6 +1502,9 ##
else:
service.get_service_status()
+ if module.params['state'] == 'status':
+ module.exit_json(state=service.running)
+
# Calculate if request will change service state
service.check_service_changed()

Resources