Read name of directory created using ansible's tempfile module - ansible

I wrote a simple ansible script to create a temporary directory and want to save the name of this directory into a variable. My .yml file is:
- hosts: " {{ lookup('env', 'HOSTNAME') }} "
tasks:
- name : Create staging directory
tempfile:
state: directory
suffix: staging
path: "{{ lookup('env', 'HOME') }}"
become: true
register: output
- name: print stdout
debug: msg="{{ output }}"
The output from running the above prints a dict
$ ansible-playbook -i hosts tempfile.yml
PLAY [localhost] ******************************************************************************************
TASK [Gathering Facts] ************************************************************************************
ok: [localhost]
TASK [Create staging directory] ***************************************************************************
changed: [localhost]
TASK [print stdout] ***************************************************************************************
ok: [localhost] => {
"msg": {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0700",
"owner": "root",
"path": "/home/xxxx/ansible.Fb7rbKstaging",
"size": 4096,
"state": "directory",
"uid": 0
}
}
PLAY RECAP ************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0
How do I get access to some_dict['localhost']['msg']['path']? I looked up the hostvars variable and do see my temporary directory in it, but can't figure out how to get access to it.

Check the Registered variables section in the docs to get more details, from your example register: output you could access the path by using something like this:
- name: print stdout
debug:
msg: "{{ output.path }}"

Related

How can I filter certain element in a string

playbook.yml
---
hosts: local_host
connection: local
gather_facts: False
tasks:
- name: set-details
set_fact:
filter: "{{ lookup('file', 'tmp/task2.yml') | from_json }}"
- set_fact:
result: "{{ filter['msg'] }}"
- debug:
var: result
task2.yml
{
"ansible_loop_var": "item",
"_ansible_no_log": false,
"invocation": {
"module_args": {
"wait_for_task": true,
"policy_package": "Mills07_Simplified",
"version": null,
"wait_for_task_timeout": 30
}
},
"item": "Mills07_Simplified",
"changed": false,
"msg": "Task Verify policy operation with task id 01234567-89ab-cdef-928b-bef7e174fc7a failed. Look at the logs for more details",
"_ansible_item_label": "Mills07_Simplified"
}
debug message
TASK [debug] *****************************************************************************************************************************************************************************
ok: [localhost] => {
"result": "Task Verify policy operation with task id 01234567-89ab-cdef-928b-bef7e174fc7a failed. Look at the logs for more details"
}
When I did the following,
- set_fact:
task_id: "{{ result |
select('regex', my_regex)|
first|
regex_replace(my_regex, my_replace) }}"
vars:
my_regex: '^Task Verify policy operation with task id (.*)$'
my_replace: '\1'
- debug:
var: task_id
I got an error message
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'my_regex' is undefined\n\nThe error appears to be in
Goal: I want to get the task-id "01234567-89ab-cdef-928b-bef7e174fc7a"
How can I get this string 01234567-89ab-cdef-928b-bef7e174fc7a
Since you are looking for a universally unique identifier (or UUID) which has a defined format of 8-4-4-4-12 characters for a total of 36 characters (32 hexadecimal characters and 4 hyphens) source, you can use a simple regex to extract it.
It can be handled with the following regex:
[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}
You can test it there: https://regex101.com/r/4Hs7il/1
So, in a set_fact:
- set_fact:
uuid: >-
{{ filter.msg
| regex_search(
'([0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})',
'\1',
ignorecase=True
)
| first
}}
As an example:
- hosts: localhost
gather_facts: no
tasks:
- set_fact:
uuid: >-
{{ filter.msg
| regex_search(
'([0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})',
'\1',
ignorecase=True
)
| first
}}
vars:
filter:
msg: "Task Verify policy operation with task id 01234567-89ab-cdef-928b-bef7e174fc7a failed. Look at the logs for more details"
- debug:
var: uuid
Would yield the recap:
PLAY [localhost] ***************************************************************
TASK [set_fact] ****************************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] =>
uuid: 01234567-89ab-cdef-928b-bef7e174fc7a
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Ansible remove \ and brackets from output

