Here is my playbook where i try to find test-juli.jar under /app directory however, i wish to exclude /app/Patchbackup folder from the search.
Below is my playbook for the same:
tasks:
- name: Find test home directories under /app
find:
paths: /app
file_type: any
recurse: yes
depth: 4
patterns: 'test-juli.jar'
excludes: 'log,tmp,.installation,Patchbackup'
tags: always
register: tomjarfound
- debug:
msg: "ALL LISTED REFINED JARS: {{ item.path }}"
loop: "{{ tomjarfound.files }}"
When i run the above, i was expecting the find not to find under /app/Patchbackup but the output shows that it does despite being excluded.
Here is the output:
TASK [debug] ***********************************************************************************************************************************************************
ok: [10.0.0.11] => (item=/app/apache-test-9.0.10/bin/test-juli.jar) => {
"msg": "ALL LISTED REFINED JARS: /app/apache-test-9.0.10/bin/test-juli.jar"
}
ok: [10.0.0.11] => (item=/app/Patchbackup/app/apache-test-9.0.10/bin/test-juli.jar) => {
"msg": "ALL LISTED REFINED JARS: /app/Patchbackup/app/apache-test-9.0.10/bin/test-juli.jar"
}
Can you please suggest how can I exclude the folder /app/Patchbackup from ansible's find ?
The find module is arguably broken. The excludes parameter applies only to items in the final result set, and not to intermediate directories.
That is, if you have a directory structure like this:
toplevel/
foo/
testfile1.txt
bar/
testfile2.txt
And from the parent of the toplevel directory you run a task like this:
- find:
paths: toplevel
recurse: true
excludes: foo
register: results
Your result set will look like:
toplevel/bar/testfile2.txt
toplevel/foo/testfile1.txt
Compare that to setting file_type: any, like this:
- find:
paths: toplevel
file_type: any
recurse: true
excludes: foo
register: results
In this case, the result set will look like:
- `toplevel/bar`
- `toplevel/bar/testfile2.txt`
- `toplevel/foo/testfile1.txt`
Note that toplevel/bar is included in the results, but toplevel/foo is excluded. That's because:
We set file_type: any, which means we want to find directories as well as files.
This makes toplevel/foo part of the result set.
We are excluding from the results anything with the basename foo
You will get more flexible behavior if you simply use the find command:
- name: exclude an intermediate directory with find command
command: >-
find toplevel -name foo -prune -o -type f -print
register: result
Which will return the following items:
toplevel/bar/testfile2.txt
I've put a runnable version of the above on github.
Ansible's find module's excludes parameter operates on basenames of files. Per the documentation:
excludes: One or more (shell or regex) patterns, which type is controlled by use_regex option. Items whose basenames match an excludes pattern are culled from patterns matches. Multiple patterns can be specified using a list.
In your case, it is correctly ignoring /app/Patchbackup/ because its basename is Patchbackup, but also correctly including /app/Patchbackup/app/apache-test-9.0.10/bin/test-juli.jar because its basename is test-juli.jar.
As you realized, the find module doesn't provide you with an option to start with the root dir of /app but exclude one of its directories. You have a few options:
if the dirs under /app are not many, you can use the clause paths to provide a list of them (excluding the undesired Patchbackup)
retrieve all results under /app and then filter out the ones from /app/Patchbackup that you don't want. Here is an example of how to filter them out:
Code:
- set_fact:
my_results_final: "{{ my_results_final | default([]) + [item] }}"
when: item is not regex('^/app/Patchbackup(.+)')
with_items:
- "{{ tomjarfound.files }}"
- debug:
var: my_results_final
My solution to this omission is to go with json_query filter:
- find:
paths: /app
recurse: true
patterns: 'test-juli.jar'
register: results
- set_fact:
final_result: "{{ results | to_json | from_json | json_query(_query) }}"
vars:
_query: "files[?!contains(path, 'Patchbackup')]"
you will need to have jmespath python library installed. (if I remember it correctly that | to_json | from_json | part is needed to deal with another types issue.
Related
im currently running into an issue with deleting certain files from our thumbor cache with ansible. After alot of snipping I receive a list with the file names and im running following ansible task to find and delete them:
shell: find . -name {{ item }} -exec rm "{}" \;
args:
chdir: "{{ thumbor_data_path }}"
ignore_errors: true
loop:
- deletion_hash
when: file_url is defined and deletion_hash | length > 0
the list is definitly filled with the correct names of files I know exist and the task itself marks himself as changed, but the files are not getting deleted. The names of the files are sha1 hashes, and are two directories deep.
Is there something wrong with the shell script?
Example of the deletion_hash list:
"msg": [
"115b744b9f6b23bbad3b6181c858cb953136",
"f52f17b2cca937e5586751ff2e938979890b",
"1c39661a0925b3cdb3b524983aaf6cccd6ee",
"1afc79a9e0e3c07ff0e95e1af3b5cb7ae54c",
"424e9159fe652f47c8e01d0aa85a86fbefed",
"11e4994789f24537d6feea085d2bf39c355b",
"a1d2fe0e122d37555df4062d4c0a5d10b651",
"aef976fc897a87091be5a8d5a11698e19591",
"e79f3ee1e6ccb3caff288b0028e031d75d77",
"9448e5e49679c908263922debdffff68eecb",
"a3933be52277a341906751c3da2dfb07ccd8",
"bef3370862a7504f7857be396d5a3139f5c0",
"8cc0cbe847234af96c0463d49c258c85d50f",
"1e7bf6110dcf994d1270682939e14416fc6e",
"d21dae2c047895129e7c462f6ddc4e512a58",
"c107b29b3185171ec46b479352fab6c97ad2"
]
You can try using the file module; this comes with an assumption that the thumbor_data_path variable does not end with a /; if it does, you need to modify this a bit.
- name: Remove file (delete file)
ansible.builtin.file:
path: "{{ thumbor_data_path }}/{{ item }}"
state: absent
loop: deletion_hash
when: file_url is defined and deletion_hash | length > 0
I'm trying to create a github job that transforms a list of changed files to list of their directories in json format, but completely stuck with the
error shown on screenshot (line 8: Packages/test: Is a directory). Echo command at the end shows empty string.
Action step code here:
- name: Get folders
id: get-folders
run: |
echo "Changed packages: ${{ steps.filter.outputs.changed_files }}"
folders=()
for package in ${{ steps.filter.outputs.changed_files }};
do
folder="$(dirname ${package})"
folders+=("${folder}")
done
result=$("${folders[#]}" | jq -R . | jq -s)
#result=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${folders[#]}")
echo '::set-output name=FOLDERS::${result}'
- run: echo "${{ steps.get-folders.outputs.FOLDERS }}"
YOUR_BASH_ARRAY=( a b c );
jsonString="$(jq --compact-output --null-input '$ARGS.positional' --args -- "${YOUR_BASH_ARRAY[#]}")"
Result: jsonString==["a","b","c"]
Credit to pmf for calling out the answer provided by the ops' question.
1) I have cloned a bitbucket repo name myrepo which has 5 folders..branch name is development.
2) In all 5 folders (A,B,C,D,E) I need to view A folder contents using jenkins pipeline so that the user will have choice to pick/select.
3) All files names should be shown as xxx only not as xxx_yar.yaml.
I have implemented one func which clones bitbucket repo and executing shell command to find A dir and removing _yar.yaml and getting output as xxx.
Here the problem is I am not able to switch from myrepo folder to A folder to execute shell command:
def CREDS="xxxxxx"
static void clonerepo(CREDS) {
def git branch: "development",
credentialsId: "${CREDS}",
url: "https://bitbucket.com/xxx/xx/myrepo.git"
sh(find A -type f -maxdepth 1 | cut -d "/" -f 2 | sed -e "s/_yar.yaml//g")
}
After this in pipeline question I have given in below format
MYNAME=input( id: 'userInput', message: 'What is the application?', parameters: [ [$class: 'ChoiceParameterDefinition', choices: clonerepo, description: '', name: ''] ])
so that in above choices all A files contents will be shown to user.
There is a file: test.txt on remote1 and remote2 which has version with date and these file contains are n't fixed.
$ cat test.txt
Release_P1.11_2017-08-02-094316
02/08/2017
I need to check:
if file contains are same, then move on further tasks.
if file contains are not same, then stop the tasks.
---
- name: latest file check
stat:
path: /tmp/test.txt
get_checksum: yes
register: test_file_check
- debug:
var: test_file_check.stat.checksum
Now if file contains are same, checksum value are equal otherwise it doesn't have same. but I don't figure out the solution.
All you need is second time check and when condition
- hosts: remote_1
tasks:
- name: first file check
stat:
path: /tmp/test.txt
get_checksum: yes
register: test_file_check_1
...........................................
- hosts: remote_2
tasks:
- name: next check
stat:
path: /tmp/test.txt
get_checksum: yes
register: test_file_check_2
...........................................
- name: Block run only if file has no changes
command: /bin/true
when: test_file_check_1.stat.checksum == test_file_check_2.stat.checksum
http://docs.ansible.com/ansible/latest/playbooks_conditionals.html
How do I use the when statement based on the standard output of register: result? If standard output exists I want somecommand to run if no standard output exists I want someothercommand to run.
- hosts: myhosts
tasks:
- name: echo hello
command: echo hello
register: result
- command: somecommand {{ result.stdout }}
when: result|success
- command: someothercommand
when: result|failed
Try checking to see it if equals a blank string or not?
- hosts: myhosts
tasks:
- name: echo hello
command: echo hello
register: result
- command: somecommand {{ result.stdout }}
when: result.stdout != ""
- command: someothercommand
when: result.stdout == ""
As of 2018, the recommended way to test if output is empty is just:
when: result.stdout | length > 0
That is the pythonic way of evaluating truth, null, empty strings, empty lists all evaluate as false.
Other older alternatives not recommended or even not working:
result.stdout != "" would not pass ansible-lint check!
result.stdout | bool will NOT work as most strings will evaluate as False, only cases where it would return true is if stdout happens to be one of the true, yes,... kind of strings.
result.stdout used to work but now triggers:
[DEPRECATION WARNING]: evaluating as a bare variable, this
behaviour will go away and you might need to add |bool to the
expression in the future. Also see CONDITIONAL_BARE_VARS configuration
toggle.. This feature will be removed in version 2.12. Deprecation
warnings can be disabled by setting deprecation_warnings=False in
ansible.cfg.`
To expand on this answer and address the comment regarding potential problems if stdout isn't defined, the following when statement can be used to ensure stdout is defined before trying to check its length:
when: result.stdout is defined and result.stdout | length > 0