def readInventory(self): self.mount_root() try: self.inventory = util.readKeyValueFile(os.path.join( self.root_fs.mount_point, constants.INVENTORY_FILE), strip_quotes=True) self.build = self.inventory['BUILD_NUMBER'] self.version = Version.from_string( "%s-%s" % (self.inventory['PLATFORM_VERSION'], self.build)) if 'PRODUCT_NAME' in self.inventory: self.name = self.inventory['PRODUCT_NAME'] self.brand = self.inventory['PRODUCT_BRAND'] else: self.name = self.inventory['PLATFORM_NAME'] self.brand = self.inventory['PLATFORM_NAME'] if 'OEM_BRAND' in self.inventory: self.oem_brand = self.inventory['OEM_BRAND'] self.visual_brand = self.oem_brand else: self.visual_brand = self.brand if 'OEM_VERSION' in self.inventory: self.oem_version = self.inventory['OEM_VERSION'] self.visual_version = "%s-%s" % (self.inventory['OEM_VERSION'], self.build) else: if '/' in self.build: self.visual_version = self.inventory['PRODUCT_VERSION'] else: self.visual_version = "%s-%s" % ( self.inventory['PRODUCT_VERSION'], self.build) finally: self.unmount_root()
def loadFromIfcfg(filename): def valOrNone(d, k): return d.has_key(k) and d[k] or None conf = util.readKeyValueFile(filename) mode = None if conf.has_key('BOOTPROTO'): if conf['BOOTPROTO'] == 'static' or conf.has_key('IPADDR'): mode = NetInterface.Static elif conf['BOOTPROTO'] == 'dhcp': mode = NetInterface.DHCP hwaddr = valOrNone(conf, 'HWADDR') if not hwaddr: hwaddr = valOrNone(conf, 'MACADDR') if not hwaddr: try: hwaddr = netutil.getHWAddr(conf['DEVICE']) except: pass dns = None n = 1 while conf.has_key('DNS%d' % n): if not dns: dns = [] dns.append(conf['DNS%d' % n]) n += 1 return NetInterface(mode, hwaddr, valOrNone(conf, 'IPADDR'), valOrNone(conf, 'NETMASK'), valOrNone(conf, 'GATEWAY'), dns, valOrNone(conf, 'DOMAIN'))
def restoreFromBackup(backup, progress=lambda x: ()): """ Restore files from backup_partition to the root partition on disk. Call progress with a value between 0 and 100. Re-install bootloader. Fails if backup is not same version as the CD in use.""" disk = backup.root_disk tool = PartitionTool(disk) _, boot_partnum, primary_partnum, backup_partnum, logs_partnum, swap_partnum, _ = backend.inspectTargetDisk( disk, None, [], constants.PRESERVE_IF_UTILITY, True, True) backup_version = backup.version limit_version = product.THIS_PLATFORM_VERSION logs_partition = tool.getPartition(logs_partnum) boot_partition = tool.getPartition(boot_partnum) root_partition = partitionDevice(disk, primary_partnum) backup_fs = util.TempMount(backup.partition, 'backup-', options=['ro']) inventory = util.readKeyValueFile(os.path.join(backup_fs.mount_point, constants.INVENTORY_FILE), strip_quotes=True) backup_partition_layout = [] if 'PARTITION_LAYOUT' in inventory: # Present from XS 7.0 backup_partition_layout = inventory['PARTITION_LAYOUT'].split(',') backup_fs.unmount() (boot, _, _, _, logs) = diskutil.probeDisk(disk) xelogging.log("BACKUP DISK PARTITION LAYOUT: %s" % backup_partition_layout) if not logs[0] and boot[ 0] and not backup_partition_layout: # From 7.x (no new layout - yes Boot partition) to 6.x restoreWithoutRepartButUEFI(backup, progress) else: doRestore(backup, progress, backup_partition_layout, logs[0])
def completeUpgrade(self, mounts, prev_install, target_disk, backup_partnum, logs_partnum, admin_iface, admin_bridge, admin_config): util.assertDir(os.path.join(mounts['root'], "var/lib/xcp")) util.assertDir(os.path.join(mounts['root'], "etc/xensource")) Upgrader.completeUpgrade(self, mounts, target_disk, backup_partnum) v = Version(prev_install.version.ver) f = open(os.path.join(mounts['root'], 'var/tmp/.previousVersion'), 'w') f.write("PLATFORM_VERSION='%s'\n" % v) f.close() state = open( os.path.join(mounts['root'], constants.FIRSTBOOT_DATA_DIR, 'host.conf'), 'w') print >> state, "UPGRADE=true" state.close() # The existence of the static-rules.conf is used to detect upgrade from Boston or newer if os.path.exists( os.path.join( mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf' )): # CA-82901 - convert any old style ppn referenced to new style ppn references util.runCmd2([ 'sed', r's/pci\([0-9]\+p[0-9]\+\)/p\1/g', '-i', os.path.join( mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf' ) ]) net_dict = util.readKeyValueFile( os.path.join(mounts['root'], 'etc/sysconfig/network')) if net_dict.get('NETWORKING_IPV6', 'no') == 'no': nfd = open(os.path.join(mounts['root'], 'etc/sysconfig/network'), 'a') nfd.write("NETWORKING_IPV6=no\n") nfd.close() netutil.disable_ipv6_module(mounts["root"]) # handle the conversion of devices from aacraid to smartpqi primary_disk = self.source.getInventoryValue("PRIMARY_DISK") target_link = diskutil.idFromPartition(target_disk) or target_disk if primary_disk.startswith('/dev/disk/by-id/scsi-') and \ target_link.startswith('/dev/disk/by-id/scsi-') and \ primary_disk != target_link: for i in (os.path.join(constants.FIRSTBOOT_DATA_DIR, 'default-storage.conf'), constants.XAPI_DB): util.runCmd2([ 'sed', '-i', '-e', "s#%s#%s#g" % (primary_disk, target_link), os.path.join(mounts['root'], i) ])
def __init__(self, part, mnt): self.partition = part self.inventory = util.readKeyValueFile(os.path.join(mnt, constants.INVENTORY_FILE), strip_quotes=True) self.name = self.inventory["PRODUCT_NAME"] self.brand = self.inventory["PRODUCT_BRAND"] self.version = Version.from_string( "%s-%s" % (self.inventory["PRODUCT_VERSION"], self.inventory["BUILD_NUMBER"]) ) self.build = self.inventory["BUILD_NUMBER"] self.root_disk = diskutil.partitionFromId(self.inventory["PRIMARY_DISK"])
def readInventory(self): self.mount_root() try: self.inventory = util.readKeyValueFile( os.path.join(self.root_fs.mount_point, constants.INVENTORY_FILE), strip_quotes=True ) self.name = self.inventory["PRODUCT_NAME"] self.brand = self.inventory["PRODUCT_BRAND"] self.version = Version.from_string( "%s-%s" % (self.inventory["PRODUCT_VERSION"], self.inventory["BUILD_NUMBER"]) ) self.build = self.inventory["BUILD_NUMBER"] finally: self.unmount_root()
def __init__(self, source): Upgrader.__init__(self, source) primary_fs = util.TempMount(self.source.root_device, 'primary-', options=['ro']) safe2upgrade_path = os.path.join(primary_fs.mount_point, constants.SAFE_2_UPGRADE) default_storage_conf_path = os.path.join(primary_fs.mount_point, "etc/firstboot.d/data/default-storage.conf") self.safe2upgrade = os.path.isfile(safe2upgrade_path) self.vgs_output = None self.storage_type = None if os.path.exists(default_storage_conf_path): input_data = util.readKeyValueFile(default_storage_conf_path) self.storage_type = input_data['TYPE'] primary_fs.unmount()
def __init__(self, part, mnt): self.partition = part self.inventory = util.readKeyValueFile(os.path.join( mnt, constants.INVENTORY_FILE), strip_quotes=True) self.build = self.inventory['BUILD_NUMBER'] self.version = Version.from_string( "%s-%s" % (self.inventory['PLATFORM_VERSION'], self.build)) if 'PRODUCT_NAME' in self.inventory: self.name = self.inventory['PRODUCT_NAME'] self.brand = self.inventory['PRODUCT_BRAND'] else: self.name = self.inventory['PLATFORM_NAME'] self.brand = self.inventory['PLATFORM_NAME'] if 'OEM_BRAND' in self.inventory: self.oem_brand = self.inventory['OEM_BRAND'] self.visual_brand = self.oem_brand else: self.visual_brand = self.brand if 'OEM_VERSION' in self.inventory: self.oem_version = self.inventory['OEM_VERSION'] self.visual_version = "%s-%s" % (self.inventory['OEM_VERSION'], self.build) else: if '/' in self.build: self.visual_version = self.inventory['PRODUCT_VERSION'] else: self.visual_version = "%s-%s" % ( self.inventory['PRODUCT_VERSION'], self.build) if self.inventory['PRIMARY_DISK'].startswith('/dev/md_'): # Handle restoring an installation using a /dev/md_* path self.root_disk = os.path.realpath( self.inventory['PRIMARY_DISK'].replace('md_', 'md/') + '_0') else: self.root_disk = diskutil.partitionFromId( self.inventory['PRIMARY_DISK']) self.root_disk = getMpathMasterOrDisk(self.root_disk)
def loadFromIfcfg(filename): def valOrNone(d, k): return k in d and d[k] or None conf = util.readKeyValueFile(filename) mode = None if 'BOOTPROTO' in conf: if conf['BOOTPROTO'] == 'static' or 'IPADDR' in conf: mode = NetInterface.Static elif conf['BOOTPROTO'] == 'dhcp': mode = NetInterface.DHCP hwaddr = valOrNone(conf, 'HWADDR') if not hwaddr: hwaddr = valOrNone(conf, 'MACADDR') if not hwaddr: hwaddr = netutil.getHWAddr(conf['DEVICE']) dns = None n = 1 while 'DNS%d' % n in conf: if not dns: dns = [] dns.append(conf['DNS%d' % n]) n += 1 modev6 = None if 'DHCPV6C' in conf: modev6 = NetInterface.DHCP elif 'IPV6_AUTOCONF' in conf: modev6 = NetInterface.Autoconf elif 'IPV6INIT' in conf: modev6 = NetInterface.Static ni = NetInterface(mode, hwaddr, valOrNone(conf, 'IPADDR'), valOrNone(conf, 'NETMASK'), valOrNone(conf, 'GATEWAY'), dns, valOrNone(conf, 'DOMAIN')) ni.addIPv6(modev6, valOrNone(conf, 'IPV6ADDR'), valOrNone(conf, 'IPV6_DEFAULTGW')) return ni
def completeUpgrade(self, mounts, prev_install, target_disk, backup_partnum, admin_iface, admin_bridge, admin_config): util.assertDir(os.path.join(mounts['root'], "var/xapi")) util.assertDir(os.path.join(mounts['root'], "etc/xensource")) Upgrader.completeUpgrade(self, mounts, target_disk, backup_partnum) if not os.path.exists(os.path.join(mounts['root'], constants.DBCACHE)): # upgrade from 5.5, generate dbcache save_dir = os.path.join(mounts['root'], constants.FIRSTBOOT_DATA_DIR, 'initial-ifcfg') util.assertDir(save_dir) dbcache_file = os.path.join(mounts['root'], constants.DBCACHE) dbcache_fd = open(dbcache_file, 'w') network_uid = util.getUUID() dbcache_fd.write('<?xml version="1.0" ?>\n<xenserver-network-configuration>\n') if admin_iface.startswith('bond'): top_pif_uid = bond_pif_uid = util.getUUID() bond_uid = util.getUUID() # find slaves of this bond and write PIFs for them slaves = [] for file in [ f for f in os.listdir(os.path.join(mounts['root'], constants.NET_SCR_DIR)) if re.match('ifcfg-eth[0-9]+$', f) ]: slavecfg = util.readKeyValueFile(os.path.join(mounts['root'], constants.NET_SCR_DIR, file), strip_quotes = False) if slavecfg.has_key('MASTER') and slavecfg['MASTER'] == admin_iface: slave_uid = util.getUUID() slave_net_uid = util.getUUID() slaves.append(slave_uid) slave = NetInterface.loadFromIfcfg(os.path.join(mounts['root'], constants.NET_SCR_DIR, file)) slave.writePif(slavecfg['DEVICE'], dbcache_fd, slave_uid, slave_net_uid, ('slave-of', bond_uid)) # locate bridge that has this interface as its PIFDEV bridge = None for file in [ f for f in os.listdir(os.path.join(mounts['root'], constants.NET_SCR_DIR)) if re.match('ifcfg-xenbr[0-9]+$', f) ]: brcfg = util.readKeyValueFile(os.path.join(mounts['root'], constants.NET_SCR_DIR, file), strip_quotes = False) if brcfg.has_key('PIFDEV') and brcfg['PIFDEV'] == slavecfg['DEVICE']: bridge = brcfg['DEVICE'] break assert bridge dbcache_fd.write('\t<network ref="OpaqueRef:%s">\n' % slave_net_uid) dbcache_fd.write('\t\t<uuid>%sSlaveNetwork</uuid>\n' % slavecfg['DEVICE']) dbcache_fd.write('\t\t<PIFs>\n\t\t\t<PIF>OpaqueRef:%s</PIF>\n\t\t</PIFs>\n' % slave_uid) dbcache_fd.write('\t\t<bridge>%s</bridge>\n' % bridge) dbcache_fd.write('\t\t<other_config/>\n\t</network>\n') # write bond dbcache_fd.write('\t<bond ref="OpaqueRef:%s">\n' % bond_uid) dbcache_fd.write('\t\t<master>OpaqueRef:%s</master>\n' % bond_pif_uid) dbcache_fd.write('\t\t<uuid>InitialManagementBond</uuid>\n\t\t<slaves>\n') for slave_uid in slaves: dbcache_fd.write('\t\t\t<slave>OpaqueRef:%s</slave>\n' % slave_uid) dbcache_fd.write('\t\t</slaves>\n\t</bond>\n') # write bond PIF admin_config.writePif(admin_iface, dbcache_fd, bond_pif_uid, network_uid, ('master-of', bond_uid)) else: top_pif_uid = util.getUUID() # write PIF admin_config.writePif(admin_iface, dbcache_fd, top_pif_uid, network_uid) dbcache_fd.write('\t<network ref="OpaqueRef:%s">\n' % network_uid) dbcache_fd.write('\t\t<uuid>InitialManagementNetwork</uuid>\n') dbcache_fd.write('\t\t<PIFs>\n\t\t\t<PIF>OpaqueRef:%s</PIF>\n\t\t</PIFs>\n' % top_pif_uid) dbcache_fd.write('\t\t<bridge>%s</bridge>\n' % admin_bridge) dbcache_fd.write('\t\t<other_config/>\n\t</network>\n') dbcache_fd.write('</xenserver-network-configuration>\n') dbcache_fd.close() util.runCmd2(['cp', '-p', dbcache_file, save_dir]) else: # upgrade from 5.6 changed = False dbcache_file = os.path.join(mounts['root'], constants.DBCACHE) rdbcache_fd = open(dbcache_file) wdbcache_fd = open(dbcache_file + '.new', 'w') for line in rdbcache_fd: wdbcache_fd.write(line) if '<pif ref=' in line: wdbcache_fd.write("\t\t<tunnel_access_PIF_of/>\n") changed = True rdbcache_fd.close() wdbcache_fd.close() if changed: os.rename(dbcache_file + '.new', dbcache_file) else: os.remove(dbcache_file + '.new') v = Version(prev_install.version.ver) f = open(os.path.join(mounts['root'], 'var/tmp/.previousVersion'), 'w') f.write("PRODUCT_VERSION='%s'\n" % v) f.close() state = open(os.path.join(mounts['root'], constants.FIRSTBOOT_DATA_DIR, 'host.conf'), 'w') print >>state, "UPGRADE=true" state.close() # CP-1508: preserve AD service state ad_on = False try: fh = open(os.path.join(mounts['root'], 'etc/nsswitch.conf'), 'r') for line in fh: if line.startswith('passwd:') and 'lsass' in line: ad_on = True break fh.close() except: pass if ad_on: for service in ['dcerpd', 'eventlogd', 'netlogond', 'npcmuxd', 'lsassd']: util.runCmd2(['chroot', mounts['root'], 'chkconfig', '--add', service]) # EA-1069: create interface-rename state from old xapi database if it doesnt currently exist (static-rules.conf) if not os.path.exists(os.path.join(mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf')): static_text = ( "# Static rules. Autogenerated by the installer from either the answerfile or from previous install\n" "# WARNING - rules in this file override the 'lastboot' assignment of names,\n" "# so editing it may cause unexpected renaming on next boot\n\n" "# Rules are of the form:\n" "# target name: id method = \"value\"\n\n" "# target name must be in the form eth*\n" "# id methods are:\n" "# mac: value should be the mac address of a device (e.g. DE:AD:C0:DE:00:00)\n" "# pci: value should be the pci bus location of the device (e.g. 0000:01:01.1)\n" "# ppn: value should be the result of the biosdevname physical naming policy of a device (e.g. pci1p1)\n" "# label: value should be the SMBios label of a device (for SMBios 2.6 or above)\n") if not os.path.exists(os.path.join(mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/.from_install/')): os.makedirs(os.path.join(mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/.from_install/'), 0775) fout1 = open(os.path.join(mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf'), "w") fout1.write(static_text) fout1.close() fout2 = open(os.path.join(mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/.from_install/static-rules.conf'), "w") fout2.write(static_text) fout2.close() bdn = BiosDevName() bdn.run() devices = bdn.devices # this is a dirty hack but I cant think of much better dbcache = open(os.path.join(mounts['root'], constants.DBCACHE), "r") past_devs = [] mac_next = False eth_next = False for line in ( x.strip() for x in dbcache ): if mac_next: past_devs.append([line.upper()]) mac_next = False continue if eth_next: for bdev in devices: if bdev.get('Assigned MAC', None) == past_devs[-1][0] and 'Bus Info' in bdev: past_devs[-1].extend([bdev['Bus Info'], line]) break eth_next = False continue if line == "<MAC>": mac_next = True continue if line == "<device>": eth_next = True dbcache.close() def jsonify(mac, pci, dev): return '[ "%s", "%s", "%s" ]' % (mac, pci, dev) dynamic_text = ("# Automatically adjusted file. Do not edit unless you are certain you know how to\n") dynamic_text += '{"lastboot":[%s],"old":[]}' % (','.join(map(lambda x: jsonify(*x), (x for x in past_devs if len(x) == 3))), ) fout3 = open(os.path.join(mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/dynamic-rules.json'), "w") fout3.write(dynamic_text) fout3.close() fout4 = open(os.path.join(mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/.from_install/dynamic-rules.json'), "w") fout4.write(dynamic_text) fout4.close() if Version(prev_install.version.ver) < product.THIS_PRODUCT_VERSION: # set journalling option on EXT local SRs l = LVMTool() for lv in l.lvs: if lv['vg_name'].startswith(l.VG_EXT_SR_PREFIX): l.activateVG(lv['vg_name']) path = '/dev/mapper/%s-%s' % (lv['vg_name'].replace('-', '--'), lv['lv_name'].replace('-', '--')) xelogging.log("Setting ordered on " + path) util.runCmd2(['tune2fs', '-o', 'journal_data_ordered', path]) l.deactivateVG(lv['vg_name'])
def readInventoryFile(filename): return util.readKeyValueFile(filename, strip_quotes=True)
def doRestore(backup, progress, backup_partition_layout, has_logs_partition): backup_partition = backup.partition backup_version = backup.version disk = backup.root_disk tool = PartitionTool(disk) _, boot_partnum, primary_partnum, backup_partnum, logs_partnum, swap_partnum, _ = backend.inspectTargetDisk( disk, None, [], constants.PRESERVE_IF_UTILITY, True, True) limit_version = product.THIS_PLATFORM_VERSION logs_partition = tool.getPartition(logs_partnum) boot_partition = tool.getPartition(boot_partnum) assert backup_partition.startswith('/dev/') assert disk.startswith('/dev/') label = None bootlabel = None if has_logs_partition and not backup_partition_layout: # From 7.x (new layout) to 6.x restore_partition = partitionDevice(disk, logs_partnum) else: restore_partition = partitionDevice(disk, primary_partnum) xelogging.log("Restoring to partition %s." % restore_partition) tool = PartitionTool(disk) boot_part = tool.getPartition(boot_partnum) boot_device = partitionDevice(disk, boot_partnum) if boot_part else None efi_boot = boot_part and boot_part['id'] == GPTPartitionTool.ID_EFI_BOOT # determine current location of bootloader current_location = 'unknown' try: root_fs = util.TempMount(restore_partition, 'root-', options=['ro'], boot_device=boot_device) try: boot_config = bootloader.Bootloader.loadExisting( root_fs.mount_point) current_location = boot_config.location xelogging.log("Bootloader currently in %s" % current_location) finally: root_fs.unmount() except: pass # mount the backup fs backup_fs = util.TempMount(backup_partition, 'restore-backup-', options=['ro']) try: # extract the bootloader config boot_config = bootloader.Bootloader.loadExisting(backup_fs.mount_point) if boot_config.src_fmt == 'grub': raise RuntimeError, "Backup uses grub bootloader which is no longer supported - " + \ "to restore please use a version of the installer that matches the backup partition" # format the restore partition(s): if util.runCmd2(['mkfs.%s' % constants.rootfs_type, restore_partition ]) != 0: raise RuntimeError, "Failed to create root filesystem" if efi_boot: if util.runCmd2(['mkfs.vfat', boot_device]) != 0: raise RuntimeError, "Failed to create boot filesystem" # mount restore partition: dest_fs = util.TempMount(restore_partition, 'restore-dest-') try: # copy files from the backup partition to the restore partition: objs = filter( lambda x: x not in ['lost+found', '.xen-backup-partition', '.xen-gpt.bin'], os.listdir(backup_fs.mount_point)) for i in range(len(objs)): obj = objs[i] xelogging.log("Restoring subtree %s..." % obj) progress((i * 100) / len(objs)) # Use 'cp' here because Python's copying tools are useless and # get stuck in an infinite loop when copying e.g. /dev/null. if util.runCmd2([ 'cp', '-a', os.path.join(backup_fs.mount_point, obj), dest_fs.mount_point ]) != 0: raise RuntimeError, "Failed to restore %s directory" % obj xelogging.log( "Data restoration complete. About to re-install bootloader.") location = boot_config.location m = re.search(r'root=LABEL=(\S+)', boot_config.menu[boot_config.default].kernel_args) if m: label = m.group(1) if location == constants.BOOT_LOCATION_PARTITION and current_location == constants.BOOT_LOCATION_MBR: # if bootloader in the MBR it's probably not safe to restore with it # on the partition xelogging.log( "Bootloader is currently installed to MBR, restoring to MBR instead of partition" ) location = constants.BOOT_LOCATION_MBR with open(os.path.join(backup_fs.mount_point, 'etc', 'fstab'), 'r') as fstab: for line in fstab: m = re.match(r'LABEL=(\S+)\s+/boot/efi\s', line) if m: bootlabel = m.group(1) mounts = { 'root': dest_fs.mount_point, 'boot': os.path.join(dest_fs.mount_point, 'boot') } # prepare extra mounts for installing bootloader: util.bindMount("/dev", "%s/dev" % dest_fs.mount_point) util.bindMount("/sys", "%s/sys" % dest_fs.mount_point) util.bindMount("/proc", "%s/proc" % dest_fs.mount_point) if boot_config.src_fmt == 'grub2': if efi_boot: branding = util.readKeyValueFile( os.path.join(backup_fs.mount_point, constants.INVENTORY_FILE)) branding['product-brand'] = branding['PRODUCT_BRAND'] backend.setEfiBootEntry(mounts, disk, boot_partnum, branding) else: if location == constants.BOOT_LOCATION_MBR: backend.installGrub2(mounts, disk, False) else: backend.installGrub2(mounts, restore_partition, True) else: backend.installExtLinux(mounts, disk, probePartitioningScheme(disk), location) # restore bootloader configuration dst_file = boot_config.src_file.replace(backup_fs.mount_point, dest_fs.mount_point, 1) util.assertDir(os.path.dirname(dst_file)) boot_config.commit(dst_file) finally: util.umount("%s/proc" % dest_fs.mount_point) util.umount("%s/sys" % dest_fs.mount_point) util.umount("%s/dev" % dest_fs.mount_point) dest_fs.unmount() finally: backup_fs.unmount() if not label: raise RuntimeError, "Failed to find label required for root filesystem." if efi_boot and not bootlabel: raise RuntimeError( "Failed to find label required for boot filesystem.") if util.runCmd2(['e2label', restore_partition, label]) != 0: raise RuntimeError, "Failed to label root partition" if bootlabel: if util.runCmd2(['fatlabel', boot_device, bootlabel]) != 0: raise RuntimeError, "Failed to label boot partition" if has_logs_partition: if not backup_partition_layout: # From 7.x (new layout) to 6.x # Delete backup, dom0, Boot and swap partitions tool.deletePartition(backup_partnum) tool.deletePartition(primary_partnum) tool.deletePartition(boot_partnum) tool.deletePartition(swap_partnum) # Rename logs partition to be n.1 tool.renamePartition(srcNumber=logs_partnum, destNumber=primary_partnum, overwrite=False) # Create 4GB backup partition tool.createPartition( tool.ID_LINUX, sizeBytes=constants.backup_size_old * 2**20, startBytes=tool.partitionEnd(primary_partnum) + tool.sectorSize, number=backup_partnum) # Commit partition table and mark dom0 disk as bootable tool.commit(log=True) tool.commitActivePartitiontoDisk(primary_partnum) xelogging.log("Bootloader restoration complete.") xelogging.log("Restore successful.") backend.writeLog(disk, primary_partnum, logs_partnum) elif 'LOG' in backup_partition_layout: # From 7.x (new layout) to 7.x (new layout) tool.commitActivePartitiontoDisk(boot_partnum) rdm_label = label.split("-")[1] logs_part = partitionDevice(disk, logs_partnum) swap_part = partitionDevice(disk, swap_partnum) if util.runCmd2([ 'e2label', logs_part, constants.logsfs_label % rdm_label ]) != 0: raise RuntimeError, "Failed to label logs partition" if util.runCmd2([ 'swaplabel', '-L', constants.swap_label % rdm_label, swap_part ]) != 0: raise RuntimeError, "Failed to label swap partition"
def _readSettings(self): """ Read settings from the installation, returns a results dictionary. """ results = {'host-config': {}} self.mount_state() try: # timezone: tz = None clock_file = self.join_state_path('etc/localtime') if os.path.islink(clock_file): tzfile = os.path.realpath(clock_file) if '/usr/share/zoneinfo/' in tzfile: _, tz = tzfile.split('/usr/share/zoneinfo/', 1) if not tz: # No timezone found: # Supply a default and for interactive installs prompt the user. xelogging.log('No timezone configuration found.') results['request-timezone'] = True tz = "Europe/London" results['timezone'] = tz # hostname. We will assume one was set anyway and thus write # it back into the new filesystem. If one wasn't set then this # will be localhost.localdomain, in which case the old behaviour # will persist anyway: fd = open(self.join_state_path('etc/sysconfig/network'), 'r') lines = fd.readlines() fd.close() for line in lines: if line.startswith('HOSTNAME='): results['manual-hostname'] = (True, line[9:].strip()) if os.path.exists(self.join_state_path('etc/hostname')): fd = open(self.join_state_path('etc/hostname'), 'r') line = fd.readline() results['manual-hostname'] = (True, line.strip()) fd.close() if not results.has_key('manual-hostname'): results['manual-hostname'] = (False, None) # nameservers: domain = None if not os.path.exists(self.join_state_path('etc/resolv.conf')): results['manual-nameservers'] = (False, None) else: ns = [] fd = open(self.join_state_path('etc/resolv.conf'), 'r') lines = fd.readlines() fd.close() for line in lines: if line.startswith("nameserver "): ns.append(line[11:].strip()) elif line.startswith("domain "): domain = line[8:].strip() elif line.startswith("search "): domain = line.split()[1] results['manual-nameservers'] = (True, ns) # ntp servers: fd = open(self.join_state_path('etc/ntp.conf'), 'r') lines = fd.readlines() fd.close() ntps = [] for line in lines: if line.startswith("server "): ntps.append(line[7:].strip()) results['ntp-servers'] = ntps # keyboard: keyboard_dict = {} keyboard_file = self.join_state_path('etc/sysconfig/keyboard') if os.path.exists(keyboard_file): keyboard_dict = util.readKeyValueFile(keyboard_file) keyboard_file = self.join_state_path('etc/vconsole.conf') if os.path.exists(keyboard_file): keyboard_dict.update(util.readKeyValueFile(keyboard_file)) if 'KEYMAP' in keyboard_dict: results['keymap'] = keyboard_dict['KEYMAP'] elif 'KEYTABLE' in keyboard_dict: results['keymap'] = keyboard_dict['KEYTABLE'] # Do not error here if no keymap configuration is found. # This enables upgrade to still carry state on hosts without # keymap configured: # A default keymap is assigned in the backend of this installer. if not results.has_key('keymap'): xelogging.log('No existing keymap configuration found.') # root password: fd = open(self.join_state_path('etc/passwd'), 'r') root_pwd = None for line in fd: pwent = line.split(':') if pwent[0] == 'root': root_pwd = pwent[1] break fd.close() if len(root_pwd) == 1: root_pwd = None try: fd = open(self.join_state_path('etc/shadow'), 'r') for line in fd: pwent = line.split(':') if pwent[0] == 'root': root_pwd = pwent[1] break fd.close() except: pass if not root_pwd: raise SettingsNotAvailable, "no root password found" results['root-password'] = ('pwdhash', root_pwd) # don't care about this too much. results['time-config-method'] = 'ntp' # read network configuration. We only care to find out what the # management interface is, and what its configuration was. # The dev -> MAC mapping for other devices will be preserved in the # database which is available in time for everything except the # management interface. mgmt_iface = self.getInventoryValue('MANAGEMENT_INTERFACE') networkdb_path = constants.NETWORK_DB if not os.path.exists(self.join_state_path(networkdb_path)): networkdb_path = constants.OLD_NETWORK_DB dbcache_path = constants.DBCACHE if not os.path.exists(self.join_state_path(dbcache_path)): dbcache_path = constants.OLD_DBCACHE if not mgmt_iface: xelogging.log('No existing management interface found.') elif os.path.exists(self.join_state_path(networkdb_path)): networkd_db = constants.NETWORKD_DB if not os.path.exists(self.join_state_path(networkd_db)): networkd_db = constants.OLD_NETWORKD_DB xelogging.log( 'Checking %s for management interface configuration' % networkd_db) def fetchIfaceInfoFromNetworkdbAsDict(bridge, iface=None): args = [ 'chroot', self.state_fs.mount_point, '/' + networkd_db, '-bridge', bridge ] if iface: args.extend(['-iface', iface]) rv, out = util.runCmd2(args, with_stdout=True) d = {} for line in (x.strip() for x in out.split('\n') if len(x.strip())): for key_value in line.split(" "): var = key_value.split('=', 1) d[var[0]] = var[1] return d d = fetchIfaceInfoFromNetworkdbAsDict(mgmt_iface, mgmt_iface) # For mgmt on tagged vlan, networkdb output has no value for # 'interfaces' but instead has 'parent' specified. We need # to fetch 'interfaces' of parent and use for mgmt bridge. if not d.get('interfaces') and 'parent' in d: p = fetchIfaceInfoFromNetworkdbAsDict(d['parent']) d['interfaces'] = p['interfaces'] results['net-admin-bridge'] = mgmt_iface results['net-admin-interface'] = d.get('interfaces').split( ',')[0] if_hwaddr = netutil.getHWAddr(results['net-admin-interface']) vlan = int(d['vlan']) if 'vlan' in d else None proto = d.get('mode') if proto == 'static': ip = d.get('ipaddr') netmask = d.get('netmask') gateway = d.get('gateway') dns = d.get('dns', '').split(',') if ip and netmask: results['net-admin-configuration'] = NetInterface( NetInterface.Static, if_hwaddr, ip, netmask, gateway, dns, vlan=vlan) elif proto == 'dhcp': results['net-admin-configuration'] = NetInterface( NetInterface.DHCP, if_hwaddr, vlan=vlan) else: results['net-admin-configuration'] = NetInterface( None, if_hwaddr, vlan=vlan) protov6 = d.get('modev6') if protov6 == 'static': ipv6 = d.get('ipaddrv6') gatewayv6 = d.get('gatewayv6') if ipv6: results['net-admin-configuration'].addIPv6( NetInterface.Static, ipv6, gatewayv6) elif protov6 == 'dhcp': results['net-admin-configuration'].addIPv6( NetInterface.DHCP) elif protov6 == 'autoconf': results['net-admin-configuration'].addIPv6( NetInterface.Autoconf) elif os.path.exists(self.join_state_path(dbcache_path)): xelogging.log( 'Checking %s for management network configuration' % dbcache_path) def getText(nodelist): rc = "" for node in nodelist: if node.nodeType == node.TEXT_NODE: rc = rc + node.data return rc.strip().encode() xmldoc = xml.dom.minidom.parse( self.join_state_path(dbcache_path)) pif_uid = None for node in xmldoc.documentElement.childNodes: if node.nodeType == node.ELEMENT_NODE and node.tagName == 'network': network = node else: continue # CA-50971: handle renamed networks in MNR if len(network.getElementsByTagName('bridge')) == 0 or \ len(network.getElementsByTagName('PIFs')) == 0 or \ len(network.getElementsByTagName('PIFs')[0].getElementsByTagName('PIF')) == 0: continue if getText( network.getElementsByTagName('bridge') [0].childNodes) == mgmt_iface: pif_uid = getText( network.getElementsByTagName('PIFs') [0].getElementsByTagName('PIF')[0].childNodes) break if pif_uid: for node in xmldoc.documentElement.childNodes: if node.nodeType == node.ELEMENT_NODE and node.tagName == 'pif': pif = node else: continue if pif.getAttribute('ref') == pif_uid: results['net-admin-interface'] = getText( pif.getElementsByTagName('device') [0].childNodes) results['net-admin-bridge'] = mgmt_iface results[ 'net-admin-configuration'] = NetInterface.loadFromPif( pif) break else: xelogging.log( 'Checking ifcfg files for management network configuration' ) for cfile in filter(lambda x: True in [x.startswith(y) for y in ['ifcfg-eth', 'ifcfg-bond']], \ os.listdir(self.join_state_path(constants.NET_SCR_DIR))): devcfg = util.readKeyValueFile(self.join_state_path( constants.NET_SCR_DIR, cfile), strip_quotes=False) if devcfg.has_key('DEVICE') and devcfg.has_key( 'BRIDGE') and devcfg['BRIDGE'] == mgmt_iface: brcfg = util.readKeyValueFile(self.join_state_path( constants.NET_SCR_DIR, 'ifcfg-' + devcfg['BRIDGE']), strip_quotes=False) results['net-admin-interface'] = devcfg['DEVICE'] results['net-admin-bridge'] = devcfg['BRIDGE'] # get hardware address if it was recorded, otherwise look it up: if devcfg.has_key('HWADDR'): hwaddr = devcfg['HWADDR'] elif devcfg.has_key('MACADDR'): # our bonds have a key called MACADDR instead hwaddr = devcfg['MACADDR'] else: hwaddr = netutil.getHWAddr(devcfg['DEVICE']) ifcfg = NetInterface.loadFromIfcfg( self.join_state_path(constants.NET_SCR_DIR, 'ifcfg-' + devcfg['BRIDGE'])) if not ifcfg.hwaddr: ifcfg.hwaddr = hwaddr if ifcfg.isStatic() and not ifcfg.domain and domain: ifcfg.domain = domain results['net-admin-configuration'] = ifcfg break repo_list = [] if os.path.exists( self.join_state_path(constants.INSTALLED_REPOS_DIR)): try: for repo_id in os.listdir( self.join_state_path( constants.INSTALLED_REPOS_DIR)): try: repo = repository.LegacyRepository( repository.FilesystemAccessor( self.join_state_path( constants.INSTALLED_REPOS_DIR, repo_id))) if repo.hidden() != "true": repo_list.append( (repo.identifier(), repo.name(), (repo_id != constants.MAIN_REPOSITORY_NAME))) except repository.RepoFormatError: # probably pre-XML format repo = open( self.join_state_path( constants.INSTALLED_REPOS_DIR, repo_id, repository.LegacyRepository. REPOSITORY_FILENAME)) repo_id = repo.readline().strip() repo_name = repo.readline().strip() repo.close() repo_list.append( (repo_id, repo_name, (repo_id != constants.MAIN_REPOSITORY_NAME))) except Exception, e: xelogging.log('Scan for driver disks failed:') xelogging.log_exception(e) results['repo-list'] = repo_list results['ha-armed'] = False try: db_path = "var/lib/xcp/local.db" if not os.path.exists(self.join_state_path(db_path)): db_path = "var/xapi/local.db" db = open(self.join_state_path(db_path), 'r') if db.readline().find( '<row key="ha.armed" value="true"') != -1: results['ha-armed'] = True db.close() except: pass try: network_conf = open( self.join_state_path("etc/xensource/network.conf"), 'r') network_backend = network_conf.readline().strip() network_conf.close() if network_backend == constants.NETWORK_BACKEND_BRIDGE: results[ 'network-backend'] = constants.NETWORK_BACKEND_BRIDGE elif network_backend in [ constants.NETWORK_BACKEND_VSWITCH, constants.NETWORK_BACKEND_VSWITCH_ALT ]: results[ 'network-backend'] = constants.NETWORK_BACKEND_VSWITCH else: raise SettingsNotAvailable, "unknown network backend %s" % network_backend except: pass results['master'] = None try: pt = open(self.join_state_path("etc/xensource/ptoken"), 'r') results['pool-token'] = pt.readline().strip() pt.close() pc = open(self.join_state_path("etc/xensource/pool.conf"), 'r') line = pc.readline().strip() if line.startswith('slave:'): results['master'] = line[6:] pc.close() except: pass
def _readSettings(self): """ Read settings from the installation, returns a results dictionary. """ results = {'host-config': {}} self.mount_state() try: # timezone: tz = None clock_file = self.join_state_path('etc/localtime') if os.path.islink(clock_file): tzfile = os.path.realpath(clock_file) if '/usr/share/zoneinfo/' in tzfile: _, tz = tzfile.split('/usr/share/zoneinfo/', 1) if not tz: # No timezone found: # Supply a default and for interactive installs prompt the user. logger.log('No timezone configuration found.') results['request-timezone'] = True tz = "Europe/London" results['timezone'] = tz # hostname. We will assume one was set anyway and thus write # it back into the new filesystem. If one wasn't set then this # will be localhost.localdomain, in which case the old behaviour # will persist anyway: fd = open(self.join_state_path('etc/sysconfig/network'), 'r') lines = fd.readlines() fd.close() for line in lines: if line.startswith('HOSTNAME='): results['manual-hostname'] = (True, line[9:].strip()) if os.path.exists(self.join_state_path('etc/hostname')): fd = open(self.join_state_path('etc/hostname'), 'r') line = fd.readline() results['manual-hostname'] = (True, line.strip()) fd.close() if 'manual-hostname' not in results: results['manual-hostname'] = (False, None) # nameservers: domain = None if not os.path.exists(self.join_state_path('etc/resolv.conf')): results['manual-nameservers'] = (False, None) else: ns = [] fd = open(self.join_state_path('etc/resolv.conf'), 'r') lines = fd.readlines() fd.close() for line in lines: if line.startswith("nameserver "): ns.append(line[11:].strip()) elif line.startswith("domain "): domain = line[8:].strip() elif line.startswith("search "): domain = line.split()[1] results['manual-nameservers'] = (True, ns) # ntp servers: if os.path.exists(self.join_state_path('etc/chrony.conf')): fd = open(self.join_state_path('etc/chrony.conf'), 'r') else: fd = open(self.join_state_path('etc/ntp.conf'), 'r') lines = fd.readlines() fd.close() ntps = [] for line in lines: if line.startswith("server "): ntps.append(line[7:].split()[0].strip()) results['ntp-servers'] = ntps # keyboard: keyboard_dict = {} keyboard_file = self.join_state_path('etc/sysconfig/keyboard') if os.path.exists(keyboard_file): keyboard_dict = util.readKeyValueFile(keyboard_file) keyboard_file = self.join_state_path('etc/vconsole.conf') if os.path.exists(keyboard_file): keyboard_dict.update(util.readKeyValueFile(keyboard_file)) if 'KEYMAP' in keyboard_dict: results['keymap'] = keyboard_dict['KEYMAP'] elif 'KEYTABLE' in keyboard_dict: results['keymap'] = keyboard_dict['KEYTABLE'] # Do not error here if no keymap configuration is found. # This enables upgrade to still carry state on hosts without # keymap configured: # A default keymap is assigned in the backend of this installer. if 'keymap' not in results: logger.log('No existing keymap configuration found.') # root password: fd = open(self.join_state_path('etc/passwd'), 'r') root_pwd = None for line in fd: pwent = line.split(':') if pwent[0] == 'root': root_pwd = pwent[1] break fd.close() if len(root_pwd) == 1: root_pwd = None try: fd = open(self.join_state_path('etc/shadow'), 'r') for line in fd: pwent = line.split(':') if pwent[0] == 'root': root_pwd = pwent[1] break fd.close() except: pass if not root_pwd: raise SettingsNotAvailable("no root password found") results['root-password'] = ('pwdhash', root_pwd) # don't care about this too much. results['time-config-method'] = 'ntp' # read network configuration. We only care to find out what the # management interface is, and what its configuration was. # The dev -> MAC mapping for other devices will be preserved in the # database which is available in time for everything except the # management interface. mgmt_iface = self.getInventoryValue('MANAGEMENT_INTERFACE') if not mgmt_iface: logger.log('No existing management interface found.') elif os.path.exists(self.join_state_path(constants.NETWORK_DB)): logger.log( 'Checking %s for management interface configuration' % constants.NETWORKD_DB) def fetchIfaceInfoFromNetworkdbAsDict(bridge, iface=None): args = [ 'chroot', self.state_fs.mount_point, '/' + constants.NETWORKD_DB, '-bridge', bridge ] if iface: args.extend(['-iface', iface]) rv, out = util.runCmd2(args, with_stdout=True) d = {} for line in (x.strip() for x in out.split('\n') if len(x.strip())): for key_value in line.split(" "): var = key_value.split('=', 1) d[var[0]] = var[1] return d d = fetchIfaceInfoFromNetworkdbAsDict(mgmt_iface, mgmt_iface) # For mgmt on tagged vlan, networkdb output has no value for # 'interfaces' but instead has 'parent' specified. We need # to fetch 'interfaces' of parent and use for mgmt bridge. if not d.get('interfaces') and 'parent' in d: p = fetchIfaceInfoFromNetworkdbAsDict(d['parent']) d['interfaces'] = p['interfaces'] results['net-admin-bridge'] = mgmt_iface results['net-admin-interface'] = d.get('interfaces').split( ',')[0] if_hwaddr = netutil.getHWAddr(results['net-admin-interface']) vlan = int(d['vlan']) if 'vlan' in d else None proto = d.get('mode') if proto == 'static': ip = d.get('ipaddr') netmask = d.get('netmask') gateway = d.get('gateway') dns = d.get('dns', '').split(',') if ip and netmask: results['net-admin-configuration'] = NetInterface( NetInterface.Static, if_hwaddr, ip, netmask, gateway, dns, vlan=vlan) elif proto == 'dhcp': results['net-admin-configuration'] = NetInterface( NetInterface.DHCP, if_hwaddr, vlan=vlan) else: results['net-admin-configuration'] = NetInterface( None, if_hwaddr, vlan=vlan) protov6 = d.get('modev6') if protov6 == 'static': ipv6 = d.get('ipaddrv6') gatewayv6 = d.get('gatewayv6') if ipv6: results['net-admin-configuration'].addIPv6( NetInterface.Static, ipv6, gatewayv6) elif protov6 == 'dhcp': results['net-admin-configuration'].addIPv6( NetInterface.DHCP) elif protov6 == 'autoconf': results['net-admin-configuration'].addIPv6( NetInterface.Autoconf) repo_list = [] if os.path.exists( self.join_state_path(constants.INSTALLED_REPOS_DIR)): try: for repo_id in os.listdir( self.join_state_path( constants.INSTALLED_REPOS_DIR)): try: repo = repository.LegacyRepository( repository.FilesystemAccessor( self.join_state_path( constants.INSTALLED_REPOS_DIR, repo_id))) if repo.hidden() != "true": repo_list.append( (repo.identifier(), repo.name(), (repo_id != constants.MAIN_REPOSITORY_NAME))) except repository.RepoFormatError: # probably pre-XML format repo = open( self.join_state_path( constants.INSTALLED_REPOS_DIR, repo_id, repository.LegacyRepository. REPOSITORY_FILENAME)) repo_id = repo.readline().strip() repo_name = repo.readline().strip() repo.close() repo_list.append( (repo_id, repo_name, (repo_id != constants.MAIN_REPOSITORY_NAME))) except Exception as e: logger.log('Scan for driver disks failed:') logger.logException(e) results['repo-list'] = repo_list results['ha-armed'] = False try: db_path = "var/lib/xcp/local.db" if not os.path.exists(self.join_state_path(db_path)): db_path = "var/xapi/local.db" db = open(self.join_state_path(db_path), 'r') if db.readline().find( '<row key="ha.armed" value="true"') != -1: results['ha-armed'] = True db.close() except: pass try: network_conf = open( self.join_state_path("etc/xensource/network.conf"), 'r') network_backend = network_conf.readline().strip() network_conf.close() if network_backend == constants.NETWORK_BACKEND_BRIDGE: results[ 'network-backend'] = constants.NETWORK_BACKEND_BRIDGE elif network_backend in [ constants.NETWORK_BACKEND_VSWITCH, constants.NETWORK_BACKEND_VSWITCH_ALT ]: results[ 'network-backend'] = constants.NETWORK_BACKEND_VSWITCH else: raise SettingsNotAvailable("unknown network backend %s" % network_backend) except: pass results['master'] = None try: pt = open(self.join_state_path("etc/xensource/ptoken"), 'r') results['pool-token'] = pt.readline().strip() pt.close() pc = open(self.join_state_path("etc/xensource/pool.conf"), 'r') line = pc.readline().strip() if line.startswith('slave:'): results['master'] = line[6:] pc.close() except: pass finally: self.unmount_state() # read bootloader config to extract various settings try: # Boot device self.mount_boot() boot_config = bootloader.Bootloader.loadExisting( self.boot_fs_mount) # Serial console try: xen_args = boot_config.menu['xe-serial'].getHypervisorArgs() com = [i for i in xen_args if re.match('com[0-9]+=.*', i)] results['serial-console'] = hardware.SerialPort.from_string( com[0]) except Exception: logger.log("Could not parse serial settings") if boot_config.serial: results['serial-console'] = hardware.SerialPort( boot_config.serial['port'], baud=str(boot_config.serial['baud'])) results['bootloader-location'] = boot_config.location if boot_config.default != 'upgrade': results['boot-serial'] = (boot_config.default == 'xe-serial') # Subset of hypervisor arguments xen_args = boot_config.menu[ boot_config.default].getHypervisorArgs() # - cpuid_mask results['host-config']['xen-cpuid-masks'] = filter( lambda x: x.startswith('cpuid_mask'), xen_args) # - dom0_mem dom0_mem_arg = filter(lambda x: x.startswith('dom0_mem'), xen_args) (dom0_mem, dom0_mem_min, dom0_mem_max) = xcp.dom0.parse_mem(dom0_mem_arg[0]) if dom0_mem: results['host-config']['dom0-mem'] = dom0_mem / 1024 / 1024 except: pass self.unmount_boot() return results
def restoreWithoutRepartButUEFI(backup, progress): backup_partition = backup.partition disk = backup.root_disk assert backup_partition.startswith('/dev/') assert disk.startswith('/dev/') # Restore the partition layout backup_fs = util.TempMount(backup_partition, 'restore-backup-', options=['ro']) gpt_bin = None try: src_bin = os.path.join(backup_fs.mount_point, '.xen-gpt.bin') if os.path.exists(src_bin): gpt_bin = tempfile.mktemp() shutil.copyfile(src_bin, gpt_bin) finally: backup_fs.unmount() if gpt_bin: xelogging.log("Restoring partition layout") rc, err = util.runCmd2(["sgdisk", "-l", gpt_bin, disk], with_stderr=True) if rc != 0: raise RuntimeError, "Failed to restore partition layout: %s" % err label = None bootlabel = None _, boot_partnum, primary_partnum, backup_partnum, logs_partnum, swap_partnum, _ = backend.inspectTargetDisk( disk, None, [], constants.PRESERVE_IF_UTILITY, True, True) restore_partition = partitionDevice(disk, primary_partnum) xelogging.log("Restoring to partition %s." % restore_partition) tool = PartitionTool(disk) boot_part = tool.getPartition(boot_partnum) boot_device = partitionDevice(disk, boot_partnum) if boot_part else None efi_boot = boot_part and boot_part['id'] == GPTPartitionTool.ID_EFI_BOOT # determine current location of bootloader current_location = 'unknown' try: root_fs = util.TempMount(restore_partition, 'root-', options=['ro'], boot_device=boot_device) try: boot_config = bootloader.Bootloader.loadExisting( root_fs.mount_point) current_location = boot_config.location xelogging.log("Bootloader currently in %s" % current_location) finally: root_fs.unmount() except: pass # mount the backup fs backup_fs = util.TempMount(backup_partition, 'restore-backup-', options=['ro']) try: # extract the bootloader config boot_config = bootloader.Bootloader.loadExisting(backup_fs.mount_point) if boot_config.src_fmt == 'grub': raise RuntimeError, "Backup uses grub bootloader which is no longer supported - " + \ "to restore please use a version of the installer that matches the backup partition" # format the restore partition(s): if util.runCmd2(['mkfs.%s' % constants.rootfs_type, restore_partition ]) != 0: raise RuntimeError, "Failed to create root filesystem" if efi_boot: if util.runCmd2(['mkfs.vfat', boot_device]) != 0: raise RuntimeError, "Failed to create boot filesystem" # mount restore partition: dest_fs = util.TempMount(restore_partition, 'restore-dest-', boot_device=boot_device, boot_mount_point='/boot/efi') try: # copy files from the backup partition to the restore partition: objs = filter( lambda x: x not in ['lost+found', '.xen-backup-partition', '.xen-gpt.bin'], os.listdir(backup_fs.mount_point)) for i in range(len(objs)): obj = objs[i] xelogging.log("Restoring subtree %s..." % obj) progress((i * 100) / len(objs)) # Use 'cp' here because Python's copying tools are useless and # get stuck in an infinite loop when copying e.g. /dev/null. if util.runCmd2([ 'cp', '-a', os.path.join(backup_fs.mount_point, obj), dest_fs.mount_point ]) != 0: raise RuntimeError, "Failed to restore %s directory" % obj xelogging.log( "Data restoration complete. About to re-install bootloader.") location = boot_config.location m = re.search(r'root=LABEL=(\S+)', boot_config.menu[boot_config.default].kernel_args) if m: label = m.group(1) if location == constants.BOOT_LOCATION_PARTITION and current_location == constants.BOOT_LOCATION_MBR: # if bootloader in the MBR it's probably not safe to restore with it # on the partition xelogging.log( "Bootloader is currently installed to MBR, restoring to MBR instead of partition" ) location = constants.BOOT_LOCATION_MBR with open(os.path.join(backup_fs.mount_point, 'etc', 'fstab'), 'r') as fstab: for line in fstab: m = re.match(r'LABEL=(\S+)\s+/boot/efi\s', line) if m: bootlabel = m.group(1) mounts = { 'root': dest_fs.mount_point, 'boot': os.path.join(dest_fs.mount_point, 'boot') } # prepare extra mounts for installing bootloader: util.bindMount("/dev", "%s/dev" % dest_fs.mount_point) util.bindMount("/sys", "%s/sys" % dest_fs.mount_point) util.bindMount("/proc", "%s/proc" % dest_fs.mount_point) if boot_config.src_fmt == 'grub2': if efi_boot: branding = util.readKeyValueFile( os.path.join(backup_fs.mount_point, constants.INVENTORY_FILE)) branding['product-brand'] = branding['PRODUCT_BRAND'] backend.setEfiBootEntry(mounts, disk, boot_partnum, branding) else: if location == constants.BOOT_LOCATION_MBR: backend.installGrub2(mounts, disk, False) else: backend.installGrub2(mounts, restore_partition, True) else: backend.installExtLinux(mounts, disk, probePartitioningScheme(disk), location) # restore bootloader configuration dst_file = boot_config.src_file.replace(backup_fs.mount_point, dest_fs.mount_point, 1) util.assertDir(os.path.dirname(dst_file)) boot_config.commit(dst_file) finally: util.umount("%s/proc" % dest_fs.mount_point) util.umount("%s/sys" % dest_fs.mount_point) util.umount("%s/dev" % dest_fs.mount_point) dest_fs.unmount() finally: backup_fs.unmount() if not label: raise RuntimeError, "Failed to find label required for root filesystem." if efi_boot and not bootlabel: raise RuntimeError( "Failed to find label required for boot filesystem.") if util.runCmd2(['e2label', restore_partition, label]) != 0: raise RuntimeError, "Failed to label root partition" if bootlabel: if util.runCmd2(['fatlabel', boot_device, bootlabel]) != 0: raise RuntimeError, "Failed to label boot partition" xelogging.log("Bootloader restoration complete.") xelogging.log("Restore successful.") backend.writeLog(disk, primary_partnum, logs_partnum)
def _readSettings(self): """ Read settings from the installation, returns a results dictionary. """ results = {} if self.version < XENSERVER_5_6_0: raise SettingsNotAvailable, "version too old" self.mount_state() try: # timezone: tz = None clock_file = self.join_state_path("etc/sysconfig/clock") if os.path.exists(clock_file): fd = open(clock_file, "r") lines = fd.readlines() fd.close() for line in lines: if line.startswith("ZONE="): tz = line[5:].strip() if not tz: # No timezone found: # Supply a default and for interactive installs prompt the user. xelogging.log("No timezone configuration found.") results["request-timezone"] = True tz = "Europe/London" results["timezone"] = tz # hostname. We will assume one was set anyway and thus write # it back into the new filesystem. If one wasn't set then this # will be localhost.localdomain, in which case the old behaviour # will persist anyway: fd = open(self.join_state_path("etc/sysconfig/network"), "r") lines = fd.readlines() fd.close() for line in lines: if line.startswith("HOSTNAME="): results["manual-hostname"] = (True, line[9:].strip()) if not results.has_key("manual-hostname"): results["manual-hostname"] = (False, None) # nameservers: domain = None if not os.path.exists(self.join_state_path("etc/resolv.conf")): results["manual-nameservers"] = (False, None) else: ns = [] fd = open(self.join_state_path("etc/resolv.conf"), "r") lines = fd.readlines() fd.close() for line in lines: if line.startswith("nameserver "): ns.append(line[11:].strip()) elif line.startswith("domain "): domain = line[8:].strip() elif line.startswith("search "): domain = line.split()[1] results["manual-nameservers"] = (True, ns) # ntp servers: fd = open(self.join_state_path("etc/ntp.conf"), "r") lines = fd.readlines() fd.close() ntps = [] for line in lines: if line.startswith("server "): ntps.append(line[7:].strip()) results["ntp-servers"] = ntps # keyboard: keyboard_file = self.join_state_path("etc/sysconfig/keyboard") if os.path.exists(keyboard_file): fd = open(keyboard_file, "r") lines = fd.readlines() fd.close() for line in lines: if line.startswith("KEYTABLE="): results["keymap"] = line[9:].strip() # Do not error here if no keymap configuration is found. # This enables upgrade to still carry state on hosts without # keymap configured: # A default keymap is assigned in the backend of this installer. if not results.has_key("keymap"): xelogging.log("No existing keymap configuration found.") # root password: fd = open(self.join_state_path("etc/passwd"), "r") root_pwd = None for line in fd: pwent = line.split(":") if pwent[0] == "root": root_pwd = pwent[1] break fd.close() if not root_pwd: raise SettingsNotAvailable, "no root password found" results["root-password"] = ("pwdhash", root_pwd) # don't care about this too much. results["time-config-method"] = "ntp" # read network configuration. We only care to find out what the # management interface is, and what its configuration was. # The dev -> MAC mapping for other devices will be preserved in the # database which is available in time for everything except the # management interface. mgmt_iface = self.getInventoryValue("MANAGEMENT_INTERFACE") if os.path.exists(self.join_state_path(constants.DBCACHE)): def getText(nodelist): rc = "" for node in nodelist: if node.nodeType == node.TEXT_NODE: rc = rc + node.data return rc.strip().encode() xmldoc = xml.dom.minidom.parse(self.join_state_path(constants.DBCACHE)) pif_uid = None for node in xmldoc.documentElement.childNodes: if node.nodeType == node.ELEMENT_NODE and node.tagName == "network": network = node else: continue # CA-50971: handle renamed networks in MNR if ( len(network.getElementsByTagName("bridge")) == 0 or len(network.getElementsByTagName("PIFs")) == 0 or len(network.getElementsByTagName("PIFs")[0].getElementsByTagName("PIF")) == 0 ): continue if getText(network.getElementsByTagName("bridge")[0].childNodes) == mgmt_iface: pif_uid = getText( network.getElementsByTagName("PIFs")[0].getElementsByTagName("PIF")[0].childNodes ) break if pif_uid: for node in xmldoc.documentElement.childNodes: if node.nodeType == node.ELEMENT_NODE and node.tagName == "pif": pif = node else: continue if pif.getAttribute("ref") == pif_uid: results["net-admin-interface"] = getText(pif.getElementsByTagName("device")[0].childNodes) results["net-admin-bridge"] = mgmt_iface results["net-admin-configuration"] = NetInterface.loadFromPif(pif) break else: for cfile in filter( lambda x: True in [x.startswith(y) for y in ["ifcfg-eth", "ifcfg-bond"]], os.listdir(self.join_state_path(constants.NET_SCR_DIR)), ): devcfg = util.readKeyValueFile( self.join_state_path(constants.NET_SCR_DIR, cfile), strip_quotes=False ) if devcfg.has_key("DEVICE") and devcfg.has_key("BRIDGE") and devcfg["BRIDGE"] == mgmt_iface: brcfg = util.readKeyValueFile( self.join_state_path(constants.NET_SCR_DIR, "ifcfg-" + devcfg["BRIDGE"]), strip_quotes=False ) results["net-admin-interface"] = devcfg["DEVICE"] results["net-admin-bridge"] = devcfg["BRIDGE"] # get hardware address if it was recorded, otherwise look it up: if devcfg.has_key("HWADDR"): hwaddr = devcfg["HWADDR"] elif devcfg.has_key("MACADDR"): # our bonds have a key called MACADDR instead hwaddr = devcfg["MACADDR"] else: # XXX what if it's been renamed out of existence? try: hwaddr = netutil.getHWAddr(devcfg["DEVICE"]) except: hwaddr = None ifcfg = NetInterface.loadFromIfcfg( self.join_state_path(constants.NET_SCR_DIR, "ifcfg-" + devcfg["BRIDGE"]) ) if not ifcfg.hwaddr: ifcfg.hwaddr = hwaddr if ifcfg.isStatic() and not ifcfg.domain and domain: ifcfg.domain = domain results["net-admin-configuration"] = ifcfg break repo_list = [] if os.path.exists(self.join_state_path(constants.INSTALLED_REPOS_DIR)): try: for repo_id in os.listdir(self.join_state_path(constants.INSTALLED_REPOS_DIR)): try: repo = repository.Repository( repository.FilesystemAccessor( self.join_state_path(constants.INSTALLED_REPOS_DIR, repo_id) ) ) repo_list.append( (repo.identifier(), repo.name(), (repo_id != constants.MAIN_REPOSITORY_NAME)) ) except repository.RepoFormatError: # probably pre-XML format repo = open( self.join_state_path( constants.INSTALLED_REPOS_DIR, repo_id, repository.Repository.REPOSITORY_FILENAME ) ) repo_id = repo.readline().strip() repo_name = repo.readline().strip() repo.close() repo_list.append((repo_id, repo_name, (repo_id != constants.MAIN_REPOSITORY_NAME))) except Exception, e: xelogging.log("Scan for driver disks failed:") xelogging.log_exception(e) results["repo-list"] = repo_list results["ha-armed"] = False try: db = open(self.join_state_path("var/xapi/local.db"), "r") if db.readline().find('<row key="ha.armed" value="true"') != -1: results["ha-armed"] = True db.close() except: pass results["master"] = None try: pt = open(self.join_state_path("etc/xensource/ptoken"), "r") results["pool-token"] = pt.readline().strip() pt.close() pc = open(self.join_state_path("etc/xensource/pool.conf"), "r") line = pc.readline().strip() if line.startswith("slave:"): results["master"] = line[6:] pc.close() except: pass
def restoreFromBackup(backup, progress=lambda x: ()): """ Restore files from backup_partition to the root partition on disk. Call progress with a value between 0 and 100. Re-install bootloader. Fails if backup is not same version as the CD in use.""" label = None bootlabel = None disk = backup.root_disk tool = PartitionTool(disk) _, boot_partnum, primary_partnum, backup_partnum, logs_partnum, swap_partnum, _ = backend.inspectTargetDisk( disk, None, [], constants.PRESERVE_IF_UTILITY, True, True) backup_fs = util.TempMount(backup.partition, 'backup-', options=['ro']) inventory = util.readKeyValueFile(os.path.join(backup_fs.mount_point, constants.INVENTORY_FILE), strip_quotes=True) backup_partition_layout = inventory['PARTITION_LAYOUT'].split(',') backup_fs.unmount() xelogging.log("BACKUP DISK PARTITION LAYOUT: %s" % backup_partition_layout) backup_partition = backup.partition assert backup_partition.startswith('/dev/') assert disk.startswith('/dev/') restore_partition = partitionDevice(disk, primary_partnum) xelogging.log("Restoring to partition %s." % restore_partition) boot_part = tool.getPartition(boot_partnum) boot_device = partitionDevice(disk, boot_partnum) if boot_part else None efi_boot = boot_part and boot_part['id'] == GPTPartitionTool.ID_EFI_BOOT # determine current location of bootloader current_location = 'unknown' try: root_fs = util.TempMount(restore_partition, 'root-', options=['ro'], boot_device=boot_device) try: boot_config = bootloader.Bootloader.loadExisting( root_fs.mount_point) current_location = boot_config.location xelogging.log("Bootloader currently in %s" % current_location) finally: root_fs.unmount() except: pass # mount the backup fs backup_fs = util.TempMount(backup_partition, 'restore-backup-', options=['ro']) try: # extract the bootloader config boot_config = bootloader.Bootloader.loadExisting(backup_fs.mount_point) if boot_config.src_fmt == 'grub': raise RuntimeError, "Backup uses grub bootloader which is no longer supported - " + \ "to restore please use a version of the installer that matches the backup partition" # format the restore partition(s): try: util.mkfs(constants.rootfs_type, restore_partition) except Exception as e: raise RuntimeError("Failed to create root filesystem: %s" % e) if efi_boot: try: util.mkfs('vfat', boot_device) except Exception as e: raise RuntimeError("Failed to create boot filesystem: %s" % e) # mount restore partition: dest_fs = util.TempMount(restore_partition, 'restore-dest-') try: # copy files from the backup partition to the restore partition: objs = filter( lambda x: x not in ['lost+found', '.xen-backup-partition', '.xen-gpt.bin'], os.listdir(backup_fs.mount_point)) for i in range(len(objs)): obj = objs[i] xelogging.log("Restoring subtree %s..." % obj) progress((i * 100) / len(objs)) # Use 'cp' here because Python's copying tools are useless and # get stuck in an infinite loop when copying e.g. /dev/null. if util.runCmd2([ 'cp', '-a', os.path.join(backup_fs.mount_point, obj), dest_fs.mount_point ]) != 0: raise RuntimeError, "Failed to restore %s directory" % obj xelogging.log( "Data restoration complete. About to re-install bootloader.") location = boot_config.location m = re.search(r'root=LABEL=(\S+)', boot_config.menu[boot_config.default].kernel_args) if m: label = m.group(1) if location == constants.BOOT_LOCATION_PARTITION and current_location == constants.BOOT_LOCATION_MBR: # if bootloader in the MBR it's probably not safe to restore with it # on the partition xelogging.log( "Bootloader is currently installed to MBR, restoring to MBR instead of partition" ) location = constants.BOOT_LOCATION_MBR with open(os.path.join(backup_fs.mount_point, 'etc', 'fstab'), 'r') as fstab: for line in fstab: m = re.match(r'LABEL=(\S+)\s+/boot/efi\s', line) if m: bootlabel = m.group(1) mounts = { 'root': dest_fs.mount_point, 'boot': os.path.join(dest_fs.mount_point, 'boot') } # prepare extra mounts for installing bootloader: util.bindMount("/dev", "%s/dev" % dest_fs.mount_point) util.bindMount("/sys", "%s/sys" % dest_fs.mount_point) util.bindMount("/proc", "%s/proc" % dest_fs.mount_point) if boot_config.src_fmt == 'grub2': if efi_boot: branding = util.readKeyValueFile( os.path.join(backup_fs.mount_point, constants.INVENTORY_FILE)) branding['product-brand'] = branding['PRODUCT_BRAND'] backend.setEfiBootEntry(mounts, disk, boot_partnum, branding) else: if location == constants.BOOT_LOCATION_MBR: backend.installGrub2(mounts, disk, False) else: backend.installGrub2(mounts, restore_partition, True) else: backend.installExtLinux(mounts, disk, probePartitioningScheme(disk), location) # restore bootloader configuration dst_file = boot_config.src_file.replace(backup_fs.mount_point, dest_fs.mount_point, 1) util.assertDir(os.path.dirname(dst_file)) boot_config.commit(dst_file) finally: util.umount("%s/proc" % dest_fs.mount_point) util.umount("%s/sys" % dest_fs.mount_point) util.umount("%s/dev" % dest_fs.mount_point) dest_fs.unmount() finally: backup_fs.unmount() if not label: raise RuntimeError, "Failed to find label required for root filesystem." if efi_boot and not bootlabel: raise RuntimeError( "Failed to find label required for boot filesystem.") if util.runCmd2(['e2label', restore_partition, label]) != 0: raise RuntimeError, "Failed to label root partition" if bootlabel: if util.runCmd2(['fatlabel', boot_device, bootlabel]) != 0: raise RuntimeError, "Failed to label boot partition" if 'LOG' in backup_partition_layout: # From 7.x (new layout) to 7.x (new layout) tool.commitActivePartitiontoDisk(boot_partnum) rdm_label = label.split("-")[1] logs_part = partitionDevice(disk, logs_partnum) swap_part = partitionDevice(disk, swap_partnum) if util.runCmd2( ['e2label', logs_part, constants.logsfs_label % rdm_label]) != 0: raise RuntimeError, "Failed to label logs partition" if util.runCmd2([ 'swaplabel', '-L', constants.swap_label % rdm_label, swap_part ]) != 0: raise RuntimeError, "Failed to label swap partition"
def completeUpgrade(self, mounts, prev_install, target_disk, backup_partnum, admin_iface, admin_bridge, admin_config): util.assertDir(os.path.join(mounts['root'], "var/lib/xcp")) util.assertDir(os.path.join(mounts['root'], "etc/xensource")) Upgrader.completeUpgrade(self, mounts, target_disk, backup_partnum) v = Version(prev_install.version.ver) f = open(os.path.join(mounts['root'], 'var/tmp/.previousVersion'), 'w') f.write("PLATFORM_VERSION='%s'\n" % v) f.close() state = open( os.path.join(mounts['root'], constants.FIRSTBOOT_DATA_DIR, 'host.conf'), 'w') print >> state, "UPGRADE=true" state.close() # The existence of the static-rules.conf is used to detect upgrade from Boston or newer if os.path.exists( os.path.join( mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf' )): # CA-82901 - convert any old style ppn referenced to new style ppn references util.runCmd2([ 'sed', r's/pci\([0-9]\+p[0-9]\+\)/p\1/g', '-i', os.path.join( mounts['root'], 'etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf' ) ]) net_dict = util.readKeyValueFile( os.path.join(mounts['root'], 'etc/sysconfig/network')) if 'NETWORKING_IPV6' not in net_dict: nfd = open(os.path.join(mounts['root'], 'etc/sysconfig/network'), 'a') nfd.write("NETWORKING_IPV6=no\n") nfd.close() netutil.disable_ipv6_module(mounts["root"]) # handle the conversion of HP Gen6 controllers from cciss to scsi primary_disk = self.source.getInventoryValue("PRIMARY_DISK") target_link = diskutil.idFromPartition(target_disk) or target_disk if 'cciss' in primary_disk and 'scsi' in target_link: util.runCmd2([ 'sed', '-i', '-e', "s#%s#%s#g" % (primary_disk, target_link), os.path.join(mounts['root'], constants.FIRSTBOOT_DATA_DIR, 'default-storage.conf') ]) util.runCmd2([ 'sed', '-i', '-e', "s#%s#%s#g" % (primary_disk, target_link), os.path.join(mounts['root'], constants.XAPI_DB) ]) # handle the conversion of RAID devices from /dev/md_* to /dev/disk/by-id/md-uuid-* if primary_disk.startswith('/dev/md_') and target_link.startswith( '/dev/disk/by-id/md-uuid-'): for i in (os.path.join(constants.FIRSTBOOT_DATA_DIR, 'default-storage.conf'), constants.XAPI_DB): # First convert partitions from *pN to *-partN util.runCmd2([ 'sed', '-i', '-e', "s#\(%s\)p\([[:digit:]]\+\)#\\1-part\\2#g" % primary_disk, os.path.join(mounts['root'], i) ]) # Then conert from /dev/md_* to /dev/disk/by-id/md-uuid-* util.runCmd2([ 'sed', '-i', '-e', "s#%s#%s#g" % (primary_disk, target_link), os.path.join(mounts['root'], i) ]) # handle the conversion of devices from scsi-* links to ata-* links if primary_disk.startswith( '/dev/disk/by-id/scsi-') and target_link.startswith( '/dev/disk/by-id/ata-'): for i in (os.path.join(constants.FIRSTBOOT_DATA_DIR, 'default-storage.conf'), constants.XAPI_DB): util.runCmd2([ 'sed', '-i', '-e', "s#%s#%s#g" % (primary_disk, target_link), os.path.join(mounts['root'], i) ])