I am trying to print out the kubernetes version and client version with Ansible however the output comes with slashes and how can I remove the brackets for a more cleaner output?
- name: Kubernetes version
run_once: true
changed_when: False
shell: |
kubectl version
delegate_to: localhost
register: kubernetes_version
Output:
name: Output
run_once: true
delegate_to: localhost
debug:
msg: "{{ kubernetes_version.stdout_lines }}"
output:
ok: [localhost] => {
"msg": [
"Client Version: version.Info{Major:\"1\", Minor:\"18\", GitVersion:\"v1.18.4\", GitCommit:\"e0fccafd69541e3750d460ba0f9743\", GitTreeState:\"clean\", BuildDate:\"2020-04-16T11:44:03Z\", GoVersion:\"
go1.13.9\", Compiler:\"gc\", Platform:\"linux/amd64\"}",
"Server Version: version.Info{Major:\"1\", Minor:\"18\", GitVersion:\"v1.18.4\", GitCommit:\"e0fccafd69541e3750d460ba0f9743\", GitTreeState:\"clean\", BuildDate:\"2020-04-16T11:35:47Z\", GoVersion:\"
go1.13.9\", Compiler:\"gc\", Platform:\"linux/amd64\"}"
]
}
I'm replacing my original answer, because I was forgetting that
kubectl version can produce JSON output for us, which makes this
much easier.
By taking the output of kubectl version -o json and passing it
through the from_json filter, we can create an Ansible dictionary
variable from the result.
Then we can use a debug task to print out keys from this variable,
and I think you'll get something closer to what you want.
This playbook:
- hosts: localhost
gather_facts: false
tasks:
- name: run kubectl version
command: kubectl version -o json
register: kv_raw
- set_fact:
kv: "{{ kv_raw.stdout | from_json }}"
- debug:
msg:
- "{{ kv.clientVersion }}"
- "{{ kv.serverVersion }}"
Will produce output like this:
PLAY [localhost] ********************************************************************************************
TASK [run kubectl version] **********************************************************************************
changed: [localhost]
TASK [set_fact] *********************************************************************************************
ok: [localhost]
TASK [debug] ************************************************************************************************
ok: [localhost] => {
"msg": [
{
"buildDate": "2020-11-14T01:08:04Z",
"compiler": "gc",
"gitCommit": "6082e941e6d62f3a0c6ca8ba52927100948b1d0d",
"gitTreeState": "clean",
"gitVersion": "v1.18.2-0-g52c56ce",
"goVersion": "go1.13.15",
"major": "1",
"minor": "18",
"platform": "linux/amd64"
},
{
"buildDate": "2020-10-25T05:12:54Z",
"compiler": "gc",
"gitCommit": "45b9524",
"gitTreeState": "clean",
"gitVersion": "v1.18.3+45b9524",
"goVersion": "go1.13.4",
"major": "1",
"minor": "18+",
"platform": "linux/amd64"
}
]
}
PLAY RECAP **************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Create password and write it to file

