#!/usr/bin/python import re,os,sys import commands from xml.dom import minidom from xml.dom.ext import PrettyPrint sys.path.append('../new_partition/') import partition_data as p_d import interface_partition # xml file names install_xml = '/var/install/install.xml' config_xml = '../xml/config.xml' def to_xml_attr(doc, node, cls, name): ''' This method is called by to_xml. Its function is to create an attribute, and set its value based on xml data member doc - xml document node - xml node cls - python class/python instance name - attribute name''' attr = doc.createAttribute(name) attr.value = getattr(cls, name) node.setAttributeNode(attr) class SerialNumber: ''' serial number ''' value = '' @staticmethod def init_from_xml(node): ''' set value based on xml node ''' SerialNumber.value = node.firstChild.data.encode('ascii') @staticmethod def to_xml(doc, p_node): ''' write SerialNumber into xml doc - xml document instance p_node - xml node (parent node)''' sn = doc.createElement('serial-number') data = doc.createTextNode(SerialNumber.value) sn.appendChild(data) p_node.appendChild(sn) class Partition: ''' disk partition ''' unit='' dict={} def __init__(self, dev, st, sz, tp, fs, fg, fr): ''' Partition init function ''' self.device = dev self.start = st self.size = sz self.type = tp self.filesystem = fs self.flags = fg self.from_os = fr Partition.dict[dev] = self @staticmethod def check_partitions(): cmd = "grep [a-zA-Z][0-9] /proc/partitions>/dev/null" ret = os.system(cmd) return ret @staticmethod def init_from_os(): ''' create a Partition instance from hardware info''' Partition.unit='GB' cmd_cat = 'cat /proc/partitions' st,o = commands.getstatusoutput(cmd_cat) if st: print "Error cat : command not found or /proc/partitions dosen't exsit" return # an example of `cat /proc/partitions` # major minor #blocks name # # 8 0 488386584 sda # 8 1 97659103 sda1 # 8 2 1951897 sda2 # 8 3 97659135 sda3 # 8 4 291113865 sda4 # 8 16 244197527 sdb # 8 17 62918541 sdb1 # 8 18 4200997 sdb2 # 8 19 1 sdb3 # 8 21 1238016 sdb5 # 9 0 803136 md0 l = [ s.split()[-1] for s in o.splitlines() if re.match(r'\s*\d+', s)] # devices : 1) sda, sdb(first if ), or md0 (second if) for d in [ i for i in l if not re.search(r'\d+', i) or re.search(r'([a-zA-Z]+)', i).group(1) not in l]: st,o=commands.getstatusoutput('LANG=c parted /dev/%s unit %s print'%(d,Partition.unit)) if st: # if a raid device wasn't formated, exec "parted it unit GB print" # command will return a error info. continue # an example of o's content # Model: ATA Hitachi HDS72105 (scsi) # Disk /dev/sda: 500GB # Sector size (logical/physical): 512B/512B # Partition Table: msdos # # Number Start End Size Type File system Flags # 1 0.00GB 100GB 100GB primary ext3 boot # 2 100GB 102GB 2.00GB primary linux-swap(v1) # 3 102GB 202GB 100GB primary ext3 # 4 202GB 500GB 298GB primary ext3 located = False for s in o.splitlines(): # Only match number, start, end, and size, that's enough. # And when in raid case, no type appears. title_p = re.compile('Number\s+Start\s+End\s+Size\s') if title_p.match(s): nm_i = s.find('Number') st_i = s.find('Start') end_i = s.find('End') sz_i = s.find('Size') tp_i = s.find('Type') fs_i = s.find('File system') flg_i= s.find('Flags') if tp_i < 0: tp_i=fs_i located = True elif located: Partition(d[:2] == 'md' and d or d+s[nm_i:st_i].strip(), # device name s[st_i:end_i].strip().rstrip(Partition.unit), # start s[sz_i:tp_i].strip().rstrip(Partition.unit), # size s[tp_i:fs_i].strip(), # type re.search('swap', s[fs_i:flg_i]) and 'swap' or s[fs_i:flg_i].strip(), # file system s[flg_i:].strip(), # flags 'yes' ) @staticmethod def init_from_xml(node): ''' create Partition instances from xml node ''' Partition.unit = node.attributes['unit'].value.encode('ascii') for p in node.childNodes: if p.nodeType == node.ELEMENT_NODE and p.nodeName == 'partition': Partition(p.attributes['device'].value.encode('ascii'),\ p.attributes['start'].value.encode('ascii'),\ p.attributes['size'].value.encode('ascii'),\ p.attributes['type'].value.encode('ascii'),\ p.attributes['file-system'].value.encode('ascii'),\ p.attributes['flags'].value.encode('ascii'),\ p.attributes['from_os'].value.encode('ascii')) @staticmethod def to_xml(doc, p_node): ''' write all Partition instance into xml doc - xml document instance p_node - xml node (parent node)''' pts = doc.createElement("partitions") unit_attr = doc.createAttribute('unit') unit_attr.value = Partition.unit pts.setAttributeNode(unit_attr) P_keys = Partition.dict.keys() P_keys.sort() for k in P_keys: p = Partition.dict[k] pt = doc.createElement('partition') dev_attr = doc.createAttribute('device') start_attr = doc.createAttribute('start') size_attr = doc.createAttribute('size') type_attr = doc.createAttribute('type') fs_attr = doc.createAttribute('file-system') flags_attr = doc.createAttribute('flags') from_attr = doc.createAttribute('from_os') dev_attr.value = p.device start_attr.value = p.start size_attr.value = p.size type_attr.value = p.type fs_attr.value = p.filesystem flags_attr.value = p.flags from_attr.value = p.from_os pt.setAttributeNode(dev_attr) pt.setAttributeNode(start_attr) pt.setAttributeNode(size_attr) pt.setAttributeNode(type_attr) pt.setAttributeNode(fs_attr) pt.setAttributeNode(flags_attr) pt.setAttributeNode(from_attr) pts.appendChild(pt) p_node.appendChild(pts) @staticmethod def get_size(dev): try: return Partition.dict[dev].size except: return None class Raid: ''' raid information ''' dict = {} def __init__(self, dev, from_os, level, mp, fmt, filesystem,a_devs, s_devs=[]): ''' Raid init function ''' self.device = dev self.from_os = from_os self.level = level self.mp = mp self.fmt = fmt self.filesystem = filesystem self.active_components = a_devs self.spare_components = s_devs Raid.dict[dev] = self @staticmethod def init_from_os(): cmd = 'cat /proc/mdstat' st, o = commands.getstatusoutput(cmd) if st: return dev_p = re.compile(r''' ^(md\d+)\s*: # md device \s*active\s* # "active" (\w+)\s* # raid type ''', re.VERBOSE) for s in o.splitlines(): dev_res = dev_p.split(s) if len(dev_res)>1: # matched # dev_res[0] is '' # dev_res[2] is 'raidX' raid_dev = dev_res[1] raid_level = dev_res[2][4:] act_cmpts =[] spr_cmpts =[] for ss in dev_res[3].split(): if re.search(r'\(S\)', ss): spr_cmpts.append(ss[:ss.index('[')]) else: act_cmpts.append(ss[:ss.index('[')]) Raid(raid_dev, "yes", raid_level, '', 'no', '', act_cmpts, spr_cmpts) @staticmethod def add_component(node, l): ''' add component devices (in xml node) to list node - xml node l - list ''' for sub in node.childNodes: if sub.nodeType == sub.ELEMENT_NODE and sub.nodeName == 'component': l.append(sub.firstChild.data.encode('ascii')) @staticmethod def init_from_xml(node): ''' create Raid instances from xml node ''' for e in node.childNodes: if e.nodeType == e.ELEMENT_NODE and e.nodeName == 'raid': raid_dev = e.attributes['device'].value raid_from = e.attributes['from_os'].value raid_level = e.attributes['level'].value raid_mp = e.attributes['mp'].value raid_fmt = e.attributes['fmt'].value raid_fs = e.attributes['filesystem'].value act_cmpts = [] spr_cmpts = [] for sub_e in e.childNodes: if sub_e.nodeType == sub_e.ELEMENT_NODE: if sub_e.nodeName == 'active': Raid.add_component(sub_e, act_cmpts) elif sub_e.nodeName == 'spare': Raid.add_component(sub_e, spr_cmpts) Raid(raid_dev, raid_from, raid_level, raid_mp, raid_fmt, raid_fs, act_cmpts, spr_cmpts) @staticmethod def to_xml(doc, p_node): ''' write all raid instance into xml doc - xml document instance p_node - xml node (parent node) ''' raids = doc.createElement('raids') R_keys = Raid.dict.keys() R_keys.sort() for k in R_keys: r = Raid.dict[k] rd = doc.createElement('raid') rd_dev_attr = doc.createAttribute('device') rd_dev_attr.value = r.device rd.setAttributeNode(rd_dev_attr) rd_from_attr = doc.createAttribute('from_os') rd_from_attr.value = r.from_os rd.setAttributeNode(rd_from_attr) rd_level_attr = doc.createAttribute('level') rd_level_attr.value = r.level rd.setAttributeNode(rd_level_attr) rd_mp_attr = doc.createAttribute('mp') rd_mp_attr.value = r.mp rd.setAttributeNode(rd_mp_attr) rd_fmt_attr = doc.createAttribute('fmt') rd_fmt_attr.value = r.fmt rd.setAttributeNode(rd_fmt_attr) rd_fs_attr = doc.createAttribute('filesystem') rd_fs_attr.value = r.filesystem rd.setAttributeNode(rd_fs_attr) rd_act_elem = doc.createElement('active') for act_c in r.active_components: act_c_e = doc.createElement('component') act_c_tn = doc.createTextNode(act_c) act_c_e.appendChild(act_c_tn) rd_act_elem.appendChild(act_c_e) rd.appendChild(rd_act_elem) rd_spr_elem = doc.createElement('spare') for spr_c in r.spare_components: spr_c_e = doc.createElement('component') spr_c_tn = doc.createTextNode(spr_c) spr_c_e.appendChild(spr_c_tn) rd_spr_elem.appendChild(spr_c_e) rd.appendChild(rd_spr_elem) raids.appendChild(rd) p_node.appendChild(raids) #ri_tk_cmd.py use @staticmethod def get_size(dev): ''' calculate raid device size ''' rd = Raid.dict[dev] Min = min([ float(interface_partition.get_num(p_d.Partition.dict[p_d.Partition.get_disk_from_partition('/dev/'+d)]\ ['partition']['/dev/'+d]['size'])) for d in rd.active_components]) Sum = sum([ float(interface_partition.get_num(p_d.Partition.dict[p_d.Partition.get_disk_from_partition('/dev/'+d)]\ ['partition']['/dev/'+d]['size'])) for d in rd.active_components]) #if rd.level == '0': return str(interface_partition.pretty_unit(Min*len(rd.active_components))) #elif rd.level == '1': return str(interface_partition.pretty_unit(Min*len(rd.active_components)/2)) if rd.level == '0': return str(interface_partition.pretty_unit(Sum)) elif rd.level == '1': return str(interface_partition.pretty_unit(Min)) elif rd.level == '5': return str(interface_partition.pretty_unit(Min*(len(rd.active_components)-1))) @staticmethod def get_next_device(): ''' get next available raid device name ''' num_p = re.compile(r'md(\d+)') numbers = [ int(num_p.match(r).groups()[0]) for r in Raid.dict.keys()] numbers.sort() if numbers: return 'md%d' %(int(numbers[-1])+1) return 'md0' @staticmethod def dev_in_raid(): """if the device in raid or not""" devices_in_raid=set() for r in Raid.dict.values(): devices_in_raid.update(r.active_components) devices_in_raid.update(r.spare_components) return devices_in_raid @staticmethod def get_raid_from_partition(partition): for raid in Raid.dict.keys(): for p in Raid.dict[raid].active_components + Raid.dict[Raid].spare.components: if p == partition: return raid class MountPoint: ''' mount-points ''' dict={} def __init__(self, dev, dir='', fs='', fm='no'): self.device = dev self.directory = dir self.filesystem = fs self.format = fm MountPoint.dict[dev]=self @staticmethod def change(dev, dir, fs, fm): mp = MountPoint.dict[dev] mp.directory = dir mp.filesystem = fs mp.format = fm @staticmethod def init_from_internal(): ''' init MountPoint from internal class Partition and class Raid ''' # add raid device in dev_in_raid dev_in_raid = Raid.dev_in_raid() for dev in set([ k for k in Partition.dict.keys() if not re.search('extended',Partition.dict[k].type)]).difference(set(dev_in_raid)): if MountPoint.dict.has_key(dev): continue MountPoint(dev, fs=Partition.dict[dev].filesystem) for dev in Raid.dict.keys(): if MountPoint.dict.has_key(dev): continue MountPoint(dev) # now delete unexist partition/raid mount point, or # partition that used in raid. s1 = set(MountPoint.dict.keys()) s2 = set(Partition.dict.keys() + Raid.dict.keys()) - set(dev_in_raid) for dev in s1-s2: del MountPoint.dict[dev] @staticmethod def init_from_xml(node): ''' create MountPoint instances from xml node ''' for m in node.childNodes: if m.nodeType == node.ELEMENT_NODE and m.nodeName == 'mount-point': MountPoint(m.attributes['device'].value.encode('ascii'), \ m.attributes['directory'].value.encode('ascii'), \ m.attributes['file-system'].value.encode('ascii'), \ m.attributes['format'].value.encode('ascii')) @staticmethod def to_xml(doc, p_node): ''' write all MountPoint instance into xml doc - xml document instance p_node - xml node (parent node)''' mps = doc.createElement('mount-points') M_keys = MountPoint.dict.keys() M_keys.sort() for k in M_keys: m = MountPoint.dict[k] mp = doc.createElement('mount-point') dev_attr = doc.createAttribute('device') dir_attr = doc.createAttribute('directory') fs_attr = doc.createAttribute('file-system') fm_attr = doc.createAttribute('format') dev_attr.value = m.device dir_attr.value = m.directory fs_attr.value = m.filesystem fm_attr.value = m.format mp.setAttributeNode(dev_attr) mp.setAttributeNode(dir_attr) mp.setAttributeNode(fs_attr) mp.setAttributeNode(fm_attr) mps.appendChild(mp) p_node.appendChild(mps) @staticmethod def get_size(dev): '''get size of this mount point ''' if dev in Partition.dict.keys(): return Partition.get_size(dev) elif dev in Raid.dict.keys(): return Raid.get_size(dev) @staticmethod def check_data(dev,dr,fs): '''check mount point is feasible. dr is mount point, dev is device''' # check mount point is existent or not if dr and dr in [ m.directory for m in MountPoint.dict.values() if m.device !=dev ]: return False # if fs is swap, then dr must be none if fs == 'swap' and dr: return False # check mount point is special or not if dr in ['/etc','/bin','/sbin','/lib']: return False elif dr in ['/','/boot'] and fs in ['reiserfs','xfs']: return False return True class Network: ''' network ''' hostname ='localhost' configuration ='' domain = 'in.linx' ip = '192.168.1.109' mask = '255.255.255.0' gateway = '192.168.1.1' primary_dns = '192.168.1.1' secondary_dns = '' @staticmethod def init_from_xml(node): ''' init Network from xml node ''' for k in node.attributes.keys(): setattr(Network, k, node.attributes[k].value.encode('ascii')) @staticmethod def to_xml(doc, p_node): ''' write Network into xml doc - xml document instance p_node - xml node (parent node)''' ntwk = doc.createElement('network') for nm in ('hostname', 'configuration', 'ip', 'mask', 'gateway', 'primary_dns', 'secondary_dns', 'domain'): to_xml_attr(doc, ntwk, Network, nm) p_node.appendChild(ntwk) class Group: ''' software package group ''' dict = {} def __init__(self, n, i): self.name = n self.install = i self.description = '' self.mandatory = [] self.selection = 'manual' self.optional = [] Group.dict[n] = self @staticmethod def handle_release_node(r_node): ''' This method is called by init_from_config_xml r_node - release node ''' for i in r_node.childNodes: if i.nodeType == i.ELEMENT_NODE and i.nodeName == 'including': Group(i.attributes['group'].value, \ i.attributes['install'].value == 'mandatory' and 'mandatory' or 'no') @staticmethod def handle_group_node(g_node): ''' This method is called by init_from_config_xml g_node - group node ''' g = Group.dict[g_node.attributes['name'].value] for n in g_node.childNodes: if n.nodeType == n.ELEMENT_NODE: if n.nodeName == 'description': g.description = n.firstChild.data elif n.nodeName == 'including': if n.attributes['install'].value == 'mandatory': g.mandatory.append(n.attributes['package'].value.encode('ascii')) else: g.optional.append([n.attributes['package'].value.encode('ascii'), 'no']) @staticmethod def init_from_config_xml(node): ''' init Group instances from config xml node - root node of config xml''' rls_list = [r for r in node.childNodes if r.nodeType == r.ELEMENT_NODE and r.nodeName == 'release'] grp_list = [g for g in node.childNodes if g.nodeType == g.ELEMENT_NODE and g.nodeName == 'group'] Group.handle_release_node(rls_list[0]) for g in grp_list: Group.handle_group_node(g) @staticmethod def init_from_install_xml(node): ''' init Group instances from install xml node - install xml 'groups' node''' for grp in node.childNodes: if grp.nodeType == grp.ELEMENT_NODE and grp.nodeName == 'group': g = Group(grp.attributes['name'].value, grp.attributes['install'].value) for grp_chld in grp.childNodes: if grp_chld.nodeType == grp_chld.ELEMENT_NODE: if grp_chld.nodeName == 'description': g.description = grp_chld.firstChild.data elif grp_chld.nodeName == 'mandatory': g.mandatory.extend([pkg.attributes['name'].value for pkg in grp_chld.childNodes if pkg.nodeType == pkg.ELEMENT_NODE and pkg.nodeName == 'package']) elif grp_chld.nodeName == 'optional': g.optional.extend([[pkg.attributes['name'].value, pkg.attributes['install'].value] for pkg in grp_chld.childNodes if pkg.nodeType == pkg.ELEMENT_NODE and pkg.nodeName == 'package']) g.selection = grp_chld.attributes['selection'].value init_from_xml = init_from_install_xml @staticmethod def to_xml(doc, p_node): ''' write Group instances into xml doc - xml document instance p_node - xml node (parent node)''' grps = doc.createElement('groups') for g in Group.dict.values(): grp = doc.createElement('group') name_attr = doc.createAttribute('name') name_attr.value = g.name grp.setAttributeNode(name_attr) inst_attr = doc.createAttribute('install') inst_attr.value = g.install grp.setAttributeNode(inst_attr) if g.description: dscp = doc.createElement('description') dscp_data = doc.createTextNode(g.description) dscp.appendChild(dscp_data) grp.appendChild(dscp) if g.mandatory: mndt = doc.createElement('mandatory') for m in g.mandatory: pkg = doc.createElement('package') pname_attr = doc.createAttribute('name') pname_attr.value = m pkg.setAttributeNode(pname_attr) mndt.appendChild(pkg) grp.appendChild(mndt) if g.optional: optl = doc.createElement('optional') sel_attr = doc.createAttribute('selection') sel_attr.value = g.selection optl.setAttributeNode(sel_attr) for o in g.optional: pkg = doc.createElement('package') pname_attr = doc.createAttribute('name') pname_attr.value = o[0] pkg.setAttributeNode(pname_attr) pinst_attr = doc.createAttribute('install') pinst_attr.value = o[1] pkg.setAttributeNode(pinst_attr) optl.appendChild(pkg) grp.appendChild(optl) grps.appendChild(grp) p_node.appendChild(grps) @staticmethod def get_install_pkgs(): ''' get package names that should be installed ''' l = [] for g in Group.dict.values(): if g.install != 'no': l.extend([ p for p in g.mandatory ]) if g.selection == 'manual': l.extend([ p[0] for p in g.optional if p[1] == 'yes' ]) elif g.selection == 'all': l.extend([ p[0] for p in g.optional ]) else: # selection is 'none' pass return l class Service: ''' service ''' list = [] def __init__(self, nm, nb, sc, st, p): ''' init method nm - name nb - number sc - script st - start (yes/no/disable) p - pkg, that includes this service ''' self.name = nm self.number = nb self.script = sc self.start = st self.package = p Service.list.append(self) @staticmethod def init_from_config_xml(root): ''' init Service instances from config xml root - root node of config xml ''' for p in root.childNodes: if p.nodeType == p.ELEMENT_NODE and p.nodeName == 'package': for s in p.childNodes: if s.nodeType == s.ELEMENT_NODE and s.nodeName == 'service': Service(s.attributes['name'].value, \ s.attributes['number'].value, \ s.attributes['script'].value, \ 'disable', \ p.attributes['name'].value ) @staticmethod def change_state(): ''' Based on package information in Group class, change 'start' data member from 'disable' to 'no', or from 'yes'/'no' to 'disable' ''' l = Group.get_install_pkgs() for s in Service.list: if s.package in l: if s.start == 'disable': s.start = 'no' else: s.start = 'disable' @staticmethod def init_from_install_xml(node): ''' init Service instances from install xml node - install xml 'services' node''' for srv in node.childNodes: if srv.nodeType == srv.ELEMENT_NODE and srv.nodeName == 'service': Service(srv.attributes['name'].value, \ srv.attributes['number'].value, \ srv.attributes['script'].value, \ srv.attributes['start'].value, \ srv.attributes['package'].value) init_from_xml = init_from_install_xml @staticmethod def to_xml(doc, p_node): ''' write Service instances into xml doc - xml document instance p_node - xml node (parent node)''' srvs = doc.createElement('services') for s in Service.list: srv = doc.createElement('service') for n in ('name', 'number', 'script', 'start', 'package'): to_xml_attr(doc, srv, s, n) srvs.appendChild(srv) p_node.appendChild(srvs) def prepar_installation(): '''create file called 'intall.xml',which contains the information about the installation''' to_xml() xmldoc = minidom.parse(install_xml) root = xmldoc.firstChild return root.toxml() def init(): ''' initialize ''' Partition.init_from_os() #Raid.init_from_os() MountPoint.init_from_internal() xmldoc_cfg = minidom.parse(config_xml) root_cfg = xmldoc_cfg.firstChild Group.init_from_config_xml(root_cfg) Service.init_from_config_xml(root_cfg) def init_from_xml(): ''' get data in file (install.xml)''' xmldoc = minidom.parse(install_xml) root = xmldoc.firstChild for n in root.childNodes: if n.nodeType == n.ELEMENT_NODE: if n.nodeName == 'serial-number': SerialNumber.init_from_xml(n) elif n.nodeName == 'disks': p_d.Partition.init_from_xml(n) elif n.nodeName == 'raids': Raid.init_from_xml(n) elif n.nodeName == 'network': Network.init_from_xml(n) elif n.nodeName == 'groups': Group.init_from_xml(n) elif n.nodeName == 'services': Service.init_from_xml(n) elif n.nodeName == 'stategrid': StateGrid.init_from_xml(n) def init_from_xml_and_os(): ''' init all classes in this module from file and os ''' xmldoc = minidom.parse(install_xml) root = xmldoc.firstChild for n in root.childNodes: if n.nodeType == n.ELEMENT_NODE: if n.nodeName == 'serial-number': SerialNumber.init_from_xml(n) elif n.nodeName == 'network': Network.init_from_xml(n) elif n.nodeName == 'groups': Group.init_from_xml(n) elif n.nodeName == 'services': Service.init_from_xml(n) Partition.init_from_os() Raid.init_from_os() MountPoint.init_from_internal() def to_xml(): ''' write internal data into xml file ''' f = file(install_xml, 'w') xmldoc = minidom.Document() root = xmldoc.createElement('install') xmldoc.appendChild(root) SerialNumber.to_xml(xmldoc, root) p_d.Partition.to_xml(xmldoc, root) Raid.to_xml(xmldoc, root) Network.to_xml(xmldoc, root) Group.to_xml(xmldoc, root) Service.to_xml(xmldoc, root) PrettyPrint(xmldoc, f) f.close() class StateGrid(): ''' state grid custom install data ''' username = '' home_dir = '' shell = '' @staticmethod def init_from_xml(node): ''' init State Grid data from xml node ''' for k in node.attributes.keys(): setattr(StateGrid, k, node.attributes[k].value.encode('ascii')) @staticmethod def to_xml(doc, p_node): ''' write State Grid data into xml doc - xml document instance p_node - xml node (parent node)''' stgd = doc.createElement('stategrid') for st in ('username','home_dir','shell'): to_xml_attr(doc, stgd, StateGrid, st) p_node.appendChild(stgd)