Merge branch 'hotfix-0.4.4' into develop
authorNikos Skalkotos <skalkoto@grnet.gr>
Wed, 31 Jul 2013 12:53:59 +0000 (15:53 +0300)
committerNikos Skalkotos <skalkoto@grnet.gr>
Wed, 31 Jul 2013 12:53:59 +0000 (15:53 +0300)
Conflicts:
image_creator/os_type/unix.py
image_creator/version.py
version

1  2 
image_creator/os_type/__init__.py
image_creator/os_type/unix.py
image_creator/version.py
version

@@@ -41,8 -41,6 +41,8 @@@ from image_creator.util import FatalErr
  
  import textwrap
  import re
 +from collections import namedtuple
 +from functools import wraps
  
  
  def os_cls(distro, osfamily):
  
  
  def add_prefix(target):
 +    """Decorator that adds a prefix to the result of a function"""
      def wrapper(self, *args):
          prefix = args[0]
 -        return map(lambda x: prefix + x, target(self, *args))
 +        return [prefix + path for path in target(self, *args)]
      return wrapper
  
  
 -def sysprep(enabled=True):
 +def sysprep(message, enabled=True, **kwargs):
      """Decorator for system preparation tasks"""
 +    def wrapper(method):
 +        method.sysprep = True
 +        method.enabled = enabled
 +        method.executed = False
 +
 +        for key, val in kwargs.items():
 +            setattr(method, key, val)
 +
 +        @wraps(method)
 +        def inner(self, print_message=True):
 +            if print_message:
 +                self.out.output(message)
 +            return method(self)
 +
 +        return inner
 +    return wrapper
 +
 +
 +def add_sysprep_param(name, type, default, descr, validate=lambda x: True):
 +    """Decorator for __init__ that adds the definition for a system preparation
 +    parameter in an instance of a os_type class
 +    """
 +    def wrapper(init):
 +        @wraps(init)
 +        def inner(self, *args, **kwargs):
 +            init(self, *args, **kwargs)
 +            self.needed_sysprep_params[name] = \
 +                self.SysprepParam(type, default, descr, validate)
 +            if default is not None:
 +                self.sysprep_params[name] = default
 +        return inner
 +    return wrapper
 +
 +
 +def del_sysprep_param(name):
 +    """Decorator for __init__ that deletes a previously added sysprep parameter
 +    definition from an instance of a os_type class.
 +    """
      def wrapper(func):
 -        func.sysprep = True
 -        func.enabled = enabled
 -        func.executed = False
 -        return func
 +        @wraps(func)
 +        def inner(self, *args, **kwargs):
 +            del self.needed_sysprep_params[name]
 +            func(self, *args, **kwargs)
 +        return inner
      return wrapper
  
  
  class OSBase(object):
      """Basic operating system class"""
  
 -    def __init__(self, rootdev, ghandler, output):
 -        self.root = rootdev
 -        self.g = ghandler
 -        self.out = output
 +    SysprepParam = namedtuple('SysprepParam',
 +                              ['type', 'default', 'description', 'validate'])
 +
 +    def __init__(self, image, **kargs):
 +        self.image = image
 +
 +        self.root = image.root
 +        self.g = image.g
 +        self.out = image.out
 +
 +        self.needed_sysprep_params = {}
 +        self.sysprep_params = \
 +            kargs['sysprep_params'] if 'sysprep_params' in kargs else {}
 +
          self.meta = {}
 +        self.mounted = False
  
+         # Many guestfs compilations don't support scrub
+         self._scrub_support = True
+         try:
+             self.g.available(['scrub'])
+         except RuntimeError:
+             self._scrub_support = False
      def collect_metadata(self):
          """Collect metadata about the OS"""
          try:
          """Returns information about a sysprep object"""
          assert self._is_sysprep(obj), "Object is not a sysprep"
  
 -        return (obj.__name__.replace('_', '-'), textwrap.dedent(obj.__doc__))
 +        SysprepInfo = namedtuple("SysprepInfo", "name description")
 +
 +        return SysprepInfo(obj.__name__.replace('_', '-'),
 +                           textwrap.dedent(obj.__doc__))
  
      def get_sysprep_by_name(self, name):
          """Returns the sysprep object with the given name"""
          """Print enabled and disabled system preparation operations."""
  
          syspreps = self.list_syspreps()
 -        enabled = filter(lambda x: x.enabled, syspreps)
 -        disabled = filter(lambda x: not x.enabled, syspreps)
 +        enabled = [sysprep for sysprep in syspreps if sysprep.enabled]
 +        disabled = [sysprep for sysprep in syspreps if not sysprep.enabled]
  
          wrapper = textwrap.TextWrapper()
          wrapper.subsequent_indent = '\t'
                  descr = wrapper.fill(textwrap.dedent(sysprep.__doc__))
                  self.out.output('    %s:\n%s\n' % (name, descr))
  
 +    def print_sysprep_params(self):
 +        """Print the system preparation parameter the user may use"""
 +
 +        self.out.output("Needed system preparation parameters:")
 +
 +        if len(self.needed_sysprep_params) == 0:
 +            self.out.output("(none)")
 +            return
 +
 +        for name, param in self.needed_sysprep_params.items():
 +            self.out.output("\t%s (%s): %s" %
 +                            (param.description, name,
 +                             self.sysprep_params[name] if name in
 +                             self.sysprep_params else "(none)"))
 +
      def do_sysprep(self):
          """Prepare system for image creation."""
  
  
              self.out.output('Preparing system for image creation:')
  
 -            tasks = self.list_syspreps()
 -            enabled = filter(lambda x: x.enabled, tasks)
 +            enabled = [task for task in self.list_syspreps() if task.enabled]
  
              size = len(enabled)
              cnt = 0
