Skip to content

Commit 8d81d1c

Browse files
committed
Bug 8208 - bare metal provisioning
new package baremetal agent
1 parent b56c82e commit 8d81d1c

2 files changed

Lines changed: 223 additions & 0 deletions

File tree

cloud.spec

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,18 @@ Requires: %{name}-daemonize
222222
Requires: /sbin/service
223223
Requires: /sbin/chkconfig
224224

225+
%package baremetal-agent
226+
Summary: Cloud.com baremetal agent
227+
Requires: PING
228+
Requires: tftp-server
229+
Requires: xinetd
230+
Requires: syslinux
231+
Requires: chkconfig
232+
Requires: dhcp
233+
Group: System Environment/Libraries
234+
%description baremetal-agent
235+
The Cloud.com baremetal agent
236+
225237
%if 0%{?rhel} >= 6
226238
Requires: cloud-kvm
227239
%else
@@ -591,6 +603,9 @@ fi
591603
%{_prefix}/lib*/python*/site-packages/%{name}tool/*
592604
%{_prefix}/lib*/python*/site-packages/%{name}apis.py
593605

606+
%files baremetal-agent
607+
%attr(0755,root,root) %{_bindir}/cloud-setup-baremetal
608+
594609
%if %{_premium}
595610

596611
%files test
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
#
2+
# Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
3+
#
4+
# This software is licensed under the GNU General Public License v3 or later.
5+
#
6+
# It is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or any later version.
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
#
17+
18+
#!/usr/bin/python
19+
import sys, os
20+
from subprocess import PIPE, Popen
21+
import logging
22+
import traceback
23+
from os.path import exists, join
24+
from signal import alarm, signal, SIGALRM, SIGKILL
25+
26+
class CloudRuntimeException(Exception):
27+
def __init__(self, errMsg):
28+
self.errMsg = errMsg
29+
def __str__(self):
30+
return self.errMsg
31+
def formatExceptionInfo(maxTBlevel=5):
32+
cla, exc, trbk = sys.exc_info()
33+
excTb = traceback.format_tb(trbk, maxTBlevel)
34+
msg = str(exc) + "\n"
35+
for tb in excTb:
36+
msg += tb
37+
return msg
38+
39+
class bash:
40+
def __init__(self, args, timeout=600):
41+
self.args = args
42+
logging.debug("execute:%s"%args)
43+
self.timeout = timeout
44+
self.process = None
45+
self.success = False
46+
self.run()
47+
48+
def run(self):
49+
class Alarm(Exception):
50+
pass
51+
def alarm_handler(signum, frame):
52+
raise Alarm
53+
54+
try:
55+
self.process = Popen(self.args, shell=True, stdout=PIPE, stderr=PIPE)
56+
if self.timeout != -1:
57+
signal(SIGALRM, alarm_handler)
58+
alarm(self.timeout)
59+
60+
try:
61+
self.stdout, self.stderr = self.process.communicate()
62+
if self.timeout != -1:
63+
alarm(0)
64+
except Alarm:
65+
os.kill(self.process.pid, SIGKILL)
66+
raise CloudRuntimeException("Timeout during command execution")
67+
68+
self.success = self.process.returncode == 0
69+
except:
70+
raise CloudRuntimeException(formatExceptionInfo())
71+
72+
# if not self.success:
73+
# raise CloudRuntimeException(self.getStderr())
74+
75+
def isSuccess(self):
76+
return self.success
77+
78+
def getStdout(self):
79+
return self.stdout.strip("\n")
80+
81+
def getLines(self):
82+
return self.stdout.split("\n")
83+
84+
def getStderr(self):
85+
return self.stderr.strip("\n")
86+
87+
88+
def initLoging(logFile=None):
89+
try:
90+
if logFile is None:
91+
logging.basicConfig(level=logging.DEBUG)
92+
else:
93+
logging.basicConfig(filename=logFile, level=logging.DEBUG)
94+
except:
95+
logging.basicConfig(level=logging.DEBUG)
96+
97+
def writeProgressBar(msg, result=None):
98+
if msg is not None:
99+
output = "%-80s"%msg
100+
elif result is True:
101+
output = "[%-2s]\n"%"OK"
102+
elif result is False:
103+
output = "[%-6s]\n"%"Failed"
104+
sys.stdout.write(output)
105+
sys.stdout.flush()
106+
107+
def printError(msg):
108+
sys.stderr.write(msg)
109+
sys.stderr.write("\n")
110+
sys.stderr.flush()
111+
112+
def checkRpm(pkgName):
113+
chkPkg = bash("rpm -q %s"%pkgName)
114+
writeProgressBar("Checking %s"%pkgName, None)
115+
if not chkPkg.isSuccess():
116+
writeProgressBar(None, False)
117+
printError("%s is not found, please make sure it is installed. You may try 'yum install %s'\n"%(pkgName, pkgName))
118+
return False
119+
else:
120+
writeProgressBar(None, True)
121+
return True
122+
123+
def checkEnv():
124+
writeProgressBar("Checking is root")
125+
ret = bash("whoami")
126+
if ret.getStdout() != "root":
127+
writeProgressBar(None, False)
128+
printError("This script must run as root")
129+
return False
130+
else:
131+
writeProgressBar(None, True)
132+
133+
pkgList = ['tftp-server', 'syslinux', 'xinetd', 'chkconfig', 'dhcp']
134+
for pkg in pkgList:
135+
if not checkRpm(pkg):
136+
return False
137+
return True
138+
139+
def exitIfFail(ret):
140+
if not ret: sys.exit(1)
141+
142+
def bashWithResult(cmd):
143+
writeProgressBar("Executing '%s'"%cmd)
144+
ret = bash(cmd)
145+
if not ret.isSuccess():
146+
writeProgressBar(None, False)
147+
writeProgressBar(ret.getStderr() + '\n')
148+
return False
149+
else:
150+
writeProgressBar(None, True)
151+
return True
152+
153+
def configurePxeStuff():
154+
stuff = ['tftp', 'xinetd', 'dhcpd']
155+
cmds = ['chkconfig --level 345 %s on' % i for i in stuff]
156+
cmds.append('service xinetd restart')
157+
158+
for cmd in cmds:
159+
if not bashWithResult(cmd): return False
160+
return True
161+
162+
def getTftpRootDir(tftpRootDirList):
163+
tftpRoot = bash("cat /etc/xinetd.d/tftp | grep server_args")
164+
if not tftpRoot.isSuccess():
165+
printError("Cannot get tftp root directory from /etc/xinetd.d/tftp, here may be something wrong with your tftp-server, try reinstall it\n")
166+
return False
167+
tftpRootDir = tftpRoot.getStdout()
168+
index = tftpRootDir.find("/")
169+
if index == -1:
170+
printError("Wrong server_arg in /etc/xinetd.d/tftp (%s)"%tftpRootDir)
171+
return False
172+
tftpRootDir = tftpRootDir[index:]
173+
tftpRootDirList.append(tftpRootDir)
174+
return True
175+
176+
def preparePING(tftpRootDir):
177+
pingFiles = ['boot.msg', 'initrd.gz', 'kernel', 'pxelinux.0']
178+
pingDir = "/usr/share/PING"
179+
180+
for f in pingFiles:
181+
path = join(pingDir, f)
182+
if not exists(path):
183+
printError("Cannot find %s, please make sure PING-3.01 is installed"%path)
184+
return False
185+
if not bashWithResult("cp -f %s %s"%(path, tftpRootDir)): return False
186+
187+
if not bashWithResult("mkdir -p %s/pxelinux.cfg"%tftpRootDir): return False
188+
189+
return True
190+
191+
192+
if __name__ == "__main__":
193+
initLoging("/tmp/cloud-setup-baremetal.log")
194+
tftpRootDirList = []
195+
196+
exitIfFail(checkEnv())
197+
exitIfFail(configurePxeStuff())
198+
exitIfFail(getTftpRootDir(tftpRootDirList))
199+
200+
tftpRootDir = tftpRootDirList[0].strip()
201+
exitIfFail(preparePING(tftpRootDir))
202+
print ""
203+
writeProgressBar("Setup BareMetal PXE server successfully")
204+
print ""
205+
writeProgressBar("TFTP root directory is: %s\n"%tftpRootDir)
206+
print ""
207+
sys.exit(0)
208+

0 commit comments

Comments
 (0)