diff --git a/tmcd/myplc/bootmanager.patch b/tmcd/myplc/bootmanager.patch new file mode 100644 index 0000000000000000000000000000000000000000..91bd56c772eaaaac2b238f461027a26ac179c4f8 --- /dev/null +++ b/tmcd/myplc/bootmanager.patch @@ -0,0 +1,24 @@ +diff -ur source/configuration source.new/configuration +--- source/configuration 2007-03-12 00:18:05.000000000 -0700 ++++ source.new/configuration 2007-03-12 00:19:30.000000000 -0700 +@@ -52,7 +52,7 @@ + + + # whether or not to skip hardware requirement check +-SKIP_HARDWARE_REQUIREMENT_CHECK=0 ++SKIP_HARDWARE_REQUIREMENT_CHECK=1 + + + # minimum amount of memory needed for installer, in kb +diff -ur source/steps/ConfirmInstallWithUser.py source.new/steps/ConfirmInstallWithUser.py +--- source/steps/ConfirmInstallWithUser.py 2007-03-12 00:18:05.000000000 -0700 ++++ source.new/steps/ConfirmInstallWithUser.py 2007-03-12 00:21:41.000000000 -0700 +@@ -47,7 +47,7 @@ + log.write( "\n\nStep: Confirming install with user.\n" ) + + try: +- confirmation= "" ++ confirmation= "yes" + install= 0 + print welcome_message + diff --git a/tmcd/myplc/libplcsetup.py b/tmcd/myplc/libplcsetup.py new file mode 100644 index 0000000000000000000000000000000000000000..73606b57a3b78dde09aa3f4807af3e02f30f0b2d --- /dev/null +++ b/tmcd/myplc/libplcsetup.py @@ -0,0 +1,520 @@ +#!/usr/bin/python + +import sys +import os +import os.path +import socket +import random +import traceback +import xmlrpclib +# grab plc_config +sys.path.append('/plc/root/usr/lib/python2.4/site-packages') +from plc_config import PLCConfiguration + + +debug = 1 +cachedRootUID = None +cachedRootPasswd = None + +DEF_ROOT_UID = 'root@localhost.localdomain' +DEF_ROOT_ACCOUNT_INFO_FILE = '/etc/planetlab/rootacctinfo' +DEF_PLC_CONFIG_FILE = '/plc/data/etc/planetlab/plc_config.xml' +DEF_PLC_URL = 'https://localhost/PLCAPI/' +DEF_SITE_ID = 1 + +def plcReadConfigVar(catID,varID,configFile=DEF_PLC_CONFIG_FILE): + """ + Returns the value of the specified variable. + """ + plcc = PLCConfiguration(configFile) + ret = plcc.get(catID,varID) + if ret == None: + return None + + for d in ret: + if d['id'] == varID: + ret = d['value'] + break + pass + + return ret + +def plcUpdateConfig(variables,configFile=DEF_PLC_CONFIG_FILE): + """ + Update the default planetlab config file. + Arguments: + variables = list of dicts or lists + configFile = alternate planetlab config file + + Example: to set plc_www/host (i.e., PLC_WWW_HOST in myplc docs), do + + variables[0] = { 'category' : 'plc_www', + 'variable' : 'host', + 'value' : <value> } + or + variables[0] = [ 'plc_www','host',<value> ] + """ + + plcc = PLCConfiguration(configFile) + + for obj in variables: + catDict = dict() + varDict = dict() + + if type(obj) == list: + catDict['id'] = obj[0] + varDict['id'] = obj[1] + varDict['value'] = obj[2] + pass + elif type(obj) == dict: + catDict['id'] = obj['category'] + varDict['id'] = obj['variable'] + varDict['value'] = obj['value'] + pass + else: + raise "Unsupported variable object!" + + plcc.set(catDict,varDict) + pass + + plcc.save() + pass + +def getXMLRPCAuthInfo(): + readRootAcctInfo() + + auth = { 'Username' : cachedRootUID, + 'AuthString' : cachedRootPasswd, + 'AuthMethod' : 'password', + 'Role' : 'admin' } + + return auth + +def getXMLRPCServer(url=DEF_PLC_URL): + return xmlrpclib.Server(url,allow_none=True) + +def plcAddUser(realname,email,passwd,keys=[],root=False): + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + (fn,ln) = (None,None) + sn = realname.split(' ') + if len(sn) >= 2: + (fn,ln) = (sn[0],sn[-1]) + pass + else: + (fn,ln) = (sn[0],'EmulabFamily') + pass + + pid = server.AddPerson(auth,{ 'first_name' : fn, + 'last_name' : ln, + 'url' : 'http://www.emulab.net', + # "saw your name and number on the wall..." + 'phone' : '867-5309', + 'password' : passwd, + 'email' : email }) + + server.UpdatePerson(auth,pid,{ 'enabled' : True }) + + for key in keys: + # have to catch exceptions here cause plc only allows ssh2 keys, + # and users could have *anything* in their authorized_keys + try: + server.AddPersonKey(auth,pid,{ 'key_type' : 'ssh', + 'key' : key }) + except: + pass + pass + + if root: + server.AddRoleToPerson(auth,'admin',pid) + pass + + return pid + +def plcDeleteUser(email): + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + return server.DeletePerson(auth,email) + +def plcUpdateUser(realname,email,passwd,keys=[],root=False): + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + ulist = server.GetPersons(auth, + { 'email' : email }, + [ 'first_name','last_name','roles','key_ids' ]) + + if len(ulist) == 0: + print "WARNING: could not find match for user %s!" % email + return 0 + elif len(ulist) > 1: + print "WARNING: more than one match for user %s, using first" % email + pass + + (fn,ln) = (None,None) + sn = realname.split(' ') + if len(sn) >= 2: + (fn,ln) = (sn[0],sn[-1]) + pass + else: + (fn,ln) = (sn[0],'EmulabFamily') + pass + + # update name + if fn != ulist[0]['first_name'] or ln != ulist[0]['last_name']: + server.UpdatePerson(auth,email,{ 'first_name' : fn, + 'last_name' : ln }) + pass + + # update roles + if 'admin' in ulist[0]['roles'] and not root: + server.UpdatePerson(auth,email,{ 'roles' : [ 'user' ] }) + pass + + # update keys + retlist = server.GetKeys(auth,ulist[0]['key_ids'],[ 'key_id','key' ]) + keylist = map(lambda(x): x['key'],retlist) + # add: + for rk in keys: + if not rk in keylist: + # have to catch exceptions here cause plc only allows ssh2 keys, + # and users could have *anything* in their authorized_keys + try: + server.AddPersonKey(auth,email,{ 'key_type' : 'ssh', + 'key' : rk }) + except: + pass + pass + pass + # delete: + for ret in retlist: + if not ret['key'] in keylist: + server.DeletePersonKey(auth,ret['key_id']) + pass + pass + + # always update the password, it's easier than doing AuthCheck and all... + server.UpdatePerson(auth,email,{ 'password' : passwd }) + + return 1 + +def plcUpdateUsers(uplist=[]): + """ + Takes a list of (realname,email,passwd,keys=[],root=False) account tuples + and adds, deletes, and updates as needed. + """ + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + userlist = server.GetPersons(auth,{},[ 'email' ]) + + # go through the uplist and ulist and figure out what needs + # adding, deleting, or updating: + alist = list() # list of tuples from uplist + dlist = list() # list of hostnames to be deleted + ulist = list() # list of tuples from uplist + + for ntuple in uplist: + found = False + for user in userlist: + if ntuple[1] == user['email']: + found = True + break + pass + if found: + ulist.append(ntuple) + pass + else: + alist.append(ntuple) + pass + pass + + for user in userlist: + found = False + for ntuple in uplist: + if ntuple[1] == user['email']: + found = True + break + pass + if not found and user['email'].endswith('emulab.net'): + dlist.append(user['email']) + pass + pass + + #print "alist = %s\n\nulist = %s\n\ndlist = %s\n" % (alist,ulist,dlist) + + for als in alist: + print "Adding user %s" % als[1] + plcAddUser(*als) + pass + + for uls in ulist: + print "Updating user %s" % uls[1] + plcUpdateUser(*uls) + pass + + for dls in dlist: + print "Deleting user %s" % dls + plcDeleteUser(dls) + pass + + return None + +def addMACDelim(mac,delim=':'): + if mac.count(delim) == 0: + return mac[0:2] + delim + mac[2:4] + delim + mac[4:6] + delim + \ + mac[6:8] + delim + mac[8:10] + delim + mac[10:12] + else: + return mac + pass + +def plcAddNode(hostname,ip,mac): + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + fmac = addMACDelim(mac,':') + + nid = server.AddNode(auth,DEF_SITE_ID,{ 'hostname' : hostname }) + + nnid = server.AddNodeNetwork(auth,nid,{ 'is_primary' : True, + 'hostname' : hostname, + 'ip' : ip, + 'mac' : fmac, + 'method' : 'dhcp', + 'type' : 'ipv4' }) + + # ugh, have to set a node key manually + astr = "abcdefghijklmnopqrstuvwxyz" + rstr = astr + astr.upper() + '0123456789' + tpasslist = random.sample(rstr,32) + tkey = '' + for char in tpasslist: + tkey += char + pass + + server.UpdateNode(auth,nid,{ 'key' : tkey }) + + return (nid,nnid) + +def plcDeleteNode(hostname): + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + return server.DeleteNode(auth,hostname) + +def plcUpdateNode(hostname,ip,mac): + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + fmac = addMACDelim(mac,':') + + nodelist = server.GetNodes(auth, + { 'hostname' : hostname }, + [ 'nodenetwork_ids' ]) + + if len(nodelist) != 1: + print "ERROR: more than one node %s found!" % hostname + return -1 + + if len(nodelist[0]['nodenetwork_ids']) != 1: + print "WARNING: more than one node network for %s; " + \ + "using first!" % hostname + pass + + nnid = nodelist[0]['nodenetwork_ids'][0] + + nnlist = server.GetNodeNetworks(auth,[ nnid ],[ 'ip','mac' ]) + + if len(nnlist) != 1: + print "WARNING: more than one node network for %s; " + \ + "using first!" % hostname + pass + + if ip != nnlist[0]['ip'] or fmac != nnlist[0]['mac']: + return server.UpdateNodeNetwork(auth,nnid,{ 'ip' : ip, + 'mac' : fmac }) + pass + + # even if we don't do anything, return 1. + return 1 + +def plcUpdateNodes(uplist=[]): + """ + uplist should be a list of (hostname,ip,mac) tuples. + """ + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + pnodelist = server.GetNodes(auth,{}, + [ 'hostname','nodenetwork_ids','node_id' ]) + #pnetlist = server.GetNodeNetworks(auth,{},[ 'ip','hostname','mac' ]) + + # go through the uplist and pnodelist/pnetlist and figure out what needs + # adding, deleting, or updating: + alist = list() # list of tuples from uplist + dlist = list() # list of hostnames to be deleted + ulist = list() # list of tuples from uplist + + for ntuple in uplist: + found = False + for pnode in pnodelist: + if ntuple[0] == pnode['hostname']: + found = True + break + pass + if found: + ulist.append(ntuple) + pass + else: + alist.append(ntuple) + pass + pass + + for pnode in pnodelist: + found = False + for ntuple in uplist: + if ntuple[0] == pnode['hostname']: + found = True + break + pass + if not found: + dlist.append(ntuple[0]) + pass + pass + + #print "alist = %s\nulist = %s\ndlist = %s" % (alist,ulist,dlist) + + for als in alist: + print "Adding node %s" % als[0] + plcAddNode(*als) + pass + + for uls in ulist: + print "Updating node %s" % uls[0] + plcUpdateNode(*uls) + pass + + for dls in dlist: + print "Deleting node %s" % dls + plcDeleteNode(dls) + pass + + return None + +# XXX: what to do when we delete a node on one swapmod, then later re-add it? +# Will both nids hang around in the db? +def plcGetNodeID(hostname): + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + nodelist = server.GetNodes(auth,{ 'hostname' : hostname },[ 'node_id' ]) + if len(nodelist) > 0: + return nodelist[0]['node_id'] + else: + raise "Could not find node_id for %s" % hostname + + return None + +def plcGetNodeConfig(hostname): + """ + Returns a list of strings that should be lines in a node config file. + """ + auth = getXMLRPCAuthInfo() + server = getXMLRPCServer() + + nlist = server.GetNodes(auth, + { 'hostname' : hostname }, + [ 'hostname','node_id','key' ]) + + if len(nlist) != 1: + return [] + + nnlist = server.GetNodeNetworks(auth, + { 'hostname' : hostname }, + [ 'mac','method' ]) + + if len(nnlist) != 1: + return [] + + (host,network) = hostname.split('.',1) + + return [ 'NODE_ID="%d"' % nlist[0]['node_id'], + 'NODE_KEY="%s"' % nlist[0]['key'], + 'NET_DEVICE="%s"' % nnlist[0]['mac'], + 'IP_METHOD="%s"' % nnlist[0]['method'], + 'HOST_NAME="%s"' % host, + 'DOMAIN_NAME="%s"' % network ] + + +def readRootAcctInfo(refresh=False,pwfile=DEF_ROOT_ACCOUNT_INFO_FILE): + global cachedRootUID,cachedRootPasswd + + if not os.path.isfile(pwfile): + return None + + if not refresh and (cachedRootUID != None and cachedRootPasswd != None): + return (cachedRootUID,cachedRootPasswd) + + info = list() + try: + fd = open(pwfile,'r') + line = fd.readline().strip('\n') + while line != '': + if not line.startswith('#'): + info.append(line) + pass + line = fd.readline().strip('\n') + pass + pass + except: + if debug: + print "Failed to read root account info from %s" % pwfile + traceback.print_exc() + pass + raise + + if info == []: + return None + + (cachedRootUID,cachedRootPasswd) = tuple(info) + + return tuple(info) + + +def writeRootAcctInfo(uid=DEF_ROOT_UID,passwd=None, + pwfile=DEF_ROOT_ACCOUNT_INFO_FILE): + global cachedRootUID,cachedRootPasswd + + tpass = passwd + if tpass == None: + astr = "abcdefghijklmnopqrstuvwxyz" + rstr = astr + astr.upper() + '0123456789' + '!@#$%^&*' + + tpasslist = random.sample(rstr,8) + tpass = '' + for char in tpasslist: + tpass += char + pass + pass + + try: + fd = open(pwfile,'w') + fd.write("%s\n" % uid) + fd.write("%s\n" % tpass) + fd.close() + except: + if debug: + print "Failed to write root account info to %s" % pwfile + traceback.print_exc() + pass + raise + + cachedRootUID = uid + cachedRootPasswd = tpass + + return (cachedRootUID,cachedRootPasswd) + + + diff --git a/tmcd/myplc/plcsetup.py b/tmcd/myplc/plcsetup.py new file mode 100755 index 0000000000000000000000000000000000000000..6e2dc09617b8a145b374e914b3559b3ecc085632 --- /dev/null +++ b/tmcd/myplc/plcsetup.py @@ -0,0 +1,392 @@ +#!/usr/bin/python + +import traceback +import sys +import os.path + +# +# Helper functions. +# +def runCommand(cmd): + output = list() + cp = os.popen(cmd,'r') + line = cp.readline() + while line != '': + output.append(line) + line = cp.readline() + pass + return output + +def getHostname(): + return runCommand('/bin/hostname')[0].strip('\n') + +def doService(serviceName,serviceAction): + #print "Sending %s to %s" % (serviceAction,serviceName) + return os.system("service %s %s" % (serviceName,serviceAction)) + +def readUserKeys(uid): + """ + Reads the Emulab-generated /users/@uid@/.ssh/authorized_keys file + and returns a list of the keys contained therein. + """ + keyfile = '/users/%s/.ssh/authorized_keys' % uid + fd = file(keyfile) + keylist = list() + + for line in fd: + if line != '' and not line.startswith('#'): + keylist.append(line.strip('\n')) + pass + pass + + return keylist + +def runTMCC(cmd): + """ + Runs the tmcc command indicated and returns, for each line, a list of + keys with no value, and a dict of key/value pairs. + """ + retlist = list() + retval = runCommand("%s %s" % (TMCC,cmd)) + + for line in retval: + rline = line.strip('\n') + lineDict = dict() + lineDict['onlykey'] = [] + + while len(rline) > 0: + [k,rline] = rline.split('=',1) + if k.count(' ') > 0: + # "key" is really multiple keys... + realkeys = k.split(' ') + k = realkeys[-1] + for r in realkeys[0:-1]: + lineDict['onlykey'].append(r) + pass + pass + if rline[0] == '"': + # need to split at the next '" ' + [v,rline] = rline[1:].split('"',1) + if len(rline) > 0: + # get rid of the next space... + rline = rline[1:] + pass + pass + else: + if rline.count(' ') > 0: + [v,rline] = rline.split(' ',1) + pass + else: + v = rline + rline = '' + pass + pass + lineDict[k] = v + pass + + retlist.append(lineDict) + pass + + return retlist + +# -4. Must be root. +# -3. Stop and mount plc. +# -2. Create some dirs we need. +# -1. Read in necessary Emulab tmcc data. +# 0. Read in (set if can't read) plc root account info. +# 1. Read in plc config, reset any of the key defaults that are incorrect. +# 2. Restart plc so we can talk to xmlrpc server and so changes are grabbed. +# 3. Do a diff on the current plc nodes/networks/users and add/remove as +# necessary. +# 4. Extract crap from the bootcd, make config imgs, setup pxe configs. +# 5. Stop plc from running on boot, since this setup will run it. + + +# -4. +if not os.getuid() == 0: + print "ERROR: must be root to run this script!" + sys.exit(-1) + pass + +# -3. +print "plabinelab: stopping plc:" +doService('plc','stop') +print "plabinelab: mounting plc:" +doService('plc','mount') + +# ick! need to patch the bootmanager so that 1) it doesn't ask if we're sure +# before installing, and 2) it doesn't fail the hardware check on slow nodes. +if not os.path.exists('/plc/emulab/bootmanager.patch.done'): + print "plabinelab: patching bootmanager" + cwd = os.getcwd() + os.chdir('/plc/root/usr/share/bootmanager') + os.system('patch -p0 < /plc/emulab/bootmanager.patch') + os.chdir(cwd) + bpd = open('/plc/emulab/bootmanager.patch.done','w') + bpd.write('done\n') + bpd.close() + pass + +# can only import this after plc is mounted; else we can't get access to the +# python modules. +from libplcsetup import * + +TMCC = '/usr/local/etc/emulab/tmcc' +# XXX: need to switch this stuff to be a little more intelligent so +# we can configure private planetlab networks from the control net. +DEF_PLC_HOST = getHostname() +DEF_PLC_IP = socket.gethostbyname(DEF_PLC_HOST) + +# -2. +#try: +# os.makedirs('/plc/emulab/setup') +#except: +# pass +try: + os.makedirs('/plc/emulab/nodes') +except: + pass + +# -1. +print "plabinelab: gathering info from tmcd" +tmccAccounts = runTMCC('accounts') +tmccCreator = runTMCC('creator') +tmccEPlabConfig = runTMCC('eplabconfig') + +(creatorUID,creatorEmail) = (None,None) +for acct in tmccAccounts: + if 'ADDUSER' in acct['onlykey'] \ + and acct['LOGIN'] == tmccCreator[0]['CREATOR']: + # found creator + (creatorUID,creatorEmail) = (acct['LOGIN'],acct['EMAIL']) + break + pass +if creatorUID == None or creatorEmail == None: + print "ERROR: could not find experiment creator's user info!" + sys.exit(-1) + pass + + +# 0. +(rootUID,rootPasswd) = (None,None) +try: + ret = readRootAcctInfo() + if ret != None and len(ret) == 2: + (rootUID,rootPasswd) = ret + print "plabinelab: read root account info" + pass +except: + print "ERROR: could not read root account info!" + traceback.print_exc() + sys.exit(-1) + pass + +if rootUID == None or rootPasswd == None: + try: + (rootUID,rootPasswd) = writeRootAcctInfo() + print "plabinelab: wrote new root account info" + except: + print "ERROR: could not write root account info!" + traceback.print_exc() + sys.exit(-1) + pass + pass + +# 1. +# XXX: can eventually store these in some other xml file, then merge them in +# with the main plc config file. Better to do it this way since then +# plc-config-tty will still work... + +# grab the PLC's name while we're at it... +PLC_NAME = plcReadConfigVar('plc','name') + +print "plabinelab: updating config for PLC '%s'" % str(PLC_NAME) +configVarsList = [ [ 'plc_www','ip', DEF_PLC_IP ], + [ 'plc_www','host', DEF_PLC_HOST ], + [ 'plc','root_user', rootUID ], + [ 'plc','root_password', rootPasswd ], + [ 'plc_boot','ip', DEF_PLC_IP ], + [ 'plc_boot','host', DEF_PLC_HOST ], + [ 'plc_mail','support_address',creatorEmail ], + [ 'plc_mail','boot_address', creatorEmail ], + [ 'plc_mail','slice_address', creatorEmail ], + [ 'plc_api','ip', DEF_PLC_IP ], + [ 'plc_api','host', DEF_PLC_HOST ], + [ 'plc_db','ip', DEF_PLC_IP ], + [ 'plc_db','host', DEF_PLC_HOST ] ] +plcUpdateConfig(configVarsList) + +# XXX: can't find a good way to grab this, but it's unlikely that it will +# change during emulab exp runtime. +PLC_BOOTCD_VERSION = '3.3' + +# 2. +print "plabinelab: restarting plc" +doService('plc','start') + +# 3. +# first update users: +print "plabinelab: updating user accounts" +userlist = list() +for lineDict in tmccAccounts: + if 'ADDUSER' in lineDict['onlykey']: + root = False + if lineDict['ROOT'] == '1': + root = True + pass + # we use the @emulab.net address because it makes it easier for us + # to later remove users during a swapmod (there are legit plc users + # in the db that are needed for plc maint). + userlist.append((lineDict['NAME'], + lineDict['LOGIN'] + '@emulab.net',lineDict['PSWD'], + readUserKeys(lineDict['LOGIN']),root)) + pass + pass + +plcUpdateUsers(userlist) + +# now do nodes: +print "plabinelab: updating nodes" +nodelist = list() +for lineDict in tmccEPlabConfig: + if lineDict.has_key('ROLE') and lineDict['ROLE'] == 'node': + nodelist.append((lineDict['PNAME'], + lineDict['CNETIP'],lineDict['CNETMAC'])) + pass + pass + +plcUpdateNodes(nodelist) + +# 4. +# first create the local node config info: +vnameToNID = dict() +nidToMAC = dict() +# XXX: this does depend on tmcd returning the ROLE lines before the private +# iface lines for each vname. +for lineDict in tmccEPlabConfig: + if lineDict.has_key('ROLE') and lineDict['ROLE'] == 'node': + nid = plcGetNodeID(lineDict['PNAME']) + + print "plabinelab: generating config files for node id %d" % nid + + vnameToNID[lineDict['VNAME']] = nid + nidToMAC[nid] = lineDict['CNETMAC'] + + configLines = plcGetNodeConfig(lineDict['PNAME']) + macLines = [ addMACDelim(lineDict['CNETMAC'],'-') ] + + if not os.path.exists('/plc/emulab/nodes/%d' % nid): + os.makedirs('/plc/emulab/nodes/%d' % nid) + pass + + cfd = open('/plc/emulab/nodes/%d/conf' % nid,'w') + for cl in configLines: + cfd.write('%s\n' % cl) + pass + cfd.close() + + mfd = open('/plc/emulab/nodes/%d/mac' % nid,'w') + for ml in macLines: + mfd.write('%s\n' % ml) + pass + mfd.close() + + pass + elif not lineDict.has_key('ROLE') and lineDict.has_key('VNAME'): + nid = vnameToNID[lineDict['VNAME']] + + pfd = open('/plc/emulab/nodes/%d/ifcfg-eth1' % nid,'w') + pfd.write("DEVICE=eth1\n") + pfd.write("BOOTPROTO=none\n") + pfd.write("IPADDR=%s\n" % lineDict['IP']) + pfd.write("NETMASK=%s\n" % lineDict['NETMASK']) + pfd.write("HWADDR=%s\n" % addMACDelim(lineDict['MAC'],':')) + pfd.write("ONBOOT=yes\n") + pfd.write("TYPE=Ethernet\n") + pfd.close() + pass + pass + +# tar it up... +for nid in vnameToNID.values(): + print "plabinelab: creating config tarball for node id %d" % nid + os.system('rm -rf /tmp/ncfg-root') + os.makedirs('/tmp/ncfg-root/etc') + os.system('cp /etc/hosts /tmp/ncfg-root/etc/') + if os.path.isfile('/plc/emulab/nodes/%d/ifcfg-eth1' % nid): + os.makedirs('/tmp/ncfg-root/etc/sysconfig/network-scripts') + os.system('cp /plc/emulab/nodes/%d/ifcfg-eth1 /tmp/ncfg-root/etc/sysconfig/network-scripts' % nid) + pass + cwd = os.getcwd() + os.chdir('/tmp/ncfg-root') + os.system('tar cf /plc/data/var/www/html/download/%d.tar .' % nid) + os.chdir(cwd) + os.system('rm -rf /tmp/ncfg-root') + pass + +# setup tftp: +# we have to extract the node kernel that chainboots into the real kernel, +# the various img files, and create an img with config data for each node. +# also end up adjusting the isolinux boot cmdline. + +print "plabinelab: extracting info from BootCD" + +if not os.path.exists('/mnt/bootcd'): + os.makedirs('/mnt/bootcd') + pass +os.system('mount -o loop "/plc/data/var/www/html/download/' \ + '%s-BootCD-%s-serial.iso" /mnt/bootcd' % (PLC_NAME, + PLC_BOOTCD_VERSION)) +os.system('cp /mnt/bootcd/pl_version /tftpboot') +os.system('cp /mnt/bootcd/kernel /tftpboot') +os.system('cp /mnt/bootcd/*.img /tftpboot') + +ilfd = open('/mnt/bootcd/isolinux.cfg','r') +ilconfigLines = ilfd.read().split('\n') +ilfd.close() + +for nid in vnameToNID.values(): + print "plabinelab: configuring pxelinux for node id %d" % nid + + os.system('rm -rf /tmp/real-ncfg') + os.makedirs('/tmp/real-ncfg/usr/boot') + os.system('cp /plc/emulab/nodes/%d/conf ' \ + '/tmp/real-ncfg/usr/boot/plnode.txt' % nid) + cwd = os.getcwd() + os.chdir('/tmp/real-ncfg') + os.system('find . | cpio -o -c | gzip -9 > /tftpboot/config-%d.img' % nid) + os.system('rm -rf /tmp/real-ncfg') + os.chdir(cwd) + + if not os.path.exists('/tftpboot/pxelinux.cfg'): + os.makedirs('/tftpboot/pxelinux.cfg') + pass + + pfd = open('/tftpboot/pxelinux.cfg/01-%s' % addMACDelim(nidToMAC[nid],'-'),'w') + for iline in ilconfigLines: + rline = '' + if iline.count('initrd') > 0: + sline = iline.split('img') + for sl in sline[:-1]: + rline += sl + 'img' + pass + rline += ',config-%d.img' % nid + rline += sline[-1] + pass + else: + rline = iline + pass + pfd.write('%s\n' % rline) + pass + pfd.close() + pass + +os.system('umount /mnt/bootcd') + +# 5. +os.system('chkconfig plc off') + +# Finis. +print "plabinelab: done!" + +sys.exit(0)