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)
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)
44 utils.header("%(hostname)s not fully booted" % locals(), False)
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
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)
81 # Which plc does this node talk to
82 plc = self.config.get_plc(plc_name)
84 auth = plc.config.auth
85 path = node.get_path()
87 homedir = node['homedir']
89 bootimage_filename = "%(hostname)s-bootcd.iso" % locals()
90 diskimage_filename = "%(hostname)s-hda.img" % locals()
91 bootimage = "%(homedir)s/%(bootimage_filename)s" % locals()
92 diskimage = "%(homedir)s/%(diskimage_filename)s" % locals()
93 diskimage_path = "/%(path)s/%(diskimage_filename)s" % locals()
94 bootimage_tmppath = "%(tmpdir)s/%(bootimage_filename)s" % locals()
95 bootimage_path = "%(path)s/%(bootimage_filename)s" % locals()
96 remote_bootimage_path = "%(homedir)s/%(bootimage_filename)s" % locals()
98 # wait up to 30 minutes for a node to boot and install itself correctly
99 self.hostname = hostname
100 self.totaltime = 60*60*wait
103 nodes = api.GetNodes(auth, [hostname], ['hostname', 'boot_state'])
105 raise Exception, "%s not found at plc %s" % (hostname, plc['name'])
106 node.update(nodes[0])
108 # try reinstalling the node if it is in debug state
109 if node['boot_state'] in ['dbg']:
110 if self.config.verbose:
111 utils.header("%(hostname)s is in debug state. Attempting a re-install" % locals())
112 api.UpdateNode(auth, node['node_id'], {'boot_state': 'rins'})
115 if self.config.verbose:
116 utils.header("Creating bootcd for %(hostname)s at %(bootimage_path)s" % locals())
117 nodeimage = api.GetBootMedium(auth, hostname, image_type, '', ['serial'])
118 fp = open(bootimage_tmppath, 'w')
119 fp.write(base64.b64decode(nodeimage))
122 # Move the boot image to the nodes home directory
123 node.host_commands("mkdir -p %(homedir)s" % locals())
124 node.scp_to_host(bootimage_tmppath, "%(remote_bootimage_path)s" % locals())
126 # Create a temporary disk image if it doesnt already exist or we are reinstalling
127 img_check_cmd = "ls -ld %(diskimage)s" % locals()
128 (status, output) = node.host_commands(img_check_cmd, False)
129 if status != 0 or node['boot_state'] in ['rins', 'inst']:
130 qemu_img_cmd = "qemu-img create -f qcow2 %(diskimage)s %(disk_size)s" % locals()
131 node.host_commands(qemu_img_cmd)
133 if self.config.verbose:
134 utils.header("Booting %(hostname)s" % locals())
136 # Attempt to boot this node image
138 # generate a temp filename to which qemu should store its pid (crappy approach)
139 tmp = tempfile.mkstemp(".pid","qemu_")
144 # boot node with ramsize memory
147 # always use the 64 bit version of qemu, as this will work on both 32 & 64 bit host kernels
148 bootcmd = "qemu-system-x86_64"
149 # tell qemu to store its pid ina file
150 bootcmd = bootcmd + " -pidfile %(pidfile)s " % locals()
151 # boot with ramsize memory
152 bootcmd = bootcmd + " -m %(ramsize)s" % locals()
154 bootcmd = bootcmd + " -smp 1"
155 # redirect incomming tcp connections on specified port to guest node
156 if 'redir_ssh_port' in node and node['redir_ssh_port']:
157 port = node['redir_ssh_port']
158 ip = node['nodenetworks'][0]['ip']
159 bootcmd = bootcmd + " -redir tcp:%(port)s:%(ip)s:22" % locals()
160 # no graphics support -> assume we are booting via serial console
161 bootcmd = bootcmd + " -nographic"
162 # boot from the supplied cdrom iso file
163 bootcmd = bootcmd + " -boot d"
164 bootcmd = bootcmd + " -cdrom %(bootimage)s" % locals()
165 # hard disk image to use for the node
166 bootcmd = bootcmd + " %(diskimage)s" % locals()
167 # redirect stdout, stderr to logfile
168 bootcmd = bootcmd + " 2>&1 >> %s " % (node.logfile.filename)
170 # kill any old qemu processes for this node
171 pid_cmd = "ps -elfy | grep qemu | grep %(hostname)s | awk '{print$3}'" % locals()
172 (status, output) = node.host_commands(pid_cmd)
173 pids = " ".join(output.split("\n")).strip()
175 kill_cmd = "kill %(pids)s" % locals()
176 (status, output) = node.host_commands(kill_cmd)
180 (self.stdin, self.stdout, self.stderr) = node.host_popen3(bootcmd)
182 # wait for qemu to start up
184 # get qemu's pid from its pidfile (crappy approach)
185 pid_cmd = "cat %(pidfile)s" % locals()
186 (staus, output) = node.host_commands(pid_cmd)
187 self.pid = output.strip()
194 # loop until the node is either fully booted, some error
195 # occured, or we've reached our totaltime out
196 def catch(sig, frame):
197 self.totaltime = self.totaltime -1
198 utils.header("beep %d\n" %self.totaltime, False)
199 total = self.totaltime
201 (((total % 60)==0) and self.state_nanny()):
208 signal.signal(signal.SIGALRM, catch)
212 #console_states = {"login:":1}
216 # self.console_nanny(console_states)
217 #except: # need a better way to catch exceptions
218 # traceback.print_exc()
228 if __name__ == '__main__':
229 args = tuple(sys.argv[1:])