class HostDisk(Disk): log=ComLog.getLogger("comoonics.ComDisk.HostDisk") LABEL_PREFIX="LABEL=" TAGNAME="disk" class DeviceNameResolver(object): key=None def getKey(self): return self.key def resolve(self, value): pass class DeviceNameResolverError(ComException): pass resolver=dict() # static methods def map2realDMName(device, prefixpath="/dev/mapper"): """ Maps the given devicemapper name to the real one (first created). Should be executed on every proper device mapper device. """ if os.path.islink(device): # more recent versions of multipath will not use device files but symbolic links to the # dm-* devices. Those links are relative and need therefore be converted to absolute # paths. return os.path.realpath(os.path.join(os.path.dirname(device), os.readlink(device))) else: cmd="%s info -c --noheadings -o name %s" %(CMD_DMSETUP, device) try: return os.path.join(prefixpath, ComSystem.execLocalOutput(cmd, True, "")[:-1]) except ComSystem.ExecLocalException: ComLog.debugTraceLog() return device map2realDMName=staticmethod(map2realDMName) def __init__(self, *params): """ Disk represents a raw disk Possible constructors: __init__(self, element, doc=None) type(element)=Node __init__(self, name, doc=None) type(name)==str """ if len(params)==1: doc=xml.dom.getDOMImplementation().createDocument(None, self.TAGNAME, None) elif len(params)==2: doc=params[1] else: raise exceptions.TypeError("""Wrong number of arguments to constructor of HostDisk. Either __init__(self, element, doc=None) or __init__(self, name, doc=None) are supported.""") if isinstance(params[0], basestring): element=doc.createElement(self.TAGNAME) element.setAttribute("name", params[0]) else: element=params[0] super(HostDisk, self).__init__(element, doc) self.log.debug("__init__") self.devicename=None self.stabilizedfile="/proc/partitions" self.stabilizedtype="hash" self.stabilizedgood=2 self.partitions=dict() def is_lvm(self): return hasattr(self, "volumegroup") and hasattr(self, "logicalvolume") def is_lvm_activated(self): return self.is_lvm() and self.logicalvolume.isActivated() def lvm_vg_activate(self): self.volumegroup.activate() def lvm_vg_deactivate(self): self.volumegroup.deactivate() def pv_deactivate(self, devicename=None): """ Deactivates all vgs held by this disk (including partitions) @param devicename: if given only this device will be taken into account """ if not devicename: for devicename in self.getDeviceNames(): self.pv_deactivate(devicename) if not PhysicalVolume.isPV(devicename): return pvs=LinuxVolumeManager.pvlist(pvname=devicename) for pv in pvs: if pv.parentvg: for lv in LinuxVolumeManager.lvlist(pv.parentvg): if lv.isActivated(): pv.parentvg.deactivate() break def pv_activate(self, devicename=None): """ Activates all vgs hold by this disk/or given device """ if not devicename: for devicename in self.getDeviceNames(): self.pv_activate(devicename) pvs=LinuxVolumeManager.pvlist(pvname=devicename) for pv in pvs: if pv.parentvg: for lv in LinuxVolumeManager.lvlist(pv.parentvg): if lv.isActivated(): pv.parentvg.deactivate() break def getLog(self): return self.log def exists(self): return ComSystem.execMethod(os.path.exists, self.getDeviceName()) def sameSize(self): """ """ return self.getAttributeBoolean("samesize", False) def getDeviceName(self): """ returns the Disks device name (e.g. /dev/sda) """ if hasattr(self, "devicename") and self.devicename != None: return self.devicename else: return self.getAttribute("name") def getDevicePath(self): return self.getDeviceName() def getDeviceNames(self, notme=False): """ Returns a list of devicenames for this devices and all partitions. @param notme: do not include the disk devicename but only the paritions. """ devicenames=list() basedevice=HostDisk.map2realDMName(self.getDeviceName()) if not notme: devicenames.append(basedevice) self.initFromDisk() for part in self.partitions.keys(): devicenames.append(basedevice+self.getPartitionDelim()+part) return devicenames def getPartitionDelim(self): if self.isDMMultipath(): return DEVICEMAPPER_PART_DELIM else: return "" def getSize(self): """ returns the size of the disk in sectors""" pass def refByLabel(self): """ is disk referenced by Label? returns True or False Format <disk name="LABEL=..."/> """ return self.getDeviceName()[:len(self.LABEL_PREFIX)]==self.LABEL_PREFIX def resolveDeviceNameByKeyValue(self, key, value): """ resolves a device name by searching for a method to resolve it by key and the resolve via value as Parameter """ if self.resolver.has_key(key): name=self.resolver[key].resolve(value) if name and name != "": self.devicename=name else: raise HostDisk.DeviceNameResolverError("Could not resolve device \"%s\" for type \"%s\"" %(value, key)) else: raise HostDisk.DeviceNameResolverError("Could not find resolver for device referrenced by %s=%s" %(key, value)) def resolveDeviceName(self): """ resolves the given devicenames and returns a list of commands to execute to get device operational. """ journal_cmds=list() if len(self.getDeviceName().split("="))==2: (key, value)=self.getDeviceName().split("=")[:2] self.resolveDeviceNameByKeyValue(key, value) if LogicalVolume.isValidLVPath(self.getDeviceName()): lv=LogicalVolume(self.getDeviceName()) lv.init_from_disk() self.initLVM() self.lvm_activated=False if self.getAttribute("options", "") != "skipactivate" and not self.is_lvm_activated(): self.lvm_vg_activate() self.lvm_activated=True journal_cmds.append("lvm_vg_activate") elif self.getAttribute("options", "") != "skipdeactivate": devicenames=list() devicename=HostDisk.map2realDMName(self.getDeviceName()) devicenames.append(devicename) self.initFromDisk() if self.isDMMultipath(): partdelim=DEVICEMAPPER_PART_DELIM else: partdelim="" for partition in self.getAllPartitions(): devicenames.append("%s%s%s" %(devicename, partdelim, partition.getAttribute("name"))) for devicename in devicenames: if PhysicalVolume.isPV(devicename): journal_cmds.append("pv_deactivate") return journal_cmds def initLVM(self): (vgname, lvname)=LogicalVolume.splitLVPath(self.getDeviceName()) self.volumegroup=VolumeGroup(vgname, self.getDocument()) self.logicalvolume=LogicalVolume(lvname, self.volumegroup, self.getDocument()) self.volumegroup.init_from_disk() self.logicalvolume.init_from_disk() def initFromDisk(self): """ reads partition information from the disk and fills up DOM with new information """ HostDisk.log.debug("initFromDisk()") #FIXME: create LabelResolver if self.refByLabel(): pass if not self.exists(): raise ComException("Device %s not found or no valid device!" % self.getDeviceName()) import ComParted phelper=ComParted.getInstance() for partition in phelper.initFromDisk(self.getDeviceName()): self.addPartition(Partition(partition, self.getDocument())) def restore(self): if hasattr(self, "lvm_activated") and self.lvm_activated: self.lvm_vg_deactivate() def addPartition(self, part): """ adds a partition to the existing ones. Already existing ones will be overwritten """ added=False self.partitions[part.getAttribute("name")]=part for epartition in self.getElement().getElementsByTagName(Partition.TAGNAME): if epartition.getAttribute("name") == part.getAttribute("name"): self.getElement().replaceChild(part.getElement(), epartition) added=True if not added: self.appendChild(part) def hasPartition(self, part): """ Returns true if partition (Partition object) exists as partion in this disk """ return self.partitions[part.getAttribute("name")] def removePartition(self, part): """ Removes the given partition from the partitions """ if self.hasPartition(part): del self.partitions[part.getAttribute("name")] for epartition in self.getElement().getElementsByTagName(Partition.TAGNAME): if epartition.getAttribute("name") == part.getAttribute("name"): self.getElement().removeChild(epartition) def createPartitions(self): """ creates new partition table """ if not self.exists(): raise ComException("Device %s not found" % self.getDeviceName()) import ComParted phelper=ComParted.getInstance() phelper.createPartitions(self.getDeviceName(), self.getAllPartitions(), self.sameSize()) self.stabilize() def stabilize(self): self.commit() #dev.sync() #dev.close() # run partx if the device is a multipath device self.log.debug("ComHostDisk: checking for multipath devices") if self.isDMMultipath(): devicename=HostDisk.map2realDMName(self.getDeviceName()) self.log.debug("Device %s is a dm_multipath device, adding partitions" %devicename) __cmd=CMD_KPARTX + " " + OPTS_KPARTX +" -d " + devicename try: __ret = ComSystem.execLocalOutput(__cmd, True, "") self.log.debug(__ret) __cmd=CMD_KPARTX + " " + OPTS_KPARTX + " -a " + devicename __ret = ComSystem.execLocalOutput(__cmd, True, "") self.log.debug(__ret) #FIXME: crappy fix to give os some time to create devicefiles. time.sleep(10) except ComSystem.ExecLocalException, ele: ComLog.debugTraceLog(self.log) self.log.debug("Could not execute %s. Error %s" %(ele.cmd, ele))
class HostDisk(Disk): log=ComLog.getLogger("comoonics.ComDisk.HostDisk") LABEL_PREFIX="LABEL=" TAGNAME="disk" class DeviceNameResolver(object): key=None def getKey(self): return self.key def resolve(self, value): pass class DeviceNameResolverError(ComException): pass resolver=dict() def __init__(self, *params): """ Disk represents a raw disk Possible constructors: __init__(self, element, doc=None) type(element)=Node __init__(self, name, doc=None) type(name)==str """ if len(params)==1: doc=xml.dom.getDOMImplementation().createDocument(None, self.TAGNAME, None) elif len(params)==2: doc=params[1] else: raise exceptions.TypeError("""Wrong number of arguments to constructor of HostDisk. Either __init__(self, element, doc=None) or __init__(self, name, doc=None) are supported.""") if isinstance(params[0], basestring): element=doc.createElement(self.TAGNAME) element.setAttribute("name", params[0]) else: element=params[0] super(HostDisk, self).__init__(element, doc) self.log.debug("__init__") self.devicename=None self.stabilizedfile="/proc/partitions" self.stabilizedtype="hash" self.stabilizedgood=2 def is_lvm(self): return hasattr(self, "volumegroup") and hasattr(self, "logicalvolume") def is_lvm_activated(self): return self.is_lvm() and self.logicalvolume.isActivated() def lvm_vg_activate(self): self.volumegroup.activate() def lvm_vg_deactivate(self): self.volumegroup.deactivate() def getLog(self): return self.log def exists(self): return ComSystem.execMethod(os.path.exists, self.getDeviceName()) def sameSize(self): """ """ return self.getAttributeBoolean("samesize", False) def getDeviceName(self): """ returns the Disks device name (e.g. /dev/sda) """ if hasattr(self, "devicename") and self.devicename != None: return self.devicename else: return self.getAttribute("name") def getDevicePath(self): return self.getDeviceName() def getSize(self): """ returns the size of the disk in sectors""" pass def refByLabel(self): """ is disk referenced by Label? returns True or False Format <disk name="LABEL=..."/> """ return self.getDeviceName()[:len(self.LABEL_PREFIX)]==self.LABEL_PREFIX def resolveDeviceNameByKeyValue(self, key, value): """ resolves a device name by searching for a method to resolve it by key and the resolve via value as Parameter """ if self.resolver.has_key(key): name=self.resolver[key].resolve(value) if name and name != "": self.devicename=name else: raise HostDisk.DeviceNameResolverError("Could not resolve device \"%s\" for type \"%s\"" %(value, key)) else: raise HostDisk.DeviceNameResolverError("Could not find resolver for device referrenced by %s=%s" %(key, value)) def resolveDeviceName(self): """ resolves the given devicenames and returns a list of executed commands. """ journal_cmds=list() if len(self.getDeviceName().split("="))==2: (key, value)=self.getDeviceName().split("=")[:2] self.resolveDeviceNameByKeyValue(key, value) if LogicalVolume.isValidLVPath(self.getDeviceName()): self.initLVM() self.lvm_activated=False if self.getAttribute("options", "") != "skipactivate" and not self.is_lvm_activated(): self.lvm_vg_activate() self.lvm_activated=True journal_cmds.append("lvm_vg_activate") return journal_cmds def initLVM(self): (vgname, lvname)=LogicalVolume.splitLVPath(self.getDeviceName()) self.volumegroup=VolumeGroup(vgname, self.getDocument()) self.logicalvolume=LogicalVolume(lvname, self.volumegroup, self.getDocument()) self.volumegroup.init_from_disk() self.logicalvolume.init_from_disk() def initFromDisk(self): """ reads partition information from the disk and fills up DOM with new information """ HostDisk.log.debug("initFromDisk()") #FIXME: create LabelResolver if self.refByLabel(): pass if not self.exists(): raise ComException("Device %s not found or no valid device!" % self.getDeviceName()) try: self.initFromDiskParted() except ImportError: self.initFromDiskPartedCmd() def initFromDiskPartedCmd(self): raise ImportError("No pyparted found. You might want to install pyparted.") def initFromDiskParted(self): import parted import ComParted phelper=ComParted.PartedHelper() dev=parted.PedDevice.get(self.getDeviceName()) try: disk=parted.PedDisk.new(dev) partlist=phelper.get_primary_partitions(disk) for part in partlist: self.appendChild(Partition(part, self.getDocument())) except parted.error: HostDisk.log.debug("no partitions found") def restore(self): if hasattr(self, "lvm_activated") and self.lvm_activated: self.lvm_vg_deactivate() def createPartitions(self): """ creates new partition table """ try: self.createPartitionsParted() except ImportError: self.createPartitionsPartedCmd() def createPartitionsPartedCmd(self): pass def createPartitionsParted(self): import parted import ComParted if not self.exists(): raise ComException("Device %s not found" % self.getDeviceName()) phelper=ComParted.PartedHelper() #IDEA compare the partition configurations for update #1. delete all aprtitions dev=parted.PedDevice.get(self.getDeviceName()) try: disk=parted.PedDisk.new(dev) disk.delete_all() except parted.error: #FIXME use generic disk types disk=dev.disk_new_fresh(parted.disk_type_get("msdos")) # create new partitions for com_part in self.getAllPartitions(): type=com_part.getPartedType() if self.sameSize(): size=com_part.getPartedSize(dev) else: size=com_part.getPartedSizeOptimum(dev) flags=com_part.getPartedFlags() self.log.debug("creating partition: size: %i" % size ) phelper.add_partition(disk, type, size, flags) disk.commit() self.commit() #dev.sync() #dev.close() # run partx if the device is a multipath device self.log.debug("ComHostDisk: checking for multipath devices") if self.isDMMultipath(): self.log.debug("Device %s is a dm_multipath device, adding partitions" %self.getDeviceName()) __cmd=CMD_KPARTX + " -d " + self.getDeviceName() try: __ret = ComSystem.execLocalOutput(__cmd, True, "") self.log.debug(__ret) __cmd=CMD_KPARTX + " -a " + self.getDeviceName() __ret = ComSystem.execLocalOutput(__cmd, True, "") self.log.debug(__ret) #FIXME: crappy fix to give os some time to create devicefiles. time.sleep(10) except ComSystem.ExecLocalException, ele: ComLog.debugTraceLog(self.log) self.log.debug("Could not execute %s. Error %s" %(ele.cmd, ele))
def initLVM(self): (vgname, lvname)=LogicalVolume.splitLVPath(self.getDeviceName()) self.volumegroup=VolumeGroup(vgname, self.getDocument()) self.logicalvolume=LogicalVolume(lvname, self.volumegroup, self.getDocument()) self.volumegroup.init_from_disk() self.logicalvolume.init_from_disk()