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="10G", 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()
97 if host in ['localhost', None]:
98 remote_bootimage_path = bootimage_path
100 remote_bootimage_path = "%(host)s:%(bootimage_path)s" % locals()
102 # wait up to 30 minutes for a node to boot and install itself correctly
103 self.hostname = hostname
104 self.totaltime = 60*60*wait
107 nodes = api.GetNodes(auth, [hostname], ['hostname'])
109 raise Exception, "%s not found at plc %s" % (hostname, plc['name'])
110 node.update(nodes[0])
113 if self.config.verbose:
114 utils.header("Creating bootcd for %(hostname)s at %(bootimage_path)s" % locals())
115 nodeimage = api.GetBootMedium(auth, hostname, image_type, '', ['serial'])
116 fp = open(bootimage_tmppath, 'w')
117 fp.write(base64.b64decode(nodeimage))
120 # Move the boot image to the nodes home directory
121 node.host_commands("mkdir -p %(homedir)s" % locals())
122 node.scp(bootimage_tmppath, "%(remote_bootimage_path)s" % locals())
124 # Create a temporary disk image
125 qemu_img_cmd = "qemu-img create -f qcow2 %(diskimage)s %(disk_size)s" % locals()
126 node.host_commands(qemu_img_cmd)
128 if self.config.verbose:
129 utils.header("Booting %(hostname)s" % locals())
131 # Attempt to boot this node image
133 # generate a temp filename to which qemu should store its pid (crappy approach)
134 tmp = tempfile.mkstemp(".pid","qemu_")
139 # boot node with ramsize memory
142 # always use the 64 bit version of qemu, as this will work on both 32 & 64 bit host kernels
143 bootcmd = "qemu-system-x86_64"
144 # tell qemu to store its pid ina file
145 bootcmd = bootcmd + " -pidfile %(pidfile)s " % locals()
146 # boot with ramsize memory
147 bootcmd = bootcmd + " -m %(ramsize)s" % locals()
149 bootcmd = bootcmd + " -smp 1"
150 # redirect incomming tcp connections on specified port to guest node
151 if 'redir_ssh_port' in node and node['redir_ssh_port']:
152 port = node['redir_ssh_port']
153 ip = node['nodenetworks'][0]['ip']
154 bootcmd = bootcmd + " -redir tcp:%(port)s:%(ip)s:22" % locals()
155 # no graphics support -> assume we are booting via serial console
156 bootcmd = bootcmd + " -nographic"
157 # boot from the supplied cdrom iso file
158 bootcmd = bootcmd + " -boot d"
159 bootcmd = bootcmd + " -cdrom %(bootimage)s" % locals()
160 # hard disk image to use for the node
161 bootcmd = bootcmd + " %(diskimage)s" % locals()
162 # redirect stdout, stderr to logfile
163 bootcmd = bootcmd + " 2>&1 >> %s " % (self.config.log_filename)
165 # kill any old qemu processes for this node
166 pid_cmd = "ps -elfy | grep qemu | grep %(hostname)s | awk '{print$3}'" % locals()
167 (status, output) = node.host_commands(pid_cmd)
168 pids = " ".join(output.split("\n")).strip()
170 kill_cmd = "kill %(pids)s" % locals()
171 (status, output) = node.host_commands(kill_cmd)
174 (self.stdin, self.stdout, self.stderr) = node.host_popen3(bootcmd)
176 # wait for qemu to start up
178 # get qemu's pid from its pidfile (crappy approach)
179 pid_cmd = "cat %(pidfile)s" % locals()
180 (staus, output) = node.host_commands(pid_cmd)
181 self.pid = output.strip()
188 # loop until the node is either fully booted, some error
189 # occured, or we've reached our totaltime out
190 def catch(sig, frame):
191 self.totaltime = self.totaltime -1
192 utils.header("beep %d\n" %self.totaltime, False)
193 total = self.totaltime
195 (((total % 60)==0) and self.state_nanny()):
202 signal.signal(signal.SIGALRM, catch)
206 #console_states = {"login:":1}
210 # self.console_nanny(console_states)
211 #except: # need a better way to catch exceptions
212 # traceback.print_exc()
222 if __name__ == '__main__':
223 args = tuple(sys.argv[1:])