def __call__(self, spalloc_server, spalloc_port=22244, spalloc_machine=None): with ProtocolClient(spalloc_server, spalloc_port) as client: machines = client.list_machines() # Close the context immediately; don't want to keep this particular # connection around as there's not a great chance of this code # being rerun in this process any time soon. max_width = None max_height = None max_area = -1 for machine in self._filter(machines, spalloc_machine): # Get the width and height in chips, and logical area in chips**2 width, height, area = self._get_size(machine) # The "biggest" board is the one with the most chips if area > max_area: max_area = area max_width = width max_height = height # Return the width and height, and make no assumption about wrap- # arounds or version. return max_width, max_height, None, None
def test_close(c, s, bg_accept): # If already connected, should be able to close assert not c._has_open_socket() c.connect() assert c._has_open_socket() c.close() assert not c._has_open_socket() bg_accept.join() s.close() # Should be able to close again c.close() assert not c._has_open_socket() # And should be able to close a newly created connection c = ProtocolClient("localhost") assert not c._has_open_socket() c.close() assert not c._has_open_socket()
def test_reconnect(self): # If previously connected, connecting should close the existing # connection and attempt to start a new one c = ProtocolClient("localhost") started = threading.Event() def accept_and_listen(): s = MockServer() s.listen() started.set() s.connect() # Attempt several reconnects for _ in range(3): t = threading.Thread(target=accept_and_listen) t.start() started.wait() started.clear() c.connect() t.join()
def __call__(self, spalloc_server, spalloc_port=22244, spalloc_machine=None, max_sdram_size=None, max_machine_core_reduction=0): """ :param str spalloc_server: :param int spalloc_port: :param str spalloc_machine: :param int max_sdram_size: :param int max_machine_core_reduction: :rtype: ~.Machine """ with ProtocolClient(spalloc_server, spalloc_port) as client: machines = client.list_machines() # Close the context immediately; don't want to keep this particular # connection around as there's not a great chance of this code # being rerun in this process any time soon. max_width = None max_height = None max_area = -1 for machine in self._filter(machines, spalloc_machine): # Get the width and height in chips, and logical area in chips**2 width, height, area = self._get_size(machine) # The "biggest" board is the one with the most chips if area > max_area: max_area = area max_width = width max_height = height if max_width is None: raise Exception( "The spalloc server appears to have no compatible machines") n_cpus_per_chip = (Machine.max_cores_per_chip() - max_machine_core_reduction) # Return the width and height, and make no assumption about wrap- # arounds or version. return virtual_machine(width=max_width, height=max_height, sdram_per_chip=max_sdram_size, n_cpus_per_chip=n_cpus_per_chip, validate=False)
def main(argv=None): t = Terminal(stream=sys.stderr) cfg = config.read_config() parser = argparse.ArgumentParser(description="List all active jobs.") parser.add_argument("--version", "-V", action="version", version=__version__) parser.add_argument("--watch", "-w", action="store_true", default=False, help="watch the list of live jobs in real time") filter_args = parser.add_argument_group("filtering arguments") filter_args.add_argument("--machine", "-m", help="list only jobs on the specified " "machine") filter_args.add_argument("--owner", "-o", help="list only jobs belonging to a particular " "owner") server_args = parser.add_argument_group("spalloc server arguments") server_args.add_argument("--hostname", "-H", default=cfg["hostname"], help="hostname or IP of the spalloc server " "(default: %(default)s)") server_args.add_argument("--port", "-P", default=cfg["port"], type=int, help="port number of the spalloc server " "(default: %(default)s)") server_args.add_argument("--timeout", default=cfg["timeout"], type=float, metavar="SECONDS", help="seconds to wait for a response " "from the server (default: %(default)s)") args = parser.parse_args(argv) # Fail if server not specified if args.hostname is None: parser.error("--hostname of spalloc server must be specified") client = ProtocolClient(args.hostname, args.port) try: # Connect to server and ensure compatible version client.connect() version = tuple( map(int, client.version(timeout=args.timeout).split("."))) if not (VERSION_RANGE_START <= version < VERSION_RANGE_STOP): sys.stderr.write("Incompatible server version ({}).\n".format( ".".join(map(str, version)))) return 2 if args.watch: client.notify_job(timeout=args.timeout) while True: jobs = client.list_jobs(timeout=args.timeout) # Clear the screen before reprinting the table if args.watch: sys.stdout.write(t.clear_screen()) print(render_job_list(t, jobs, args.machine, args.owner)) # Exit or wait for changes, if requested if not args.watch: return 0 else: # Wait for state change try: client.wait_for_notification() except KeyboardInterrupt: # Gracefully exit print("") return 0 # Print a newline to separate old table from the new table when # it gets printed if ANSI screen clearing is not possible. print("") except (IOError, OSError, ProtocolTimeoutError) as e: sys.stderr.write("Error communicating with server: {}\n".format(e)) return 1 finally: client.close()
def main(argv=None): t = Terminal() cfg = config.read_config() parser = argparse.ArgumentParser( description="Get the state of individual machines.") parser.add_argument("--version", "-V", action="version", version=__version__) parser.add_argument("machine", nargs="?", help="if given, specifies the machine to inspect") parser.add_argument("--watch", "-w", action="store_true", default=False, help="update the output when things change.") parser.add_argument("--detailed", "-d", action="store_true", default=False, help="list detailed job information") server_args = parser.add_argument_group("spalloc server arguments") server_args.add_argument("--hostname", "-H", default=cfg["hostname"], help="hostname or IP of the spalloc server " "(default: %(default)s)") server_args.add_argument("--port", "-P", default=cfg["port"], type=int, help="port number of the spalloc server " "(default: %(default)s)") server_args.add_argument("--timeout", default=cfg["timeout"], type=float, metavar="SECONDS", help="seconds to wait for a response " "from the server (default: %(default)s)") args = parser.parse_args(argv) # Fail if server not specified if args.hostname is None: parser.error("--hostname of spalloc server must be specified") # Fail if --detailed used without specifying machine if args.machine is None and args.detailed: parser.error( "--detailed only works when a specific machine is specified") client = ProtocolClient(args.hostname, args.port) try: # Connect to server and ensure compatible version client.connect() version = tuple( map(int, client.version(timeout=args.timeout).split("."))) if not (VERSION_RANGE_START <= version < VERSION_RANGE_STOP): sys.stderr.write("Incompatible server version ({}).\n".format( ".".join(map(str, version)))) return 2 while True: if args.watch: client.notify_machine(args.machine, timeout=args.timeout) t.stream.write(t.clear_screen()) # Prevent errors on stderr being cleared away due to clear # being buffered t.stream.flush() # Get all information machines = client.list_machines(timeout=args.timeout) jobs = client.list_jobs(timeout=args.timeout) # Display accordingly if args.machine is None: retval = list_machines(t, machines, jobs) else: retval = show_machine(t, machines, jobs, args.machine, not args.detailed) # Wait for changes (if required) if retval != 0 or not args.watch: return retval else: try: client.wait_for_notification() print("") except KeyboardInterrupt: print("") return 0 except (IOError, OSError, ProtocolTimeoutError) as e: sys.stderr.write("Error communicating with server: {}\n".format(e)) return 1 finally: client.close()
def main(argv=None): cfg = config.read_config() parser = argparse.ArgumentParser( description="Find out the location (physical or logical) " "of a chip or board.") parser.add_argument("--version", "-V", action="version", version=__version__) control_args = parser.add_mutually_exclusive_group(required=True) control_args.add_argument("--board", "-b", "--logical", "-l", nargs=4, metavar=("MACHINE", "X", "Y", "Z"), help="specify the logical board coordinate") control_args.add_argument("--physical", "-p", nargs=4, metavar=("MACHINE", "CABINET", "FRAME", "BOARD"), help="specify a board's physical location") control_args.add_argument("--chip", "-c", nargs=3, metavar=("MACHINE", "X", "Y"), help="specify a board by chip coordinates (as " "if the whole machine is being used)") control_args.add_argument("--job-chip", "-j", nargs=3, metavar=("JOB_ID", "X", "Y"), help="specify the chip coordinates of a chip " "within a job's boards") server_args = parser.add_argument_group("spalloc server arguments") server_args.add_argument("--hostname", "-H", default=cfg["hostname"], help="hostname or IP of the spalloc server " "(default: %(default)s)") server_args.add_argument("--port", "-P", default=cfg["port"], type=int, help="port number of the spalloc server " "(default: %(default)s)") server_args.add_argument("--timeout", default=cfg["timeout"], type=float, metavar="SECONDS", help="seconds to wait for a response " "from the server (default: %(default)s)") args = parser.parse_args(argv) # Fail if server not specified if args.hostname is None: parser.error("--hostname of spalloc server must be specified") client = ProtocolClient(args.hostname, args.port) try: # Connect to server and ensure compatible version client.connect() version = tuple( map(int, client.version(timeout=args.timeout).split("."))) if not (VERSION_RANGE_START <= version < VERSION_RANGE_STOP): sys.stderr.write("Incompatible server version ({}).\n".format( ".".join(map(str, version)))) return 2 # Work out what the user asked for try: show_board_chip = False if args.board: machine, x, y, z = args.board where_is_kwargs = { "machine": machine, "x": int(x), "y": int(y), "z": int(z), } elif args.physical: machine, c, f, b = args.physical where_is_kwargs = { "machine": machine, "cabinet": int(c), "frame": int(f), "board": int(b), } elif args.chip: machine, x, y = args.chip where_is_kwargs = { "machine": machine, "chip_x": int(x), "chip_y": int(y), } show_board_chip = True elif args.job_chip: job_id, x, y = args.job_chip where_is_kwargs = { "job_id": int(job_id), "chip_x": int(x), "chip_y": int(y), } show_board_chip = True except ValueError as e: parser.error("Error: {}".format(e)) # Ask the server location = client.where_is(**where_is_kwargs) if location is None: sys.stderr.write("No boards at the specified location.\n") return 4 else: out = OrderedDict() out["Machine"] = location["machine"] out["Physical location"] = "Cabinet {}, Frame {}, Board {}".format( *location["physical"]) out["Board coordinate"] = tuple(location["logical"]) out["Machine chip coordinates"] = tuple(location["chip"]) if show_board_chip: out["Coordinates within board"] = tuple(location["board_chip"]) out["Job using board"] = location["job_id"] if location["job_id"]: out["Coordinates within job"] = tuple(location["job_chip"]) print(render_definitions(out)) return 0 except (IOError, OSError, ProtocolTimeoutError) as e: sys.stderr.write("Error communicating with server: {}\n".format(e)) return 1 finally: client.close()
def main(argv=None): t = Terminal() cfg = config.read_config() parser = argparse.ArgumentParser(description="Manage running jobs.") parser.add_argument("--version", "-V", action="version", version=__version__) parser.add_argument("job_id", type=int, nargs="?", help="the job ID of interest, optional if the current " "owner only has one job") parser.add_argument("--owner", "-o", default=cfg["owner"], help="if no job ID is provided and this owner has " "only one job, this job is assumed " "(default: %(default)s)") control_args = parser.add_mutually_exclusive_group() control_args.add_argument("--info", "-i", action="store_true", help="Show basic job information (the default)") control_args.add_argument("--watch", "-w", action="store_true", help="watch this job for state changes") control_args.add_argument("--power-on", "--reset", "-p", "-r", action="store_true", help="power-on or reset the job's boards") control_args.add_argument("--power-off", action="store_true", help="power-off the job's boards") control_args.add_argument("--ethernet-ips", "-e", action="store_true", help="output the IPs of all Ethernet connected " "chips as a CSV") control_args.add_argument("--destroy", "-D", nargs="?", metavar="REASON", const="", help="destroy a queued or running job") server_args = parser.add_argument_group("spalloc server arguments") server_args.add_argument("--hostname", "-H", default=cfg["hostname"], help="hostname or IP of the spalloc server " "(default: %(default)s)") server_args.add_argument("--port", "-P", default=cfg["port"], type=int, help="port number of the spalloc server " "(default: %(default)s)") server_args.add_argument("--timeout", default=cfg["timeout"], type=float, metavar="SECONDS", help="seconds to wait for a response " "from the server (default: %(default)s)") args = parser.parse_args(argv) # Fail if server not specified if args.hostname is None: parser.error("--hostname of spalloc server must be specified") # Fail if job *and* owner not specified if args.job_id is None and args.owner is None: parser.error("job ID (or --owner) not specified") client = ProtocolClient(args.hostname, args.port) try: # Connect to server and ensure compatible version client.connect() version = tuple( map(int, client.version(timeout=args.timeout).split("."))) if not (VERSION_RANGE_START <= version < VERSION_RANGE_STOP): sys.stderr.write("Incompatible server version ({}).\n".format( ".".join(map(str, version)))) return 2 # If no Job ID specified, attempt to discover one if args.job_id is None: jobs = client.list_jobs(timeout=args.timeout) job_ids = [ job["job_id"] for job in jobs if job["owner"] == args.owner ] if len(job_ids) == 0: sys.stderr.write("Owner {} has no live jobs.\n".format( args.owner)) return 3 elif len(job_ids) > 1: sys.stderr.write("Ambiguous: {} has {} live jobs: {}\n".format( args.owner, len(job_ids), ", ".join(map(str, job_ids)))) return 3 else: args.job_id = job_ids[0] # Do as the user asked if args.watch: return watch_job(t, client, args.timeout, args.job_id) elif args.power_on: return power_job(client, args.timeout, args.job_id, True) elif args.power_off: return power_job(client, args.timeout, args.job_id, False) elif args.ethernet_ips: return list_ips(client, args.timeout, args.job_id) elif args.destroy is not None: # Set default destruction message if args.destroy == "" and args.owner: args.destroy = "Destroyed by {}".format(args.owner) return destroy_job(client, args.timeout, args.job_id, args.destroy) else: return show_job_info(t, client, args.timeout, args.job_id) except (IOError, OSError, ProtocolTimeoutError) as e: sys.stderr.write("Error communicating with server: {}\n".format(e)) return 1 finally: client.close()
def test_no_server(self): # Should just fail if there is no server c = ProtocolClient("localhost") with pytest.raises((IOError, OSError)): c.connect()
def c(): c = ProtocolClient("localhost") yield c c.close()