Repository: cloudstack Updated Branches: refs/heads/4.3-forward c03fd70ed -> c1806bd87
CLOUDSTACK-6155 Baremetal agent RPM missing in spec file Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/c1806bd8 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/c1806bd8 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/c1806bd8 Branch: refs/heads/4.3-forward Commit: c1806bd873fe661756aeee94b25339c25f9724a5 Parents: c03fd70 Author: Frank.Zhang <frank.zh...@citrix.com> Authored: Fri Feb 21 13:22:55 2014 -0800 Committer: Frank.Zhang <frank.zh...@citrix.com> Committed: Fri Feb 21 13:22:55 2014 -0800 ---------------------------------------------------------------------- setup/bindir/cloud-setup-baremetal.in | 232 +++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/c1806bd8/setup/bindir/cloud-setup-baremetal.in ---------------------------------------------------------------------- diff --git a/setup/bindir/cloud-setup-baremetal.in b/setup/bindir/cloud-setup-baremetal.in new file mode 100644 index 0000000..367e389 --- /dev/null +++ b/setup/bindir/cloud-setup-baremetal.in @@ -0,0 +1,232 @@ +#!/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 + +def prepareSyslinux(tftpRootDir): + pkg = bash('rpm -ql syslinux | grep "/pxelinux.0$"') + if not pkg.isSuccess(): + printError('cannot find pxelinux.0 on system. is syslinux installed?') + return False + + pkg = pkg.getStdout() + cp = "cp -f %s %s" % (pkg, tftpRootDir) + if not bashWithResult(cp): + 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)) + exitIfFail(prepareSyslinux(tftpRootDir)) + printMsg("") + printMsg("Setup BareMetal PXE server successfully") + printMsg("TFTP root directory is: %s\n"%tftpRootDir) + sys.exit(0) +