Revision 0969420b

b/image_creator/bundle_volume.py
304 304
        mpoints = []
305 305
        for entry in self._read_fstable('/proc/mounts'):
306 306
            if entry.mpoint.startswith(os.path.abspath(target)):
307
                    mpoints.append(entry.mpoint)
307
                mpoints.append(entry.mpoint)
308 308

  
309 309
        mpoints.sort()
310 310
        for mpoint in reversed(mpoints):
......
336 336
                continue
337 337

  
338 338
            dirname = mpoint
339
            basename = ''
340 339
            found_ancestor = False
341 340
            while dirname != '/':
342
                (dirname, basename) = os.path.split(dirname)
341
                (dirname, _) = os.path.split(dirname)
343 342
                if dirname in excluded:
344 343
                    found_ancestor = True
345 344
                    break
b/image_creator/dialog_menu.py
68 68
    ("File injection", ["EnforcePersonality"], ["windows", "linux"])
69 69
]
70 70

  
71
SYSPREP_PARAM_MAXLEN = 20
71 72

  
72 73
class MetadataMonitor(object):
73 74
    """Monitors image metadata chages"""
......
395 396
                if len(Kamaki.get_clouds()):
396 397
                    default_item = "Cloud"
397 398
                else:
398
                    default_time = "Add/Edit"
399
                    default_item = "Add/Edit"
399 400
            else:
400
                default_time = "Delete"
401
                default_item = "Delete"
401 402
        elif choice == "Cloud":
402 403
            default_item = "Cloud"
403 404
            clouds = Kamaki.get_clouds()
......
616 617

  
617 618

  
618 619
def sysprep_params(session):
619

  
620
    """Collect the needed sysprep parameters"""
620 621
    d = session['dialog']
621 622
    image = session['image']
622 623

  
......
631 632
    for name in names:
632 633
        param = needed[name]
633 634
        default = available[name] if name in available else ""
634
        fields.append(("%s: " % param.description, default, param.maxlen))
635
        fields.append(("%s: " % param.description, default,
636
                       SYSPREP_PARAM_MAXLEN))
635 637

  
636 638
    txt = "Please provide the following system preparation parameters:"
637 639
    code, output = d.form(txt, height=13, width=WIDTH, form_height=len(fields),
......
640 642
    if code in (d.DIALOG_CANCEL, d.DIALOG_ESC):
641 643
        return False
642 644

  
643
    sysprep_params = {}
644 645
    for i in range(len(fields)):
645 646
        param = needed[names[i]]
646 647
        if param.validator(output[i]):
647 648
            image.os.sysprep_params[names[i]] = output[i]
648 649
        else:
649 650
            d.msgbox("The value you provided for parameter: %s is not valid" %
650
                     name, width=SMALL_WIDTH)
651
                     names[i], width=SMALL_WIDTH)
651 652
            return False
652 653

  
653 654
    return True
b/image_creator/dialog_wizard.py
49 49

  
50 50
PAGE_WIDTH = 70
51 51
PAGE_HEIGHT = 10
52
SYSPREP_PARAM_MAXLEN = 20
52 53

  
53 54

  
54 55
class WizardExit(Exception):
......
221 222

  
222 223
        field_lenght = len(self.fields())
223 224
        form_height = field_lenght if field_lenght < PAGE_HEIGHT - 4 \
224
            else PAGET_HEIGHT - 4
225
            else PAGE_HEIGHT - 4
