Revision f165adc0

b/image_creator/__init__.py
33 33

  
34 34
__version__ = '0.1'
35 35

  
36

  
36 37
import image_creator.os_type
37 38

  
38 39

  
......
51 52
    return getattr(module, classname)
52 53

  
53 54

  
54
class FatalError(Exception):
55
    pass
56 55

  
57 56
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
b/image_creator/disk.py
32 32
# or implied, of GRNET S.A.
33 33

  
34 34
from image_creator.util import get_command
35
from image_creator.util import warn, progress, success, output
36
from image_creator import FatalError
35
from image_creator.util import warn, progress, success, output, FatalError
37 36

  
38 37
import stat
39 38
import os
b/image_creator/main.py
35 35

  
36 36
from image_creator import get_os_class
37 37
from image_creator import __version__ as version
38
from image_creator import FatalError
39 38
from image_creator.disk import Disk
40
from image_creator.util import get_command, error, success, output
39
from image_creator.util import get_command, error, success, output, FatalError
41 40
from image_creator import util
42 41
import sys
43 42
import os
......
65 64
    parser.add_option("-f", "--force", dest="force", default=False,
66 65
        action="store_true", help="overwrite output files if they exist")
67 66

  
68
    parser.add_option("--no-cleanup", dest="cleanup", default=True,
69
        help="don't cleanup sensitive data", action="store_false")
70

  
71 67
    parser.add_option("--no-sysprep", dest="sysprep", default=True,
72 68
        help="don't perform system preperation", action="store_false")
73 69

  
......
78 74
        default=None, action="callback", callback=check_writable_dir,
79 75
        help="dump image to FILE", metavar="FILE")
80 76

  
81
    parser.add_option("--print-sysprep", dest="print_sysprep", default=False,
82
        help="Print the enabled and disable sysprep actions for this image",
83
        action="store_true")
77
    parser.add_option("--enable-sysprep", dest="enabled_syspreps", default=[],
78
        help="Run SYSPREP operation on the input media",
79
        action="append", metavar="SYSPREP")
84 80

  
85
    parser.add_option("--print-data-cleanup", dest="print_data_cleanup",
86
        default=False, help="Print the enabled and disable data cleanup "
87
        "operations actions for this source", action="store_true")
81
    parser.add_option("--disable-sysprep", dest="disabled_syspreps",
82
        help="Prevent SYSPREP operation from running on the input media",
83
        default=[], action="append", metavar="SYSPREP")
84

  
85
    parser.add_option("--print-sysprep", dest="print_sysprep", default=False,
86
        help="Print the enabled and disabled sysprep operations for this "
87
        "input media", action="store_true")
88 88

  
89 89
    parser.add_option("-s", "--silent", dest="silent", default=False,
90
        help="silent mode, only output error", action="store_true")
90
        help="silent mode, only output errors", action="store_true")
91 91

  
92 92
    parser.add_option("-u", "--upload", dest="upload", default=False,
93 93
        help="upload the image to pithos", action="store_true")
......
116 116
        util.silent = True
117 117

  
118 118
    if options.outfile is None and not options.upload \
119
        and not options.print_sysprep and not options.print_data_cleanup:
120
        FatalError("At least one of the following: `-o', `-u', "
121
        "`--print-sysprep' `--print-data-cleanup' must be set")
119
                                            and not options.print_sysprep:
120
        raise FatalError("At least one of `-o', `-u' or" \
121
                            "`--print-sysprep' must be set")
122 122

  
123 123
    output('snf-image-creator %s\n' % version)
124 124

  
......
144 144

  
145 145
        output()
146 146

  
147
        if options.print_sysprep:
148
            image_os.print_sysprep()
149
            output()
147
        for sysprep in options.disabled_syspreps:
148
            image_os.disable_sysprep(sysprep)
149

  
150
        for sysprep in options.enabled_syspreps:
151
            image_os.enable_sysprep(sysprep)
150 152

  
151
        if options.print_data_cleanup:
152
            image_os.print_data_cleanup()
153
        if options.print_sysprep:
154
            image_os.print_syspreps()
153 155
            output()
154 156

  
155 157
        if options.outfile is None and not options.upload:
156 158
            return 0
157 159

  
158 160
        if options.sysprep:
159
            image_os.sysprep()
160

  
161
        if options.cleanup:
162
            image_os.data_cleanup()
161
            image_os.do_sysprep()
163 162

  
164 163
        dev.umount()
165 164

  
b/image_creator/os_type/__init__.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from image_creator.util import output
34
from image_creator.util import output, FatalError
35 35

  
36
import textwrap
36 37
import re
37 38

  
38 39

  
......
43 44
    return wrapper
