Coverage for drivers/lvutil : 29%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
#!/usr/bin/python # # Copyright (C) Citrix Systems Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; version 2.1 only. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Miscellaneous LVM utility functions #
CMD_VGEXTEND}) CMD_LVCHANGE, CMD_LVRENAME, CMD_LVRESIZE, CMD_LVEXTEND})
"""Search for and return a VG name
Search 'str_in' for a substring in the form of 'VG_XenStorage-<UUID>'. If there are more than one VG names, the first is returned.
Input: str_in -- (str) string to search for a VG name in the format specified above.
Return: vgname -- if found -> (str) if not found -> None
Raise: TypeError """
if not util.is_string(str_in): raise TypeError("'str_in' not of type 'str'.")
i = str_in.find(VG_PREFIX) prefix = VG_PREFIX
if i == -1: i = str_in.find(EXT_PREFIX) prefix = EXT_PREFIX
uuid_start = i + len(prefix) re_obj = util.match_uuid(str_in[uuid_start:])
if i != -1 and re_obj: return prefix + re_obj.group(0) # vgname
return None
""" Context manager around the LVM lock.
To allow for higher level operations, e.g. VDI snapshot to pre-emptively acquire the lock to encapsulte a set of calls and avoid having to reacquire the locks for each LVM call. """
return
""" Construct and run the appropriate lvm command.
For PV commands, the full path to the device is required.
Input: cmd -- (list) lvm command cmd[0] -- (str) lvm command name cmd[1:] -- (str) lvm command parameters
pread_func -- (function) the flavor of util.pread to use to execute the lvm command Default: util.pread2()
*args -- extra arguments passed to cmd_lvm will be passed to 'pread_func'
Return: stdout -- (str) stdout after running the lvm command.
Raise: util.CommandException """
util.SMlog("CMD_LVM: Argument 'cmd' not of type 'list'") return None util.SMlog("CMD_LVM: 'cmd' list is empty") return None
util.SMlog("CMD_LVM: '{}' is not a valid lvm command".format(lvm_cmd)) return None
util.SMlog("CMD_LVM: Not all lvm arguments are of type 'str'") return None
util.SMlog("***** Long LVM call of '%s' took %s" % (lvm_cmd, (end_time - start_time)))
self.name = name
return "%s, size=%d, active=%s, open=%s, hidden=%s, ro=%s" % \ (self.name, self.size, self.active, self.open, self.hidden, \ self.readonly)
try: cmd_lvm([CMD_VGS, "--readonly", vgname]) return True except: return False
try: cmd_lvm([CMD_PVS, pvname]) return True except: return False
try: cmd_lvm([CMD_LVDISPLAY, path]) return True except: return False
try: lines = cmd_lvm([CMD_LVDISPLAY, "-c", path]).split(':') return long(lines[6]) * 512 except: raise xs_errors.XenError('VDIUnavailable', \ opterr='no such VDI %s' % path)
try: text = cmd_lvm([CMD_VGS, "--noheadings", "--nosuffix", "--units", "b", vgname], pread_func=util.pread).split() size = long(text[5]) freespace = long(text[6]) utilisation = size - freespace stats = {} stats['physical_size'] = size stats['physical_utilisation'] = utilisation stats['freespace'] = freespace return stats except util.CommandException, inst: raise xs_errors.XenError('VDILoad', \ opterr='rvgstats failed error is %d' % inst.code) except ValueError: raise xs_errors.XenError('VDILoad', opterr='rvgstats failed')
try: text = cmd_lvm([CMD_PVS, "--noheadings", "--nosuffix", "--units", "b", dev], pread_func=util.pread).split() size = long(text[4]) freespace = long(text[5]) utilisation = size - freespace stats = {} stats['physical_size'] = size stats['physical_utilisation'] = utilisation stats['freespace'] = freespace return stats except util.CommandException, inst: raise xs_errors.XenError('VDILoad', \ opterr='pvstats failed error is %d' % inst.code) except ValueError: raise xs_errors.XenError('VDILoad', opterr='rvgstats failed')
# Retrieves the UUID of the SR that corresponds to the specified Physical # Volume (pvname). Each element in prefix_list is checked whether it is a # prefix of Volume Groups that correspond to the specified PV. If so, the # prefix is stripped from the matched VG name and the remainder is returned # (effectively the SR UUID). If no match if found, the empty string is # returned. # E.g. # PV VG Fmt Attr PSize PFree # /dev/sda4 VG_XenStorage-some-hex-value lvm2 a- 224.74G 223.73G # will return "some-hex-value". try: return match_VG(cmd_lvm([CMD_PVS, "--noheadings", "-o", "vg_name", pvname]), prefix_list) except: return ""
# Tries to match any prefix contained in prefix_list in s. If matched, the # remainder string is returned, else the empty string is returned. E.g. if s is # "VG_XenStorage-some-hex-value" and prefix_list contains "VG_XenStorage-", # "some-hex-value" is returned. # # TODO Items in prefix_list are expected to be found at the beginning of the # target string, though if any of them is found inside it a match will be # produced. This could be remedied by making the regular expression more # specific. for val in prefix_list: regex = re.compile(val) if regex.search(s, 0): return s.split(val)[1] return ""
# Retrieves the devices an SR is composed of. A dictionary is returned, indexed # by the SR UUID, where each SR UUID is mapped to a comma-separated list of # devices. Exceptions are ignored. VGs = {} for dev in root.split(','): try: sr_uuid = _get_sr_uuid(dev, [prefix]).strip(' \n') if len(sr_uuid): if VGs.has_key(sr_uuid): VGs[sr_uuid] += ",%s" % dev else: VGs[sr_uuid] = dev except Exception, e: util.logException("exception (ignored): %s" % e) continue return VGs
# Converts an SR list to an XML document with the following structure: # <SRlist> # <SR> # <UUID>...</UUID> # <Devlist>...</Devlist> # <size>...</size> # <!-- If includeMetadata is set to True, the following additional nodes # are supplied. --> # <name_label>...</name_label> # <name_description>...</name_description> # <pool_metadata_detected>...</pool_metadata_detected> # </SR> # # <SR>...</SR> # </SRlist> # # Arguments: # VGs: a dictionary containing the SR UUID to device list mappings # prefix: the prefix that if prefixes the SR UUID the VG is produced # includeMetadata (optional): include additional information dom = xml.dom.minidom.Document() element = dom.createElement("SRlist") dom.appendChild(element)
for val in VGs: entry = dom.createElement('SR') element.appendChild(entry)
subentry = dom.createElement("UUID") entry.appendChild(subentry) textnode = dom.createTextNode(val) subentry.appendChild(textnode)
subentry = dom.createElement("Devlist") entry.appendChild(subentry) textnode = dom.createTextNode(VGs[val]) subentry.appendChild(textnode)
subentry = dom.createElement("size") entry.appendChild(subentry) size = str(_getVGstats(prefix + val)['physical_size']) textnode = dom.createTextNode(size) subentry.appendChild(textnode)
if includeMetadata: metadataVDI = None
# add SR name_label mdpath = os.path.join(VG_LOCATION, VG_PREFIX + val) mdpath = os.path.join(mdpath, MDVOLUME_NAME) try: mgtVolActivated = False if not os.path.exists(mdpath): # probe happens out of band with attach so this volume # may not have been activated at this point lvmCache = lvmcache.LVMCache(VG_PREFIX + val) lvmCache.activateNoRefcount(MDVOLUME_NAME) mgtVolActivated = True
sr_metadata = \ srmetadata.LVMMetadataHandler(mdpath, \ False).getMetadata()[0] subentry = dom.createElement("name_label") entry.appendChild(subentry) textnode = dom.createTextNode(sr_metadata[srmetadata.NAME_LABEL_TAG]) subentry.appendChild(textnode)
# add SR description subentry = dom.createElement("name_description") entry.appendChild(subentry) textnode = dom.createTextNode(sr_metadata[srmetadata.NAME_DESCRIPTION_TAG]) subentry.appendChild(textnode)
# add metadata VDI UUID metadataVDI = srmetadata.LVMMetadataHandler(mdpath, \ False).findMetadataVDI() subentry = dom.createElement("pool_metadata_detected") entry.appendChild(subentry) if metadataVDI != None: subentry.appendChild(dom.createTextNode("true")) else: subentry.appendChild(dom.createTextNode("false")) finally: if mgtVolActivated: # deactivate only if we activated it lvmCache.deactivateNoRefcount(MDVOLUME_NAME)
return dom.toprettyxml()
try: return os.open("%s" % dev, os.O_RDWR | os.O_EXCL) except OSError as ose: opened_by = '' if ose.errno == 16: if retry: util.SMlog('Device %s is busy, settle and one shot retry' % dev) util.pread2(['/usr/sbin/udevadm', 'settle']) return _openExclusive(dev, False) else: util.SMlog('Device %s is busy after retry' % dev)
util.SMlog('Opening device %s failed with %d' % (dev, ose.errno)) raise xs_errors.XenError( 'SRInUse', opterr=('Device %s in use, please check your existing ' + 'SRs for an instance of this device') % dev)
systemroot = util.getrootdev() rootdev = root.split(',')[0]
# Create PVs for each device for dev in root.split(','): if dev in [systemroot, '%s1' % systemroot, '%s2' % systemroot]: raise xs_errors.XenError('Rootdev', \ opterr=('Device %s contains core system files, ' \ + 'please use another device') % dev) if not os.path.exists(dev): raise xs_errors.XenError('InvalidDev', \ opterr=('Device %s does not exist') % dev)
f = _openExclusive(dev, True) os.close(f) try: # Overwrite the disk header, try direct IO first cmd = [util.CMD_DD, "if=/dev/zero", "of=%s" % dev, "bs=1M", "count=10", "oflag=direct"] util.pread2(cmd) except util.CommandException, inst: if inst.code == errno.EPERM: try: # Overwrite the disk header, try normal IO cmd = [util.CMD_DD, "if=/dev/zero", "of=%s" % dev, "bs=1M", "count=10"] util.pread2(cmd) except util.CommandException, inst: raise xs_errors.XenError('LVMWrite', \ opterr='device %s' % dev) else: raise xs_errors.XenError('LVMWrite', \ opterr='device %s' % dev)
if not (dev == rootdev): try: cmd_lvm([CMD_PVCREATE, "-ff", "-y", "--metadatasize", "10M", dev]) except util.CommandException, inst: raise xs_errors.XenError('LVMPartCreate', opterr='error is %d' % inst.code)
# Create VG on first device try: cmd_lvm([CMD_VGCREATE, "--metadatasize", "10M", vgname, rootdev]) except : raise xs_errors.XenError('LVMGroupCreate')
# Then add any additional devs into the VG for dev in root.split(',')[1:]: try: cmd_lvm([CMD_VGEXTEND, vgname, dev]) except util.CommandException, inst: # One of the PV args failed, delete SR try: cmd_lvm([CMD_VGREMOVE, vgname]) except: pass raise xs_errors.XenError('LVMGroupCreate')
try: cmd_lvm([CMD_VGCHANGE, "-an", vgname]) except util.CommandException, inst: raise xs_errors.XenError('LVMUnMount', opterr='errno is %d' % inst.code)
# End block
# Check PVs match VG try: for dev in root.split(','): txt = cmd_lvm([CMD_PVS, dev]) if txt.find(vgname) == -1: raise xs_errors.XenError('LVMNoVolume', \ opterr='volume is %s' % vgname) except util.CommandException, inst: raise xs_errors.XenError('PVSfailed', \ opterr='error is %d' % inst.code)
try: cmd_lvm([CMD_VGREMOVE, vgname])
for dev in root.split(','): cmd_lvm([CMD_PVREMOVE, dev]) except util.CommandException, inst: raise xs_errors.XenError('LVMDelete', \ opterr='errno is %d' % inst.code)
try: cmd_lvm([CMD_PVRESIZE, dev]) except util.CommandException, inst: util.SMlog("Failed to grow the PV, non-fatal")
"activate or deactivate VG 'path'" val = "n" if active: val = "y" text = cmd_lvm([CMD_VGCHANGE, "-a" + val, path])
else:
# see deactivateNoRefcount() except util.CommandException, e: if i >= LVM_FAIL_RETRIES - 1: raise util.SMlog("*** lvremove failed on attempt #%d" % i)
cmd_lvm([CMD_LVRENAME, path, newName], pread_func=util.pread)
val = "r" if not readonly: val += "w" ret = cmd_lvm([CMD_LVCHANGE, path, "-p", val], pread_func=util.pread)
(rc, stdout, stderr) = cmd_lvm([CMD_LVS, "--noheadings", path], pread_func=util.doexec) return rc == 0
sizeMB = size / (1024 * 1024) if confirm: cmd_lvm([CMD_LVRESIZE, "-L", str(sizeMB), path],util.pread3, "y\n") else: cmd_lvm([CMD_LVRESIZE, "-L", str(sizeMB), path], pread_func=util.pread)
opt = "--addtag" if not hidden: opt = "--deltag" cmd_lvm([CMD_LVCHANGE, opt, LV_TAG_HIDDEN, path])
cmd = [CMD_LVCHANGE, "-ay", path] text = cmd_lvm(cmd) if not _checkActive(path): raise util.CommandException(-1, str(cmd), "LV not activated") if refresh: # Override slave mode lvm.conf for this command os.environ['LVM_SYSTEM_DIR'] = MASTER_LVM_CONF text = cmd_lvm([CMD_LVCHANGE, "--refresh", path]) mapperDevice = path[5:].replace("-", "--").replace("/", "-") cmd = [CMD_DMSETUP, "table", mapperDevice] ret = util.pread(cmd) util.SMlog("DM table for %s: %s" % (path, ret.strip())) # Restore slave mode lvm.conf os.environ['LVM_SYSTEM_DIR'] = DEF_LVM_CONF
# LVM has a bug where if an "lvs" command happens to run at the same time # as "lvchange -an", it might hold the device in use and cause "lvchange # -an" to fail. Thus, we need to retry if "lvchange -an" fails. Worse yet, # the race could lead to "lvchange -an" starting to deactivate (removing # the symlink), failing to "dmsetup remove" the device, and still returning # success. Thus, we need to check for the device mapper file existence if # "lvchange -an" returns success. for i in range(LVM_FAIL_RETRIES): try: _deactivate(path) break except util.CommandException: if i >= LVM_FAIL_RETRIES - 1: raise util.SMlog("*** lvchange -an failed on attempt #%d" % i) _lvmBugCleanup(path)
text = cmd_lvm([CMD_LVCHANGE, "-an", path])
if util.pathexists(path): return True
util.SMlog("_checkActive: %s does not exist!" % path) symlinkExists = os.path.lexists(path) util.SMlog("_checkActive: symlink exists: %s" % symlinkExists)
mapperDeviceExists = False mapperDevice = path[5:].replace("-", "--").replace("/", "-") cmd = [CMD_DMSETUP, "status", mapperDevice] try: ret = util.pread2(cmd) mapperDeviceExists = True util.SMlog("_checkActive: %s: %s" % (mapperDevice, ret)) except util.CommandException: util.SMlog("_checkActive: device %s does not exist" % mapperDevice)
mapperPath = "/dev/mapper/" + mapperDevice mapperPathExists = util.pathexists(mapperPath) util.SMlog("_checkActive: path %s exists: %s" % \ (mapperPath, mapperPathExists))
if mapperDeviceExists and mapperPathExists and not symlinkExists: # we can fix this situation manually here try: util.SMlog("_checkActive: attempt to create the symlink manually.") os.symlink(mapperPath, path) except OSError, e: util.SMlog("ERROR: failed to symlink!") if e.errno != errno.EEXIST: raise if util.pathexists(path): util.SMlog("_checkActive: created the symlink manually") return True
return False
# the device should not exist at this point. If it does, this was an LVM # bug, and we manually clean up after LVM here
return
# destroy the dm device except util.CommandException, e: if i < LVM_FAIL_RETRIES - 1: util.SMlog("Failed on try %d, retrying" % i) try: util.pread(cmd_st, expect_rc=1) util.SMlog("_lvmBugCleanup: dm device {}" " removed".format(mapperDevice) ) break except: cmd_rm = cmd_rf time.sleep(1) else: # make sure the symlink is still there for consistency if not os.path.lexists(path): os.symlink(mapperPath, path) util.SMlog("_lvmBugCleanup: restored symlink %s" % path) raise e
os.unlink(mapperPath) util.SMlog("_lvmBugCleanup: deleted devmapper file %s" % mapperPath)
# delete the symlink os.unlink(path) util.SMlog("_lvmBugCleanup: deleted symlink %s" % path)
# mdpath is of format /dev/VG-SR-UUID/MGT # or in other words /VG_LOCATION/VG_PREFIXSR-UUID/MDVOLUME_NAME if not os.path.exists(mdpath): vgname = mdpath.split('/')[2] lvmCache = lvmcache.LVMCache(vgname) lvmCache.activateNoRefcount(MDVOLUME_NAME)
try: # remove devmapper entry using dmsetup cmd = [CMD_DMSETUP, "remove", path] cmd_lvm(cmd) return True except Exception, e: if not strict: cmd = [CMD_DMSETUP, "status", path] try: util.pread(cmd, expect_rc=1) return True except: pass # Continuining will fail and log the right way ret = util.pread2(["lsof", path]) util.SMlog("removeDevMapperEntry: dmsetup remove failed for file %s " \ "with error %s, and lsof ret is %s." % (path, str(e), ret)) return False |