mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-11-04 00:02:37 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			218 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/python
 | 
						|
# Licensed to the Apache Software Foundation (ASF) under one
 | 
						|
# or more contributor license agreements.  See the NOTICE file
 | 
						|
# distributed with this work for additional information
 | 
						|
# regarding copyright ownership.  The ASF licenses this file
 | 
						|
# to you under the Apache License, Version 2.0 (the
 | 
						|
# "License"); you may not use this file except in compliance
 | 
						|
# with the License.  You may obtain a copy of the License at
 | 
						|
# 
 | 
						|
#   http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
# 
 | 
						|
# Unless required by applicable law or agreed to in writing,
 | 
						|
# software distributed under the License is distributed on an
 | 
						|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 | 
						|
# KIND, either express or implied.  See the License for the
 | 
						|
# specific language governing permissions and limitations
 | 
						|
# under the License.
 | 
						|
 | 
						|
import sys, os
 | 
						|
from subprocess import PIPE, Popen
 | 
						|
import logging
 | 
						|
import traceback
 | 
						|
from os.path import exists, join
 | 
						|
from signal import alarm, signal, SIGALRM, SIGKILL
 | 
						|
 | 
						|
class CloudRuntimeException(Exception):
 | 
						|
    def __init__(self, errMsg):
 | 
						|
        self.errMsg = errMsg
 | 
						|
    def __str__(self):
 | 
						|
        return self.errMsg
 | 
						|
def formatExceptionInfo(maxTBlevel=5):
 | 
						|
    cla, exc, trbk = sys.exc_info()
 | 
						|
    excTb = traceback.format_tb(trbk, maxTBlevel)
 | 
						|
    msg = str(exc) + "\n"
 | 
						|
    for tb in excTb:
 | 
						|
        msg += tb
 | 
						|
    return msg
 | 
						|
 | 
						|
class bash:
 | 
						|
    def __init__(self, args, timeout=600):
 | 
						|
        self.args = args
 | 
						|
        logging.debug("execute:%s"%args)
 | 
						|
        self.timeout = timeout
 | 
						|
        self.process = None
 | 
						|
        self.success = False
 | 
						|
        self.run()
 | 
						|
 | 
						|
    def run(self):
 | 
						|
        class Alarm(Exception):
 | 
						|
            pass
 | 
						|
        def alarm_handler(signum, frame):
 | 
						|
            raise Alarm
 | 
						|
 | 
						|
        try:
 | 
						|
            self.process = Popen(self.args, shell=True, stdout=PIPE, stderr=PIPE)
 | 
						|
            if self.timeout != -1:
 | 
						|
                signal(SIGALRM, alarm_handler)
 | 
						|
                alarm(self.timeout)
 | 
						|
 | 
						|
            try:
 | 
						|
                self.stdout, self.stderr = self.process.communicate()
 | 
						|
                if self.timeout != -1:
 | 
						|
                    alarm(0)
 | 
						|
            except Alarm:
 | 
						|
                os.kill(self.process.pid, SIGKILL)
 | 
						|
                raise  CloudRuntimeException("Timeout during command execution")
 | 
						|
 | 
						|
            self.success = self.process.returncode == 0
 | 
						|
        except:
 | 
						|
            raise  CloudRuntimeException(formatExceptionInfo())
 | 
						|
 | 
						|
#        if not self.success: 
 | 
						|
#            raise  CloudRuntimeException(self.getStderr())
 | 
						|
 | 
						|
    def isSuccess(self):
 | 
						|
        return self.success
 | 
						|
    
 | 
						|
    def getStdout(self):
 | 
						|
        return self.stdout.strip("\n")
 | 
						|
    
 | 
						|
    def getLines(self):
 | 
						|
        return self.stdout.split("\n")
 | 
						|
 | 
						|
    def getStderr(self):
 | 
						|
        return self.stderr.strip("\n")
 | 
						|
 | 
						|
 | 
						|
def initLoging(logFile=None):
 | 
						|
    try:
 | 
						|
        if logFile is None:
 | 
						|
            logging.basicConfig(level=logging.DEBUG) 
 | 
						|
        else: 
 | 
						|
            logging.basicConfig(filename=logFile, level=logging.DEBUG) 
 | 
						|
    except:
 | 
						|
        logging.basicConfig(level=logging.DEBUG) 
 | 
						|
 | 
						|
def writeProgressBar(msg, result=None):    
 | 
						|
    if msg is not None:
 | 
						|
        output = "%-80s"%msg
 | 
						|
    elif result is True:
 | 
						|
        output = "[ \033[92m%-2s\033[0m ]\n"%"OK"
 | 
						|
    elif result is False:
 | 
						|
        output = "[ \033[91m%-6s\033[0m ]\n"%"FAILED"
 | 
						|
    sys.stdout.write(output)
 | 
						|
    sys.stdout.flush()
 | 
						|
    
 | 
						|
def printError(msg):
 | 
						|
    sys.stderr.write(msg)
 | 
						|
    sys.stderr.write("\n")
 | 
						|
    sys.stderr.flush()
 | 
						|
 | 
						|
def printMsg(msg):
 | 
						|
    sys.stdout.write(msg+"\n")
 | 
						|
    sys.stdout.flush()
 | 
						|
 | 
						|