@@@ -35,6 -35,8 +35,6 @@@
  
  """This module hosts OS-specific code common to all Unix-like OSs."""
  
 -import re
 -
  from image_creator.os_type import OSBase, sysprep
  
  
@@@ -85,48 -87,69 +85,54 @@@ class Unix(OSBase)
  
          return True
  
 -    @sysprep()
 -    def cleanup_cache(self, print_header=True):
 +    @sysprep('Removing files under /var/cache')
 +    def cleanup_cache(self):
          """Remove all regular files under /var/cache"""
  
 -        if print_header:
 -            self.out.output('Removing files under /var/cache')
 -
          self._foreach_file('/var/cache', self.g.rm, ftype='r')
  
 -    @sysprep()
 -    def cleanup_tmp(self, print_header=True):
 +    @sysprep('Removing files under /tmp and /var/tmp')
 +    def cleanup_tmp(self):
          """Remove all files under /tmp and /var/tmp"""
  
          self._foreach_file('/tmp', self.g.rm_rf, maxdepth=1)
          self._foreach_file('/var/tmp', self.g.rm_rf, maxdepth=1)
  
 -    @sysprep()
 -    def cleanup_log(self, print_header=True):
 +    @sysprep('Emptying all files under /var/log')
 +    def cleanup_log(self):
          """Empty all files under /var/log"""
  
 -        if print_header:
 -            self.out.output('Emptying all files under /var/log')
 -
          self._foreach_file('/var/log', self.g.truncate, ftype='r')
  
 -    @sysprep(enabled=False)
 -    def cleanup_mail(self, print_header=True):
 +    @sysprep('Removing files under /var/mail & /var/spool/mail', enabled=False)
 +    def cleanup_mail(self):
          """Remove all files under /var/mail and /var/spool/mail"""
  
 -        if print_header:
 -            self.out.output('Removing files under /var/mail & /var/spool/mail')
 -
          if self.g.is_dir('/var/spool/mail'):
              self._foreach_file('/var/spool/mail', self.g.rm_rf, maxdepth=1)
  
          self._foreach_file('/var/mail', self.g.rm_rf, maxdepth=1)
  
 -    @sysprep()
 -    def cleanup_userdata(self, print_header=True):
 +    @sysprep('Removing sensitive user data')
 +    def cleanup_userdata(self):
          """Delete sensitive userdata"""
  
          homedirs = ['/root']
          if self.g.is_dir('/home/'):
              homedirs += self._ls('/home/')
  
 -        if print_header:
 -            self.out.output("Removing sensitive user data under %s" %
 -                            " ".join(homedirs))
 -
+         action = self.g.rm_rf
+         if self._scrub_support:
+             action = self.g.scrub_file
+         else:
+             self.out.warn("Sensitive data won't be scrubbed (not supported)")
++
          for homedir in homedirs:
              for data in self.sensitive_userdata:
                  fname = "%s/%s" % (homedir, data)
                  if self.g.is_file(fname):
-                     self.g.scrub_file(fname)
+                     action(fname)
                  elif self.g.is_dir(fname):
-                     self._foreach_file(fname, self.g.scrub_file, ftype='r')
+                     self._foreach_file(fname, action, ftype='r')
  
  # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
diff --combined image_creator/version.py
@@@ -1,8 -1,7 +1,8 @@@
 -__version__ = "0.4.4"
 -__version_info__ = ['0', '4', '4']
 +
- __version__ = "0.4.3next"
++__version__ = "0.4.4next"
  __version_vcs_info__ = {
 -    'branch': 'hotfix-0.4.4',
 -    'revid': 'ce66ae3',
 -    'revno': 322}
 -__version_user_info__ = "skalkoto@darkstar.admin.grnet.gr"
 +    'branch': 'develop',
-     'revid': '64556e6',
-     'revno': 330}
++    'revid': 'c5effe0',
++    'revno': 370}
 +__version_user_email__ = "skalkoto@grnet.gr"
 +__version_user_name__ = "Nikos Skalkotos"
diff --combined version
+++ b/version
@@@ -1,1 -1,1 +1,1 @@@
- 0.4.3next
 -0.4.4
++0.4.4next