send multiline form with ansible uri module - ansible

I'm trying to upload a multi-line file to a appdynamics controller, using the ansible uri module. Any advice?
As you'll notice in the snippets, I'm brand new to Ansible...
It works fine with shell: curl, but I can't seem to get the output correct for a more structured play.
Works
- name: import health rule xml via curl
shell: "curl -i -X POST {{ APPD_HEALTH_RULE_URL }}/{{ APPD_APPLICATIAON_ID }}?overwrite={{ OVERWRITE_EXISTING_RULE }} -H {{ APPD_AUTH_TOKEN }} -F file=#{{ WORKSPACE }}/infrastructure_health_rule_template.xml"
register: health_rule
Doesn't work
- name: import health rule to application
uri:
url: "{{ APPD_HEALTH_RULE_URL }}/{{ APPD_APPLICATIAON_ID }}?overwrite={{ OVERWRITE_EXISTING_RULE }}"
method: POST
headers:
Authorization : "{{ APPD_TOKEN }}"
Content-Type : "multipart/form-data"
return_content : yes
follow_redirects : all
body_format : raw
body : msg="{{lookup('file', '{{ WORKSPACE }}/infrastructure_health_rule_template.xml') }}"
status_code:
- 100
- 200
- 201
- 202
- 300
- 301
- 302
- 307
register: health_rule
Expected outcome - I'm able to successfully import the health rule to AppD
Actual - I get a 200 response, and nothing happens.
Response:
ok: [localhost] => {
"age": "0",
"changed": false,
"connection": "close",
"content": "the request was rejected because no multipart boundary was found \n",
"cookies": {
"JSESSIONID": "NUMBERS & STUFF"
},
"cookies_string": "JSESSIONID=NUMBERS & STUFF",
"date": "Wed, 25 Sep 2019 20:25:07 GMT",
"elapsed": 0,
"invocation": {
"module_args": {
"attributes": null,
"backup": null,
"body": "<health-rules controller-version=\"VERSION HERE\">\n <health-rule>\n <name>Disk_Space_too_low</name>\n <type>INFRASTRUCTURE</type>\n <description/>\n <enabled>True</enabled>\n <is-default>false</is-default>\n <always-enabled>true</always-enabled>\n <duration-min>35</duration-min>\n <wait-time-min>35</wait-time-min>\n <affected-entities-match-criteria>\n <affected-infra-match-criteria>\n <type>NODES</type>\n <node-match-criteria>\n <type>CUSTOM</type>\n <match-type>STARTSWITH</match-type>\n <match-pattern>i-</match-pattern>\n <inverse>True</inverse>\n <node-meta-info-match-criteria/>\n <vm-sys-properties/>\n <env-properties/>\n </node-match-criteria>\n </affected-infra-match-criteria>\n </affected-entities-match-criteria>\n <critical-execution-criteria>\n <entity-aggregation-scope>\n <type>ANY</type>\n <value>0</value>\n </entity-aggregation-scope>\n <policy-condition>\n <type>leaf</type>\n <display-name>Hardware Resources|Volumes|Used %</display-name>\n <condition-value-type>ABSOLUTE</condition-value-type>\n <condition-value>90.0</condition-value>\n <operator>GREATER_THAN</operator>\n <condition-expression/>\n <use-active-baseline>False</use-active-baseline>\n <trigger-on-no-data>False</trigger-on-no-data>\n <metric-expression>\n <type>leaf</type>\n <function-type>VALUE</function-type>\n <value>0</value>\n <is-literal-expression>False</is-literal-expression>\n <display-name></display-name>\n <metric-definition>\n <type>LOGICAL_METRIC</type>\n <logical-metric-name>Hardware Resources|Volumes|Used (%)</logical-metric-name>\n </metric-definition>\n </metric-expression>\n </policy-condition>\n </critical-execution-criteria>\n <warning-execution-criteria>\n <entity-aggregation-scope>\n <type>ANY</type>\n <value>0</value>\n </entity-aggregation-scope>\n <policy-condition>\n <type>leaf</type>\n <display-name>Hardware Resources|Volumes|Used %</display-name>\n <condition-value-type>ABSOLUTE</condition-value-type>\n <condition-value>80.0</condition-value>\n <operator>GREATER_THAN</operator>\n <condition-expression/>\n <use-active-baseline>False</use-active-baseline>\n <trigger-on-no-data>False</trigger-on-no-data>\n <metric-expression>\n <type>leaf</type>\n <function-type>VALUE</function-type>\n <value>0</value>\n <is-literal-expression>False</is-literal-expression>\n <display-name></display-name>\n <metric-definition>\n <type>LOGICAL_METRIC</type>\n <logical-metric-name>Hardware Resources|Volumes|Used (%)</logical-metric-name>\n </metric-definition>\n </metric-expression>\n </policy-condition>\n </warning-execution-criteria>\n</health-rule>\n</health-rules>",
"body_format": "raw",
"client_cert": null,
"client_key": null,
"content": null,
"creates": null,
"delimiter": null,
"dest": null,
"directory_mode": null,
"follow": false,
"follow_redirects": "all",
"force": false,
"force_basic_auth": false,
"group": null,
"headers": {
"Authorization": "Bearer REALLY LONG STRING OF CHARACTERS",
"Content-Type": "multipart/form-data"
},
"http_agent": "ansible-httpget",
"method": "POST",
"mode": null,
"owner": null,
"regexp": null,
"remote_src": null,
"removes": null,
"return_content": true,
"selevel": null,
"serole": null,
"setype": null,
"seuser": null,
"src": null,
"status_code": [
100,
200,
201,
202,
300,
301,
302,
307
],
"timeout": 30,
"unix_socket": null,
"unsafe_writes": null,
"url": "####### URL #######",
"url_password": null,
"url_username": null,
"use_proxy": true,
"validate_certs": true
}
},
"msg": "OK (unknown bytes)",
"redirected": false,
"server": "AppDynamics",
"set_cookie": "JSESSIONID=NUMBERS & STUFF; Path=/controller; HttpOnly;Secure",
"status": 200,
"transfer_encoding": "chunked",
"url": "####### URL #######,
"via": "1.1 varnish",
"x_content_type_options": "Nosniff",
"x_frame_options": "SAMEORIGIN",
"x_varnish": "1299636501",
"x_xss_protection": "1; mode=block"
}
META: ran handlers
META: ran handlers
PLAY RECAP ***************************************************************************************************************
localhost : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Not sure if it is still needed. With ansible v2.10 this is possible. What you need is this:
- name: import health rule to application
uri:
url: "{{ APPD_HEALTH_RULE_URL }}/{{ APPD_APPLICATIAON_ID }}?overwrite={{ OVERWRITE_EXISTING_RULE }}"
method: POST
headers:
Authorization : "{{ APPD_TOKEN }}"
Content-Type : "multipart/form-data"
return_content : yes
follow_redirects : all
body_format : form-multipart
body :
file : "{{lookup('file', '{{ WORKSPACE }}/infrastructure_health_rule_template.xml') }}"
filename : infrastructure_health_rule_template.xml
mime_type : application/xml
status_code:
- 100
- 200
- 201
- 202
- 300
- 301
- 302
- 307
register: health_rule
Notice the body_format: form-multipart and the body structure. Check documentation examples. More specific the example: Upload a file via multipart/form-multipart