225 226

  
226 227
        (code, output) = d.form(
227 228
            self.text, width=PAGE_WIDTH, height=PAGE_HEIGHT,
......
343 344
        for name in param_names:
344 345
            text = needed[name].description
345 346
            default = available[name] if name in available else ""
346
            fields.append(("%s: " % text, default, needed[name].maxlen))
347
            fields.append(("%s: " % text, default, SYSPREP_PARAM_MAXLEN))
347 348
        return fields
348 349

  
349 350
    def sysprep_params_validate(answer):
b/image_creator/os_type/__init__.py
64 64
def add_prefix(target):
65 65
    def wrapper(self, *args):
66 66
        prefix = args[0]
67
        return map(lambda x: prefix + x, target(self, *args))
67
        return [prefix + path for path in target(self, *args)]
68 68
    return wrapper
69 69

  
70 70

  
71 71
def sysprep(message, enabled=True, **kwargs):
72 72
    """Decorator for system preparation tasks"""
73
    def wrapper(func):
74
        func.sysprep = True
75
        func.enabled = enabled
76
        func.executed = False
73
    def wrapper(method):
74
        method.sysprep = True
75
        method.enabled = enabled
76
        method.executed = False
77 77

  
78 78
        for key, val in kwargs.items():
79
            setattr(func, key, val)
79
            setattr(method, key, val)
80 80

  
81
        @wraps(func)
81
        @wraps(method)
82 82
        def inner(self, print_message=True):
83 83
            if print_message:
84 84
                self.out.output(message)
85
            return func(self)
85
            return method(self)
86 86

  
87 87
        return inner
88

  
89 88
    return wrapper
90 89

  
91 90

  
92
def add_sysprep_param(name, descr, maxlen, default=None,
93
                      validator=lambda x: True):
94
    """Decorator for init that adds the definition for a system preparation
95
    parameter
91
def add_sysprep_param(name, default, description, validator=lambda x: True):
92
    """Decorator for __init__ that adds the definition for a system preparation
93
    parameter in an instance of a os_type class
96 94
    """
97
    def wrapper(func):
98

  
99
        @wraps(func)
95
    def wrapper(init):
96
        @wraps(init)
100 97
        def inner(self, *args, **kwargs):
101

  
102
            func(self, *args, **kwargs)
103

  
104
            if not hasattr(self, 'needed_sysprep_params'):
105
                self.needed_sysprep_params = {}
106
            getattr(self, 'needed_sysprep_params')[name] = \
107
                self.SysprepParam(descr, maxlen, validator)
98
            init(self, *args, **kwargs)
99
            self.needed_sysprep_params[name] = \
100
                self.SysprepParam(default, description, validator)
108 101
        return inner
109

  
110 102
    return wrapper
111 103

  
112 104

  
113 105
def del_sysprep_param(name):
114
    """Decorator for init that deletes a previously added sysprep parameter
115
    definition .
106
    """Decorator for __init__ that deletes a previously added sysprep parameter
107
    definition from an instance of a os_type class.
116 108
    """
117 109
    def wrapper(func):
118

  
119 110
        @wraps(func)
120 111
        def inner(self, *args, **kwargs):
121
            del self.needed_sysprep_params[nam]
112
            del self.needed_sysprep_params[name]
122 113
            func(self, *args, **kwargs)
123

  
124 114
        return inner
125

  
126 115
    return wrapper
127 116

  
128 117

  
129 118
class OSBase(object):
130 119
    """Basic operating system class"""
131 120

  
132
    SysprepParam = namedtuple('SysprepParam', 'description maxlen validator')
121
    SysprepParam = namedtuple('SysprepParam', 'default description validator')
133 122

  
134 123
    def __init__(self, image, **kargs):
135 124
        self.image = image
......
138 127
        self.g = image.g
139 128
        self.out = image.out
140 129

  
130
        self.needed_sysprep_params = {}
141 131
        self.sysprep_params = \
142 132
            kargs['sysprep_params'] if 'sysprep_params' in kargs else {}
143 133

  
144 134
        self.meta = {}
135
        self.mounted = False
145 136

  
146 137
    def collect_metadata(self):
147 138
        """Collect metadata about the OS"""
......
202 193
        """Print enabled and disabled system preparation operations."""
203 194

  
204 195
        syspreps = self.list_syspreps()
205
        enabled = filter(lambda x: x.enabled, syspreps)
206
        disabled = filter(lambda x: not x.enabled, syspreps)
196
        enabled = [sysprep for sysprep in syspreps if sysprep.enabled]
197
        disabled = [sysprep for sysprep in syspreps if not sysprep.enabled]
207 198

  
208 199
        wrapper = textwrap.TextWrapper()
209 200
        wrapper.subsequent_indent = '\t'
......
233 224

  
234 225
        self.out.output("Needed system preparation parameters:")
235 226

  
236
        params = self.needed_sysprep_params()
237

  
238
        if len(params) == 0:
227
        if len(self.needed_sysprep_params) == 0:
239 228
            self.out.output("(none)")
240 229
            return
241 230

  
242
        for param in params:
231
        for name, param in self.needed_sysprep_params.items():
243 232
            self.out.output("\t%s (%s): %s" %
244
                            (param.description, param.name,
245
                             self.sysprep_params[param.name] if param.name in
233
                            (param.description, name,
234
                             self.sysprep_params[name] if name in
246 235
                             self.sysprep_params else "(none)"))
247 236

  
248 237
    def do_sysprep(self):
......
254 243

  
255 244
            self.out.output('Preparing system for image creation:')
256 245

  
257
            tasks = self.list_syspreps()
258
            enabled = filter(lambda x: x.enabled, tasks)
246
            enabled = [task for task in self.list_syspreps() if task.enabled]
259 247

  
260 248
            size = len(enabled)
261 249
            cnt = 0
b/image_creator/os_type/freebsd.py
110 110
        # libguestfs can't handle correct freebsd partitions on a GUID
111 111
        # Partition Table. We have to do the translation to linux device names
112 112
        # ourselves
113
        guid_device = re.compile('^/dev/((?:ada)|(?:vtbd))(\d+)p(\d+)$')
113
        guid_device = re.compile(r'^/dev/((?:ada)|(?:vtbd))(\d+)p(\d+)$')
114 114

  
115 115
        mopts = "ufstype=ufs2,%s" % ('ro' if readonly else 'rw')
116 116
        for mp, dev in self._mountpoints():
b/image_creator/os_type/linux.py
310 310
    def _get_passworded_users(self):
311 311
        """Returns a list of non-locked user accounts"""
312 312
        users = []
313
        regexp = re.compile('(\S+):((?:!\S+)|(?:[^!*]\S+)|):(?:\S*:){6}')
313
        regexp = re.compile(r'(\S+):((?:!\S+)|(?:[^!*]\S+)|):(?:\S*:){6}')
314 314

  
315 315
        for line in self.g.cat('/etc/shadow').splitlines():
316 316
            match = regexp.match(line)
b/image_creator/os_type/unix.py
35 35

  
36 36
"""This module hosts OS-specific code common to all Unix-like OSs."""
37 37

  
38
import re
39

  
40 38
from image_creator.os_type import OSBase, sysprep
41 39

  
42 40

  
......
87 85

  
88 86
        return True
89 87

  
90
    @sysprep('Removing files u)nder /var/cache')
88
    @sysprep('Removing files under /var/cache')
91 89
    def cleanup_cache(self):
92 90
        """Remove all regular files under /var/cache"""
93 91

  
b/image_creator/os_type/windows.py
37 37
Windows OSs."""
38 38

  
39 39
from image_creator.os_type import OSBase, sysprep, add_sysprep_param
40
from image_creator.util import FatalError, check_guestfs_version, get_command
40
from image_creator.util import FatalError, check_guestfs_version
41 41
from image_creator.winexe import WinEXE, WinexeTimeout
42 42

  
43 43
import hivex
......
108 108
class Windows(OSBase):
109 109
    """OS class for Windows"""
110 110

  
111
    @add_sysprep_param('password', 'Image Administrator Password', 20)
111
    @add_sysprep_param('password', None, 'Image Administrator Password')
112 112
    def __init__(self, image, **kargs):
113 113
        super(Windows, self).__init__(image, **kargs)
114 114

  
......
127 127
        assert self.system_drive
128 128

  
129 129
        self.product_name = self.g.inspect_get_product_name(self.root)
130
        self.syspreped = False
130 131

  
131 132
    @sysprep('Disabling IPv6 privacy extensions')
132 133
    def disable_ipv6_privacy_extensions(self):
......
202 203
            return
203 204

  
204 205
        self._guest_exec(
205
            "cscript \Windows\system32\slmgr.vbs /ipk %s" % setup_key)
206
            r"cscript \Windows\system32\slmgr.vbs /ipk %s" % setup_key)
206 207

  
207 208
    @sysprep('Shrinking the last filesystem')
208 209
    def shrink(self):
......
273 274
            raise FatalError("Image is already syspreped!")
274 275

  
275 276
        txt = "System preparation parameter: `%s' is needed but missing!"
276
        for param in self.needed_sysprep_params:
277
            if param not in self.sysprep_params:
277
        for name, param in self.needed_sysprep_params.items():
278
            if name not in self.sysprep_params:
278 279
                raise FatalError(txt % param)
279 280

  
280 281
        self.mount(readonly=False)
......
298 299
        # guestfs_shutdown which is the prefered way to shutdown the backend
299 300
        # process was introduced in version 1.19.16
300 301
        if check_guestfs_version(self.g, 1, 19, 16) >= 0:
301
            ret = self.g.shutdown()
302
            self.g.shutdown()
302 303
        else:
303
            ret = self.g.kill_subprocess()
304
            self.g.kill_subprocess()
304 305

  
305 306
        self.out.success('done')
306 307

  
......
329 330
            self.out.output('Preparing system for image creation:')
330 331

  
331 332
            tasks = self.list_syspreps()
332
            enabled = filter(lambda x: x.enabled, tasks)
333
            enabled = [task for task in tasks if task.enabled]
333 334
            size = len(enabled)
334 335

  
335 336
            # Make sure shrink runs in the end, before ms sysprep
336
            enabled = filter(lambda x: self.sysprep_info(x).name != 'shrink',
337
                             enabled)
337
            enabled = [task for task in enabled if
338
                       self.sysprep_info(task).name != 'shrink']
338 339

  
339
            shrink_enabled = False
340 340
            if len(enabled) != size:
341 341
                enabled.append(self.shrink)
342
                shrink_enabled = True
343 342

  
344 343
            # Make sure the ms sysprep is the last task to run if it is enabled
345
            enabled = filter(
346
                lambda x: self.sysprep_info(x).name != 'microsoft-sysprep',
347
                enabled)
344
            enabled = [task for task in enabled if
345
                       self.sysprep_info(task).name != 'microsoft-sysprep']
348 346

  
349 347
            ms_sysprep_enabled = False
350 348
            if len(enabled) != size:
......
397 395
    def _wait_vm_boot(self, vm, fname, msg):
398 396
        """Wait until a message appears on a file or the vm process dies"""
399 397

  
400
        for i in range(BOOT_TIMEOUT):
398
        for _ in range(BOOT_TIMEOUT):
401 399
            time.sleep(1)
402 400
            with open(fname) as f:
403 401
                for line in f:
......
425 423
        path = "%s/system32/config/%s" % (systemroot, regfile)
426 424
        try:
427 425
            path = self.g.case_sensitive_path(path)
428
        except RuntimeError as e:
426
        except RuntimeError as error:
429 427
            raise FatalError("Unable to retrieve registry file: %s. Reason: %s"
430
                             % (regfile, str(e)))
428
                             % (regfile, str(error)))
431 429
        return path
432 430

  
433 431
    def _enable_os_monitor(self):
......
634 632

  
635 633
    def _get_users(self):
636 634
        """Returns a list of users found in the images"""
637
        path = self._registry_file_path('SAM')
638 635
        samfd, sam = tempfile.mkstemp()
639 636
        try:
640 637
            os.close(samfd)
641
            self.g.download(path, sam)
638
            self.g.download(self._registry_file_path('SAM'), sam)
642 639

  
643 640
            h = hivex.Hivex(sam)
644 641

  
......
701 698
                log.file.write(stdout)
702 699
            finally:
703 700
                log.close()
704
            self.out.output("failed! See: `%' for the full output" % log.name)
701
            self.out.output("failed! See: `%s' for the full output" % log.name)
705 702
            if i < CONNECTION_RETRIES - 1:
706 703
                self.out.output("Retrying ...", False)
707 704
        raise FatalError("Connection to the VM failed after %d retries" %
......
743 740
        self.serial = serial
744 741

  
745 742
        def random_mac():
743
            """creates a random mac address"""
746 744
            mac = [0x00, 0x16, 0x3e,
747 745
                   random.randint(0x00, 0x7f),
748 746
                   random.randint(0x00, 0xff),
749 747
                   random.randint(0x00, 0xff)]
750 748

  
751
            return ':'.join(map(lambda x: "%02x" % x, mac))
749
            return ':'.join(['%02x' % x for x in mac])
752 750

  
753 751
        # Use ganeti's VNC port range for a random vnc port
754 752
        self.display = random.randint(11000, 14999) - 5900
......
780 778
            if self.isalive():
781 779
                self.process.kill()
782 780
            self.process.wait()
783
            self.out.output("timed-out")
784 781
            raise FatalError("VM destroy timed-out")
785 782

  
786 783
        signal.signal(signal.SIGALRM, handler)

Also available in: Unified diff