Extract a directory from tar archive using ansible unarchive - ansible

I'd like to extract one directory from tar file.
In Linux OS for install directory unpacking - I simply do:
tar -xvf ingres.tar install
For ansible I've tried:
unarchive:
remote_src: yes
src: /ingres/ingres.tar
dest: /ingres
extra_opts:
- "install"
But it doesn't work of course. Any idea?

The GNU tar command has an option to select archive members: --add-file. Section 6.2 of the manual mentions it:
If a file name begins with dash (-), precede it with --add-file option to prevent it from being treated as an option.
However, it works for other files too, which means you can specify this option in the extra_opts of your task to select file(s) or directories to extract:
unarchive:
remote_src: yes
src: /ingres/ingres.tar
dest: /ingres
extra_opts:
- "--add-file"
- "install"

Related

Extracting multi part zip files with Ansible (Example case: WebSphere installation)

For HCL Connections, we still need WebSphere and I want to automate this complex and slow process with Ansible. WebSphere needs to be manually downloaded with differenet ZIP files for each component, for example:
├── CIK1VML.zip
├── CIK1WML.zip
└── CIK1XML.zip
The char after CIK1 identifies the part. On the command line, I can unzip them by replacing those part identifier with a question mark:
unzip '/cnx-smb/was/supplements/CIK1?ML.zip' -d /tmp/was-suppl-manual
I'd like to use the unarchive module cause it supports features like remote_src which would be usefull for me, so I tried a simple POC playbook:
- hosts: 127.0.0.1
connection: local
tasks:
- name: Unpack test
become: yes
unarchive:
src: "/cnx-smb/was/supplements/CIK1?ML.zip"
remote_src: no
dest: "/tmp/was-extracted"
But this doesn't work:
TASK [Unpack test] **********************************************************************************************************************************************************************************************************************************************************
Wednesday 10 February 2021 16:17:25 +0000 (0:00:00.637) 0:00:00.651 ****
fatal: [127.0.0.1]: FAILED! => changed=false
msg: |-
Could not find or access '/cnx-smb/was/supplements/'CIK1?ML.zip'' on the Ansible Controller.
If you are using a module and expect the file to exist on the remote, see the remote_src option
I also tried different src paths like /cnx-smb/was/supplements/'CIK1?ML.zip', cause the unzip CLI call works only when at least the filename is masked in quotes, or alternatively the entire path. Ansible accepts only when the file name is quoted, '/cnx-smb/was/supplements/CIK1?ML.zip' seems to be interpreted as relative path (which obviously fails).
It seems that those multipart zip-archives aren't really "multi part" archives, as I know from compression formats like 7zip where we have File.partX.7z which are only used together. 7zip validates them and throws an error if e.g. a part is missing.
The situation is different on those zip files. I took a look in them and noticed that I can extract every single zip file without the others. Every zip file contains a part of the installation archive. It seems that zip itself doesn't divide a large folder into parts. It's IBM who put some folders like disk2 in a seperate archive file for whatever reason.
This means I can do the same with ansible: Just extract every single file on its own, but in the same directory:
- hosts: 127.0.0.1
connection: local
vars:
base_dir: /cnx-smb/was/supplements/
tasks:
- name: Unpack
become: yes
unarchive:
src: "{{ base_dir }}/{{ item }}"
remote_src: no
dest: "/tmp/was-extracted"
with_items:
- CIK1VML.zip
- CIK1WML.zip
- CIK1XML.zip
Both extracted folderse (Ansible + manually using zip command with ? placeholder) were of the same size and contains the same data:
vagrant#ansible:/cnx-repo$ du -hs /tmp/was-extracted/
3.0G /tmp/was-extracted/
vagrant#ansible:/cnx-repo$ du -hs /tmp/was-suppl-manual
3.0G /tmp/was-suppl-manual

Ansible unarchive exclude syntax

