def bugtool(inst, dest_url): try: inst.mount_root(ro = False) util.bindMount('/dev', os.path.join(inst.root_fs.mount_point, 'dev')) util.bindMount('/proc', os.path.join(inst.root_fs.mount_point, 'proc')) util.bindMount('/sys', os.path.join(inst.root_fs.mount_point, 'sys')) os.environ['XEN_RT'] = '1' os.environ['XENRT_BUGTOOL_BASENAME'] = 'offline-bugtool' util.runCmd2(['chroot', inst.root_fs.mount_point, '/usr/sbin/xen-bugtool', '-y', '--unlimited']) out_fname = os.path.join(inst.root_fs.mount_point, 'var/opt/xen/bug-report/offline-bugtool.tar.bz2') util.umount(os.path.join(inst.root_fs.mount_point, 'sys')) util.umount(os.path.join(inst.root_fs.mount_point, 'proc')) util.umount(os.path.join(inst.root_fs.mount_point, 'dev')) xcp.logger.log("Saving to " + dest_url) a = xcp.accessor.createAccessor(dest_url, False) a.start() inh = open(out_fname) a.writeFile(inh, 'offline-bugtool.tar.bz2') inh.close() a.finish() os.remove(out_fname) finally: inst.unmount_root()
def restore_file(src_base, f, d=None): if not d: d = f src = os.path.join(src_base, f) dst = os.path.join(mounts['root'], d) if os.path.exists(src): xelogging.log("Restoring /%s" % f) util.assertDir(os.path.dirname(dst)) if os.path.isdir(src): util.runCmd2(['cp', '-a', src, os.path.dirname(dst)]) else: util.runCmd2(['cp', '-a', src, dst]) abs_f = os.path.join('/', f) abs_d = os.path.join('/', d) copy_ownership(src_base, abs_f, mounts['root'], abs_d) for dirpath, dirnames, filenames in os.walk(src): for i in dirnames + filenames: src_path = os.path.join(dirpath, i)[len(src_base):] dst_path = os.path.join(abs_d, src_path[len(abs_f) + 1:]) copy_ownership(src_base, src_path, mounts['root'], dst_path) else: xelogging.log( "WARNING: /%s did not exist in the backup image." % f)
def process_ibft(ui, interactive): """ Bring up any disks that the iBFT should be attached, and reserve the NICs that it says should be used for iSCSI """ if not have_ibft(): return try: iname, target_configs = read_ibft() except: # only raise exception if user decides to proceed if ui and interactive: msg = "Found iSCSI Boot Firmware Table\n\nAttach to disks specified in iBFT?" button = ButtonChoiceWindowEx(ui.screen, "Attach iSCSI disks" , msg, ['Yes', 'No']) if button == 'no': return raise else: # Do nothing if the iBFT contains no valid targets if len(target_configs) == 0: xelogging.log("process_ibft: No valid target configs found in iBFT") return # If interactive, ask user if he wants to proceed if ui and interactive: nics = list(set([ conf.iface for conf in target_configs ])) nics.sort() msg = \ "Found iSCSI Boot Firmware Table\n\nAttach to disks specified in iBFT?\n\n" \ "This will reserve %s for iSCSI disk access. Reserved NICs are not available " \ "for use as the management interface or for use by virtual machines." % " and ".join(nics) button = ButtonChoiceWindowEx(ui.screen, "Attach iSCSI disks" , msg, ['Yes', 'No'], width=60) if button == 'no': return # Bring up the targets for conf in target_configs: # Bring up interface if conf.iface not in ibft_reserved_nics: rv = util.runCmd2(['ifconfig', conf.iface, conf.ip, 'netmask', conf.nm]) assert rv == 0 ibft_reserved_nics.append(conf.iface) xelogging.log("process_ibft: reserving %s for access to iSCSI disk" % conf.iface) # Pin tgtip to this interface if netutil.network(conf.ip, conf.nm) == netutil.network(conf.tgtip, conf.nm): rv = util.runCmd2(['ip', 'route', 'add', conf.tgtip, 'dev', conf.iface]) else: assert conf.gw rv = util.runCmd2(['ip', 'route', 'add', conf.tgtip, 'dev', conf.iface, 'via', conf.gw]) # Attach to target (this creates new nodes /dev) spec = "iscsi:%s::%d:%d:%s" % (conf.tgtip, conf.port, conf.lun, conf.iqn) try: disk = attach_rfc4173(iname, spec) except Exception as e: xelogging.log_exception(e) raise RuntimeError, "Could not attach to iSCSI LUN %s" % spec xelogging.log("process_ibft: attached iSCSI disk %s." % disk)
def modprobe_file(module, remove=True, params="", name=None): INSMOD = "/sbin/insmod" if remove and module_present(module): # Try to remove the module if already loaded rc = util.runCmd2(["rmmod", module]) if rc != 0: raise RuntimeError, "Unable to replace module %s which is already loaded. Please see the documentation for instructions of how to blacklist it." % module # First use modinfo to find out what the dependants of the # module are and modprobe them: # # deps will initially look like 'depends: x,y,z' rc, out = util.runCmd2(["modinfo", module], with_stdout=True) if rc != 0: raise RuntimeError, "Error interrogating module." [deps] = filter(lambda x: x.startswith("depends:"), out.split("\n")) deps = deps[9:].strip() if deps != "": deps = deps.split(",") for dep in deps: if not module_present(dep): modprobe(dep) xelogging.log("Inserting module %s %s (%s)" % (module, params, name)) rc = util.runCmd2([INSMOD, module, params]) if rc != 0: xelogging.log("(Failed.)") return rc
def process_ibft(ui, interactive): """ Bring up any disks that the iBFT should be attached, and reserve the NICs that it says should be used for iSCSI """ if not have_ibft(): return try: iname, target_configs = read_ibft() except: # only raise exception if user decides to proceed if ui and interactive: msg = "Found iSCSI Boot Firmware Table\n\nAttach to disks specified in iBFT?" button = ButtonChoiceWindowEx(ui.screen, "Attach iSCSI disks" , msg, ['Yes', 'No']) if button == 'no': return raise else: # Do nothing if the iBFT contains no valid targets if len(target_configs) == 0: xelogging.log("process_ibft: No valid target configs found in iBFT") return # If interactive, ask user if he wants to proceed if ui and interactive: nics = list(set([ conf.iface for conf in target_configs ])) nics.sort() msg = \ "Found iSCSI Boot Firmware Table\n\nAttach to disks specified in iBFT?\n\n" \ "This will reserve %s for iSCSI disk access. Reserved NICs are not available " \ "for use as the management interface or for use by virtual machines." % " and ".join(nics) button = ButtonChoiceWindowEx(ui.screen, "Attach iSCSI disks" , msg, ['Yes', 'No'], width=60) if button == 'no': return # Bring up the targets for conf in target_configs: # Bring up interface if conf.iface not in ibft_reserved_nics: rv = util.runCmd2(['ifconfig', conf.iface, conf.ip, 'netmask', conf.nm]) assert rv == 0 ibft_reserved_nics.append(conf.iface) xelogging.log("process_ibft: reserving %s for access to iSCSI disk" % conf.iface) # Pin tgtip to this interface if netutil.network(conf.ip, conf.nm) == netutil.network(conf.tgtip, conf.nm): rv = util.runCmd2(['ip', 'route', 'add', conf.tgtip, 'dev', conf.iface]) else: assert conf.gw rv = util.runCmd2(['ip', 'route', 'add', conf.tgtip, 'dev', conf.iface, 'via', conf.gw]) # Attach to target (this creates new nodes /dev) spec = "iscsi:%s::%d:%d:%s" % (conf.tgtip, conf.port, conf.lun, conf.iqn) try: disk = attach_rfc4173(iname, spec) except: raise RuntimeError, "Could not attach to iSCSI LUN %s" % spec xelogging.log("process_ibft: attached iSCSI disk %s." % disk)
def replace_config(config_file, destination): src = os.path.join(backup_fs.mount_point, constants.ROLLING_POOL_DIR, config_file) if os.path.exists(src): util.runCmd2([ 'cp', '-f', src, os.path.join(backup_fs.mount_point, destination) ])
def mpath_part_scan(force = False): global use_mpath if not force and not use_mpath: return 0 ret = createMpathPartnodes() if ret == 0: util.runCmd2(util.udevsettleCmd()) return ret
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 start_lldpad(): util.runCmd2(['/sbin/lldpad', '-d']) # Wait for lldpad to be ready retries = 0 while True: retries += 1 if util.runCmd2(['lldptool', '-p']) == 0: break if retries == 10: raise Exception('Timed out waiting for lldpad to be ready') time.sleep(1)
def restore_file(src_base, f, d = None): if not d: d = f src = os.path.join(src_base, f) dst = os.path.join(mounts['root'], d) if os.path.exists(src): xelogging.log("Restoring /%s" % f) if os.path.isdir(src): util.runCmd2(['cp', '-rp', src, os.path.dirname(dst)]) else: util.assertDir(os.path.dirname(dst)) util.runCmd2(['cp', '-p', src, dst]) else: xelogging.log("WARNING: /%s did not exist in the backup image." % f)
def create_raid(configuration): if configuration: for raid_device, members in configuration.viewitems(): # allows for idempotence if not os.path.exists(raid_device): for dev in members: util.runCmd2(['mdadm', '--zero-superblock', '--force', dev]) # let it fail without catching cmd = ['mdadm', '--create', raid_device, '--run', '--metadata=1.0', '--level=mirror', '--raid-devices=%s' % (len(members))] + members rc, out, err = util.runCmd2(cmd, with_stdout=True, with_stderr=True) if rc != 0: raise Exception('Error running: %s\n%s\n\n%s' % (' '.join(cmd), out, err))
def mpath_enable(): global use_mpath assert 0 == util.runCmd2(['modprobe','dm-multipath']) # This creates maps for all disks at start of day (because -e is ommitted) assert 0 == util.runCmd2('multipathd -d &> /var/log/multipathd &') wait_for_multipathd() # CA-48440: Cope with lost udev events add_mpath_udev_rule() util.runCmd2(["multipathd","-k"], inputtext="reconfigure") # Tell DM to create partition nodes for newly created mpath devices assert 0 == createMpathPartnodes() xelogging.log("created multipath device(s)"); use_mpath = True
def get_fcoe_vlans(interface): ''' This routine return fcoe vlans associated with an interface. returns the vlans as a list. ''' vlans = [] rc, out, err = util.runCmd2(['fcoeadm', '-f'], True, True) if rc != 0: return vlans for l in out.split('\n'): line = l.strip() if len(line) == 0 or ':' not in line: continue k, v = line.split(':', 1) key = k.strip() value = v.strip() if key == 'Interface': iface = value.split('.', 1)[0].strip() if iface == interface: vlans.append(value) return vlans
def configure_ibft_nic(target_ip, iface, ip, nm, gw): prefix = sum([bin(int(i)).count('1') for i in nm.split('.')]) rv = util.runCmd2(['ip', 'addr', 'add', '%s/%s' % (ip, prefix), 'dev', iface]) if rv: raise RuntimeError('Failed to initialize NIC for iSCSI') if netutil.network(ip, nm) == netutil.network(target_ip, nm): # Same subnet, don't use the gateway rv = util.runCmd2(['ip', 'route', 'add', target_ip, 'dev', iface]) elif gw: rv = util.runCmd2(['ip', 'route', 'add', target_ip, 'dev', iface, 'via', gw]) else: raise RuntimeError('A gateway is needed to initialize NIC for iSCSI') if rv: raise RuntimeError('Failed to initialize NIC for iSCSI')
def disk_more_info(context): if not context: return True usage = 'unknown' (boot, state, storage) = diskutil.probeDisk(context) if boot[0]: usage = "%s installation" % MY_PRODUCT_BRAND elif storage[0]: usage = 'VM storage' else: # Determine disk is being used as an LVM SR with no partitioning rv, out = util.runCmd2([ 'pvs', context, '-o', 'vg_name', '--noheadings' ], with_stdout=True) if rv == 0: vg_name = out.strip() if vg_name.startswith('VG_XenStorage-'): usage = 'VM Storage' tui.update_help_line([' ', ' ']) snackutil.TableDialog(tui.screen, "Details", ("Disk:", diskutil.getHumanDiskName(context)), ("Vendor:", diskutil.getDiskDeviceVendor(context)), ("Model:", diskutil.getDiskDeviceModel(context)), ("Serial:", diskutil.getDiskSerialNumber(context)), ("Size:", diskutil.getHumanDiskSize(diskutil.getDiskDeviceSize(context))), ("Current usage:", usage)) tui.screen.popHelpLine() return True
def run_script(script, stage, *args): xelogging.log("Running script for stage %s: %s %s" % (stage, script, " ".join(args))) util.assertDir(constants.SCRIPTS_DIR) fd, local_name = tempfile.mkstemp(prefix=stage, dir=constants.SCRIPTS_DIR) try: util.fetchFile(script, local_name) # check the interpreter fh = os.fdopen(fd) fh.seek(0) line = fh.readline(40) fh.close() except: raise RuntimeError, "Unable to fetch script %s" % script if not line.startswith("#!"): raise RuntimeError, "Missing interpreter in %s." % script interp = line[2:].split() if interp[0] == "/usr/bin/env": if len(interp) < 2 or interp[1] not in ["python"]: raise RuntimeError, "Invalid interpreter %s in." % (interp[1], script) elif interp[0] not in ["/bin/sh", "/bin/bash", "/usr/bin/python"]: raise RuntimeError, "Invalid interpreter %s in %s." % (interp[0], script) cmd = [local_name] cmd.extend(args) os.chmod(local_name, stat.S_IRUSR | stat.S_IXUSR) os.environ["XS_STAGE"] = stage rc, out, err = util.runCmd2(cmd, with_stdout=True, with_stderr=True) xelogging.log("Script returned %d" % rc) # keep script, will be collected in support tarball return rc, out, err
def isRepo(cls, accessor): if UpdateYumRepository.isRepo(accessor): url = accessor.url() with open('/root/yum.conf', 'w') as yum_conf: yum_conf.write(cls._yum_conf) yum_conf.write(""" [driverrepo] name=driverrepo baseurl=%s """ % url.getPlainURL()) username = url.getUsername() if username is not None: yum_conf.write("username=%s\n" % (url.getUsername(), )) password = url.getPassword() if password is not None: yum_conf.write("password=%s\n" % (url.getPassword(), )) # Check that the drivers group exists in the repo. rv, out = util.runCmd2( ['yum', '-c', '/root/yum.conf', 'group', 'summary', 'drivers'], with_stdout=True) if rv == 0 and 'Groups: 1\n' in out.strip(): return True return False
def run_script(script, stage, *args): xelogging.log("Running script for stage %s: %s %s" % (stage, script, ' '.join(args))) util.assertDir(constants.SCRIPTS_DIR) fd, local_name = tempfile.mkstemp(prefix = stage, dir = constants.SCRIPTS_DIR) try: util.fetchFile(script, local_name) # check the interpreter fh = os.fdopen(fd) fh.seek(0) line = fh.readline(40) fh.close() except: raise RuntimeError, "Unable to fetch script %s" % script if not line.startswith('#!'): raise RuntimeError, "Missing interpreter in %s." % script interp = line[2:].split() if interp[0] == '/usr/bin/env': if len (interp) < 2 or interp[1] not in ['python']: raise RuntimeError, "Invalid interpreter %s in %s." % (interp[1], script) elif interp[0] not in ['/bin/sh', '/bin/bash', '/usr/bin/python']: raise RuntimeError, "Invalid interpreter %s in %s." % (interp[0], script) cmd = [local_name] cmd.extend(args) os.chmod(local_name, stat.S_IRUSR | stat.S_IXUSR) os.environ['XS_STAGE'] = stage rc, out, err = util.runCmd2(cmd, with_stdout = True, with_stderr = True) xelogging.log("Script returned %d" % rc) # keep script, will be collected in support tarball return rc, out, err
def modprobe(module, params=""): xelogging.log("Loading module %s" % " ".join([module, params])) rc = util.runCmd2(["modprobe", module, params]) if rc != 0: xelogging.log("(Failed.)") return rc
def getPCIInfo(interface): interface, vlan = splitInterfaceVlan(interface) info = "<Information unknown>" devpath = os.path.realpath('/sys/class/net/%s/device' % interface) slot = devpath[len(devpath) - 7:] rc, output = util.runCmd2( ['lspci', '-i', '/usr/share/misc/pci.ids', '-s', slot], with_stdout=True) if rc == 0: info = output.strip('\n') cur_if = None pipe = subprocess.Popen(['biosdevname', '-d'], bufsize=1, stdout=subprocess.PIPE) for line in pipe.stdout: l = line.strip('\n') if l.startswith('Kernel name'): cur_if = l[13:] elif l.startswith( 'PCI Slot') and cur_if == interface and l[16:] != 'embedded': info += "\nSlot " + l[16:] pipe.wait() return info
def getBroadcast(self): bcast = None rc, output = util.runCmd2( ['/bin/ipcalc', '-b', self.ipaddr, self.netmask], with_stdout=True) if rc == 0: bcast = output[10:].strip() return bcast
def rfc4173_to_disk(rfc4173_spec): "Get the disk (e.g. '/dev/sdb') corresponding to a LUN on an IQN to which we are logged in" try: parts = rfc4173_spec.split(':',5) assert(parts[0] == "iscsi") targetip = parts[1] lun = parts[4] and int(parts[4]) or 0 iqn = parts[5] except: raise IscsiDeviceException, "Cannot parse spec %s" % rfc4173_spec sid = iscsi_get_sid(targetip, iqn) rv, out = util.runCmd2([ 'iscsiadm', '-m', 'session', '-r', str(sid), '-P', '3' ], with_stdout=True) assert(rv == 0) lines = out.strip().split('\n') regex = re.compile('^\\s*\\w+ Channel \\d+ Id \\d+ Lun: %d$' % lun) while lines: line = lines.pop(0) if regex.match(line): # next line says what the disk is called! line = lines.pop(0) regex2 = re.compile('^\\s*Attached scsi disk (\\w+)\\s+.*$') match = regex2.match(line) assert match != None return '/dev/' + match.groups()[0] raise Exception, "Could not find iscsi disk with IQN %s and lun %d" % (iqn,lun)
def rfc4173_to_disk(rfc4173_spec): "Get the disk (e.g. '/dev/sdb') corresponding to a LUN on an IQN to which we are logged in" try: parts = rfc4173_spec.split(':',5) assert(parts[0] == "iscsi") targetip = parts[1] lun = parts[4] and int(parts[4]) or 0 iqn = parts[5] except: raise IscsiDeviceException, "Cannot parse spec %s" % rfc4173_spec # Retry this a few times since it may take awhile for the device name to # appear in the iscsiadm output. retry = 10 while retry > 0: sid = iscsi_get_sid(targetip, iqn) rv, out = util.runCmd2([ 'iscsiadm', '-m', 'session', '-r', str(sid), '-P', '3' ], with_stdout=True) assert(rv == 0) lines = out.strip().split('\n') regex = re.compile('^\\s*\\w+ Channel \\d+ Id \\d+ Lun: %d$' % lun) while lines: line = lines.pop(0) if regex.match(line): if not lines: break # next line says what the disk is called! line = lines.pop(0) regex2 = re.compile('^\\s*Attached scsi disk (\\w+)\\s+.*$') match = regex2.match(line) assert match != None return '/dev/' + match.groups()[0] time.sleep(1) retry -= 1 raise Exception, "Could not find iscsi disk with IQN %s and lun %d" % (iqn,lun)
def disk_more_info(context): if not context: return True usage = 'unknown' (boot, root, state, storage, logs) = diskutil.probeDisk(context) if root[0]: usage = "%s installation" % MY_PRODUCT_BRAND elif storage[0]: usage = 'VM storage' else: # Determine disk is being used as an LVM SR with no partitioning rv, out = util.runCmd2([ 'pvs', context, '-o', 'vg_name', '--noheadings' ], with_stdout=True) if rv == 0: vg_name = out.strip() if vg_name.startswith('VG_XenStorage-'): usage = 'VM Storage' tui.update_help_line([' ', ' ']) snackutil.TableDialog(tui.screen, "Details", ("Disk:", diskutil.getHumanDiskName(context)), ("Vendor:", diskutil.getDiskDeviceVendor(context)), ("Model:", diskutil.getDiskDeviceModel(context)), ("Serial:", diskutil.getDiskSerialNumber(context)), ("Size:", diskutil.getHumanDiskSize(diskutil.getDiskDeviceSize(context))), ("Current usage:", usage)) tui.screen.popHelpLine() return True
def get_fcoe_luns(): ''' returns a dictionary of fcoe luns ''' d = {} rc, out, err = util.runCmd2(['fcoeadm', '-t'], True, True) if rc != 0: return d state = 'header' for l in out.split('\n'): line = l.lstrip() if len(line) == 0 or line.startswith('--') or line.startswith( 'PCI') or line.startswith('No'): continue if state == 'header': if ':' not in line: # LUN banner rport = header['OS Device Name'] if iface not in d: d[iface] = {} d[iface][rport] = header state = 'luns' continue k, v = line.split(':', 1) key = k.strip() value = v.strip() if key == 'Interface': iface = value header = {} else: header[key] = value else: # LUNs m = lun_re.match(line) if m: if 'luns' not in d[iface][rport]: d[iface][rport]['luns'] = {} d[iface][rport]['luns'][m.group(1)] = { 'device': m.group(2), 'capacity': m.group(3), 'bsize': m.group(4), 'description': m.group(5) } else: if not line.startswith('Interface:'): # Skip LUNs which do not yet have a block device. continue # New header, starts with Interface: state = 'header' _, v = line.split(':', 1) iface = v.strip() header = {} return d
def readExtPartitionLabel(partition): """Read the ext partition label.""" rc, out = util.runCmd2(['/sbin/e2label', partition], with_stdout = True) if rc == 0: label = out.strip() else: raise Exception("%s is not ext partition" % partition) return label
def cmdWrap(cls, params): rv, out, err = util.runCmd2(params, True, True) if rv != 0: if isinstance(err, (types.ListType, types.TupleType)): raise Exception("\n".join(err) + "\nError=" + str(rv)) else: raise Exception(str(err) + "\nError=" + str(rv)) return out
def mpath_cli_is_working(): regex = re.compile("switchgroup") try: (rc,stdout) = util.runCmd2(["multipathd","-k"], with_stdout=True, inputtext="help") m=regex.search(stdout) return bool(m) except: return False
def getMdDeviceName(disk): rv, out = util.runCmd2(['mdadm', '--detail', '--export', disk], with_stdout=True) for line in out.split("\n"): line = line.strip().split('=', 1) if line[0] == 'MD_DEVNAME': return line[1] return disk
def iscsi_get_sessions(): "Get information about each active iSCSI session" rv, out = util.runCmd2([ 'iscsiadm', '-m', 'session' ], with_stdout=True) assert(rv == 0) lines = out.strip().split('\n') regex = re.compile(r'^tcp: \[(\d+)\] ([^:]+):([^,]+),([^ ]+) ([^ ]+).*$') # List of tuples (sid, target_ip, port, target_port_group_tag, iqn) return map(lambda line: regex.match(line).groups(), lines)
def getMpathNodes(): nodes = [] rv, out = util.runCmd2(["dmsetup", "ls", "--target", "multipath", "--exec", "ls"], with_stdout=True) xelogging.log("multipath devs: %s" % out) lines = out.strip().split("\n") for line in lines: if line.startswith("/dev/"): nodes.append(line) return nodes
def idFromPartition(partition): symlink = None v, out = util.runCmd2(['/usr/bin/udevinfo', '-q', 'symlink', '-n', partition], with_stdout = True) if v == 0: for link in out.split(): if link.startswith('disk/by-id') and not link.startswith('disk/by-id/edd'): symlink = '/dev/'+link break return symlink
def attach_rfc4173(iname, rfc4173_spec): """ Attach a disk given an initiator name, and spec in the following format: "iscsi:"<targetip>":"<protocol>":"<port>":"<LUN>":"<targetname> return disk, e.g. "/dev/sdb" """ try: parts = rfc4173_spec.split(':',5) assert(parts[0] == "iscsi") targetip = parts[1] port = parts[3] lun = parts[4] and int(parts[4]) or 0 iqn = parts[5] except: raise IscsiDeviceException, "Cannot parse spec %s" % rfc4173_spec if port: targetip += ':%s' % port # Attach to disk if not os.path.exists("/etc/iscsi/initiatorname.iscsi"): open("/etc/iscsi/initiatorname.iscsi","w").write("InitiatorName=%s" % iname) rv = util.runCmd2([ '/sbin/modprobe', 'iscsi_tcp' ]) if rv: raise RuntimeError, "/sbin/modprobe iscsi_tcp failed" try: if not util.pidof('iscsid'): fd = open("/etc/iscsi/initiatorname.iscsi", "w") fd.write("InitiatorName=%s" % iname) fd.close() rv = util.runCmd2([ '/sbin/iscsiadm', '-m', 'discovery', '-t', 'sendtargets', '-p', targetip]) if rv: raise RuntimeError, "/sbin/iscsiadm -m discovery failed" rv = util.runCmd2([ '/sbin/iscsiadm', '-m', 'node', '-T', iqn, '-p', targetip, '-l']) # login if rv: raise RuntimeError, "/sbin/iscsiadm -m node -l failed" finally: util.runCmd2(util.udevsettleCmd()) # update /dev disk = rfc4173_to_disk(rfc4173_spec) iscsi_disks.append(disk) return disk
def have_ibft(): """ Determine if an iBFT is present """ rv = util.runCmd2([ '/sbin/modprobe', 'iscsi_ibft' ]) if rv: raise RuntimeError, "/sbin/modprobe iscsi_ibft failed" if os.path.isdir("%s/initiator" % sysfs_ibft_dir): xelogging.log("process_ibft: iBFT found.") return True xelogging.log("process_ibft: No iBFT found.") return False
def ipaddr(interface): rc, out = util.runCmd2(['ip', 'addr', 'show', interface], with_stdout = True) if rc != 0: return None inets = filter(lambda x: 'inet ' in x, out.split("\n")) if len(inets) == 1: m = re.search(r'inet (S+)/', inets[0]) if m: return m.match(1) return None
def destroyPartnodes(dev): # Destroy partition nodes for a device-mapper device dmnodes = ["/dev/mapper/%s" % f for f in os.listdir("/dev/mapper")] partitions = filter(lambda dmnode: dmnode.startswith(dev + "p"), dmnodes) for partition in partitions: # the obvious way to do this is to use "kpartx -d" but that's broken! rv = util.runCmd2(["dmsetup", "remove", partition]) if rv: return rv return 0
def ipaddr(interface): rc, out = util.runCmd2(['ip', 'addr', 'show', interface], with_stdout=True) if rc != 0: return None inets = filter(lambda x: 'inet ' in x, out.split("\n")) if len(inets) == 1: m = re.search(r'inet (\S+)/', inets[0]) if m: return m.group(1) return None
def idFromPartition(partition): symlink = None v, out = util.runCmd2(util.udevinfoCmd() + ['-q', 'symlink', '-n', partition], with_stdout = True) prefixes = ['disk/by-id/edd', 'disk/by-id/dm-name-', 'disk/by-id/dm-uuid-', 'disk/by-id/lvm-pv-uuid-', 'disk/by-id/cciss-'] if v == 0: for link in out.split(): if link.startswith('disk/by-id') and not True in map(lambda x : link.startswith(x), prefixes): symlink = '/dev/'+link break return symlink
def iscsi_get_sid(targetip, iqn): "Get the Session ID corresponding to an IQN to which we are logged in" rv, out = util.runCmd2([ 'iscsiadm', '-m', 'session' ], with_stdout=True) assert(rv == 0) lines = out.strip().split('\n') regex = re.compile('^tcp: \\[(\\d+)\\] ([^:]+):([^,]+),[^ ]+ (.*)$') tuples = map(lambda line: regex.match(line).groups(), lines) tuples = filter(lambda entry: entry[1] == targetip and entry[3] == iqn, tuples) assert(len(tuples) == 1) sid = int(tuples[0][0]) return sid
def iscsi_get_sid(targetip, iqn): "Get the Session ID corresponding to an IQN to which we are logged in" rv, out = util.runCmd2([ 'iscsiadm', '-m', 'session' ], with_stdout=True) assert(rv == 0) lines = out.strip().split('\n') regex = re.compile('^tcp: \\[(\\d+)\\] ([^:]+):([^,]+),[^ ]+ ([^ ]+).*$') tuples = map(lambda line: regex.match(line).groups(), lines) tuples = filter(lambda entry: entry[1] == targetip and entry[3] == iqn, tuples) assert(len(tuples) == 1) sid = int(tuples[0][0]) return sid
def module_file_uname(module): rc, out = util.runCmd2(["modinfo", module], with_stdout=True) if rc != 0: raise RuntimeError, "Error interrogating module" vermagics = filter(lambda x: x.startswith("vermagic:"), out.split("\n")) if len(vermagics) != 1: raise RuntimeError, "No version magic field for module %s" % module vermagic = vermagics[0] vermagic = vermagic[10:].strip() return vermagic.split(" ")[0]
def waitUntilUp(self, iface): if not self.isStatic(): return True if not self.gateway: return True rc = util.runCmd2([ '/usr/sbin/arping', '-f', '-w', '120', '-I', self.getInterfaceName(iface), self.gateway ]) return rc == 0
def linkUp(interface): linkUp = None rc, out = util.runCmd2(['ethtool', interface], with_stdout = True) if rc != 0: return None for line in out.split('\n'): line = line.strip() if line.startswith('Link detected:'): linkUp = line.endswith('yes') return linkUp
def mpath_cli_is_working(): regex = re.compile("switchgroup") try: (rc,stdout) = util.runCmd2(["multipathd","-k"], with_stdout=True, inputtext="help") m=regex.search(stdout) if m: return True else: return False except: return False
def getDiskSerialNumber(dev): # For Multipath nodes return info about 1st slave if not dev.startswith("/dev/"): dev = '/dev/' + dev if isDeviceMapperNode(dev): return getDiskSerialNumber(getMpathSlaves(dev)[0]) rc, out = util.runCmd2(['/bin/sdparm', '-q', '-i', '-p', 'sn', dev], with_stdout = True) if rc == 0: lines = out.split('\n') if len(lines) >= 2: return lines[1].strip() return ""
def getMpathSlaves(disk): """ Return the list of slaves for an mpath device or an empty list if not mpath """ slaves = [] major, minor = getMajMin(disk) rv, out = util.runCmd2(["sh", "-c", "ls -d1 /sys/block/*/holders/*/dev"], with_stdout=True) lines = out.strip().split("\n") lines = filter(lambda x: x != "", lines) for f in lines: _, _, _, dev, _, _, _ = f.split("/") __major, __minor = map(int, open(f).read().split(":")) if (__major, __minor) == (major, minor): dev = "/dev/" + dev.replace("!", "/") slaves.append(dev) return slaves
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
def attach_rfc4173(iname, rfc4173_spec): """ Attach a disk given an initiator name, and spec in the following format: "iscsi:"<targetip>":"<protocol>":"<port>":"<LUN>":"<targetname> return disk, e.g. "/dev/sdb" """ try: parts = rfc4173_spec.split(':',5) assert(parts[0] == "iscsi") targetip = parts[1] port = parts[3] lun = parts[4] and int(parts[4]) or 0 iqn = parts[5] except: raise IscsiDeviceException, "Cannot parse spec %s" % rfc4173_spec if port: targetip += ':%s' % port # Attach to disk if not os.path.exists("/etc/iscsi/initiatorname.iscsi"): rv, iname = util.runCmd2([ '/sbin/iscsi-iname' ], with_stdout=True) if rv: raise RuntimeError, "/sbin/iscsi-iname failed" open("/etc/iscsi/initiatorname.iscsi","w").write("InitiatorName=%s" % iname) rv = util.runCmd2([ '/sbin/modprobe', 'iscsi_tcp' ]) if rv: raise RuntimeError, "/sbin/modprobe iscsi_tcp failed" try: if not util.pidof('iscsid'): fd = open("/etc/iscsi/initiatorname.iscsi", "w") fd.write("InitiatorName=%s" % iname) fd.close() rv = util.runCmd2([ '/sbin/iscsid' ]) # start iscsiadm if rv: raise RuntimeError, "/sbin/iscsid failed" rv = util.runCmd2([ '/sbin/iscsiadm', '-m', 'discovery', '-t', 'sendtargets', '-p', targetip]) if rv: raise RuntimeError, "/sbin/iscsiadm -m discovery failed" rv = util.runCmd2([ '/sbin/iscsiadm', '-m', 'node', '-T', iqn, '-p', targetip, '-l']) # login if rv: raise RuntimeError, "/sbin/iscsiadm -m node -l failed" finally: util.runCmd2([ '/sbin/udevsettle' ]) # update /dev disk = rfc4173_to_disk(rfc4173_spec) iscsi_disks.append(disk) return disk
def getDiskSerialNumber(dev): # For Multipath nodes return info about 1st slave if not dev.startswith("/dev/"): dev = '/dev/' + dev if isDeviceMapperNode(dev): return getDiskSerialNumber(getDeviceSlaves(dev)[0]) if is_raid(dev): serials = set(map(getDiskSerialNumber, getDeviceSlaves(dev))) return '/'.join(serials) rc, out = util.runCmd2(['/bin/sdparm', '-q', '-i', '-p', 'sn', dev], with_stdout = True) if rc == 0: lines = out.split('\n') if len(lines) >= 2: return lines[1].strip() return ""
def write_iscsi_records(mounts, primary_disk): record = [] node_name = node_address = node_port = None rv, out = util.runCmd2(['iscsistart', '-f'], with_stdout=True) if rv: raise Exception('Invalid iSCSI record') for line in out.split('\n'): line = line.strip() if not line: continue if line.startswith('node.name = '): node_name = line.split()[2] if line.startswith('node.conn[0].address = '): node_address = line.split()[2] if line.startswith('node.conn[0].port = '): node_port = line.split()[2] if line == '# END RECORD': if node_name is None or node_address is None or node_port is None: raise Exception('Invalid iSCSI record') # Ensure that the session does not get logged out during shutdown record.append('node.startup = onboot') # iscsistart hardcodes the target portal group tag to 1 record.append('node.tpgt = 1') if isDeviceMapperNode(primary_disk): record.append('%s = %d\n' % ('node.session.timeo.replacement_timeout', constants.MPATH_ISCSI_TIMEOUT)) record.append(line) path = os.path.join(mounts['root'], constants.ISCSI_NODES, node_name, '%s,%s,1' % (node_address, node_port)) os.makedirs(path) with open(os.path.join(path, 'default'), 'w') as f: f.write('\n'.join(record) + '\n') record = [] node_name = node_address = node_port = None continue record.append(line) if record: raise Exception('Invalid iSCSI record')
def writeDebStyleInterface(self, iface, f): """ Write a Debian-style configuration entry for this interface to file object f using interface name iface. """ assert self.mode if self.mode == self.DHCP: f.write("iface %s inet dhcp\n" % iface) else: # CA-11825: broadcast needs to be determined for non-standard networks bcast = None rc, output = util.runCmd2(['/bin/ipcalc', '-b', self.ipaddr, self.netmask], with_stdout=True) if rc == 0: bcast = output[10:].strip() f.write("iface %s inet static\n" % iface) f.write(" address %s\n" % self.ipaddr) if bcast != None: f.write(" broadcast %s\n" % bcast) f.write(" netmask %s\n" % self.netmask) if self.gateway: f.write(" gateway %s\n" % self.gateway)
def probePartitioningScheme(device): """Determine whether the MBR is a DOS MBR, a GPT PMBR, or corrupt""" rv, out, err = util.runCmd2(["fdisk", "-l", device], with_stdout=True, with_stderr=True) lines = out.split("\n") + err.split("\n") def matchline(s): match = re.compile(s) for l in lines: if match.match(l): return True return False if rv: partitionType = "GPT" # default elif matchline("^.*doesn't contain a valid partition table$"): partitionType = "GPT" # default elif matchline("^.*EFI GPT$"): partitionType = "GPT" # default else: partitionType = "DOS" return partitionType
def getPCIInfo(interface): info = "<Information unknown>" devpath = os.path.realpath('/sys/class/net/%s/device' % interface) slot = devpath[len(devpath) - 7:] rc, output = util.runCmd2(['lspci', '-i', '/usr/share/misc/pci.ids', '-s', slot], with_stdout=True) if rc == 0: info = output.strip('\n') cur_if = None pipe = subprocess.Popen(['biosdevname', '-d'], bufsize = 1, stdout = subprocess.PIPE) for line in pipe.stdout: l = line.strip('\n') if l.startswith('Kernel name'): cur_if = l[13:] elif l.startswith('PCI Slot') and cur_if == interface and l[16:] != 'embedded': info += "\nSlot "+l[16:] pipe.wait() return info
def doBackup(self, progress_callback, target_disk, backup_partnum): # format the backup partition: backup_partition = partitionDevice(target_disk, backup_partnum) if util.runCmd2(['mkfs.ext3', backup_partition]) != 0: raise RuntimeError, "Backup: Failed to format filesystem on %s" % backup_partition progress_callback(10) # copy the files across: primary_fs = util.TempMount(self.source.root_device, 'primary-', options = ['ro']) try: backup_fs = util.TempMount(backup_partition, 'backup-') try: just_dirs = ['dev', 'proc', 'lost+found', 'sys'] top_dirs = os.listdir(primary_fs.mount_point) val = 10 for x in top_dirs: if x in just_dirs: path = os.path.join(backup_fs.mount_point, x) if not os.path.exists(path): os.mkdir(path, 0755) else: cmd = ['cp', '-a'] + \ [ os.path.join(primary_fs.mount_point, x) ] + \ ['%s/' % backup_fs.mount_point] if util.runCmd2(cmd) != 0: raise RuntimeError, "Backup of %s directory failed" % x val += 90 / len(top_dirs) progress_callback(val) finally: # replace rolling pool upgrade bootloader config src = os.path.join(backup_fs.mount_point, constants.ROLLING_POOL_DIR, 'menu.lst') if os.path.exists(src): util.runCmd2(['cp', '-f', src, os.path.join(backup_fs.mount_point, 'boot/grub')]) src = os.path.join(backup_fs.mount_point, constants.ROLLING_POOL_DIR, 'extlinux.conf') if os.path.exists(src): util.runCmd2(['cp', '-f', src, os.path.join(backup_fs.mount_point, 'boot')]) fh = open(os.path.join(backup_fs.mount_point, '.xen-backup-partition'), 'w') fh.close() backup_fs.unmount() finally: primary_fs.unmount()
def remap_netdevs(remap_list): # rename everything sideways to safe faffing with temp renanes for x in ( x for x in os.listdir("/sys/class/net/") if x[:3] == "eth" ): util.runCmd2(['ip', 'link', 'set', x, 'name', 'side-'+x]) bdn = BiosDevName() bdn.run(policy="physical") all_devices = bdn.devices[:] parsed_list = filter(lambda x: x is not None, map(parse_arg, remap_list)) # python sorting is stable so the following results in sorted by # static/dynamic, then subsorted by ethname parsed_list.sort(key=lambda x: x[0]) parsed_list.sort(key=lambda x: x[1]) for rule in parsed_list: target, sd, method, val = rule # If the rule specifies an SMBios Label if method == METH_LABEL: dev = None for d in bdn.devices: if 'SMBIOS Label' in d and d['SMBIOS Label'] == val: dev = d break if dev is None: xelogging.log("No SMBios Label found for %s rule - Discarding" % target) continue else: bdn.devices.remove(dev) if sd == DEV_STATIC: srules.append('%s: label="%s"' % (target, val)) else: drules.append([dev['Assigned MAC'].lower(), dev['Bus Info'].lower(), target]) xelogging.log("Renaming '%s' to '%s' due to SMBIOS Label" % ( dev['Kernel name'], target )) util.runCmd2(['ip', 'link', 'set', dev['Kernel name'], 'name', target]) elif method == METH_MAC: dev = None for d in bdn.devices: if d['Assigned MAC'].lower() == val: dev = d break if dev is None: xelogging.log("No device with mac address '%s' found for %s " "rule - Discarding" % (val, target)) continue else: bdn.devices.remove(dev) if sd == DEV_STATIC: srules.append('%s: mac="%s"' % (target, val)) else: drules.append([val, dev['Bus Info'].lower(), target]) xelogging.log("Renaming '%s' to '%s' due to MAC address" % ( dev['Kernel name'], target )) util.runCmd2(['ip', 'link', 'set', dev['Kernel name'], 'name', target]) elif method == METH_PCI: dev = None for d in bdn.devices: if d['Bus Info'].lower() == val: dev = d break if dev is None: xelogging.log("No device with pci address '%s' found for %s " "rule - Discarding" % (val, target)) continue else: bdn.devices.remove(dev) if sd == DEV_STATIC: srules.append('%s: pci="%s"' % (target, val)) else: drules.append([dev['Assigned MAC'].lower(), val, target]) xelogging.log("Renaming '%s' to '%s' due to PCI mapping" % ( dev['Kernel name'], target )) util.runCmd2(['ip', 'link', 'set', dev['Kernel name'], 'name', target]) elif method == METH_PPN: dev = None for d in bdn.devices: if d['BIOS device'] == val: dev = d break if dev is None: xelogging.log("No device with physical address '%s' found for " "%s rule - Discarding" % (val, target)) continue else: bdn.devices.remove(dev) if sd == DEV_STATIC: srules.append('%s: ppn="%s"' % (target, val)) else: drules.append([dev['Assigned MAC'].lower(), dev['Bus Info'].lower(), target]) xelogging.log("Renaming '%s' to '%s' due to Physical name" % ( dev['Kernel name'], target )) util.runCmd2(['ip', 'link', 'set', dev['Kernel name'], 'name', target]) else: xelogging.log("Unrecognised method - Ignoring") side_devs = [ x for x in os.listdir("/sys/class/net") if x[:5] == "side-" ] side_devs.sort(key=lambda x: int(x[8:])) if len(side_devs): xelogging.log("Renaming devices which have not been displaced by mapping rules") for x in side_devs: if not os.path.exists("/sys/class/net/"+x[5:]): for dev in all_devices: if dev['Kernel name'] == x: drules.append([dev['Assigned MAC'].lower(), dev['Bus Info'].lower(), x[5:]]) util.runCmd2(['ip', 'link', 'set', x, 'name', x[5:]]) def gen_free_netdev(): x = -1 while True: x += 1 if not os.path.exists("/sys/class/net/eth%d" % x): yield "eth%d" % x free_netdev = gen_free_netdev() side_devs = [ x for x in os.listdir("/sys/class/net") if x[:5] == "side-" ] side_devs.sort(key=lambda x: int(x[8:])) if len(side_devs): xelogging.log("Reallocating names for devices which have been displaced") for x in side_devs: free_dev = free_netdev.next() for dev in all_devices: if dev['Kernel name'] == x: drules.append([dev['Assigned MAC'].lower(), dev['Bus Info'].lower(), free_dev]) util.runCmd2(['ip', 'link', 'set', x, 'name', free_dev]) xelogging.log("All done ordering the network devices") xelogging.log("Static rules = %r" % srules) xelogging.log("Dynamic rules = %r" % drules)
def networkingUp(): rc, out = util.runCmd2(['ip', 'route'], with_stdout = True) if rc == 0 and len(out.split('\n')) > 2: return True return False
def ifup(interface): assert interface in getNetifList() interface_up[interface] = True return util.runCmd2(['ifup', interface])