def checkRpm(pkgName):
 | 
						|
    chkPkg = bash("rpm -q %s"%pkgName)
 | 
						|
    writeProgressBar("Checking %s"%pkgName, None)
 | 
						|
    if not chkPkg.isSuccess():
 | 
						|
        writeProgressBar(None, False)
 | 
						|
        printError("%s is not found, please make sure it is installed. You may try 'yum install %s'\n"%(pkgName, pkgName))
 | 
						|
        return False
 | 
						|
    else:
 | 
						|
        writeProgressBar(None, True)
 | 
						|
        return True
 | 
						|
      
 | 
						|
def checkEnv():
 | 
						|
   writeProgressBar("Checking is root")
 | 
						|
   ret = bash("whoami")
 | 
						|
   if ret.getStdout() != "root":
 | 
						|
       writeProgressBar(None, False)
 | 
						|
       printError("This script must run as root")
 | 
						|
       return False
 | 
						|
   else:
 | 
						|
       writeProgressBar(None, True)
 | 
						|
       
 | 
						|
   pkgList = ['tftp-server', 'syslinux', 'xinetd', 'chkconfig', 'dhcp']
 | 
						|
   for pkg in pkgList:
 | 
						|
       if not checkRpm(pkg):
 | 
						|
           return False
 | 
						|
   return True
 | 
						|
 | 
						|
def exitIfFail(ret):
 | 
						|
    if not ret: sys.exit(1) 
 | 
						|
    
 | 
						|
def bashWithResult(cmd):
 | 
						|
    writeProgressBar("Executing '%s'"%cmd)
 | 
						|
    ret = bash(cmd)
 | 
						|
    if not ret.isSuccess():
 | 
						|
        writeProgressBar(None, False)
 | 
						|
        writeProgressBar(ret.getStderr() + '\n')
 | 
						|
        return False
 | 
						|
    else:
 | 
						|
        writeProgressBar(None, True)
 | 
						|
        return True
 | 
						|
    
 | 
						|
def configurePxeStuff(): 
 | 
						|
    stuff = ['tftp', 'xinetd', 'dhcpd']
 | 
						|
    cmds = ['chkconfig --level 345 %s on' % i for i in stuff]
 | 
						|
    cmds.append('/etc/init.d/xinetd restart')
 | 
						|
    
 | 
						|
    for cmd in cmds:
 | 
						|
        if not bashWithResult(cmd): return False
 | 
						|
        
 | 
						|
    chkIptable = bash('chkconfig --list iptables')
 | 
						|
    if 'on' in chkIptable.getStdout():
 | 
						|
        printMsg("Detected iptables is running, need to open tftp port 69")
 | 
						|
        if not bashWithResult('iptables -I INPUT 1 -p udp --dport 69 -j ACCEPT'): return False
 | 
						|
        if not bashWithResult('/etc/init.d/iptables save'): return False
 | 
						|
        
 | 
						|
    return True  
 | 
						|
    
 | 
						|
def getTftpRootDir(tftpRootDirList):
 | 
						|
    tftpRoot = bash("cat /etc/xinetd.d/tftp | grep server_args")
 | 
						|
    if not tftpRoot.isSuccess():
 | 
						|
        printError("Cannot get tftp root directory from /etc/xinetd.d/tftp, here may be something wrong with your tftp-server, try reinstall it\n")
 | 
						|
        return False
 | 
						|
    tftpRootDir = tftpRoot.getStdout()
 | 
						|
    index = tftpRootDir.find("/")
 | 
						|
    if index == -1:
 | 
						|
        printError("Wrong server_arg in /etc/xinetd.d/tftp (%s)"%tftpRootDir)
 | 
						|
        return False
 | 
						|
    tftpRootDir = tftpRootDir[index:]
 | 
						|
    tftpRootDirList.append(tftpRootDir)
 | 
						|
    return True
 | 
						|
 | 
						|
def preparePING(tftpRootDir):
 | 
						|
    pingFiles = ['boot.msg', 'initrd.gz', 'kernel', 'pxelinux.0']
 | 
						|
    pingDir = "/usr/share/PING"
 | 
						|
    
 | 
						|
    for f in pingFiles:
 | 
						|
        path = join(pingDir, f)
 | 
						|
        if not exists(path):
 | 
						|
            printError("Cannot find %s, please make sure PING-3.01 is installed"%path)
 | 
						|
            return False
 | 
						|
        if not bashWithResult("cp -f %s %s"%(path, tftpRootDir)): return False
 | 
						|
     
 | 
						|
    if not bashWithResult("mkdir -p %s/pxelinux.cfg"%tftpRootDir): return False
 | 
						|
    
 | 
						|
    return True
 | 
						|
            
 | 
						|
        
 | 
						|
if __name__ == "__main__":
 | 
						|
    initLoging("/tmp/cloud-setup-baremetal.log")
 | 
						|
    tftpRootDirList = []
 | 
						|
    
 | 
						|
    exitIfFail(checkEnv())
 | 
						|
    exitIfFail(configurePxeStuff())
 | 
						|
    exitIfFail(getTftpRootDir(tftpRootDirList))
 | 
						|
    
 | 
						|
    tftpRootDir = tftpRootDirList[0].strip()
 | 
						|
    exitIfFail(preparePING(tftpRootDir))
 | 
						|
    printMsg("")
 | 
						|
    printMsg("Setup BareMetal PXE server successfully")
 | 
						|
    printMsg("TFTP root directory is: %s\n"%tftpRootDir)
 | 
						|
    sys.exit(0)
 | 
						|
    
 |