I'm trying to specify part of an archive not to extract via Ansible's unarchive module using the exclude option.
I believe the syntax should be roughly as shown here...
- name: Extract files from discovered zip file
unarchive:
src: "{{ base_path }}/weblogic-deployment/environments/{{ client_environment }}/discovered_domain.zip"
dest: "{{ base_path }}/weblogic-deployment/environments/{{ client_environment }}/tmp"
exclude:
- ./wlsdeploy/applications/
remote_src: yes
I have tried a great many slight differences but the excluded directory is always output. Any suggestions?
The exclude option is expected to be a list of paths to exclude. So most likely it doesn't support directories alone.
List the directory and file entries that you would like to exclude from the unarchive action.
So try something like:
exclude:
- ./wlsdeploy/applications/*
For some syntax examples, see: unarchive/tasks/main.yml. Also check the source code.
To exclude the folder entirely:
exclude:
- "wlsdeploy/applications"
To extract the folder, but exclude the contents, you can use a glob:
exclude:
- "wlsdeploy/applications/*"
As the paths are relative to the archive, you don't need the preceding ./.
If you need to look inside the archive first (to find the paths), you can use less:
less discovered_domain.zip
From the unarchive tests for exclude:
- name: Unpack archive file excluding regular and glob files.
unarchive:
src: "{{ remote_tmp_dir }}/unarchive-00.{{item}}"
dest: "{{ remote_tmp_dir }}/exclude-{{item}}"
remote_src: yes
exclude:
- "exclude/exclude-*.txt"
- "other/exclude-1.ext"
with_items:
- zip
- tar

Ansible Unarchive command causes error "Failed to find handler"

I operate AmazonLinux2 on EC2 using Ansible. However, when the Unarchive command is executed, the following error is displayed.
"Failed to find handler for \"/tmp/hoge.db.gz\".
Make sure the required command to extract the file is installed.
Command \"/usr/bin/unzip\" could not handle archive. Command \"/usr/bin/gtar\" could not handle archive."
The contents of PlayBook are as follows.
- name: Unarchive hoge
become: yes
unarchive:
src: /tmp/hoge.db.gz
dest: /root/fuga/
remote_src: yes
Below is the information I have examined to identify the cause of the error.
unarchive Requires Command
[root#ip- ~]# which gtar
/usr/bin/gtar
[root#ip- ~]# which unzip
/usr/bin/unzip
[root#ip- ~]# which zipinfo
/usr/bin/zipinfo
PATH
- debug:
var: ansible_env.PATH
"ansible_env.PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin"
The unarchive module cannot handle gzip files unless they are a compressed tar ball (see https://docs.ansible.com/ansible/latest/modules/unarchive_module.html).
You will need to use the copy module to first copy the gzip file, and then the shell module to decompress it using gunzip.
Example:
- copy:
src: /tmp/hoge.db.gz
dest: /root/fuga/hoge.db.gz
- shell: gunzip /root/fuga/hoge.db.gz
You may need to first install gunzip on the managed host
It works if you use the extra_opts like so:
- name: Unarchive hoge
become: true
ansible.builtin.unarchive:
src: /tmp/hoge.db.gz
dest: /root/fuga/
remote_src: yes
extra_opts:
- '-z'
Tested with ansible 2.9.25 and python 3.6.8 on CentOS 8.

Ansible 2.7 : How to list files from unarchive

Need to unarchive a .zip file then list the unpacked files. This is to select some pattern of files and use them in rest of the code
My playbook yaml snippet is
- name: uarchive the opar zip
unarchive:
src: "{{opar_download_path}}/opar.zip"
dest: "{{opar_download_path}}"
remote_src: yes
list_files: yes
I am not able to find details of how to use the result from "list_files",ie how to store the list of files to a variable. I was referring below document
https://docs.ansible.com/ansible/latest/modules/unarchive_module.html
The list_files: yes includes additional response attribute called files. For better understanding, try to print the output unarchived_list.files, as shown below:
- name: unarchive the opar zip
unarchive:
src: "{{opar_download_path}}/opar.zip"
dest: "{{opar_download_path}}"
remote_src: yes
list_files: yes
register: unarchived_list
- name: print unarchived folder list of files
debug: msg="{{unarchived_list.files}}"
More information on registering variables can be found here: https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#registering-variables

Ansible: Copy contents of a directory to a location

I'm willing to transfer the contents of a folder unzipped from a source say myfolder to a location say dest_dir but apparently everything I try moves/copies/generates myfolder in the dest_dir location.
I tried
command: mv src dest_dir
I also tried unarchiving in the dest_dir location using,
unarchive:
src: /path/to/myfolder
dest: dest_dir
copy: no
become: yes
Apparently, for copy module, I found that remote_src does not support recursive copying yet.
What is the correct way to go about this?
Normally, in my system, I would do mv /path/to/myfolder/* dest_dir but wildcards throw an error with Ansible.
I'm using Ansible 2.3.2.
The reason you can't do it easily in Ansible is because Ansible was not designed to do it.
Just execute the command directly with shell module. Your requirement is not idempotent anyway:
- shell: mv /path/to/myfolder/* dest_dir
become: yes
Pay attention to mv defaults, you might want to add -f to prevent it from prompting for confirmation.
Otherwise play with synchronize module, but there's no value added for "move" operation. Just complexity.

Resources