#!/usr/bin/python import re import commands from xml.dom import minidom from xml.dom.ext import PrettyPrint # xml file names install_xml = '../xml/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 Network 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='' list=[] def __init__(self, dev, st, sz, id, fr): ''' Partition init function ''' self.device = dev self.start = st self.size = sz self.id = id self.from_os = fr Partition.list.append(self) @staticmethod def init_from_os(): ''' create a Partition instance from hardware info''' # cmd = 'sfdisk -d' # has problem on raid detection cmd = 'cat /home/zhi/work/new_install/python/mine/sfdisk.txt' st, o = commands.getstatusoutput(cmd) if st: return p0 = re.compile(r'unit:\s*(\w+)') p = re.compile(r''' \s*(\w+)\s*: # device \s*start=\s*(\d+)\s*, # start \s*size=\s*(\d+)\s*, # size \s*Id=\s*(\d+) # id ''', re.VERBOSE) for s in o.splitlines(): res0 = p0.search(s) if res0: Partition.unit = res0.groups()[0] res = p.search(s) if res: dev, start, size, id = res.groups() Partition(dev.split('/')[-1], start, size, id, True) @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['id'].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) for p in Partition.list: pt = doc.createElement('partition') dev_attr = doc.createAttribute('device') start_attr = doc.createAttribute('start') size_attr = doc.createAttribute('size') id_attr = doc.createAttribute('id') from_attr = doc.createAttribute('from_os') dev_attr.value = p.device start_attr.value = p.start size_attr.value = p.size id_attr.value = p.id from_attr.value = p.from_os pt.setAttributeNode(dev_attr) pt.setAttributeNode(start_attr) pt.setAttributeNode(size_attr) pt.setAttributeNode(id_attr) pt.setAttributeNode(from_attr) pts.appendChild(pt) p_node.appendChild(pts) @staticmethod def get_size(dev): for p in Partition.list: if p.device == dev: return p.size class Raid: ''' raid information ''' list = [] def __init__(self, dev, from_os, level, sz, a_devs, s_devs=[]): ''' Raid init function ''' self.device = dev self.from_os = from_os self.level = level self.size = sz self.active_components = a_devs self.spare_components = s_devs Raid.list.append(self) @staticmethod def init_from_os(): #cmd = 'cat /proc/mdstat' cmd = 'cat /home/zhi/work/new_install/python/mine/raid.txt' 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) size_p = re.compile(r''' ^\s*(\d+) # block number \s*blocks''', re.VERBOSE) for s in o.splitlines(): dev_res = dev_p.split(s) if len(dev_res)>1: # matched # dev_res[0] is '' raid_dev = dev_res[1] raid_level = dev_res[2] 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('[')]) continue if size_p.match(s).groups(): raid_size = size_p.match(s).groups()[0] # if already detect a raid dev if raid_dev: Raid(raid_dev, True, raid_level, raid_size, act_cmpts, spr_cmpts) # clear raid dev raid_dev='' @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_size = e.attributes['size'].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_size, 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') for r in Raid.list: 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_size_attr = doc.createAttribute('size') rd_size_attr.value = r.size rd.setAttributeNode(rd_size_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) @staticmethod def get_size(dev): for r in Raid.list: if r.device == dev: return r.size @staticmethod def get_next_device(): ''' get next available raid device name ''' num_p = re.compile(r'md(\d+)') numbers = [ int(num_p.match(r.device).groups()[0]) for r in Raid.list ] max = 0 for n in numbers: if n > max: max = n return 'md%d' %(max+1) class MountPoint: ''' mount-points ''' list=[] def __init__(self, dev, dir='', fs='', fm='no', sz='0'): self.device = dev self.directory = dir self.filesystem = fs self.format = fm self.size = sz MountPoint.list.append(self) @staticmethod def change(dev, dir, fs, fm): for mp in MountPoint.list: if mp.device == dev: mp.directory = dir mp.filesystem = fs mp.format = fm def device(self): return self.device @staticmethod def init_from_internal(): ''' init MountPoint from internal class Partition and class Raid ''' devs = [ m.device for m in MountPoint.list ] for p in Partition.list: if p.id != 'fd' and p.device not in devs: MountPoint(p.device, sz=p.size) for r in Raid.list: if r.device not in devs: MountPoint(r.device, sz=r.size) # now process whether a partition or raid was removed s1 = set([ m.device for m in MountPoint.list ]) s2 = set([ p.device for p in Partition.list ] + [ r.device for r in Raid.list]) for dev in s1-s2: for i in range(len(MountPoint.list)): if dev == MountPoint.list[i].device: del MountPoint.list[i] break # sort MountPoint.list.sort(key=MountPoint.device) @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') for m in MountPoint.list: 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) class Network: ''' network ''' hostname ='' configuration ='' domain = '' ip = '' mask = '' gateway = '' primary_dns = '' 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) 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 = [] for g in Group.dict.values(): if g.install == 'mandatory' or g.install == 'yes': l.extend(g.mandatory) if g.selection == 'all': l.extend([ n for n, i in g.optional]) elif g.selection == 'manual': l.extend([ n for n, i in g.optional if i == 'yes']) else: # selection is 'none' pass 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 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(): ''' init all classes in this module based input 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 == 'partitions': Partition.init_from_xml(n) elif n.nodeName == 'raids': Raid.init_from_xml(n) elif n.nodeName == 'mount-points': MountPoint.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) 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) Partition.to_xml(xmldoc, root) Raid.to_xml(xmldoc, root) MountPoint.to_xml(xmldoc, root) Network.to_xml(xmldoc, root) Group.to_xml(xmldoc, root) Service.to_xml(xmldoc, root) PrettyPrint(xmldoc, f) f.close()