diff options
Diffstat (limited to 'scripts/lib/mic/imager/raw.py')
| -rw-r--r-- | scripts/lib/mic/imager/raw.py | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/scripts/lib/mic/imager/raw.py b/scripts/lib/mic/imager/raw.py new file mode 100644 index 0000000000..838191a6f1 --- /dev/null +++ b/scripts/lib/mic/imager/raw.py | |||
| @@ -0,0 +1,501 @@ | |||
| 1 | #!/usr/bin/python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2011 Intel, Inc. | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify it | ||
| 6 | # under the terms of the GNU General Public License as published by the Free | ||
| 7 | # Software Foundation; version 2 of the License | ||
| 8 | # | ||
| 9 | # This program is distributed in the hope that it will be useful, but | ||
| 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 12 | # for more details. | ||
| 13 | # | ||
| 14 | # You should have received a copy of the GNU General Public License along | ||
| 15 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 16 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | |||
| 18 | import os | ||
| 19 | import stat | ||
| 20 | import shutil | ||
| 21 | |||
| 22 | from mic import kickstart, msger | ||
| 23 | from mic.utils import fs_related, runner, misc | ||
| 24 | from mic.utils.partitionedfs import PartitionedMount | ||
| 25 | from mic.utils.errors import CreatorError, MountError | ||
| 26 | from mic.imager.baseimager import BaseImageCreator | ||
| 27 | |||
| 28 | |||
| 29 | class RawImageCreator(BaseImageCreator): | ||
| 30 | """Installs a system into a file containing a partitioned disk image. | ||
| 31 | |||
| 32 | ApplianceImageCreator is an advanced ImageCreator subclass; a sparse file | ||
| 33 | is formatted with a partition table, each partition loopback mounted | ||
| 34 | and the system installed into an virtual disk. The disk image can | ||
| 35 | subsequently be booted in a virtual machine or accessed with kpartx | ||
| 36 | """ | ||
| 37 | |||
| 38 | def __init__(self, creatoropts=None, pkgmgr=None, compress_image=None, generate_bmap=None, fstab_entry="uuid"): | ||
| 39 | """Initialize a ApplianceImageCreator instance. | ||
| 40 | |||
| 41 | This method takes the same arguments as ImageCreator.__init__() | ||
| 42 | """ | ||
| 43 | BaseImageCreator.__init__(self, creatoropts, pkgmgr) | ||
| 44 | |||
| 45 | self.__instloop = None | ||
| 46 | self.__imgdir = None | ||
| 47 | self.__disks = {} | ||
| 48 | self.__disk_format = "raw" | ||
| 49 | self._disk_names = [] | ||
| 50 | self._ptable_format = self.ks.handler.bootloader.ptable | ||
| 51 | self.vmem = 512 | ||
| 52 | self.vcpu = 1 | ||
| 53 | self.checksum = False | ||
| 54 | self.use_uuid = fstab_entry == "uuid" | ||
| 55 | self.appliance_version = None | ||
| 56 | self.appliance_release = None | ||
| 57 | self.compress_image = compress_image | ||
| 58 | self.bmap_needed = generate_bmap | ||
| 59 | self._need_extlinux = not kickstart.use_installerfw(self.ks, "extlinux") | ||
| 60 | #self.getsource = False | ||
| 61 | #self.listpkg = False | ||
| 62 | |||
| 63 | self._dep_checks.extend(["sync", "kpartx", "parted"]) | ||
| 64 | if self._need_extlinux: | ||
| 65 | self._dep_checks.extend(["extlinux"]) | ||
| 66 | |||
| 67 | def configure(self, repodata = None): | ||
| 68 | import subprocess | ||
| 69 | def chroot(): | ||
| 70 | os.chroot(self._instroot) | ||
| 71 | os.chdir("/") | ||
| 72 | |||
| 73 | if os.path.exists(self._instroot + "/usr/bin/Xorg"): | ||
| 74 | subprocess.call(["/bin/chmod", "u+s", "/usr/bin/Xorg"], | ||
| 75 | preexec_fn = chroot) | ||
| 76 | |||
| 77 | BaseImageCreator.configure(self, repodata) | ||
| 78 | |||
| 79 | def _get_fstab(self): | ||
| 80 | if kickstart.use_installerfw(self.ks, "fstab"): | ||
| 81 | # The fstab file will be generated by installer framework scripts | ||
| 82 | # instead. | ||
| 83 | return None | ||
| 84 | |||
| 85 | s = "" | ||
| 86 | for mp in self.__instloop.mountOrder: | ||
| 87 | p = None | ||
| 88 | for p1 in self.__instloop.partitions: | ||
| 89 | if p1['mountpoint'] == mp: | ||
| 90 | p = p1 | ||
| 91 | break | ||
| 92 | |||
| 93 | if self.use_uuid and p['uuid']: | ||
| 94 | device = "UUID=%s" % p['uuid'] | ||
| 95 | else: | ||
| 96 | device = "/dev/%s%-d" % (p['disk_name'], p['num']) | ||
| 97 | |||
| 98 | s += "%(device)s %(mountpoint)s %(fstype)s %(fsopts)s 0 0\n" % { | ||
| 99 | 'device': device, | ||
| 100 | 'mountpoint': p['mountpoint'], | ||
| 101 | 'fstype': p['fstype'], | ||
| 102 | 'fsopts': "defaults,noatime" if not p['fsopts'] else p['fsopts']} | ||
| 103 | |||
| 104 | if p['mountpoint'] == "/": | ||
| 105 | for subvol in self.__instloop.subvolumes: | ||
| 106 | if subvol['mountpoint'] == "/": | ||
| 107 | continue | ||
| 108 | s += "%(device)s %(mountpoint)s %(fstype)s %(fsopts)s 0 0\n" % { | ||
| 109 | 'device': "/dev/%s%-d" % (p['disk_name'], p['num']), | ||
| 110 | 'mountpoint': subvol['mountpoint'], | ||
| 111 | 'fstype': p['fstype'], | ||
| 112 | 'fsopts': "defaults,noatime" if not subvol['fsopts'] else subvol['fsopts']} | ||
| 113 | |||
| 114 | s += "devpts /dev/pts devpts gid=5,mode=620 0 0\n" | ||
| 115 | s += "tmpfs /dev/shm tmpfs defaults 0 0\n" | ||
| 116 | s += "proc /proc proc defaults 0 0\n" | ||
| 117 | s += "sysfs /sys sysfs defaults 0 0\n" | ||
| 118 | return s | ||
| 119 | |||
| 120 | def _create_mkinitrd_config(self): | ||
| 121 | """write to tell which modules to be included in initrd""" | ||
| 122 | |||
| 123 | mkinitrd = "" | ||
| 124 | mkinitrd += "PROBE=\"no\"\n" | ||
| 125 | mkinitrd += "MODULES+=\"ext3 ata_piix sd_mod libata scsi_mod\"\n" | ||
| 126 | mkinitrd += "rootfs=\"ext3\"\n" | ||
| 127 | mkinitrd += "rootopts=\"defaults\"\n" | ||
| 128 | |||
| 129 | msger.debug("Writing mkinitrd config %s/etc/sysconfig/mkinitrd" \ | ||
| 130 | % self._instroot) | ||
| 131 | os.makedirs(self._instroot + "/etc/sysconfig/",mode=644) | ||
| 132 | cfg = open(self._instroot + "/etc/sysconfig/mkinitrd", "w") | ||
| 133 | cfg.write(mkinitrd) | ||
| 134 | cfg.close() | ||
| 135 | |||
| 136 | def _get_parts(self): | ||
| 137 | if not self.ks: | ||
| 138 | raise CreatorError("Failed to get partition info, " | ||
| 139 | "please check your kickstart setting.") | ||
| 140 | |||
| 141 | # Set a default partition if no partition is given out | ||
| 142 | if not self.ks.handler.partition.partitions: | ||
| 143 | partstr = "part / --size 1900 --ondisk sda --fstype=ext3" | ||
| 144 | args = partstr.split() | ||
| 145 | pd = self.ks.handler.partition.parse(args[1:]) | ||
| 146 | if pd not in self.ks.handler.partition.partitions: | ||
| 147 | self.ks.handler.partition.partitions.append(pd) | ||
| 148 | |||
| 149 | # partitions list from kickstart file | ||
| 150 | return kickstart.get_partitions(self.ks) | ||
| 151 | |||
| 152 | def get_disk_names(self): | ||
| 153 | """ Returns a list of physical target disk names (e.g., 'sdb') which | ||
| 154 | will be created. """ | ||
| 155 | |||
| 156 | if self._disk_names: | ||
| 157 | return self._disk_names | ||
| 158 | |||
| 159 | #get partition info from ks handler | ||
| 160 | parts = self._get_parts() | ||
| 161 | |||
| 162 | for i in range(len(parts)): | ||
| 163 | if parts[i].disk: | ||
| 164 | disk_name = parts[i].disk | ||
| 165 | else: | ||
| 166 | raise CreatorError("Failed to create disks, no --ondisk " | ||
| 167 | "specified in partition line of ks file") | ||
| 168 | |||
| 169 | if parts[i].mountpoint and not parts[i].fstype: | ||
| 170 | raise CreatorError("Failed to create disks, no --fstype " | ||
| 171 | "specified for partition with mountpoint " | ||
| 172 | "'%s' in the ks file") | ||
| 173 | |||
| 174 | self._disk_names.append(disk_name) | ||
| 175 | |||
| 176 | return self._disk_names | ||
| 177 | |||
| 178 | def _full_name(self, name, extention): | ||
| 179 | """ Construct full file name for a file we generate. """ | ||
| 180 | return "%s-%s.%s" % (self.name, name, extention) | ||
| 181 | |||
| 182 | def _full_path(self, path, name, extention): | ||
| 183 | """ Construct full file path to a file we generate. """ | ||
| 184 | return os.path.join(path, self._full_name(name, extention)) | ||
| 185 | |||
| 186 | # | ||
| 187 | # Actual implemention | ||
| 188 | # | ||
| 189 | def _mount_instroot(self, base_on = None): | ||
| 190 | parts = self._get_parts() | ||
| 191 | self.__instloop = PartitionedMount(self._instroot) | ||
| 192 | |||
| 193 | for p in parts: | ||
| 194 | self.__instloop.add_partition(int(p.size), | ||
| 195 | p.disk, | ||
| 196 | p.mountpoint, | ||
| 197 | p.fstype, | ||
| 198 | p.label, | ||
| 199 | fsopts = p.fsopts, | ||
| 200 | boot = p.active, | ||
| 201 | align = p.align, | ||
| 202 | part_type = p.part_type) | ||
| 203 | |||
| 204 | self.__instloop.layout_partitions(self._ptable_format) | ||
| 205 | |||
| 206 | # Create the disks | ||
| 207 | self.__imgdir = self._mkdtemp() | ||
| 208 | for disk_name, disk in self.__instloop.disks.items(): | ||
| 209 | full_path = self._full_path(self.__imgdir, disk_name, "raw") | ||
| 210 | msger.debug("Adding disk %s as %s with size %s bytes" \ | ||
| 211 | % (disk_name, full_path, disk['min_size'])) | ||
| 212 | |||
| 213 | disk_obj = fs_related.SparseLoopbackDisk(full_path, | ||
| 214 | disk['min_size']) | ||
| 215 | self.__disks[disk_name] = disk_obj | ||
| 216 | self.__instloop.add_disk(disk_name, disk_obj) | ||
| 217 | |||
| 218 | self.__instloop.mount() | ||
| 219 | self._create_mkinitrd_config() | ||
| 220 | |||
| 221 | def _get_required_packages(self): | ||
| 222 | required_packages = BaseImageCreator._get_required_packages(self) | ||
| 223 | if self._need_extlinux: | ||
| 224 | if not self.target_arch or not self.target_arch.startswith("arm"): | ||
| 225 | required_packages += ["syslinux", "syslinux-extlinux"] | ||
| 226 | return required_packages | ||
| 227 | |||
| 228 | def _get_excluded_packages(self): | ||
| 229 | return BaseImageCreator._get_excluded_packages(self) | ||
| 230 | |||
| 231 | def _get_syslinux_boot_config(self): | ||
| 232 | rootdev = None | ||
| 233 | root_part_uuid = None | ||
| 234 | for p in self.__instloop.partitions: | ||
| 235 | if p['mountpoint'] == "/": | ||
| 236 | rootdev = "/dev/%s%-d" % (p['disk_name'], p['num']) | ||
| 237 | root_part_uuid = p['partuuid'] | ||
| 238 | |||
| 239 | return (rootdev, root_part_uuid) | ||
| 240 | |||
| 241 | def _create_syslinux_config(self): | ||
| 242 | |||
| 243 | splash = os.path.join(self._instroot, "boot/extlinux") | ||
| 244 | if os.path.exists(splash): | ||
| 245 | splashline = "menu background splash.jpg" | ||
| 246 | else: | ||
| 247 | splashline = "" | ||
| 248 | |||
| 249 | (rootdev, root_part_uuid) = self._get_syslinux_boot_config() | ||
| 250 | options = self.ks.handler.bootloader.appendLine | ||
| 251 | |||
| 252 | #XXX don't hardcode default kernel - see livecd code | ||
| 253 | syslinux_conf = "" | ||
| 254 | syslinux_conf += "prompt 0\n" | ||
| 255 | syslinux_conf += "timeout 1\n" | ||
| 256 | syslinux_conf += "\n" | ||
| 257 | syslinux_conf += "default vesamenu.c32\n" | ||
| 258 | syslinux_conf += "menu autoboot Starting %s...\n" % self.distro_name | ||
| 259 | syslinux_conf += "menu hidden\n" | ||
| 260 | syslinux_conf += "\n" | ||
| 261 | syslinux_conf += "%s\n" % splashline | ||
| 262 | syslinux_conf += "menu title Welcome to %s!\n" % self.distro_name | ||
| 263 | syslinux_conf += "menu color border 0 #ffffffff #00000000\n" | ||
| 264 | syslinux_conf += "menu color sel 7 #ffffffff #ff000000\n" | ||
| 265 | syslinux_conf += "menu color title 0 #ffffffff #00000000\n" | ||
| 266 | syslinux_conf += "menu color tabmsg 0 #ffffffff #00000000\n" | ||
| 267 | syslinux_conf += "menu color unsel 0 #ffffffff #00000000\n" | ||
| 268 | syslinux_conf += "menu color hotsel 0 #ff000000 #ffffffff\n" | ||
| 269 | syslinux_conf += "menu color hotkey 7 #ffffffff #ff000000\n" | ||
| 270 | syslinux_conf += "menu color timeout_msg 0 #ffffffff #00000000\n" | ||
| 271 | syslinux_conf += "menu color timeout 0 #ffffffff #00000000\n" | ||
| 272 | syslinux_conf += "menu color cmdline 0 #ffffffff #00000000\n" | ||
| 273 | |||
| 274 | versions = [] | ||
| 275 | kernels = self._get_kernel_versions() | ||
| 276 | symkern = "%s/boot/vmlinuz" % self._instroot | ||
| 277 | |||
| 278 | if os.path.lexists(symkern): | ||
| 279 | v = os.path.realpath(symkern).replace('%s-' % symkern, "") | ||
| 280 | syslinux_conf += "label %s\n" % self.distro_name.lower() | ||
| 281 | syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v) | ||
| 282 | syslinux_conf += "\tlinux ../vmlinuz\n" | ||
| 283 | if self._ptable_format == 'msdos': | ||
| 284 | rootstr = rootdev | ||
| 285 | else: | ||
| 286 | if not root_part_uuid: | ||
| 287 | raise MountError("Cannot find the root GPT partition UUID") | ||
| 288 | rootstr = "PARTUUID=%s" % root_part_uuid | ||
| 289 | syslinux_conf += "\tappend ro root=%s %s\n" % (rootstr, options) | ||
| 290 | syslinux_conf += "\tmenu default\n" | ||
| 291 | else: | ||
| 292 | for kernel in kernels: | ||
| 293 | for version in kernels[kernel]: | ||
| 294 | versions.append(version) | ||
| 295 | |||
| 296 | footlabel = 0 | ||
| 297 | for v in versions: | ||
| 298 | syslinux_conf += "label %s%d\n" \ | ||
| 299 | % (self.distro_name.lower(), footlabel) | ||
| 300 | syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v) | ||
| 301 | syslinux_conf += "\tlinux ../vmlinuz-%s\n" % v | ||
| 302 | syslinux_conf += "\tappend ro root=%s %s\n" \ | ||
| 303 | % (rootdev, options) | ||
| 304 | if footlabel == 0: | ||
| 305 | syslinux_conf += "\tmenu default\n" | ||
| 306 | footlabel += 1; | ||
| 307 | |||
| 308 | msger.debug("Writing syslinux config %s/boot/extlinux/extlinux.conf" \ | ||
| 309 | % self._instroot) | ||
| 310 | cfg = open(self._instroot + "/boot/extlinux/extlinux.conf", "w") | ||
| 311 | cfg.write(syslinux_conf) | ||
| 312 | cfg.close() | ||
| 313 | |||
| 314 | def _install_syslinux(self): | ||
| 315 | for name in self.__disks.keys(): | ||
| 316 | loopdev = self.__disks[name].device | ||
| 317 | |||
| 318 | # Set MBR | ||
| 319 | mbrfile = "%s/usr/share/syslinux/" % self._instroot | ||
| 320 | if self._ptable_format == 'gpt': | ||
| 321 | mbrfile += "gptmbr.bin" | ||
| 322 | else: | ||
| 323 | mbrfile += "mbr.bin" | ||
| 324 | |||
| 325 | msger.debug("Installing syslinux bootloader '%s' to %s" % \ | ||
| 326 | (mbrfile, loopdev)) | ||
| 327 | |||
| 328 | mbrsize = os.stat(mbrfile)[stat.ST_SIZE] | ||
| 329 | rc = runner.show(['dd', 'if=%s' % mbrfile, 'of=' + loopdev]) | ||
| 330 | if rc != 0: | ||
| 331 | raise MountError("Unable to set MBR to %s" % loopdev) | ||
| 332 | |||
| 333 | |||
| 334 | # Ensure all data is flushed to disk before doing syslinux install | ||
| 335 | runner.quiet('sync') | ||
| 336 | |||
| 337 | fullpathsyslinux = fs_related.find_binary_path("extlinux") | ||
| 338 | rc = runner.show([fullpathsyslinux, | ||
| 339 | "-i", | ||
| 340 | "%s/boot/extlinux" % self._instroot]) | ||
| 341 | if rc != 0: | ||
| 342 | raise MountError("Unable to install syslinux bootloader to %s" \ | ||
| 343 | % loopdev) | ||
| 344 | |||
| 345 | def _create_bootconfig(self): | ||
| 346 | #If syslinux is available do the required configurations. | ||
| 347 | if self._need_extlinux \ | ||
| 348 | and os.path.exists("%s/usr/share/syslinux/" % (self._instroot)) \ | ||
| 349 | and os.path.exists("%s/boot/extlinux/" % (self._instroot)): | ||
| 350 | self._create_syslinux_config() | ||
| 351 | self._install_syslinux() | ||
| 352 | |||
| 353 | def _unmount_instroot(self): | ||
| 354 | if not self.__instloop is None: | ||
| 355 | try: | ||
| 356 | self.__instloop.cleanup() | ||
| 357 | except MountError, err: | ||
| 358 | msger.warning("%s" % err) | ||
| 359 | |||
| 360 | def _resparse(self, size = None): | ||
| 361 | return self.__instloop.resparse(size) | ||
| 362 | |||
| 363 | def _get_post_scripts_env(self, in_chroot): | ||
| 364 | env = BaseImageCreator._get_post_scripts_env(self, in_chroot) | ||
| 365 | |||
| 366 | # Export the file-system UUIDs and partition UUIDs (AKA PARTUUIDs) | ||
| 367 | for p in self.__instloop.partitions: | ||
| 368 | env.update(self._set_part_env(p['ks_pnum'], "UUID", p['uuid'])) | ||
| 369 | env.update(self._set_part_env(p['ks_pnum'], "PARTUUID", p['partuuid'])) | ||
| 370 | |||
| 371 | return env | ||
| 372 | |||
| 373 | def _stage_final_image(self): | ||
| 374 | """Stage the final system image in _outdir. | ||
| 375 | write meta data | ||
| 376 | """ | ||
| 377 | self._resparse() | ||
| 378 | |||
| 379 | if self.compress_image: | ||
| 380 | for imgfile in os.listdir(self.__imgdir): | ||
| 381 | if imgfile.endswith('.raw') or imgfile.endswith('bin'): | ||
| 382 | imgpath = os.path.join(self.__imgdir, imgfile) | ||
| 383 | misc.compressing(imgpath, self.compress_image) | ||
| 384 | |||
| 385 | if self.pack_to: | ||
| 386 | dst = os.path.join(self._outdir, self.pack_to) | ||
| 387 | msger.info("Pack all raw images to %s" % dst) | ||
| 388 | misc.packing(dst, self.__imgdir) | ||
| 389 | else: | ||
| 390 | msger.debug("moving disks to stage location") | ||
| 391 | for imgfile in os.listdir(self.__imgdir): | ||
| 392 | src = os.path.join(self.__imgdir, imgfile) | ||
| 393 | dst = os.path.join(self._outdir, imgfile) | ||
| 394 | msger.debug("moving %s to %s" % (src,dst)) | ||
| 395 | shutil.move(src,dst) | ||
| 396 | self._write_image_xml() | ||
| 397 | |||
| 398 | def _write_image_xml(self): | ||
| 399 | imgarch = "i686" | ||
| 400 | if self.target_arch and self.target_arch.startswith("arm"): | ||
| 401 | imgarch = "arm" | ||
| 402 | xml = "<image>\n" | ||
| 403 | |||
| 404 | name_attributes = "" | ||
| 405 | if self.appliance_version: | ||
| 406 | name_attributes += " version='%s'" % self.appliance_version | ||
| 407 | if self.appliance_release: | ||
| 408 | name_attributes += " release='%s'" % self.appliance_release | ||
| 409 | xml += " <name%s>%s</name>\n" % (name_attributes, self.name) | ||
| 410 | xml += " <domain>\n" | ||
| 411 | # XXX don't hardcode - determine based on the kernel we installed for | ||
| 412 | # grub baremetal vs xen | ||
| 413 | xml += " <boot type='hvm'>\n" | ||
| 414 | xml += " <guest>\n" | ||
| 415 | xml += " <arch>%s</arch>\n" % imgarch | ||
| 416 | xml += " </guest>\n" | ||
| 417 | xml += " <os>\n" | ||
| 418 | xml += " <loader dev='hd'/>\n" | ||
| 419 | xml += " </os>\n" | ||
| 420 | |||
| 421 | i = 0 | ||
| 422 | for name in self.__disks.keys(): | ||
| 423 | full_name = self._full_name(name, self.__disk_format) | ||
| 424 | xml += " <drive disk='%s' target='hd%s'/>\n" \ | ||
| 425 | % (full_name, chr(ord('a') + i)) | ||
| 426 | i = i + 1 | ||
| 427 | |||
| 428 | xml += " </boot>\n" | ||
| 429 | xml += " <devices>\n" | ||
| 430 | xml += " <vcpu>%s</vcpu>\n" % self.vcpu | ||
| 431 | xml += " <memory>%d</memory>\n" %(self.vmem * 1024) | ||
| 432 | for network in self.ks.handler.network.network: | ||
| 433 | xml += " <interface/>\n" | ||
| 434 | xml += " <graphics/>\n" | ||
| 435 | xml += " </devices>\n" | ||
| 436 | xml += " </domain>\n" | ||
| 437 | xml += " <storage>\n" | ||
| 438 | |||
| 439 | if self.checksum is True: | ||
| 440 | for name in self.__disks.keys(): | ||
| 441 | diskpath = self._full_path(self._outdir, name, \ | ||
| 442 | self.__disk_format) | ||
| 443 | full_name = self._full_name(name, self.__disk_format) | ||
| 444 | |||
| 445 | msger.debug("Generating disk signature for %s" % full_name) | ||
| 446 | |||
| 447 | xml += " <disk file='%s' use='system' format='%s'>\n" \ | ||
| 448 | % (full_name, self.__disk_format) | ||
| 449 | |||
| 450 | hashes = misc.calc_hashes(diskpath, ('sha1', 'sha256')) | ||
| 451 | |||
| 452 | xml += " <checksum type='sha1'>%s</checksum>\n" \ | ||
| 453 | % hashes[0] | ||
| 454 | xml += " <checksum type='sha256'>%s</checksum>\n" \ | ||
| 455 | % hashes[1] | ||
| 456 | xml += " </disk>\n" | ||
| 457 | else: | ||
| 458 | for name in self.__disks.keys(): | ||
| 459 | full_name = self._full_name(name, self.__disk_format) | ||
| 460 | xml += " <disk file='%s' use='system' format='%s'/>\n" \ | ||
| 461 | % (full_name, self.__disk_format) | ||
| 462 | |||
| 463 | xml += " </storage>\n" | ||
| 464 | xml += "</image>\n" | ||
| 465 | |||
| 466 | msger.debug("writing image XML to %s/%s.xml" %(self._outdir, self.name)) | ||
| 467 | cfg = open("%s/%s.xml" % (self._outdir, self.name), "w") | ||
| 468 | cfg.write(xml) | ||
| 469 | cfg.close() | ||
| 470 | |||
| 471 | def generate_bmap(self): | ||
| 472 | """ Generate block map file for the image. The idea is that while disk | ||
| 473 | images we generate may be large (e.g., 4GiB), they may actually contain | ||
| 474 | only little real data, e.g., 512MiB. This data are files, directories, | ||
| 475 | file-system meta-data, partition table, etc. In other words, when | ||
| 476 | flashing the image to the target device, you do not have to copy all the | ||
| 477 | 4GiB of data, you can copy only 512MiB of it, which is 4 times faster. | ||
| 478 | |||
| 479 | This function generates the block map file for an arbitrary image that | ||
| 480 | mic has generated. The block map file is basically an XML file which | ||
| 481 | contains a list of blocks which have to be copied to the target device. | ||
| 482 | The other blocks are not used and there is no need to copy them. """ | ||
| 483 | |||
| 484 | if self.bmap_needed is None: | ||
| 485 | return | ||
| 486 | |||
| 487 | from mic.utils import BmapCreate | ||
| 488 | msger.info("Generating the map file(s)") | ||
| 489 | |||
| 490 | for name in self.__disks.keys(): | ||
| 491 | image = self._full_path(self.__imgdir, name, self.__disk_format) | ||
| 492 | bmap_file = self._full_path(self._outdir, name, "bmap") | ||
| 493 | |||
| 494 | msger.debug("Generating block map file '%s'" % bmap_file) | ||
| 495 | |||
| 496 | try: | ||
| 497 | creator = BmapCreate.BmapCreate(image, bmap_file) | ||
| 498 | creator.generate() | ||
| 499 | del creator | ||
| 500 | except BmapCreate.Error as err: | ||
| 501 | raise CreatorError("Failed to create bmap file: %s" % str(err)) | ||