44 45

  
45 46

  
46
def exclude_task(func):
47
    func.excluded = True
48
    return func
47
def sysprep(enabled=True):
48
    def wrapper(func):
49
        func.sysprep = True
50
        func.enabled = enabled
51
        return func
52
    return wrapper
49 53

  
50 54

  
51 55
class OSBase(object):
52 56
    """Basic operating system class"""
57

  
53 58
    def __init__(self, rootdev, ghandler):
54 59
        self.root = rootdev
55 60
        self.g = ghandler
56 61

  
57
        self.sysprep_regexp = re.compile('^sysprep_')
58
        self.data_cleanup_regexp = re.compile('^data_cleanup_')
62
    def _is_sysprep(self, obj):
63
        return getattr(obj, 'sysprep', False) and callable(obj)
59 64

  
60
    def _print_task(self, task):
61
        name = task.__name__
65
    def list_syspreps(self):
62 66

  
63
        if self.sysprep_regexp.match(name):
64
            name = self.sysprep_regexp.sub("", name)
65
        elif self.data_cleanup_regexp.match(name):
66
            name = self.data_cleanup_regexp.sub("", name)
67
        else:
68
            raise FatalError("%s is not a task" % name)
67
        objs = [getattr(self, name) for name in dir(self) \
68
            if not name.startswith('_')]
69

  
70
        enabled = [x for x in objs if self._is_sysprep(x) and x.enabled]
71
        disabled = [x for x in objs if self._is_sysprep(x) and not x.enabled]
72

  
73
        return enabled, disabled
74

  
75
    def _sysprep_change_status(self, name, status):
76

  
77
        error_msg = "Syprep operation %s does not exist for %s" % \
78
                (name, self.__class__.__name__)
79

  
80
        method_name = name.replace('-', '_')
81
        method = None
82
        try:
83
            method = getattr(self, method_name)
84
        except AttributeError:
85
            raise FatalError(error_msg)
86

  
87
        if not self._is_sysprep(method):
88
            raise FatalError(error_msg)
89

  
90
        setattr(method.im_func, 'enabled', status)
91

  
92
    def enable_sysprep(self, name):
93
        """Enable a system preperation operation"""
94
        self._sysprep_change_status(name, True)
95

  
96
    def disable_sysprep(self, name):
97
        """Disable a system preperation operation"""
98
        self._sysprep_change_status(name, False)
99

  
100
    def print_syspreps(self):
101
        """Print enabled and disabled system preperation operations."""
69 102

  
70
        name = name.replace('_', '-')
103
        enabled, disabled = self.list_syspreps()
71 104

  
72
        output("  %s:\n    %s" % (name, task.__doc__))
105
        wrapper = textwrap.TextWrapper()
106
        wrapper.subsequent_indent = '\t'
107
        wrapper.initial_indent = '\t'
108

  
109
        output("Enabled system preperation operations:")
110
        if len(enabled) == 0:
111
            output("(none)")
112
        else:
113
            for sysprep in enabled:
114
                name = sysprep.__name__.replace('_', '-')
115
                descr = wrapper.fill(sysprep.__doc__)
116
                output('    %s:\n%s\n' % (name, descr))
117

  
118
        output("Disabled system preperation operations:")
119
        if len(disabled) == 0:
120
            output("(none)")
121
        else:
122
            for sysprep in disabled:
123
                name = sysprep.__name__.replace('_', '-')
124
                descr = wrapper.fill(sysprep.__doc__)
125
                output('    %s:\n%s\n' % (name, descr))
73 126

  
74 127
    @add_prefix
75 128
    def ls(self, directory):
......
133 186

  
134 187
        return meta
135 188

  
136
    def list_sysprep(self):
137
        """List all sysprep actions"""
138

  
139
        is_sysprep = lambda x: x.startswith('sysprep_') and \
140
                                                    callable(getattr(self, x))
141
        tasks = [getattr(self, x) for x in dir(self) if is_sysprep(x)]
142

  
143
        included = [t for t in tasks if not getattr(t, "excluded", False)]
144
        excluded = [t for t in tasks if getattr(t, "excluded", False)]
145

  
146
        return included, excluded
147

  
148
    def list_data_cleanup(self):
149
        """List all data_cleanup actions"""
150

  
151
        is_cleanup = lambda x: x.startswith('data_cleanup_') and \
152
                                                    callable(getattr(self, x))
153
        tasks = [getattr(self, x) for x in dir(self) if is_cleanup(x)]
