--- /dev/null
+import xmlrpclib
+import xml.parsers.expat
+import hmac
+import string
+import sha
+
+from Exceptions import *
+
+
+def create_auth_structure( vars, call_params ):
+ """
+ create and return an authentication structure for a Boot API
+ call. Vars contains the boot manager runtime variables, and
+ call_params is a tuple of the parameters that will be passed to the
+ API call. Return None if unable to (typically due to missing
+ keys in vars, such as node_id or node_key)
+ """
+
+ auth= {}
+ auth['AuthMethod']= 'hmac'
+
+ try:
+ network= vars['NETWORK_SETTINGS']
+
+ auth['node_id']= vars['NODE_ID']
+ auth['node_ip']= network['ip']
+ node_key= vars['NODE_KEY']
+ except KeyError, e:
+ return None
+
+ msg= serialize_params(call_params)
+ node_hmac= hmac.new(node_key,msg,sha).hexdigest()
+ auth['value']= node_hmac
+
+ return auth
+
+
+
+def serialize_params( call_params ):
+ """
+ convert a list of parameters into a format that will be used in the
+ hmac generation. both the boot manager and plc must have a common
+ format. full documentation is in the boot manager technical document,
+ but essentially we are going to take all the values (and keys for
+ dictionary objects), and put them into a list. sort them, and combine
+ them into one long string encased in a set of braces.
+ """
+
+ # if there are no parameters, just return empty paren set
+ if len(call_params) == 0:
+ return "[]"
+
+ values= []
+
+ for param in call_params:
+ if isinstance(param,list) or isinstance(param,tuple):
+ values= values + map(str,param)
+ elif isinstance(param,dict):
+ values= values + collapse_dict(param)
+ else:
+ values.append( str(param) )
+
+ values.sort()
+ values= "[" + string.join(values,"") + "]"
+ return values
+
+
+def collapse_dict( value ):
+ """
+ given a dictionary, return a list of all the keys and values as strings,
+ in no particular order
+ """
+
+ item_list= []
+
+ if not isinstance(value,dict):
+ return item_list
+
+ for key in value.keys():
+ key_value= value[key]
+ if isinstance(key_value,list) or isinstance(key_value,tuple):
+ item_list= item_list + map(str,key_value)
+ elif isinstance(key_value,dict):
+ item_list= item_list + collapse_dict(key_value)
+ else:
+ item_list.append( str(key_value) )
+
+ return item_list
+
+
+
+def call_api_function( vars, function, user_params ):
+ """
+ call the named api function with params, and return the
+ value to the caller. the authentication structure is handled
+ automatically, and doesn't need to be passed in with params.
+
+ If the call fails, a BootManagerException is raised.
+ """
+
+ try:
+ api_server= vars['API_SERVER_INST']
+ except KeyError, e:
+ raise BootManagerException, "No connection to the API server exists."
+
+ auth= create_auth_structure(vars,user_params)
+ if auth is None:
+ raise BootManagerException, \
+ "Could not create auth structure, missing values."
+
+ params= (auth,)
+ params= params + user_params
+
+ try:
+ exec( "rc= api_server.%s(*params)" % function )
+ return rc
+ except xmlrpclib.Fault, fault:
+ raise BootManagerException, "API Fault: %s" % fault
+ except xmlrpclib.ProtocolError, err:
+ raise BootManagerException,"XML RPC protocol error: %s" % err
+ except xml.parsers.expat.ExpatError, err:
+ raise BootManagerException,"XML parsing error: %s" % err
--- /dev/null
+#!/usr/bin/python2 -u
+
+# ------------------------------------------------------------------------
+# THIS file used to be named alpina.py, from the node installer. Since then
+# the installer has been expanded to include all the functions of the boot
+# manager as well, hence the new name for this file.
+# ------------------------------------------------------------------------
+
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import string
+import sys, os, traceback
+from time import gmtime, strftime
+from gzip import GzipFile
+
+from steps import *
+from Exceptions import *
+import notify_messages
+
+
+
+# all output is written to this file
+LOG_FILE= "/tmp/bm.log"
+CURL_PATH= "curl"
+UPLOAD_LOG_URL = "http://boot.planet-lab.org/alpina-logs/upload.php"
+
+# the new contents of PATH when the boot manager is running
+BIN_PATH= ('/usr/local/bin',
+ '/usr/local/sbin',
+ '/bin',
+ '/sbin',
+ '/usr/bin',
+ '/usr/sbin',
+ '/usr/local/planetlab/bin')
+
+
+
+class log:
+
+ def __init__( self, OutputFilePath= None ):
+ if OutputFilePath:
+ try:
+ self.OutputFilePath= OutputFilePath
+ self.OutputFile= GzipFile( OutputFilePath, "w", 9 )
+ except:
+ print( "Unable to open output file for log, continuing" )
+ self.OutputFile= None
+
+ # for upload
+ os.system( "ifconfig eth0 > /tmp/ifconfig" )
+
+
+ def LogEntry( self, str, inc_newline= 1, display_screen= 1 ):
+ if self.OutputFile:
+ self.OutputFile.write( str )
+ if display_screen:
+ sys.stdout.write( str )
+
+ if inc_newline:
+ if display_screen:
+ sys.stdout.write( "\n" )
+ if self.OutputFile:
+ self.OutputFile.write( "\n" )
+
+ if self.OutputFile:
+ self.OutputFile.flush()
+
+
+
+ def write( self, str ):
+ """
+ make log behave like a writable file object (for traceback
+ prints)
+ """
+ self.LogEntry( str, 0, 1 )
+
+
+
+ def Upload( self ):
+ """
+ upload the contents of the log to the server
+ """
+
+ self.LogEntry( "Uploading logs to %s" % UPLOAD_LOG_URL )
+
+ self.OutputFile.close()
+ self.OutputFile= None
+
+ curl_cmd= "%s -s --connect-timeout 60 --max-time 600 " \
+ "--form log=@%s --form ifconfig=\</tmp/ifconfig %s" % \
+ (CURL_PATH, self.OutputFilePath, UPLOAD_LOG_URL)
+ os.system( curl_cmd )
+
+
+
+
+
+
+class BootManager:
+
+ # file containing initial variables/constants
+ VARS_FILE = "configuration"
+
+
+ def __init__(self, log):
+ # this contains a set of information used and updated
+ # by each step
+ self.VARS= {}
+
+ # the main logging point
+ self.LOG= log
+
+ # set to 1 if we can run after initialization
+ self.CAN_RUN = 0
+
+ if not self.ReadBMConf():
+ self.LOG.LogEntry( "Unable to read configuration vars." )
+ return
+
+ # find out which directory we are running it, and set a variable
+ # for that. future steps may need to get files out of the bootmanager
+ # directory
+ current_dir= os.getcwd()
+ self.VARS['BM_SOURCE_DIR']= current_dir
+
+ # not sure what the current PATH is set to, replace it with what
+ # we know will work with all the boot cds
+ os.environ['PATH']= string.join(BIN_PATH,":")
+
+ self.CAN_RUN= 1
+
+
+
+
+ def ReadBMConf(self):
+ """
+ read in and store all variables in VARS_FILE into
+ self.VARS
+
+ each line is in the format name=val (any whitespace around
+ the = is removed. everything after the = to the end of
+ the line is the value
+ """
+
+ vars_file= file(self.VARS_FILE,'r')
+ for line in vars_file:
+ # if its a comment or a whitespace line, ignore
+ if line[:1] == "#" or string.strip(line) == "":
+ continue
+
+ parts= string.split(line,"=")
+ if len(parts) != 2:
+ self.LOG.LogEntry( "Invalid line in vars file: %s" % line )
+ return 0
+
+ name= string.strip(parts[0])
+ value= string.strip(parts[1])
+
+ self.VARS[name]= value
+
+ return 1
+
+
+ def Run(self):
+ """
+ core boot manager logic.
+
+ the way errors are handled is as such: if any particular step
+ cannot continue or unexpectibly fails, an exception is thrown.
+ in this case, the boot manager cannot continue running.
+
+ these step functions can also return a 0/1 depending on whether
+ or not it succeeded. In the case of steps like ConfirmInstallWithUser,
+ a 0 is returned and no exception is thrown if the user chose not
+ to confirm the install. The same goes with the CheckHardwareRequirements.
+ If requriements not met, but tests were succesfull, return 0.
+
+ for steps that run within the installer, they are expected to either
+ complete succesfully and return 1, or throw an execption.
+
+ For exact return values and expected operations, see the comments
+ at the top of each of the invididual step functions.
+ """
+
+ try:
+ InitializeBootManager.Run( self.VARS, self.LOG )
+ ReadNodeConfiguration.Run( self.VARS, self.LOG )
+ AuthenticateWithPLC.Run( self.VARS, self.LOG )
+ GetAndUpdateNodeDetails.Run( self.VARS, self.LOG )
+
+ if self.VARS['BOOT_STATE'] == 'new' or \
+ self.VARS['BOOT_STATE'] == 'inst':
+ if not ConfirmInstallWithUser.Run( self.VARS, self.LOG ):
+ return 0
+
+ self.VARS['BOOT_STATE']= 'rins'
+ UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
+
+ if not CheckHardwareRequirements.Run( self.VARS, self.LOG ):
+ self.VARS['BOOT_STATE']= 'dbg'
+ UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
+ raise BootManagerException, "Hardware requirements not met."
+
+ self.RunInstaller()
+
+ if ValidateNodeInstall.Run( self.VARS, self.LOG ):
+ SendHardwareConfigToPLC.Run( self.VARS, self.LOG )
+ ChainBootNode.Run( self.VARS, self.LOG )
+ else:
+ self.VARS['BOOT_STATE']= 'dbg'
+ self.VARS['STATE_CHANGE_NOTIFY']= 1
+ self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \
+ notify_messages.MSG_NODE_NOT_INSTALLED
+ UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
+
+
+ elif self.VARS['BOOT_STATE'] == 'rins':
+ if not CheckHardwareRequirements.Run( self.VARS, self.LOG ):
+ self.VARS['BOOT_STATE']= 'dbg'
+ UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
+ raise BootManagerException, "Hardware requirements not met."
+
+ self.RunInstaller()
+
+ if ValidateNodeInstall.Run( self.VARS, self.LOG ):
+ SendHardwareConfigToPLC.Run( self.VARS, self.LOG )
+ ChainBootNode.Run( self.VARS, self.LOG )
+ else:
+ self.VARS['BOOT_STATE']= 'dbg'
+ self.VARS['STATE_CHANGE_NOTIFY']= 1
+ self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \
+ notify_messages.MSG_NODE_NOT_INSTALLED
+ UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
+
+ elif self.VARS['BOOT_STATE'] == 'boot':
+ if ValidateNodeInstall.Run( self.VARS, self.LOG ):
+ UpdateNodeConfiguration.Run( self.VARS, self.LOG )
+ CheckForNewDisks.Run( self.VARS, self.LOG )
+ SendHardwareConfigToPLC.Run( self.VARS, self.LOG )
+ ChainBootNode.Run( self.VARS, self.LOG )
+ else:
+ self.VARS['BOOT_STATE']= 'dbg'
+ self.VARS['STATE_CHANGE_NOTIFY']= 1
+ self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \
+ notify_messages.MSG_NODE_NOT_INSTALLED
+ UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
+
+ elif self.VARS['BOOT_STATE'] == 'dbg':
+ StartDebug.Run( self.VARS, self.LOG )
+
+ except KeyError, e:
+ self.LOG.write( "\n\nKeyError while running: %s\n" % str(e) )
+ except BootManagerException, e:
+ self.LOG.write( "\n\nException while running: %s\n" % str(e) )
+
+ return 1
+
+
+
+ def RunInstaller(self):
+ """
+ since the installer can be invoked at more than one place
+ in the boot manager logic, seperate the steps necessary
+ to do it here
+ """
+
+ InstallInit.Run( self.VARS, self.LOG )
+ InstallPartitionDisks.Run( self.VARS, self.LOG )
+ InstallBootstrapRPM.Run( self.VARS, self.LOG )
+ InstallBase.Run( self.VARS, self.LOG )
+ InstallWriteConfig.Run( self.VARS, self.LOG )
+ InstallBuildVServer.Run( self.VARS, self.LOG )
+ InstallNodeInit.Run( self.VARS, self.LOG )
+ InstallUninitHardware.Run( self.VARS, self.LOG )
+
+ self.VARS['BOOT_STATE']= 'boot'
+ self.VARS['STATE_CHANGE_NOTIFY']= 1
+ self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \
+ notify_messages.MSG_INSTALL_FINISHED
+ UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
+
+ SendHardwareConfigToPLC.Run( self.VARS, self.LOG )
+
+
+
+if __name__ == "__main__":
+
+ # set to 0 if no error occurred
+ error= 1
+
+ # all output goes through this class so we can save it and post
+ # the data back to PlanetLab central
+ LOG= log( LOG_FILE )
+
+ LOG.LogEntry( "BootManager started at: %s" % \
+ strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) )
+
+ try:
+ bm= BootManager(LOG)
+ if bm.CAN_RUN == 0:
+ LOG.LogEntry( "Unable to initialize BootManager." )
+ else:
+ LOG.LogEntry( "Running version %s of BootManager." %
+ bm.VARS['VERSION'] )
+ success= bm.Run()
+ if success:
+ LOG.LogEntry( "\nDone!" );
+ else:
+ LOG.LogEntry( "\nError occurred!" );
+
+ except:
+ traceback.print_exc(file=LOG.OutputFile)
+ traceback.print_exc()
+
+ LOG.LogEntry( "BootManager finished at: %s" % \
+ strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) )
+
+ LOG.Upload()
+
+ sys.exit(error)
--- /dev/null
+#!/usr/bin/python2
+
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import os, sys
+import re
+import string
+import urllib
+
+# try to load pycurl
+try:
+ import pycurl
+ PYCURL_LOADED= 1
+except:
+ PYCURL_LOADED= 0
+
+
+# if there is no cStringIO, fall back to the original
+try:
+ from cStringIO import StringIO
+except:
+ from StringIO import StringIO
+
+
+
+class BootServerRequest:
+
+ VERBOSE = 0
+
+ # all possible places to check the cdrom mount point.
+ # /mnt/cdrom is typically after the machine has come up,
+ # and /usr is when the boot cd is running
+ CDROM_MOUNT_PATH = ("/mnt/cdrom/","/usr/")
+
+ # this is the server to contact if we don't have a bootcd
+ DEFAULT_BOOT_SERVER = "boot.planet-lab.org"
+
+ BOOTCD_VERSION_FILE = "bootme/ID"
+ BOOTCD_SERVER_FILE = "bootme/BOOTSERVER"
+ BOOTCD_SERVER_CERT_DIR = "bootme/cacert"
+ CACERT_NAME = "cacert.pem"
+
+ # location of file containing http/https proxy info, if needed
+ PROXY_FILE = '/etc/planetlab/http_proxy'
+
+ # location of curl executable, if pycurl isn't available
+ # and the DownloadFile method is called (backup, only
+ # really need for the boot cd environment where pycurl
+ # doesn't exist
+ CURL_CMD = 'curl'
+
+ # in seconds, how maximum time allowed for connect
+ DEFAULT_CURL_CONNECT_TIMEOUT = 30
+
+ # in seconds, maximum time allowed for any transfer
+ DEFAULT_CURL_MAX_TRANSFER_TIME = 3600
+
+ CURL_SSL_VERSION = 3
+
+ HTTP_SUCCESS = 200
+
+ # proxy variables
+ USE_PROXY = 0
+ PROXY = 0
+
+ # bootcd variables
+ HAS_BOOTCD = 0
+ BOOTCD_VERSION = ""
+ BOOTSERVER_CERTS= {}
+
+ def __init__(self, verbose=0):
+
+ self.VERBOSE= verbose
+
+ # see if we have a boot cd mounted by checking for the version file
+ # if HAS_BOOTCD == 0 then either the machine doesn't have
+ # a boot cd, or something else is mounted
+ self.HAS_BOOTCD = 0
+
+ for path in self.CDROM_MOUNT_PATH:
+ self.Message( "Checking existance of boot cd on %s" % path )
+
+ os.system("/bin/mount %s > /dev/null 2>&1" % path )
+
+ version_file= path + self.BOOTCD_VERSION_FILE
+ self.Message( "Looking for version file %s" % version_file )
+
+ if os.access(version_file, os.R_OK) == 0:
+ self.Message( "No boot cd found." );
+ else:
+ self.Message( "Found boot cd." )
+ self.HAS_BOOTCD=1
+ break
+
+
+ if self.HAS_BOOTCD:
+
+ # check the version of the boot cd, and locate the certs
+ self.Message( "Getting boot cd version." )
+
+ versionRegExp= re.compile(r"PlanetLab BootCD v(\S+)")
+
+ bootcd_version_f= file(version_file,"r")
+ line= string.strip(bootcd_version_f.readline())
+ bootcd_version_f.close()
+
+ match= versionRegExp.findall(line)
+ if match:
+ (self.BOOTCD_VERSION)= match[0]
+
+ # right now, all the versions of the bootcd are supported,
+ # so no need to check it
+
+ # create a list of the servers we should
+ # attempt to contact, and the certs for each
+ server_list= path + self.BOOTCD_SERVER_FILE
+ self.Message( "Getting list of servers off of cd from %s." %
+ server_list )
+
+ bootservers_f= file(server_list,"r")
+ bootservers= bootservers_f.readlines()
+ bootservers_f.close()
+
+ for bootserver in bootservers:
+ bootserver = string.strip(bootserver)
+ cacert_path= "%s/%s/%s/%s" % \
+ (path,self.BOOTCD_SERVER_CERT_DIR,
+ bootserver,self.CACERT_NAME)
+ if os.access(cacert_path, os.R_OK):
+ self.BOOTSERVER_CERTS[bootserver]= cacert_path
+
+ self.Message( "Set of servers to contact: %s" %
+ str(self.BOOTSERVER_CERTS) )
+ else:
+ self.Message( "Using default boot server address." )
+ self.BOOTSERVER_CERTS[self.DEFAULT_BOOT_SERVER]= ""
+
+
+ def CheckProxy( self ):
+ # see if we have any proxy info from the machine
+ self.USE_PROXY= 0
+ self.Message( "Checking existance of proxy config file..." )
+
+ if os.access(self.PROXY_FILE, os.R_OK) and \
+ os.path.isfile(self.PROXY_FILE):
+ self.PROXY= string.strip(file(self.PROXY_FILE,'r').readline())
+ self.USE_PROXY= 1
+ self.Message( "Using proxy %s." % self.PROXY )
+ else:
+ self.Message( "Not using any proxy." )
+
+
+
+ def Message( self, Msg ):
+ if( self.VERBOSE ):
+ print( Msg )
+
+
+
+ def Error( self, Msg ):
+ sys.stderr.write( Msg + "\n" )
+
+
+
+ def Warning( self, Msg ):
+ self.Error(Msg)
+
+
+
+ def MakeRequest( self, PartialPath, GetVars,
+ PostVars, DoSSL, DoCertCheck,
+ ConnectTimeout= DEFAULT_CURL_CONNECT_TIMEOUT,
+ MaxTransferTime= DEFAULT_CURL_MAX_TRANSFER_TIME):
+
+ if PYCURL_LOADED == 0:
+ self.Error( "MakeRequest method requires pycurl." )
+ return None
+
+ self.CheckProxy()
+
+ self.Message( "Attempting to retrieve %s" % PartialPath )
+
+ # we can't do ssl and check the cert if we don't have a bootcd
+ if DoSSL and DoCertCheck and not self.HAS_BOOTCD:
+ self.Error( "No boot cd exists (needed to use -c and -s.\n" )
+ return None
+
+ # didn't pass a path in? just get the root doc
+ if PartialPath == "":
+ PartialPath= "/"
+
+ # ConnectTimeout has to be greater than 0
+ if ConnectTimeout <= 0:
+ self.Error( "Connect timeout must be greater than zero.\n" )
+ return None
+
+ # setup the post and get vars for the request
+ if PostVars:
+ dopostdata= 1
+ postdata = urllib.urlencode(PostVars)
+ self.Message( "Posting data:\n%s\n" % postdata )
+ else:
+ dopostdata= 0
+
+ getstr= ""
+ if GetVars:
+ getstr= "?" + urllib.urlencode(GetVars)
+ self.Message( "Get data:\n%s\n" % getstr )
+
+ # now, attempt to make the request, starting at the first
+ # server in the list
+ for server in self.BOOTSERVER_CERTS:
+ self.Message( "Contacting server %s." % server )
+
+ certpath = self.BOOTSERVER_CERTS[server]
+
+ curl= pycurl.Curl()
+
+ # don't want curl sending any signals
+ curl.setopt(pycurl.NOSIGNAL, 1)
+
+ curl.setopt(pycurl.CONNECTTIMEOUT, ConnectTimeout)
+ self.Message( "Connect timeout is %s seconds" % \
+ ConnectTimeout )
+
+ curl.setopt(pycurl.TIMEOUT, MaxTransferTime)
+ self.Message( "Max transfer time is %s seconds" % \
+ MaxTransferTime )
+
+ curl.setopt(pycurl.FOLLOWLOCATION, 1)
+ curl.setopt(pycurl.MAXREDIRS, 2)
+
+ if self.USE_PROXY:
+ curl.setopt(pycurl.PROXY, self.PROXY )
+
+ if DoSSL:
+ curl.setopt(pycurl.SSLVERSION, self.CURL_SSL_VERSION)
+
+ url = "https://%s/%s%s" % (server,PartialPath,getstr)
+ if DoCertCheck:
+ curl.setopt(pycurl.CAINFO, certpath)
+ curl.setopt(pycurl.SSL_VERIFYPEER, 2)
+ self.Message( "Using SSL version %d and verifying peer." % \
+ self.CURL_SSL_VERSION )
+ else:
+ curl.setopt(pycurl.SSL_VERIFYPEER, 0)
+ self.Message( "Using SSL version %d" % \
+ self.CURL_SSL_VERSION )
+ else:
+ url = "http://%s/%s%s" % (server,PartialPath,getstr)
+
+ if dopostdata:
+ curl.setopt(pycurl.POSTFIELDS, postdata)
+
+ curl.setopt(pycurl.URL, url)
+ self.Message( "URL: %s" % url )
+
+ # setup the output buffer
+ buffer = StringIO()
+ curl.setopt(pycurl.WRITEFUNCTION, buffer.write)
+
+ try:
+ self.Message( "Fetching..." )
+ curl.perform()
+ self.Message( "Done." )
+
+ http_result= curl.getinfo(pycurl.HTTP_CODE)
+ curl.close()
+
+ # check the code, return the string only if it was successfull
+ if http_result == self.HTTP_SUCCESS:
+ self.Message( "Successfull!" )
+ return buffer.getvalue()
+ else:
+ self.Message( "Failure, resultant http code: %d" % \
+ http_result )
+ return None
+
+ except pycurl.error, err:
+ errno, errstr= err
+ self.Error( "connect to %s failed; curl error %d: '%s'\n" %
+ (server,errno,errstr) )
+
+ self.Error( "Unable to successfully contact any boot servers.\n" )
+ return None
+
+
+
+ def DownloadFile(self, PartialPath, GetVars, PostVars,
+ DoSSL, DoCertCheck, DestFilePath,
+ ConnectTimeout= DEFAULT_CURL_CONNECT_TIMEOUT,
+ MaxTransferTime= DEFAULT_CURL_MAX_TRANSFER_TIME):
+
+ self.Message( "Attempting to retrieve %s" % PartialPath )
+
+ # we can't do ssl and check the cert if we don't have a bootcd
+ if DoSSL and DoCertCheck and not self.HAS_BOOTCD:
+ self.Error( "No boot cd exists (needed to use -c and -s.\n" )
+ return 0
+
+ if DoSSL and not PYCURL_LOADED:
+ self.Warning( "Using SSL without pycurl will by default " \
+ "check at least standard certs." )
+
+ # ConnectTimeout has to be greater than 0
+ if ConnectTimeout <= 0:
+ self.Error( "Connect timeout must be greater than zero.\n" )
+ return 0
+
+
+ self.CheckProxy()
+
+ dopostdata= 0
+
+ # setup the post and get vars for the request
+ if PostVars:
+ dopostdata= 1
+ postdata = urllib.urlencode(PostVars)
+ self.Message( "Posting data:\n%s\n" % postdata )
+
+ getstr= ""
+ if GetVars:
+ getstr= "?" + urllib.urlencode(GetVars)
+ self.Message( "Get data:\n%s\n" % getstr )
+
+ # now, attempt to make the request, starting at the first
+ # server in the list
+
+ for server in self.BOOTSERVER_CERTS:
+ self.Message( "Contacting server %s." % server )
+
+ certpath = self.BOOTSERVER_CERTS[server]
+
+
+ # output what we are going to be doing
+ self.Message( "Connect timeout is %s seconds" % \
+ ConnectTimeout )
+
+ self.Message( "Max transfer time is %s seconds" % \
+ MaxTransferTime )
+
+ if DoSSL:
+ url = "https://%s/%s%s" % (server,PartialPath,getstr)
+
+ if DoCertCheck and PYCURL_LOADED:
+ self.Message( "Using SSL version %d and verifying peer." %
+ self.CURL_SSL_VERSION )
+ else:
+ self.Message( "Using SSL version %d." %
+ self.CURL_SSL_VERSION )
+ else:
+ url = "http://%s/%s%s" % (server,PartialPath,getstr)
+
+ self.Message( "URL: %s" % url )
+
+ # setup a new pycurl instance, or a curl command line string
+ # if we don't have pycurl
+
+ if PYCURL_LOADED:
+ curl= pycurl.Curl()
+
+ # don't want curl sending any signals
+ curl.setopt(pycurl.NOSIGNAL, 1)
+
+ curl.setopt(pycurl.CONNECTTIMEOUT, ConnectTimeout)
+ curl.setopt(pycurl.TIMEOUT, MaxTransferTime)
+
+ # do not follow location when attempting to download a file
+ curl.setopt(pycurl.FOLLOWLOCATION, 0)
+
+ if self.USE_PROXY:
+ curl.setopt(pycurl.PROXY, self.PROXY )
+
+ if DoSSL:
+ curl.setopt(pycurl.SSLVERSION, self.CURL_SSL_VERSION)
+
+ if DoCertCheck:
+ curl.setopt(pycurl.CAINFO, certpath)
+ curl.setopt(pycurl.SSL_VERIFYPEER, 2)
+
+ else:
+ curl.setopt(pycurl.SSL_VERIFYPEER, 0)
+
+ if dopostdata:
+ curl.setopt(pycurl.POSTFIELDS, postdata)
+
+ curl.setopt(pycurl.URL, url)
+ else:
+
+ cmdline = "%s " \
+ "--connect-timeout %d " \
+ "--max-time %d " \
+ "--header Pragma: " \
+ "--output %s " \
+ "--fail " % \
+ (self.CURL_CMD, ConnectTimeout,
+ MaxTransferTime, DestFilePath)
+
+ if dopostdata:
+ cmdline = cmdline + "--data '" + postdata + "' "
+
+ if not self.VERBOSE:
+ cmdline = cmdline + "--silent "
+
+ if self.USE_PROXY:
+ cmdline = cmdline + "--proxy %s " % self.PROXY
+
+ if DoSSL:
+ cmdline = cmdline + "--sslv%d " % self.CURL_SSL_VERSION
+
+ if DoCertCheck:
+ cmdline = cmdline + "--cacert %s " % certpath
+
+ cmdline = cmdline + url
+
+ self.Message( "curl command: %s" % cmdline )
+
+
+ if PYCURL_LOADED:
+ try:
+ # setup the output file
+ outfile = open(DestFilePath,"wb")
+
+ self.Message( "Opened output file %s" % DestFilePath )
+
+ curl.setopt(pycurl.WRITEDATA, outfile)
+
+ self.Message( "Fetching..." )
+ curl.perform()
+ self.Message( "Done." )
+
+ http_result= curl.getinfo(pycurl.HTTP_CODE)
+ curl.close()
+
+ outfile.close()
+ self.Message( "Results saved in %s" % DestFilePath )
+
+ # check the code, return 1 if successfull
+ if http_result == self.HTTP_SUCCESS:
+ self.Message( "Successfull!" )
+ return 1
+ else:
+ self.Message( "Failure, resultant http code: %d" % \
+ http_result )
+
+ except pycurl.error, err:
+ errno, errstr= err
+ self.Error( "connect to %s failed; curl error %d: '%s'\n" %
+ (server,errno,errstr) )
+
+ if not outfile.closed:
+ try:
+ os.unlink(DestFilePath)
+ outfile.close
+ except OSError:
+ pass
+
+ else:
+ self.Message( "Fetching..." )
+ rc = os.system(cmdline)
+ self.Message( "Done." )
+
+ if rc != 0:
+ try:
+ os.unlink( DestFilePath )
+ except OSError:
+ pass
+ self.Message( "Failure, resultant curl code: %d" % rc )
+ self.Message( "Removed %s" % DestFilePath )
+ else:
+ self.Message( "Successfull!" )
+ return 1
+
+ self.Error( "Unable to successfully contact any boot servers.\n" )
+ return 0
+
+
+
+
+def usage():
+ print(
+ """
+Usage: BootServerRequest.py [options] <partialpath>
+Options:
+ -c/--checkcert Check SSL certs. Ignored if -s/--ssl missing.
+ -h/--help This help text
+ -o/--output <file> Write result to file
+ -s/--ssl Make the request over HTTPS
+ -v Makes the operation more talkative
+""");
+
+
+
+if __name__ == "__main__":
+ import getopt
+
+ # check out our command line options
+ try:
+ opt_list, arg_list = getopt.getopt(sys.argv[1:],
+ "o:vhsc",
+ [ "output=", "verbose", \
+ "help","ssl","checkcert"])
+
+ ssl= 0
+ checkcert= 0
+ output_file= None
+ verbose= 0
+
+ for opt, arg in opt_list:
+ if opt in ("-h","--help"):
+ usage(0)
+ sys.exit()
+
+ if opt in ("-c","--checkcert"):
+ checkcert= 1
+
+ if opt in ("-s","--ssl"):
+ ssl= 1
+
+ if opt in ("-o","--output"):
+ output_file= arg
+
+ if opt == "-v":
+ verbose= 1
+
+ if len(arg_list) != 1:
+ raise Exception
+
+ partialpath= arg_list[0]
+ if string.lower(partialpath[:4]) == "http":
+ raise Exception
+
+ except:
+ usage()
+ sys.exit(2)
+
+ # got the command line args straightened out
+ requestor= BootServerRequest(verbose)
+
+ if output_file:
+ requestor.DownloadFile( partialpath, None, None, ssl,
+ checkcert, output_file)
+ else:
+ result= requestor.MakeRequest( partialpath, None, None, ssl, checkcert)
+ if result:
+ print result
+ else:
+ sys.exit(1)
--- /dev/null
+
+class BootManagerException(Exception):
+ def __init__( self, err ):
+ self.__fault= err
+
+ def __str__( self ):
+ return self.__fault
+
--- /dev/null
+"""
+Various functions that are used to allow the boot manager to run on various
+different cds are included here
+"""
+
+import string
+import os, sys
+
+import utils
+import BootServerRequest
+
+
+def setup_lvm_2x_cd( vars, log ):
+ """
+ make available a set of lvm utilities for 2.x cds that don't have them
+ on the cd.
+
+ Expect the following variables to be set:
+ TEMP_PATH somewhere to store what we need to run
+ BOOT_CD_VERSION A tuple of the current bootcd version
+ ALPINA_SERVER_DIR directory on the boot servers containing alpina
+ scripts and support files
+ LVM_SETUP_2X_CD indicates if lvm is downloaded and setup for 2.x cds
+
+ Set the following variables upon successfully running:
+ LVM_SETUP_2X_CD indicates if lvm is downloaded and setup for 2.x cds
+ """
+
+ # make sure we have the variables we need
+ try:
+ TEMP_PATH= vars["TEMP_PATH"]
+ if TEMP_PATH == "":
+ raise ValueError, "TEMP_PATH"
+
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ ALPINA_SERVER_DIR= vars["ALPINA_SERVER_DIR"]
+ if ALPINA_SERVER_DIR == None:
+ raise ValueError, "ALPINA_SERVER_DIR"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ if BOOT_CD_VERSION[0] != 2:
+ log.write( "Only 2.x boot cds need lvm setup manually.\n" )
+ return 1
+
+ LVM_SETUP_2X_CD= 0
+ if 'LVM_SETUP_2X_CD' in vars.keys():
+ LVM_SETUP_2X_CD= vars['LVM_SETUP_2X_CD']
+
+ if LVM_SETUP_2X_CD:
+ log.write( "LVM already downloaded and setup\n" )
+ return 1
+
+ log.write( "Downloading additional libraries for lvm\n" )
+
+ bs_request= BootServerRequest.BootServerRequest()
+
+ utils.makedirs(TEMP_PATH)
+
+ # download and extract support tarball for this step,
+ # which has everything we need to successfully run
+ step_support_file= "alpina-BootLVM.tar.gz"
+ source_file= "%s/%s" % (ALPINA_SERVER_DIR,step_support_file)
+ dest_file= "%s/%s" % (TEMP_PATH, step_support_file)
+
+ log.write( "Downloading support file for this step\n" )
+ result= bs_request.DownloadFile( source_file, None, None,
+ 1, 1, dest_file )
+ if not result:
+ raise BootManagerException, "Download failed."
+
+ log.write( "Extracting support files\n" )
+ old_wd= os.getcwd()
+ utils.chdir( TEMP_PATH )
+ utils.sysexec( "tar -C / -xzf %s" % step_support_file, log )
+ utils.removefile( dest_file )
+ utils.chdir( old_wd )
+
+ utils.sysexec( "ldconfig", log )
+
+ # load lvm-mod
+ log.write( "Loading lvm module\n" )
+ utils.sysexec( "modprobe lvm-mod", log )
+
+ # take note that we have lvm setup
+ LVM_SETUP_2X_CD= 1
+ vars['LVM_SETUP_2X_CD']= LVM_SETUP_2X_CD
+
+ return 1
+
+
+
+def setup_partdisks_2x_cd( vars, log ):
+ """
+ download necessary files to handle partitioning disks on 2.x cds
+
+ Expect the following variables to be set:
+ TEMP_PATH somewhere to store what we need to run
+ BOOT_CD_VERSION A tuple of the current bootcd version
+ ALPINA_SERVER_DIR directory on the boot servers containing alpina
+ scripts and support files
+ PARTDISKS_SETUP_2X_CD indicates if lvm is downloaded and setup for 2.x cds
+
+ Set the following variables upon successfully running:
+ PARTDISKS_SETUP_2X_CD indicates if lvm is downloaded and setup for 2.x cds
+ """
+
+ # make sure we have the variables we need
+ try:
+ TEMP_PATH= vars["TEMP_PATH"]
+ if TEMP_PATH == "":
+ raise ValueError, "TEMP_PATH"
+
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ ALPINA_SERVER_DIR= vars["ALPINA_SERVER_DIR"]
+ if ALPINA_SERVER_DIR == None:
+ raise ValueError, "ALPINA_SERVER_DIR"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ if BOOT_CD_VERSION[0] != 2:
+ log.write( "Only 2.x boot cds need partition disk tools setup manually.\n" )
+ return 1
+
+ PARTDISKS_SETUP_2X_CD= 0
+ if 'PARTDISKS_SETUP_2X_CD' in vars.keys():
+ PARTDISKS_SETUP_2X_CD= vars['PARTDISKS_SETUP_2X_CD']
+
+ if PARTDISKS_SETUP_2X_CD:
+ log.write( "Partition disk tools already downloaded and setup\n" )
+ return 1
+
+ log.write( "Downloading additional libraries for partitioning disks\n" )
+
+ bs_request= BootServerRequest.BootServerRequest()
+
+ # download and extract support tarball for this step,
+ # which has everything we need to successfully run
+ step_support_file= "alpina-PartDisks.tar.gz"
+ source_file= "%s/%s" % (ALPINA_SERVER_DIR,step_support_file)
+ dest_file= "%s/%s" % (TEMP_PATH, step_support_file)
+
+ log.write( "Downloading support file for this step\n" )
+ result= bs_request.DownloadFile( source_file, None, None,
+ 1, 1, dest_file )
+ if not result:
+ raise BootManagerException, "Download failed."
+
+ log.write( "Extracting support files\n" )
+ old_wd= os.getcwd()
+ utils.chdir( TEMP_PATH )
+ utils.sysexec( "tar -xzf %s" % step_support_file, log )
+ utils.removefile( dest_file )
+ utils.chdir( old_wd )
+
+ # also included in the support package was a list of extra
+ # paths (lib-paths) for /etc/ld.so.conf.
+ # so add those, and rerun ldconfig
+ # so we can make our newly downloaded libraries available
+
+ ldconf_file= file("/etc/ld.so.conf","a+")
+ lib_paths_file= file( TEMP_PATH + "/lib-paths","r")
+
+ for line in lib_paths_file:
+ path= string.strip(line)
+ if path != "":
+ ldconf_file.write( "%s/%s\n" % (TEMP_PATH,path) )
+ ldconf_file.close()
+ lib_paths_file.close()
+
+ utils.sysexec( "ldconfig", log )
+
+ # update the PYTHONPATH to include the python modules in
+ # the support package
+ sys.path.append( TEMP_PATH + "/usr/lib/python2.2" )
+ sys.path.append( TEMP_PATH + "/usr/lib/python2.2/site-packages" )
+
+ # update the environment variable PATH to include
+ # TEMP_PATH/sbin and others there
+ new_paths= ('%s/sbin'% TEMP_PATH,
+ '%s/bin'% TEMP_PATH,
+ '%s/user/sbin'% TEMP_PATH,
+ '%s/user/bin'% TEMP_PATH)
+
+ old_path= os.environ['PATH']
+ os.environ['PATH']= old_path + ":" + string.join(new_paths,":")
+
+ # everything should be setup to import parted. this
+ # import is just to make sure it'll work when this step
+ # is being run
+ log.write( "Imported parted\n" )
+ try:
+ import parted
+ except ImportError:
+ raise BootManagerException, "Unable to import parted."
+
+ # take note that we have part disks setup
+ PARTDISKS_SETUP_2X_CD= 1
+ vars['PARTDISKS_SETUP_2X_CD']= PARTDISKS_SETUP_2X_CD
+
+
+
--- /dev/null
+# this file contains a list of variables
+# to import to the INSTALL_STORE before
+# any of the steps run.
+
+
+# the current version of the bootmanager
+VERSION=3.1
+
+
+# full url to which api server to contact
+BOOT_API_SERVER=https://www.planet-lab.org:443/PLCAPI/
+
+
+# path to store temporary files during the install,
+# do not include trailing slashes
+TEMP_PATH=/mnt/tmp
+
+
+# path to the system mount point
+SYSIMG_PATH=/mnt/tmp/sysimg
+
+
+# where the cacerts for the boot cd can be found
+# currently, this must start with /mnt/cdrom
+# which is hardcoded in the installer
+CACERT_PATH=/mnt/cdrom/bootme/cacert
+
+
+# the nonce the boot cd created, need to authenticate
+# requests that are made to the boot server
+NONCE_FILE=/tmp/nonce
+
+
+# directory containing planetlab specific configuration
+# files, like the http_proxy file
+PLCONF_DIR=/etc/planetlab
+
+
+# directory on the boot server containing
+# alpina support files and scripts
+ALPINA_SERVER_DIR=/alpina-v3
+
+
+# this sets the size of the root logical volume,
+# after the root and swap has been created, remaining
+# goes to the vserver partition
+ROOT_SIZE=3G
+
+
+# override the swap size
+SWAP_SIZE=1G
+
+
+# whether or not to skip hardware requirement check
+SKIP_HARDWARE_REQUIREMENT_CHECK=0
+
+
+# minimum amount of memory needed for installer, in kb
+MINIMUM_MEMORY=511000
+
+
+# minimum block disk size in GB to be added to lvm.
+# if any block devices are smaller than this, they are ignored.
+MINIMUM_DISK_SIZE=5
+
+
+# total minimum disk size in GB if all usable disks are below this
+# size, the node cannot be installed
+TOTAL_MINIMUM_DISK_SIZE=50
+
+
+# set of langugase for install (used in /etc/rpm/macros)
+INSTALL_LANGS=en_US
+
+
+# number of auth failures before starting debug mode
+NUM_AUTH_FAILURES_BEFORE_DEBUG=2
--- /dev/null
+ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAs3jl1PRq97O4WKngafKUe4LTkQrKqgaHUj6sUKfC9KT40ek19jlzU2YWnuoaxEpSLks+Z0KPnSAIyZW5fnFYasIh9mrLSbY06d2Mor5919sCv9fIm/6QHq6gBiFjs50HITx53jWjeu/nmZeLOBsBtioLkNW2vBMQKHz6+q+wea2nh+YX3X5ZRpSp6znPR5fjaWzm0TEfA6oStUfsOIBds98XswghfT0GtWehG5FpPT/X9g7EObQKN/fzSSe1SdMSEMLPl+e0+KQ0+jB/pCULfSm9Qlw6I5cYQXwxKeT2tEPIcmLPe/U1hhoqGyaADo+a0OmCQ84yJ3obMNMWGH0uIQ== debug@planet-lab.org
--- /dev/null
+# boot cd version 3.x sshd configuration file for debug mode
+
+#Port 22
+Protocol 2
+#ListenAddress 0.0.0.0
+#ListenAddress ::
+
+# HostKey for protocol version 1
+#HostKey /etc/ssh/ssh_host_key
+# HostKeys for protocol version 2
+#HostKey /etc/ssh/ssh_host_rsa_key
+#HostKey /etc/ssh/ssh_host_dsa_key
+
+# Lifetime and size of ephemeral version 1 server key
+#KeyRegenerationInterval 1h
+#ServerKeyBits 768
+
+# Logging
+#obsoletes QuietMode and FascistLogging
+#SyslogFacility AUTH
+SyslogFacility AUTHPRIV
+#LogLevel INFO
+
+# Authentication:
+
+#LoginGraceTime 2m
+#PermitRootLogin yes
+#StrictModes yes
+#MaxAuthTries 6
+
+#RSAAuthentication yes
+#PubkeyAuthentication yes
+#AuthorizedKeysFile .ssh/authorized_keys
+
+# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
+#RhostsRSAAuthentication no
+# similar for protocol version 2
+#HostbasedAuthentication no
+# Change to yes if you don't trust ~/.ssh/known_hosts for
+# RhostsRSAAuthentication and HostbasedAuthentication
+#IgnoreUserKnownHosts no
+# Don't read the user's ~/.rhosts and ~/.shosts files
+#IgnoreRhosts yes
+
+# To disable tunneled clear text passwords, change to no here!
+#PermitEmptyPasswords no
+PasswordAuthentication no
+
+# Change to no to disable s/key passwords
+#ChallengeResponseAuthentication yes
+ChallengeResponseAuthentication no
+
+# Kerberos options
+#KerberosAuthentication no
+#KerberosOrLocalPasswd yes
+#KerberosTicketCleanup yes
+#KerberosGetAFSToken no
+
+# Set this to 'yes' to enable PAM authentication, account processing,
+# and session processing. If this is enabled, PAM authentication will
+# be allowed through the ChallengeResponseAuthentication mechanism.
+# Depending on your PAM configuration, this may bypass the setting of
+# PasswordAuthentication, PermitEmptyPasswords, and
+# "PermitRootLogin without-password". If you just want the PAM account and
+# session checks to run without PAM authentication, then enable this but set
+# ChallengeResponseAuthentication=no
+PAMAuthenticationViaKbdInt no
+
+#AllowTcpForwarding yes
+#GatewayPorts no
+#X11Forwarding no
+X11Forwarding yes
+#X11DisplayOffset 10
+#X11UseLocalhost yes
+#PrintMotd yes
+#PrintLastLog yes
+#TCPKeepAlive yes
+#UseLogin no
+#UsePrivilegeSeparation yes
+#PermitUserEnvironment no
+#Compression yes
+#ClientAliveInterval 0
+#ClientAliveCountMax 3
+#UseDNS yes
+#PidFile /var/run/sshd.pid
+#MaxStartups 10
+#ShowPatchLevel no
+
+# no default banner path
+#Banner /some/path
+
+# override default of no subsystems
+Subsystem sftp /usr/libexec/openssh/sftp-server
--- /dev/null
+# boot cd version 3.x sshd configuration file for debug mode
+
+#Port 22
+Protocol 2
+#ListenAddress 0.0.0.0
+#ListenAddress ::
+
+# HostKey for protocol version 1
+#HostKey /etc/ssh/ssh_host_key
+# HostKeys for protocol version 2
+#HostKey /etc/ssh/ssh_host_rsa_key
+#HostKey /etc/ssh/ssh_host_dsa_key
+
+# Lifetime and size of ephemeral version 1 server key
+#KeyRegenerationInterval 1h
+#ServerKeyBits 768
+
+# Logging
+#obsoletes QuietMode and FascistLogging
+#SyslogFacility AUTH
+SyslogFacility AUTHPRIV
+#LogLevel INFO
+
+# Authentication:
+
+#LoginGraceTime 2m
+#PermitRootLogin yes
+#StrictModes yes
+#MaxAuthTries 6
+
+#RSAAuthentication yes
+#PubkeyAuthentication yes
+#AuthorizedKeysFile .ssh/authorized_keys
+
+# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
+#RhostsRSAAuthentication no
+# similar for protocol version 2
+#HostbasedAuthentication no
+# Change to yes if you don't trust ~/.ssh/known_hosts for
+# RhostsRSAAuthentication and HostbasedAuthentication
+#IgnoreUserKnownHosts no
+# Don't read the user's ~/.rhosts and ~/.shosts files
+#IgnoreRhosts yes
+
+# To disable tunneled clear text passwords, change to no here!
+#PermitEmptyPasswords no
+PasswordAuthentication no
+
+# Change to no to disable s/key passwords
+#ChallengeResponseAuthentication yes
+ChallengeResponseAuthentication no
+
+# Kerberos options
+#KerberosAuthentication no
+#KerberosOrLocalPasswd yes
+#KerberosTicketCleanup yes
+#KerberosGetAFSToken no
+
+# Set this to 'yes' to enable PAM authentication, account processing,
+# and session processing. If this is enabled, PAM authentication will
+# be allowed through the ChallengeResponseAuthentication mechanism.
+# Depending on your PAM configuration, this may bypass the setting of
+# PasswordAuthentication, PermitEmptyPasswords, and
+# "PermitRootLogin without-password". If you just want the PAM account and
+# session checks to run without PAM authentication, then enable this but set
+# ChallengeResponseAuthentication=no
+
+#AllowTcpForwarding yes
+#GatewayPorts no
+#X11Forwarding no
+X11Forwarding yes
+#X11DisplayOffset 10
+#X11UseLocalhost yes
+#PrintMotd yes
+#PrintLastLog yes
+#TCPKeepAlive yes
+#UseLogin no
+#UsePrivilegeSeparation yes
+#PermitUserEnvironment no
+#Compression yes
+#ClientAliveInterval 0
+#ClientAliveCountMax 3
+#UseDNS yes
+#PidFile /var/run/sshd.pid
+#MaxStartups 10
+#ShowPatchLevel no
+
+# no default banner path
+#Banner /some/path
+
+# override default of no subsystems
+Subsystem sftp /usr/libexec/openssh/sftp-server
--- /dev/null
+#!/usr/bin/env python
+
+"""
+The point of this small utility is to take a file in the format
+of /lib/modules/`uname -r`/modules.pcimap and /usr/share/hwdata/pcitable
+and output a condensed, more easily used format for module detection. This is
+done by first getting a list of all the built modules, then loading the
+pci ids for each of those modules from modules.pcimap, then finally merging
+in the contents of pcitable (for built modules only). The result should be
+a file with a pretty comprehensive mapping of pci ids to module names.
+
+The output is used by the PlanetLab boot cd (3.0+) and the pl_hwinit script
+to load all the applicable modules by scanning lspci output.
+
+
+
+Expected format of file modules.dep includes lines of:
+
+/full/module/path/mod.ko: <dependencies>
+
+Expected format of file modules.pcimap includes lines of:
+
+# pci_module vendor device subvendor subdevice class class_mask driver_data
+cciss 0x00000e11 0x0000b060 0x00000e11 0x00004070 0x00000000 0x00000000 0x0
+cciss 0x00000e11 0x0000b178 0x00000e11 0x00004070 0x00000000 0x00000000 0x0
+
+Expected format of file pcitable includes lines of:
+
+# ("%d\t%d\t%s\t"%s"\n", vendid, devid, moduleName, cardDescription)
+# or ("%d\t%d\t%d\t%d\t%s\t"%s"\n", vendid, devid, subvendid, subdevid, moduleNa
+# me, cardDescription)
+0x0e11 0x0508 "tmspci" "Compaq|Netelligent 4/16 Token Ring"
+0x1000 0x0407 0x8086 0x0532 "megaraid" "Storage RAID Controller SRCU42X"
+
+Lines listing a module name of ignore or unknown from pcitable are skipped
+
+
+
+Output format, for each line that matches the above lines:
+cciss 0e11:b060 0e11:b178
+
+"""
+
+import os, sys
+import string
+
+
+
+class merge_hw_tables:
+
+ def merge_files(self, modules_dep_path, modules_pcimap_path, pcitable_path):
+ """
+ merge the three files as described above, and return a dictionary.
+ keys are module names, value is a list of pci ids for that module,
+ in the form "0e11:b178"
+ """
+
+ try:
+ modulesdep_file= file(modules_dep_path,"r")
+ except IOError:
+ sys.stderr.write( "Unable to open modules.dep: %s\n" %
+ modules_dep_path )
+ return
+
+ try:
+ pcimap_file= file(modules_pcimap_path,"r")
+ except IOError:
+ sys.stderr.write( "Unable to open modules.pcimap: %s\n" %
+ modules_pcimap_path )
+ return
+
+ try:
+ pcitable_file= file(pcitable_path,"r")
+ except IOError:
+ sys.stderr.write( "Unable to open pcitable: %s\n" %
+ pcitable_path )
+ return
+
+
+ # associative array to store all matches of module -> ['vendor:device',..]
+ # entries
+ all_modules= {}
+
+
+ # first step, create an associative array of all the built modules
+ for line in modulesdep_file:
+ parts= string.split(line,":")
+ if len(parts) < 2:
+ continue
+
+ full_mod_path= parts[0]
+ parts= string.split(full_mod_path,"/")
+ module_name= parts[len(parts)-1]
+ module_name_len= len(module_name)
+ if module_name[module_name_len-3:] == ".ko":
+ all_modules[module_name[:-3]]= []
+
+
+ # now, parse the pcimap and add devices
+ line_num= 0
+ for line in pcimap_file:
+ line_num= line_num+1
+
+ # skip blank lines, or lines that begin with # (comments)
+ line= string.strip(line)
+ if len(line) == 0:
+ continue
+
+ if line[0] == "#":
+ continue
+
+ line_parts= string.split(line)
+ if line_parts is None or len(line_parts) != 8:
+ sys.stderr.write( "Skipping line %d in pcimap " \
+ "(incorrect format)\n" % line_num )
+ continue
+
+ # first two parts are always vendor / device id
+ module= line_parts[0]
+ vendor_id= line_parts[1]
+ device_id= line_parts[2]
+
+
+ # valid vendor and devices are 10 chars (0xXXXXXXXX) and begin with 0x
+ if len(vendor_id) != 10 or len(device_id) != 10:
+ sys.stderr.write( "Skipping line %d in pcimap " \
+ "(invalid vendor/device id length)\n" %
+ line_num )
+ continue
+
+ if string.lower(vendor_id[:2]) != "0x" \
+ or string.lower(device_id[:2]) != "0x":
+ sys.stderr.write( "Skipping line %d in pcimap " \
+ "(invalid vendor/device id format)\n" % line_num )
+ continue
+
+ # cut down the ids, only need last 4 bytes
+ # start at 6 = (10 total chars - 4 last chars need)
+ vendor_id= string.lower(vendor_id[6:])
+ device_id= string.lower(device_id[6:])
+
+ full_id= "%s:%s" % (vendor_id, device_id)
+
+ if all_modules.has_key(module):
+ if full_id not in all_modules[module]:
+ all_modules[module].append( full_id )
+ else:
+ # normally shouldn't get here, as the list is
+ # prepopulated with all the built modules
+ all_modules[module]= [full_id,]
+
+
+ # parse pcitable, add any more ids for the devices
+ line_num= 0
+ for line in pcitable_file:
+ line_num= line_num+1
+
+ # skip blank lines, or lines that begin with # (comments)
+ line= string.strip(line)
+ if len(line) == 0:
+ continue
+
+ if line[0] == "#":
+ continue
+
+ line_parts= string.split(line)
+ if line_parts is None or len(line_parts) <= 2:
+ sys.stderr.write( "Skipping line %d in pcitable " \
+ "(incorrect format 1)\n" % line_num )
+ continue
+
+ # vendor id is always the first field, device the second. also,
+ # strip off first two chars (the 0x)
+ vendor_id= string.lower(line_parts[0][2:])
+ device_id= string.lower(line_parts[1][2:])
+
+ full_id= "%s:%s" % (vendor_id, device_id)
+
+ # if the first char of the third field is a double
+ # quote, the third field is a module, else if the first
+ # char of the third field is a 0 (zero), the fifth field is
+ # the module name. it would nice if there was any easy way
+ # to split a string on spaces, but recognize quoted strings,
+ # so they wouldn't be split up. that is the reason for this wierd check
+ if line_parts[2][0] == '"':
+ module= line_parts[2]
+ elif line_parts[2][0] == '0':
+ try:
+ module= line_parts[4]
+ except ValueError, e:
+ sys.stderr.write( "Skipping line %d in pcitable " \
+ "(incorrect format 2)\n" % line_num )
+ continue
+ else:
+ sys.stderr.write( "Skipping line %d in pcitable " \
+ "(incorrect format 3)\n" % line_num )
+ continue
+
+ # remove the first and last char of module (quote marks)
+ module= module[1:]
+ module= module[:len(module)-1]
+
+ # now add it if we don't already have this module -> id mapping
+ if all_modules.has_key(module):
+ if full_id not in all_modules[module]:
+ all_modules[module].append( full_id )
+ else:
+ # don't add any modules from pcitable that we don't
+ # already know about
+ pass
+
+ pcitable_file.close()
+ pcimap_file.close()
+ modulesdep_file.close()
+
+ return all_modules
+
+
+
+if __name__ == "__main__":
+ def usage():
+ print( "\nUsage:" )
+ print( "rewrite-pcitable.py <modules.dep> <modules.pcimap> " \
+ "<pcitable> [<output>]" )
+ print( "" )
+
+
+ if len(sys.argv) < 4:
+ usage()
+ sys.exit(1)
+
+
+ if len(sys.argv) > 4:
+ output_file_name= sys.argv[4]
+ try:
+ output_file= file(output_file_name,"w")
+ except IOError:
+ sys.stderr.write( "Unable to open %s for writing.\n" % output_file )
+ sys.exit(1)
+ else:
+ output_file= sys.stdout
+
+
+ all_modules= merge_hw_tables().merge_files( sys.argv[1], sys.argv[2],
+ sys.argv[3] )
+
+ if all_modules is not None:
+ for module in all_modules.keys():
+ devices= all_modules[module]
+ if len(devices) > 0:
+ devices_str= string.join( all_modules[module], " " )
+ output_file.write( "%s %s\n" % (module,devices_str) )
+ else:
+ sys.stderr.write( "Unable to list modules.\n" )
+
+ output_file.close()
--- /dev/null
+"""
+this file contains the ids of messages that we can send the contacts
+at a site, through the BootNotifyOwners call
+"""
+
+MSG_INSTALL_FINISHED= "installfinished"
+MSG_INSUFFICIENT_DISK= "insufficientdisk"
+MSG_INSUFFICIENT_MEMORY= "insufficientmemory"
+MSG_NO_NODE_CONFIG_FILE= "noconfig"
+MSG_AUTH_FAIL= "authfail"
+MSG_NODE_NOT_INSTALLED= "notinstalled"
--- /dev/null
+import os
+
+from Exceptions import *
+import BootAPI
+import StartDebug
+
+
+AUTH_FAILURE_COUNT_FILE= "/tmp/authfailurecount"
+
+
+def Run( vars, log ):
+ """
+ Authenticate this node with PLC. This ensures that the node can operate
+ as normal, and that our management authority has authorized it.
+
+ For this, just call the PLC api function BootCheckAuthentication
+
+ Return 1 if authorized, a BootManagerException if not or the
+ call fails entirely.
+
+ If there are two consecutive authentication failures, put the node
+ into debug mode and exit the bootmanager.
+
+ Expect the following variables from the store:
+ NUM_AUTH_FAILURES_BEFORE_DEBUG How many failures before debug
+ """
+
+ log.write( "\n\nStep: Authenticating node with PLC.\n" )
+
+ # make sure we have the variables we need
+ try:
+ NUM_AUTH_FAILURES_BEFORE_DEBUG= int(vars["NUM_AUTH_FAILURES_BEFORE_DEBUG"])
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+ try:
+ authorized= BootAPI.call_api_function( vars, "BootCheckAuthentication", () )
+ if authorized == 1:
+ log.write( "Authentication successful.\n" )
+
+ try:
+ os.unlink( AUTH_FAILURE_COUNT_FILE )
+ except OSError, e:
+ pass
+
+ return 1
+ except BootManagerException, e:
+ log.write( "Authentication failed: %s.\n" % e )
+
+ # increment auth failure
+ auth_failure_count= 0
+ try:
+ auth_failure_count= int(file(AUTH_FAILURE_COUNT_FILE,"r").read().strip())
+ except IOError:
+ pass
+ except ValueError:
+ pass
+
+ auth_failure_count += 1
+
+ try:
+ fail_file= file(AUTH_FAILURE_COUNT_FILE,"w")
+ fail_file.write( str(auth_failure_count) )
+ fail_file.close()
+ except IOError:
+ pass
+
+ if auth_failure_count >= NUM_AUTH_FAILURES_BEFORE_DEBUG:
+ log.write( "Maximum number of authentication failures reached.\n" )
+ log.write( "Canceling boot process and going into debug mode.\n" )
+
+ StartDebug.Run( vars, log )
+
+ raise BootManagerException, "Unable to authenticate node."
+
+
--- /dev/null
+import string
+
+from Exceptions import *
+import utils
+import compatibility
+from systeminfo import systeminfo
+import BootAPI
+
+
+def Run( vars, log ):
+ """
+ Load the kernel off of a node and boot to it.
+ This step assumes the disks are mounted on SYSIMG_PATH.
+
+ Expect the following variables:
+ BOOT_CD_VERSION A tuple of the current bootcd version
+ SYSIMG_PATH the path where the system image will be mounted
+ (always starts with TEMP_PATH)
+ ROOT_MOUNTED the node root file system is mounted
+
+ Sets the following variables:
+ ROOT_MOUNTED the node root file system is mounted
+ """
+
+ log.write( "\n\nStep: Chain booting node.\n" )
+
+ # make sure we have the variables we need
+ try:
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+ ROOT_MOUNTED= 0
+ if 'ROOT_MOUNTED' in vars.keys():
+ ROOT_MOUNTED= vars['ROOT_MOUNTED']
+
+ if ROOT_MOUNTED == 0:
+ log.write( "Mounting node partitions\n" )
+
+ # old cds need extra utilities to run lvm
+ if BOOT_CD_VERSION[0] == 2:
+ compatibility.setup_lvm_2x_cd( vars, log )
+
+ # simply creating an instance of this class and listing the system
+ # block devices will make them show up so vgscan can find the planetlab
+ # volume group
+ systeminfo().get_block_device_list()
+
+ utils.sysexec( "vgscan", log )
+ utils.sysexec( "vgchange -ay planetlab", log )
+
+ utils.makedirs( SYSIMG_PATH )
+
+ utils.sysexec( "mount /dev/planetlab/root %s" % SYSIMG_PATH, log )
+ utils.sysexec( "mount /dev/planetlab/vservers %s/vservers" %
+ SYSIMG_PATH, log )
+
+ ROOT_MOUNTED= 1
+ vars['ROOT_MOUNTED']= 1
+
+
+ node_update_cmd= "/usr/local/planetlab/bin/NodeUpdate.py start noreboot"
+
+ log.write( "Running node update.\n" )
+ utils.sysexec( "chroot %s %s" % (SYSIMG_PATH,node_update_cmd), log )
+
+ log.write( "Updating ssh public host key with PLC.\n" )
+ ssh_host_key= ""
+ try:
+ ssh_host_key_file= file("%s/etc/ssh/ssh_host_rsa_key.pub"%SYSIMG_PATH,"r")
+ ssh_host_key= ssh_host_key_file.read().strip()
+ ssh_host_key_file.close()
+ ssh_host_key_file= None
+ except IOError, e:
+ pass
+
+ update_vals= {}
+ update_vals['ssh_host_key']= ssh_host_key
+ BootAPI.call_api_function( vars, "BootUpdateNode", (update_vals,) )
+
+
+ log.write( "Copying kernel and initrd for booting.\n" )
+ utils.sysexec( "cp %s/boot/kernel-boot /tmp/kernel" % SYSIMG_PATH, log )
+ utils.sysexec( "cp %s/boot/initrd-boot /tmp/initrd" % SYSIMG_PATH, log )
+
+ log.write( "Unmounting disks.\n" )
+ utils.sysexec_noerr( "chroot %s umount /rcfs" % SYSIMG_PATH, log )
+ utils.sysexec_noerr( "umount -r /dev/planetlab/vservers", log )
+ utils.sysexec_noerr( "umount -r /dev/planetlab/root", log )
+ utils.sysexec_noerr( "vgchange -an", log )
+
+ ROOT_MOUNTED= 0
+ vars['ROOT_MOUNTED']= 0
+
+ if BOOT_CD_VERSION[0] == 2:
+ log.write( "Unloading modules and chaining booting to new kernel.\n" )
+ else:
+ log.write( "Chaining booting to new kernel.\n" )
+
+ # further use of log after Upload will only output to screen
+ log.Upload()
+
+ # on 2.x cds (2.4 kernel) for sure, we need to shutdown everything to
+ # get kexec to work correctly
+
+ utils.sysexec_noerr( "ifconfig eth0 down", log )
+
+ if BOOT_CD_VERSION[0] == 2:
+ utils.sysexec_noerr( "killall dhcpcd", log )
+ elif BOOT_CD_VERSION[0] == 3:
+ utils.sysexec_noerr( "killall dhclient", log )
+
+ utils.sysexec_noerr( "umount -a -r -t ext2,ext3", log )
+ utils.sysexec_noerr( "modprobe -r lvm-mod", log )
+
+ try:
+ modules= file("/tmp/loadedmodules","r")
+
+ for line in modules:
+ module= string.strip(line)
+ if module != "":
+ utils.sysexec_noerr( "modprobe -r %s" % module, log )
+ except IOError:
+ log.write( "Couldn't load /tmp/loadedmodules to unload, continuing.\n" )
+
+ utils.sysexec( "kexec --force --initrd=/tmp/initrd " \
+ "--append=ramdisk_size=8192 /tmp/kernel" )
+
+ return
--- /dev/null
+import string
+
+import InstallPartitionDisks
+from Exceptions import *
+from systeminfo import systeminfo
+import compatibility
+import utils
+
+
+def Run( vars, log ):
+ """
+ Find any new large block devices we can add to the vservers volume group
+
+ Expect the following variables to be set:
+ SYSIMG_PATH the path where the system image will be mounted
+ BOOT_CD_VERSION A tuple of the current bootcd version
+ MINIMUM_DISK_SIZE any disks smaller than this size, in GB, are not used
+
+ Set the following variables upon successfully running:
+ ROOT_MOUNTED the node root file system is mounted
+ """
+
+ log.write( "\n\nStep: Checking for unused disks to add to LVM.\n" )
+
+ # make sure we have the variables we need
+ try:
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ MINIMUM_DISK_SIZE= int(vars["MINIMUM_DISK_SIZE"])
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+ sysinfo= systeminfo()
+
+ all_devices= sysinfo.get_block_device_list()
+
+ # find out if there are unused disks in all_devices that are greater
+ # than old cds need extra utilities to run lvm
+ if BOOT_CD_VERSION[0] == 2:
+ compatibility.setup_lvm_2x_cd( vars, log )
+
+ # will contain the new devices to add to the volume group
+ new_devices= []
+
+ # total amount of new space in gb
+ extended_gb_size= 0
+
+ for device in all_devices.keys():
+
+ (major,minor,blocks,gb_size,readonly)= all_devices[device]
+
+ if device[:14] == "/dev/planetlab":
+ log.write( "Skipping device %s in volume group.\n" % device )
+ continue
+
+ if readonly:
+ log.write( "Skipping read only device %s\n" % device )
+ continue
+
+ if gb_size < MINIMUM_DISK_SIZE:
+ log.write( "Skipping too small device %s (%4.2f)\n" %
+ (device,gb_size) )
+ continue
+
+ log.write( "Checking device %s to see if it is part " \
+ "of the volume group.\n" % device )
+
+ # this is the lvm partition, if it exists on that device
+ lvm_partition= "%s1" % device
+ already_added= utils.sysexec_noerr( "pvdisplay %s | grep -q 'planetlab'" %
+ lvm_partition )
+
+ if already_added:
+ log.write( "It appears %s is part of the volume group, continuing.\n" %
+ device )
+ continue
+
+ # just to be extra paranoid, ignore the device if it already has
+ # an lvm partition on it (new disks won't have this, and that is
+ # what this code is for, so it should be ok).
+ has_lvm= utils.sysexec_noerr( "sfdisk -l %s | grep -q 'Linux LVM'" %
+ device )
+ if has_lvm:
+ log.write( "It appears %s has/had lvm already setup on "\
+ "it, continuing.\n" % device )
+ continue
+
+
+ log.write( "Attempting to add %s to the volume group\n" % device )
+
+ if not InstallPartitionDisks.single_partition_device( device, vars, log ):
+ log.write( "Unable to partition %s, not using it.\n" % device )
+ continue
+
+ log.write( "Successfully initialized %s\n" % device )
+
+ part_path= InstallPartitionDisks.get_partition_path_from_device( device,
+ vars, log )
+ if not InstallPartitionDisks.create_lvm_physical_volume( part_path,
+ vars, log ):
+ log.write( "Unable to create lvm physical volume %s, not using it.\n" %
+ part_path )
+ continue
+
+ log.write( "Adding %s to list of devices to add to " \
+ "planetlab volume group.\n" % device )
+
+ extended_gb_size= extended_gb_size + gb_size
+ new_devices.append( part_path )
+
+
+ if len(new_devices) > 0:
+
+ log.write( "Extending planetlab volume group.\n" )
+
+ log.write( "Unmounting disks.\n" )
+ utils.sysexec_noerr( "chroot %s umount /rcfs" % SYSIMG_PATH, log )
+ utils.sysexec_noerr( "umount /dev/planetlab/vservers", log )
+ utils.sysexec_noerr( "umount /dev/planetlab/root", log )
+ utils.sysexec( "vgchange -an", log )
+
+ vars['ROOT_MOUNTED']= 0
+
+ if not utils.sysexec_noerr( "vgextend planetlab %s" %
+ string.join(new_devices," "), log ):
+ log.write( "Failed to add physical volumes %s to " \
+ "volume group, continuing.\n" % string.join(new_devices," "))
+ return 1
+
+ # now, get the number of unused extents, and extend the vserver
+ # logical volume by that much.
+ remaining_extents= \
+ InstallPartitionDisks.get_remaining_extents_on_vg( vars, log )
+
+ log.write( "Extending vservers logical volume.\n" )
+
+ if not utils.sysexec_noerr("lvextend -l +%s /dev/planetlab/vservers" %
+ remaining_extents, log):
+ log.write( "Failed to extend vservers logical volume, continuing\n" )
+ return 1
+
+ log.write( "making the ext3 filesystem match new logical volume size.\n" )
+ if not utils.sysexec_noerr("resize2fs /dev/planetlab/vservers",log):
+ log.write( "Failed to make ext3 file system match, continuing\n" )
+ return 1
+
+ log.write( "Succesfully extended vservers partition by %4.2f GB\n" %
+ extended_gb_size )
+ else:
+ log.write( "No new disk devices to add to volume group.\n" )
+
+ return 1
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import os
+import popen2
+import string
+
+from systeminfo import systeminfo
+from Exceptions import *
+import utils
+import notify_messages
+import BootAPI
+
+
+def Run( vars, log ):
+ """
+ Make sure the hardware we are running on is sufficient for
+ the PlanetLab OS to be installed on. In the process, identify
+ the list of block devices that may be used for a node installation,
+ and identify the cdrom device that we booted off of.
+
+ Return 1 if requiremenst met, 0 if requirements not met. Raise
+ BootManagerException if any problems occur that prevent the requirements
+ from being checked.
+
+ Expect the following variables from the store:
+
+ MINIMUM_MEMORY minimum amount of memory in kb required
+ for install
+ NODE_ID the node_id from the database for this node
+ MINIMUM_DISK_SIZE any disks smaller than this size, in GB, are not used
+ TOTAL_MINIMUM_DISK_SIZE total disk size in GB, if all usable disks
+ meet this number, there isn't enough disk space for
+ this node to be usable after install
+ SKIP_HARDWARE_REQUIREMENT_CHECK
+ If set, don't check if minimum requirements are met
+ BOOT_CD_VERSION A tuple of the current bootcd version
+ Sets the following variables:
+ INSTALL_BLOCK_DEVICES list of block devices to install onto
+ """
+
+ log.write( "\n\nStep: Checking if hardware requirements met.\n" )
+
+ try:
+ MINIMUM_MEMORY= int(vars["MINIMUM_MEMORY"])
+ if MINIMUM_MEMORY == "":
+ raise ValueError, "MINIMUM_MEMORY"
+
+ NODE_ID= vars["NODE_ID"]
+ if NODE_ID == "":
+ raise ValueError("NODE_ID")
+
+ MINIMUM_DISK_SIZE= int(vars["MINIMUM_DISK_SIZE"])
+
+ TOTAL_MINIMUM_DISK_SIZE= \
+ int(vars["TOTAL_MINIMUM_DISK_SIZE"])
+
+ SKIP_HARDWARE_REQUIREMENT_CHECK= \
+ int(vars["SKIP_HARDWARE_REQUIREMENT_CHECK"])
+
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ except KeyError, var:
+ raise BootManagerException, \
+ "Missing variable in install store: %s" % var
+ except ValueError, var:
+ raise BootManagerException, \
+ "Variable in install store blank, shouldn't be: %s" % var
+
+ sysinfo= systeminfo()
+
+ # lets see if we have enough memory to run
+ log.write( "Checking for available memory.\n" )
+
+ total_mem= sysinfo.get_total_phsyical_mem()
+ if total_mem is None:
+ raise BootManagerException, "Unable to read total physical memory"
+
+ if total_mem < MINIMUM_MEMORY:
+ if not SKIP_HARDWARE_REQUIREMENT_CHECK:
+ log.write( "Insufficient memory to run node: %s kb\n" % total_mem )
+ log.write( "Required memory: %s kb\n" % MINIMUM_MEMORY )
+
+ include_pis= 0
+ include_techs= 1
+ include_support= 0
+
+ sent= 0
+ try:
+ sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
+ (notify_messages.MSG_INSUFFICIENT_MEMORY,
+ include_pis,
+ include_techs,
+ include_support) )
+ except BootManagerException, e:
+ log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
+
+ if sent == 0:
+ log.write( "Unable to notify site contacts of problem.\n" )
+ else:
+ log.write( "Notified contacts of problem.\n" )
+
+ return 0
+ else:
+ log.write( "Memory requirements not met, but running anyway: %s kb\n"
+ % total_mem )
+ else:
+ log.write( "Looks like we have enough memory: %s kb\n" % total_mem )
+
+
+
+ # get a list of block devices to attempt to install on
+ # (may include cdrom devices)
+ install_devices= sysinfo.get_block_device_list()
+
+ # save the list of block devices in the log
+ log.write( "Detected block devices:\n" )
+ log.write( repr(install_devices) + "\n" )
+
+ if not install_devices or len(install_devices) == 0:
+ log.write( "No block devices detected.\n" )
+
+ include_pis= 0
+ include_techs= 1
+ include_support= 0
+
+ sent= 0
+ try:
+ sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
+ (notify_messages.MSG_INSUFFICIENT_DISK,
+ include_pis,
+ include_techs,
+ include_support) )
+ except BootManagerException, e:
+ log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
+
+ if sent == 0:
+ log.write( "Unable to notify site contacts of problem.\n" )
+
+ return 0
+
+ # now, lets remove any block devices we know won't work (readonly,cdroms),
+ # or could be other writable removable disks (usb keychains, zip disks, etc)
+ # i'm not aware of anything that helps with the latter test, so,
+ # what we'll probably do is simply not use any block device below
+ # some size threshold (set in installstore)
+
+ # also, keep track of the total size for all devices that appear usable
+ total_size= 0
+
+ for device in install_devices.keys():
+
+ (major,minor,blocks,gb_size,readonly)= install_devices[device]
+
+ # if the device string starts with
+ # planetlab, ignore it (could be old lvm setup)
+ if device[:14] == "/dev/planetlab":
+ del install_devices[device]
+ continue
+
+ if gb_size < MINIMUM_DISK_SIZE:
+ log.write( "Device is too small to use: %s \n(appears" \
+ " to be %4.2f GB)\n" % (device,gb_size) )
+ try:
+ del install_devices[device]
+ except KeyError, e:
+ pass
+ continue
+
+ if readonly:
+ log.write( "Device is readonly, not using: %s\n" % device )
+ try:
+ del install_devices[device]
+ except KeyError, e:
+ pass
+ continue
+
+ # add this sector count to the total count of usable
+ # sectors we've found.
+ total_size= total_size + gb_size
+
+
+ if len(install_devices) == 0:
+ log.write( "No suitable block devices found for install.\n" )
+
+ include_pis= 0
+ include_techs= 1
+ include_support= 0
+
+ sent= 0
+ try:
+ sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
+ (notify_messages.MSG_INSUFFICIENT_DISK,
+ include_pis,
+ include_techs,
+ include_support) )
+ except BootManagerException, e:
+ log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
+
+ if sent == 0:
+ log.write( "Unable to notify site contacts of problem.\n" )
+
+ return 0
+
+
+ # show the devices we found that are usable
+ log.write( "Usable block devices:\n" )
+ log.write( repr(install_devices.keys()) + "\n" )
+
+ # save the list of devices for the following steps
+ vars["INSTALL_BLOCK_DEVICES"]= install_devices.keys()
+
+
+ # ensure the total disk size is large enough. if
+ # not, we need to email the tech contacts the problem, and
+ # put the node into debug mode.
+ if total_size < TOTAL_MINIMUM_DISK_SIZE:
+ if not SKIP_HARDWARE_REQUIREMENT_CHECK:
+ log.write( "The total usable disk size of all disks is " \
+ "insufficient to be usable as a PlanetLab node.\n" )
+ include_pis= 0
+ include_techs= 1
+ include_support= 0
+
+ sent= 0
+ try:
+ sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
+ (notify_messages.MSG_INSUFFICIENT_DISK,
+ include_pis,
+ include_techs,
+ include_support) )
+ except BootManagerException, e:
+ log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
+
+ if sent == 0:
+ log.write( "Unable to notify site contacts of problem.\n" )
+
+ return 0
+
+ else:
+ log.write( "The total usable disk size of all disks is " \
+ "insufficient, but running anyway.\n" )
+
+ log.write( "Total size for all usable block devices: %4.2f GB\n" % total_size )
+
+ # turn off UDMA for all block devices on 2.x cds (2.4 kernel)
+ if BOOT_CD_VERSION[0] == 2:
+ for device in install_devices:
+ log.write( "Disabling UDMA on %s\n" % device )
+ utils.sysexec_noerr( "/sbin/hdparm -d0 %s" % device, log )
+
+ return 1
--- /dev/null
+from Exceptions import *
+
+welcome_message= \
+"""
+********************************************************************************
+* *
+* Welcome to PlanetLab *
+* ~~~~~~~~~~~~~~~~~~~~ *
+* *
+* The PlanetLab boot CD allows you to automatically install this machine as a *
+* node within the PlanetLab overlay network. *
+* *
+* PlanetLab is a global overlay network for developing and accessing new *
+* network services. Our goal is to grow to 1000 geographically distributed *
+* nodes, connected by a diverse collection of links. Toward this end, we are *
+* putting PlanetLab nodes into edge sites, co-location and routing centers, *
+* and homes (i.e., at the end of DSL lines and cable modems). PlanetLab is *
+* designed to support both short-term experiments and long-running services. *
+* Currently running services include network weather maps, network-embedded *
+* storage, peer-to-peer networks, and content distribution networks. *
+* *
+* Information on joining PlanetLab available at planet-lab.org/consortium/ *
+* *
+********************************************************************************
+
+WARNING : Installing PlanetLab will remove any existing operating system and
+ data from this computer.
+"""
+
+
+def Run( vars, log ):
+ """
+ Ask the user if we really want to wipe this machine.
+
+ Return 1 if the user accept, 0 if the user denied, and
+ a BootManagerException if anything unexpected occurred.
+ """
+
+ log.write( "\n\nStep: Confirming install with user.\n" )
+
+ try:
+ confirmation= ""
+ install= 0
+ print welcome_message
+
+ while confirmation not in ("yes","no"):
+ confirmation= \
+ raw_input("Are you sure you wish to continue (yes/no):")
+ install= confirmation=="yes"
+ except EOFError, e:
+ pass
+ except KeyboardInterrupt, e:
+ pass
+
+ if install:
+ log.write( "\nUser accepted install.\n" )
+ else:
+ log.write( "\nUser canceled install.\n" )
+
+ return install
--- /dev/null
+import string
+
+from Exceptions import *
+import BootAPI
+
+
+SKIP_MODEL_STRING= "/minhw"
+
+
+def Run( vars, log ):
+ """
+ Contact PLC and get the attributes for this node. Also, if the node model
+ string ends in SKIP_MODEL_STRING, override the hardware requirements
+ configuration value, and skip the checks.
+
+ Also, update any node network settings at PLC, minus the ip address,
+ so, upload the mac (if node_id was in conf file), gateway, network,
+ broadcast, netmask, dns1/2, and the hostname/domainname.
+
+ Expect the following keys to be set:
+ BOOT_CD_VERSION A tuple of the current bootcd version
+ SKIP_HARDWARE_REQUIREMENT_CHECK Whether or not we should skip hardware
+ requirement checks
+
+ The following keys are set/updated:
+ WAS_NODE_ID_IN_CONF Set to 1 if the node id was in the conf file
+ WAS_NODE_KEY_IN_CONF Set to 1 if the node key was in the conf file
+ BOOT_STATE The current node boot state
+ NODE_MODEL The user specified model of this node
+ NETWORK_SETTINGS A dictionary of the values of the network settings
+ SKIP_HARDWARE_REQUIREMENT_CHECK Whether or not we should skip hardware
+ requirement checks
+
+ Return 1 if able to contact PLC and get node info.
+ Raise a BootManagerException if anything fails.
+ """
+
+ log.write( "\n\nStep: Retrieving details of node from PLC.\n" )
+
+ # make sure we have the variables we need
+ try:
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ SKIP_HARDWARE_REQUIREMENT_CHECK= vars["SKIP_HARDWARE_REQUIREMENT_CHECK"]
+ if SKIP_HARDWARE_REQUIREMENT_CHECK == "":
+ raise ValueError, "SKIP_HARDWARE_REQUIREMENT_CHECK"
+
+ NETWORK_SETTINGS= vars["NETWORK_SETTINGS"]
+ if NETWORK_SETTINGS == "":
+ raise ValueError, "NETWORK_SETTINGS"
+
+ WAS_NODE_ID_IN_CONF= vars["WAS_NODE_ID_IN_CONF"]
+ if WAS_NODE_ID_IN_CONF == "":
+ raise ValueError, "WAS_NODE_ID_IN_CONF"
+
+ WAS_NODE_KEY_IN_CONF= vars["WAS_NODE_KEY_IN_CONF"]
+ if WAS_NODE_KEY_IN_CONF == "":
+ raise ValueError, "WAS_NODE_KEY_IN_CONF"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ details= BootAPI.call_api_function( vars, "BootGetNodeDetails", () )
+
+ vars['BOOT_STATE']= details['boot_state']
+ vars['NODE_MODEL']= string.strip(details['model'])
+
+ log.write( "Successfully retrieved node record.\n" )
+ log.write( "Current boot state: %s\n" % vars['BOOT_STATE'] )
+ log.write( "Node make/model: %s\n" % vars['NODE_MODEL'] )
+
+ # if the end of NODE_MODEL string ends in SKIP_MODEL_STRING, skip hardware
+ # requirement checks (overrides configuration)
+ model= vars['NODE_MODEL']
+ len_skip_str= len(SKIP_MODEL_STRING)
+ if model[-len_skip_str:] == SKIP_MODEL_STRING:
+ vars['SKIP_HARDWARE_REQUIREMENT_CHECK']= 1
+ log.write( "node model indicates override to hardware requirements.\n" )
+
+
+ # this contains all the node networks, for now, we are only concerned
+ # in the primary network
+ node_networks= details['networks']
+ got_primary= 0
+ for network in node_networks:
+ if network['is_primary'] == 1:
+ got_primary= 1
+ break
+
+ if not got_primary:
+ raise BootManagerException, "Node did not have a primary network."
+
+ log.write( "Primary network as returned from PLC: %s\n" % str(network) )
+
+ # if we got this far, the ip on the floppy and the ip in plc match,
+ # make the rest of the PLC information match whats on the floppy
+ network['method']= NETWORK_SETTINGS['method']
+
+ # only nodes that have the node_id specified directly in the configuration
+ # file can change their mac address
+ if BOOT_CD_VERSION[0] == 3 and WAS_NODE_ID_IN_CONF == 1:
+ network['mac']= NETWORK_SETTINGS['mac']
+
+ network['gateway']= NETWORK_SETTINGS['gateway']
+ network['network']= NETWORK_SETTINGS['network']
+ network['broadcast']= NETWORK_SETTINGS['broadcast']
+ network['netmask']= NETWORK_SETTINGS['netmask']
+ network['dns1']= NETWORK_SETTINGS['dns1']
+ network['dns2']= NETWORK_SETTINGS['dns2']
+
+ log.write( "Updating network settings at PLC to match floppy " \
+ "(except for node ip).\n" )
+ update_vals= {}
+ update_vals['primary_network']= network
+ BootAPI.call_api_function( vars, "BootUpdateNode", (update_vals,) )
+
+ return 1
--- /dev/null
+import os
+import xmlrpclib
+import socket
+import string
+
+from Exceptions import *
+import utils
+
+
+# locations of boot os version files
+BOOT_VERSION_2X_FILE='/usr/bootme/ID'
+BOOT_VERSION_3X_FILE='/pl_version'
+
+# minimium version of the boot os we need to run, as a (major,minor) tuple
+MINIMUM_BOOT_VERSION= (2,0)
+
+# minimum version of python required to run the boot manager
+MINIMUM_PYTHON_VERSION= (2,2,0)
+
+
+def Run( vars, log ):
+ """
+ Setup the boot manager so it can run, do any extra necessary
+ hardware setup (to fix old cd problems)
+
+ Sets the following variables:
+ BOOT_CD_VERSION A two number tuple of the boot cd version
+ """
+
+ log.write( "\n\nStep: Initializing the BootManager.\n" )
+
+
+ log.write( "Opening connection to API server\n" )
+ try:
+ api_inst= xmlrpclib.Server( vars['BOOT_API_SERVER'], verbose=0 )
+ except KeyError, e:
+ raise BootManagerException, \
+ "configuration file does not specify API server URL"
+
+ vars['API_SERVER_INST']= api_inst
+
+ if not __check_boot_version( vars, log ):
+ raise BootManagerException, \
+ "Boot CD version insufficient to run the Boot Manager"
+ else:
+ log.write( "Running on boot cd version: %s\n" %
+ str(vars['BOOT_CD_VERSION']) )
+
+ BOOT_CD_VERSION= vars['BOOT_CD_VERSION']
+
+ # old cds need extra modules loaded for compaq smart array
+ if BOOT_CD_VERSION[0] == 2:
+
+ has_smartarray= utils.sysexec_noerr(
+ 'lspci | egrep "0e11:b178|0e11:4070|0e11:4080|0e11:4082|0e11:4083"')
+
+ if has_smartarray:
+ log.write( "Loading support for Compaq smart array\n" )
+ utils.sysexec_noerr( "modprobe cciss", log )
+ _create_cciss_dev_entries()
+
+
+ has_fusion= utils.sysexec_noerr('lspci | egrep "1000:0030"')
+
+ if has_fusion:
+ log.write( "Loading support for Fusion MPT SCSI controllers\n" )
+ utils.sysexec_noerr( "modprobe mptscsih", log )
+
+ # for anything that needs to know we are running under the boot cd and
+ # not the runtime os
+ os.environ['PL_BOOTCD']= "1"
+
+ return 1
+
+
+
+def __check_boot_version( vars, log ):
+ """
+ identify which version of the boot os we are running on, and whether
+ or not we can run at all on the given version. later, this will be
+ used to identify extra packages to download to enable the boot manager
+ to run on any supported version.
+
+ 2.x cds have the version file in /usr/bootme/ID, which looked like:
+ 'PlanetLab BootCD v2.0.3'
+
+ 3.x cds have the version file in /pl_version, which lookes like:
+ 'PlanetLab BootCD 3.0-beta0.3'
+
+ All current known version strings that we support:
+ PlanetLab BootCD 3.0
+ PlanetLab BootCD 3.0-beta0.1
+ PlanetLab BootCD 3.0-beta0.3
+ PlanetLab BootCD v2.0
+ PlanetLab BootCD v2.0.1
+ PlanetLab BootCD v2.0.2
+ PlanetLab BootCD v2.0.3
+
+ Returns 1 if the boot os version is identified and will work
+ to run the boot manager. Two class variables are set:
+ BOOT_OS_MAJOR_VERSION
+ BOOT_OS_MINOR_VERSION
+ version strings with three parts parts to the version ignore the
+ middle number (so 2.0.3 is major 2, minor 3)
+
+ Returns 0 if the boot os is insufficient to run the boot manager
+ """
+
+ try:
+ # check for a 3.x version first
+ version_file= file(BOOT_VERSION_3X_FILE,'r')
+ full_version= string.strip(version_file.read())
+ version_file.close()
+
+ version_parts= string.split(full_version)
+ version= version_parts[-1]
+
+ version_numbers= string.split(version,".")
+ if len(version_numbers) == 2:
+ BOOT_OS_MAJOR_VERSION= int(version_numbers[0])
+ BOOT_OS_MINOR_VERSION= int(version_numbers[1])
+ else:
+ # for 3.x cds, if there are more than two parts
+ # separated by a ., its one of the beta cds.
+ # hardcode as a 3.0 cd
+ BOOT_OS_MAJOR_VERSION= 3
+ BOOT_OS_MINOR_VERSION= 0
+
+ vars['BOOT_CD_VERSION']= (BOOT_OS_MAJOR_VERSION,BOOT_OS_MINOR_VERSION)
+
+ if (BOOT_OS_MAJOR_VERSION,BOOT_OS_MINOR_VERSION) >= \
+ MINIMUM_BOOT_VERSION:
+ return 1
+
+ except IOError, e:
+ pass
+ except IndexError, e:
+ pass
+ except TypeError, e:
+ pass
+
+
+ try:
+ # check for a 2.x version first
+ version_file= file(BOOT_VERSION_2X_FILE,'r')
+ full_version= string.strip(version_file.read())
+ version_file.close()
+
+ version_parts= string.split(full_version)
+ version= version_parts[-1]
+ if version[0] == 'v':
+ version= version[1:]
+
+ version_numbers= string.split(version,".")
+ if len(version_numbers) == 2:
+ BOOT_OS_MAJOR_VERSION= int(version_numbers[0])
+ BOOT_OS_MINOR_VERSION= int(version_numbers[1])
+ else:
+ BOOT_OS_MAJOR_VERSION= int(version_numbers[0])
+ BOOT_OS_MINOR_VERSION= int(version_numbers[2])
+
+ vars['BOOT_CD_VERSION']= (BOOT_OS_MAJOR_VERSION,BOOT_OS_MINOR_VERSION)
+
+ if (BOOT_OS_MAJOR_VERSION,BOOT_OS_MINOR_VERSION) >= \
+ MINIMUM_BOOT_VERSION:
+ return 1
+
+ except IOError, e:
+ pass
+ except IndexError, e:
+ pass
+ except TypeError, e:
+ pass
+
+
+ return 0
+
+
+
+def _create_cciss_dev_entries():
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0 b 104 0" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p1 b 104 1" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p2 b 104 2" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p3 b 104 3" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p4 b 104 4" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p5 b 104 5" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p6 b 104 6" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p7 b 104 7" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p8 b 104 8" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p9 b 104 9" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p10 b 104 10" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p11 b 104 11" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p12 b 104 12" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p13 b 104 13" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p14 b 104 14" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d0p15 b 104 15" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1 b 104 16" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p1 b 104 17" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p2 b 104 18" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p3 b 104 19" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p4 b 104 20" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p5 b 104 21" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p6 b 104 22" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p7 b 104 23" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p8 b 104 24" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p9 b 104 25" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p10 b 104 26" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p11 b 104 27" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p12 b 104 28" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p13 b 104 29" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p14 b 104 30" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d1p15 b 104 31" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2 b 104 32" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p1 b 104 33" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p2 b 104 34" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p3 b 104 35" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p4 b 104 36" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p5 b 104 37" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p6 b 104 38" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p7 b 104 39" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p8 b 104 40" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p9 b 104 41" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p10 b 104 42" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p11 b 104 43" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p12 b 104 44" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p13 b 104 45" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p14 b 104 46" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d2p15 b 104 47" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3 b 104 48" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p1 b 104 49" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p2 b 104 50" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p3 b 104 51" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p4 b 104 52" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p5 b 104 53" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p6 b 104 54" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p7 b 104 55" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p8 b 104 56" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p9 b 104 57" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p10 b 104 58" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p11 b 104 59" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p12 b 104 60" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p13 b 104 61" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p14 b 104 62" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d3p15 b 104 63" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4 b 104 64" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p1 b 104 65" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p2 b 104 66" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p3 b 104 67" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p4 b 104 68" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p5 b 104 69" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p6 b 104 70" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p7 b 104 71" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p8 b 104 72" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p9 b 104 73" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p10 b 104 74" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p11 b 104 75" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p12 b 104 76" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p13 b 104 77" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p14 b 104 78" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d4p15 b 104 79" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5 b 104 80" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p1 b 104 81" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p2 b 104 82" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p3 b 104 83" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p4 b 104 84" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p5 b 104 85" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p6 b 104 86" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p7 b 104 87" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p8 b 104 88" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p9 b 104 89" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p10 b 104 90" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p11 b 104 91" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p12 b 104 92" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p13 b 104 93" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p14 b 104 94" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d5p15 b 104 95" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6 b 104 96" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p1 b 104 97" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p2 b 104 98" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p3 b 104 99" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p4 b 104 100" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p5 b 104 101" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p6 b 104 102" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p7 b 104 103" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p8 b 104 104" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p9 b 104 105" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p10 b 104 106" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p11 b 104 107" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p12 b 104 108" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p13 b 104 109" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p14 b 104 110" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d6p15 b 104 111" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7 b 104 112" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p1 b 104 113" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p2 b 104 114" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p3 b 104 115" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p4 b 104 116" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p5 b 104 117" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p6 b 104 118" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p7 b 104 119" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p8 b 104 120" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p9 b 104 121" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p10 b 104 122" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p11 b 104 123" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p12 b 104 124" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p13 b 104 125" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p14 b 104 126" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d7p15 b 104 127" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8 b 104 128" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p1 b 104 129" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p2 b 104 130" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p3 b 104 131" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p4 b 104 132" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p5 b 104 133" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p6 b 104 134" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p7 b 104 135" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p8 b 104 136" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p9 b 104 137" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p10 b 104 138" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p11 b 104 139" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p12 b 104 140" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p13 b 104 141" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p14 b 104 142" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d8p15 b 104 143" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9 b 104 144" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p1 b 104 145" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p2 b 104 146" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p3 b 104 147" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p4 b 104 148" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p5 b 104 149" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p6 b 104 150" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p7 b 104 151" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p8 b 104 152" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p9 b 104 153" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p10 b 104 154" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p11 b 104 155" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p12 b 104 156" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p13 b 104 157" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p14 b 104 158" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d9p15 b 104 159" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10 b 104 160" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p1 b 104 161" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p2 b 104 162" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p3 b 104 163" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p4 b 104 164" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p5 b 104 165" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p6 b 104 166" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p7 b 104 167" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p8 b 104 168" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p9 b 104 169" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p10 b 104 170" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p11 b 104 171" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p12 b 104 172" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p13 b 104 173" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p14 b 104 174" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d10p15 b 104 175" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11 b 104 176" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p1 b 104 177" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p2 b 104 178" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p3 b 104 179" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p4 b 104 180" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p5 b 104 181" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p6 b 104 182" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p7 b 104 183" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p8 b 104 184" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p9 b 104 185" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p10 b 104 186" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p11 b 104 187" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p12 b 104 188" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p13 b 104 189" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p14 b 104 190" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d11p15 b 104 191" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12 b 104 192" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p1 b 104 193" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p2 b 104 194" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p3 b 104 195" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p4 b 104 196" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p5 b 104 197" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p6 b 104 198" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p7 b 104 199" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p8 b 104 200" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p9 b 104 201" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p10 b 104 202" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p11 b 104 203" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p12 b 104 204" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p13 b 104 205" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p14 b 104 206" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d12p15 b 104 207" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13 b 104 208" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p1 b 104 209" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p2 b 104 210" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p3 b 104 211" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p4 b 104 212" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p5 b 104 213" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p6 b 104 214" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p7 b 104 215" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p8 b 104 216" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p9 b 104 217" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p10 b 104 218" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p11 b 104 219" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p12 b 104 220" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p13 b 104 221" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p14 b 104 222" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d13p15 b 104 223" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14 b 104 224" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p1 b 104 225" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p2 b 104 226" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p3 b 104 227" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p4 b 104 228" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p5 b 104 229" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p6 b 104 230" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p7 b 104 231" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p8 b 104 232" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p9 b 104 233" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p10 b 104 234" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p11 b 104 235" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p12 b 104 236" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p13 b 104 237" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p14 b 104 238" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d14p15 b 104 239" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15 b 104 240" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p1 b 104 241" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p2 b 104 242" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p3 b 104 243" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p4 b 104 244" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p5 b 104 245" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p6 b 104 246" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p7 b 104 247" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p8 b 104 248" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p9 b 104 249" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p10 b 104 250" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p11 b 104 251" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p12 b 104 252" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p13 b 104 253" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p14 b 104 254" )
+ utils.sysexec_noerr( "mknod /dev/cciss/c0d15p15 b 104 255" )
+
+
+
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import os
+
+from Exceptions import *
+import utils
+
+
+def Run( vars, log ):
+ """
+ Install the base system group of RPMs
+
+ Except the following variables from the store:
+ TEMP_PATH the path to download and store temp files to
+ CACERT_PATH path where the cacerts on the bootcd live
+ SYSIMG_PATH the path where the system image will be mounted
+ (always starts with TEMP_PATH)
+ INSTALL_LANGS languages for install (used by rpm)
+
+ Sets the following variables:
+ None
+
+ """
+
+ log.write( "\n\nStep: Install: Installing base OS.\n" )
+
+ # make sure we have the variables we need
+ try:
+ TEMP_PATH= vars["TEMP_PATH"]
+ if TEMP_PATH == "":
+ raise ValueError, "TEMP_PATH"
+
+ CACERT_PATH= vars["CACERT_PATH"]
+ if CACERT_PATH == "":
+ raise ValueError, "CACERT_PATH"
+
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ INSTALL_LANGS= vars["INSTALL_LANGS"]
+ if INSTALL_LANGS == "":
+ raise ValueError, "INSTALL_LANGS"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ # this will prevent all the locales from being installed
+ log.write( "Setting up RPM configuration in sysimg\n" )
+ utils.makedirs( "%s/etc/rpm" % SYSIMG_PATH )
+ rpm_macros= file( "%s/etc/rpm/macros" % SYSIMG_PATH, "w" )
+ rpm_macros.write( "%%_install_langs %s\n" % INSTALL_LANGS )
+ rpm_macros.write( "%_excludedocs 1\n" )
+ rpm_macros.write( "%__file_context_path /dev/null\n" )
+ rpm_macros.close()
+ rpm_macros= None
+
+ log.write( "Running base group install using yum\n" )
+
+ # groupupdate instead of groupinstall since BootstrapRPM
+ # already installed a pre-configured RPM
+ # database. 'PlanetLab' is now a subset of Fedora Core 2
+ # Core/Base plus PlanetLab specific RPMs, so that we don't
+ # have to run yum multiple times. The group is called
+ # 'PlanetLab' for backward compatibility with NodeUpdate,
+ # which is hard-coded to update the 'PlanetLab' group.
+ yum_cmd= "chroot %s yum --sslcertdir %s -y groupupdate 'PlanetLab'" % \
+ (SYSIMG_PATH, CACERT_PATH)
+
+ utils.sysexec( yum_cmd, log );
+
+ return 1
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+
+import os, sys, string
+import popen2
+
+from Exceptions import *
+import utils
+import BootServerRequest
+
+
+def Run( vars, log ):
+ """
+ Download enough files to run rpm and yum from a chroot in
+ the system image directory
+
+ Expect the following variables from the store:
+ SYSIMG_PATH the path where the system image will be mounted
+ PARTITIONS dictionary of generic part. types (root/swap)
+ and their associated devices.
+ ALPINA_SERVER_DIR directory on the boot servers containing alpina
+ scripts and support files
+ INSTALL_LANGS languages for install (used by rpm)
+ NODE_ID the id of this machine
+
+ Sets the following variables:
+ TEMP_BOOTCD_PATH where the boot cd is remounted in the temp
+ path
+ """
+
+ log.write( "\n\nStep: Install: Bootstrapping RPM.\n" )
+
+ # make sure we have the variables we need
+ try:
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ PARTITIONS= vars["PARTITIONS"]
+ if PARTITIONS == None:
+ raise ValueError, "PARTITIONS"
+
+ ALPINA_SERVER_DIR= vars["ALPINA_SERVER_DIR"]
+ if ALPINA_SERVER_DIR == None:
+ raise ValueError, "ALPINA_SERVER_DIR"
+
+ INSTALL_LANGS= vars["INSTALL_LANGS"]
+ if INSTALL_LANGS == "":
+ raise ValueError, "INSTALL_LANGS"
+
+ NODE_ID= vars["NODE_ID"]
+ if NODE_ID == "":
+ raise ValueError, "NODE_ID"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ try:
+ # make sure the required partitions exist
+ val= PARTITIONS["root"]
+ val= PARTITIONS["swap"]
+ val= PARTITIONS["vservers"]
+ except KeyError, part:
+ log.write( "Missing partition in PARTITIONS: %s\n" % part )
+ return 0
+
+ bs_request= BootServerRequest.BootServerRequest()
+
+ log.write( "turning on swap space\n" )
+ utils.sysexec( "swapon %s" % PARTITIONS["swap"], log )
+
+ # make sure the sysimg dir is present
+ utils.makedirs( SYSIMG_PATH )
+
+ log.write( "mounting root file system\n" )
+ utils.sysexec( "mount -t ext3 %s %s" % (PARTITIONS["root"],SYSIMG_PATH), log )
+
+ log.write( "mounting vserver partition in root file system\n" )
+ utils.makedirs( SYSIMG_PATH + "/vservers" )
+ utils.sysexec( "mount -t ext3 %s %s/vservers" % (PARTITIONS["vservers"],
+ SYSIMG_PATH), log )
+
+ # download and extract support tarball for
+ # this step, which has everything
+ # we need to successfully run
+ step_support_file= "alpina-BootstrapRPM.tar.bz2"
+ source_file= "%s/%s" % (ALPINA_SERVER_DIR,step_support_file)
+ dest_file= "%s/%s" % (SYSIMG_PATH, step_support_file)
+
+ # 30 is the connect timeout, 7200 is the max transfer time
+ # in seconds (2 hours)
+ log.write( "downloading %s\n" % step_support_file )
+ result= bs_request.DownloadFile( source_file, None, None,
+ 1, 1, dest_file,
+ 30, 7200)
+ if not result:
+ raise BootManagerException, "Unable to download %s from server." % \
+ source_file
+
+ log.write( "extracting %s in %s\n" % (dest_file,SYSIMG_PATH) )
+ result= utils.sysexec( "tar -C %s -xpjf %s" % (SYSIMG_PATH,dest_file), log )
+ utils.removefile( dest_file )
+
+ # get the yum configuration file for this node (yum.conf).
+ # this needs to come from the configuration file service,
+ # so, if its a beta node, it'll install the beta rpms from
+ # the beginning. The configuration file service will return
+ # the url for the file we need to request to get the actual
+ # conf file, so two requests need to be made.
+
+ # the only changes we will need to make to it are to change
+ # the cache and log directories, so when we run yum from
+ # the chrooted tempfs mount, it'll cache the rpms on the
+ # sysimg partition
+
+ log.write( "Fetching URL for yum.conf from configuration file service\n" )
+
+ postVars= {"node_id" : NODE_ID,
+ "file" : "/etc/yum.conf"}
+
+ yum_conf_url_file= "/tmp/yumconf.url"
+
+ result= bs_request.DownloadFile(
+ "/db/plnodeconf/getsinglefile.php",
+ None, postVars, 1, 1, yum_conf_url_file)
+
+ if result == 0:
+ log.write( "Unable to make request to get url for yum.conf\n" )
+ return 0
+
+ try:
+ yum_conf_url= file(yum_conf_url_file,"r").read()
+ yum_conf_url= string.strip(yum_conf_url)
+ if yum_conf_url == "":
+ raise BootManagerException, \
+ "Downloaded yum configuration file URL is empty."
+ except IOError:
+ raise BootManagerException, \
+ "Unable to open downloaded yum configuration file URL."
+
+ # now, get the actual contents of yum.conf for this node
+ log.write( "Fetching yum.conf contents from configuration file service\n" )
+
+ postVars= {}
+ download_file_loc= "%s/etc/yum.conf" % SYSIMG_PATH
+
+ result= bs_request.DownloadFile( yum_conf_url,
+ None, postVars, 1, 1,
+ download_file_loc)
+
+ if result == 0:
+ log.write( "Unable to make request to get yum.conf\n" )
+ return 0
+
+ # copy resolv.conf from the base system into our temp dir
+ # so DNS lookups work correctly while we are chrooted
+ log.write( "Copying resolv.conf to temp dir\n" )
+ utils.sysexec( "cp /etc/resolv.conf %s/etc/" % SYSIMG_PATH, log )
+
+ # mount the boot cd in the temp path, under /mnt/cdrom. this way,
+ # we can use the certs when programs are running
+ # chrooted in the temp path
+ cdrom_mount_point= "%s/mnt/cdrom" % SYSIMG_PATH
+ utils.makedirs( cdrom_mount_point )
+ log.write( "Copying contents of /usr/bootme to /mnt/cdrom\n" )
+ utils.sysexec( "cp -r /usr/bootme %s/mnt/cdrom/" % SYSIMG_PATH, log )
+
+ return 1
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import os
+import string
+
+from Exceptions import *
+import utils
+
+
+# if this file is present in the vservers /etc directory,
+# the resolv.conf and hosts files will automatically be updated
+# by the bootmanager
+UPDATE_FILE_FLAG= "AUTO_UPDATE_NET_FILES"
+
+# the name of the vserver-reference directory
+VSERVER_REFERENCE_DIR_NAME='vserver-reference'
+
+
+def Run( vars, log ):
+ """
+ Setup directories for building vserver reference image.
+
+ Except the following variables from the store:
+ SYSIMG_PATH the path where the system image will be mounted
+ (always starts with TEMP_PATH)
+ NETWORK_SETTINGS A dictionary of the values from the network
+ configuration file
+
+ Sets the following variables:
+ None
+
+ """
+
+ log.write( "\n\nStep: Install: Setting up VServer image.\n" )
+
+ # make sure we have the variables we need
+ try:
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ NETWORK_SETTINGS= vars["NETWORK_SETTINGS"]
+ if NETWORK_SETTINGS == "":
+ raise ValueError, "NETWORK_SETTINGS"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+ vserver_ref_dir= "/vservers/vserver-reference"
+ full_vserver_ref_path= "%s/%s" % (SYSIMG_PATH,vserver_ref_dir)
+
+ utils.makedirs( full_vserver_ref_path )
+ utils.makedirs( "%s/etc" % full_vserver_ref_path )
+
+ log.write( "Setting permissions on directories\n" )
+ utils.sysexec( "chmod 0000 %s/vservers/" % SYSIMG_PATH, log )
+
+ return 1
+
+
+
+def update_vserver_network_files( vserver_dir, vars, log ):
+ """
+ Update the /etc/resolv.conf and /etc/hosts files in the specified
+ vserver directory. If the files do not exist, write them out. If they
+ do exist, rewrite them with new values if the file UPDATE_FILE_FLAG
+ exists it /etc. if this is called with the vserver-reference directory,
+ always update the network config files and create the UPDATE_FILE_FLAG.
+
+ This is currently called when setting up the initial vserver reference,
+ and later when nodes boot to update existing vserver images.
+
+ Expect the following variables from the store:
+ SYSIMG_PATH the path where the system image will be mounted
+ (always starts with TEMP_PATH)
+ NETWORK_SETTINGS A dictionary of the values from the network
+ configuration file
+ """
+
+ try:
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ NETWORK_SETTINGS= vars["NETWORK_SETTINGS"]
+ if NETWORK_SETTINGS == "":
+ raise ValueError, "NETWORK_SETTINGS"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+ try:
+ ip= NETWORK_SETTINGS['ip']
+ method= NETWORK_SETTINGS['method']
+ hostname= NETWORK_SETTINGS['hostname']
+ domainname= NETWORK_SETTINGS['domainname']
+ except KeyError, var:
+ raise BootManagerException, \
+ "Missing network value %s in var NETWORK_SETTINGS\n" % var
+
+ try:
+ os.listdir(vserver_dir)
+ except OSError:
+ log.write( "Directory %s does not exist to write network conf in.\n" %
+ vserver_dir )
+ return
+
+ file_path= "%s/etc/%s" % (vserver_dir,UPDATE_FILE_FLAG)
+ update_files= 0
+ if os.access(file_path,os.F_OK):
+ update_files= 1
+
+
+ if vserver_dir.find(VSERVER_REFERENCE_DIR_NAME) != -1:
+ log.write( "Forcing update on vserver-reference directory:\n%s\n" %
+ vserver_dir )
+ utils.sysexec_noerr( "echo '%s' > %s/etc/%s" %
+ (UPDATE_FILE_FLAG,vserver_dir,UPDATE_FILE_FLAG),
+ log )
+ update_files= 1
+
+
+ if update_files:
+ log.write( "Updating network files in %s.\n" % vserver_dir )
+
+ file_path= "%s/etc/hosts" % vserver_dir
+ hosts_file= file(file_path, "w" )
+ hosts_file.write( "127.0.0.1 localhost\n" )
+ if method == "static":
+ hosts_file.write( "%s %s.%s\n" % (ip, hostname, domainname) )
+ hosts_file.close()
+ hosts_file= None
+
+
+ file_path= "%s/etc/resolv.conf" % vserver_dir
+ if method == "dhcp":
+ # copy the resolv.conf from the boot cd env.
+ utils.sysexec( "cp /etc/resolv.conf %s/etc" % vserver_dir, log )
+ else:
+ # copy the generated resolv.conf from the system image, since
+ # we generated it via static settings
+ utils.sysexec( "cp %s/etc/resolv.conf %s/etc" % \
+ (SYSIMG_PATH,vserver_dir), log )
+
+ return
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+
+import os, sys, shutil
+import string
+
+import utils
+
+
+def Run( vars, log ):
+ """
+ Setup the install environment:
+ - unmount anything in the temp/sysimg path (possible from previous
+ aborted installs
+ - create temp directories
+
+ Expect the following variables from the store:
+ TEMP_PATH the path to download and store temp files to
+ SYSIMG_DIR the directory name of the system image
+ contained in TEMP_PATH
+ PLCONF_DIR The directory to store the configuration file in
+ ALPINA_SERVER_DIR The dir on the server where the support files are
+
+ Sets the following variables:
+ SYSIMG_PATH the directory where the system image will be mounted,
+ (= TEMP_PATH/SYSIMG_DIR)
+ """
+
+ log.write( "\n\nStep: Install: Initializing.\n" )
+
+ # make sure we have the variables we need
+ try:
+ TEMP_PATH= vars["TEMP_PATH"]
+ if TEMP_PATH == "":
+ raise ValueError("TEMP_PATH")
+
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError("SYSIMG_PATH")
+
+ PLCONF_DIR= vars["PLCONF_DIR"]
+ if PLCONF_DIR == "":
+ raise ValueError, "PLCONF_DIR"
+
+ ALPINA_SERVER_DIR= vars["ALPINA_SERVER_DIR"]
+ if ALPINA_SERVER_DIR == "":
+ raise ValueError, "ALPINA_SERVER_DIR"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+ # if this is a fresh install, then nothing should be
+ # here, but we support restarted installs without rebooting
+ # so who knows what the current state is
+
+ log.write( "Unmounting any previous mounts\n" )
+ utils.sysexec_noerr( "chroot %s umount /rcfs" % SYSIMG_PATH, log )
+ utils.sysexec_noerr( "umount %s/proc" % SYSIMG_PATH, log )
+ utils.sysexec_noerr( "umount %s/mnt/cdrom" % SYSIMG_PATH, log )
+ utils.sysexec_noerr( "umount %s/vservers" % SYSIMG_PATH, log )
+ utils.sysexec_noerr( "umount %s" % SYSIMG_PATH, log )
+
+ log.write( "Removing any old files, directories\n" )
+ utils.removedir( TEMP_PATH )
+
+ log.write( "Cleaning up any existing PlanetLab config files\n" )
+ utils.removedir( PLCONF_DIR )
+
+ # create the temp path and sysimg path. since sysimg
+ # path is in temp path, both are created here
+ log.write( "Creating system image path\n" )
+ utils.makedirs( SYSIMG_PATH )
+
+ return 1
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+from Exceptions import *
+import utils
+
+
+def Run( vars, log ):
+ """
+ Initialize the node:
+ - runs planetlabconf
+
+ Except the following variables from the store:
+ SYSIMG_PATH the path where the system image will be mounted
+ (always starts with TEMP_PATH)
+
+ Sets the following variables:
+ None
+
+ """
+
+ log.write( "\n\nStep: Install: Final node initialization.\n" )
+
+ # make sure we have the variables we need
+ try:
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ log.write( "Running PlanetLabConf to update any configuration files\n" )
+
+ if not utils.sysexec( "chroot %s PlanetLabConf.py noscripts" %
+ SYSIMG_PATH, log ):
+ log.write( "PlanetLabConf failed, install incomplete.\n" )
+ return 0
+
+ services= [ "netfs", "rawdevices", "cpuspeed", "smartd" ]
+ for service in services:
+ log.write( "Disabling unneeded service: %s\n" % service )
+ utils.sysexec( "chroot %s chkconfig --level 12345 %s off" %
+ (SYSIMG_PATH,service), log )
+
+ return 1
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import os, sys
+import string
+import popen2
+
+
+from Exceptions import *
+import utils
+import BootServerRequest
+import compatibility
+
+
+
+def Run( vars, log ):
+ """
+ Setup the block devices for install, partition them w/ LVM
+
+ Expect the following variables from the store:
+ INSTALL_BLOCK_DEVICES list of block devices to install onto
+ TEMP_PATH somewhere to store what we need to run
+ ROOT_SIZE the size of the root logical volume
+ SWAP_SIZE the size of the swap partition
+ ALPINA_SERVER_DIR directory on the boot servers containing alpina
+ scripts and support files
+ BOOT_CD_VERSION A tuple of the current bootcd version
+
+ Sets the following variables:
+ PARTITIONS diction of generic part. types (root/swap)
+ and their associated devices.
+ Current keys/values:
+ root /dev/planetlab/root
+ swap /dev/planetlab/swap
+
+ """
+
+ log.write( "\n\nStep: Install: partitioning disks.\n" )
+
+ # make sure we have the variables we need
+ try:
+ TEMP_PATH= vars["TEMP_PATH"]
+ if TEMP_PATH == "":
+ raise ValueError, "TEMP_PATH"
+
+ INSTALL_BLOCK_DEVICES= vars["INSTALL_BLOCK_DEVICES"]
+ if( len(INSTALL_BLOCK_DEVICES) == 0 ):
+ raise ValueError, "INSTALL_BLOCK_DEVICES is empty"
+
+ ROOT_SIZE= vars["ROOT_SIZE"]
+ if ROOT_SIZE == "" or ROOT_SIZE == 0:
+ raise ValueError, "ROOT_SIZE invalid"
+
+ SWAP_SIZE= vars["SWAP_SIZE"]
+ if SWAP_SIZE == "" or SWAP_SIZE == 0:
+ raise ValueError, "SWAP_SIZE invalid"
+
+ ALPINA_SERVER_DIR= vars["ALPINA_SERVER_DIR"]
+ if ALPINA_SERVER_DIR == None:
+ raise ValueError, "ALPINA_SERVER_DIR"
+
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+ bs_request= BootServerRequest.BootServerRequest()
+
+
+ # old cds need extra utilities to partition disks and setup lvm
+ if BOOT_CD_VERSION[0] == 2:
+ compatibility.setup_partdisks_2x_cd( vars, log )
+
+ import parted
+
+ # define the basic partition paths
+ PARTITIONS= {}
+ PARTITIONS["root"]= "/dev/planetlab/root"
+ PARTITIONS["swap"]= "/dev/planetlab/swap"
+ PARTITIONS["vservers"]= "/dev/planetlab/vservers"
+ # Linux 2.6 mounts LVM with device mapper
+ PARTITIONS["mapper-root"]= "/dev/mapper/planetlab-root"
+ PARTITIONS["mapper-swap"]= "/dev/mapper/planetlab-swap"
+ PARTITIONS["mapper-vservers"]= "/dev/mapper/planetlab-vservers"
+ vars["PARTITIONS"]= PARTITIONS
+
+
+ # disable swap if its on
+ utils.sysexec_noerr( "swapoff %s" % PARTITIONS["swap"], log )
+
+ # shutdown and remove any lvm groups/volumes
+ utils.sysexec_noerr( "vgscan", log )
+ utils.sysexec_noerr( "vgchange -ay", log )
+ utils.sysexec_noerr( "lvremove -f /dev/planetlab/root", log )
+ utils.sysexec_noerr( "lvremove -f /dev/planetlab/swap", log )
+ utils.sysexec_noerr( "lvremove -f /dev/planetlab/vservers", log )
+ utils.sysexec_noerr( "vgchange -an", log )
+ utils.sysexec_noerr( "vgremove planetlab", log )
+
+ log.write( "Running vgscan for devices\n" )
+ utils.sysexec_noerr( "vgscan", log )
+
+ used_devices= []
+
+ for device in INSTALL_BLOCK_DEVICES:
+
+ if single_partition_device( device, vars, log ):
+ used_devices.append( device )
+ log.write( "Successfully initialized %s\n" % device )
+ else:
+ log.write( "Unable to partition %s, not using it.\n" % device )
+ continue
+
+ # list of devices to be used with vgcreate
+ vg_device_list= ""
+
+ # initialize the physical volumes
+ for device in used_devices:
+
+ part_path= get_partition_path_from_device( device, vars, log )
+
+ if not create_lvm_physical_volume( part_path, vars, log ):
+ raise BootManagerException, "Could not create lvm physical volume " \
+ "on partition %s" % part_path
+
+ vg_device_list = vg_device_list + " " + part_path
+
+ # create an lvm volume group
+ utils.sysexec( "vgcreate -s32M planetlab %s" % vg_device_list, log)
+
+ # create swap logical volume
+ utils.sysexec( "lvcreate -L%s -nswap planetlab" % SWAP_SIZE, log )
+
+ # create root logical volume
+ utils.sysexec( "lvcreate -L%s -nroot planetlab" % ROOT_SIZE, log )
+
+ # create vservers logical volume with all remaining space
+ # first, we need to get the number of remaining extents we can use
+ remaining_extents= get_remaining_extents_on_vg( vars, log )
+
+ utils.sysexec( "lvcreate -l%s -nvservers planetlab" % remaining_extents, log )
+
+ # activate volume group (should already be active)
+ #utils.sysexec( TEMP_PATH + "vgchange -ay planetlab", log )
+
+ # make swap
+ utils.sysexec( "mkswap %s" % PARTITIONS["swap"], log )
+
+ # make root file system
+ utils.sysexec( "mkfs.ext2 -j %s" % PARTITIONS["root"], log )
+
+ # make vservers file system
+ utils.sysexec( "mkfs.ext2 -m 0 -j %s" % PARTITIONS["vservers"], log )
+
+ # save the list of block devices in the log
+ log.write( "Block devices used (in lvm):\n" )
+ log.write( repr(used_devices) + "\n" )
+ log.write( "End of block devices used (in lvm).\n" )
+
+ # list of block devices used may be updated
+ vars["INSTALL_BLOCK_DEVICES"]= used_devices
+
+ return 1
+
+
+
+def single_partition_device( device, vars, log ):
+ """
+ initialize a disk by removing the old partition tables,
+ and creating a new single partition that fills the disk.
+
+ return 1 if sucessful, 0 otherwise
+ """
+
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION[0] == 2:
+ compatibility.setup_partdisks_2x_cd( vars, log )
+
+ import parted
+
+ lvm_flag= parted.partition_flag_get_by_name('lvm')
+
+ try:
+ # wipe the old partition table
+ utils.sysexec( "dd if=/dev/zero of=%s bs=512 count=1" % device, log )
+
+ # get the device
+ dev= parted.PedDevice.get(device)
+
+ # 2.x cds have different libparted that 3.x cds, and they have
+ # different interfaces
+ if BOOT_CD_VERSION[0] == 3:
+
+ # create a new partition table
+ disk= dev.disk_new_fresh(parted.disk_type_get("msdos"))
+
+ # create one big partition on each block device
+ constraint= dev.constraint_any()
+
+ new_part= disk.partition_new(
+ parted.PARTITION_PRIMARY,
+ parted.file_system_type_get("ext2"),
+ 0, 1 )
+
+ # make it an lvm partition
+ new_part.set_flag(lvm_flag,1)
+
+ # actually add the partition to the disk
+ disk.add_partition(new_part, constraint)
+
+ disk.maximize_partition(new_part,constraint)
+
+ disk.commit()
+ del disk
+ else:
+ # create a new partition table
+ dev.disk_create(parted.disk_type_get("msdos"))
+
+ # get the disk
+ disk= parted.PedDisk.open(dev)
+
+ # create one big partition on each block device
+ part= disk.next_partition()
+ while part:
+ if part.type == parted.PARTITION_FREESPACE:
+ new_part= disk.partition_new(
+ parted.PARTITION_PRIMARY,
+ parted.file_system_type_get("ext2"),
+ part.geom.start,
+ part.geom.end )
+
+ constraint = disk.constraint_any()
+
+ # make it an lvm partition
+ new_part.set_flag(lvm_flag,1)
+
+ # actually add the partition to the disk
+ disk.add_partition(new_part, constraint)
+
+ break
+
+ part= disk.next_partition(part)
+
+ disk.write()
+ disk.close()
+ del disk
+
+ except BootManagerException, e:
+ log.write( "BootManagerException while running: %s\n" % str(e) )
+ return 0
+
+ except parted.error, e:
+ log.write( "parted exception while running: %s\n" % str(e) )
+ return 0
+
+ return 1
+
+
+
+def create_lvm_physical_volume( part_path, vars, log ):
+ """
+ make the specificed partition a lvm physical volume.
+
+ return 1 if successful, 0 otherwise.
+ """
+
+ try:
+ # again, wipe any old data, this time on the partition
+ utils.sysexec( "dd if=/dev/zero of=%s bs=512 count=1" % part_path, log )
+ utils.sysexec( "pvcreate -fy %s" % part_path, log )
+ except BootManagerException, e:
+ log.write( "create_lvm_physical_volume failed.\n" )
+ return 0
+
+ return 1
+
+
+
+def get_partition_path_from_device( device, vars, log ):
+ """
+ given a device, return the path of the first partition on the device
+ """
+
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+
+ # those who wrote the cciss driver just had to make it difficult
+ if BOOT_CD_VERSION[0] == 3:
+ cciss_test= "/dev/cciss"
+ if device[:len(cciss_test)] == cciss_test:
+ part_path= device + "p1"
+ else:
+ part_path= device + "1"
+ else:
+ # since device ends in /disc, we need to make it end in
+ # /part1 to indicate the first partition (for devfs based 2.x cds)
+ dev_parts= string.split(device,"/")
+ dev_parts[len(dev_parts)-1]= "part1"
+ part_path= string.join(dev_parts,"/")
+
+ return part_path
+
+
+
+def get_remaining_extents_on_vg( vars, log ):
+ """
+ return the free amount of extents on the planetlab volume group
+ """
+
+ c_stdout, c_stdin = popen2.popen2("vgdisplay -c planetlab")
+ result= string.strip(c_stdout.readline())
+ c_stdout.close()
+ c_stdin.close()
+ remaining_extents= string.split(result,":")[15]
+
+ return remaining_extents
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import os
+
+from Exceptions import *
+import utils
+
+
+
+def Run( vars, log ):
+ """
+ Unitializes hardware:
+ - unmount all previously mounted partitions
+
+ Except the following variables from the store:
+ TEMP_PATH the path to download and store temp files to
+ SYSIMG_PATH the path where the system image will be mounted
+ (always starts with TEMP_PATH)
+ PARTITIONS dictionary of generic part. types (root/swap)
+ and their associated devices.
+ NODE_ID the node_id from the database for this node
+
+ this is needed to make any requests back to the server
+
+ Sets the following variables:
+ None
+
+ """
+
+ log.write( "\n\nStep: Install: Shutting down installer.\n" )
+
+ # make sure we have the variables we need
+ try:
+ TEMP_PATH= vars["TEMP_PATH"]
+ if TEMP_PATH == "":
+ raise ValueError, "TEMP_PATH"
+
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ PARTITIONS= vars["PARTITIONS"]
+ if PARTITIONS == None:
+ raise ValueError, "PARTITIONS"
+
+ NODE_ID= vars["NODE_ID"]
+ if NODE_ID == "":
+ raise ValueError("NODE_ID")
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ try:
+ # make sure the required partitions exist
+ val= PARTITIONS["root"]
+ val= PARTITIONS["swap"]
+ val= PARTITIONS["vservers"]
+ except KeyError, part:
+ raise BootManagerException, "Missing partition in PARTITIONS: %s\n" % part
+
+ # workaround
+ utils.sysexec_noerr( "chroot %s umount /rcfs" % SYSIMG_PATH, log )
+
+ log.write( "Unmounting proc.\n" )
+ utils.sysexec( "umount %s/proc" % SYSIMG_PATH, log )
+
+ log.write( "Unmounting vserver partition.\n" )
+ utils.sysexec( "umount %s" % PARTITIONS["vservers"], log )
+
+ log.write( "Unmounting rcfs file system in image.\n" )
+ utils.sysexec_noerr( "chroot %s umount /rcfs" % SYSIMG_PATH, log )
+
+ log.write( "Unmounting system image.\n" )
+ utils.sysexec( "umount %s" % PARTITIONS["root"], log )
+
+ log.write( "Shutting down swap\n" )
+ utils.sysexec( "swapoff %s" % PARTITIONS["swap"], log )
+
+ # as one of the last steps, upload /var/log/messages if it exists
+
+ # send a notification that the install is complete
+ #action= "email"
+ #message= "installfinished"
+ #nodestate= ""
+
+ #try:
+ # result= utils.notifybootserver( BS_REQUEST, NODE_ID,
+ # NODE_NONCE,
+ # action, message, nodestate )
+ #except AlpinaError, desc:
+ # log.write( "Unable to notify boot server of " \
+ # "install complete (not critical): %s" % desc )
+
+ return 1
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import os, string
+
+from Exceptions import *
+import utils
+from systeminfo import systeminfo
+import BootAPI
+
+
+def Run( vars, log ):
+
+ """
+ Writes out the following configuration files for the node:
+ /etc/fstab
+ /etc/hosts
+ /etc/sysconfig/network-scripts/ifcfg-eth0
+ /etc/resolv.conf (if applicable)
+ /etc/sysconfig/network
+ /etc/modprobe.conf
+ /etc/ssh/ssh_host_key
+ /etc/ssh/ssh_host_rsa_key
+ /etc/ssh/ssh_host_dsa_key
+
+ Expect the following variables from the store:
+ VERSION the version of the install
+ SYSIMG_PATH the path where the system image will be mounted
+ (always starts with TEMP_PATH)
+ PARTITIONS dictionary of generic part. types (root/swap)
+ and their associated devices.
+ PLCONF_DIR The directory to store the configuration file in
+ NETWORK_SETTINGS A dictionary of the values from the network
+ configuration file
+ BOOT_CD_VERSION A tuple of the current bootcd version
+
+ Sets the following variables:
+ None
+
+ """
+
+ log.write( "\n\nStep: Install: Writing configuration files.\n" )
+
+ # make sure we have the variables we need
+ try:
+ VERSION= vars["VERSION"]
+ if VERSION == "":
+ raise ValueError, "VERSION"
+
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ PARTITIONS= vars["PARTITIONS"]
+ if PARTITIONS == None:
+ raise ValueError, "PARTITIONS"
+
+ PLCONF_DIR= vars["PLCONF_DIR"]
+ if PLCONF_DIR == "":
+ raise ValueError, "PLCONF_DIR"
+
+ NETWORK_SETTINGS= vars["NETWORK_SETTINGS"]
+ if NETWORK_SETTINGS == "":
+ raise ValueError, "NETWORK_SETTINGS"
+
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+ try:
+ # we need to keys in PARTITIONS, root and swap, make sure
+ # they exist
+ val= PARTITIONS["root"]
+ val= PARTITIONS["swap"]
+ val= PARTITIONS["vservers"]
+ val= PARTITIONS["mapper-root"]
+ val= PARTITIONS["mapper-swap"]
+ val= PARTITIONS["mapper-vservers"]
+ except KeyError, part:
+ log.write( "Missing partition in PARTITIONS: %s\n" % part )
+ return 0
+
+
+ log.write( "Setting local time to UTC\n" )
+ utils.sysexec( "chroot %s ln -sf /usr/share/zoneinfo/UTC /etc/localtime" % \
+ SYSIMG_PATH, log )
+
+
+ log.write( "Enabling ntp at boot\n" )
+ utils.sysexec( "chroot %s chkconfig ntpd on" % SYSIMG_PATH, log )
+
+ log.write( "Creating system directory %s\n" % PLCONF_DIR )
+ if not utils.makedirs( "%s/%s" % (SYSIMG_PATH,PLCONF_DIR) ):
+ log.write( "Unable to create directory\n" )
+ return 0
+
+
+ log.write( "Writing network configuration\n" )
+ write_network_configuration( vars, log )
+
+ # write out the modprobe.conf file for the system. make sure
+ # the order of the ethernet devices are listed in the same order
+ # as the boot cd loaded the modules. this is found in /tmp/loadedmodules
+ # ultimately, the order will only match the boot cd order if
+ # the kernel modules have the same name - which should be true for the later
+ # version boot cds because they use the same kernel version.
+ # older boot cds use a 2.4.19 kernel, and its possible some of the network
+ # module names have changed, in which case the system might not boot
+ # if the network modules are activated in a different order that the
+ # boot cd.
+ log.write( "Writing /etc/modprobe.conf\n" )
+
+ sysinfo= systeminfo()
+ sysmods= sysinfo.get_system_modules(SYSIMG_PATH)
+ if sysmods is None:
+ raise BootManagerException, "Unable to get list of system modules."
+
+ eth_count= 0
+ scsi_count= 0
+
+ modulesconf_file= file("%s/etc/modprobe.conf" % SYSIMG_PATH, "w" )
+
+ for type in sysmods:
+ if type == sysinfo.MODULE_CLASS_SCSI:
+ for a_mod in sysmods[type]:
+ if scsi_count == 0:
+ modulesconf_file.write( "alias scsi_hostadapter %s\n" %
+ a_mod )
+ else:
+ modulesconf_file.write( "alias scsi_hostadapter%d %s\n" %
+ (scsi_count,a_mod) )
+ scsi_count= scsi_count + 1
+
+ elif type == sysinfo.MODULE_CLASS_NETWORK:
+ for a_mod in sysmods[type]:
+ modulesconf_file.write( "alias eth%d %s\n" %
+ (eth_count,a_mod) )
+ eth_count= eth_count + 1
+
+ modulesconf_file.close()
+ modulesconf_file= None
+
+
+ # dump the modprobe.conf file to the log (not to screen)
+ log.write( "Contents of new modprobe.conf file:\n" )
+ modulesconf_file= file("%s/etc/modprobe.conf" % SYSIMG_PATH, "r" )
+ contents= modulesconf_file.read()
+ log.write( contents + "\n" )
+ modulesconf_file.close()
+ modulesconf_file= None
+ log.write( "End contents of new modprobe.conf file.\n" )
+
+ log.write( "Writing system /etc/fstab\n" )
+ fstab= file( "%s/etc/fstab" % SYSIMG_PATH, "w" )
+ fstab.write( "%s none swap sw 0 0\n" % \
+ PARTITIONS["mapper-swap"] )
+ fstab.write( "%s / ext3 defaults 0 0\n" % \
+ PARTITIONS["mapper-root"] )
+ fstab.write( "%s /vservers ext3 tagxid,defaults 0 0\n" % \
+ PARTITIONS["mapper-vservers"] )
+ fstab.write( "none /proc proc defaults 0 0\n" )
+ fstab.write( "none /dev/shm tmpfs defaults 0 0\n" )
+ fstab.write( "none /dev/pts devpts defaults 0 0\n" )
+ fstab.write( "none /rcfs rcfs defaults 0 0\n" )
+ fstab.close()
+
+
+ log.write( "Writing system /etc/issue\n" )
+ issue= file( "%s/etc/issue" % SYSIMG_PATH, "w" )
+ issue.write( "PlanetLab Node: \\n\n" )
+ issue.write( "Kernel \\r on an \\m\n" )
+ issue.write( "http://www.planet-lab.org\n\n" )
+ issue.close()
+
+ log.write( "Setting up authentication (non-ssh)\n" )
+ utils.sysexec( "chroot %s authconfig --nostart --kickstart --enablemd5 " \
+ "--enableshadow" % SYSIMG_PATH, log )
+ utils.sysexec( "sed -e 's/^root\:\:/root\:*\:/g' " \
+ "%s/etc/shadow > %s/etc/shadow.new" % \
+ (SYSIMG_PATH,SYSIMG_PATH), log )
+ utils.sysexec( "chroot %s mv " \
+ "/etc/shadow.new /etc/shadow" % SYSIMG_PATH, log )
+ utils.sysexec( "chroot %s chmod 400 /etc/shadow" % SYSIMG_PATH, log )
+
+ # if we are setup with dhcp, copy the current /etc/resolv.conf into
+ # the system image so we can run programs inside that need network access
+ method= ""
+ try:
+ method= vars['NETWORK_SETTINGS']['method']
+ except:
+ pass
+
+ if method == "dhcp":
+ utils.sysexec( "cp /etc/resolv.conf %s/etc/" % SYSIMG_PATH, log )
+
+ # the kernel rpm should have already done this, so don't fail the
+ # install if it fails
+ log.write( "Mounting /proc in system image\n" )
+ utils.sysexec_noerr( "mount -t proc proc %s/proc" % SYSIMG_PATH, log )
+
+ # mkinitrd references both /etc/modprobe.conf and /etc/fstab
+ # as well as /proc/lvm/global. The kernel RPM installation
+ # likely created an improper initrd since these files did not
+ # yet exist. Re-create the initrd here.
+ log.write( "Making initrd\n" )
+
+ # trick mkinitrd in case the current environment does not have device mapper
+ fake_root_lvm= 0
+ if not os.path.exists( "%s/%s" % (SYSIMG_PATH,PARTITIONS["mapper-root"]) ):
+ fake_root_lvm= 1
+ utils.makedirs( "%s/dev/mapper" % SYSIMG_PATH )
+ rootdev= file( "%s/%s" % (SYSIMG_PATH,PARTITIONS["mapper-root"]), "w" )
+ rootdev.close()
+
+ utils.sysexec( "chroot %s sh -c '" \
+ "kernelversion=`ls /lib/modules | tail -1` && " \
+ "rm -f /boot/initrd-$kernelversion.img && " \
+ "mkinitrd /boot/initrd-$kernelversion.img $kernelversion'" % \
+ SYSIMG_PATH, log )
+
+ if fake_root_lvm == 1:
+ utils.removefile( "%s/%s" % (SYSIMG_PATH,PARTITIONS["mapper-root"]) )
+
+ log.write( "Writing node install version\n" )
+ utils.makedirs( "%s/etc/planetlab" % SYSIMG_PATH )
+ ver= file( "%s/etc/planetlab/install_version" % SYSIMG_PATH, "w" )
+ ver.write( "%s\n" % VERSION )
+ ver.close()
+
+ log.write( "Creating ssh host keys\n" )
+ key_gen_prog= "/usr/bin/ssh-keygen"
+
+ log.write( "Generating SSH1 RSA host key:\n" )
+ key_file= "/etc/ssh/ssh_host_key"
+ utils.sysexec( "chroot %s %s -q -t rsa1 -f %s -C '' -N ''" %
+ (SYSIMG_PATH,key_gen_prog,key_file), log )
+ utils.sysexec( "chmod 600 %s/%s" % (SYSIMG_PATH,key_file), log )
+ utils.sysexec( "chmod 644 %s/%s.pub" % (SYSIMG_PATH,key_file), log )
+
+ log.write( "Generating SSH2 RSA host key:\n" )
+ key_file= "/etc/ssh/ssh_host_rsa_key"
+ utils.sysexec( "chroot %s %s -q -t rsa -f %s -C '' -N ''" %
+ (SYSIMG_PATH,key_gen_prog,key_file), log )
+ utils.sysexec( "chmod 600 %s/%s" % (SYSIMG_PATH,key_file), log )
+ utils.sysexec( "chmod 644 %s/%s.pub" % (SYSIMG_PATH,key_file), log )
+
+ log.write( "Generating SSH2 DSA host key:\n" )
+ key_file= "/etc/ssh/ssh_host_dsa_key"
+ utils.sysexec( "chroot %s %s -q -t dsa -f %s -C '' -N ''" %
+ (SYSIMG_PATH,key_gen_prog,key_file), log )
+ utils.sysexec( "chmod 600 %s/%s" % (SYSIMG_PATH,key_file), log )
+ utils.sysexec( "chmod 644 %s/%s.pub" % (SYSIMG_PATH,key_file), log )
+
+ return 1
+
+
+
+def write_network_configuration( vars, log ):
+ """
+ Write out the network configuration for this machine:
+ /etc/hosts
+ /etc/sysconfig/network-scripts/ifcfg-eth0
+ /etc/resolv.conf (if applicable)
+ /etc/sysconfig/network
+
+ It is assumed the caller mounted the root partition and the vserver partition
+ starting on SYSIMG_PATH - it is not checked here.
+
+ The values to be used for the network settings are to be set in vars
+ in the variable 'NETWORK_SETTINGS', which is a dictionary
+ with keys:
+
+ Key Used by this function
+ -----------------------------------------------
+ node_id
+ node_key
+ method x
+ ip x
+ mac x (optional)
+ gateway x
+ network x
+ broadcast x
+ netmask x
+ dns1 x
+ dns2 x (optional)
+ hostname x
+ domainname x
+ """
+
+ try:
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ try:
+ network_settings= vars['NETWORK_SETTINGS']
+ except KeyError, e:
+ raise BootManagerException, "No network settings found in vars."
+
+ try:
+ hostname= network_settings['hostname']
+ domainname= network_settings['domainname']
+ method= network_settings['method']
+ ip= network_settings['ip']
+ gateway= network_settings['gateway']
+ network= network_settings['network']
+ netmask= network_settings['netmask']
+ dns1= network_settings['dns1']
+ except KeyError, e:
+ raise BootManagerException, "Missing value %s in network settings." % str(e)
+
+ try:
+ dns2= ''
+ dns2= network_settings['dns2']
+ except KeyError, e:
+ pass
+
+
+ log.write( "Writing /etc/hosts\n" )
+ hosts_file= file("%s/etc/hosts" % SYSIMG_PATH, "w" )
+ hosts_file.write( "127.0.0.1 localhost\n" )
+ if method == "static":
+ hosts_file.write( "%s %s.%s\n" % (ip, hostname, domainname) )
+ hosts_file.close()
+ hosts_file= None
+
+
+ log.write( "Writing /etc/sysconfig/network-scripts/ifcfg-eth0\n" )
+ eth0_file= file("%s/etc/sysconfig/network-scripts/ifcfg-eth0" %
+ SYSIMG_PATH, "w" )
+ eth0_file.write( "DEVICE=eth0\n" )
+ if method == "static":
+ eth0_file.write( "BOOTPROTO=static\n" )
+ eth0_file.write( "IPADDR=%s\n" % ip )
+ eth0_file.write( "NETMASK=%s\n" % netmask )
+ eth0_file.write( "GATEWAY=%s\n" % gateway )
+ else:
+ eth0_file.write( "BOOTPROTO=dhcp\n" )
+ eth0_file.write( "DHCP_HOSTNAME=%s\n" % hostname )
+ eth0_file.write( "ONBOOT=yes\n" )
+ eth0_file.write( "USERCTL=no\n" )
+ eth0_file.close()
+ eth0_file= None
+
+ if method == "static":
+ log.write( "Writing /etc/resolv.conf\n" )
+ resolv_file= file("%s/etc/resolv.conf" % SYSIMG_PATH, "w" )
+ if dns1 != "":
+ resolv_file.write( "nameserver %s\n" % dns1 )
+ if dns2 != "":
+ resolv_file.write( "nameserver %s\n" % dns2 )
+ resolv_file.write( "search %s\n" % domainname )
+ resolv_file.close()
+ resolv_file= None
+
+ log.write( "Writing /etc/sysconfig/network\n" )
+ network_file= file("%s/etc/sysconfig/network" % SYSIMG_PATH, "w" )
+ network_file.write( "NETWORKING=yes\n" )
+ network_file.write( "HOSTNAME=%s.%s\n" % (hostname, domainname) )
+ if method == "static":
+ network_file.write( "GATEWAY=%s\n" % gateway )
+ network_file.close()
+ network_file= None
+
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import sys, os, traceback
+import string
+import socket
+
+import utils
+from Exceptions import *
+import BootServerRequest
+
+
+# two possible names of the configuration files
+NEW_CONF_FILE_NAME= "plnode.txt"
+OLD_CONF_FILE_NAME= "planet.cnf"
+
+
+def Run( vars, log ):
+ """
+ read the machines node configuration file, which contains
+ the node key and the node_id for this machine.
+
+ these files can exist in several different locations with
+ several different names. Below is the search order:
+
+ filename floppy flash cd
+ plnode.txt 1 2 4 (/usr/boot), 5 (/usr)
+ planet.cnf 3
+
+ The locations will be searched in the above order, plnode.txt
+ will be checked first, then planet.cnf. Flash devices will only
+ be searched on 3.0 cds.
+
+ Because some of the earlier
+ boot cds don't validate the configuration file (which results
+ in a file named /tmp/planet-clean.cnf), and some do, lets
+ bypass this, and mount and attempt to read in the conf
+ file ourselves. If it doesn't exist, we cannot continue, and a
+ BootManagerException will be raised. If the configuration file is found
+ and read, return 1.
+
+ Expect the following variables from the store:
+ BOOT_CD_VERSION A tuple of the current bootcd version
+ ALPINA_SERVER_DIR directory on the boot servers containing alpina
+ scripts and support files
+
+ Sets the following variables from the configuration file:
+ WAS_NODE_ID_IN_CONF Set to 1 if the node id was in the conf file
+ WAS_NODE_KEY_IN_CONF Set to 1 if the node key was in the conf file
+ NONE_ID The db node_id for this machine
+ NODE_KEY The key for this node
+ NETWORK_SETTINGS A dictionary of the values from the network
+ configuration file. keys set:
+ method
+ ip
+ mac
+ gateway
+ network
+ broadcast
+ netmask
+ dns1
+ dns2
+ hostname
+ domainname
+ """
+
+ log.write( "\n\nStep: Reading node configuration file.\n" )
+
+
+ # make sure we have the variables we need
+ try:
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ ALPINA_SERVER_DIR= vars["ALPINA_SERVER_DIR"]
+ if ALPINA_SERVER_DIR == None:
+ raise ValueError, "ALPINA_SERVER_DIR"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ NETWORK_SETTINGS= {}
+ NETWORK_SETTINGS['method']= "dhcp"
+ NETWORK_SETTINGS['ip']= ""
+ NETWORK_SETTINGS['mac']= ""
+ NETWORK_SETTINGS['gateway']= ""
+ NETWORK_SETTINGS['network']= ""
+ NETWORK_SETTINGS['broadcast']= ""
+ NETWORK_SETTINGS['netmask']= ""
+ NETWORK_SETTINGS['dns1']= ""
+ NETWORK_SETTINGS['dns2']= ""
+ NETWORK_SETTINGS['hostname']= "localhost"
+ NETWORK_SETTINGS['domainname']= "localdomain"
+ vars['NETWORK_SETTINGS']= NETWORK_SETTINGS
+
+ vars['NODE_ID']= 0
+ vars['NODE_KEY']= ""
+
+ vars['WAS_NODE_ID_IN_CONF']= 0
+ vars['WAS_NODE_KEY_IN_CONF']= 0
+
+ # for any devices that need to be mounted to get the configuration
+ # file, mount them here.
+ mount_point= "/tmp/conffilemount"
+ utils.makedirs( mount_point )
+
+ old_conf_file_contents= None
+ conf_file_contents= None
+
+
+ # 1. check the regular floppy device
+ log.write( "Checking standard floppy disk for plnode.txt file.\n" )
+
+ utils.sysexec_noerr( "mount -o ro -t ext2,msdos /dev/fd0 %s " \
+ % mount_point, log )
+
+ conf_file_path= "%s/%s" % (mount_point,NEW_CONF_FILE_NAME)
+ if os.access( conf_file_path, os.R_OK ):
+ try:
+ conf_file= file(conf_file_path,"r")
+ conf_file_contents= conf_file.read()
+ conf_file.close()
+ except IOError, e:
+ pass
+
+ utils.sysexec_noerr( "umount /dev/fd0", log )
+ if __parse_configuration_file( vars, log, conf_file_contents):
+ return 1
+ else:
+ raise BootManagerException( "Found configuration file plnode.txt " \
+ "on floppy, but was unable to parse it." )
+
+
+ # try the old file name, same device. its actually number 3 on the search
+ # order, but do it now to save mounting/unmounting the disk twice.
+ # try to parse it later...
+ conf_file_path= "%s/%s" % (mount_point,OLD_CONF_FILE_NAME)
+ if os.access( conf_file_path, os.R_OK ):
+ try:
+ old_conf_file= file(conf_file_path,"r")
+ old_conf_file_contents= old_conf_file.read()
+ old_conf_file.close()
+ except IOError, e:
+ pass
+
+ utils.sysexec_noerr( "umount /dev/fd0", log )
+
+
+
+ if BOOT_CD_VERSION[0] == 3:
+ # 2. check flash devices on 3.0 based cds
+ log.write( "Checking flash devices for plnode.txt file.\n" )
+
+ # this is done the same way the 3.0 cds do it, by attempting
+ # to mount and sd*1 devices that are removable
+ devices= os.listdir("/sys/block/")
+
+ for device in devices:
+ if device[:2] != "sd":
+ continue
+
+ # test removable
+ removable_file_path= "/sys/block/%s/removable" % device
+ try:
+ removable= int(file(removable_file_path,"r").read().strip())
+ except ValueError, e:
+ continue
+ except IOError, e:
+ continue
+
+ if not removable:
+ continue
+
+ log.write( "Checking removable device %s\n" % device )
+
+ # ok, try to mount it and see if we have a conf file.
+ full_device= "/dev/%s1" % device
+
+ try:
+ utils.sysexec( "mount -o ro -t ext2,msdos %s %s" \
+ % (full_device,mount_point), log )
+ except BootManagerException, e:
+ continue
+
+ conf_file_path= "%s/%s" % (mount_point,NEW_CONF_FILE_NAME)
+ if os.access( conf_file_path, os.R_OK ):
+ try:
+ conf_file= file(conf_file_path,"r")
+ conf_file_contents= conf_file.read()
+ conf_file.close()
+ except IOError, e:
+ pass
+
+ utils.sysexec_noerr( "umount %s" % full_device, log )
+ if __parse_configuration_file( vars, log, conf_file_contents):
+ return 1
+ else:
+ raise BootManagerException("Found configuration file plnode.txt " \
+ "on floppy, but was unable to parse it.")
+
+
+
+ # 3. check standard floppy disk for old file name planet.cnf
+ log.write( "Checking standard floppy disk for planet.cnf file.\n" )
+
+ if old_conf_file_contents:
+ if __parse_configuration_file( vars, log, old_conf_file_contents):
+ return 1
+ else:
+ raise BootManagerException( "Found configuration file planet.cnf " \
+ "on floppy, but was unable to parse it." )
+
+
+ # 4. check for plnode.txt in /usr/boot (mounted already)
+ log.write( "Checking /usr/boot (cd) for plnode.txt file.\n" )
+
+ conf_file_path= "/usr/boot/%s" % NEW_CONF_FILE_NAME
+ if os.access(conf_file_path,os.R_OK):
+ try:
+ conf_file= file(conf_file_path,"r")
+ conf_file_contents= conf_file.read()
+ conf_file.close()
+ except IOError, e:
+ pass
+
+ if __parse_configuration_file( vars, log, conf_file_contents):
+ return 1
+ else:
+ raise BootManagerException( "Found configuration file plnode.txt " \
+ "in /usr/boot, but was unable to parse it.")
+
+
+
+ # 5. check for plnode.txt in /usr (mounted already)
+ log.write( "Checking /usr (cd) for plnode.txt file.\n" )
+
+ conf_file_path= "/usr/%s" % NEW_CONF_FILE_NAME
+ if os.access(conf_file_path,os.R_OK):
+ try:
+ conf_file= file(conf_file_path,"r")
+ conf_file_contents= conf_file.read()
+ conf_file.close()
+ except IOError, e:
+ pass
+
+ if __parse_configuration_file( vars, log, conf_file_contents):
+ return 1
+ else:
+ raise BootManagerException( "Found configuration file plnode.txt " \
+ "in /usr, but was unable to parse it.")
+
+
+ raise BootManagerException, "Unable to find and read a node configuration file."
+
+
+
+
+def __parse_configuration_file( vars, log, file_contents ):
+ """
+ parse a configuration file, set keys in var NETWORK_SETTINGS
+ in vars (see comment for function ReadNodeConfiguration)
+ """
+
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ ALPINA_SERVER_DIR= vars["ALPINA_SERVER_DIR"]
+ NETWORK_SETTINGS= vars["NETWORK_SETTINGS"]
+
+ if file_contents is None:
+ return 0
+
+ try:
+ line_num= 0
+ for line in file_contents.split("\n"):
+
+ line_num = line_num + 1
+
+ # if its a comment or a whitespace line, ignore
+ if line[:1] == "#" or string.strip(line) == "":
+ continue
+
+ # file is setup as name="value" pairs
+ parts= string.split(line,"=")
+ if len(parts) != 2:
+ log.write( "Invalid line %d in configuration file:\n" % line_num )
+ log.write( line + "\n" )
+ return 0
+
+ name= string.strip(parts[0])
+ value= string.strip(parts[1])
+
+ # make sure value starts and ends with
+ # single or double quotes
+ quotes= value[0] + value[len(value)-1]
+ if quotes != "''" and quotes != '""':
+ log.write( "Invalid line %d in configuration file:\n" % line_num )
+ log.write( line + "\n" )
+ return 0
+
+ # get rid of the quotes around the value
+ value= string.strip(value[1:len(value)-1])
+
+ if name == "NODE_ID":
+ try:
+ vars['NODE_ID']= int(value)
+ vars['WAS_NODE_ID_IN_CONF']= 1
+ except ValueError, e:
+ log.write( "Non-numeric node_id in configuration file.\n" )
+ return 0
+
+ if name == "NODE_KEY":
+ vars['NODE_KEY']= value
+ vars['WAS_NODE_KEY_IN_CONF']= 1
+
+ if name == "IP_METHOD":
+ value= string.lower(value)
+ if value != "static" and value != "dhcp":
+ log.write( "Invalid IP_METHOD in configuration file:\n" )
+ log.write( line + "\n" )
+ return 0
+ NETWORK_SETTINGS['method']= value.strip()
+
+ if name == "IP_ADDRESS":
+ NETWORK_SETTINGS['ip']= value.strip()
+
+ if name == "IP_GATEWAY":
+ NETWORK_SETTINGS['gateway']= value.strip()
+
+ if name == "IP_NETMASK":
+ NETWORK_SETTINGS['netmask']= value.strip()
+
+ if name == "IP_NETADDR":
+ NETWORK_SETTINGS['network']= value.strip()
+
+ if name == "IP_BROADCASTADDR":
+ NETWORK_SETTINGS['broadcast']= value.strip()
+
+ if name == "IP_DNS1":
+ NETWORK_SETTINGS['dns1']= value.strip()
+
+ if name == "IP_DNS2":
+ NETWORK_SETTINGS['dns2']= value.strip()
+
+ if name == "HOST_NAME":
+ NETWORK_SETTINGS['hostname']= string.lower(value)
+
+ if name == "DOMAIN_NAME":
+ NETWORK_SETTINGS['domainname']= string.lower(value)
+
+ except IndexError, e:
+ log.write( "Unable to parse configuration file\n" )
+ return 0
+
+ # now if we are set to dhcp, clear out any fields
+ # that don't make sense
+ if NETWORK_SETTINGS["method"] == "dhcp":
+ NETWORK_SETTINGS["ip"]= ""
+ NETWORK_SETTINGS["gateway"]= ""
+ NETWORK_SETTINGS["netmask"]= ""
+ NETWORK_SETTINGS["network"]= ""
+ NETWORK_SETTINGS["broadcast"]= ""
+ NETWORK_SETTINGS["dns1"]= ""
+ NETWORK_SETTINGS["dns2"]= ""
+
+
+ log.write("Successfully read and parsed node configuration file.\n" )
+
+
+ if vars['NODE_ID'] is None or vars['NODE_ID'] == 0:
+ log.write( "Configuration file does not contain the node_id value.\n" )
+ log.write( "Querying PLC for node_id.\n" )
+
+ bs_request= BootServerRequest.BootServerRequest()
+
+ try:
+ ifconfig_file= file("/tmp/ifconfig","r")
+ ifconfig= ifconfig_file.read()
+ ifconfig_file.close()
+ except IOError:
+ log.write( "Unable to read ifconfig output from /tmp/ifconfig\n" )
+ return 0
+
+ postVars= {"ifconfig" : ifconfig}
+ result= bs_request.DownloadFile( "%s/getnodeid.php" %
+ ALPINA_SERVER_DIR,
+ None, postVars, 1, 1,
+ "/tmp/node_id")
+ if result == 0:
+ log.write( "Unable to make request to get node_id.\n" )
+ return 0
+
+ try:
+ node_id_file= file("/tmp/node_id","r")
+ node_id= string.strip(node_id_file.read())
+ node_id_file.close()
+ except IOError:
+ log.write( "Unable to read node_id from /tmp/node_id\n" )
+ return 0
+
+ try:
+ node_id= int(string.strip(node_id))
+ except ValueError:
+ log.write( "Got node_id from PLC, but not numeric: %s" % str(node_id) )
+ return 0
+
+ if node_id == -1:
+ log.write( "Got node_id, but it returned -1\n" )
+ return 0
+
+ log.write( "Got node_id from PLC: %s\n" % str(node_id) )
+ vars['NODE_ID']= node_id
+
+
+
+ if vars['NODE_KEY'] is None or vars['NODE_KEY'] == "":
+ log.write( "Configuration file does not contain a node_key value.\n" )
+ log.write( "Using boot nonce instead.\n" )
+
+ # 3.x cds stored the file in /tmp/nonce in ascii form, so they
+ # can be read and used directly. 2.x cds stored in the same place
+ # but in binary form, so we need to convert it to ascii the same
+ # way the old boot scripts did so it matches whats in the db
+ # (php uses bin2hex,
+ if BOOT_CD_VERSION[0] == 2:
+ read_mode= "rb"
+ else:
+ read_mode= "r"
+
+ try:
+ nonce_file= file("/tmp/nonce",read_mode)
+ nonce= nonce_file.read()
+ nonce_file.close()
+ except IOError:
+ log.write( "Unable to read nonce from /tmp/nonce\n" )
+ return 0
+
+ if BOOT_CD_VERSION[0] == 2:
+ nonce= nonce.encode('hex')
+
+ # there is this nice bug in the php that currently accepts the
+ # nonce for the old scripts, in that if the nonce contains
+ # null chars (2.x cds sent as binary), then
+ # the nonce is truncated. so, do the same here, truncate the nonce
+ # at the first null ('00'). This could leave us with an empty string.
+ nonce_len= len(nonce)
+ for byte_index in range(0,nonce_len,2):
+ if nonce[byte_index:byte_index+2] == '00':
+ nonce= nonce[:byte_index]
+ break
+ else:
+ nonce= string.strip(nonce)
+
+ log.write( "Read nonce, using as key.\n" )
+ vars['NODE_KEY']= nonce
+
+
+ # at this point, we've read the network configuration file.
+ # if we were setup using dhcp, get this system's current ip
+ # address and update the vars key ip, because it
+ # is needed for future api calls.
+
+ # at the same time, we can check to make sure that the hostname
+ # in the configuration file matches the ip address.
+
+ hostname= NETWORK_SETTINGS['hostname'] + "." + \
+ NETWORK_SETTINGS['domainname']
+
+ log.write( "Checking that hostname %s resolves\n" % hostname )
+ try:
+ resolved_node_ip= socket.gethostbyname(hostname)
+ except socket.gaierror, e:
+ raise BootManagerException, \
+ "Configured node hostname does not resolve."
+
+ if NETWORK_SETTINGS['method'] == "dhcp":
+ NETWORK_SETTINGS['ip']= resolved_node_ip
+ node_ip= resolved_node_ip
+ else:
+ node_ip= NETWORK_SETTINGS['ip']
+
+ if node_ip != resolved_node_ip:
+ log.write( "Hostname %s does not resolve to %s, but %s:\n" % \
+ (hostname,node_ip,resolved_node_ip) )
+ else:
+ log.write( "Hostname %s resolves to %s:\n" % (hostname,node_ip) )
+
+ # 3.x cds, with a node_key on the floppy, can update their mac address
+ # at plc, so get it here
+ if BOOT_CD_VERSION[0] == 3 and vars['WAS_NODE_ID_IN_CONF'] == 1:
+ eth_device= "eth0"
+ try:
+ hw_addr_file= file("/sys/class/net/%s/address" % eth_device, "r")
+ hw_addr= hw_addr_file.read().strip().upper()
+ hw_addr_file.close()
+ except IOError, e:
+ raise BootmanagerException, \
+ "could not get hw address for device %s" % eth_device
+
+ NETWORK_SETTINGS['mac']= hw_addr
+
+
+ vars["NETWORK_SETTINGS"]= NETWORK_SETTINGS
+
+ return 1
--- /dev/null
+from Exceptions import *
+
+
+def Run( vars, log ):
+
+ log.write( "\n\nStep: Sending hardware configuration to PLC.\n" )
+
+ log.write( "Not implemented, continuing.\n" )
+
+ return
--- /dev/null
+import os
+
+from Exceptions import *
+import utils
+import compatibility
+
+
+message= \
+"""
+---------------------------------------------------------
+This machine has entered a temporary debug state, so
+Planetlab Support can login and fix any problems that
+might have occurred.
+
+Please do not reboot this machine at this point, unless
+specifically asked to.
+
+Thank you.
+---------------------------------------------------------
+"""
+
+
+def Run( vars, log ):
+ """
+ Bring up sshd inside the boot cd environment for debug purposes.
+
+ Once its running, touch the file /tmp/SSHD_RUNNING so future
+ calls to this function don't do anything.
+
+ Expect the following variables in vars to be set:
+ BM_SOURCE_DIR The source dir for the boot manager sources that
+ we are currently running from
+ BOOT_CD_VERSION A tuple of the current bootcd version
+ """
+
+ log.write( "\n\nStep: Starting debug mode.\n" )
+
+ # make sure we have the variables we need
+ try:
+ BM_SOURCE_DIR= vars["BM_SOURCE_DIR"]
+ if BM_SOURCE_DIR == "":
+ raise ValueError, "BM_SOURCE_DIR"
+
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ log.write( "Starting debug environment\n" )
+
+ ssh_source_files= "%s/debug_files/" % BM_SOURCE_DIR
+ ssh_dir= "/etc/ssh/"
+ ssh_home= "/root/.ssh"
+ cancel_boot_flag= "/tmp/CANCEL_BOOT"
+ sshd_started_flag= "/tmp/SSHD_RUNNING"
+
+ sshd_started= 0
+ try:
+ os.stat(sshd_started_flag)
+ sshd_started= 1
+ except OSError, e:
+ pass
+
+ if not sshd_started:
+ log.write( "Creating ssh host keys\n" )
+
+ utils.makedirs( ssh_dir )
+ utils.sysexec( "ssh-keygen -t rsa1 -b 1024 -f %s/ssh_host_key -N ''" %
+ ssh_dir, log )
+ utils.sysexec( "ssh-keygen -t rsa -f %s/ssh_host_rsa_key -N ''" %
+ ssh_dir, log )
+ utils.sysexec( "ssh-keygen -d -f %s/ssh_host_dsa_key -N ''" %
+ ssh_dir, log )
+
+ if BOOT_CD_VERSION[0] == 3:
+ utils.sysexec( "cp -f %s/sshd_config_v3 %s/sshd_config" %
+ (ssh_source_files,ssh_dir), log )
+ else:
+ utils.sysexec( "cp -f %s/sshd_config_v2 %s/sshd_config" %
+ (ssh_source_files,ssh_dir), log )
+ else:
+ log.write( "ssh host keys already created\n" )
+
+
+ # always update the key, may have change in this instance of the bootmanager
+ log.write( "Installing debug ssh key for root user\n" )
+
+ utils.makedirs( ssh_home )
+ utils.sysexec( "cp -f %s/debug_root_ssh_key %s/authorized_keys" %
+ (ssh_source_files,ssh_home), log )
+ utils.sysexec( "chmod 700 %s" % ssh_home, log )
+ utils.sysexec( "chmod 600 %s/authorized_keys" % ssh_home, log )
+
+ if not sshd_started:
+ log.write( "Starting sshd\n" )
+
+ if BOOT_CD_VERSION[0] == 2:
+ utils.sysexec( "/usr/sbin/sshd", log )
+ else:
+ utils.sysexec( "service sshd start", log )
+
+ # flag that ssh is running
+ utils.sysexec( "touch %s" % sshd_started_flag, log )
+ else:
+ log.write( "sshd already running\n" )
+
+
+ # for ease of use, setup lvm on 2.x cds
+ if BOOT_CD_VERSION[0] == 2:
+ compatibility.setup_lvm_2x_cd(vars,log)
+
+
+ # this will make the initial script stop requesting scripts from PLC
+ utils.sysexec( "touch %s" % cancel_boot_flag, log )
+
+ print message
+
+ return
+
--- /dev/null
+from Exceptions import *
+import BootAPI
+import notify_messages
+
+
+def Run( vars, log ):
+ """
+ Change this nodes boot state at PLC.
+
+ The current value of the BOOT_STATE key in vars is used.
+ Optionally, notify the contacts of the boot state change.
+ If this is the case, the following keys/values
+ should be set in vars before calling this step:
+ STATE_CHANGE_NOTIFY= 1
+ STATE_CHANGE_NOTIFY_MESSAGE= "<notify message>"
+ The second value is a message to send the users from notify_messages.py
+
+ Return 1 if succesfull, a BootManagerException otherwise.
+ """
+
+ log.write( "\n\nStep: Updating node boot state at PLC.\n" )
+
+ update_vals= {}
+ update_vals['boot_state']= vars['BOOT_STATE']
+ BootAPI.call_api_function( vars, "BootUpdateNode", (update_vals,) )
+
+ log.write( "Successfully updated boot state for this node at PLC\n" )
+
+
+ if "STATE_CHANGE_NOTIFY" in vars.keys():
+ if vars["STATE_CHANGE_NOTIFY"] == 1:
+ message= vars['STATE_CHANGE_NOTIFY_MESSAGE']
+ include_pis= 0
+ include_techs= 1
+ include_support= 0
+
+ sent= 0
+ try:
+ sent= BootAPI.call_api_function( vars, "BootNotifyOwners",
+ (message,
+ include_pis,
+ include_techs,
+ include_support) )
+ except BootManagerException, e:
+ log.write( "Call to BootNotifyOwners failed: %s.\n" % e )
+
+ if sent == 0:
+ log.write( "Unable to notify site contacts of state change.\n" )
+
+ return 1
--- /dev/null
+import os
+
+import InstallWriteConfig
+import InstallBuildVServer
+from Exceptions import *
+import utils
+
+
+
+def Run( vars, log ):
+ """
+ Reconfigure a node if necessary, including rewriting any network init
+ scripts based on what PLC has. Also, update any slivers on the machine
+ incase their network files are out of date (primarily /etc/hosts).
+
+ This step expects the root to be already mounted on SYSIMG_PATH.
+
+ Except the following keys to be set:
+ SYSIMG_PATH the path where the system image will be mounted
+ (always starts with TEMP_PATH)
+ ROOT_MOUNTED the node root file system is mounted
+ NETWORK_SETTINGS A dictionary of the values from the network
+ configuration file
+ """
+
+ log.write( "\n\nStep: Updating node configuration.\n" )
+
+ # make sure we have the variables we need
+ try:
+ NETWORK_SETTINGS= vars["NETWORK_SETTINGS"]
+ if NETWORK_SETTINGS == "":
+ raise ValueError, "NETWORK_SETTINGS"
+
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ ROOT_MOUNTED= vars["ROOT_MOUNTED"]
+ if ROOT_MOUNTED == "":
+ raise ValueError, "ROOT_MOUNTED"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+ try:
+ ip= NETWORK_SETTINGS['ip']
+ method= NETWORK_SETTINGS['method']
+ hostname= NETWORK_SETTINGS['hostname']
+ domainname= NETWORK_SETTINGS['domainname']
+ except KeyError, var:
+ raise BootManagerException, \
+ "Missing network value %s in var NETWORK_SETTINGS\n" % var
+
+
+ if not ROOT_MOUNTED:
+ raise BootManagerException, "Root isn't mounted on SYSIMG_PATH\n"
+
+
+ log.write( "Updating node network configuration\n" )
+ InstallWriteConfig.write_network_configuration( vars, log )
+
+
+ log.write( "Updating vserver's /etc/hosts and /etc/resolv.conf files\n" )
+
+ # create a list of the full directory paths of all the vserver images that
+ # need to be updated.
+ update_path_list= []
+
+ for base_dir in ('/vservers','/vservers/.vcache'):
+ try:
+ full_dir_path= "%s/%s" % (SYSIMG_PATH,base_dir)
+ slices= os.listdir( full_dir_path )
+
+ try:
+ slices.remove("lost+found")
+ except ValueError, e:
+ pass
+
+ update_path_list= update_path_list + map(lambda x: \
+ full_dir_path+"/"+x,
+ slices)
+ except OSError, e:
+ continue
+
+
+ log.write( "Updating network configuration in:\n" )
+ if len(update_path_list) == 0:
+ log.write( "No vserver images found to update.\n" )
+ else:
+ for base_dir in update_path_list:
+ log.write( "%s\n" % base_dir )
+
+
+ # now, update /etc/hosts and /etc/resolv.conf in each dir if
+ # the update flag is there
+ for base_dir in update_path_list:
+ InstallBuildVServer.update_vserver_network_files(base_dir,vars,log)
+
+ return
--- /dev/null
+import os
+
+from Exceptions import *
+import utils
+from systeminfo import systeminfo
+import compatibility
+
+
+def Run( vars, log ):
+ """
+ See if a node installation is valid. More checks should certainly be
+ done in the future, but for now, make sure that the sym links kernel-boot
+ and initrd-boot exist in /boot
+
+ Expect the following variables to be set:
+ SYSIMG_PATH the path where the system image will be mounted
+ (always starts with TEMP_PATH)
+ BOOT_CD_VERSION A tuple of the current bootcd version
+ ROOT_MOUNTED the node root file system is mounted
+
+ Set the following variables upon successfully running:
+ ROOT_MOUNTED the node root file system is mounted
+ """
+
+ log.write( "\n\nStep: Validating node installation.\n" )
+
+ # make sure we have the variables we need
+ try:
+ BOOT_CD_VERSION= vars["BOOT_CD_VERSION"]
+ if BOOT_CD_VERSION == "":
+ raise ValueError, "BOOT_CD_VERSION"
+
+ SYSIMG_PATH= vars["SYSIMG_PATH"]
+ if SYSIMG_PATH == "":
+ raise ValueError, "SYSIMG_PATH"
+
+ except KeyError, var:
+ raise BootManagerException, "Missing variable in vars: %s\n" % var
+ except ValueError, var:
+ raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var
+
+
+ ROOT_MOUNTED= 0
+ if 'ROOT_MOUNTED' in vars.keys():
+ ROOT_MOUNTED= vars['ROOT_MOUNTED']
+
+ # old cds need extra utilities to run lvm
+ if BOOT_CD_VERSION[0] == 2:
+ compatibility.setup_lvm_2x_cd( vars, log )
+
+ # simply creating an instance of this class and listing the system
+ # block devices will make them show up so vgscan can find the planetlab
+ # volume group
+ systeminfo().get_block_device_list()
+
+ # mount the root system image if we haven't already.
+ # capture BootManagerExceptions during the vgscan/change and mount
+ # calls, so we can return 0 instead
+ if ROOT_MOUNTED == 0:
+ try:
+ utils.sysexec( "vgscan", log )
+ utils.sysexec( "vgchange -ay planetlab", log )
+ except BootManagerException, e:
+ log.write( "BootManagerException during vgscan/vgchange: %s\n" %
+ str(e) )
+ return 0
+
+ utils.makedirs( SYSIMG_PATH )
+
+ try:
+ utils.sysexec( "mount /dev/planetlab/root %s" % SYSIMG_PATH, log )
+ utils.sysexec( "mount /dev/planetlab/vservers %s/vservers" %
+ SYSIMG_PATH, log )
+ except BootManagerException, e:
+ log.write( "BootManagerException during vgscan/vgchange: %s\n" %
+ str(e) )
+ return 0
+
+ ROOT_MOUNTED= 1
+ vars['ROOT_MOUNTED']= 1
+
+ valid= 0
+
+ if os.access("%s/boot/kernel-boot" % SYSIMG_PATH, os.F_OK | os.R_OK) and \
+ os.access("%s/boot/initrd-boot" % SYSIMG_PATH, os.F_OK | os.R_OK):
+ valid= 1
+
+ if not valid:
+ log.write( "Node does not appear to be installed correctly:\n" )
+ log.write( "missing file /boot/ initrd-boot or kernel-boot\n" )
+ return 0
+
+ return 1
--- /dev/null
+"""
+This directory contains individual step classes
+"""
+
+__all__ = ["ReadNodeConfiguration",
+ "AuthenticateWithPLC",
+ "GetAndUpdateNodeDetails",
+ "ConfirmInstallWithUser",
+ "UpdateBootStateWithPLC",
+ "CheckHardwareRequirements",
+ "SendHardwareConfigToPLC",
+ "InitializeBootManager",
+ "UpdateNodeConfiguration",
+ "CheckForNewDisks",
+ "ChainBootNode",
+ "ValidateNodeInstall",
+ "StartDebug",
+ "InstallBootstrapRPM",
+ "InstallBuildVServer",
+ "InstallInit",
+ "InstallBase",
+ "InstallNodeInit",
+ "InstallPartitionDisks",
+ "InstallUninitHardware",
+ "InstallWriteConfig"]
--- /dev/null
+#!/usr/bin/python2
+
+# --------------
+# THIS file used to be named 'blockdevicescan.py', but has been renamed
+# systeminfo.py and made more generic (now includes info about memory,
+# and other hardware info on the machine)
+# --------------
+
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+# expected /proc/partitions format
+#
+#----------------------------------------------------
+#major minor #blocks name
+#
+#3 0 40017915 hda
+#3 1 208813 hda1
+#3 2 20482875 hda2
+#3 3 522112 hda3
+#3 4 18804082 hda4
+#----------------------------------------------------
+
+
+import string
+import os
+import popen2
+from merge_hw_tables import merge_hw_tables
+
+
+class systeminfo:
+ """
+ a utility class for finding and returning information about
+ block devices, memory, and other hardware on the system
+ """
+
+ PROC_MEMINFO_PATH= "/proc/meminfo"
+
+
+ PROC_PARTITIONS_PATH= "/proc/partitions"
+
+ # set when the sfdisk -l <dev> trick has been done to make
+ # all devices show up
+ DEVICES_SCANNED_FLAG= "/tmp/devices_scanned"
+
+ # a /proc/partitions block is 1024 bytes
+ # a GB to a HDD manufacturer is 10^9 bytes
+ BLOCKS_PER_GB = pow(10, 9) / 1024.0;
+
+
+ # -n is numeric ids (no lookup), -m is machine readable
+ LSPCI_CMD= "/sbin/lspci -nm"
+
+ MODULE_CLASS_NETWORK= "network"
+ MODULE_CLASS_SCSI= "scsi"
+
+ PCI_CLASS_NETWORK= "0200"
+ PCI_CLASS_RAID= "0104"
+ PCI_CLASS_RAID2= "0100"
+
+
+ def get_total_phsyical_mem(self):
+ """
+ return the total physical memory of the machine, in kilobytes.
+
+ Return None if /proc/meminfo not readable.
+ """
+
+ try:
+ meminfo_file= file(self.PROC_MEMINFO_PATH,"r")
+ except IOError, e:
+ return
+
+ total_memory= None
+
+ for line in meminfo_file:
+
+ try:
+ (fieldname,value)= string.split(line,":")
+ except ValueError, e:
+ # this will happen for lines that don't have two values
+ # (like the first line on 2.4 kernels)
+ continue
+
+ fieldname= string.strip(fieldname)
+ value= string.strip(value)
+
+ if fieldname == "MemTotal":
+ try:
+ (total_memory,units)= string.split(value)
+ except ValueError, e:
+ return
+
+ if total_memory == "" or total_memory == None or \
+ units == "" or units == None:
+ return
+
+ if string.lower(units) != "kb":
+ return
+
+ try:
+ total_memory= int(total_memory)
+ except ValueError, e:
+ return
+
+ break
+
+ meminfo_file.close()
+
+ return total_memory
+
+
+
+ def get_block_device_list(self):
+ """
+ get a list of block devices from this system.
+ return an associative array, where the device name
+ (full /dev/device path) is the key, and the value
+ is a tuple of (major,minor,numblocks,gb_size,readonly)
+ """
+
+ # make sure we can access to the files/directories in /proc
+ if not os.access(self.PROC_PARTITIONS_PATH, os.F_OK):
+ return None
+
+
+ # only do this once every system boot
+ if not os.access(self.DEVICES_SCANNED_FLAG, os.R_OK):
+
+ # this is ugly. under devfs, device
+ # entries in /dev/scsi/.. and /dev/ide/...
+ # don't show up until you attempt to read
+ # from the associated device at /dev (/dev/sda).
+ # so, lets run sfdisk -l (list partitions) against
+ # most possible block devices, that way they show
+ # up when it comes time to do the install.
+ for dev_prefix in ('sd','hd'):
+ block_dev_num= 0
+ while block_dev_num < 10:
+ if block_dev_num < 26:
+ devicename= "/dev/%s%c" % \
+ (dev_prefix, chr(ord('a')+block_dev_num))
+ else:
+ devicename= "/dev/%s%c%c" % \
+ ( dev_prefix,
+ chr(ord('a')+((block_dev_num/26)-1)),
+ chr(ord('a')+(block_dev_num%26)) )
+
+ os.system( "sfdisk -l %s > /dev/null 2>&1" % devicename )
+ block_dev_num = block_dev_num + 1
+
+ additional_scan_devices= ("/dev/cciss/c0d0p", "/dev/cciss/c0d1p",
+ "/dev/cciss/c0d2p", "/dev/cciss/c0d3p",
+ "/dev/cciss/c0d4p", "/dev/cciss/c0d5p",
+ "/dev/cciss/c0d6p", "/dev/cciss/c0d7p",
+ "/dev/cciss/c1d0p", "/dev/cciss/c1d1p",
+ "/dev/cciss/c1d2p", "/dev/cciss/c1d3p",
+ "/dev/cciss/c1d4p", "/dev/cciss/c1d5p",
+ "/dev/cciss/c1d6p", "/dev/cciss/c1d7p",)
+
+ for devicename in additional_scan_devices:
+ os.system( "sfdisk -l %s > /dev/null 2>&1" % devicename )
+
+ os.system( "touch %s" % self.DEVICES_SCANNED_FLAG )
+
+
+ devicelist= {}
+
+ partitions_file= file(self.PROC_PARTITIONS_PATH,"r")
+ line_count= 0
+
+ for line in partitions_file:
+ line_count= line_count + 1
+
+ # skip the first two lines always
+ if line_count < 2:
+ continue
+
+ parts= string.split(line)
+
+ if len(parts) < 4:
+ continue
+
+ device= parts[3]
+
+ # if the last char in device is a number, its
+ # a partition, and we ignore it
+
+ if device[len(device)-1].isdigit():
+ continue
+
+ dev_name= "/dev/%s" % device
+
+ try:
+ major= int(parts[0])
+ minor= int(parts[1])
+ blocks= int(parts[2])
+ except ValueError, err:
+ continue
+
+ gb_size= blocks/self.BLOCKS_PER_GB
+
+ # parse the output of hdparm <disk> to get the readonly flag;
+ # if this fails, assume it isn't read only
+ readonly= 0
+
+ hdparm_cmd = popen2.Popen3("hdparm %s 2> /dev/null" % dev_name)
+ status= hdparm_cmd.wait()
+
+ if os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0:
+ try:
+ hdparm_output= hdparm_cmd.fromchild.read()
+ hdparm_cmd= None
+
+ # parse the output of hdparm, the lines we are interested
+ # in look
+ # like:
+ #
+ # readonly = 0 (off)
+ #
+
+ for line in string.split(hdparm_output,"\n"):
+
+ line= string.strip(line)
+ if line == "":
+ continue
+
+ line_parts= string.split(line,"=")
+ if len(line_parts) < 2:
+ continue
+
+ name= string.strip(line_parts[0])
+
+ if name == "readonly":
+ value= string.strip(line_parts[1])
+ if len(value) == 0:
+ break
+
+ if value[0] == "1":
+ readonly= 1
+ break
+
+ except IOError:
+ pass
+
+ devicelist[dev_name]= (major,minor,blocks,gb_size,readonly)
+
+
+ return devicelist
+
+
+
+ def get_system_modules( self, install_root ):
+ """
+ Return a list of kernel modules that this system requires.
+ This requires access to the installed system's root
+ directory, as the following files must exist and are used:
+ <install_root>/usr/share/hwdata/pcitable
+ <install_root>/lib/modules/(first entry)/modules.pcimap
+ <install_root>/lib/modules/(first entry)/modules.dep
+
+ Note, that this assumes there is only one kernel
+ that is installed. If there are more than one, then
+ only the first one in a directory listing is used.
+
+ Returns a dictionary, keys being the type of module:
+ - scsi MODULE_CLASS_SCSI
+ - network MODULE_CLASS_NETWORK
+ The value being the kernel module name to load.
+ """
+
+ # get the kernel version we are assuming
+ try:
+ kernel_version= os.listdir( "%s/lib/modules/" % install_root )
+ except OSError, e:
+ return
+
+ if len(kernel_version) == 0:
+ return
+
+ if len(kernel_version) > 1:
+ print( "WARNING: We may be returning modules for the wrong kernel." )
+
+ kernel_version= kernel_version[0]
+ print( "Using kernel version %s" % kernel_version )
+
+ # test to make sure the three files we need are present
+ pcitable_path = "%s/usr/share/hwdata/pcitable" % install_root
+ modules_pcimap_path = "%s/lib/modules/%s/modules.pcimap" % \
+ (install_root,kernel_version)
+ modules_dep_path = "%s/lib/modules/%s/modules.dep" % \
+ (install_root,kernel_version)
+
+ for path in (pcitable_path,modules_pcimap_path,modules_dep_path):
+ if not os.access(path,os.R_OK):
+ print( "Unable to read %s" % path )
+ return
+
+ # now, with those three files, merge them all into one easy to
+ # use lookup table
+ all_modules= merge_hw_tables().merge_files( modules_dep_path,
+ modules_pcimap_path,
+ pcitable_path )
+
+ if all_modules is None:
+ print( "Unable to merge pci id tables." )
+ return
+
+
+ # this is the actual data structure we return
+ system_mods= {}
+
+ # these are the lists that will be in system_mods
+ network_mods= []
+ scsi_mods= []
+
+
+ # get all the system devices from lspci
+ lspci_prog= popen2.Popen3( self.LSPCI_CMD, 1 )
+ if lspci_prog is None:
+ print( "Unable to run %s with popen2.Popen3" % self.LSPCI_CMD )
+ return
+
+ returncode= lspci_prog.wait()
+ if returncode != 0:
+ print( "Running %s failed" % self.LSPCI_CMD )
+ return
+ else:
+ print( "Successfully ran %s" % self.LSPCI_CMD )
+
+ for line in lspci_prog.fromchild:
+ if string.strip(line) == "":
+ continue
+
+ parts= string.split(line)
+
+ try:
+ classid= self.remove_quotes(parts[2])
+ vendorid= self.remove_quotes(parts[3])
+ deviceid= self.remove_quotes(parts[4])
+ except IndexError:
+ print( "Skipping invalid line:", string.strip(line) )
+ continue
+
+ if classid not in (self.PCI_CLASS_NETWORK,
+ self.PCI_CLASS_RAID,
+ self.PCI_CLASS_RAID2):
+ continue
+
+ full_deviceid= "%s:%s" % (vendorid,deviceid)
+
+ for module in all_modules.keys():
+ if full_deviceid in all_modules[module]:
+ if classid == self.PCI_CLASS_NETWORK:
+ network_mods.append(module)
+ elif classid in (self.PCI_CLASS_RAID,
+ self.PCI_CLASS_RAID2):
+ scsi_mods.append(module)
+
+ system_mods[self.MODULE_CLASS_SCSI]= scsi_mods
+ system_mods[self.MODULE_CLASS_NETWORK]= network_mods
+
+ return system_mods
+
+
+ def remove_quotes( self, str ):
+ """
+ remove double quotes off of a string if they exist
+ """
+ if str == "" or str == None:
+ return str
+ if str[:1] == '"':
+ str= str[1:]
+ if str[len(str)-1] == '"':
+ str= str[:len(str)-1]
+ return str
+
+
+
+if __name__ == "__main__":
+ info= systeminfo()
+
+ devices= info.get_block_device_list()
+ print "block devices detected:"
+ if not devices:
+ print "no devices found!"
+ else:
+ for dev in devices.keys():
+ print "%s %s" % (dev, repr(devices[dev]))
+
+
+ print ""
+ memory= info.get_total_phsyical_mem()
+ if not memory:
+ print "unable to read /proc/meminfo for memory"
+ else:
+ print "total physical memory: %d kb" % memory
+
+
+ print ""
+ modules= info.get_system_modules("/")
+ if not modules:
+ print "unable to list system modules"
+ else:
+ for type in modules:
+ if type == info.MODULE_CLASS_SCSI:
+ print( "all scsi modules:" )
+ for a_mod in modules[type]:
+ print a_mod
+ elif type == info.MODULE_CLASS_NETWORK:
+ print( "all network modules:" )
+ for a_mod in modules[type]:
+ print a_mod
+
--- /dev/null
+# Copyright (c) 2003 Intel Corporation
+# All rights reserved.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF
+# YOUR JURISDICTION. It is licensee's responsibility to comply with any
+# export regulations applicable in licensee's jurisdiction. Under
+# CURRENT (May 2000) U.S. export regulations this software is eligible
+# for export from the U.S. and can be downloaded by or otherwise
+# exported or reexported worldwide EXCEPT to U.S. embargoed destinations
+# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan,
+# Afghanistan and any other country to which the U.S. has embargoed
+# goods and services.
+
+
+import os, sys, shutil
+import popen2
+
+from Exceptions import *
+
+
+def makedirs( path ):
+ """
+ from python docs for os.makedirs:
+ Throws an error exception if the leaf directory
+ already exists or cannot be created.
+
+ That is real useful. Instead, we'll create the directory, then use a
+ separate function to test for its existance.
+
+ Return 1 if the directory exists and/or has been created, a BootManagerException
+ otherwise. Does not test the writability of said directory.
+ """
+ try:
+ os.makedirs( path )
+ except OSError:
+ pass
+ try:
+ os.listdir( path )
+ except OSError:
+ raise BootManagerException, "Unable to create directory tree: %s" % path
+
+ return 1
+
+
+
+def removedir( path ):
+ """
+ remove a directory tree, return 1 if successful, a BootManagerException
+ if failure.
+ """
+ try:
+ os.listdir( path )
+ except OSError:
+ return 1
+
+ try:
+ shutil.rmtree( path )
+ except OSError, desc:
+ raise BootManagerException, "Unable to remove directory tree: %s" % path
+
+ return 1
+
+
+
+def sysexec( cmd, log= None ):
+ """
+ execute a system command, output the results to the logger
+ if log <> None
+
+ return 1 if command completed (return code of non-zero),
+ 0 if failed. A BootManagerException is raised if the command
+ was unable to execute or was interrupted by the user with Ctrl+C
+ """
+ prog= popen2.Popen4( cmd, 0 )
+ if prog is None:
+ raise BootManagerException, \
+ "Unable to create instance of popen2.Popen3 " \
+ "for command: %s" % cmd
+
+ if log is not None:
+ try:
+ for line in prog.fromchild:
+ log.write( line )
+ except KeyboardInterrupt:
+ raise BootManagerException, "Interrupted by user"
+
+ returncode= prog.wait()
+ if returncode != 0:
+ raise BootManagerException, "Running %s failed (rc=%d)" % (cmd,returncode)
+
+ prog= None
+ return 1
+
+
+def sysexec_noerr( cmd, log= None ):
+ """
+ same as sysexec, but capture boot manager exceptions
+ """
+ try:
+ rc= 0
+ rc= sysexec( cmd, log )
+ except BootManagerException, e:
+ pass
+
+ return rc
+
+
+
+def chdir( dir ):
+ """
+ change to a directory, return 1 if successful, a BootManagerException if failure
+ """
+ try:
+ os.chdir( dir )
+ except OSError:
+ raise BootManagerException, "Unable to change to directory: %s" % dir
+
+ return 1
+
+
+
+def removefile( filepath ):
+ """
+ removes a file, return 1 if successful, 0 if failure
+ """
+ try:
+ os.remove( filepath )
+ except OSError:
+ raise BootManagerException, "Unable to remove file: %s" % filepath
+
+ return 1
+