Commit 71b0ab28 authored by Nikos Skalkotos's avatar Nikos Skalkotos

Move mount/umount from image to os_type module

parent bf3a282c
......@@ -38,7 +38,7 @@ import textwrap
import StringIO
from image_creator import __version__ as version
from image_creator.util import MD5
from image_creator.util import MD5, FatalError
from image_creator.output.dialog import GaugeOutput, InfoBoxOutput
from image_creator.kamaki_wrapper import Kamaki, ClientError
from image_creator.help import get_help_file
......@@ -568,30 +568,19 @@ def sysprep(session):
try:
image.out.add(infobox)
try:
image.mount(readonly=False)
try:
err = "Unable to execute the system preparation " \
"tasks. Couldn't mount the media%s."
title = "System Preparation"
if not image.mounted:
d.msgbox(err % "", title=title, width=SMALL_WIDTH)
return
elif image.mounted_ro:
d.msgbox(err % " read-write", title=title,
width=SMALL_WIDTH)
return
# The checksum is invalid. We have mounted the image rw
if 'checksum' in session:
del session['checksum']
# Monitor the metadata changes during syspreps
with MetadataMonitor(session, image.os.meta):
# The checksum is invalid. We have mounted the image rw
if 'checksum' in session:
del session['checksum']
# Monitor the metadata changes during syspreps
with MetadataMonitor(session, image.os.meta):
try:
image.os.do_sysprep()
infobox.finalize()
finally:
image.umount()
except FatalError as e:
title = "System Preparation"
d.msgbox("System Preparation failed: %s" % e,
title=title, width=SMALL_WIDTH)
finally:
image.out.remove(infobox)
finally:
......
......@@ -266,16 +266,8 @@ def create_image(session):
out.clear()
#Sysprep
image.mount(False)
err_msg = "Unable to execute the system preparation tasks."
if not image.mounted:
raise FatalError("%s Couldn't mount the media." % err_msg)
elif image.mounted_ro:
raise FatalError("%s Couldn't mount the media read-write."
% err_msg)
image.os.do_sysprep()
metadata = image.os.meta
image.umount()
#Shrink
size = image.shrink()
......
......@@ -53,8 +53,6 @@ class Image(object):
self.progress_bar = None
self.guestfs_device = None
self.size = 0
self.mounted = False
self.mounted_ro = False
self.g = guestfs.GuestFS()
self.g.add_drive_opts(self.device, readonly=0, format="raw")
......@@ -120,19 +118,10 @@ class Image(object):
if not self.guestfs_enabled:
self.enable()
if not self.mounted:
do_unmount = True
self.mount(readonly=True)
else:
do_unmount = False
try:
cls = os_cls(self.distro, self.ostype)
self._os = cls(self.root, self.g, self.out)
cls = os_cls(self.distro, self.ostype)
self._os = cls(self.root, self.g, self.out)
finally:
if do_unmount:
self.umount()
self._os.collect_metadata()
return self._os
......@@ -156,70 +145,6 @@ class Image(object):
#
# self.progressbar.goto((position * 100) // total)
def mount(self, readonly=False):
"""Mount all disk partitions in a correct order."""
msg = "Mounting the media%s ..." % (" read-only" if readonly else "")
self.out.output(msg, False)
#If something goes wrong when mounting rw, remount the filesystem ro
remount_ro = False
rw_mpoints = ('/', '/etc', '/root', '/home', '/var')
# Sort the keys to mount the fs in a correct order.
# / should be mounted befor /boot, etc
def compare(a, b):
if len(a[0]) > len(b[0]):
return 1
elif len(a[0]) == len(b[0]):
return 0
else:
return -1
mps = self.g.inspect_get_mountpoints(self.root)
mps.sort(compare)
mopts = 'ro' if readonly else 'rw'
for mp, dev in mps:
if self.ostype == 'freebsd':
# libguestfs can't handle correct freebsd partitions on GUID
# Partition Table. We have to do the translation to linux
# device names ourselves
m = re.match('^/dev/((?:ada)|(?:vtbd))(\d+)p(\d+)$', dev)
if m:
m2 = int(m.group(2))
m3 = int(m.group(3))
dev = '/dev/sd%c%d' % (chr(ord('a') + m2), m3)
try:
self.g.mount_options(mopts, dev, mp)
except RuntimeError as msg:
if self.ostype == 'freebsd':
freebsd_mopts = "ufstype=ufs2,%s" % mopts
try:
self.g.mount_vfs(freebsd_mopts, 'ufs', dev, mp)
except RuntimeError as msg:
if readonly is False and mp in rw_mpoints:
remount_ro = True
break
elif readonly is False and mp in rw_mpoints:
remount_ro = True
break
else:
self.out.warn("%s (ignored)" % msg)
if remount_ro:
self.out.warn("Unable to mount %s read-write. "
"Remounting everything read-only..." % mp)
self.umount()
self.mount(True)
else:
self.mounted = True
self.mounted_ro = readonly
self.out.success("done")
def umount(self):
"""Umount all mounted filesystems."""
self.g.umount_all()
self.mounted = False
def _last_partition(self):
"""Return the last partition of the image disk"""
if self.meta['PARTITION_TABLE'] not in 'msdos' 'gpt':
......
......@@ -221,36 +221,23 @@ def image_creator():
image = disk.get_image(snapshot)
# If no customization is to be done, the image should be mounted ro
ro = (not (options.sysprep or options.shrink) or options.print_sysprep)
image.mount(ro)
try:
for sysprep in options.disabled_syspreps:
image.os.disable_sysprep(image.os.get_sysprep_by_name(sysprep))
for sysprep in options.disabled_syspreps:
image.os.disable_sysprep(image.os.get_sysprep_by_name(sysprep))
for sysprep in options.enabled_syspreps:
image.os.enable_sysprep(image.os.get_sysprep_by_name(sysprep))
for sysprep in options.enabled_syspreps:
image.os.enable_sysprep(image.os.get_sysprep_by_name(sysprep))
if options.print_sysprep:
image.os.print_syspreps()
out.output()
if options.print_sysprep:
image.os.print_syspreps()
out.output()
if options.outfile is None and not options.upload:
return 0
if options.sysprep:
image.os.do_sysprep()
if options.outfile is None and not options.upload:
return 0
if options.sysprep:
err_msg = "Unable to perform the system preparation tasks. " \
"Couldn't mount the media%s. Use --no-sysprep if you " \
"don't won't to perform any system preparation task."
if not image.mounted:
raise FatalError(err_msg % "")
elif image.mounted_ro:
raise FatalError(err_msg % " read-write")
image.os.do_sysprep()
metadata = image.os.meta
finally:
image.umount()
metadata = image.os.meta
size = options.shrink and image.shrink() or image.size
metadata.update(image.meta)
......
......@@ -77,9 +77,23 @@ class OSBase(object):
self.root = rootdev
self.g = ghandler
self.out = output
# Collect metadata about the OS
self.meta = {}
def collect_metadata(self):
"""Collect metadata about the OS"""
try:
if not self.mount(readonly=True):
raise FatalError("Unable to mount the media read-only")
self.out.output('Collecting image metadata ...', False)
self._do_collect_metadata()
self.out.success('done')
finally:
self.umount()
def _do_collect_metadata(self):
self.meta['ROOT_PARTITION'] = "%d" % self.g.part_to_partnum(self.root)
self.meta['OSFAMILY'] = self.g.inspect_get_type(self.root)
self.meta['OS'] = self.g.inspect_get_distro(self.root)
......@@ -212,18 +226,54 @@ class OSBase(object):
def do_sysprep(self):
"""Prepere system for image creation."""
self.out.output('Preparing system for image creation:')
try:
if not self.mount(readonly=False):
raise FatalError("Unable to mount the media read-write")
self.out.output('Preparing system for image creation:')
tasks = self.list_syspreps()
enabled = filter(lambda x: x.enabled, tasks)
size = len(enabled)
cnt = 0
for task in enabled:
cnt += 1
self.out.output(('(%d/%d)' % (cnt, size)).ljust(7), False)
task()
setattr(task.im_func, 'executed', True)
self.out.output()
finally:
self.umount()
def _do_mount(self, readonly):
try:
self.g.mount_options('ro' if readonly else 'rw', self.root, '/')
except RuntimeError as msg:
self.out.warn("unable to mount the root partition: %s" % msg)
return False
return True
def mount(self, readonly=False):
"""Mount image."""
if getattr(self, "mounted", False):
return True
mount_type = 'read-only' if readonly else 'read-write'
self.out.output("Mount the media %s ..." % mount_type, False)
if not self._do_mount(readonly):
return False
tasks = self.list_syspreps()
enabled = filter(lambda x: x.enabled, tasks)
self.mounted = True
self.out.success('done')
return True
size = len(enabled)
cnt = 0
for task in enabled:
cnt += 1
self.out.output(('(%d/%d)' % (cnt, size)).ljust(7), False)
task()
setattr(task.im_func, 'executed', True)
self.out.output()
def umount(self):
"""Umount all mounted filesystems."""
self.g.umount_all()
self.mounted = False
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
......@@ -41,6 +41,9 @@ class Freebsd(Unix):
def __init__(self, rootdev, ghandler, output):
super(Freebsd, self).__init__(rootdev, ghandler, output)
def _do_collect_metadata(self):
super(Freebsd, self)._do_collect_metadata()
self.meta["USERS"] = " ".join(self._get_passworded_users())
#The original product name key is long and ugly
......@@ -72,6 +75,34 @@ class Freebsd(Unix):
return users
def _do_mount(self, readonly):
"""Mount partitions in the correct order"""
critical_mpoints = ('/', '/etc', '/root', '/home', '/var')
# libguestfs can't handle correct freebsd partitions on GUID
# Partition Table. We have to do the translation to linux
# device names ourselves
guid_device = re.compile('^/dev/((?:ada)|(?:vtbd))(\d+)p(\d+)$')
mopts = "ufstype=ufs2,%s" % ('ro' if readonly else 'rw')
for mp, dev in self._mountpoints():
match = guid_device.match(dev)
if match:
m2 = int(match.group(2))
m3 = int(match.group(3))
dev = '/dev/sd%c%d' % (chr(ord('a') + m2), m3)
try:
self.g.mount_vfs(mopts, 'ufs', dev, mp)
except RuntimeError as msg:
if mp in critical_mpoints:
self.out.warn('unable to mount %s. Reason: %s' % (mp, msg))
return False
else:
self.out.warn('%s (ignored)' % msg)
return True
@sysprep()
def cleanup_password(self, print_header=True):
"""Remove all passwords and lock all user accounts"""
......
......@@ -44,6 +44,10 @@ class Linux(Unix):
self._uuid = dict()
self._persistent = re.compile('/dev/[hsv]d[a-z][1-9]*')
def _do_collect_metadata(self):
"""Collect metadata about the OS"""
super(Linux, self)._do_collect_metadata()
self.meta["USERS"] = " ".join(self._get_passworded_users())
# Delete the USERS metadata if empty
......
......@@ -39,6 +39,10 @@ class Ubuntu(Linux):
def __init__(self, rootdev, ghandler, output):
super(Ubuntu, self).__init__(rootdev, ghandler, output)
def _do_collect_metadata(self):
"""Collect metadata about the OS"""
super(Ubuntu, self)._do_collect_metadata()
apps = self.g.inspect_list_applications(self.root)
for app in apps:
if app['app_name'] == 'kubuntu-desktop':
......
......@@ -47,8 +47,41 @@ class Unix(OSBase):
'.kamaki.history'
]
def __init__(self, rootdev, ghandler, output):
super(Unix, self).__init__(rootdev, ghandler, output)
def _mountpoints(self):
"""Return mountpoints in the correct order.
/ should be mounted before /boot or /usr, /usr befor /usr/bin ...
"""
mps = self.g.inspect_get_mountpoints(self.root)
def compare(a, b):
if len(a[0]) > len(b[0]):
return 1
elif len(a[0]) == len(b[0]):
return 0
else:
return -1
mps.sort(compare)
for mp in mps:
yield mp
def _do_mount(self, readonly):
"""Mount partitions in the correct order"""
critical_mpoints = ('/', '/etc', '/root', '/home', '/var')
mopts = 'ro' if readonly else 'rw'
for mp, dev in self._mountpoints():
try:
self.g.mount_options(mopts, dev, mp)
except RuntimeError as msg:
if mp in critical_mpoint:
self.out.warn('unable to mount %s. Reason: %s' % (mp, msg))
return False
else:
self.out.warn('%s (ignored)' % msg)
return True
@sysprep()
def cleanup_cache(self, print_header=True):
......
__version__ = "0.3next"
__version_info__ = ['0', '3next']
__version_vcs_info__ = {'branch': 'develop',
'revid': '9c060ab',
'revno': 297,
'toplevel': '/home/skalkoto/src/snf-image-creator'}
__version_vcs_info__ = {
'branch': 'develop',
'revid': '9c060ab',
'revno': 297,
'toplevel': '/home/skalkoto/src/snf-image-creator'}
__version_user_info__ = "skalkoto@darkstar.admin.grnet.gr"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment