Revision 8c574358
b/image_creator/__init__.py | ||
---|---|---|
35 | 35 |
|
36 | 36 |
import image_creator.os_type |
37 | 37 |
|
38 |
|
|
38 | 39 |
def get_os_class(distro, osfamily): |
39 | 40 |
module = None |
40 | 41 |
classname = None |
b/image_creator/disk.py | ||
---|---|---|
13 | 13 |
from pbs import blockdev |
14 | 14 |
from pbs import dd |
15 | 15 |
|
16 |
class DiskError(Exception): pass |
|
16 |
|
|
17 |
class DiskError(Exception): |
|
18 |
pass |
|
19 |
|
|
17 | 20 |
|
18 | 21 |
class Disk(object): |
19 | 22 |
|
... | ... | |
38 | 41 |
while len(self._devices): |
39 | 42 |
device = self._devices.pop() |
40 | 43 |
device.destroy() |
41 |
|
|
44 |
|
|
42 | 45 |
while len(self._cleanup_jobs): |
43 | 46 |
job, args = self._cleanup_jobs.pop() |
44 | 47 |
job(*args) |
... | ... | |
57 | 60 |
size = blockdev('--getsize', sourcedev) |
58 | 61 |
cowfd, cow = tempfile.mkstemp() |
59 | 62 |
self._add_cleanup(os.unlink, cow) |
60 |
# Create 1G cow file |
|
61 |
dd('if=/dev/null', 'of=%s' % cow, 'bs=1k' ,'seek=%d' % (1024*1024))
|
|
63 |
# Create 1G cow sparse file
|
|
64 |
dd('if=/dev/null', 'of=%s' % cow, 'bs=1k', 'seek=%d' % (1024 * 1024))
|
|
62 | 65 |
cowdev = self._losetup(cow) |
63 | 66 |
|
64 | 67 |
snapshot = uuid.uuid4().hex |
... | ... | |
79 | 82 |
self._devices.remove(device) |
80 | 83 |
device.destroy() |
81 | 84 |
|
85 |
|
|
82 | 86 |
class DiskDevice(object): |
83 | 87 |
|
84 |
def __init__(self, device, bootable = True):
|
|
88 |
def __init__(self, device, bootable=True):
|
|
85 | 89 |
self.device = device |
86 | 90 |
self.bootable = bootable |
87 | 91 |
|
... | ... | |
89 | 93 |
|
90 | 94 |
self.g.set_trace(1) |
91 | 95 |
|
92 |
self.g.add_drive_opts(device, readonly = 0)
|
|
96 |
self.g.add_drive_opts(device, readonly=0)
|
|
93 | 97 |
self.g.launch() |
94 | 98 |
roots = self.g.inspect_os() |
95 | 99 |
if len(roots) == 0: |
... | ... | |
100 | 104 |
self.root = roots[0] |
101 | 105 |
self.ostype = self.g.inspect_get_type(self.root) |
102 | 106 |
self.distro = self.g.inspect_get_distro(self.root) |
103 |
|
|
107 |
|
|
104 | 108 |
def destroy(self): |
105 | 109 |
self.g.umount_all() |
106 | 110 |
self.g.sync() |
107 | 111 |
# Close the guestfs handler |
108 | 112 |
self.g.close() |
109 | 113 |
del self.g |
110 |
|
|
114 |
|
|
111 | 115 |
def mount(self): |
112 | 116 |
mps = self.g.inspect_get_mountpoints(self.root) |
117 |
|
|
113 | 118 |
# Sort the keys to mount the fs in a correct order. |
114 | 119 |
# / should be mounted befor /boot, etc |
115 |
def compare (a, b): |
|
116 |
if len(a[0]) > len(b[0]): return 1 |
|
117 |
elif len(a[0]) == len(b[0]): return 0 |
|
118 |
else: return -1 |
|
120 |
def compare(a, b): |
|
121 |
if len(a[0]) > len(b[0]): |
|
122 |
return 1 |
|
123 |
elif len(a[0]) == len(b[0]): |
|
124 |
return 0 |
|
125 |
else: |
|
126 |
return -1 |
|
119 | 127 |
mps.sort(compare) |
120 | 128 |
for mp, dev in mps: |
121 | 129 |
try: |
... | ... | |
123 | 131 |
except RuntimeError as msg: |
124 | 132 |
print "%s (ignored)" % msg |
125 | 133 |
|
134 |
def umount(self): |
|
135 |
self.g.umount_all() |
|
136 |
|
|
137 |
def shrink(self): |
|
138 |
dev = self.g.part_to_dev(self.root) |
|
139 |
parttype = self.g.part_get_parttype(dev) |
|
140 |
if parttype != 'msdos': |
|
141 |
raise DiskError("You have a %s partition table. " |
|
142 |
"Only msdos partitions are supported" % parttype) |
|
143 |
|
|
144 |
last_partition = self.g.part_list(dev)[-1] |
|
145 |
|
|
146 |
if last_partition['part_num'] > 4: |
|
147 |
raise DiskError("This disk contains logical partitions. " |
|
148 |
"Only primary partitions are supported.") |
|
149 |
|
|
150 |
part_dev = "%s%d" % (dev, last_partition['part_num']) |
|
151 |
fs_type = self.g.vfs_type(part_dev) |
|
152 |
if not re.match("ext[234]", fs_type): |
|
153 |
print "Warning, don't know how to resize %s partitions" % vfs_type |
|
154 |
return |
|
155 |
|
|
156 |
self.g.e2fsck_f(part_dev) |
|
157 |
self.g.resize2fs_M(part_dev) |
|
158 |
output = self.g.tune2fs_l(part_dev) |
|
159 |
block_size = int(filter(lambda x: x[0] == 'Block size', output)[0][1]) |
|
160 |
block_cnt = int(filter(lambda x: x[0] == 'Block count', output)[0][1]) |
|
161 |
|
|
162 |
sector_size = self.g.blockdev_getss(dev) |
|
163 |
|
|
164 |
start = last_partition['part_start'] / sector_size |
|
165 |
end = start + (block_size * block_cnt) / sector_size - 1 |
|
166 |
|
|
167 |
|
|
168 |
|
|
126 | 169 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |
b/image_creator/main.py | ||
---|---|---|
36 | 36 |
import sys |
37 | 37 |
import os |
38 | 38 |
|
39 |
|
|
39 | 40 |
def main(): |
40 | 41 |
if len(sys.argv) != 3: |
41 | 42 |
sys.exit("Usage: %s <source> <output_file>" % |
... | ... | |
50 | 51 |
osclass = get_os_class(dev.distro, dev.ostype) |
51 | 52 |
image_os = osclass(dev.root, dev.g) |
52 | 53 |
metadata = image_os.get_metadata() |
53 |
for key, val in metadata.iteritems(): |
|
54 |
print "%s=%s" % (key,val) |
|
55 |
|
|
56 | 54 |
image_os.data_cleanup() |
55 |
dev.umount() |
|
56 |
dev.shrink() |
|
57 | 57 |
|
58 | 58 |
finally: |
59 | 59 |
disk.cleanup() |
... | ... | |
62 | 62 |
main() |
63 | 63 |
|
64 | 64 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |
65 |
|
b/image_creator/os_type/__init__.py | ||
---|---|---|
1 | 1 |
#!/usr/bin/env python |
2 | 2 |
|
3 |
import re |
|
4 |
|
|
5 |
|
|
3 | 6 |
def add_prefix(target): |
4 | 7 |
def wrapper(self, *args): |
5 | 8 |
prefix = args[0] |
6 | 9 |
return map(lambda x: prefix + x, target(self, *args)) |
7 | 10 |
return wrapper |
8 | 11 |
|
12 |
|
|
9 | 13 |
class OSBase(object): |
10 | 14 |
def __init__(self, rootdev, ghandler): |
11 | 15 |
self.root = rootdev |
12 | 16 |
self.g = ghandler |
13 | 17 |
|
14 | 18 |
@add_prefix |
15 |
def ls(self, directory): return self.g.ls(directory) |
|
19 |
def ls(self, directory): |
|
20 |
return self.g.ls(directory) |
|
16 | 21 |
|
17 | 22 |
@add_prefix |
18 |
def find(self, directory): return self.g.find(directory) |
|
23 |
def find(self, directory): |
|
24 |
return self.g.find(directory) |
|
25 |
|
|
26 |
def foreach_file(self, directory, action, **kargs): |
|
27 |
|
|
28 |
maxdepth = None if 'maxdepth' not in kargs else kargs['maxdepth'] |
|
29 |
if maxdepth == 0: |
|
30 |
return |
|
31 |
|
|
32 |
# maxdepth -= 1 |
|
33 |
maxdepth = None if maxdepth is None else maxdepth - 1 |
|
34 |
kargs['maxdepth'] = maxdepth |
|
35 |
|
|
36 |
exclude = None if 'exclude' not in kargs else kargs['exclude'] |
|
37 |
ftype = None if 'ftype' not in kargs else kargs['ftype'] |
|
38 |
has_ftype = lambda x, y: y is None and True or x['ftyp'] == y |
|
39 |
|
|
40 |
for f in self.g.readdir(directory): |
|
41 |
if f['name'] in ('.', '..'): |
|
42 |
continue |
|
43 |
|
|
44 |
full_path = "%s/%s" % (directory, f['name']) |
|
45 |
|
|
46 |
if exclude and re.match(exclude, full_path): |
|
47 |
continue |
|
48 |
|
|
49 |
if has_ftype(f, 'd'): |
|
50 |
self.foreach_file(full_path, action, **kargs) |
|
51 |
|
|
52 |
if has_ftype(f, ftype): |
|
53 |
action(full_path) |
|
19 | 54 |
|
20 | 55 |
def get_metadata(self): |
21 | 56 |
meta = {} |
... | ... | |
24 | 59 |
meta["description"] = self.g.inspect_get_product_name(self.root) |
25 | 60 |
|
26 | 61 |
return meta |
27 |
|
|
28 |
def mount_all(self): |
|
29 |
mps = g.inspect_get_mountpoints(self.root) |
|
30 |
# Sort the keys to mount the fs in a correct order. |
|
31 |
# / should be mounted befor /boot, etc |
|
32 |
def compare (a, b): |
|
33 |
if len(a[0]) > len(b[0]): return 1 |
|
34 |
elif len(a[0]) == len(b[0]): return 0 |
|
35 |
else: return -1 |
|
36 |
mps.sort(compare) |
|
37 |
for mp, dev in mps: |
|
38 |
try: |
|
39 |
self.g.mount(dev, mp) |
|
40 |
except RuntimeError as msg: |
|
41 |
print "%s (ignored)" % msg |
|
42 |
|
|
43 |
def cleanup_sensitive_data(self): |
|
62 |
|
|
63 |
def data_cleanup(self): |
|
44 | 64 |
raise NotImplementedError |
45 | 65 |
|
46 | 66 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |
b/image_creator/os_type/freebsd.py | ||
---|---|---|
1 | 1 |
from image_creator.os_type.unix import Unix |
2 | 2 |
|
3 |
|
|
3 | 4 |
class Freebsd(Unix): |
4 |
pass
|
|
5 |
pass
|
|
5 | 6 |
|
6 | 7 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |
b/image_creator/os_type/hurd.py | ||
---|---|---|
1 | 1 |
from image_creator.os_type.unix import Unix |
2 | 2 |
|
3 |
|
|
3 | 4 |
class Hard(Unix): |
4 |
pass
|
|
5 |
pass
|
|
5 | 6 |
|
6 | 7 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |
b/image_creator/os_type/linux.py | ||
---|---|---|
1 | 1 |
from image_creator.os_type.unix import Unix |
2 | 2 |
|
3 |
|
|
3 | 4 |
class Linux(Unix): |
4 |
pass
|
|
5 |
pass
|
|
5 | 6 |
|
6 | 7 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |
b/image_creator/os_type/netbsd.py | ||
---|---|---|
1 | 1 |
from image_creator.os_type.unix import Unix |
2 | 2 |
|
3 |
|
|
3 | 4 |
class Netbsd(Unix): |
4 |
pass
|
|
5 |
pass
|
|
5 | 6 |
|
6 | 7 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |
b/image_creator/os_type/slackware.py | ||
---|---|---|
1 |
from image_creator.os_type.linux import Linux |
|
2 |
|
|
3 |
|
|
4 |
class Slackware(Linux): |
|
5 |
def cleanup_log(self): |
|
6 |
# In slackware the the installed packages info are stored in |
|
7 |
# /var/log/packages. Clearing all /var/log files will destroy |
|
8 |
# the package management |
|
9 |
self.foreach_file('/var/log', self.g.truncate, ftype='r', \ |
|
10 |
exclude='/var/log/packages') |
|
11 |
|
|
12 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |
b/image_creator/os_type/unix.py | ||
---|---|---|
1 | 1 |
#!/usr/bin/env python |
2 | 2 |
|
3 | 3 |
import re |
4 |
import sys |
|
4 | 5 |
|
5 | 6 |
from image_creator.os_type import OSBase |
6 | 7 |
|
8 |
|
|
7 | 9 |
class Unix(OSBase): |
8 | 10 |
|
9 | 11 |
sensitive_userdata = ['.bash_history'] |
... | ... | |
36 | 38 |
self.cleanup_log() |
37 | 39 |
|
38 | 40 |
def cleanup_tmp(self): |
39 |
files = [] |
|
40 |
files.extend(self.ls('/tmp/')) |
|
41 |
files.extend(self.ls('/var/tmp/')) |
|
42 |
|
|
43 |
for filename in files: |
|
44 |
self.g.rm_rf(filename) |
|
41 |
self.foreach_file('/tmp', self.g.rm_rf, maxdepth=1) |
|
45 | 42 |
|
46 | 43 |
def cleanup_log(self): |
47 |
files = self.find( '/var/log/')
|
|
44 |
self.foreach_file('/var/log', self.g.truncate, ftype='r')
|
|
48 | 45 |
|
49 |
for filename in filter(self.g.is_file, files): |
|
50 |
self.g.truncate(filename) |
|
51 |
|
|
52 | 46 |
def cleanup_userdata(self): |
53 | 47 |
homedirs = ['/root'] + self.ls('/home/') |
54 | 48 |
|
55 | 49 |
for homedir in homedirs: |
56 | 50 |
for data in self.sensitive_userdata: |
57 | 51 |
fname = "%s/%s" % (homedir, data) |
58 |
print "Filename: %s\n" % fname |
|
59 | 52 |
if self.g.is_file(fname): |
60 | 53 |
self.g.scrub_file(fname) |
61 | 54 |
|
b/image_creator/os_type/windows.py | ||
---|---|---|
1 | 1 |
from image_creator.os_type import OSBase |
2 | 2 |
|
3 |
|
|
3 | 4 |
class Windows(OSBase): |
4 |
pass
|
|
5 |
pass
|
|
5 | 6 |
|
6 | 7 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |
Also available in: Unified diff