mirror of
				https://github.com/ansible-collections/community.general.git
				synced 2024-09-14 20:13:21 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			220 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			220 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/python
 | |
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| # Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com>
 | |
| # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
 | |
| from __future__ import (absolute_import, division, print_function)
 | |
| __metaclass__ = type
 | |
| 
 | |
| DOCUMENTATION = '''
 | |
| ---
 | |
| module: sapcar_extract
 | |
| short_description: Manages SAP SAPCAR archives
 | |
| version_added: "3.2.0"
 | |
| description:
 | |
|     - Provides support for unpacking C(sar)/C(car) files with the SAPCAR binary from SAP and pulling
 | |
|       information back into Ansible.
 | |
| options:
 | |
|   path:
 | |
|     description: The path to the SAR/CAR file.
 | |
|     type: path
 | |
|     required: true
 | |
|   dest:
 | |
|     description:
 | |
|       - The destination where SAPCAR extracts the SAR file. Missing folders will be created.
 | |
|         If this parameter is not provided it will unpack in the same folder as the SAR file.
 | |
|     type: path
 | |
|   binary_path:
 | |
|     description:
 | |
|       - The path to the SAPCAR binary, for example, C(/home/dummy/sapcar) or C(https://myserver/SAPCAR).
 | |
|         If this parameter is not provided the module will look in C(PATH).
 | |
|     type: path
 | |
|   signature:
 | |
|     description:
 | |
|       - If C(true) the signature will be extracted.
 | |
|     default: false
 | |
|     type: bool
 | |
|   security_library:
 | |
|     description:
 | |
|       - The path to the security library, for example, C(/usr/sap/hostctrl/exe/libsapcrytp.so), for signature operations.
 | |
|     type: path
 | |
|   manifest:
 | |
|     description:
 | |
|       - The name of the manifest.
 | |
|     default: "SIGNATURE.SMF"
 | |
|     type: str
 | |
|   remove:
 | |
|     description:
 | |
|       - If C(true) the SAR/CAR file will be removed. B(This should be used with caution!)
 | |
|     default: false
 | |
|     type: bool
 | |
| author:
 | |
|     - Rainer Leber (@RainerLeber)
 | |
| notes:
 | |
|     - Always returns C(changed=true) in C(check_mode).
 | |
| '''
 | |
| 
 | |
| EXAMPLES = """
 | |
| - name: Extract SAR file
 | |
|   community.general.sapcar_extract:
 | |
|     path: "~/source/hana.sar"
 | |
| 
 | |
| - name: Extract SAR file with destination
 | |
|   community.general.sapcar_extract:
 | |
|     path: "~/source/hana.sar"
 | |
|     dest: "~/test/"
 | |
| 
 | |
| - name: Extract SAR file with destination and download from webserver can be a fileshare as well
 | |
|   community.general.sapcar_extract:
 | |
|     path: "~/source/hana.sar"
 | |
|     dest: "~/dest/"
 | |
|     binary_path: "https://myserver/SAPCAR"
 | |
| 
 | |
| - name: Extract SAR file and delete SAR after extract
 | |
|   community.general.sapcar_extract:
 | |
|     path: "~/source/hana.sar"
 | |
|     remove: true
 | |
| 
 | |
| - name: Extract SAR file with manifest
 | |
|   community.general.sapcar_extract:
 | |
|     path: "~/source/hana.sar"
 | |
|     signature: true
 | |
| 
 | |
| - name: Extract SAR file with manifest and rename it
 | |
|   community.general.sapcar_extract:
 | |
|     path: "~/source/hana.sar"
 | |
|     manifest: "MyNewSignature.SMF"
 | |
|     signature: true
 | |
| """
 | |
| 
 | |
| import os
 | |
| from tempfile import NamedTemporaryFile
 | |
| from ansible.module_utils.basic import AnsibleModule
 | |
| from ansible.module_utils.urls import open_url
 | |
| from ansible.module_utils.common.text.converters import to_native
 | |
| 
 | |
| 
 | |
| def get_list_of_files(dir_name):
 | |
|     # create a list of file and directories
 | |
|     # names in the given directory
 | |
|     list_of_file = os.listdir(dir_name)
 | |
|     allFiles = list()
 | |
|     # Iterate over all the entries
 | |
|     for entry in list_of_file:
 | |
|         # Create full path
 | |
|         fullPath = os.path.join(dir_name, entry)
 | |
|         # If entry is a directory then get the list of files in this directory
 | |
|         if os.path.isdir(fullPath):
 | |
|             allFiles = allFiles + [fullPath]
 | |
|             allFiles = allFiles + get_list_of_files(fullPath)
 | |
|         else:
 | |
|             allFiles.append(fullPath)
 | |
|     return allFiles
 | |