The idea is to generate user accounts over an API. Using default variables as the basic information:
---
students:
- Username: testuser1
E-Mail: student1#student.com
- Username: testuser2
E-Mail: student2#student.com
The Creating User role will then create all users with the API:
- name: "Creating User"
uri:
url: "https://URL/api/v1/users"
method: POST
headers:
Content-Type: application/json
Authorization: AUTH TOKEN
body:
name: "{{ item['Username'] }}"
email: "{{ item['E-Mail'] }}"
password: "{{ item['Password'] }}"
body_format: json
validate_certs: no
loop: "{{ students }}"
I can not find a way to generate a password for each user and write them to a file. Is there a way I can append a Password variable to each student item before the Creating User role? If so I could just write the default variable to a file as a last role.
I've played with the password module. I do not want to have 100+ files with the passwords of the users. I need to have a singe file at the end with all information.
I'm not 100% sure I understood your question.
The below will take your actual user list, create a new one with a generated password for each and store the result in a single file for all users. Bonus: if the file exists, the var will be initialized from there bypassing the password creation.
Notes:
The below can be enhanced. You can put the block tasks for file creation in a separate file and use a conditional include so that the skipped loop iteration do not take place at all when the file already exists.
I obviously did not take security into account here and I strongly suggest you secure the way your file is stored.
Demo playbook:
---
- name: Create random passwords and store
hosts: localhost
gather_facts: false
vars:
users_with_pass_file: /tmp/test_pass.txt
students:
- Username: testuser1
E-Mail: student1#student.com
- Username: testuser2
E-Mail: student2#student.com
tasks:
- name: Try to load users and passwords from file if it exists
vars:
file_content: "{{ lookup('ansible.builtin.file', users_with_pass_file, errors='ignore') }}"
ansible.builtin.set_fact:
users_with_pass: "{{ file_content }}"
when:
- file_content | length > 0
# Unfortunately, there is no test 'is list' in jinja2...
- file_content is iterable
- file_content is not mapping
- file_content is not string
ignore_errors: true
changed_when: false
register: load_from_disk
- name: Create user list with passwords and store it if it does not exists (or is malformed...)
block:
- name: Create the list
vars:
user_password: "{{ lookup('ansible.builtin.password', '/dev/null', length=12) }}"
ansible.builtin.set_fact:
users_with_pass: "{{ users_with_pass | default([]) + [item | combine({'password': user_password})] }}"
loop: "{{ students }}"
- name: Store the result
ansible.builtin.copy:
dest: "{{ users_with_pass_file }}"
content: "{{ users_with_pass | to_json }}"
when: load_from_disk is skipped or load_from_disk is failed
- name: Show the result
ansible.builtin.debug:
var: users_with_pass
first run (with used ansible version):
$ ansible-playbook --version
ansible-playbook 2.10.1
config file = None
configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.6/dist-packages/ansible
executable location = /usr/local/bin/ansible-playbook
python version = 3.6.9 (default, Jul 17 2020, 12:50:27) [GCC 8.4.0]
$ ansible-playbook test.yml
PLAY [Create random passwords and store] ***********************************************************************************************************************************************************************************************
TASK [Try to load users and passwords from file if it exists] **************************************************************************************************************************************************************************
[WARNING]: Unable to find '/tmp/test_pass.txt' in expected paths (use -vvvvv to see paths)
skipping: [localhost]
TASK [Create the list] *****************************************************************************************************************************************************************************************************************
ok: [localhost] => (item={'Username': 'testuser1', 'E-Mail': 'student1#student.com'})
ok: [localhost] => (item={'Username': 'testuser2', 'E-Mail': 'student2#student.com'})
TASK [Store the result] ****************************************************************************************************************************************************************************************************************
changed: [localhost]
TASK [Show the result] *****************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"users_with_pass": [
{
"E-Mail": "student1#student.com",
"Username": "testuser1",
"password": "5l1RG7HzqaKMWJcH:mRH"
},
{
"E-Mail": "student2#student.com",
"Username": "testuser2",
"password": "tZvLT3LVj3_60GV_WoQd"
}
]
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Second run:
PLAY [Create random passwords and store] ***********************************************************************************************************************************************************************************************
TASK [Try to load users and passwords from file if it exists] **************************************************************************************************************************************************************************
ok: [localhost]
TASK [Create the list] *****************************************************************************************************************************************************************************************************************
skipping: [localhost] => (item={'Username': 'testuser1', 'E-Mail': 'student1#student.com'})
skipping: [localhost] => (item={'Username': 'testuser2', 'E-Mail': 'student2#student.com'})
TASK [Store the result] ****************************************************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Show the result] *****************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"users_with_pass": [
{
"E-Mail": "student1#student.com",
"Username": "testuser1",
"password": "5l1RG7HzqaKMWJcH:mRH"
},
{
"E-Mail": "student2#student.com",
"Username": "testuser2",
"password": "tZvLT3LVj3_60GV_WoQd"
}
]
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
If you have diceware installed, then you can generate the password:
- name: generate new password
delegate_to: localhost
command: diceware --no-caps -d ' ' -w en_eff
register: generatedpass
Then you can store in the file:
- name: store password
copy:
dest: '/path/to/password/file'
content: |
{{ generatedpass }}
If I understand your question correctly, this should do the trick.

Ansible: move on to the next task if the task is completed on one host

