#!/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 = './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): ''' Partition init function ''' self.device = dev self.start = st self.size = sz self.id = id 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) @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')) @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') dev_attr.value = p.device start_attr.value = p.start size_attr.value = p.size id_attr.value = p.id pt.setAttributeNode(dev_attr) pt.setAttributeNode(start_attr) pt.setAttributeNode(size_attr) pt.setAttributeNode(id_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, raid_dev, raid_type, raid_size, raw_devs): ''' Raid init function ''' self.raid_device = raid_dev self.raid_type = raid_type self.raid_size = raid_size self.raw_devices = raw_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) 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_type = dev_res[2] raw_devs =[] for ss in dev_res[3].split(): raw_devs.append(ss[:ss.index('[')]) Raid(raid_dev, raid_type, '-1', raw_devs) @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['raid-device'].value raid_type = e.attributes['raid-type'].value raid_size = e.attributes['raid-size'].value raw_devs = [] for sub_e in e.childNodes: if sub_e.nodeType == sub_e.ELEMENT_NODE and sub_e.nodeName == 'raw-device': raw_devs.append(sub_e.firstChild.data.encode('ascii')) Raid(raid_dev, raid_type, raid_size, raw_devs) @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('raid-device') rd_dev_attr.value = r.raid_device rd.setAttributeNode(rd_dev_attr) rd_type_attr = doc.createAttribute('raid-type') rd_type_attr.value = r.raid_type rd.setAttributeNode(rd_type_attr) rd_size_attr = doc.createAttribute('raid-size') rd_size_attr.value = r.raid_size rd.setAttributeNode(rd_size_attr) for raw_dev in r.raw_devices: raw_dev_e = doc.createElement('raw-device') raw_dev_tn = doc.createTextNode(raw_dev) raw_dev_e.appendChild(raw_dev_tn) rd.appendChild(raw_dev_e) raids.appendChild(rd) p_node.appendChild(raids) @staticmethod def get_size(dev): for r in Raid.list: if r.raid_device == dev: return r.raid_size class MountPoint: ''' mount-points ''' list=[] def __init__(self, dev, dir='', fs='', fm='no'): self.device = dev self.directory = dir self.filesystem = fs self.format = fm MountPoint.list.append(self) @staticmethod def init_from_internal(): ''' init MountPoint from internal class Partition and class Raid ''' devs = [ p.device for p in Partition.list ] for r in Raid.list: for raw_d in r.raw_devices: if raw_d in devs: devs.remove(raw_d) if not r.raid_device in devs: devs.append(r.raid_device) for dev in devs: MountPoint(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') 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']) 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') 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.pkg 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()