154

  
155
        included = [t for t in tasks if not getattr(t, "excluded", False)]
156
        excluded = [t for t in tasks if getattr(t, "excluded", False)]
157

  
158
        return included, excluded
159

  
160
    def data_cleanup(self):
161
        """Cleanup sensitive data out of the OS image."""
162

  
163
        output('Cleaning up sensitive data out of the OS image:')
164

  
165
        tasks, _ = self.list_data_cleanup()
166
        size = len(tasks)
167
        cnt = 0
168
        for task in tasks:
169
            cnt += 1
170
            output(('(%d/%d)' % (cnt, size)).ljust(7), False)
171
            task()
172
        output()
173

  
174
    def sysprep(self):
189
    def do_sysprep(self):
175 190
        """Prepere system for image creation."""
176 191

  
177 192
        output('Preparing system for image creation:')
......
185 200
            task()
186 201
        output()
187 202

  
188
    def print_task(self, task):
189
        name = task.__name__
190

  
191
        if self.sysprep_regexp.match(name):
192
            name = self.sysprep_regexp.sub("", name)
193
        elif self.data_cleanup_regexp.match(name):
194
            name = self.data_cleanup_regexp.sub("", name)
195
        else:
196
            raise FatalError("%s is not a task" % name)
197

  
198
        name = name.replace('_', '-')
199

  
200
        output("  %s:\n    %s" % (name, task.__doc__))
201

  
202
    def print_data_cleanup(self):
203
        included, excluded = self.list_data_cleanup()
204

  
205
        output("Included data cleanup operations:")
206
        if len(included) == 0:
207
            ouput("(none)")
208
        else:
209
            for task in included:
210
                self._print_task(task)
211
        output("Ommited data cleanup operations:")
212
        if len(excluded) == 0:
213
            ouput("(none)")
214
        else:
215
            for task in excluded:
216
                self._print_task(task)
217

  
218
    def print_sysprep(self):
219
        included, excluded = self.list_sysprep()
220

  
221
        output("Included sysprep operations:")
222
        if len(included) == 0:
223
            ouput("(none)")
224
        else:
225
            for task in included:
226
                self._print_task(task)
227
        output("Ommited sysprep operations:")
228
        if len(excluded) == 0:
229
            output("(none)")
230
        else:
231
            for task in excluded:
232
                self._print_task(task)
233

  
234 203
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :
b/image_creator/os_type/freebsd.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from image_creator.os_type.unix import Unix, exclude_task
34
from image_creator.os_type.unix import Unix, sysprep
35 35

  
36 36

  
37 37
class Freebsd(Unix):
b/image_creator/os_type/hurd.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from image_creator.os_type.unix import Unix, exclude_task
34
from image_creator.os_type.unix import Unix, sysprep
35 35

  
36 36

  
37 37
class Hard(Unix):
b/image_creator/os_type/linux.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from image_creator.os_type.unix import Unix, exclude_task
34
from image_creator.os_type.unix import Unix, sysprep
35 35
from image_creator.util import warn, output
36 36

  
37 37
import re
......
56 56
                self._uuid[dev] = attr[1]
57 57
                return attr[1]
58 58

  
59
    def sysprep_fix_acpid(self, print_header=True):
59
    @sysprep()
60
    def fix_acpid(self, print_header=True):
60 61
        """Replace acpid powerdown action scripts to immediately shutdown the
61 62
        system without checking if a GUI is running.
62 63
        """
......
110 111
                    "event occures" % action)
111 112
                return
112 113

  
113
    def sysprep_persistent_net_rules(self, print_header=True):
114
    @sysprep()
115
    def persistent_net_rules(self, print_header=True):
114 116
        """Remove udev rules that will keep network interface names persistent
115 117
        after hardware changes and reboots. Those rules will be created again
116 118
        the next time the image runs.
......
123 125
        if self.g.is_file(rule_file):
124 126
            self.g.rm(rule_file)
125 127

  
126
    def sysprep_persistent_devs(self, print_header=True):
127
        """Scan fstab and grub configuration files and replace all
128
        non-persistent device appearences with UUIDs.
128
    @sysprep()
129
    def persistent_devs(self, print_header=True):
130
        """Scan fstab & grub configuration files and replace all non-persistent
131
        device appearences with UUIDs.
129 132
        """
130 133

  
131 134
        if print_header:
b/image_creator/os_type/netbsd.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from image_creator.os_type.unix import Unix, exclude_task
34
from image_creator.os_type.unix import Unix, sysprep
35 35

  
36 36

  
37 37
class Netbsd(Unix):
b/image_creator/os_type/slackware.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from image_creator.os_type.linux import Linux, exclude_task
34
from image_creator.os_type.linux import Linux, sysprep
35 35

  
36 36

  
37 37
class Slackware(Linux):
38
    def data_cleanup_log(self):
