1 ##########################################################################
2 # Copyright (c) 2009-2016 ETH Zurich.
5 # This file is distributed under the terms in the attached LICENSE file.
6 # If you do not find this file, copies can be found by writing to:
7 # ETH Zurich D-INFK, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group.
8 ##########################################################################
10 import os, getpass, subprocess, socket, pty
11 import debug, eth_machinedata
12 from machines import Machine, MachineLockedError, MachineFactory,\
15 from subprocess_timeout import wait_or_terminate
17 TFTP_PATH='/home/netos/tftpboot'
18 TOOLS_PATH='/home/netos/tools/bin'
19 RACKBOOT=os.path.join(TOOLS_PATH, 'rackboot.sh')
20 RACKPOWER=os.path.join(TOOLS_PATH, 'rackpower')
22 class ETHBaseMachine(Machine):
25 def __init__(self, options,
27 serial_binary='serial_pc16550d',
30 super(ETHBaseMachine, self).__init__(options, operations,
31 serial_binary=serial_binary,
34 def get_perfcount_type(self):
35 return self._perfcount_type
37 class ETHBaseMachineOperations(MachineOperations):
39 def __init__(self, machine):
40 super(ETHBaseMachineOperations, self).__init__(machine)
41 self.lockprocess = None
44 def _get_console_status(self):
45 raise NotImplementedError
48 """Use conserver to lock the machine."""
50 # find out current status of console
51 cstate = self._get_console_status()
52 # check that nobody else has it open for writing
53 myuser = getpass.getuser()
54 parts = cstate.strip().split(':')
55 conname, child, contype, details, users, state = parts[:6]
57 for userinfo in users.split(','):
58 mode, username, host, port = userinfo.split('@')[:4]
59 if 'w' in mode and username != myuser:
60 raise MachineLockedError # Machine is not free
62 # run a console in the background to 'hold' the lock and read output
63 debug.verbose('starting "console %s"' % self._machine.get_machine_name())
64 # run on a PTY to work around terminal mangling code in console
65 (self.masterfd, slavefd) = pty.openpty()
66 self.lockprocess = subprocess.Popen(["console", self._machine.get_machine_name()],
68 stdout=slavefd, stdin=slavefd)
70 # XXX: open in binary mode with no buffering
71 # otherwise select.select() may block when there is data in the buffer
72 self.console_out = os.fdopen(self.masterfd, 'rb', 0)
75 if self.lockprocess is None:
77 debug.verbose('quitting console process (%d)' % self.lockprocess.pid)
78 # os.kill(self.lockprocess.pid, signal.SIGTERM)
79 os.write(self.masterfd, "\x05c.")
80 wait_or_terminate(self.lockprocess)
81 self.lockprocess = None
84 # this expects a pexpect object for `consolectrl`
85 def force_write(self, consolectrl):
87 consolectrl.send('\x05cf')
89 print "Unable to force write control through consolectrl, trying masterfd"
90 os.write(self.masterfd, "\x05cf")
93 return self.console_out
96 class ETHMachine(ETHBaseMachine):
97 _machines = eth_machinedata.machines
99 def __init__(self, options, **kwargs):
100 super(ETHMachine, self).__init__(options, ETHMachineOperations(self), **kwargs)
102 def get_buildall_target(self):
103 if 'buildall_target' in self._machines[self.name]:
104 return self._machines[self.name]['buildall_target']
105 return self.get_bootarch().upper() + "_Full"
107 def get_xphi_ncores(self):
108 if 'xphi_ncores' in self._machines[self.name] :
109 return self._machines[self.name]['xphi_ncores']
113 def get_xphi_ncards(self):
114 if 'xphi_ncards' in self._machines[self.name] :
115 return self._machines[self.name]['xphi_ncards']
119 def get_xphi_ram_gb(self):
120 if 'xphi_ram_gb' in self._machines[self.name] :
121 return self._machines[self.name]['xphi_ram_gb']
125 def get_xphi_tickrate(self):
126 if 'xphi_tickrate' in self._machines[self.name] :
127 return self._machines[self.name]['xphi_tickrate']
131 def get_hostname(self):
132 return self.get_machine_name() + '.in.barrelfish.org'
135 return socket.gethostbyname(self.get_hostname())
137 class ETHMachineOperations(ETHBaseMachineOperations):
139 def __init__(self, machine):
140 super(ETHMachineOperations, self).__init__(machine)
142 def get_tftp_dir(self):
143 user = getpass.getuser()
144 return os.path.join(TFTP_PATH, user, self._machine.name + "_harness")
146 def get_tftp_subdir(self):
147 user = getpass.getuser()
148 return os.path.join(user, self._machine.name + "_harness")
150 def _write_menu_lst(self, data, path):
151 debug.verbose('writing %s' % path)
153 with open(path, 'w') as f:
157 def _get_menu_lst_name(self):
158 if self._machine.get_bootarch() == "armv8":
163 def _set_menu_lst(self, relpath):
164 ip_menu_name = os.path.join(TFTP_PATH, self._get_menu_lst_name() + "." + self._machine.get_ip())
165 debug.verbose('relinking %s to %s' % (ip_menu_name, relpath))
166 os.remove(ip_menu_name)
167 os.symlink(relpath, ip_menu_name)
169 def set_bootmodules(self, modules):
170 fullpath = os.path.join(self.get_tftp_dir(), self._get_menu_lst_name())
171 relpath = os.path.relpath(fullpath, TFTP_PATH)
172 tftppath = '/' + os.path.relpath(self.get_tftp_dir(), TFTP_PATH)
173 self._write_menu_lst(modules.get_menu_data(tftppath), fullpath)
174 self._set_menu_lst(relpath)
176 def _get_console_status(self):
177 debug.verbose('executing "console -i %s" to check state' %
178 self._machine.get_machine_name())
179 proc = subprocess.Popen(["console", "-i", self._machine.get_machine_name()],
180 stdout=subprocess.PIPE)
181 line = proc.communicate()[0]
182 assert(proc.returncode == 0)
185 def __rackboot(self, args):
186 debug.checkcmd([RACKBOOT] + args + [self._machine.get_machine_name()])
189 if self._machine.get_bootarch() == "armv8":
190 self.__rackboot(["-b", "-H", "-n"])
192 self.__rackboot(["-b", "-n"])
194 def __rackpower(self, arg):
196 debug.checkcmd([RACKPOWER, arg, self._machine.get_machine_name()])
197 except subprocess.CalledProcessError:
198 debug.warning("rackpower %s %s failed" %
199 (arg, self._machine.get_machine_name()))
202 self.__rackpower('-r')
205 self.__rackpower('-d')
208 for n in sorted(ETHMachine._machines.keys()):
209 class TmpMachine(ETHMachine):
211 MachineFactory.addMachine(n, TmpMachine, **ETHMachine._machines[n])