Revision b0376b3f

b/image_creator/bundle_volume.py
34 34
import os
35 35
import re
36 36
import tempfile
37
import uuid
37 38
from collections import namedtuple
38 39

  
39 40
import parted
......
43 44
from image_creator.util import FatalError
44 45
from image_creator.util import try_fail_repeat
45 46
from image_creator.util import free_space
47
from image_creator.gpt import GPTPartitionTable
46 48

  
47 49
findfs = get_command('findfs')
48 50
dd = get_command('dd')
......
128 130

  
129 131
    def _create_partition_table(self, image):
130 132

  
131
        if self.disk.type != 'msdos':
132
            raise FatalError('Only msdos partition tables are supported')
133

  
134 133
        # Copy the MBR and the space between the MBR and the first partition.
135
        # In Grub version 1 Stage 1.5 is located there.
134
        # In msdos partitons tables Grub Stage 1.5 is located there.
135
        # In gpt partition tables the Primary GPT Header is there.
136 136
        first_sector = self.disk.getPrimaryPartitions()[0].geometry.start
137 137

  
138 138
        dd('if=%s' % self.disk.device.path, 'of=%s' % image,
139 139
           'bs=%d' % self.disk.device.sectorSize,
140 140
           'count=%d' % first_sector, 'conv=notrunc')
141 141

  
142
        if self.disk.type == 'gpt':
143
            # Copy the Secondary GPT Header
144
            table = GPTPartitionTable(self.disk.device.path)
145
            dd('if=%s' % self.disk.device.path, 'of=%s' % image,
146
            'bs=%d' % self.disk.device.sectorSize, 'conv=notrunc',
147
            'seek=%d' % table.primary.last_usable_lba,
148
            'skip=%d' % table.primary.last_usable_lba)
149

  
142 150
        # Create the Extended boot records (EBRs) in the image
143 151
        extended = self.disk.getExtendedPartition()
144 152
        if not extended:
......
172 180

  
173 181
        new_end = self.disk.device.length
174 182

  
175
        image_dev = parted.Device(image)
176
        image_disk = parted.Disk(image_dev)
183
        image_disk = parted.Disk(parted.Device(image))
177 184

  
178 185
        is_extended = lambda p: p.type == parted.PARTITION_EXTENDED
179 186
        is_logical = lambda p: p.type == parted.PARTITION_LOGICAL
......
188 195

  
189 196
            image_disk.deletePartition(
190 197
                image_disk.getPartitionBySector(last.start))
191
            image_disk.commit()
198
            image_disk.commitToDevice()
192 199

  
193 200
            if is_logical(last) and last.num == 5:
194 201
                extended = image_disk.getExtendedPartition()
195 202
                image_disk.deletePartition(extended)
196
                image_disk.commit()
203
                image_disk.commitToDevice()
197 204
                partitions.remove(filter(is_extended, partitions)[0])
198 205

  
199 206
            partitions.remove(last)
200 207
            last = partitions[-1]
201 208

  
202
            # Leave 2048 blocks at the end
203
            new_end = last.end + 2048
209
            new_end = last.end
204 210

  
205 211
        mount_options = self._get_mount_options(
206 212
            self.disk.getPartitionBySector(last.start).path)
......
220 226
                image_disk.getPartitionBySector(last.start),
221 227
                parted.Constraint(device=image_disk.device),
222 228
                start=last.start, end=part_end)
223
            image_disk.commit()
229
            image_disk.commitToDevice()
224 230

  
225 231
            # Parted may have changed this for better alignment
226 232
            part_end = image_disk.getPartitionBySector(last.start).geometry.end
227 233
            last = last._replace(end=part_end)
228 234
            partitions[-1] = last
229 235

  
230
            # Leave 2048 blocks at the end.
231
            new_end = part_end + 2048
236
            new_end = part_end
232 237

  
233 238
            if last.type == parted.PARTITION_LOGICAL:
234 239
                # Fix the extended partition
235
                extended = disk.getExtendedPartition()
236

  
237
                image_disk.setPartitionGeometry(
238
                    extended, parted.Constraint(device=img_dev),
239
                    ext.geometry.start, end=last.end)
240
                image_disk.commit()
240
                image_disk.minimizeExtendedPartition()
241 241

  
242
        # image_dev.destroy()
243
        return new_end
242
        return (new_end, self._get_partitions(image_disk))
244 243

  
245 244
    def _map_partition(self, dev, num, start, end):
246
        name = os.path.basename(dev)
245
        name = os.path.basename(dev) + "_" + uuid.uuid4().hex
247 246
        tablefd, table = tempfile.mkstemp()
248 247
        try:
249 248
            size = end - start + 1
......
321 320
                 '/boot/grub/menu.lst',
322 321
                 '/boot/grub/grub.conf']
323 322

  
324
        orig = dict(map(
325
            lambda p: (
326
                p.number,
327
                blkid('-s', 'UUID', '-o', 'value', p.path).stdout.strip()),
328
            self.disk.partitions))
323
        orig = {}
324
        for p in self.disk.partitions:
325
            if p.number in new_uuid.keys():
326
                orig[p.number] = \
327
                    blkid('-s', 'UUID', '-o', 'value', p.path).stdout.strip()
329 328

  
330 329
        for f in map(lambda f: target + f, files):
331

  
332 330
            if not os.path.exists(f):
333 331
                continue
334 332

  
......
340 338
                        line = re.sub(orig[i], uuid, line)
341 339
                    dest.write(line)
342 340

  
343
    def _create_filesystems(self, image):
341
    def _create_filesystems(self, image, partitions):
344 342

  
345 343
        filesystem = {}
346 344
        for p in self.disk.partitions:
347 345
            filesystem[p.number] = self._get_mount_options(p.path)
348 346

  
349
        partitions = self._get_partitions(parted.Disk(parted.Device(image)))
350 347
        unmounted = filter(lambda p: filesystem[p.num] is None, partitions)
351 348
        mounted = filter(lambda p: filesystem[p.num] is not None, partitions)
352 349

  
......
429 426
            os.close(fd)
430 427

  
431 428
        self._create_partition_table(image)
432

  
433
        end_sector = self._shrink_partitions(image)
434

  
435
        size = (end_sector + 1) * self.disk.device.sectorSize
429
        end_sector, partitions = self._shrink_partitions(image)
430

  
431
        if self.disk.type == 'gpt':
432
            old_size = size
433
            size = (end_sector + 1) * self.disk.device.sectorSize
434
            ptable = GPTPartitionTable(image)
435
            size = ptable.shrink(size, old_size)
436
        else:
437
            # Alighn to 2048
438
            end_sector = ((end_sector + 2047) // 2048) * 2048
439
            size = (end_sector + 1) * self.disk.device.sectorSize
436 440

  
437 441
        # Truncate image to the new size.
438 442
        fd = os.open(image, os.O_RDWR)
......
449 453
                             dirname)
450 454
        self.out.success("sufficient")
451 455

  
452
        self._create_filesystems(image)
456
        self._create_filesystems(image, partitions)
453 457

  
454 458
        return image
455 459

  
b/image_creator/gpt.py
296 296
            d.write(self.mbr.pack())
297 297
            d.write(self.primary.pack())
298 298
            d.write('\x00' * (BLOCKSIZE - self.primary.size()))
299
            d.write(self.part_entries)
299 300
            d.seek(self.secondary.part_entry_start * BLOCKSIZE)
300 301
            d.write(self.part_entries)
301 302
            d.seek(self.primary.backup_lba * BLOCKSIZE)

Also available in: Unified diff