38
    @sysprep()
39
    def cleanup_log(self):
39 40
        # In slackware the metadata about installed packages are
40 41
        # stored in /var/log/packages. Clearing all /var/log files
41 42
        # will destroy the package management system.
b/image_creator/os_type/ubuntu.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from image_creator.os_type.linux import Linux, exclude_task
34
from image_creator.os_type.linux import Linux, sysprep
35 35

  
36 36

  
37 37
class Ubuntu(Linux):
b/image_creator/os_type/unix.py
34 34
import re
35 35
import sys
36 36

  
37
from image_creator.os_type import OSBase, exclude_task
37
from image_creator.os_type import OSBase, sysprep
38 38
from image_creator.util import warn, output
39 39

  
40 40

  
......
70 70

  
71 71
        return users
72 72

  
73
    @exclude_task
74
    def data_cleanup_user_accounts(self, print_header=True):
73
    @sysprep(enabled=False)
74
    def remove_user_accounts(self, print_header=True):
75 75
        """Remove all user account with id more than 1000"""
76 76

  
77 77
        if print_header:
......
113 113
            if self.g.is_dir(home) and home.startswith('/home/'):
114 114
                self.g.rm_rf(home)
115 115

  
116
    def data_cleanup_passwords(self, print_header=True):
116
    @sysprep()
117
    def cleanup_passwords(self, print_header=True):
117 118
        """Remove all passwords and lock all user accounts"""
118 119

  
119 120
        if print_header:
......
130 131

  
131 132
        self.g.write('/etc/shadow', "\n".join(shadow) + '\n')
132 133

  
133
    def data_cleanup_cache(self, print_header=True):
134
    @sysprep()
135
    def cleanup_cache(self, print_header=True):
134 136
        """Remove all regular files under /var/cache"""
135 137

  
136 138
        if print_header:
......
138 140

  
139 141
        self.foreach_file('/var/cache', self.g.rm, ftype='r')
140 142

  
141
    def data_cleanup_tmp(self, print_header=True):
143
    @sysprep()
144
    def cleanup_tmp(self, print_header=True):
142 145
        """Remove all files under /tmp and /var/tmp"""
143 146

  
144 147
        if print_header:
......
147 150
        self.foreach_file('/tmp', self.g.rm_rf, maxdepth=1)
148 151
        self.foreach_file('/var/tmp', self.g.rm_rf, maxdepth=1)
149 152

  
150
    def data_cleanup_log(self, print_header=True):
153
    @sysprep()
154
    def cleanup_log(self, print_header=True):
151 155
        """Empty all files under /var/log"""
152 156

  
153 157
        if print_header:
......
155 159

  
156 160
        self.foreach_file('/var/log', self.g.truncate, ftype='r')
157 161

  
158
    @exclude_task
159
    def data_cleanup_mail(self, print_header=True):
162
    @sysprep(enabled=False)
163
    def cleanup_mail(self, print_header=True):
160 164
        """Remove all files under /var/mail and /var/spool/mail"""
161 165

  
162 166
        if print_header:
......
165 169
        self.foreach_file('/var/spool/mail', self.g.rm_rf, maxdepth=1)
166 170
        self.foreach_file('/var/mail', self.g.rm_rf, maxdepth=1)
167 171

  
168
    def data_cleanup_userdata(self, print_header=True):
172
    @sysprep()
173
    def cleanup_userdata(self, print_header=True):
169 174
        """Delete sensitive userdata"""
170 175

  
171 176
        homedirs = ['/root'] + self.ls('/home/')
b/image_creator/os_type/windows.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from image_creator.os_type import OSBase, exclude_task
34
from image_creator.os_type import OSBase, sysprep
35 35

  
36 36

  
37 37
class Windows(OSBase):
b/image_creator/util.py
35 35
import pbs
36 36
from clint.textui import colored, progress as uiprogress
37 37

  
38

  
39
class FatalError(Exception):
40
    pass
41

  
42

  
38 43
silent = False
39 44

  
40 45

  
......
54 59

  
55 60
def error(msg, new_line=True):
56 61
    nl = "\n" if new_line else ''
57
    sys.stderr.write('Error: %s' % msg + nl)
62
    sys.stderr.write(colored.red('Error: %s' % msg) + nl)
58 63

  
59 64

  
60 65
def warn(msg, new_line=True):

Also available in: Unified diff