You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-2.2-install/pym/cl_distr.py

514 lines
19 KiB

#-*- coding: utf-8 -*-
from os.path import exists as pathexists
from os.path import dirname as pathdirname
from os.path import join as pathjoin
from random import choice
import string
import os
import types
from time import sleep
import re
import sys
from cl_utils import runOsCommand,isMount,removeDir
from shutil import copyfile
class DistributiveError(Exception):
def __init__(self,value,reason=None):
self.value = value
if type(reason) == types.ListType:
reason = "".join(reason)
self.reason = reason
def __str__(self):
if self.reason:
return repr("%s: '%s'"%(self.value,self.reason))
else:
return repr(self.value)
class Distributive(object):
"""Distributive object. Parent object for all distributive."""
mountError = "Cann't mount %s"
def __init__(self, parent=None):
self.childs = []
# if specified parent
if parent:
# save parent type for correct resource release
self.parent = type(parent)
# append this object as child to specified parent
parent.childs.append(self)
else:
self.parent = None
def detach(self):
"""Detach child distributive from parent.
At example: ArchiveDistributive create child DirectoryDistributive by
unpacking to temporary directory and at close method remove it. If the
removing directroy do not need, then need call detach in
DirectoryDistributive object
dist1 = ArchiveDistributive(file="/os.tar.bz2",mdirectory="/tmp/test")
dist2 = dist1.convertTo(DirectoryDistributive)
dist2.detach()
dist1.close()
...
"""
self.parent = None
def close(self):
"""Release all child distributive and release himself.
Need call this method at end work with object for right releasing
resources.
Example:
dist1 = PartitionDistributive(partition="/dev/sda2")
dist2 = dist1.convertTo(DirectoryDistributive)
dist1.close()
"""
# close all child
if self.childs:
for child in self.childs:
# check detach
if child.parent:
child.close()
self.childs = []
# if has parent
if self.parent:
self.parent().releaseChild(self)
self.parent = None
def releaseChild(self,child):
"""Method of release child state of distributive
At example: PartitionDistributive may be DirectoryDistributive by
mounting it to directory. But at end this directory must be
unmounted."""
pass
def _convertTo(self,typeDistributive):
"""Overridden"""
return None
def convertTo(self,typeDistributive):
"""Default c raise error about impossible convert object"""
obj = self._convertTo(typeDistributive)
if obj:
return obj
else:
raise DistributiveError("Cann't convert '%s' to '%s'" %
(self.__class__.__name__,
typeDistributive.__name__))
# def __del__(self):
# """Uncomment this method for automaticaly release all distributive
# instance"""
# self.close()
def _makeDirectory(self,path):
"""Make directory and parent.
If directory exists then return False else True"""
try:
parent = os.path.split(path)[0]
if not pathexists(parent):
self._makeDirectory(parent)
else:
if pathexists(path):
return False
os.mkdir(path)
return True
except (Exception,KeyboardInterrupt),e:
raise DistributiveError("Cann't create directory '%s'"%path,
reason=str(e))
def _removeDirectory(self,directory):
"""Remove directory and files contained in it"""
print "removeDirectory:",directory
try:
removeDir(directory)
except (Exception,KeyboardInterrupt),e:
raise DistributiveError("Unable remove directory from '%s'"
%directory, reason=str(e))
def _copyfile(self,infile,outfile):
try:
copyfile(infile,outfile)
except (Exception,KeyboardInterrupt),e:
raise DistributiveError("Cann't copy '%s' to '%s'"%
(infile,outfile),reason=str(e))
def copy(self,fromdir,todir):
"""Copy files from 'fromdir' directory to 'todir' directory"""
res,errmes = runOsCommand("rsync -a -x %s/ %s/" % (fromdir,todir))
if res == 0:
return True
else:
raise DistributiveError("Cann't copy file from '%s' to '%s'"%
(fromdir,todir),reason=errmes)
def rndString(self):
"""Get random string with len 8 char"""
return "".join([choice(string.ascii_letters+string.digits)
for i in xrange(0,8)])
def _mountToDirectory(self,file,directory,mountopts=""):
"""Mount squashfs to directory"""
if isMount(directory):
raise DistributiveError("Cann't mount to directory",
reason="Directory already mounted")
res,errmes = runOsCommand("/bin/mount %s %s %s"%
(mountopts,file,directory))
if res == 0:
return True
else:
try:
self._removeDirectory(directory)
except:
pass
raise DistributiveError(self.mountError%file,
reason=errmes)
def _umountDirectory(self,directory):
"""Umount directory"""
if isMount(directory):
for wait in [0,0.5,2,5]:
sleep(wait)
res,errmes = runOsCommand("/bin/umount %s"%directory)
if res == 0:
return True
raise DistributiveError("Cann't umount %s"%directory, reason=errmes)
else:
return True
def getMntDirectory(self,directory):
"""Get directory name, which will use for mounting or unpacking
If queried name is not free then to name append random string
"""
newDirectoryName = directory
while pathexists(newDirectoryName):
newDirectoryName = "%s.%s"%(directory,self.rndString())
return newDirectoryName
class DirectoryDistributive(Distributive):
def __init__(self,directory=None,parent=None):
super(DirectoryDistributive,self).__init__(parent=parent)
self.directory = directory
if not parent:
self._makeDirectory(self.directory)
def _convertTo(self,typeDistributive):
if typeDistributive == DirectoryDistributive:
return self
def installFrom(self, source):
"""Install distributive to directory from source distributive"""
if isinstance(source,ArchiveDistributive):
source.unpackTo(self.directory)
else:
# get source distributive as directory distributive
dFrom = source.convertTo(DirectoryDistributive)
# copy distributive from source to this
self.copy(dFrom.directory,self.directory)
class PartitionDistributive(Distributive):
def __init__(self,partition=None,parent=None,mdirectory="/mnt/calculate"):
super(PartitionDistributive,self).__init__(parent=parent)
self.partition = partition
self.mdirectory = mdirectory
def _mountPartition(self,partition,directory):
"""Mount partition to directory"""
self._makeDirectory(directory)
self._mountToDirectory(partition,directory)
def _umountPartition(self,directory):
"""Umount partition and remove directory"""
self._umountDirectory(directory)
self._removeDirectory(directory)
def releaseChild(self,child):
"""Umount child Directory distributive"""
if isinstance(child,DirectoryDistributive):
self._umountPartition(child.directory)
child.directory = None
def _convertToDirectory(self):
mdirectory = self.mdirectory
for child in self.childs:
if isinstance(child,DirectoryDistributive) and \
mdirectory in child.directory:
return child
mdirectory = self.getMntDirectory(mdirectory)
self._mountPartition(self.partition,mdirectory)
return DirectoryDistributive(directory=mdirectory,parent=self)
def _convertTo(self,typeDistributive):
if typeDistributive == DirectoryDistributive:
return self._convertToDirectory()
if typeDistributive == PartitionDistributive:
return self
def installFrom(self, source):
"""Install distributive to partition from source distributive"""
# get currect partition as directory
distrTo = self.convertTo(DirectoryDistributive)
# install into directroy distributive from source
distrTo.installFrom(source)
class ArchiveDistributive(Distributive):
def __init__(self,file=None,parent=None,mdirectory="/var/calculate/tmp/stage"):
super(ArchiveDistributive,self).__init__(parent=parent)
self.file = file
self.mdirectory = mdirectory
def _detectArchive(self,file):
"""Detect archive by "/usr/bin/file" command
Return bzip2,gzip,7z or None
"""
res,mes = runOsCommand("/usr/bin/file %s"%file)
if "bzip2 compressed data" in mes:
return "bzip2"
elif "gzip compressed data" in mes:
return "gzip"
elif "7-zip archive data" in mes:
return "7z"
else:
return None
def _unpackArchive(self,file,directory):
"""Unpack archive"""
# archive is exists
if not pathexists(file):
raise DistributiveError("File '%s' not found"%file)
# detect type archive
archiveType = self._detectArchive(file)
# make directory if archive was detected normally
if archiveType:
self._makeDirectory(directory)
# unpack archive
if archiveType == "7z":
res,mes = runOsCommand("7za x -so %s | tar xf - -C %s/"%
(file,directory))
elif archiveType == "bzip2":
res,mes = runOsCommand("tar xjf %s -C %s/"% (file,directory))
elif archiveType == "gzip":
res,mes = runOsCommand("tar xf %s -C %s/"%(file,directory))
else:
raise DistributiveError("Unknown archive type by '%s'"%file)
def unpackTo(self,directory):
"""Unpack currect archive to directory"""
self._unpackArchive(self.file,directory)
def _convertToDirectory(self):
"""Get archive as directory (unpack to directory)"""
# check may be the archive already unpacked
mdirectory = self.mdirectory
for child in self.childs:
if isinstance(child,DirectoryDistributive) and \
mdirectory in child.directory:
return child
# get temporary directory for unpacking
mdirectory = self.getMntDirectory(mdirectory)
dirdist = DirectoryDistributive(directory=mdirectory,parent=self)
self._unpackArchive(self.file,mdirectory)
return dirdist
def releaseChild(self,child):
"""Remove child Directory distributive"""
if isinstance(child,DirectoryDistributive):
self._removeDirectory(child.directory)
child.directory = None
def _convertTo(self,typeDistributive):
"""Support DirectroyDistributive and ArchiveDistributive"""
if typeDistributive == DirectoryDistributive:
return self._convertToDirectory()
if typeDistributive == ArchiveDistributive:
return self
def packToArchive(self,directory,file):
res,errmes = runOsCommand("tar cf %s -C %s ."%(file,directory))
if res != 0:
raise DistributiveError("Cann't create archive '%s'"%file,
reason=errmes)
def installFrom(self, source):
"""Install distributive to partition from source distributive"""
# get source distributive as directory distributive
dFrom = source.convertTo(DirectoryDistributive)
# install into directroy distributive from source
self.packToArchive(dFrom.directory, self.file)
class SquashDistributive(Distributive):
def __init__(self,file=None,parent=None,mdirectory="/mnt/livecd"):
super(SquashDistributive,self).__init__(parent=parent)
self.file = file
self.mdirectory = mdirectory
def _mountSquash(self,file,directory):
"""Mount squashfs to directory"""
self._makeDirectory(directory)
self._mountPartition(file,directory,mountopts="-o loop -t squashfs")
def _umountSquash(self,directory):
self._umountDirectory(directory)
self._removeDirectory(directory)
def _convertToDirectory(self):
mdirectory = self.mdirectory
for child in self.childs:
if isinstance(child,DirectoryDistributive) and \
mdirectory in child.directory:
return child
mdirectory = self.getMntDirectory(mdirectory)
self._mountSquash(self.file,mdirectory)
return DirectoryDistributive(directory=mdirectory,parent=self)
def releaseChild(self,child):
"""Umount child Directory distributive"""
if isinstance(child,DirectoryDistributive):
self._umountSquash(child.directory)
child.directory = None
def _convertTo(self,typeDistributive):
if typeDistributive == DirectoryDistributive:
return self._convertToDirectory()
elif typeDistributive == SquashDistributive:
return self
def packToSquash(self,directory,file):
res,errmes = runOsCommand("/usr/bin/mksquashfs %s/ %s"%
(directory,file))
if res != 0:
raise DistributiveError("Cann't create squashfs '%s'"%file,
reason=errmes)
def installFrom(self, source):
"""Install distributive to partition from source distributive"""
# get source distributive as directory distributive
dFrom = source.convertTo(DirectoryDistributive)
# install into directroy distributive from source
self.packToSquash(dFrom.directory, self.file)
class IsoDistributive(Distributive):
reLive = re.compile(r"^live[^.]*(\.(\d+))?\.squashfs$",re.S)
def __init__(self,file=None,parent=None,mdirectory="/mnt/cdrom",
bdirectory="/var/calculate/tmp/iso"):
super(IsoDistributive,self).__init__(parent=parent)
self.file = file
self.mdirectory = mdirectory
self.bdirectory = bdirectory
def _mountIso(self,file,directory):
self._makeDirectory(directory)
self._mountToDirectory(file,directory,mountopts="-o loop")
def _umountIso(self,directory):
self._umountDirectory(directory)
self._removeDirectory(directory)
def _getLastLive(self,directory):
curfile = None
curnum = -1
for file in os.listdir(directory):
res = self.reLive.search(i)
if res:
if res.groups()[1]:
num = int(res.groups()[1])
else:
num = 0
if num > curnum:
curfile = file
curnum = num
return curfile
def _convertToSquash(self):
mdirectory = self.mdirectory
for child in self.childs:
if isinstance(child,SquashDistributive) and \
mdirectory in child.file:
return child
mdirectory = self.getMntDirectory(mdirectory)
self._mountIso(self.file,mdirectory)
fileLive = self._getLastLive(mdirectory)
if not fileLive:
raise DistributiveError("Iso %s doesn't contain live image" %
self.file)
return SquashDistributive(file=pathjoin(mdirectory,fileLive),
parent=self)
def releaseChild(self,child):
"""Umount child Directory distributive"""
if isinstance(child,SquashDistributive):
self._umountIso(pathdirname(child.file))
child.directory = None
def _convertTo(self,typeDistributive):
if typeDistributive == DirectoryDistributive:
return self.convertTo(SquashDistributive).\
convertTo(DirectoryDistributive)
if typeDistributive == SquashDistributive:
return self._Squash()
if typeDistributive == IsoDistributive:
return self
def prepareIso(self,directory):
print("apply iso templates to %s/"%directory)
self._makeDirectory(pathjoin(directory,"isolinux"))
self._copyfile("/usr/share/syslinux/isolinux.bin",
pathjoin(directory,"isolinux/isolinux.bin"))
def packToIso(self,directory,file):
# remove previous version of iso
try:
if pathexists(file):
os.unlink(file)
except (Exception,KeyboardInterrupt),e:
raise DistributiveError("Cann't remove %s"%file,reason=str(e))
res,errmes = runOsCommand("/usr/bin/mkisofs -b isolinux/isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table -iso-level 4 -hide boot.catalog -o %s %s/"%
(file,directory))
if res == 0:
return True
else:
raise DistributiveError("Cann't create iso image %s"%file,
reason=errmes)
def installFrom(self, source):
"""Install distributive to partition from source distributive"""
# make temporary directory for creating iso image
isoDirectory = self.bdirectory
isoDirectory = self.getMntDirectory(isoDirectory)
self._makeDirectory(isoDirectory)
try:
# getting squash from source
if isinstance(source,SquashDistributive):
self._copyfile(source.file,
pathjoin(isoDirectory,"livecd.squashfs"))
else:
distDirectory = source.convertTo(DirectoryDistributive)
squashDistr = SquashDistributive(
file=pathjoin(isoDirectory,"livecd.squashfs"))
squashDistr.installFrom(distDirectory)
# prepare iso
self.prepareIso(directory)
# pack iso
self.packToIso(isoDirectory, self.file)
# remove temporary directory after creating iso image
self._removeDirectory(isoDirectory)
except DistributiveError,e:
self._removeDirectory(isoDirectory)
raise e
except KeyboardInterrupt,e:
self._removeDirectory(isoDirectory)
raise DistributiveError("Keyboard interrupt")