I'm using the Ansible uri module to make a PUT API call and using all files in a directory as parameters.
I have a list of files in a directory, and I want to use the name and the content of each file in the API call
First of all i tried to list all files.
- name: "Find pipeline files in folder"
find:
paths: "/app/pipelines"
patterns: "pipeline-*.json"
file_type: "file"
register: pipe_files
- debug:
var: pipe_files
Then I want to make a loop on each file in the directory and call the API
- name: PUT PIPE
uri:
method: PUT
headers:
Content-Type: "application/json"
url: "https://api_url/**FILE_NAME**"
user: "user"
password: "user_pass"
body_format: json
body: "{{ lookup('file','/app/pipelines/**FILE_NAME.json**') }}"
validate_certs: no
force_basic_auth: yes
validate_certs: no
return_content: yes
register: pipeline_created
until: pipeline_created.status == 200
When I deploy the content, I don't have the exact filename, how can I make the loop on each file to call the API?
Best regards,
Thanks in advance.
pipe_files is a register from a find task. You can have a look at returned values in the find module documentation. You can also examine your debug task output to better get accustomed with the content of the variable.
Anyway. The list of file objects returned will be in pipe_files.files. Each element is a dict where the information you need is in the path key.
You may test with
- name: PUT pipeline
uri:
method: PUT
headers:
Content-Type: "application/json"
url: "https://api_url/{{ item.path | basename }}" # depends on input list content
user: "user"
password: "user_pass"
body_format: json
body: "{{ lookup('file', item.path) }}" # content
validate_certs: no
force_basic_auth: yes
validate_certs: no
return_content: yes
until: pipeline_created.status == 200
loop: "{{ pipe_files.files }}"
register: pipeline_created # result will become a list
Related
I have a list of items services and each needs to be wrapped in single quotes to configure some parameters.
The simplest solution I saw posted was:
"{{services | match('quote') | join(' OR ')}}"
This only wrapped the first element in the list in a single quote but not the remaining.
I also tried some variations of match regex.
Finally I tried adding the single quote manually in the data source, then joining. The first element retained the single quotes but subsequent were stripped off? What is going on here?
Right now they are static from the inventory
i.e.:
---
inventory:
hosts:
host1:
procs:
- splunkd.*
services:
- 'some service name'
- 'another service name'
- 'SplunkForwarder'
I need the end result to be
"Name='some service name' OR Name='another service name'"
Currently with the services single quoted in variable the quotes are stripped or ignored.
Result
Name=some service or Name=another service
you could cut your problem by using loop:
tasks:
- name: set var
set_fact:
result: "{{ result | d('') + _i + _o }}"
loop: "{{ services }}"
loop_control:
extended: yes
vars:
_i: "Name='{{ item }}'"
_o: "{{ '' if ansible_loop.last else ' OR ' }}"
- name: display result
debug:
var: result
result:
ok: [localhost] => {
"result": "Name='some service name' OR Name='another service name' OR Name='SplunkForwarder'"
}
with your vars:
- name: Join services
set_fact:
joined_services: "{{ joined_services | d('') + service + serviceAppend }}"
loop: "{{ services }}"
loop_control:
extended: yes
vars:
service: "'{{ item }}'"
serviceAppend: "{{ '' if ansible_loop.last else ' OR ' }}"
I try to add a new key password, facing the issue with the API. The key is successfully created. But, when is used is not good value.
I try to generate the key with Postman, and the key is created but the value is not correct. When I use the same value manually on the interface then it works fine.
I deleted before the key (manually)
postman:
curl --location --request POST 'https://rundeck.dev.xxxxxx.com/api/11/storage/keys/project_name/gitlab?authtoken=FdMORu02flT2R5zI' \
--header 'Content-type: application/x-rundeck-data-password' \
--header 'Cookie: AWSALB=D6Kpid4U/o7uHy9G0Pg40uvILs1toq367tPzPiCskEha7YGM3eCJldNnKyMFYBrkwOXIyvVmKAsIe9yIRm/8xOX/0mj4LIRy2wMl3qYpOvXKw3x9e+rXnjd8gEjX; AWSALBCORS=D6Kpid4U/o7uHy9G0Pg40uvILs1toq367tPzPiCskEha7YGM3eCJldNnKyMFYBrkwOXIyvVmKAsIe9yIRm/8xOX/0mj4LIRy2wMl3qYpOvXKw3x9e+rXnjd8gEjX' \
--data-raw 'XKmB1wkjsdfikjkHkKwCEW'
I try to add SCM with the key generated but still is not working. However, when I create manually the key with the same name and value the SCM import is working.
I have the same error with ansible with URI.
I deleted before the key (manually)
I create a playbook to access rundeck API
- name: "Create Keys {{ project_name }} - gitlab"
uri:
url: "{{ RD_URL }}{{ API_11 }}/storage/keys/{{ project_name }}/gitlab?authtoken={{ RD_TOKEN }}"
method: POST
body_format: raw
validate_certs: no
status_code: [201, 409]
return_content: true
headers:
Content-Type: application/x-rundeck-data-password
X-Rundeck-Auth-Token: "{{ RD_TOKEN }}"
body: '{{ GITLAB_TOKEN }}'
You can create the password via API 40 and Rundeck 3.4.9 with the following call:
#!/bin/sh
# protocol
protocol="http"
# basic rundeck info
rdeck_host="localhost"
rdeck_port="4440"
rdeck_api="40"
rdeck_token="hcFPFbJHFIqerwaRsWtuhPnPAIUoY4Kt"
# api call
curl --location --request POST "$protocol://$rdeck_host:$rdeck_port/api/$rdeck_api/storage/keys/mypass" \
--header "X-Rundeck-Auth-Token: $rdeck_token" \
--header "Content-Type: application/x-rundeck-data-password" \
--data-raw "12345"
Also, I created a Job example to test the password content:
- defaultTab: nodes
description: ''
executionEnabled: true
id: 5658bb13-f9e9-494b-839c-d18f25057a4e
loglevel: INFO
name: HelloWorld
nodeFilterEditable: false
options:
- name: opt1
secure: true
storagePath: keys/mypass
valueExposed: true
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- exec: echo ${option.opt1}
keepgoing: false
strategy: node-first
uuid: 5658bb13-f9e9-494b-839c-d18f25057a4e
Running the job, you can see the password value.
Also tested using the SCM config.
So, make sure that you're pointing to the right key in your SCM config and ensure to use the latest API version (40 at this moment) in your API Call.
Hello I am trying to run a PUT API call via Ansible URI module for a particular API Endpoint in my application, using a dictionary that contains the json files and that is defined as:
example: { 'example1' : 'v1', 'example2': 'v2''}
- name: Update existing
block:
- name: update existing
uri:
url: "{{url}}/api/{{item.key}}/"
method: PUT
body: "{{ lookup('file', 'example/{{item.key}}/{{item.value}}.json') }}"
status_code: 200
body_format: json
headers:
Content-Type: "application/json"
Authorization: "Token {{ token.json.token }}"
with_dict: "{{ example }}"
register: result
For the PUT api call, this api endpoint will fail is the {{item.key}} does not exist, e.g. if
"{{url}}/api/{{item.key}}/" endpoint does not exist, hence it will give a 4xx error.
Given the task fails and I get a 4xx error when the api endpoint for the item does not exist, I want to run a POST command for that same json file.
How can I do this in ansible, to retry a task that failed but only specifically for that {{item.key}} and {{item.value}} in dictionary?
or
Is there a better way to do this to retry a failed PUT with a POST command
I want to use the ansible URI module
Thanks!
You can ignore the error case and then loop through result.results with filtering to keep only errors. You can have access to the original item with item.item:
- name: update existing with PUT
uri:
url: "{{url}}/api/{{item.key}}/"
method: PUT
body: "{{ lookup('file', 'example/{{item.key}}/{{item.value}}.json') }}"
status_code:
- 200
- 404 # supposing it's the "normal" error case
body_format: json
headers:
Content-Type: "application/json"
Authorization: "Token {{ token.json.token }}"
loop: "{{ example | items2dict }}"
register: result
- name: update existing with POST
uri:
url: "{{url}}/api/{{item.item.key}}/"
method: POSTT
body: "{{ lookup('file', 'example/{{item.item.key}}/{{item.item.value}}.json') }}"
status_code: 200
body_format: json
headers:
Content-Type: "application/json"
Authorization: "Token {{ token.json.token }}"
loop: "{{ result.results | rejectattr('status', '200') }}" # filter out 200 status from previous task
I have a simple Ansible playbook to
Fetch a database connection config from an RestAPI,
Extract the config object from the payload,
Using the config JSON (as request body) to create a PUT request to another RestAPI.
At the 3rd stage I found that the database username and password combination is wrong. Later, while I print the outputs, I have found that the password has been replaced with a string named "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER".
After some googling, I found that this is a security feature by Ansible. Unfortunately, I haven't found any configuration or something like this to disable this feature. Is it possible to disable this feature? Or any other workaround?
---
- name: my-playbook
gather_facts: no
hosts: all
vars_files:
- secret
tasks:
- name: Fetch the config payload from the API
uri:
url: "{{get_config}}"
method: GET
user: "{{username}}"
password: "{{password}}"
validate_certs: no
return_content: yes
status_code: 200
body_format: json
register: config
- name: Extract the config object
set_fact:
config_raw: "{{ config.json | json_query(jmesquery) }}"
vars:
jmesquery: '{{name}}.config'
- name: print the config
debug:
msg: "{{config_raw}}"
- name: Creating object using config
uri:
url: "{{create_ocject}}"
method: PUT
user: "{{username}}"
password: "{{password}}"
validate_certs: no
body: "{{config_raw}}"
body_format: json
return_content: yes
status_code: 200
headers:
Content-Type: "application/json"
register: test_res
- name: output value
debug:
msg: "{{test_res.json}}"
In the following Ansible Playbook, I am trying to create a user's password using predefined variables from defaults/main.yml which in return calls password from vars/passwords.yml. this file will be vaulted later.
vars/passwords
---
passwords:
foobar:
password: pass1234
defaults/main.yml
users:
- username: foobar
group: barfoo
password: "{{passwords.foobar}}"
tasks/main.yml
- include_vars: passwords.yml
- name: Create user
user:
name: "{{item.username}}"
group: "{{item.group}}"
password: "{{item.password | password_hash('sha512') }}"
When I run this playbook, I get the following error:
ERROR:
{
"msg": "[{u'username': u'foobar',
u'group': u'barfoo',
u'password': u'{{passwords.username}}'}]: 'list object' has no attribute 'username'"
}
Any idea how can I achieve assigning a variable by referencing another one.
the first file you provided, has passwords as a list variable, while in your defaults/main.yml file you are expecting a dictionary variable (passwords.foobar).
please change 1st file contents to:
---
passwords:
foobar: pass1234
cant comment about the rest, it looks to me that the tasks/main.yml is missing a line, probably a line including with_items statement. I dont imply its a problem in your code, you just probably didn't paste all your code to this question.
With the current variables files (defaults and vars), the solution for me was to call the password for user bar using the username as a key. I currently have:
- include_vars: passwords.yml
- name: Create user
user:
name: "{{item.username}}"
group: "{{item.group}}"
password: "{{item.password | password_hash('sha512') }}"
the new defaults/main.yml will not have a password key/value:
users:
- username: foobar
group: barfoo
Now with vars/passwords.yml :
---
passwords:
foobar:
password: pass1234
I can edit my change my task to:
- include_vars: passwords.yml
- name: Create user
user:
name: "{{item.username}}"
group: "{{item.group}}"
password: "{{passwords[item.username].password | password_hash('sha512') }}"
This solved my problem, and allows me to vault passwords.yml.
Please let me know if you have any improvements or suggestions.