1 ##########################################################################
2 # Copyright (c) 2009, 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 ##########################################################################
10 import sys, os, signal, time, getpass, subprocess, socket, pty
11 import debug, machines, msrc_machinedata
12 from machines import Machine, MachineLockedError, MachineFactory
15 TOOLS_PATH='/home/netos/tools/bin'
16 RACKBOOT=os.path.join(TOOLS_PATH, 'rackboot.sh')
17 RACKPOWER=os.path.join(TOOLS_PATH, 'rackpower')
19 class MSRCMachine(Machine):
20 _msrc_machines = msrc_machinedata.machines
22 def __init__(self, options):
23 super(MSRCMachine, self).__init__(options)
24 self.lockprocess = None
26 def get_bootarch(self):
27 b = self._msrc_machines[self.name]['bootarch']
28 assert(b in self.get_buildarchs())
31 def get_machine_name(self):
32 return self._msrc_machines[self.name]['machine_name']
34 def get_buildarchs(self):
35 return self._msrc_machines[self.name]['buildarchs']
38 return self._msrc_machines[self.name]['ncores']
40 def get_cores_per_socket(self):
41 return self._msrc_machines[self.name]['cores_per_socket']
43 def get_tickrate(self):
44 return self._msrc_machines[self.name]['tickrate']
46 def get_perfcount_type(self):
47 return self._msrc_machines[self.name]['perfcount_type']
49 def get_hostname(self):
50 return self.get_machine_name()
53 return socket.gethostbyname(self.get_hostname())
55 def get_tftp_dir(self):
56 user = getpass.getuser()
57 return os.path.join(TFTP_PATH, user, self.name + "_harness")
59 def _write_menu_lst(self, data, path):
60 debug.verbose('writing %s' % path)
66 def _set_menu_lst(self, relpath):
67 ip_menu_name = os.path.join(TFTP_PATH, "menu.lst." + self.get_ip())
68 debug.verbose('relinking %s to %s' % (ip_menu_name, relpath))
69 os.remove(ip_menu_name)
70 os.symlink(relpath, ip_menu_name)
72 def set_bootmodules(self, modules):
73 fullpath = os.path.join(self.get_tftp_dir(), 'menu.lst')
74 relpath = os.path.relpath(fullpath, TFTP_PATH)
75 tftppath = '/' + os.path.relpath(self.get_tftp_dir(), TFTP_PATH)
76 self._write_menu_lst(modules.get_menu_data(tftppath), fullpath)
77 self._set_menu_lst(relpath)
80 """Use conserver to lock the machine."""
82 # find out current status of console
83 debug.verbose('executing "console -i %s" to check state' %
84 self.get_machine_name())
85 proc = subprocess.Popen(["console", "-i", self.get_machine_name()],
86 stdout=subprocess.PIPE)
87 line = proc.communicate()[0]
88 assert(proc.returncode == 0)
90 # check that nobody else has it open for writing
91 myuser = getpass.getuser()
92 parts = line.strip().split(':')
93 conname, child, contype, details, users, state = parts[:6]
95 for userinfo in users.split(','):
96 mode, username, host, port = userinfo.split('@')[:4]
97 if 'w' in mode and username != myuser:
98 raise MachineLockedError # Machine is not free
100 # run a console in the background to 'hold' the lock and read output
101 debug.verbose('starting "console %s"' % self.get_machine_name())
102 # run on a PTY to work around terminal mangling code in console
103 (masterfd, slavefd) = pty.openpty()
104 self.lockprocess = subprocess.Popen(["console", self.get_machine_name()],
106 stdout=slavefd, stdin=slavefd)
108 # XXX: open in binary mode with no buffering
109 # otherwise select.select() may block when there is data in the buffer
110 self.console_out = os.fdopen(masterfd, 'rb', 0)
113 if self.lockprocess is None:
115 debug.verbose('terminating console process (%d)' % self.lockprocess.pid)
116 os.kill(self.lockprocess.pid, signal.SIGTERM)
117 self.lockprocess.wait()
118 self.lockprocess = None
120 def __rackboot(self, args):
121 debug.checkcmd([RACKBOOT] + args + [self.get_machine_name()])
124 self.__rackboot(["-b", "-n"])
126 def __rackpower(self, arg):
128 debug.checkcmd([RACKPOWER, arg, self.get_machine_name()])
129 except subprocess.CalledProcessError:
130 debug.warning("rackpower %s %s failed" %
131 (arg, self.get_machine_name()))
134 self.__rackpower('-r')
137 self.__rackpower('-d')
139 def get_output(self):
140 return self.console_out
143 for n in sorted(MSRCMachine._msrc_machines.keys()):
144 class TmpMachine(MSRCMachine):
146 MachineFactory.addMachine(n, TmpMachine)