#!/usr/bin/python # # Copyright 2009 Platform Computing Inc # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # # # This script has the following functions: # 1. Determine the IP address of the Installer node # 2. Retreive the NII and set the state to installed # 3. Create/update the CFM shared secret # 4. Create/update the profile.nii # 5. Call the script to generate the network config # # It should be run only after the network is up, but before other # services have started import os import sys import string import gettext import shutil import time import glob from kusu.ipfun import * from kusu.niifun import * ANACONDA='/root/anaconda-ks.cfg' LOGFILE = '/var/log/kusu/updatenii.log' class App: def __init__(self): """ Initialize Class variables. Extend as needed (if needed) """ self.args = sys.argv self.installerIP = '' # The IP address of the installer self.ostype = '' langdomain = 'kusunodeapps' localedir = '/opt/kusu/share/locale' if not os.path.exists(localedir): # Try the system path localedir = '/usr/share/locale' gettext.bindtextdomain(langdomain, localedir) gettext.textdomain(langdomain) self.gettext = gettext.gettext self._ = self.gettext def eout(self, message, *args): """eout - Output messages to STDERR with Internationalization. Additional arguments will be used to substitute variables in the message output""" if len(args) > 0: mesg = self.gettext(message) % args else: mesg = self.gettext(message) sys.stderr.write(mesg) try: fp = open(LOGFILE, 'a') fp.write(mesg) fp.close() except: pass def out(self, message, *args): """print - Output messages to STDOUT with Internationalization. Additional arguments will be used to substitute variables in the message output""" if len(args) > 0: mesg = self.gettext(message) % args else: mesg = self.gettext(message) sys.stdout.write(mesg) try: fp = open(LOGFILE, 'a') fp.write(mesg) fp.close() except: pass def getInstallerIP(self): """getInstallerIP - Get the installers IP address""" self.installerIP = self.getProfileVal('NII_INSTALLERS') if self.installerIP == '': self.eout("ERROR: Failed to determing the IP address of the Installer.\n") self.eout("ERROR: Do not run this tool on the installer.\n") sys.exit(-1) self.out("Installer IP is: %s\n", self.installerIP) def getProfileVal(self, name): """getProfileVal - Returns the value of the NII property from /etc/profile.nii with any quotes removed.""" cmd = "grep %s /etc/profile.nii 2>/dev/null" % name val = '' proc = os.popen(cmd) for line in proc.readlines(): loc = string.find(line, name) if loc < 0: continue t2 = string.split(line[string.find(line, '=')+1:])[0] val = string.strip(t2, '"') break proc.close() return val def getHaddrForNic(self, nic): """getHaddrForNic - extract the HWADDR field from a NIC configuration script. It look like: HWADDR=00:16:29:F7:99:99 """ filename = '/etc/sysconfig/network-scripts/ifcfg-%s' % nic if not os.path.exists(filename): # +++++++++++++ FIXME for other OS's return '' try: fin = open(filename, 'r') except: return '' lines = fin.readlines() fin.close() for line in lines: if line[0] == "#" or line.isspace(): continue try: key,val = string.split(line, '=', 1) key = string.strip(key) except: continue if key == 'HWADDR': val = string.strip(val) return val def getNii(self): url = 'http://%s/repos/nodeboot.cgi?dump=1' % self.installerIP goturl = False for i in [1, 2, 3, 4, 5, 6]: try: (niidata, header) = urllib.urlretrieve(url) goturl = True except: self.eout("WARNING: Failed to download NII. Try: %i\n", i) time.sleep(5) if not goturl: self.eout("ERROR: Failed to download NII using: %s\n", url) sys.exit(-1) parser = make_parser() self.niihandler = NodeInstInfoHandler() parser.setContentHandler(self.niihandler) try: parser.parse(open(niidata)) except: self.eout("ERROR: Error parsing NII got:\n") fp = open(niidata) print fp.readlines() fp.close() if self.niihandler.name == '': self.eout("ERROR: Failed to get good NII\n") fp = open(niidata) data = fp.readlines() fp.close() for line in data: self.eout(line) sys.exit(-1) os.unlink(niidata) self.ostype = string.split(self.niihandler.ostype, '-', 1)[0] return self.niihandler def updateHostname(self, niihandler): '''updateHostname - Update the hosts name in the configuration and set it''' dnszone = '' if niihandler.appglobal.has_key('DNSZone'): fqhn = "%s.%s" % (niihandler.name, niihandler.appglobal['DNSZone']) else: fqhn = "%s.%s" % (niihandler.name) if self.ostype in ['rhel', 'centos', 'fedora']: if os.path.exists('/etc/sysconfig/network'): fp = open('/etc/sysconfig/network', 'r') lines = fp.readlines() fp.close() fp = open('/etc/sysconfig/network', 'w') for line in lines: try: key,val = string.split(line, '=', 1) except: key = 'none' if key == 'HOSTNAME': line = "HOSTNAME=%s\n" % fqhn fp.write(line) fp.close() cmd = '/bin/hostname %s' % fqhn os.system(cmd) else: self.eout("WARNING: Failed to update NOSTNAME in network file") else: print "+++++++++++++++++ SLES ++++++++++++++++++++++++ FIX ME" def delOldNics(self, niihandler): # Get list of existing configs, and build a list of current NICs delNics = [] if self.ostype in ['rhel', 'centos', 'fedora']: # RHEL implementation! pattern = '/etc/sysconfig/network-scripts/ifcfg-*' flist = glob.glob(pattern) for i in flist: n = i[len(pattern)-1:] if n == 'lo': continue delNics.append(n) # Determine which NICS need to be removed if delNics: for i in niihandler.nics.keys(): dev = niihandler.nics[i]['device'] if niihandler.nics[i]['device'] in delNics: delNics.remove(dev) # delNics not should only contain NICS that need to be deleted if delNics: for i in delNics: self.out("Deconfiguring NIC %s\n", i) cmd = '/etc/sysconfig/network-scripts/ifdown %s' % i os.system(cmd) if self.ostype in ['rhel', 'centos', 'fedora']: # RHEL implementation! mac = '' ifcfg = '/etc/sysconfig/network-scripts/ifcfg-%s' % i if os.path.exists(ifcfg): # Back it up and extract the MAC shutil.copy(ifcfg, "/tmp/ifcfg-%s.ORIG" % i) mac = self.getHaddrForNic(i) # Write back the file fp = open("%s" % ifcfg, 'w') fp.write('# Updated by OCS/Kusu\n') fp.write('DEVICE=%s\n' % i) fp.write('ONBOOT=no\n') if mac != '': fp.write('HWADDR=%s\n' % mac) fp.close() else: # ___________________ Other OS's ________________________________ FIX ME pass def configNics(self, niihandler): # Update the NIC config. for i in niihandler.nics.keys(): self.out("------------------------------ NICS: Key = %s\n", i) self.out(" Device = %s\n", (niihandler.nics[i]['device'])) self.out(" IP = %s\n", (niihandler.nics[i]['ip'])) self.out(" subnet = %s\n", (niihandler.nics[i]['subnet'])) self.out(" network = %s\n", (niihandler.nics[i]['network'])) self.out(" suffix = %s\n", (niihandler.nics[i]['suffix'])) self.out(" gateway = %s\n", (niihandler.nics[i]['gateway'])) self.out(" dhcp = %s\n", (niihandler.nics[i]['dhcp'])) self.out(" options = %s\n", (niihandler.nics[i]['options'])) # Call external script to handle BMC devices print niihandler.nics if niihandler.nics[i]['device'] == 'bmc': self.out("Configuring BMC\n") # --------------------- NEED THE SCRIPT --------------------------------------- FIX ME if not os.path.exists("/opt/omsa"): os.system("/opt/kusu/bin/kusurc /etc/rc.kusu.d/S99DellBMCSetup") continue if self.ostype in ['rhel', 'centos', 'fedora']: # RHEL implementation! mac = '' ifcfg = '/etc/sysconfig/network-scripts/ifcfg-%s' % niihandler.nics[i]['device'] if os.path.exists(ifcfg): # Back it up and extract the MAC shutil.copy(ifcfg, "/tmp/ifcfg-%s.ORIG" % niihandler.nics[i]['device']) mac = self.getHaddrForNic(niihandler.nics[i]['device']) # Write back the file fp = open("%s" % ifcfg, 'w') fp.write('# Updated by OCS/Kusu\n') fp.write('DEVICE=%s\n' % niihandler.nics[i]['device']) fp.write('ONBOOT=yes\n') if niihandler.nics[i]['dhcp'] == '0': fp.write('BOOTPROTO=static\n') fp.write('IPADDR=%s\n' % niihandler.nics[i]['ip']) fp.write('NETWORK=%s\n' % niihandler.nics[i]['network']) fp.write('NETMASK=%s\n' % niihandler.nics[i]['subnet']) # Don't think BROADCAST is needed else: fp.write('BOOTPROTO=dhcp\n') if mac != '': fp.write('HWADDR=%s\n' % mac) fp.close() # Bring up NIC cmd = '/etc/sysconfig/network-scripts/ifdown %s' % niihandler.nics[i]['device'] os.system(cmd) cmd = '/etc/sysconfig/network-scripts/ifup %s' % niihandler.nics[i]['device'] os.system(cmd) else: # SLES and OpenSuse print "+++++++++++++++++ SLES ++++++++++++++++++++++++ FIX ME 2" def run(self): self.getInstallerIP() niihandler = self.getNii() self.out("Name = %s\n", niihandler.name) self.out("installers = %s\n", niihandler.installers) self.out("repo = %s\n", niihandler.repo) self.out("ostype = %s\n", niihandler.ostype) self.out("installtype = %s\n", niihandler.installtype) self.out("nodegrpid = %s\n", niihandler.nodegrpid) if niihandler.nodegrpid == '1': self.eout("ERROR: This tool should not be run on the installer\n") sys.exit(1) self.ostype = string.split(niihandler.ostype, '-', 1)[0] niihandler.saveAppGlobalsEnv('/etc/profile.nii') self.out("Wrote: /etc/profile.nii\n") niihandler.saveCFMSecret('/etc/cfm/.cfmsecret') self.out("Wrote: /etc/cfm/.cfmsecret\n") self.updateHostname(niihandler) self.delOldNics(niihandler) self.configNics(niihandler) if __name__ == '__main__': # Check if root user if os.geteuid(): print "ERROR: Only root can run this tool" sys.exit(-1) args = sys.argv[1:] i = 0 while i < len(args): if args[i] == '-v': self.out("Updatenic Version 5.2\n") sys.exit(0) elif args[i] == '-h': self.out("updatenic [-h|-v]\n\n") self.out("The updatenic tool queries the installer for an updated profile.nii.\n") self.out("It also causes the network configuration on the node to be created\n") self.out("or updated, and the hostname to be updated.\n") self.out("This tool is typically invoked by a cfmclient plugin.\n") self.out("It should not be invoked on the installer,\n") sys.exit(0) else: self.eout("ERROR: Unknown argument\n") sys.exit(1) i += 1 app = App() app.run()