I'm writing a playbook to install 'oh my fish' for all local fish user.
I want trigger the install for local fish user (default shell set to /usr/bin/fish)
And ONLY if 'omf' is not installed in their home (check the presence ~/.local/share/omf directory)
Here what I produced
- name: Read local user database
getent:
database: passwd
- name: List local user of fish
set_fact:
fish_users: "{{ getent_passwd | dict2items | json_query('[? contains(value, `/usr/bin/fish`)].key') }}"
- name: Check if omf install for fish users
stat:
path: "/home/{{ item }}/.local/share/omf"
loop: "{{ fish_users }}"
register: omf_user_status
- name: Install omf when absent of fish user home
block:
- name: Get last omf repos
git:
repo: 'https://github.com/oh-my-fish/oh-my-fish'
dest: '/tmp/omf'
clone: yes
- name: Installing omf for fish user
become: yes
become_user: "{{ item }}"
command: /tmp/omf/bin/install -y --offline --noninteractive
loop: "{{ fish_users }}"
when: omf_user_status.item.stat.exists == 'False'
So maybe my approach is not good...
Currently I can get 'omf', installed for all fish users.
But I really struggle to generate a usable list , to only install omf for user who haven't it
Obviously the condition doesn't work.
omf_user_status variable is a dict, here an example of the content.
"omf_user_status": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_attributes": true,
"get_checksum": true,
"get_md5": false,
"get_mime": true,
"path": "/home/test_ansible/.local/share/omf"
}
},
"item": "test_ansible",
"stat": {
"atime": 1608164175.7067902,
"attr_flags": "e",
"attributes": [
"extents"
],
"block_size": 4096,
"blocks": 8,
"charset": "binary",
"ctime": 1608164176.1907954,
"dev": 1800,
"device_type": 0,
"executable": true,
"exists": true,
"gid": 1343,
"gr_name": "test_ansible",
"inode": 397192,
"isblk": false,
"ischr": false,
"isdir": true,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": false,
"issock": false,
"isuid": false,
"mimetype": "inode/directory",
"mode": "0755",
"mtime": 1608164176.1907954,
"nlink": 12,
"path": "/home/test_ansible/.local/share/omf",
"pw_name": "test_ansible",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": 4096,
"uid": 1343,
"version": "3120069218",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": true,
"xoth": true,
"xusr": true
}
}
]
}
Cheers
I finally make it works with this code.
- name: Register users who need omf
set_fact:
list_of_user: "{{ omf_user_status.results | rejectattr('stat.exists') | map(attribute='item') | list }}"
Here the full plabook
# OMF install
- name: Read local user database
getent:
database: passwd
- name: List local user of fish
set_fact:
fish_users: "{{ getent_passwd | dict2items | json_query('[? contains(value, `/usr/bin/fish`)].key') }}"
- name: Check if omf is installed for fish users
stat:
path: "/home/{{ item }}/.local/share/omf"
loop: "{{ fish_users }}"
register: omf_user_status
- name: Register users who need omf
set_fact:
user_need_omf: "{{ omf_user_status.results | rejectattr('stat.exists') | map(attribute='item') | list }}"
- name: Install omf when absent of fish user's home
block:
- name: Get lastest omf from git
git:
repo: 'https://github.com/oh-my-fish/oh-my-fish'
dest: '/tmp/omf'
clone: yes
- name: Installing omf for fish user
become: yes
become_user: "{{ item }}"
command: /tmp/omf/bin/install -y --offline --noninteractive
loop: "{{ user_need_omf }}"
- name: Cleanup omf install files
file:
path: '/tmp/omf'
state: absent
# only run this block if the user_need_omf list is not empty
when: user_need_omf | length > 0
Related
I'm trying to rename a jar file in a path for deployment using ansible and it is successful. I have tried multiple ways but still, it's failing,
For example, there are multiple Jar files in the path /appdata/tomcat/lib/jars/
we havemultiple jar files with version numbers like below
app_deploy-1.1.1.jar
app_deploy-1.1.2_old_1.jar
app_deploy-1.1.2.jar_before
app_deploy-1.1.2_old_2022.jar
app_deploy-1.1.2_before.jar
I have move all files with .jar extension with date using custom date variable {deploy_date} like this app_deploy-1.1.2_before.jar_{deploy_date}
I have method 1 as below :
- name: Get the name of the current jar files
shell: ls -l /appdata/tomcat/lib/jars/ | grep .*.jar
register: jar_files_list
- debug:
msg: "{{ jar_files_list }}"
- name: Get the date
shell: date +%Y%m%d%H%M%S
register: timestamp
when: jar_files_list.stdout != ''
- name: Rename the current jar file
file:
src: /appdata/tomcat/lib/jars/{{ jar_files_list }}
dest: /appdata/tomcat/lib/jars/{{ jar_files_list }}_{{ ansible_date_time.date }}_backup
when: jar_files_list.stdout != ''
I have method 2 as below :
- name: Rename the current jar files
shell: mv /appdata/tomcat/lib/jars/*.jar {{ repo_name }}-*.jar_backup_{{ ansible_date_time.date }}
- name: Move current filesto backup directory
shell: mv /appdata/tomcat/lib/jars/{{ repo_name }}-.*.jar /appdata/tomcat/lib/jars//backup_jars/`
Both of the solutions doest work, can someone help me with some solutions
The find module can be used to find and generate a list of files located on a remote host based on a pattern:
- name: Get jars in {{ jars_path }}
find:
paths: "{{ jars_path }}"
file_type: file
patterns: '*.jar'
register: jars_list
The output will be a dictionary of only the *.jar files in the specified path:
TASK [Get jars in /appdata/tomcat/lib/jars] ************************
ok: [test-001] => {
"changed": false,
"examined": 4,
"files": [
{
"atime": 1661249640.3583002,
"ctime": 1661249640.3583002,
"dev": 64768,
"gid": 0,
"gr_name": "root",
"inode": 8980720,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1661249640.3583002,
"nlink": 1,
"path": "/appdata/tomcat/lib/jars/test1.jar",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 0,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
},
{
"atime": 1661249640.3583002,
"ctime": 1661249640.3583002,
"dev": 64768,
"gid": 0,
"gr_name": "root",
"inode": 8980722,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1661249640.3583002,
"nlink": 1,
"path": "/appdata/tomcat/lib/jars/test2.jar",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 0,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
},
{
"atime": 1661249640.3583002,
"ctime": 1661249640.3583002,
"dev": 64768,
"gid": 0,
"gr_name": "root",
"inode": 8980726,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1661249640.3583002,
"nlink": 1,
"path": "/appdata/tomcat/lib/jars/test3.jar",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 0,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
],
"invocation": {
"module_args": {
"age": null,
"age_stamp": "mtime",
"contains": null,
"depth": null,
"excludes": null,
"file_type": "file",
"follow": false,
"get_checksum": false,
"hidden": false,
"paths": [
"/appdata/tomcat/lib/jars"
],
"patterns": [
"*.jar"
],
"read_whole_file": false,
"recurse": false,
"size": null,
"use_regex": false
}
},
"matched": 3,
"msg": "All paths examined",
"skipped_paths": {}
}
"{{ jars_list.files }}" will list the files and .path will provide the full path of the file.
Now the copy module with the option remote_src: yes can be used to rename the files:
- name: Rename jars
copy:
src: "{{ item.path }}"
dest: "{{ item.path }}_{{ deploy_date }}"
remote_src: yes
loop: "{{ jars_list.files }}"
Delete the old files:
- name: Remove old jars
file:
path: "{{ item.path }}"
state: absent
loop: "{{ jars_list.files }}"
The complete playbook
- hosts: all
vars:
deploy_date: "{{ ansible_date_time.date }}"
jars_path: /appdata/tomcat/lib/jars
tasks:
- name: Get jars in {{ jars_path }}
find:
paths: "{{ jars_path }}"
file_type: file
patterns: '*.jar'
register: jars_list
- name: Rename jars
copy:
src: "{{ item.path }}"
dest: "{{ item.path }}_{{ deploy_date }}"
remote_src: yes
loop: "{{ jars_list.files }}"
- name: Remove old jars
file:
path: "{{ item.path }}"
state: absent
loop: "{{ jars_list.files }}"
I need help going through the output of this task in ansible and ONLY pulling out the path for the "{{ item }}" being found.
Tried multiple ways and having very little success. Still learning ansible, and in this case, I'm trying to create a new directory based on the output of my inventory file. (the tail command for now because I only need to test it on 10 entries)
Playbook:
'''
- name: Get the inventory file printout.
command: tail "{{ build_dir }}{{ inventory_file }}"
register: command_output
- debug:
msg: "{{ command_output.stdout_lines }}"
- name : Find the RPMs in "{{ build_dir }}"
find:
paths: "{{ build_dir }}"
patterns: "{{ item }}.rpm"
recurse: yes
with_items:
- "{{ command_output.stdout_lines }}"
register: found_pkgs
- name: Just the Path for each Found Pkgs.
debug:
msg: "{{ item }}"
loop:
- "{{ found_pkgs }}"
Output:
"msg": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"examined": 15029,
"failed": false,
"files": [
{
"atime": 1629933434.2974539,
"ctime": 1629814445.3359122,
"dev": 64773,
"gid": 70000,
"gr_name": "engineering",
"inode": 469762133,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1629814445.3359122,
"nlink": 1,
"path": "<REDACTED>/newISO/repos/zeek/packages/zeek-btest-4.0.2-1.1.x86_64.rpm",
You could use json_query filter to extract the path of each file from results[]. A set_fact task such as below should do:
- name: save the files path in file_names var
set_fact:
file_paths: "{{ found_pkgs | json_query('results[].files[].path') }}"
- name: show file names
debug:
var: file_paths
This is my ansible:
- name: finding files
find:
paths: /etc/nginx
patterns: '{{ my_vhost }}'
recurse: "yes"
file_type: "file"
delegate_to: '{{ my_server }}'
register: find_result
- name: output the path of the conf file
debug: msg="{{ find_result.files }}"
and the output of msg is:
"msg": [
{
"atime": 1567585207.0371234,
"ctime": 1567585219.9410768,
"dev": 64768,
"gid": 1001,
"inode": 4425684,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1567585219.9410768,
"nlink": 1,
"path": "/etc/nginx/sites-enabled/specified-file",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 546,
"uid": 1001,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
]
}
and I only want this line to be outputed:
"path": "/etc/nginx/sites-enabled/specified-file",
I don't really care about the msg, specifically I want to use just this path "/etc/nginx/sites-enabled/specified-file" for later usage. There will always be only one result of the file path in my system.
#CzipO2, You can use the below tasks which also sets the file path in a variable which can be used later in the playbook,
- set_fact:
filepath: "{{ find_result.files | map(attribute='path') | list | first}}"
- name: output the path of the conf file
debug:
msg: "{{ filepath }}"
I don't really care about the msg, specifically, I want to use just this path "/etc/nginx/sites-enabled/specified-file" for later usage.
The filepath fact can be used in the playbook for later use.
Please try as below
- name: output the path of the conf file
set_fact:
path: "{{ item.path }}"
with_items: "{{ find_result.files}}"
- debug:
msg: "{{ path }}"
Hello i am trying to find a string as a part of a key in a dictionary.(file list)
In the next step i have to loop over a list of strings and search for it in a dictionary.
Any help out there?
Thanks for advice
Example dict:
[
{
"atime": 1564643897.7426093,
"ctime": 1564643891.0105128,
"dev": 64768,
"gid": 3007,
"gr_name": "group",
"inode": 2230336,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1564643891.0105128,
"nlink": 1,
"path": "/home/user/branches/user/roles/manage_users/vars/users/my.user.yml",
"pw_name": "user",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 776,
"uid": 1050,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}...
}
]
}
The match should be in key path: in the dict.
Tried several things but the closest seems to be;
- name: compare lists 1
debug:
msg: "item"
when: "item in users_list.files"
with_items:
- "{{ users }}"
But i cant get any result
Instead i get: Skipped
Expected Msg:
Msg: my.user
Got it by myself:
The trick is to create a list of path objects first with json query.
After that u can use it for comparing:
- name: create list of valid users
local_action:
module: find
path: "{{ role_path }}/vars/users"
register: users_list
- name: create list existing users
win_shell: |
try {
# powershell supposed way
$users=Get-LocalUser;echo $users.name
} catch {
#fall back
$users=Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount='True'" | select name;echo $users.name
}
register: users
- set_fact:
found_users: []
- name: compare lists
set_fact:
found_users: "{{ found_users + [item[1]] }}"
when: item[0].find(item[1]) != -1
with_nested:
- "{{ users_list.files|json_query(query) }}"
- "{{ users.stdout_lines}}"
vars:
query: "[*].path"
- debug: msg="{{ found_users }}"
I am getting some errors while doing the following:
group_vars:
tomcat_servers:
- name: tomcat_1
shutdown_port: 8005
connector_port: 8080
ajp_port: 8009
- name: tomcat_2
shutdown_port: 8105
connector_port: 8180
ajp_port: 8109
main code:
- name: "Check if tomcat is already installed"
stat: path={{ tomcat_server_dir }}/{{ item.name }}/RELEASE-NOTES
register: status
with_items: "{{ tomcat_servers }}"
- debug: var=status
- name: "Copy tomcat into folder if it is not installed"
command: /bin/tar -zxvf /tmp/{{ tomcat_catalina_base }} -C {{ tomcat_server_dir }}/{{ item.name }} --strip 2
when: not status.results[0].stat.exists
with_items:
- "{{ tomcat_servers }}"
- "{{ status.results }}"
Debug result:
ok: [VM1] => {
"status": {
"changed": false,
"msg": "All items completed",
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"changed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_checksum": true,
"get_md5": true,
"mime": false,
"path": "/opt/tomcat_3/RELEASE-NOTES"
},
"module_name": "stat"
},
"item": {
"ajp_port": 8009,
"connector_port": 8080,
"name": "tomcat_1",
"shutdown_port": 8005
},
"stat": {
"exists": false
},
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"changed": false,
"invocation": {
"module_args": {
"checksum_algorithm": "sha1",
"follow": false,
"get_checksum": true,
"get_md5": true,
"mime": false,
"path": "/opt/tomcat_3/RELEASE-NOTES"
},
"module_name": "stat"
},
"item": {
"ajp_port": 8109,
"connector_port": 8180,
"name": "tomcat_2",
"shutdown_port": 8105
},
"stat": {
"exists": false
}
}
]
}
}
Now unfortunally I seem to get the error
"skip_reason": "Conditional check failed", "skipped": true
I have been around the "have you googled it" many times but cannot seem to find the solution here. Google ansible check if file exists with_items and you will probably see the same results.
Any one got an idea how to get this working?
Correct second loop:
---
- hosts: localhost
vars:
results:
- item:
ajp_port: 8009
connector_port: 8080
name: tomcat_1
shutdown_port: 8005
stat:
exists: false
- item:
ajp_port: 8109
connector_port: 8180
name: tomcat_2
shutdown_port: 8105
stat:
exists: false
- item:
name: tomcat_exist
stat:
exists: true
tasks:
- debug:
msg: "name: {{ item.item.name }}, exists: {{ item.stat.exists }}"
when: not item.stat.exists
with_items: "{{ results }}"
So in your setup you need to loop over status.results and refer to item.item.name and item.stat.exists.