13 from qa.Nodes import Node, Nodes
15 image_types = ['node-iso', 'node-usb', 'generic-iso', 'generic-usb']
19 os.kill(pid, signal.SIGKILL)
20 os.waitpid(pid,os.WNOHANG)
24 class boot_node(Test):
26 Attempts to boot the specified node using qemu.
29 def state_nanny(self):
30 hostname = self.hostname
31 nodes = self.config.api.GetNodes(self.config.auth, [hostname], ['boot_state'])
33 boot_state = node['boot_state']
34 if True or self.config.verbose:
35 utils.header("%(hostname)s boot_state is %(boot_state)s" % locals(), False, self.config.logfile)
37 if boot_state in ['boot']:
40 if self.config.verbose:
41 if boot_state in ['boot']:
42 utils.header("%(hostname)s correctly installed and booted" % locals(), False, self.config.logfile)
44 utils.header("%(hostname)s not fully booted" % locals(), False, self.config.logfile)
45 self.boot_state = boot_state
48 def console_nanny(self,console_states):
49 #ready = select.select([],[self.stdout],[],1)[1]
51 if True or len(ready)>0:
56 lines = self.stdout.readlines()
61 #for searchstring in console_states.keys():
62 # result = line.find(searchstring)
63 # if result... ret = console_states[searchstring]
65 # check result for whether we found it
67 # for now just print it out
70 utils.header(line, logfile = self.config.logfile)
71 # should be parsing for special strings that indicate whether
72 # we've reached a particular state within the boot sequence
76 def call(self, plc_name, hostname, image_type = 'node-iso', disk_size="17G", wait = 30):
79 # Get this nodes configuration
80 node = self.config.get_node(hostname)
83 # Which plc does this node talk to
84 plc = self.config.get_plc(plc_name)
86 auth = plc.config.auth
87 path = node.get_path()
89 homedir = node['homedir']
91 bootimage_filename = "%(hostname)s-bootcd.iso" % locals()
92 diskimage_filename = "%(hostname)s-hda.img" % locals()
93 bootimage = "%(homedir)s/%(bootimage_filename)s" % locals()
94 diskimage = "%(homedir)s/%(diskimage_filename)s" % locals()
97 diskimage_path = "/%(path)s/%(diskimage)s" % locals()
98 bootimage_tmppath = "%(tmpdir)s/%(bootimage_filename)s" % locals()
99 bootimage_path = "/%(path)s/%(bootimage)s" % locals()
100 remote_bootimage_path = "%(homedir)s/%(bootimage_filename)s" % locals()
103 print remote_bootimage_path
104 # wait up to 30 minutes for a node to boot and install itself correctly
105 self.hostname = hostname
106 self.totaltime = 60*60*wait
109 nodes = api.GetNodes(auth, [hostname], ['hostname', 'boot_state'])
111 raise Exception, "%s not found at plc %s" % (hostname, plc['name'])
112 node.update(nodes[0])
114 # try reinstalling the node if it is in debug state
115 if node['boot_state'] in ['dbg']:
116 if self.config.verbose:
117 utils.header("%(hostname)s is in debug state. Attempting a re-install" % locals(), logfile = self.config.logfile)
118 api.UpdateNode(auth, node['hostname'], {'boot_state': 'rins'})
121 if self.config.verbose:
122 utils.header("Creating bootcd for %(hostname)s at %(bootimage_path)s" % locals(), logfile = self.config.logfile)
123 nodeimage = api.GetBootMedium(auth, hostname, image_type, '', ['serial'])
124 fp = open(bootimage_tmppath, 'w')
125 fp.write(base64.b64decode(nodeimage))
128 # Move the boot image to the nodes home directory
129 node.host_commands("mkdir -p %(homedir)s" % locals())
130 node.scp_to_host(bootimage_tmppath, "%(remote_bootimage_path)s" % locals())
132 # If node is vm (qemu) try installing kqemu
133 #node.host_commands("yum -y install kqemu", False)
134 #node.host_commands("modprobe kqemu", False)
136 # Create a temporary disk image if it doesnt already exist or we are reinstalling
137 img_check_cmd = "ls -ld %(diskimage)s" % locals()
138 (status, output) = node.host_commands(img_check_cmd, False)
139 if status != 0 or node['boot_state'] in ['rins', 'inst']:
140 qemu_img_cmd = "/usr/bin/qemu-img create -f qcow2 %(diskimage)s %(disk_size)s" % locals()
141 node.host_commands(qemu_img_cmd)
144 if self.config.verbose:
145 utils.header("Booting %(hostname)s" % locals(), logfile = self.config.logfile)
147 # Attempt to boot this node image
149 # generate a temp filename to which qemu should store its pid (crappy approach)
150 tmp = tempfile.mkstemp(".pid","qemu_")
155 # boot node with ramsize memory
158 # always use the 64 bit version of qemu, as this will work on both 32 & 64 bit host kernels
159 bootcmd = "/usr/bin/qemu-system-x86_64"
160 # tell qemu to store its pid ina file
161 bootcmd = bootcmd + " -pidfile %(pidfile)s " % locals()
162 # boot with ramsize memory
163 bootcmd = bootcmd + " -m %(ramsize)s" % locals()
165 bootcmd = bootcmd + " -smp 1"
166 # redirect incomming tcp connections on specified port to guest node
167 if 'redir_ssh_port' in node and node['redir_ssh_port']:
168 port = node['redir_ssh_port']
169 ip = node['nodenetworks'][0]['ip']
170 bootcmd = bootcmd + " -redir tcp:%(port)s:%(ip)s:22" % locals()
171 # no graphics support -> assume we are booting via serial console
172 bootcmd = bootcmd + " -nographic"
173 # boot from the supplied cdrom iso file
174 bootcmd = bootcmd + " -boot d"
175 bootcmd = bootcmd + " -cdrom %(bootimage)s" % locals()
176 # hard disk image to use for the node
177 bootcmd = bootcmd + " %(diskimage)s" % locals()
178 # redirect stdout, stderr to logfile
179 bootcmd = bootcmd + " 2>&1 >> %s " % (node.logfile.filename)
181 # kill any old qemu processes for this node
182 pid_cmd = "ps -elfy | grep qemu | grep -v grep | grep %(hostname)s | awk '{print$3}'" % locals()
183 (status, output) = node.host_commands(pid_cmd)
184 pids = " ".join(output.split("\n")).strip()
186 kill_cmd = "kill %(pids)s" % locals()
187 (status, output) = node.host_commands(kill_cmd)
192 (self.stdin, self.stdout, self.stderr) = node.host_popen3(bootcmd)
194 # wait for qemu to start up
196 # get qemu's pid from its pidfile (crappy approach)
197 pid_cmd = "cat %(pidfile)s" % locals()
198 (staus, output) = node.host_commands(pid_cmd)
199 self.pid = output.strip()
206 # loop until the node is either fully booted, some error
207 # occured, or we've reached our totaltime out
208 def catch(sig, frame):
209 self.totaltime = self.totaltime -1
210 utils.header("beep %d\n" %self.totaltime, False, logfile = self.config.logfile )
211 total = self.totaltime
213 (((total % 60)==0) and self.state_nanny()):
220 signal.signal(signal.SIGALRM, catch)
224 #console_states = {"login:":1}
228 # self.console_nanny(console_states)
229 #except: # need a better way to catch exceptions
230 # traceback.print_exc()
240 if __name__ == '__main__':
241 args = tuple(sys.argv[1:])