Related

ansible problem with single quote, double quote in uri body

I have a problem with the correct syntax to address an API with absolutely don't understands any json arguments.
In the body must be exactly one value in this form '["XXXX"]' so that it works.
- uri:
url: "{{ AssociatePolicies_url }}"
method: POST
return_content: yes
validate_certs: no
body_format: form-urlencoded
body:
apiKey: "{{ apiKey }}"
ASSIGNED_POLICIES: '["XXXX"]'
RESOURCEID: "{{ resourceId }}"
RUNCOMPCHECK_STATUS: true
headers:
Content-Type: "application/x-www-form-urlencoded;charset=UTF-8"
but when I pass the value now as variable i don't get it in the correct form
---
- name: Post to API
hosts: KingKong
connection: local
gather_facts: no
vars:
policygroup:
- XXXX
# - YYYY
# - ZZZZ
tasks:
- uri:
url: "{{ AssociatePolicies_url }}"
method: POST
return_content: yes
validate_certs: no
body_format: form-urlencoded
body:
apiKey: "{{ apiKey }}"
ASSIGNED_POLICIES: "'["{{ item }}"]'"
RESOURCEID: "{{ resourceId }}"
RUNCOMPCHECK_STATUS: true
headers:
Content-Type: "application/x-www-form-urlencoded;charset=UTF-8"
with_items: "{{ policygroup }}"
Is the response: Error while parsing ASSIGNED_POLICIES json data
After various approaches I don't get any closer to the result:
ASSIGNED_POLICIES: "\'[{{ item }}]\'" is the format '[XXXX]
ASSIGNED_POLICIES: \'["{{ item }}"]\' is the format \\'[\"XXXX\"]\\'
ASSIGNED_POLICIES: "\'[\"{{ item }}\"]\'" is the format '[\"XXXX\"]'
ASSIGNED_POLICIES: "\'["{{ item }}"]\'" playbook error
ASSIGNED_POLICIES: "\'[{{ \" }}{{ item }}{{\"}}]\'" is the format '[ }}{{ item }}{{]'"}]
where I get almost closer to the format is:
ASSIGNED_POLICIES: "\'['{{ item }}']\'" is the format "'['XXXX']'"
but with single quote in front anb ack of XXXX but there must be double quote.
Maybe one of you has a creative idea
I have corrected my source code above and post below what I get back as a response.
What i see in see response:
"content": "{\"error\":{\"message\":\"Error while parsing ASSIGNED_POLICIES json data.\",\"errorcode\":\"JSON_PARSE_ERROR\"}}\n"
and the wrong format:
"ASSIGNED_POLICIES": "'[XXXX]'"
It is missing double quote in front and behind XXXX.
this must be the correct post
"ASSIGNED_POLICIES": "'["XXXX"]'"
.
{
"changed": false,
"_ansible_verbose_always": true,
"result_4": {
"msg": "All items completed",
"changed": false,
"results": [
{
"content_length": "104",
"status": 200,
"cookies": {
"opmcsrfcookie": "192d408c-be9b-42f7-985b-56360c06fdd7"
},
"set_cookie": "opmcsrfcookie=192d408c-be9b-42f7-985b-56360c06fdd7;path=/;Secure;priority=high",
"vary": "Accept-Encoding",
"elapsed": 0,
"msg": "OK (104 bytes)",
"content_type": "application/json;charset=UTF-8",
"date": "Wed, 16 Mar 2021 16:22:55 GMT",
"x_frame_options": "deny",
"ansible_loop_var": "item",
"x_xss_protection": "1",
"url": "https://https://AssociatePolicies_url",
"changed": false,
"x_content_type_options": "nosniff",
"connection": "close",
"content": "{\"error\":{\"message\":\"Error while parsing ASSIGNED_POLICIES json data.\",\"errorcode\":\"JSON_PARSE_ERROR\"}}\n",
"failed": false,
"json": {
"error": {
"errorcode": "JSON_PARSE_ERROR",
"message": "Error while parsing ASSIGNED_POLICIES json data."
}
},
"item": 301,
"invocation": {
"module_args": {
"directory_mode": null,
"force": false,
"remote_src": null,
"status_code": [
200
],
"follow": false,
"owner": null,
"body_format": "form-urlencoded",
"client_key": null,
"group": null,
"use_proxy": true,
"unix_socket": null,
"unsafe_writes": null,
"setype": null,
"content": null,
"serole": null,
"follow_redirects": "safe",
"return_content": true,
"client_cert": null,
"body": {
"RUNCOMPCHECK_STATUS": true,
"RESOURCEID": "abcde",
"apiKey": "just_a_Key",
"ASSIGNED_POLICIES": "'[XXXX]'"
},
"url_username": null,
"src": null,
"dest": null,
"selevel": null,
"force_basic_auth": false,
"removes": null,
"http_agent": "ansible-httpget",
"regexp": null,
"url_password": null,
"url": "https://AssociatePolicies_url",
"validate_certs": false,
"seuser": null,
"method": "POST",
"creates": null,
"headers": {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
"delimiter": null,
"mode": null,
"timeout": 30,
"attributes": null,
"backup": null
}
},
"redirected": false,
"cookies_string": "opmcsrfcookie=192d408c-be9b-42f7-985b-56360c06fdd7"
}
]
},
"_ansible_no_log": false
}

Ansible Parse for value from REST API Response Header

I must be missing something obvious. I need to extract the value from one key in the response header of a GET API call.
I am trying to get the value of client_version but cant seem to pull that data out.
Anisble version: 2.4.2.0
playbook:
- name: Get test client version
uri:
url: "{{ current_client_version_url }}"
method: GET
header:
Content-Type: "application/json"
register: resp
- debug: msg={{ resp }}
Output:
{
"msg": {
"content_length": "180",
"status": 200,
"cookies": {},
"x_ratelimit_reset": "1",
"json": {
"defaultContainerAlias": "_default",
"exchangeContainerAlias": null,
"hasContainersEnabled": true,
"hasExchangeEnabled": false,
"hasTargetedOffers": false,
"autoDeleteItemReferences": false
},
"url": "https://some.url.goes.here.com/v1/subdir/metadata",
"changed": false,
"vary": "Accept-Encoding, User-Agent",
"x_envoy_upstream_service_time": "3",
"failed": false,
"connection": "close",
"content_type": "application/json;charset=utf-8",
"client_version": "1a2b3c4d5f",
"date": "Tue, 04 Aug 2020 22:34:34 GMT",
"redirected": false,
"x_ratelimit_remaining": "197",
"msg": "OK (180 bytes)"
},
"changed": false,
"_ansible_verbose_always": true,
"_ansible_no_log": false
}
I assumed it would be a regular Ansible output and have tried:
resp.msg.client_version
resp.msg['client_version']
resp.msg[client_version]
When I reference resp.msg in the debug statement, I just get:
"msg": "OK (180 bytes)"
which makes no sense to me...
Help is appreciated.
figured it out solution is resp.client_version. it made sense funny enough once I pasted here. there is another key msg.

CentOS/Ansible - How to fix an error "_ssl.c:602: The handshake operation timed out"

I am running an API login task for network device and sometimes I get this error: "_ssl.c:602: The handshake operation timed out". Sometimes it runs and sometimes it gives a handshake error. I recently added RADIUS authentication to network device when using SSH, but API still using local credentials. But would that cause the problem?
Module I am using is the basic URI module and the task looks following:
- name: Login to switch using API
uri:
url: "https://{{ ansible_host }}/rest/v4/login-sessions"
method: POST
headers:
Accept: "application/json"
Content-Type: "application/json"
body: {"userName": "{{ ansible_user }}", "password": "{{ ansible_password }}"}
body_format: json
validate_certs: no
status_code: 201
register: switch_session
Error I am getting looks following:
fatal: [test_switch]: FAILED! => {
"changed": false,
"content": "",
"elapsed": 30,
"invocation": {
"module_args": {
"attributes": null,
"backup": null,
"body": {
"password": "<PASSWORD>",
"userName": "<USERNAME>"
},
"body_format": "json",
"client_cert": null,
"client_key": null,
"content": null,
"creates": null,
"delimiter": null,
"dest": null,
"directory_mode": null,
"follow": false,
"follow_redirects": "safe",
"force": false,
"force_basic_auth": false,
"group": null,
"headers": {
"Accept": "application/json",
"Content-Type": "application/json"
},
"http_agent": "ansible-httpget",
"method": "POST",
"mode": null,
"owner": null,
"regexp": null,
"remote_src": null,
"removes": null,
"return_content": false,
"selevel": null,
"serole": null,
"setype": null,
"seuser": null,
"src": null,
"status_code": [
"201"
],
"timeout": 30,
"unix_socket": null,
"unsafe_writes": null,
"url": "https://<IP_ADDR>/rest/v4/login-sessions",
"url_password": null,
"url_username": null,
"use_proxy": true,
"validate_certs": false
}
},
"msg": "Status code was -1 and not [201]: Request failed: <urlopen error ('_ssl.c:602: The handshake operation timed out',)>",
"redirected": false,
"status": -1,
"url": "https://<IP_ADDR>/rest/v4/login-sessions"

Ansible Symbolic Link Task Role Failure

I am new to ansible and executing the following ansible task:
- name: Create symbolic links
file:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: "{{ jboss_usr }}"
group: "{{ jboss_grp }}"
state: link
with_items:
- { src: "/apps/etc/jboss", dest: "/etc/jboss" }
- { src: "/apps/var/log/jboss", dest: "/var/log/jboss" }
And I got the following error:
2018-12-21 21:27:23,469 p=15185 u=ex_sam | failed: [hostname.x] (item={u'dest': u'/etc/jboss', u'src': u'/apps/etc/jboss'}) => {
"changed": false,
"invocation": {
"module_args": {
"attributes": null,
"backup": null,
"content": null,
"delimiter": null,
"dest": "/etc/jboss",
"diff_peek": null,
"directory_mode": null,
"follow": true,
"force": true,
"group": "jboss",
"mode": null,
"original_basename": null,
"owner": "jboss",
"path": "/etc/jboss",
"recurse": false,
"regexp": null,
"remote_src": null,
"selevel": null,
"serole": null,
"setype": null,
"seuser": null,
"src": "/apps/etc/jboss",
"state": "link",
"unsafe_writes": null,
"validate": null
}
},
"item": {
"dest": "/etc/jboss-as",
"src": "/apps/etc/jboss"
},
"msg": "Error while linking: [Errno 13] Permission denied",
"path": "/etc/jboss-as",
"state": "absent"
}
I am trying to find out why the symbolic link creation failed.
I read the following:
https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#id6
I says the "changed" attribute is a boolean indicating if the task had to make changes.
But, there are lots of null parameters in the invocation:module_args elements of the json
Does that mean the values are really “null” or they are being set to a default value?
I have looked into the ansible documentation and I am not sure if the invocation:module_args null values are representative of the outcome of the trying to create the symbolic link i.e. are the null input or output of executing the tasks.
I think some of the nulls are defaults, but will appreciate some helpful comments on the possible relation between the json returned in my ansible error log and the actual "Error while linking: [Errno 13] Permission denied".
Thanks all for you anticipated help.
I think, is the permissions on /etc. So probably you need to add the option:
become: true
To your task.

Make ansible run a task in a playbook multiple times based on variables

I am trying to use the Ansible URI Module to log into multiple webpages and check the environments are up and working.
At the moment, i want it to just log into 2 webpages (Peoplesoft envs), but i would like a vars file that i can add to each time i want to to check a new page.
This is what i have so far, but it doesnt seem to log into both pages, just 1 of them....any help woould be appreciated.
Playbook -
---
- name: Run Selenium Test Scripts
hosts: local
vars_files:
- /etc/ansible/uri_module/vars_uri.yml
tasks:
- name: Installing URI dependancy
yum: name=python-httplib2.noarch state=present
- name: Log into Webpage
uri:
url: http://{{appserver}}:{{port}}/{{dbname}}/signon.html
method: POST
body: "name={{userid}}&password={{password}}&enter=Sign%20in"
with_file: /etc/ansible/uri_module/vars_uri.yml
Vars file
---
- { name: 'dog', appserver: 'st1920', port: '8100', dbname: 'dbdog', userid: 'user', password: 'pass' }
- { name: 'cat', appserver: 'st1921', port: '8300', dbname: 'dbcat', userid: 'user', password: 'pass' }
Output with -vvvv
ok: [local] => {"changed": false, "content_language": "en-US", "content_length": "1831", "content_type": "text/html", "date": "Thu, 13 Oct 2016 11:45:23 GMT", "invocation": {"module_args": {"backup": null, "body": "name=user&password=pass&enter=Sign%20in", "body_format": "raw", "content": null, "creates": null, "delimiter": null, "dest": null, "directory_mode": null, "follow": false, "follow_redirects": "safe", "force": null, "force_basic_auth": false, "group": null, "method": "POST", "mode": null, "owner": null, "password": null, "regexp": null, "remote_src": null, "removes": null, "return_content": false, "selevel": null, "serole": null, "setype": null, "seuser": null, "src": null, "status_code": [200], "timeout": 30, "url": "http://st1921:8300/dbcat/signon.html", "user": null, "validate_certs": true, "with_file": "/etc/ansible/uri_module/vars_uri.yml"}, "module_name": "uri"}, "last_modified": "Wed, 13 Aug 2014 11:42:42 GMT", "redirected": false, "server": "WebSphere Application Server/7.0", "status": 200}
Using the vars file, i want it to log into the dog environment, tell me its there, log into the cat environment, tell me its there. Then if i have a horse, frog, or what ever environment, i can keep adding to the vars file without adding to or changing the playbook. At the moment it only logs into cat and i dont know why.
Have i goen down the right route with this? Is there a better way of doing it? With it not giving an error, im struggling to figure out the issue!
Thanks.
I don't think it is possible to use with_file like that.
It would be cleaner to store the vars_uri dictonaries in a list like this:
---
vars_uri:
- { name: 'dog', appserver: 'st1920', port: '8100', dbname: 'dbdog', userid: 'user', password: 'pass' }
- { name: 'cat', appserver: 'st1921', port: '8300', dbname: 'dbcat', userid: 'user', password: 'pass' }
and loop over it with with_items like this:
---
# Run Selenium Test Scripts
hosts: local
vars_files:
- /etc/ansible/uri_module/vars_uri.yml
tasks:
- name: Installing URI dependancy
yum: name=python-httplib2.noarch state=present
- name: Log into Webpage
uri:
url: http://{{ item.appserver }}:{{ item.port }}/{{ item.dbname }}/signon.html
method: POST
body: "name={{ item.userid }}&password={{ item.password }}&enter=Sign%20in"
with_items: vars_uri

Resources