| 
 | |
| 
 | |
| def download_SAPCAR(binary_path, module):
 | |
|     bin_path = None
 | |
|     # download sapcar binary if url is provided otherwise path is returned
 | |
|     if binary_path is not None:
 | |
|         if binary_path.startswith('https://') or binary_path.startswith('http://'):
 | |
|             random_file = NamedTemporaryFile(delete=False)
 | |
|             with open_url(binary_path) as response:
 | |
|                 with random_file as out_file:
 | |
|                     data = response.read()
 | |
|                     out_file.write(data)
 | |
|             os.chmod(out_file.name, 0o700)
 | |
|             bin_path = out_file.name
 | |
|             module.add_cleanup_file(bin_path)
 | |
|         else:
 | |
|             bin_path = binary_path
 | |
|     return bin_path
 | |
| 
 | |
| 
 | |
| def check_if_present(command, path, dest, signature, manifest, module):
 | |
|     # manipuliating output from SAR file for compare with already extracted files
 | |
|     iter_command = [command, '-tvf', path]
 | |
|     sar_out = module.run_command(iter_command)[1]
 | |
|     sar_raw = sar_out.split("\n")[1:]
 | |
|     if dest[-1] != "/":
 | |
|         dest = dest + "/"
 | |
|     sar_files = [dest + x.split(" ")[-1] for x in sar_raw if x]
 | |
|     # remove any SIGNATURE.SMF from list because it will not unpacked if signature is false
 | |
|     if not signature:
 | |
|         sar_files = [item for item in sar_files if '.SMF' not in item]
 | |
|     # if signature is renamed manipulate files in list of sar file for compare.
 | |
|     if manifest != "SIGNATURE.SMF":
 | |
|         sar_files = [item for item in sar_files if '.SMF' not in item]
 | |
|         sar_files = sar_files + [manifest]
 | |
|     # get extracted files if present
 | |
|     files_extracted = get_list_of_files(dest)
 | |
|     # compare extracted files with files in sar file
 | |
|     present = all(elem in files_extracted for elem in sar_files)
 | |
|     return present
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     module = AnsibleModule(
 | |
|         argument_spec=dict(
 | |
|             path=dict(type='path', required=True),
 | |
|             dest=dict(type='path'),
 | |
|             binary_path=dict(type='path'),
 | |
|             signature=dict(type='bool', default=False),
 | |
|             security_library=dict(type='path'),
 | |
|             manifest=dict(type='str', default="SIGNATURE.SMF"),
 | |
|             remove=dict(type='bool', default=False),
 | |
|         ),
 | |
|         supports_check_mode=True,
 | |
|     )
 | |
|     rc, out, err = [0, "", ""]
 | |
|     params = module.params
 | |
|     check_mode = module.check_mode
 | |
| 
 | |
|     path = params['path']
 | |
|     dest = params['dest']
 | |
|     signature = params['signature']
 | |
|     security_library = params['security_library']
 | |
|     manifest = params['manifest']
 | |
|     remove = params['remove']
 | |
| 
 | |
|     bin_path = download_SAPCAR(params['binary_path'], module)
 | |
| 
 | |
|     if dest is None:
 | |
|         dest_head_tail = os.path.split(path)
 | |
|         dest = dest_head_tail[0] + '/'
 | |
|     else:
 | |
|         if not os.path.exists(dest):
 | |
|             os.makedirs(dest, 0o755)
 | |
| 
 | |
|     if bin_path is not None:
 | |
|         command = [module.get_bin_path(bin_path, required=True)]
 | |
|     else:
 | |
|         try:
 | |
|             command = [module.get_bin_path('sapcar', required=True)]
 | |
|         except Exception as e:
 | |
|             module.fail_json(msg='Failed to find SAPCAR at the expected path or URL "{0}". Please check whether it is available: {1}'
 | |
|                              .format(bin_path, to_native(e)))
 | |
| 
 | |
|     present = check_if_present(command[0], path, dest, signature, manifest, module)
 | |
| 
 | |
|     if not present:
 | |
|         command.extend(['-xvf', path, '-R', dest])
 | |
|         if security_library:
 | |
|             command.extend(['-L', security_library])
 | |
|         if signature:
 | |
|             command.extend(['-manifest', manifest])
 | |
|         if not check_mode:
 | |
|             (rc, out, err) = module.run_command(command, check_rc=True)
 | |
|         changed = True
 | |
|     else:
 | |
|         changed = False
 | |
|         out = "allready unpacked"
 | |
| 
 | |
|     if remove:
 | |
|         os.remove(path)
 | |
| 
 | |
|     module.exit_json(changed=changed, message=rc, stdout=out,
 | |
|                      stderr=err, command=' '.join(command))
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     main()
 |