1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
|
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2013, Jeroen Hoekx <jeroen.hoekx@dsquare.be>
# Copyright (c) 2016, Matt Robinson <git@nerdoftheherd.com>
# Copyright (c) 2017, Dag Wieers <dag@wieers.com>
# Copyright (c) 2017, Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r'''
---
author:
- Jeroen Hoekx (@jhoekx)
- Matt Robinson (@ribbons)
- Dag Wieers (@dagwieers)
module: iso_extract
short_description: Extract files from an ISO image
description:
- This module has two possible ways of operation.
- If 7zip is installed on the system, this module extracts files from an ISO
into a temporary directory and copies files to a given destination,
if needed.
- If the user has mount-capabilities (CAP_SYS_ADMIN on Linux) this module
mounts the ISO image to a temporary location, and copies files to a given
destination, if needed.
requirements:
- Either 7z (from C(7zip) or C(p7zip) package)
- Or mount capabilities (root-access, or CAP_SYS_ADMIN capability on Linux)
extends_documentation_fragment:
- community.general.attributes
attributes:
check_mode:
support: full
diff_mode:
support: none
options:
image:
description:
- The ISO image to extract files from.
type: path
required: true
aliases: [ path, src ]
dest:
description:
- The destination directory to extract files to.
type: path
required: true
files:
description:
- A list of files to extract from the image.
- Extracting directories does not work.
type: list
elements: str
required: true
force:
description:
- If V(true), which will replace the remote file when contents are different than the source.
- If V(false), the file will only be extracted and copied if the destination does not already exist.
type: bool
default: true
executable:
description:
- The path to the C(7z) executable to use for extracting files from the ISO.
- If not provided, it will assume the value V(7z).
type: path
notes:
- Only the file checksum (content) is taken into account when extracting files
from the ISO image. If O(force=false), only checks the presence of the file.
'''
EXAMPLES = r'''
- name: Extract kernel and ramdisk from a LiveCD
community.general.iso_extract:
image: /tmp/rear-test.iso
dest: /tmp/virt-rear/
files:
- isolinux/kernel
- isolinux/initrd.cgz
'''
RETURN = r'''
#
'''
import os.path
import shutil
import tempfile
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
image=dict(type='path', required=True, aliases=['path', 'src']),
dest=dict(type='path', required=True),
files=dict(type='list', elements='str', required=True),
force=dict(type='bool', default=True),
executable=dict(type='path'), # No default on purpose
),
supports_check_mode=True,
)
image = module.params['image']
dest = module.params['dest']
files = module.params['files']
force = module.params['force']
executable = module.params['executable']
result = dict(
changed=False,
dest=dest,
image=image,
)
# We want to know if the user provided it or not, so we set default here
if executable is None:
executable = '7z'
binary = module.get_bin_path(executable, None)
# When executable was provided and binary not found, warn user !
if module.params['executable'] is not None and not binary:
module.warn("Executable '%s' is not found on the system, trying to mount ISO instead." % executable)
if not os.path.exists(dest):
module.fail_json(msg="Directory '%s' does not exist" % dest)
if not os.path.exists(os.path.dirname(image)):
module.fail_json(msg="ISO image '%s' does not exist" % image)
result['files'] = []
extract_files = list(files)
if not force:
# Check if we have to process any files based on existence
for f in files:
dest_file = os.path.join(dest, os.path.basename(f))
if os.path.exists(dest_file):
result['files'].append(dict(
checksum=None,
dest=dest_file,
src=f,
))
extract_files.remove(f)
if not extract_files:
module.exit_json(**result)
tmp_dir = tempfile.mkdtemp()
# Use 7zip when we have a binary, otherwise try to mount
if binary:
cmd = [binary, 'x', image, '-o%s' % tmp_dir] + extract_files
else:
cmd = [module.get_bin_path('mount'), '-o', 'loop,ro', image, tmp_dir]
rc, out, err = module.run_command(cmd)
if rc != 0:
result.update(dict(
cmd=cmd,
rc=rc,
stderr=err,
stdout=out,
))
shutil.rmtree(tmp_dir)
if binary:
module.fail_json(msg="Failed to extract from ISO image '%s' to '%s'" % (image, tmp_dir), **result)
else:
module.fail_json(msg="Failed to mount ISO image '%s' to '%s', and we could not find executable '%s'." % (image, tmp_dir, executable), **result)
try:
for f in extract_files:
tmp_src = os.path.join(tmp_dir, f)
if not os.path.exists(tmp_src):
module.fail_json(msg="Failed to extract '%s' from ISO image" % f, **result)
src_checksum = module.sha1(tmp_src)
dest_file = os.path.join(dest, os.path.basename(f))
if os.path.exists(dest_file):
dest_checksum = module.sha1(dest_file)
else:
dest_checksum = None
result['files'].append(dict(
checksum=src_checksum,
dest=dest_file,
src=f,
))
if src_checksum != dest_checksum:
if not module.check_mode:
shutil.copy(tmp_src, dest_file)
result['changed'] = True
finally:
if not binary:
module.run_command([module.get_bin_path('umount'), tmp_dir])
shutil.rmtree(tmp_dir)
module.exit_json(**result)
if __name__ == '__main__':
main()
|