In ansible what i require is to check for a file is available on two hosts. But if the file is available on even one host i need to cancel the task on other host and move onto the next task. The reason why i require this is because a the next task can only be done if that particular file is available and that file can be randomly written to any of the hosts.
The following play does exactly what you want:
---
- hosts:
- server1
- server2
gather_facts: False
vars:
file_name: 'foo.bar'
tasks:
- name: wait for file
wait_for:
path: '{{ file_name }}'
state: present
timeout: 30
ignore_errors: True
- name: stat
stat:
path: '{{ file_name }}'
register: result
- name: next
debug:
msg: "File {{ file_name }} available on {{ ansible_host }}"
when: result.stat.isreg is defined and result.stat.isreg
The output is:
PLAY [server1,server2] *********************************************************
TASK [wait for file] ***********************************************************
ok: [server1]
fatal: [server2]: FAILED! => {"changed": false, "elapsed": 3, "msg": "Timeout when waiting for file foo.bar"}
...ignoring
TASK [stat] ********************************************************************
ok: [server1]
ok: [server2]
TASK [next] ********************************************************************
skipping: [server2]
ok: [server1] => {
"msg": "File foo.bar available on server1"
}
PLAY RECAP *********************************************************************
server1 : ok=3 changed=0 unreachable=0 failed=0
server2 : ok=0 changed=0 unreachable=0 failed=0
You can use the stat module to check the status like below and for also you can add the serial:1 below hosts: in your playbook
stat:
path: /path/to/something
register: p
debug:
msg: "Path exists and is a directory"
when: p.stat.isdir is defined and p.stat.isdir
https://docs.ansible.com/ansible/latest/modules/stat_module.html for more details

Ansible playbook - environment variables

I am trying (newbie) to setup a playbook, which will use lookup plugin to fetch secrets from vault (https://github.com/jhaals/ansible-vault), but it will fail on missing environment variables every time. Can anyone help? Thanks for the help.
PS: token is for a test purposes
There is condition in lookup module :
url = os.getenv('VAULT_ADDR')
if not url:
raise AnsibleError('VAULT_ADDR environment variable is missing')
Playbook:
---
- hosts: localhost
vars:
vault1_env:
VAULT_ADDR: https://localhost:8200/
VAULT_TOKEN: my-token-id
VAULT_SKIP_VERIFY: True
tasks:
- shell: echo VAULT_ADDR is $VAULT_ADDR, VAULT_TOKEN is $VAULT_TOKEN, VAULT_SKIP_VERIFY is $VAULT_SKIP_VERIFY
environment: "{{ vault1_env }}"
register: shellout
- debug: var=shellout
- debug: msg="{{ lookup('vault', 'secret/hello', 'value') }}"
output:
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [command] *****************************************************************
changed: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"shellout": {
"changed": true,
"cmd": "echo VAULT_ADDR is $VAULT_ADDR, VAULT_TOKEN is $VAULT_TOKEN, VAULT_SKIP_VERIFY is $VAULT_SKIP_VERIFY",
"delta": "0:00:00.001268",
"end": "2016-05-17 15:46:34.144735",
"rc": 0,
"start": "2016-05-17 15:46:34.143467",
"stderr": "",
"stdout": "VAULT_ADDR is https://localhost:8200/, VAULT_TOKEN is ab9b16c6-52d9-2051-0802-6f047d929b63, VAULT_SKIP_VERIFY is True",
"stdout_lines": [
"VAULT_ADDR is https://localhost:8200/, VAULT_TOKEN is ab9b16c6-52d9-2051-0802-6f047d929b63, VAULT_SKIP_VERIFY is True"
],
"warnings": []
}
}
TASK [debug] *******************************************************************
fatal: [localhost]: FAILED! => {"failed": true, "msg": "ERROR! VAULT_ADDR environment variable is missing"}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=1
Here you are only setting environmental variables for the shell module, and not for the others. If you want to use variables across multiple modules, or for an entire a host, you should use the environment attribute on all of the modules, or on the host itself, something like this:
---
- hosts: localhost
environment:
VAULT_ADDR: https://localhost:8200/
VAULT_TOKEN: my-token-id
VAULT_SKIP_VERIFY: True
Why don't you make use of the vault feature to encrypt a variable file and then include this file in your playbook.
http://docs.ansible.com/ansible/playbooks_vault.html#running-a-playbook-with-vault

Resources