Commit 121f3bc0 authored by Nikos Skalkotos's avatar Nikos Skalkotos
Browse files

Code Cleanup

 * Prefix all private methods with _
 * Write missing docstrings
 * Move all public methods above the private ones
 * Add module docstrings where missing
 * Define source code encodings on all modules
parent 71b0ab28
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,6 +33,10 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""Package for creating images to be used with Synnefo open source cloud
software.
"""
from image_creator.version import __version__
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,6 +33,11 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This module hosts the code that performes the host bundling operation. By
using the create_image method of the BundleVolume class the user can create an
image out of the running system.
"""
import os
import re
import tempfile
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -33,6 +34,11 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This module is the entrance point for the dialog-based version of the
snf-image-creator program. The main function will create a dialog where the
user is asked if he wants to use the program in expert or wizard mode.
"""
import dialog
import sys
import os
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -33,6 +33,10 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This module implements the "expert" mode of the dialog-based version of
snf-image-creator.
"""
import os
import textwrap
import StringIO
......@@ -313,7 +317,7 @@ def kamaki_menu(session):
if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
continue
if len(answer) == 0 and "account" in session:
del session["account"]
del session["account"]
else:
token = answer.strip()
session['account'] = Kamaki.get_account(token)
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -33,6 +33,10 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""Module providing useful functions for the dialog-based version of
snf-image-creator.
"""
import os
from image_creator.output.dialog import GaugeOutput
from image_creator.util import MD5
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -33,6 +33,10 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This module implements the "wizard" mode of the dialog-based version of
snf-image-creator.
"""
import time
import StringIO
......
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,6 +33,8 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""Module hosting the Disk class."""
from image_creator.util import get_command
from image_creator.util import try_fail_repeat
from image_creator.util import free_space
......@@ -50,7 +54,26 @@ losetup = get_command('losetup')
blockdev = get_command('blockdev')
TMP_CANDIDATES = ['/var/tmp', os.path.expanduser('~'), '/mnt']
def get_tmp_dir(default=None):
"""Check tmp directory candidates and return the one with the most
available space.
"""
if default is not None:
return default
TMP_CANDIDATES = ['/var/tmp', os.path.expanduser('~'), '/mnt']
space = map(free_space, TMP_CANDIDATES)
max_idx = 0
max_val = space[0]
for i, val in zip(range(len(space)), space):
if val > max_val:
max_val = val
max_idx = i
# Return the candidate path with more available space
return TMP_CANDIDATES[max_idx]
class Disk(object):
......@@ -71,29 +94,10 @@ class Disk(object):
self.out = output
self.meta = {}
self.tmp = tempfile.mkdtemp(prefix='.snf_image_creator.',
dir=self._get_tmp_dir(tmp))
dir=get_tmp_dir(tmp))
self._add_cleanup(shutil.rmtree, self.tmp)
def _get_tmp_dir(self, default=None):
"""Check tmp directory candidates and return the one with the most
available space.
"""
if default is not None:
return default
space = map(free_space, TMP_CANDIDATES)
max_idx = 0
max_val = space[0]
for i, val in zip(range(len(space)), space):
if val > max_val:
max_val = val
max_idx = i
# Return the candidate path with more available space
return TMP_CANDIDATES[max_idx]
def _add_cleanup(self, job, *args):
"""Add a new job in the cleanup list"""
self._cleanup_jobs.append((job, args))
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,6 +34,8 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This module provides the code for handling GUID partition tables"""
import struct
import sys
import uuid
......
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,11 +33,14 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This package hosts the help files of the programe."""
import sys
import os
def get_help_file(name):
"""Returns the full path of a helpfile"""
dirname = os.path.dirname(sys.modules[__name__].__file__)
return "%s%s%s.rst" % (dirname, os.sep, name)
......
# -*- coding: utf-8 -*-
#
# Copyright 2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,6 +33,11 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This modules provides the interface for working with the ./kamaki library.
The library is used to upload images to and register them with a Synnefo
deployment.
"""
from os.path import basename
from kamaki.cli.config import Config
......@@ -41,7 +48,7 @@ from kamaki.clients.astakos import AstakosClient
class Kamaki(object):
"""Wrapper class for the ./kamaki library"""
CONTAINER = "images"
@staticmethod
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -33,6 +34,10 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This module is the entrance point for the non-interactive version of the
snf-image-creator program.
"""
from image_creator import __version__ as version
from image_creator.disk import Disk
from image_creator.util import FatalError, MD5
......
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,6 +33,10 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This package provides various classes for preparing different Operating
Systems for image creation.
"""
from image_creator.util import FatalError
import textwrap
......@@ -81,7 +87,6 @@ class OSBase(object):
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")
......@@ -92,26 +97,17 @@ class OSBase(object):
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)
if self.meta['OS'] == "unknown":
self.meta['OS'] = self.meta['OSFAMILY']
self.meta['DESCRIPTION'] = self.g.inspect_get_product_name(self.root)
def _is_sysprep(self, obj):
return getattr(obj, 'sysprep', False) and callable(obj)
self.out.output()
def list_syspreps(self):
"""Returns a list of sysprep objects"""
objs = [getattr(self, name) for name in dir(self)
if not name.startswith('_')]
return [x for x in objs if self._is_sysprep(x) and x.executed is False]
def sysprep_info(self, obj):
"""Returns information about a sysprep object"""
assert self._is_sysprep(obj), "Object is not a sysprep"
return (obj.__name__.replace('_', '-'), textwrap.dedent(obj.__doc__))
......@@ -171,17 +167,69 @@ class OSBase(object):
descr = wrapper.fill(textwrap.dedent(sysprep.__doc__))
self.out.output(' %s:\n%s\n' % (name, descr))
def do_sysprep(self):
"""Prepare 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)
finally:
self.umount()
self.out.output()
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("Mounting the media %s ..." % mount_type, False)
if not self._do_mount(readonly):
return False
self.mounted = True
self.out.success('done')
return True
def umount(self):
"""Umount all mounted filesystems."""
self.out.output("Umounting the media ...", False)
self.g.umount_all()
self.mounted = False
self.out.success('done')
def _is_sysprep(self, obj):
"""Checks if an object is a sysprep"""
return getattr(obj, 'sysprep', False) and callable(obj)
@add_prefix
def ls(self, directory):
def _ls(self, directory):
"""List the name of all files under a directory"""
return self.g.ls(directory)
@add_prefix
def find(self, directory):
def _find(self, directory):
"""List the name of all files recursively under a directory"""
return self.g.find(directory)
def foreach_file(self, directory, action, **kargs):
def _foreach_file(self, directory, action, **kargs):
"""Perform an action recursively on all files under a directory.
The following options are allowed:
......@@ -218,35 +266,22 @@ class OSBase(object):
continue
if has_ftype(f, 'd'):
self.foreach_file(full_path, action, **kargs)
self._foreach_file(full_path, action, **kargs)
if has_ftype(f, ftype):
action(full_path)
def do_sysprep(self):
"""Prepere 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_collect_metadata(self):
"""helper method for collect_metadata"""
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)
if self.meta['OS'] == "unknown":
self.meta['OS'] = self.meta['OSFAMILY']
self.meta['DESCRIPTION'] = self.g.inspect_get_product_name(self.root)
def _do_mount(self, readonly):
"""helper method for mount"""
try:
self.g.mount_options('ro' if readonly else 'rw', self.root, '/')
except RuntimeError as msg:
......@@ -255,25 +290,4 @@ class OSBase(object):
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
self.mounted = True
self.out.success('done')
return True
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 :
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,6 +33,8 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This module hosts OS-specific code for FreeBSD."""
from image_creator.os_type.unix import Unix, sysprep
import re
......@@ -41,8 +45,36 @@ class Freebsd(Unix):
def __init__(self, rootdev, ghandler, output):
super(Freebsd, self).__init__(rootdev, ghandler, output)
def _do_collect_metadata(self):
@sysprep()
def cleanup_password(self, print_header=True):
"""Remove all passwords and lock all user accounts"""
if print_header:
self.out.output("Cleaning up passwords & locking all user "
"accounts")
master_passwd = []
for line in self.g.cat('/etc/master.passwd').splitlines():
# Check for empty or comment lines
if len(line.split('#')[0]) == 0:
master_passwd.append(line)
continue
fields = line.split(':')
if fields[1] not in ('*', '!'):
fields[1] = '!'
master_passwd.append(":".join(fields))
self.g.write('/etc/master.passwd', "\n".join(master_passwd) + '\n')
# Make sure no one can login on the system
self.g.rm_rf('/etc/spwd.db')
def _do_collect_metadata(self):
"""Collect metadata about the OS"""
super(Freebsd, self)._do_collect_metadata()
self.meta["USERS"] = " ".join(self._get_passworded_users())
......@@ -56,6 +88,7 @@ class Freebsd(Unix):
del self.meta['USERS']
def _get_passworded_users(self):
"""Returns a list of non-locked user accounts"""
users = []
regexp = re.compile(
'^([^:]+):((?:![^:]+)|(?:[^!*][^:]+)|):(?:[^:]*:){7}(?:[^:]*)'
......@@ -80,18 +113,18 @@ class Freebsd(Unix):
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
# libguestfs can't handle correct freebsd partitions on a 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)
group2 = int(match.group(2))
group3 = int(match.group(3))
dev = '/dev/sd%c%d' % (chr(ord('a') + group2), group3)
try:
self.g.mount_vfs(mopts, 'ufs', dev, mp)
except RuntimeError as msg:
......@@ -103,32 +136,4 @@ class Freebsd(Unix):
return True
@sysprep()
def cleanup_password(self, print_header=True):
"""Remove all passwords and lock all user accounts"""
if print_header:
self.out.output("Cleaning up passwords & locking all user "
"accounts")
master_passwd = []
for line in self.g.cat('/etc/master.passwd').splitlines():
# Check for empty or comment lines
if len(line.split('#')[0]) == 0:
master_passwd.append(line)
continue
fields = line.split(':')
if fields[1] not in ('*', '!'):
fields[1] = '!'
master_passwd.append(":".join(fields))
self.g.write('/etc/master.passwd', "\n".join(master_passwd) + '\n')
# Make sure no one can login on the system
self.g.rm_rf('/etc/spwd.db')
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,6 +33,8 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This module hosts OS-specific code for GNU Hurd."""
from image_creator.os_type.unix import Unix
......
# -*- coding: utf-8 -*-
#
# Copyright 2012 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
......@@ -31,6 +33,8 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
"""This module hosts OS-specific code for Linux"""
from image_creator.os_type.unix import Unix, sysprep
import re
......@@ -44,46 +48,6 @@ class Linux(Unix):