Concatenate variable to itself in Ansible - jinja2

I am trying to concatenate variable to itself in an Ansible playback loop, but I am unable to do it. Might be its simple but unable to achieve this.
What I am trying here.
- name: all directories
set_fact: all_dir={{ item }}
with_items:
- src/main/java
- src/main/test
- src/main/resources
- debug: var=all_dir
Expected Output in all_dir
src/main/java src/main/test src/main/resources
I tried join . Any suggestion?

join is what you should be using.
- hosts: 127.0.0.1
connection: local
vars:
dirs:
- src/main/java
- src/main/test
- src/main/resources
all_dir: "{{ dirs | join(' ') }}"
tasks:
- debug: var=all_dir
Or via set_fact:
- hosts: 127.0.0.1
connection: local
vars:
dirs:
- src/main/java
- src/main/test
- src/main/resources
tasks:
- set_fact:
all_dir: "{{ dirs | join(' ') }}"
- debug: var=all_dir
TASK: [debug var=all_dir] *****************************************************
ok: [127.0.0.1] => {
"var": {
"all_dir": "src/main/java src/main/test src/main/resources"
}
}

Related

ansible based wordpress installation not working

Hope y'all are enjoying the holidays. I am attempting an automated installation of wordpress on my Linux VM using ansible. To that end, I have written this ansible piece of code that tries to mimic the official ubuntu guide.
Here is the code:
- name: "Installing wordpress dependencies"
hosts: all
become: True
gather_facts: True
vars:
get_installer: 'curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php || /bin/true'
get_signature: 'curl -sS https://composer.github.io/installer.sig'
tasks:
- name: "Update repository"
apt:
update_cache: "yes"
- name: "Installing requirements"
apt:
name:
- "curl"
- "php"
- "php-cli"
- "gnupg"
- "unzip"
- "mysql-server"
- "php-fpm"
- "php-mysql"
- "apache2"
- "ghostscript"
- "libapache2-mod-php"
- "php-bcmath"
- "php-curl"
- "php-imagick"
- "php-intl"
- "php-json"
- "php-mbstring"
- "php-xml"
- "php-zip"
state: present
- name: Populate service facts
ansible.builtin.service_facts:
- name: Print service facts
ansible.builtin.debug:
var: ansible_facts.services
- name: "stopping nginx if running"
service:
name: nginx
state: stopped
when: "'nginx' in ansible_facts.services"
- name: "remove nginx if installed"
apt:
name:
- "nginx"
state: absent
- name: stop Mysql
service:
name: mysql
state: stopped
when: "'mysql' in ansible_facts.services"
- name: stop apache2
service:
name: apache2
state: stopped
when: "'apache2' in ansible_facts.services"
- name: Installing wordpress through source
hosts: all
become: True
gather_facts: False
vars:
wprootdir: "/srv/www/wordpress"
tasks:
- name: checking if wp src dir exists
stat:
path: "{{ wprootdir }}"
register: dir_details
- name: delete existing wordpress source files
become_user: www-data
no_log: True
file:
#path: "{{ item.path }}"
#recurse: True
path: "{{ wprootdir }}"
state: absent
#with_items: "{{ path_list.files }}"
- name: creating /var/www for wordpress source
file:
#path: "'{{ wp-root-dir }}' + 'wordpress'"
path: "/srv/www/wordpress"
recurse: yes
state: directory
owner: www-data
mode: '0755'
- name: downloading and extracting wordpress source
shell:
cmd: "curl https://wordpress.org/latest.tar.gz | sudo -u www-data tar zx -C /srv/www"
register: status
- fail:
msg: "Unable to download or extract wordpress source"
when: (status.rc != 0)
- name: Configuring apache for wordpress
hosts: all
become: True
gather_facts: False
vars:
wprootdir: "/srv/www/wordpress"
wpconffile: "/etc/apache2/sites-available/wordpress.conf"
tasks:
- name: deleting the file if it exists
file:
path: "{{ wpconffile }}"
state: absent
- name: creating wordpress conf file
file:
path: "{{ wpconffile }}"
state: touch
owner: www-data
- name: populating wordpress conf file
template:
src: apache2.j2
dest: "{{ wpconffile }}"
- name: enabling the site
shell:
cmd: "a2ensite wordpress"
- name: enable URL rewriting
shell:
cmd: "a2enmod rewrite"
- name: disable default "it works" site
shell:
cmd: "a2dissite 000-default"
- name: restart apache2
service:
name: apache2
state: reloaded
- name: Configuring database
hosts: all
become: True
gather_facts: True
#gather_facts: yes
vars:
mysql_port: 3306
mysql_socket: /var/run/mysqld/mysqld.sock
mysql_superuser: root
mysql_superuser_home: "{% if mysql_superuser == 'root' %}/root{% else %}/home/{{ mysql_superuser }}{% endif %}"
mysql_superuser_password: SuperUserPwd
mysql_wordpress_password: WordpressPwd
http_port: 80
tasks:
- name: Installing PyMySql through pip
pip:
name: PyMySql
state: present
- name: ensure mysql is running and starts on boot
service:
name: mysql
state: started
enabled: True
- name: Removes anonymous user account for localhost
community.mysql.mysql_user:
name: ''
state: absent
login_user: root
login_password: ""
login_unix_socket: "{{ mysql_socket }}"
when: ansible_local.mysqlinfo is undefined
- name: adding a password for root user
mysql_user:
# Update the superuser to have all grants and a password
name: "{{ mysql_superuser }}"
host: localhost
password: "{{ mysql_superuser_password }}"
priv: "*.*:ALL,GRANT"
# Login *as root* to perform this change, even though you might
# be altering the root user itself
login_user: root
login_password: ""
login_port: "{{ mysql_port }}"
login_host: localhost
login_unix_socket: "{{ mysql_socket }}"
# As a good measure,have ansible check whether an implicit login
# is possible first
check_implicit_admin: yes
when: ansible_local.mysqlinfo is undefined
- name: "Create custom fact directory"
file:
path: "/etc/ansible/facts.d"
state: "directory"
recurse: yes
when: ansible_local.mysqlinfo is undefined
- name: "record mysql info in custom fact"
template:
src: mysqlinfo.j2
dest: /etc/ansible/facts.d/mysqlinfo.fact
mode: 0644
when: ansible_local.mysqlinfo is undefined
- name: "re-run setup to use custom facts"
setup:
filter: ansible_local
when: ansible_local.mysqlinfo is undefined
- debug:
msg:
- "mysqlinfo is {{ ansible_local.mysqlinfo }}"
when: ansible_local.mysqlinfo is defined
#- name: Create system-wide mysql configuration file
#template:
#src: mysql_sys.cnf.j2
#dest: /etc/my.cnf
#- name: Create mysql configuration file for `{{ mysql_superuser }}`
#template:
#src: mysql_superuser.cnf.j2
#dest: "{{ mysql_superuser_home }}/.my.cnf"
- name: create database wordpress
mysql_db:
db: wordpress
state: present
login_user: "{{ ansible_local.mysqlinfo.mysql_superuser }}"
login_password: "{{ ansible_local.mysqlinfo.mysql_superuser_password }}"
login_unix_socket: "{{ mysql_socket }}"
when: ansible_local.mysqlinfo is defined
- name: Create database user 'wordpress' with all database privileges
community.mysql.mysql_user:
name: wordpress
password: "{{ mysql_wordpress_password }}"
login_user: "{{ ansible_local.mysqlinfo.mysql_superuser }}"
login_password: "{{ ansible_local.mysqlinfo.mysql_superuser_password }}"
priv: '*.*:ALL'
state: present
when: ansible_local.mysqlinfo is defined
- name: Flush privileges
mysql_query:
login_db: wordpress
login_user: "{{ ansible_local.mysqlinfo.mysql_superuser }}"
login_password: "{{ ansible_local.mysqlinfo.mysql_superuser_password }}"
login_unix_socket: "{{ mysql_socket }}"
query: FLUSH PRIVILEGES
# UFW Configuration
- name: "UFW - Allow HTTP on port {{ http_port }}"
ufw:
rule: allow
port: "{{ http_port }}"
proto: tcp
notify:
- Restart Mysql
tags: [ system ]
handlers:
- name: Restart Mysql
service:
name: mysql
state: restarted
- name: Restart Apache2
service:
name: apache2
state: restarted
- name: Configuring wordpress to connect to the database
hosts: all
gather_facts: False
become: true
vars:
wpconfigfile: "/srv/www/wordpress/wp-config.php"
tasks:
- name: copy sample config to wp-config.php
#become_user: www-data
copy:
remote_src: yes
src: /srv/www/wordpress/wp-config-sample.php
dest: "{{ wpconfigfile }}"
owner: www-data
- name: "re-run setup to use custom facts"
setup:
filter: ansible_local
- name: set database credentials in the config file
become: false
#become_user: www-data
#become_method: "su"
# multiple commands are run like this whereas with
# single command one can use a cmd paramater
# since this is technically *not* a list passed to /bin/sh
# we do not need a list here. Instead it is a series of
# commands being passed to /bin/sh
#shell: |
# apparently, passing this list directly doesn't seem to work
# what works is this loop
command: "{{ item }}"
with_items:
- "sudo -u www-data sed -i s/database_name_here/wordpress/ {{ wpconfigfile }}"
- "sudo -u www-data sed -i s/username_here/wordpress/ {{ wpconfigfile }}"
- "sudo -u www-data sed -i s/password_here/{{ ansible_local.mysqlinfo.mysql_wordpress_password }}/ {{ wpconfigfile }}"
- name: get random secret keys
uri:
url: https://api.wordpress.org/secret-key/1.1/salt/
return_content: yes
body_format: json
register: wordpress_keys
- debug:
var: wordpress_keys.content
- name: delete existing bak file
file:
path: "{{ wpconfigfile }}.bak"
state: absent
- name: run script to remove key placeholders
become_user: www-data
script:
chdir: /srv/www/wordpress/
cmd: replacelines.py
executable: /usr/bin/python3
environment: /srv/www/wordpress/
- name: update config file
become_user: www-data
copy:
remote_src: yes
src: "{{ wpconfigfile }}.bak"
dest: "{{ wpconfigfile }}"
- blockinfile:
path: "{{ wpconfigfile }}"
marker: // {mark} ANSIBLE MANAGED BLOCK
# having this separator here was giving me issues
#block: |
block:
"{{ wordpress_keys.content }}"
handlers:
- name: Restart Mysql
service:
name: mysql
state: restarted
- name: Restart Apache2
service:
name: apache2
state: restarted
Associated jinja2 template files are here:
Apache2 template:
<VirtualHost *:80>
Servername {{ ansible_hostname }}
DocumentRoot "{{ wprootdir }}"
<Directory "{{ wprootdir }}">
Options FollowSymLinks
AllowOverride Limit Options FileInfo
DirectoryIndex index.php
Require all granted
</Directory>
<Directory "{{ wprootdir }}/wp-content">
Options FollowSymLinks
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
mysqlinfo template
{
"mysql_port": "{{ mysql_port }}",
"mysql_socket": "{{ mysql_socket }}",
"mysql_superuser": "{{ mysql_superuser }}",
"mysql_superuser_password": "{{ mysql_superuser_password }}",
"mysql_wordpress_password": "{{ mysql_wordpress_password }}"
}
replacelines.py script:
import re
with open("wp-config.php", "r") as wpconfig, open("wp-config.php.bak", "w") as wpconfigbak:
for line in wpconfig:
found = re.search(r'AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|NONCE_KEY|AUTH_SALT|SECURE_AUTH_SALT|LOGGED_IN_SALT|NONCE_SALT', line.strip());
if (not found):
wpconfigbak.write(line)
else:
continue
inventory file:
[local]
localhost ansible_connection=local
With this playbook I am able to see the wordpress landing page when I open 'localhost:80/' on my Linux machine. However I am unable to get to the wordpress dashboard. I run the playbook like so: ansible-playbook -i inventory SetupWordpress.yaml
To save time, you may use my github repo:
git clone -b WIP git#github.com:redbilledpanda/DevOpsScripts.git
cd DevOpsScripts && ansible-playbook -i inventory SetupWordpress.yaml
After the playbook completes, I go to http://localhost:80 and I am presented with the installer:
I fill in the details:
Apparently, it succeeds:
When I try logging in, I don't see the dashboard. Instead, I never go past the login screen (it doesn't say incorrect credentials or anything though):
I am at a loss as to what am I doing wrong. Keen to hear from you folks.
UPDATE1: If I skip the part where I generate the wordpress 'salts'/keys it works. I can see the dashboard etc. With these salts however, it just won't get to the wordpress admin dashboard.
Using a minimal sample config file wpconfig.file
<?php
/**
* The base configuration for WordPress
* ...
* Authentication unique keys and salts.
*
* Change these to different unique phrases! You can generate these using
* the {#link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}.
*
* You can change these at any point in time to invalidate all existing cookies.
* This will force all users to have to log in again.
* ...
*/
and a minimal example playbook
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Get random secret keys
uri:
url: https://api.wordpress.org/secret-key/1.1/salt/
return_content: yes
body_format: json
register: wordpress_keys
- name: Show keys
debug:
var: wordpress_keys.content
- name: Write keys to config
blockinfile:
path: wpconfig.file
marker: // {mark} ANSIBLE MANAGED BLOCK
block:
"{{ wordpress_keys.content }}"
it results into the expected and probably correct output.
TASK [Show keys] ************************************************************************************************
ok: [localhost] =>
wordpress_keys.content: |-
define('AUTH_KEY', '...');
define('SECURE_AUTH_KEY', '...');
define('LOGGED_IN_KEY', '...');
define('NONCE_KEY', '...');
define('AUTH_SALT', '...');
define('SECURE_AUTH_SALT', '...');
define('LOGGED_IN_SALT', '...');
define('NONCE_SALT', '...');
<?php
/**
* The base configuration for WordPress
* ...
* Authentication unique keys and salts.
*
* Change these to different unique phrases! You can generate these using
* the {#link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}.
*
* You can change these at any point in time to invalidate all existing cookies.
* This will force all users to have to log in again.
* ...
*/
// BEGIN ANSIBLE MANAGED BLOCK
define('AUTH_KEY', '...');
define('SECURE_AUTH_KEY', '...');
define('LOGGED_IN_KEY', '...');
define('NONCE_KEY', '...');
define('AUTH_SALT', '...');
define('SECURE_AUTH_SALT', '...');
define('LOGGED_IN_SALT', '...');
define('NONCE_SALT', '...');
// END ANSIBLE MANAGED BLOCK
Summary
Your current question and description seems not to be focused on the necessary part but on everything not so related around
On Ansible tasks I am not able to (re-)produce an issue
The part deals with configuration for a 3rd party web service or PHP only
According this it seems not to be related to Ansible at all
The problem domain seems to be Wordpress and PHP setup and configuration only, namely the config file
For further troubleshooting you may try to template module – Template a file out to a target host, the config file including keys generated define('AUTH_KEY', '{{ lookup('password', '/dev/null chars=ascii_letters length=64') }}');
Check with Browser in Incognito Mode because of invalidated cookies
Therefore it is also not about programming at all
An other site on Stack like serverfault.com, superuser.com, devops.staexchange.com or wordpress.stackexchange.com might fit better for your question
-regenerate the security keys
-Make sure the keys are entered correctly in the wp-config file of your WordPress installation.

Using Key(#) function to extract keys from an object in Ansible

I have a file file.sub which contains this JSON object {"kas_sub.test1": "true", "kas_sub.test2": "true"}. I would extract the keys and to get this: kas_sub.test1 kas_sub.test1.
When i try
- shell: 'cat path/to/file.sub'
register: file1
- debug:
var: file1.stdout_lines
I got:
TASK [shell] *****************************************************************************************************************
changed: [ansible4]
changed: [control]
TASK [debug] *****************************************************************************************************************
ok: [control] => {
"file1.stdout_lines": [
"{\"kas_sub.tes1\": \"true\", \"kas_sub.test2\": \"true\"}"
]
}
So it's not conserving the same JSON format because i would use the json_query filter.
- debug:
msg: "{{ file1.stdout_lines| json_query(value1)}}"
vars:
value1: "#[?keys(#)]"
keys(#)function doesn't return anything
ok: [control] => {
"msg": ""
}
note: taking for granted you want to read a file on the target machine
In a nutshell:
- hosts: your_group
gather_facts: false
vars:
file_to_read: /path/to/file.sub
tasks:
- name: slurp file content from target
slurp:
src: "{{ file_to_read }}"
register: slurped_file
- name: display keys from json inside file
debug:
msg: "{{ (slurped_file.content | b64decode | from_json).keys() }}"
Given the file
shell> cat /tmp/file.sub
{"kas_sub.test1": "true", "kas_sub.test2": "true"}
Use jq (if you can). For example, get the keys
- command: jq 'keys' /tmp/file.sub
register: result
and convert them to a list
keys: "{{ result.stdout|from_yaml }}"
gives
keys:
- kas_sub.test1
- kas_sub.test2
Example of a complete playbook
- hosts: localhost
vars:
keys: "{{ result.stdout|from_yaml }}"
tasks:
- command: jq 'keys' /tmp/file.sub
register: result
- debug:
var: keys

Checking the key value in a JSON file

I'm having trouble verifying the value of a json file on a remote server. I have to overwrite the file once on the remote machine from the template (j2). After that, I start a service that writes additional values to this file.
But when restarting ansible-playbook, this file is overwritten because it differs from the template. Before starting the task of writing a file from a template, I want to check the file for unique values.
For testing on a local machine, I do this and everything works:
- name: Check file
hosts: localhost
vars:
config: "{{ lookup('file','config.json') | from_json }}"
tasks:
- name: Check info
set_fact:
info: "{{ config.Settings.TimeStartUP }}"
- name: Print info
debug:
var: info
- name: Create directory
when: interfaces | length != 0
ansible.builtin.file:
...
But when I try to do the same in a task on a remote machine, for some reason ansible is looking for a file on the local machine
all.yml
---
config_file: "{{ lookup('file','/opt/my_project/config.json') | from_json }}"
site.yml
---
- name: Install My_project
hosts: server
tasks:
- name: Checking if a value exists
set_fact:
info: "{{ config_file.Settings.TimeStartUP }}"
- name: Print info
debug:
var: info
Error:
fatal: [server]: FAILED! => {"msg": "An unhandled exception occurred while templating '{{ lookup('file','/opt/my_project/config.json') | from_json }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while running the lookup plugin 'file'. Error was a <class 'ansible.errors.AnsibleError'>, original message: could not locate file in lookup: /opt/my_project/config.json. could not locate file in lookup: /opt/my_project/config.json"}
Please tell me how to correctly check the key value in a JSON file on a remote server?
fetch the files from the remote hosts first. For example, given the files below for testing
shell> ssh admin#test_11 cat /tmp/config.json
{"Settings": {"TimeStartUP": "today"}}
shell> ssh admin#test_12 cat /tmp/config.json
{"Settings": {"TimeStartUP": "yesterday"}}
The playbook below
- hosts: test_11,test_12
gather_facts: false
tasks:
- file:
state: directory
path: "{{ playbook_dir }}/configs"
delegate_to: localhost
run_once: true
- fetch:
src: /tmp/config.json
dest: "{{ playbook_dir }}/configs"
- include_vars:
file: "{{ config_path }}"
name: config
vars:
config_path: "{{ playbook_dir }}/configs/{{ inventory_hostname }}/tmp/config.json"
- debug:
var: config.Settings.TimeStartUP
will create the directory configs in playbook_dir on the controller and will fetch the files from the remote hosts into this directory. See the parameter dest on how the path will be created
shell> cat configs/test_11/tmp/config.json
{"Settings": {"TimeStartUP": "today"}}
shell> cat configs/test_12/tmp/config.json
{"Settings": {"TimeStartUP": "yesterday"}}
Then include_vars and store the dictionary into the variable config
ok: [test_11] =>
config.Settings.TimeStartUP: today
ok: [test_12] =>
config.Settings.TimeStartUP: yesterday

I'm trying to get ansible output formatted like item1 - item2 instead of two separate lists of items

I have a functioning ansible script that connects to AWS and prints out tags from instances in a specified state.
The problem I'm having is the print out is two separate lists e.g.
What I get is:
name1
name2
name3
description1
description2
description3
What I would like is:
name1 - description1
name2 - description2
name3 - description3
I've tried pushing this all into a dictionary, but got lost in the attempt. There must be an easier way.
Here's my code:
- name: print stopped systems
hosts: all
become: false
tasks:
- name: Gather ec2_metadata_facts (use -vv to show all)
action: ec2_metadata_facts
- name: pull instance info with ec2_instance_info
ec2_instance_info:
region: "{{ lookup('env','AWS_DEFAULT_REGION') }}"
aws_access_key: "{{ lookup('env','AWS_ACCESS_KEY_ID') }}"
aws_secret_key: "{{ lookup('env','AWS_SECRET_ACCESS_KEY') }}"
filters:
instance-state-name: [ "shutting-down", "stopping", "stopped" ]
register: ec2_info
- name: print Instance Info
debug:
msg:
- "{{ ec2_info | json_query(name_tag) }}"
- "{{ ec2_info | json_query(description_tag) }}"
vars:
name_tag: "instances[*].tags.Name"
description_tag: "instances[*].tags.Description"
The output of the debug statement looks like this:
TASK [print Instance Info] **********************************************************************************************************************
ok: [tools-server-01] =>
msg:
- - server-01
- server-02
- - Description for server one
- Description for server two
Thanks #Rickkwa
I've got this mostly working.
here's my current code
- name: Print stopped systems
hosts: all
become: false
tasks:
- name: Gather ec2_metadata_facts (use -vv to show all)
action: ec2_metadata_facts
- name: pull instance info with ec2_instance_info
ec2_instance_info:
region: "{{ lookup('env','AWS_DEFAULT_REGION') }}"
aws_access_key: "{{ lookup('env','AWS_ACCESS_KEY_ID') }}"
aws_secret_key: "{{ lookup('env','AWS_SECRET_ACCESS_KEY') }}"
filters:
instance-state-name: [ "shutting-down", "stopping", "stopped" ]
register: ec2_info
- name: Create Name list
no_log: true
set_fact:
name_l: "{{ec2_info | json_query(name_tag)}}"
vars:
name_tag: "instances[*].tags.Name"
- name: Create Description list
no_log: true
set_fact:
desc_l: "{{ ec2_info | json_query(description_tag) }}"
vars:
description_tag: "instances[*].tags.Description"
- name: print together
debug:
msg: "{{item.0}} --- {{item.1}}"
loop: "{{ name_l|zip(desc_l)|list}}"
Unfortunately, the last debug statement includes some 'garbage" I'd like to remove...anyone have a suggestion to get rid of the stuff following the "u"s?
here's the output :'
TASK [print together] ***************************************************************************************************************************
ok: [dev-bsd-01] => (item=[u'server-01', u'server one description']) =>
msg: server-01 --- server one description
ok: [dev-bsd-01] => (item=[u'server-02', u'server two description']) =>
msg: server-02 --- server two description

Add a new key-value to a json file using Ansible

I'm using Ansible to automate some configuration steps for my application VM, but having difficult to insert a new key-value to an existing json file on the remote host.
Say I have this json file:
{
"foo": "bar"
}
And I want to insert a new key value pair to make the file become:
{
"foo": "bar",
"hello": "world"
}
Since json format is not line based, I'm excluding lineinfile module from my options. Also, I would prefer not to use any external modules. Google keeps giving me examples to show how to read json file, but nothing about change json values and write them back to file. Really appreciate your help please!
since the file is of json format, you could import the file to a variable, append the extra key:value pairs you want, and then write back to the filesystem.
here is a way to do it:
---
- hosts: localhost
connection: local
gather_facts: false
vars:
tasks:
- name: load var from file
include_vars:
file: /tmp/var.json
name: imported_var
- debug:
var: imported_var
- name: append more key/values
set_fact:
imported_var: "{{ imported_var | default([]) | combine({ 'hello': 'world' }) }}"
- debug:
var: imported_var
- name: write var to file
copy:
content: "{{ imported_var | to_nice_json }}"
dest: /tmp/final.json
UPDATE:
as OP updated, the code should work towards remote host, in this case we cant use included_vars or lookups. We could use the slurp module.
NEW code for remote hosts:
---
- hosts: greenhat
# connection: local
gather_facts: false
vars:
tasks:
- name: load var from file
slurp:
src: /tmp/var.json
register: imported_var
- debug:
msg: "{{ imported_var.content|b64decode|from_json }}"
- name: append more key/values
set_fact:
imported_var: "{{ imported_var.content|b64decode|from_json | default([]) | combine({ 'hello': 'world' }) }}"
- debug:
var: imported_var
- name: write var to file
copy:
content: "{{ imported_var | to_nice_json }}"
dest: /tmp/final.json
hope it helps
ilias-sp's solution is great!
In my case, it lacked the case when we may have to create a base json file.
So I had to add this task in the beginning of the play:
- name: Ensure json file exists
copy:
content: "{}"
dest: /tmp/var.json
force: false
For people who are OK with custom ansible modules: https://github.com/ParticleDecay/ansible-jsonpatch works great!
With this you can simply do:
- name: append key/values
json_patch:
src: /tmp/var.json
operations:
- op: add
path: "/hello"
value: "world"
pretty: yes
create: yes
- name: update log
copy:
content: "{{ log | to_nice_json}}"
dest: "{{ log_file }}"
vars:
log: "{{ (lookup('file', log_file) | from_json) + ([{'job': (build_id if build_id != '' else 'dev'), 'keystore': ks, 'timestamp': ansible_date_time.iso8601}]) }}"
log_file: log/log.json
build_id: "{{ lookup('ENV', 'BUILD_ID') }}"
tags: log