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()
 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()