def start(self): self.mtda.debug(3, "main.start()") if self.is_remote is True: return True # Probe the specified power controller if self.power_controller is not None: status = self.power_controller.probe() if status is False: print('Probe of the Power Controller failed!', file=sys.stderr) return False # Probe the specified sdmux controller if self.sdmux_controller is not None: status = self.sdmux_controller.probe() if status is False: print('Probe of the shared storage device failed!', file=sys.stderr) return False if self.console is not None: # Create a publisher if self.is_server is True: context = zmq.Context() socket = context.socket(zmq.PUB) socket.bind("tcp://*:%s" % self.conport) else: socket = None # Create and start console logger status = self.console.probe() if status is False: print('Probe of the %s console failed!' % (self.console.variant), file=sys.stderr) return False self.console_logger = ConsoleLogger(self, self.console, socket, self.power_controller) self.console_logger.start() if self.monitor is not None: # Create and start console logger status = self.monitor.probe() if status is False: print('Probe of the %s monitor console failed!' % (self.monitor.variant), file=sys.stderr) return False self.monitor_logger = ConsoleLogger(self, self.monitor, None, self.power_controller) self.monitor_logger.toggle_prints() self.monitor_logger.start() if self.assistant is not None: self.power_monitors.append(self.assistant) self.assistant.start() return True
class MentorTestDeviceAgent: def __init__(self): self.config_files = ['mtda.ini'] self.console = None self.console_logger = None self.console_input = None self.console_output = None self.debug_level = 0 self.env = {} self.fuse = False self.keyboard = None self.mtda = self self.assistant = None self.power_controller = None self.power_on_script = None self.power_off_script = None self.power_monitors = [] self.sdmux_controller = None self._storage_mounted = False self._storage_opened = False self._writer = None self._writer_data = None self.blksz = CONSTS.WRITER.READ_SIZE self.usb_switches = [] self.ctrlport = 5556 self.conport = 5557 self.prefix_key = self._prefix_key_code(DEFAULT_PREFIX_KEY) self.is_remote = False self.is_server = False self.remote = None self._lock_owner = None self._lock_expiry = None self._lock_timeout = 5 # Lock timeout (in minutes) self.version = __version__ # Config file in $HOME/.mtda/config home = os.getenv('HOME', '') if home != '': self.config_files.append(os.path.join(home, '.mtda', 'config')) # Config file in /etc/mtda/config if os.path.exists('/etc'): self.config_files.append(os.path.join('/etc', 'mtda', 'config')) def agent_version(self): return self.version def command(self, args, session=None): self.mtda.debug(3, "main.command()") self._check_expired(session) result = False if self.power_locked(session) is False: result = self.power_controller.command(args) self.mtda.debug(3, "main.command(): %s" % str(result)) return result def console_prefix_key(self): self.mtda.debug(3, "main.console_prefix_key()") return self.prefix_key def _prefix_key_code(self, prefix_key): prefix_key = prefix_key.lower() key_dict = {'ctrl-a': '\x01', 'ctrl-b': '\x02', 'ctrl-c': '\x03', 'ctrl-d': '\x04', 'ctrl-e': '\x05', 'ctrl-f': '\x06', 'ctrl-g': '\x07', 'ctrl-h': '\x08', 'ctrl-i': '\x09', 'ctrl-j': '\x0A', 'ctrl-k': '\x0B', 'ctrl-l': '\x0C', 'ctrl-n': '\x0E', 'ctrl-o': '\x0F', 'ctrl-p': '\x10', 'ctrl-q': '\x11', 'ctrl-r': '\x12', 'ctrl-s': '\x13', 'ctrl-t': '\x14', 'ctrl-u': '\x15', 'ctrl-v': '\x16', 'ctrl-w': '\x17', 'ctrl-x': '\x18', 'ctrl-y': '\x19', 'ctrl-z': '\x1A'} if prefix_key in key_dict: key_ascii = key_dict[prefix_key] return key_ascii else: raise ValueError("the prefix key specified '{0}' is not " "supported".format(prefix_key)) def console_getkey(self): self.mtda.debug(3, "main.console_getkey()") result = None try: result = self.console_input.getkey() except AttributeError: print("Initialize the console using console_init first") self.mtda.debug(3, "main.console_getkey(): %s" % str(result)) return result def console_init(self): self.console_input = ConsoleInput() self.console_input.start() def console_clear(self, session=None): self.mtda.debug(3, "main.console_clear()") self._check_expired(session) if self.console_locked(session): self.mtda.debug(2, "console_clear(): console is locked") return None if self.console_logger is not None: result = self.console_logger.clear() else: result = None self.mtda.debug(3, "main.console_clear(): %s" % str(result)) return result def console_dump(self, session=None): self.mtda.debug(3, "main.console_dump()") self._check_expired(session) if self.console_locked(session): self.mtda.debug(2, "console_dump(): console is locked") return None result = None if self.console_logger is not None: result = self.console_logger.dump() self.mtda.debug(3, "main.console_dump(): %s" % str(result)) return result def console_flush(self, session=None): self.mtda.debug(3, "main.console_flush()") self._check_expired(session) if self.console_locked(session): self.mtda.debug(2, "console_flush(): console is locked") return None result = None if self.console_logger is not None: result = self.console_logger.flush() self.mtda.debug(3, "main.console_flush(): %s" % str(result)) return result def console_head(self, session=None): self.mtda.debug(3, "main.console_head()") self._check_expired(session) result = None if self.console_logger is not None: result = self.console_logger.head() self.mtda.debug(3, "main.console_head(): %s" % str(result)) return result def console_lines(self, session=None): self.mtda.debug(3, "main.console_lines()") self._check_expired(session) result = None if self.console_logger is not None: result = self.console_logger.lines() self.mtda.debug(3, "main.console_lines(): %s" % str(result)) return result def console_locked(self, session=None): self.mtda.debug(3, "main.console_locked()") self._check_expired(session) result = self._check_locked(session) self.mtda.debug(3, "main.console_locked(): %s" % str(result)) return result def console_print(self, data, session=None): self.mtda.debug(3, "main.console_print()") self._check_expired(session) result = None if self.console_logger is not None: result = self.console_logger.print(data) self.mtda.debug(3, "main.console_print(): %s" % str(result)) return result def console_prompt(self, newPrompt=None, session=None): self.mtda.debug(3, "main.console_prompt()") self._check_expired(session) result = None if self.console_locked(session) is False and \ self.console_logger is not None: result = self.console_logger.prompt(newPrompt) self.mtda.debug(3, "main.console_prompt(): %s" % str(result)) return result def console_remote(self, host): self.mtda.debug(3, "main.console_remote()") result = None if self.is_remote is True: # Create and start our remote console self.console_output = RemoteConsoleOutput(host, self.conport) self.console_output.start() self.mtda.debug(3, "main.console_remote(): %s" % str(result)) return result def console_run(self, cmd, session=None): self.mtda.debug(3, "main.console_run()") self._check_expired(session) result = None if self.console_locked(session) is False and \ self.console_logger is not None: result = self.console_logger.run(cmd) self.mtda.debug(3, "main.console_run(): %s" % str(result)) return result def console_send(self, data, raw=False, session=None): self.mtda.debug(3, "main.console_send()") self._check_expired(session) result = None if self.console_locked(session) is False and \ self.console_logger is not None: result = self.console_logger.write(data, raw) self.mtda.debug(3, "main.console_send(): %s" % str(result)) return result def console_tail(self, session=None): self.mtda.debug(3, "main.console_tail()") self._check_expired(session) if self.console_locked(session) is False and \ self.console_logger is not None: result = self.console_logger.tail() self.mtda.debug(3, "main.console_tail(): %s" % str(result)) return result def debug(self, level, msg): if self.debug_level >= level: if self.debug_level == 0: prefix = "# " else: prefix = "# debug%d: " % level msg = str(msg).replace("\n", "\n%s ... " % prefix) lines = msg.splitlines() for line in lines: line = _make_printable(line) print("%s%s" % (prefix, line), file=sys.stderr) def env_get(self, name, session=None): self.mtda.debug(3, "env_get()") self._check_expired(session) result = None if name in self.env: result = self.env[name] self.mtda.debug(3, "env_get(): %s" % str(result)) return result def env_set(self, name, value, session=None): self.mtda.debug(3, "env_set()") self._check_expired(session) result = None if name in self.env: old_value = self.env[name] result = old_value else: old_value = value self.env[name] = value self.env["_%s" % name] = old_value self.mtda.debug(3, "env_set(): %s" % str(result)) return result def keyboard_write(self, str, session=None): self.mtda.debug(3, "main.keyboard_write()") self._check_expired(session) result = None if self.keyboard is not None: result = self.keyboard.write(str) self.mtda.debug(3, "main.keyboard_write(): %s" % str(result)) return result def power_locked(self, session=None): self.mtda.debug(3, "main.power_locked()") self._check_expired(session) if self.power_controller is None: result = True else: result = self._check_locked(session) self.mtda.debug(3, "main.power_locked(): %s" % str(result)) return result def storage_bytes_written(self, session=None): self.mtda.debug(3, "main.storage_bytes_written()") self._check_expired(session) result = self._writer.written self.mtda.debug(3, "main.storage_bytes_written(): %s" % str(result)) return result def storage_compression(self, compression, session=None): self.mtda.debug(3, "main.storage_compression()") self._check_expired(session) if self.sdmux_controller is None: result = None else: result = self._writer.compression.value self._writer.compression = compression self.mtda.debug(3, "main.storage_compression(): %s" % str(result)) return result def storage_close(self, session=None): self.mtda.debug(3, "main.storage_close()") self._check_expired(session) if self.sdmux_controller is None: result = False else: self._writer.stop() self._writer_data = None self._storage_opened = not self.sdmux_controller.close() result = (self._storage_opened is False) self.mtda.debug(3, "main.storage_close(): %s" % str(result)) return result def storage_locked(self, session=None): self.mtda.debug(3, "main.storage_locked()") self._check_expired(session) if self._check_locked(session): result = True # Cannot swap the shared storage device between the host and target # without a driver elif self.sdmux_controller is None: self.mtda.debug(4, "storage_locked(): no shared storage device") result = True # If hotplugging is supported, swap only if the shared storage # isn't opened elif self.sdmux_controller.supports_hotplug() is True: result = self._storage_opened # We also need a power controller to be safe elif self.power_controller is None: self.mtda.debug(4, "storage_locked(): no power controller") result = True # The target shall be OFF elif self.target_status() != "OFF": self.mtda.debug(4, "storage_locked(): target isn't off") result = True # Lastly, the shared storage device shall not be opened elif self._storage_opened is True: self.mtda.debug(4, "storage_locked(): " "shared storage is in used (opened)") result = True # We may otherwise swap our shared storage device else: result = False self.mtda.debug(3, "main.storage_locked(): %s" % str(result)) return result def storage_mount(self, part=None, session=None): self.mtda.debug(3, "main.storage_mount()") self._check_expired(session) if self._storage_mounted is True: self.mtda.debug(4, "storage_mount(): already mounted") result = True elif self.sdmux_controller is None: self.mtda.debug(4, "storage_mount(): no shared storage device") return False else: result = self.sdmux_controller.mount(part) self._storage_mounted = (result is True) self.mtda.debug(3, "main.storage_mount(): %s" % str(result)) return result def storage_update(self, dst, offset, session=None): self.mtda.debug(3, "main.storage_update()") self._check_expired(session) result = False if self.sdmux_controller is None: self.mtda.debug(4, "storage_update(): no shared storage device") else: try: result = self.sdmux_controller.update(dst, offset) if result is True: self._writer.start() except (FileNotFoundError, IOError) as e: self.mtda.debug(1, "main.storage_update(): " "%s" % str(e.args[0])) self.mtda.debug(3, "main.storage_update(): %s" % str(result)) return result def storage_open(self, session=None): self.mtda.debug(3, "main.storage_open()") self._check_expired(session) if self.sdmux_controller is None: self.mtda.debug(1, "storage_open(): no shared storage device") result = False else: self.storage_close() result = self.sdmux_controller.open() if result is True: self._writer.start() self._storage_opened = result self.mtda.debug(3, "main.storage_open(): %s" % str(result)) return result def storage_status(self, session=None): self.mtda.debug(3, "main.storage_status()") self._check_expired(session) if self.sdmux_controller is None: self.mtda.debug(4, "storage_status(): no shared storage device") result = "???", False, 0 else: status = self.sdmux_controller.status() result = status, self._writer.writing, self._writer.written self.mtda.debug(3, "main.storage_status(): %s" % str(result)) return result def storage_to_host(self, session=None): self.mtda.debug(3, "main.storage_to_host()") self._check_expired(session) if self.storage_locked(session) is False: result = self.sdmux_controller.to_host() else: self.mtda.debug(1, "storage_to_host(): shared storage is locked") result = False self.mtda.debug(3, "main.storage_to_host(): %s" % str(result)) return result def storage_to_target(self, session=None): self.mtda.debug(3, "main.storage_to_target()") self._check_expired(session) if self.storage_locked(session) is False: self.storage_close() result = self.sdmux_controller.to_target() else: self.mtda.debug(1, "storage_to_target(): shared storage is locked") result = False self.mtda.debug(3, "main.storage_to_target(): %s" % str(result)) return result def storage_swap(self, session=None): self.mtda.debug(3, "main.storage_swap()") self._check_expired(session) if self.storage_locked(session) is False: result, writing, written = self.storage_status(session) if result == self.sdmux_controller.SD_ON_HOST: self.sdmux_controller.to_target() elif result == self.sdmux_controller.SD_ON_TARGET: self.sdmux_controller.to_host() result, writing, written = self.storage_status(session) return result self.mtda.debug(3, "main.storage_swap(): %s" % str(result)) return result def storage_write(self, data, session=None): self.mtda.debug(3, "main.storage_write()") self._check_expired(session) if self.sdmux_controller is None or self._writer.failed is True: result = -1 else: try: if len(data) == 0: self.mtda.debug(2, "main.storage_write(): " "using queued data") data = self._writer_data self._writer_data = data self._writer.put(data, timeout=10) result = self.blksz except queue.Full: self.mtda.debug(2, "main.storage_write(): " "queue is full") result = 0 if self._writer.failed is True: self.mtda.debug(1, "main.storage_write(): " "write or decompression error") result = -1 self.mtda.debug(3, "main.storage_write(): %s" % str(result)) return result def toggle_timestamps(self): self.mtda.debug(3, "main.toggle_timestamps()") if self.console_logger is not None: result = self.console_logger.toggle_timestamps() else: print("no console configured/found!", file=sys.stderr) result = None self.mtda.debug(3, "main.toggle_timestamps(): %s" % str(result)) return result def target_lock(self, session): self.mtda.debug(3, "main.target_lock()") self._check_expired(session) owner = self.target_owner() if owner is None or owner == session: self._lock_owner = session result = True else: result = False self.mtda.debug(3, "main.target_lock(): %s" % str(result)) return result def target_locked(self, session): self.mtda.debug(3, "main.target_locked()") self._check_expired(session) return self._check_locked(session) def target_owner(self): self.mtda.debug(3, "main.target_owner()") return self._lock_owner def _power_event(self, status): for m in self.power_monitors: m.power_changed(status) def _parse_script(self, script): self.mtda.debug(3, "main._parse_script()") result = None if script is not None: result = script.replace("... ", " ") self.mtda.debug(3, "main._parse_script(): %s" % str(result)) return result def exec_power_on_script(self): self.mtda.debug(3, "main.exec_power_on_script()") result = None if self.power_on_script: self.mtda.debug(4, "exec_power_on_script(): " "%s" % self.power_on_script) result = exec(self.power_on_script, {"env": self.env, "mtda": self}) self.mtda.debug(3, "main.exec_power_on_script(): %s" % str(result)) return result def target_on(self, session=None): self.mtda.debug(3, "main.target_on()") if self.console_logger is not None: self.console_logger.resume() self._check_expired(session) result = False if self.power_locked(session) is False: result = self.power_controller.on() if result is True: self.exec_power_on_script() self._power_event(self.power_controller.POWER_ON) self.mtda.debug(3, "main.target_on(): %s" % str(result)) return result def exec_power_off_script(self): self.mtda.debug(3, "main.exec_power_off_script()") if self.power_off_script: exec(self.power_off_script, {"env": self.env, "mtda": self}) def target_off(self, session=None): self.mtda.debug(3, "main.target_off()") result = False self._check_expired(session) if self.power_locked(session) is False: result = self.power_controller.off() if self.keyboard is not None: self.keyboard.idle() if self.console_logger is not None: self.console_logger.reset_timer() if result is True: self.console_logger.pause() self.exec_power_off_script() self._power_event(self.power_controller.POWER_OFF) self.mtda.debug(3, "main.target_off(): %s" % str(result)) return result def target_status(self, session=None): self.mtda.debug(3, "main.target_status()") self._check_expired(session) if self.power_controller is None: result = "???" else: result = self.power_controller.status() self.mtda.debug(3, "main.target_status(): %s" % str(result)) return result def target_toggle(self, session=None): self.mtda.debug(3, "main.target_toggle()") self._check_expired(session) if self.power_locked(session) is False: result = self.power_controller.toggle() if result == self.power_controller.POWER_ON: if self.console_logger is not None: self.console_logger.resume() self.exec_power_on_script() self._power_event(self.power_controller.POWER_ON) elif result == self.power_controller.POWER_OFF: self.exec_power_off_script() if self.console_logger is not None: self.console_logger.pause() self.console_logger.reset_timer() self._power_event(self.power_controller.POWER_OFF) else: result = self.power_controller.POWER_LOCKED self.mtda.debug(3, "main.target_toggle(): %s" % str(result)) return result def target_unlock(self, session): self.mtda.debug(3, "main.target_unlock()") result = False self._check_expired(session) if self.target_owner() == session: self._lock_owner = None result = True self.mtda.debug(3, "main.target_unlock(): %s" % str(result)) return result def usb_find_by_class(self, className, session=None): self.mtda.debug(3, "main.usb_find_by_class()") self._check_expired(session) ports = len(self.usb_switches) ndx = 0 while ndx < ports: usb_switch = self.usb_switches[ndx] if usb_switch.className == className: return usb_switch ndx = ndx + 1 return None def usb_has_class(self, className, session=None): self.mtda.debug(3, "main.usb_has_class()") self._check_expired(session) usb_switch = self.usb_find_by_class(className, session) return usb_switch is not None def usb_off(self, ndx, session=None): self.mtda.debug(3, "main.usb_off()") self._check_expired(session) try: if ndx > 0: usb_switch = self.usb_switches[ndx-1] usb_switch.off() except IndexError: print("invalid USB switch #" + str(ndx), file=sys.stderr) def usb_off_by_class(self, className, session=None): self.mtda.debug(3, "main.usb_off_by_class()") self._check_expired(session) usb_switch = self.usb_find_by_class(className, session) if usb_switch is not None: return usb_switch.off() return False def usb_on(self, ndx, session=None): self.mtda.debug(3, "main.usb_on()") self._check_expired(session) try: if ndx > 0: usb_switch = self.usb_switches[ndx-1] usb_switch.on() except IndexError: print("invalid USB switch #" + str(ndx), file=sys.stderr) def usb_on_by_class(self, className, session=None): self.mtda.debug(3, "main.usb_on_by_class()") self._check_expired(session) usb_switch = self.usb_find_by_class(className, session) if usb_switch is not None: return usb_switch.on() return False def usb_ports(self, session=None): self.mtda.debug(3, "main.usb_ports()") self._check_expired(session) return len(self.usb_switches) def usb_status(self, ndx, session=None): self.mtda.debug(3, "main.usb_status()") self._check_expired(session) try: if ndx > 0: usb_switch = self.usb_switches[ndx-1] status = usb_switch.status() if status == usb_switch.POWERED_OFF: return "OFF" elif status == usb_switch.POWERED_ON: return "ON" else: return "???" except IndexError: print("invalid USB switch #" + str(ndx), file=sys.stderr) return "ERR" return "???" def usb_toggle(self, ndx, session=None): self.mtda.debug(3, "main.usb_toggle()") self._check_expired(session) try: if ndx > 0: usb_switch = self.usb_switches[ndx-1] usb_switch.toggle() except IndexError: print("invalid USB switch #" + str(ndx), file=sys.stderr) def load_config(self, remote=None, is_server=False): self.mtda.debug(3, "main.load_config()") self.remote = remote self.is_remote = remote is not None self.is_server = is_server parser = configparser.ConfigParser() configs_found = parser.read(self.config_files) if parser.has_section('main'): self.load_main_config(parser) if parser.has_section('environment'): self.load_environment(parser) if parser.has_section('remote'): self.load_remote_config(parser) if parser.has_section('ui'): self.load_ui_config(parser) if self.is_remote is False: if parser.has_section('assistant'): self.load_assistant_config(parser) if parser.has_section('power'): self.load_power_config(parser) if parser.has_section('console'): self.load_console_config(parser) if parser.has_section('keyboard'): self.load_keyboard_config(parser) if parser.has_section('sdmux'): self.load_sdmux_config(parser) if parser.has_section('usb'): self.load_usb_config(parser) if parser.has_section('scripts'): scripts = parser['scripts'] self.power_on_script = self._parse_script( scripts.get('power on', None)) self.power_off_script = self._parse_script( scripts.get('power off', None)) def load_main_config(self, parser): self.mtda.debug(3, "main.load_main_config()") self.mtda.debug_level = int( parser.get('main', 'debug', fallback=self.mtda.debug_level)) self.mtda.fuse = parser.getboolean( 'main', 'fuse', fallback=self.mtda.fuse) def load_environment(self, parser): self.mtda.debug(3, "main.load_environment()") for opt in parser.options('environment'): value = parser.get('environment', opt) self.mtda.debug(4, "main.load_environment(): " "%s => %s" % (opt, value)) self.env_set(opt, value) def load_assistant_config(self, parser): self.mtda.debug(3, "main.load_assistant_config()") try: # Get variant variant = parser.get('assistant', 'variant') # Try loading its support class mod = importlib.import_module("mtda.assistant." + variant) factory = getattr(mod, 'instantiate') self.assistant = factory(self) self.assistant.variant = variant # Configure the assistant self.assistant.configure(dict(parser.items('assistant'))) except configparser.NoOptionError: print('assistant variant not defined!', file=sys.stderr) except ImportError: print('assistant "%s" could not be found/loaded!' % ( variant), file=sys.stderr) def load_console_config(self, parser): self.mtda.debug(3, "main.load_console_config()") try: # Get variant variant = parser.get('console', 'variant') # Try loading its support class mod = importlib.import_module("mtda.console." + variant) factory = getattr(mod, 'instantiate') self.console = factory(self) self.console.variant = variant # Configure the console self.console.configure(dict(parser.items('console'))) except configparser.NoOptionError: print('console variant not defined!', file=sys.stderr) except ImportError: print('console "%s" could not be found/loaded!' % ( variant), file=sys.stderr) def load_keyboard_config(self, parser): self.mtda.debug(3, "main.load_keyboard_config()") try: # Get variant variant = parser.get('keyboard', 'variant') # Try loading its support class mod = importlib.import_module("mtda.keyboard." + variant) factory = getattr(mod, 'instantiate') self.keyboard = factory(self) # Configure the keyboard controller self.keyboard.configure(dict(parser.items('keyboard'))) self.keyboard.probe() except configparser.NoOptionError: print('keyboard controller variant not defined!', file=sys.stderr) except ImportError: print('keyboard controller "%s" could not be found/loaded!' % ( variant), file=sys.stderr) def load_power_config(self, parser): self.mtda.debug(3, "main.load_power_config()") try: # Get variant variant = parser.get('power', 'variant') # Try loading its support class mod = importlib.import_module("mtda.power." + variant) factory = getattr(mod, 'instantiate') self.power_controller = factory(self) self.power_controller.variant = variant # Configure the power controller self.power_controller.configure(dict(parser.items('power'))) except configparser.NoOptionError: print('power controller variant not defined!', file=sys.stderr) except ImportError: print('power controller "%s" could not be found/loaded!' % ( variant), file=sys.stderr) def load_sdmux_config(self, parser): self.mtda.debug(3, "main.load_sdmux_config()") try: # Get variant variant = parser.get('sdmux', 'variant') # Try loading its support class mod = importlib.import_module("mtda.sdmux." + variant) factory = getattr(mod, 'instantiate') self.sdmux_controller = factory(self) self._writer = AsyncImageWriter(self, self.sdmux_controller) # Configure the sdmux controller self.sdmux_controller.configure(dict(parser.items('sdmux'))) except configparser.NoOptionError: print('sdmux controller variant not defined!', file=sys.stderr) except ImportError: print('power controller "%s" could not be found/loaded!' % ( variant), file=sys.stderr) def load_remote_config(self, parser): self.mtda.debug(3, "main.load_remote_config()") self.conport = int( parser.get('remote', 'console', fallback=self.conport)) self.ctrlport = int( parser.get('remote', 'control', fallback=self.ctrlport)) if self.is_server is False: if self.remote is None: # Load remote setting from the configuration self.remote = parser.get( 'remote', 'host', fallback=self.remote) # Allow override from the environment self.remote = os.getenv('MTDA_REMOTE', self.remote) else: self.remote = None self.is_remote = self.remote is not None def load_ui_config(self, parser): self.mtda.debug(3, "main.load_ui_config()") self.prefix_key = self._prefix_key_code(parser.get( 'ui', 'prefix', fallback=DEFAULT_PREFIX_KEY)) def load_usb_config(self, parser): self.mtda.debug(3, "main.load_usb_config()") try: # Get number of ports usb_ports = int(parser.get('usb', 'ports')) for port in range(0, usb_ports): port = port + 1 section = "usb" + str(port) if parser.has_section(section): self.load_usb_port_config(parser, section) except configparser.NoOptionError: usb_ports = 0 def load_usb_port_config(self, parser, section): self.mtda.debug(3, "main.load_usb_port_config()") try: # Get attributes className = parser.get(section, 'class', fallback="") variant = parser.get(section, 'variant') # Try loading its support class mod = importlib.import_module("mtda.usb." + variant) factory = getattr(mod, 'instantiate') usb_switch = factory(self) # Configure and probe the USB switch usb_switch.configure(dict(parser.items(section))) usb_switch.probe() # Store other attributes usb_switch.className = className # Add this USB switch self.usb_switches.append(usb_switch) except configparser.NoOptionError: print('usb switch variant not defined!', file=sys.stderr) except ImportError: print('usb switch "%s" could not be found/loaded!' % ( variant), file=sys.stderr) def start(self): self.mtda.debug(3, "main.start()") if self.is_remote is True: return True # Probe the specified power controller if self.power_controller is not None: status = self.power_controller.probe() if status is False: print('Probe of the Power Controller failed!', file=sys.stderr) return False # Probe the specified sdmux controller if self.sdmux_controller is not None: status = self.sdmux_controller.probe() if status is False: print('Probe of the shared storage device failed!', file=sys.stderr) return False if self.console is not None: # Create a publisher if self.is_server is True: context = zmq.Context() socket = context.socket(zmq.PUB) socket.bind("tcp://*:%s" % self.conport) else: socket = None # Create and start console logger status = self.console.probe() if status is False: print('Probe of the %s console failed!' % ( self.console.variant), file=sys.stderr) return False self.console_logger = ConsoleLogger( self, self.console, socket, self.power_controller) self.console_logger.start() if self.assistant is not None: self.power_monitors.append(self.assistant) self.assistant.start() return True def _check_expired(self, session): self.mtda.debug(3, "main._check_expired()") if self._lock_owner: now = time.monotonic() if session == self._lock_owner: self._lock_expiry = now + (self._lock_timeout * 60) elif now >= self._lock_expiry: self._lock_owner = None def _check_locked(self, session): self.mtda.debug(3, "main._check_locked()") owner = self.target_owner() if owner is None: return False status = False if session == owner else True return status
class MentorTestDeviceAgent: def __init__(self): self.config_files = ['mtda.ini'] self.console = None self.console_logger = None self.console_input = None self.console_output = None self.debug_level = 0 self.env = {} self.fuse = False self.keyboard = None self.mtda = self self.power_controller = None self.power_on_script = None self.power_off_script = None self.sdmux_controller = None self._storage_bytes_written = 0 self._storage_mounted = False self._storage_opened = False self.blksz = 1 * 1024 * 1024 self.bz2dec = None self.zdec = None self.fbintvl = 8 # Feedback interval self.usb_switches = [] self.ctrlport = 5556 self.conport = 5557 self.is_remote = False self.is_server = False self.remote = None self._lock_owner = None self._lock_expiry = None self._lock_timeout = 5 # Lock timeout (in minutes) # Config file in $HOME/.mtda/config home = os.getenv('HOME', '') if home != '': self.config_files.append(os.path.join(home, '.mtda', 'config')) # Config file in /etc/mtda/config if os.path.exists('/etc'): self.config_files.append(os.path.join('/etc', 'mtda', 'config')) def command(self, args, session=None): self.mtda.debug(3, "main.command()") self._check_expired(session) result = False if self.power_locked(session) is False: result = self.power_controller.command(args) self.mtda.debug(3, "main.command(): %s" % str(result)) return result def console_getkey(self): self.mtda.debug(3, "main.console_getkey()") if self.console_input is None: self.console_input = ConsoleInput() self.console_input.start() result = self.console_input.getkey() self.mtda.debug(3, "main.console_getkey(): %s" % str(result)) return result def console_clear(self, session=None): self.mtda.debug(3, "main.console_clear()") self._check_expired(session) if self.console_locked(session): self.mtda.debug(2, "console_clear(): console is locked") return None if self.console_logger is not None: result = self.console_logger.clear() else: result = None self.mtda.debug(3, "main.console_clear(): %s" % str(result)) return result def console_flush(self, session=None): self.mtda.debug(3, "main.console_flush()") self._check_expired(session) if self.console_locked(session): self.mtda.debug(2, "console_clear(): console is locked") return None result = None if self.console_logger is not None: result = self.console_logger.flush() self.mtda.debug(3, "main.console_flush(): %s" % str(result)) return result def console_head(self, session=None): self.mtda.debug(3, "main.console_head()") self._check_expired(session) result = None if self.console_logger is not None: result = self.console_logger.head() self.mtda.debug(3, "main.console_head(): %s" % str(result)) return result def console_lines(self, session=None): self.mtda.debug(3, "main.console_lines()") self._check_expired(session) result = None if self.console_logger is not None: result = self.console_logger.lines() self.mtda.debug(3, "main.console_lines(): %s" % str(result)) return result def console_locked(self, session=None): self.mtda.debug(3, "main.console_locked()") self._check_expired(session) result = self._check_locked(session) self.mtda.debug(3, "main.console_locked(): %s" % str(result)) return result def console_print(self, data, session=None): self.mtda.debug(3, "main.console_print()") self._check_expired(session) result = None if self.console_logger is not None: result = self.console_logger.print(data) self.mtda.debug(3, "main.console_print(): %s" % str(result)) return result def console_prompt(self, newPrompt=None, session=None): self.mtda.debug(3, "main.console_prompt()") self._check_expired(session) result = None if self.console_locked(session) is False and \ self.console_logger is not None: result = self.console_logger.prompt(newPrompt) self.mtda.debug(3, "main.console_prompt(): %s" % str(result)) return result def console_remote(self, host): self.mtda.debug(3, "main.console_remote()") result = None if self.is_remote is True: # Create and start our remote console self.console_output = RemoteConsoleOutput(host, self.conport) self.console_output.start() self.mtda.debug(3, "main.console_remote(): %s" % str(result)) return result def console_run(self, cmd, session=None): self.mtda.debug(3, "main.console_run()") self._check_expired(session) result = None if self.console_locked(session) is False and \ self.console_logger is not None: result = self.console_logger.run(cmd) self.mtda.debug(3, "main.console_run(): %s" % str(result)) return result def console_send(self, data, raw=False, session=None): self.mtda.debug(3, "main.console_send()") self._check_expired(session) result = None if self.console_locked(session) is False and \ self.console_logger is not None: result = self.console_logger.write(data, raw) self.mtda.debug(3, "main.console_send(): %s" % str(result)) return result def console_tail(self, session=None): self.mtda.debug(3, "main.console_tail()") self._check_expired(session) if self.console_locked(session) is False and \ self.console_logger is not None: result = self.console_logger.tail() self.mtda.debug(3, "main.console_tail(): %s" % str(result)) return result def debug(self, level, msg): if self.debug_level >= level: if self.debug_level == 0: prefix = "# " else: prefix = "# debug%d: " % level msg = str(msg).replace("\n", "\n%s ... " % prefix) lines = msg.splitlines() for line in lines: line = _make_printable(line) print("%s%s" % (prefix, line), file=sys.stderr) def env_get(self, name, session=None): self.mtda.debug(3, "env_get()") self._check_expired(session) result = None if name in self.env: result = self.env[name] self.mtda.debug(3, "env_get(): %s" % str(result)) return result def env_set(self, name, value, session=None): self.mtda.debug(3, "env_set()") self._check_expired(session) result = None if name in self.env: old_value = self.env[name] result = old_value else: old_value = value self.env[name] = value self.env["_%s" % name] = old_value self.mtda.debug(3, "env_set(): %s" % str(result)) return result def keyboard_write(self, str, session=None): self.mtda.debug(3, "main.keyboard_write()") self._check_expired(session) result = None if self.keyboard is not None: result = self.keyboard.write(str) self.mtda.debug(3, "main.keyboard_write(): %s" % str(result)) return result def power_locked(self, session=None): self.mtda.debug(3, "main.power_locked()") self._check_expired(session) if self.power_controller is None: result = True else: result = self._check_locked(session) self.mtda.debug(3, "main.power_locked(): %s" % str(result)) return result def storage_bytes_written(self, session=None): self.mtda.debug(3, "main.storage_bytes_written()") self._check_expired(session) result = self._storage_bytes_written self.mtda.debug(3, "main.storage_bytes_written(): %s" % str(result)) return result def storage_close(self, session=None): self.mtda.debug(3, "main.storage_close()") self._check_expired(session) if self.sdmux_controller is None: result = False else: self.bz2dec = None self.zdec = None if self._storage_opened is True: self._storage_opened = not self.sdmux_controller.close() result = (self._storage_opened is False) self.mtda.debug(3, "main.storage_close(): %s" % str(result)) return result def storage_locked(self, session=None): self.mtda.debug(3, "main.storage_locked()") self._check_expired(session) if self._check_locked(session): result = True # Cannot swap the shared storage device between the host and target # without a driver elif self.sdmux_controller is None: self.mtda.debug(4, "storage_locked(): no shared storage device") result = True # If hotplugging is supported, swap only if the shared storage # isn't opened elif self.sdmux_controller.supports_hotplug() is True: result = self._storage_opened # We also need a power controller to be safe elif self.power_controller is None: self.mtda.debug(4, "storage_locked(): no power controller") result = True # The target shall be OFF elif self.target_status() != "OFF": self.mtda.debug(4, "storage_locked(): target isn't off") result = True # Lastly, the shared storage device shall not be opened elif self._storage_opened is True: self.mtda.debug( 4, "storage_locked(): " "shared storage is in used (opened)") result = True # We may otherwise swap our shared storage device else: result = False self.mtda.debug(3, "main.storage_locked(): %s" % str(result)) return result def storage_mount(self, part=None, session=None): self.mtda.debug(3, "main.storage_mount()") self._check_expired(session) if self._storage_mounted is True: self.mtda.debug(4, "storage_mount(): already mounted") result = True elif self.sdmux_controller is None: self.mtda.debug(4, "storage_mount(): no shared storage device") return False else: result = self.sdmux_controller.mount(part) self._storage_mounted = (result is True) self.mtda.debug(3, "main.storage_mount(): %s" % str(result)) return result def storage_update(self, dst, offset, data, session=None): self.mtda.debug(3, "main.storage_update()") self._check_expired(session) if self.sdmux_controller is None: self.mtda.debug(4, "storage_update(): no shared storage device") result = -1 elif offset == 0: self._storage_bytes_written = 0 result = self.sdmux_controller.update(dst, offset, data) if result > 0: self._storage_bytes_written = self._storage_bytes_written + result self.mtda.debug(3, "main.storage_update(): %s" % str(result)) return result def storage_open(self, session=None): self.mtda.debug(3, "main.storage_open()") self._check_expired(session) if self.sdmux_controller is None: self.mtda.debug(1, "storage_open(): no shared storage device") result = False else: self.storage_close() self._storage_bytes_written = 0 result = self.sdmux_controller.open() self._storage_opened = (result is True) self.mtda.debug(3, "main.storage_open(): %s" % str(result)) return result def storage_status(self, session=None): self.mtda.debug(3, "main.storage_status()") self._check_expired(session) if self.sdmux_controller is None: self.mtda.debug(4, "storage_status(): no shared storage device") result = "???" else: result = self.sdmux_controller.status() self.mtda.debug(3, "main.storage_status(): %s" % str(result)) return result def _storage_write_bz2(self, data): self.mtda.debug(3, "main._storage_write_bz2()") # Decompress and write the newly received data uncompressed = self.bz2dec.decompress(data, self.blksz) result = self.sdmux_controller.write(uncompressed) if result is False: result = -1 else: self._storage_bytes_written += len(uncompressed) # Check if we can write more data without further input if self.bz2dec.needs_input is False: result = 0 else: # Data successfully uncompressed and written to the shared # storage device result = self.blksz self.mtda.debug(3, "main._storage_write_bz2(): %s" % str(result)) return result def storage_write_bz2(self, data, session=None): self.mtda.debug(3, "main.storage_write_bz2()") self._check_expired(session) if self.sdmux_controller is None: result = -1 else: # Create a bz2 decompressor when called for the first time if self.bz2dec is None: self.bz2dec = bz2.BZ2Decompressor() cont = True start = time.monotonic() result = -1 while cont is True: # Decompress and write newly received data try: # Uncompress and write data result = self._storage_write_bz2(data) if result != 0: # Either got an error or needing more data; escape from # this loop to provide feedback cont = False else: # Check if this loop has been running for quite # some time, in which case we would to give our # client an update now = time.monotonic() if (now - start) >= self.fbintvl: cont = False # If we should continue and do not need more data # at this time, use an empty buffer for the next # iteration elif result == 0: data = b'' except EOFError: # Handle multi-streams: create a new decompressor and # we will start with data unused from the previous # decompressor data = self.bz2dec.unused_data self.bz2dec = bz2.BZ2Decompressor() cont = (len(data) > 0) # loop only if we have unused data result = 0 # we do not need more input data self.mtda.debug(3, "main.storage_write_bz2(): %s" % str(result)) return result def _storage_write_gz(self, data): self.mtda.debug(3, "main._storage_write_gz()") # Decompress and write the newly received data uncompressed = self.zdec.decompress(data, self.blksz) status = self.sdmux_controller.write(uncompressed) if status is False: result = -1 else: self._storage_bytes_written += len(uncompressed) # Check if we can write more data without further input if len(self.zdec.unconsumed_tail) > 0: result = 0 else: # Data successfully uncompressed and written to the shared # storage device result = self.blksz self.mtda.debug(3, "main._storage_write_gz(): %s" % str(result)) return result def storage_write_gz(self, data, session=None): self.mtda.debug(3, "main.storage_write_gz()") self._check_expired(session) if self.sdmux_controller is None: result = -1 else: # Create a zlib decompressor when called for the first time if self.zdec is None: self.zdec = zlib.decompressobj(16 + zlib.MAX_WBITS) # Check if we should use unconsumed data from the previous call if len(data) == 0: data = self.zdata cont = True start = time.monotonic() result = -1 while cont is True: # Decompress and write newly received data result = self._storage_write_gz(data) self.zdata = None if result != 0: # Either got an error or needing more data; escape from # this loop to provide feedback cont = False else: # If we should continue and do not need more data at this # time, use the unconsumed data for the next iteration data = self.zdec.unconsumed_tail # Check if this loop has been running for quite some time, # in which case we would to give our client an update now = time.monotonic() if (now - start) >= self.fbintvl: self.zdata = data cont = False self.mtda.debug(3, "main.storage_write_gz(): %s" % str(result)) return result def storage_write_raw(self, data, session=None): self.mtda.debug(3, "main.storage_write_raw()") self._check_expired(session) if self.sdmux_controller is None: self.mtda.debug(1, "main.storage_write_raw(): no sdmux!") result = -1 else: result = self.sdmux_controller.write(data) if result is False: self.mtda.debug(1, "main.storage_write_raw(): write() failed") result = -1 else: self._storage_bytes_written += len(data) result = self.blksz self.mtda.debug(3, "main.storage_write_raw(): %s" % str(result)) return result def storage_to_host(self, session=None): self.mtda.debug(3, "main.storage_to_host()") self._check_expired(session) if self.storage_locked(session) is False: result = self.sdmux_controller.to_host() else: self.mtda.debug(1, "storage_to_host(): shared storage is locked") result = False self.mtda.debug(3, "main.storage_to_host(): %s" % str(result)) return result def storage_to_target(self, session=None): self.mtda.debug(3, "main.storage_to_target()") self._check_expired(session) if self.storage_locked(session) is False: self.storage_close() result = self.sdmux_controller.to_target() else: self.mtda.debug(1, "storage_to_target(): shared storage is locked") result = False self.mtda.debug(3, "main.storage_to_target(): %s" % str(result)) return result def storage_swap(self, session=None): self.mtda.debug(3, "main.storage_swap()") self._check_expired(session) if self.storage_locked(session) is False: result = self.storage_status(session) if result == self.sdmux_controller.SD_ON_HOST: self.sdmux_controller.to_target() elif result == self.sdmux_controller.SD_ON_TARGET: self.sdmux_controller.to_host() result = self.storage_status(session) return result self.mtda.debug(3, "main.storage_swap(): %s" % str(result)) return result def toggle_timestamps(self): self.mtda.debug(3, "main.toggle_timestamps()") if self.console_logger is not None: result = self.console_logger.toggle_timestamps() else: print("no console configured/found!", file=sys.stderr) result = None self.mtda.debug(3, "main.toggle_timestamps(): %s" % str(result)) return result def target_lock(self, session): self.mtda.debug(3, "main.target_lock()") self._check_expired(session) owner = self.target_owner() if owner is None or owner == session: self._lock_owner = session result = True else: result = False self.mtda.debug(3, "main.target_lock(): %s" % str(result)) return result def target_locked(self, session): self.mtda.debug(3, "main.target_locked()") self._check_expired(session) return self._check_locked(session) def target_owner(self): self.mtda.debug(3, "main.target_owner()") return self._lock_owner def _parse_script(self, script): self.mtda.debug(3, "main._parse_script()") result = None if script is not None: result = script.replace("... ", " ") self.mtda.debug(3, "main._parse_script(): %s" % str(result)) return result def exec_power_on_script(self): self.mtda.debug(3, "main.exec_power_on_script()") result = None if self.power_on_script: self.mtda.debug( 4, "exec_power_on_script(): " "%s" % self.power_on_script) result = exec(self.power_on_script, { "env": self.env, "mtda": self }) self.mtda.debug(3, "main.exec_power_on_script(): %s" % str(result)) return result def target_on(self, session=None): self.mtda.debug(3, "main.target_on()") if self.console_logger is not None: self.console_logger.resume() self._check_expired(session) result = False if self.power_locked(session) is False: result = self.power_controller.on() if result is True: self.exec_power_on_script() self.mtda.debug(3, "main.target_on(): %s" % str(result)) return result def exec_power_off_script(self): self.mtda.debug(3, "main.exec_power_off_script()") if self.power_off_script: exec(self.power_off_script, {"env": self.env, "mtda": self}) def target_off(self, session=None): self.mtda.debug(3, "main.target_off()") result = False self._check_expired(session) if self.power_locked(session) is False: result = self.power_controller.off() if self.keyboard is not None: self.keyboard.idle() if self.console_logger is not None: self.console_logger.reset_timer() if result is True: self.console_logger.pause() self.exec_power_off_script() self.mtda.debug(3, "main.target_off(): %s" % str(result)) return result def target_status(self, session=None): self.mtda.debug(3, "main.target_status()") self._check_expired(session) if self.power_controller is None: result = "???" else: result = self.power_controller.status() self.mtda.debug(3, "main.target_status(): %s" % str(result)) return result def target_toggle(self, session=None): self.mtda.debug(3, "main.target_toggle()") self._check_expired(session) if self.power_locked(session) is False: result = self.power_controller.toggle() if result == self.power_controller.POWER_ON: if self.console_logger is not None: self.console_logger.resume() self.exec_power_on_script() elif result == self.power_controller.POWER_OFF: self.exec_power_off_script() if self.console_logger is not None: self.console_logger.pause() self.console_logger.reset_timer() else: result = self.power_controller.POWER_LOCKED self.mtda.debug(3, "main.target_toggle(): %s" % str(result)) return result def target_unlock(self, session): self.mtda.debug(3, "main.target_unlock()") result = False self._check_expired(session) if self.target_owner() == session: self._lock_owner = None result = True self.mtda.debug(3, "main.target_unlock(): %s" % str(result)) return result def usb_find_by_class(self, className, session=None): self.mtda.debug(3, "main.usb_find_by_class()") self._check_expired(session) ports = len(self.usb_switches) ndx = 0 while ndx < ports: usb_switch = self.usb_switches[ndx] if usb_switch.className == className: return usb_switch ndx = ndx + 1 return None def usb_has_class(self, className, session=None): self.mtda.debug(3, "main.usb_has_class()") self._check_expired(session) usb_switch = self.usb_find_by_class(className, session) return usb_switch is not None def usb_off(self, ndx, session=None): self.mtda.debug(3, "main.usb_off()") self._check_expired(session) try: if ndx > 0: usb_switch = self.usb_switches[ndx - 1] usb_switch.off() except IndexError: print("invalid USB switch #" + str(ndx), file=sys.stderr) def usb_off_by_class(self, className, session=None): self.mtda.debug(3, "main.usb_off_by_class()") self._check_expired(session) usb_switch = self.usb_find_by_class(className, session) if usb_switch is not None: return usb_switch.off() return False def usb_on(self, ndx, session=None): self.mtda.debug(3, "main.usb_on()") self._check_expired(session) try: if ndx > 0: usb_switch = self.usb_switches[ndx - 1] usb_switch.on() except IndexError: print("invalid USB switch #" + str(ndx), file=sys.stderr) def usb_on_by_class(self, className, session=None): self.mtda.debug(3, "main.usb_on_by_class()") self._check_expired(session) usb_switch = self.usb_find_by_class(className, session) if usb_switch is not None: return usb_switch.on() return False def usb_ports(self, session=None): self.mtda.debug(3, "main.usb_ports()") self._check_expired(session) return len(self.usb_switches) def usb_status(self, ndx, session=None): self.mtda.debug(3, "main.usb_status()") self._check_expired(session) try: if ndx > 0: usb_switch = self.usb_switches[ndx - 1] status = usb_switch.status() if status == usb_switch.POWERED_OFF: return "OFF" elif status == usb_switch.POWERED_ON: return "ON" else: return "???" except IndexError: print("invalid USB switch #" + str(ndx), file=sys.stderr) return "ERR" return "???" def usb_toggle(self, ndx, session=None): self.mtda.debug(3, "main.usb_toggle()") self._check_expired(session) try: if ndx > 0: usb_switch = self.usb_switches[ndx - 1] usb_switch.toggle() except IndexError: print("invalid USB switch #" + str(ndx), file=sys.stderr) def load_config(self, remote=None, is_server=False): self.mtda.debug(3, "main.load_config()") self.remote = remote self.is_remote = remote is not None self.is_server = is_server parser = configparser.ConfigParser() configs_found = parser.read(self.config_files) if parser.has_section('main'): self.load_main_config(parser) if parser.has_section('environment'): self.load_environment(parser) if parser.has_section('remote'): self.load_remote_config(parser) if self.is_remote is False: if parser.has_section('power'): self.load_power_config(parser) if parser.has_section('console'): self.load_console_config(parser) if parser.has_section('keyboard'): self.load_keyboard_config(parser) if parser.has_section('sdmux'): self.load_sdmux_config(parser) if parser.has_section('usb'): self.load_usb_config(parser) if parser.has_section('scripts'): scripts = parser['scripts'] self.power_on_script = self._parse_script( scripts.get('power on', None)) self.power_off_script = self._parse_script( scripts.get('power off', None)) def load_main_config(self, parser): self.mtda.debug(3, "main.load_main_config()") self.mtda.debug_level = int( parser.get('main', 'debug', fallback=self.mtda.debug_level)) self.mtda.fuse = parser.getboolean('main', 'fuse', fallback=self.mtda.fuse) def load_environment(self, parser): self.mtda.debug(3, "main.load_environment()") for opt in parser.options('environment'): value = parser.get('environment', opt) self.mtda.debug( 4, "main.load_environment(): " "%s => %s" % (opt, value)) self.env_set(opt, value) def load_console_config(self, parser): self.mtda.debug(3, "main.load_console_config()") try: # Get variant variant = parser.get('console', 'variant') # Try loading its support class mod = importlib.import_module("mtda.console." + variant) factory = getattr(mod, 'instantiate') self.console = factory(self) self.console.variant = variant # Configure the console self.console.configure(dict(parser.items('console'))) except configparser.NoOptionError: print('console variant not defined!', file=sys.stderr) except ImportError: print('console "%s" could not be found/loaded!' % (variant), file=sys.stderr) def load_keyboard_config(self, parser): self.mtda.debug(3, "main.load_keyboard_config()") try: # Get variant variant = parser.get('keyboard', 'variant') # Try loading its support class mod = importlib.import_module("mtda.keyboard." + variant) factory = getattr(mod, 'instantiate') self.keyboard = factory(self) # Configure the keyboard controller self.keyboard.configure(dict(parser.items('keyboard'))) self.keyboard.probe() except configparser.NoOptionError: print('keyboard controller variant not defined!', file=sys.stderr) except ImportError: print('keyboard controller "%s" could not be found/loaded!' % (variant), file=sys.stderr) def load_power_config(self, parser): self.mtda.debug(3, "main.load_power_config()") try: # Get variant variant = parser.get('power', 'variant') # Try loading its support class mod = importlib.import_module("mtda.power." + variant) factory = getattr(mod, 'instantiate') self.power_controller = factory(self) self.power_controller.variant = variant # Configure the power controller self.power_controller.configure(dict(parser.items('power'))) except configparser.NoOptionError: print('power controller variant not defined!', file=sys.stderr) except ImportError: print('power controller "%s" could not be found/loaded!' % (variant), file=sys.stderr) def load_sdmux_config(self, parser): self.mtda.debug(3, "main.load_sdmux_config()") try: # Get variant variant = parser.get('sdmux', 'variant') # Try loading its support class mod = importlib.import_module("mtda.sdmux." + variant) factory = getattr(mod, 'instantiate') self.sdmux_controller = factory(self) # Configure the sdmux controller self.sdmux_controller.configure(dict(parser.items('sdmux'))) except configparser.NoOptionError: print('sdmux controller variant not defined!', file=sys.stderr) except ImportError: print('power controller "%s" could not be found/loaded!' % (variant), file=sys.stderr) def load_remote_config(self, parser): self.mtda.debug(3, "main.load_remote_config()") self.conport = int( parser.get('remote', 'console', fallback=self.conport)) self.ctrlport = int( parser.get('remote', 'control', fallback=self.ctrlport)) if self.is_server is False: if self.remote is None: # Load remote setting from the configuration self.remote = parser.get('remote', 'host', fallback=self.remote) # Allow override from the environment self.remote = os.getenv('MTDA_REMOTE', self.remote) else: self.remote = None self.is_remote = self.remote is not None def load_usb_config(self, parser): self.mtda.debug(3, "main.load_usb_config()") try: # Get number of ports usb_ports = int(parser.get('usb', 'ports')) for port in range(0, usb_ports): port = port + 1 section = "usb" + str(port) if parser.has_section(section): self.load_usb_port_config(parser, section) except configparser.NoOptionError: usb_ports = 0 def load_usb_port_config(self, parser, section): self.mtda.debug(3, "main.load_usb_port_config()") try: # Get attributes className = parser.get(section, 'class', fallback="") variant = parser.get(section, 'variant') # Try loading its support class mod = importlib.import_module("mtda.usb." + variant) factory = getattr(mod, 'instantiate') usb_switch = factory(self) # Configure and probe the USB switch usb_switch.configure(dict(parser.items(section))) usb_switch.probe() # Store other attributes usb_switch.className = className # Add this USB switch self.usb_switches.append(usb_switch) except configparser.NoOptionError: print('usb switch variant not defined!', file=sys.stderr) except ImportError: print('usb switch "%s" could not be found/loaded!' % (variant), file=sys.stderr) def start(self): self.mtda.debug(3, "main.start()") if self.is_remote is True: return True # Probe the specified power controller if self.power_controller is not None: status = self.power_controller.probe() if status is False: print('Probe of the Power Controller failed!', file=sys.stderr) return False # Probe the specified sdmux controller if self.sdmux_controller is not None: status = self.sdmux_controller.probe() if status is False: print('Probe of the shared storage device failed!', file=sys.stderr) return False if self.console is not None: # Create a publisher if self.is_server is True: context = zmq.Context() socket = context.socket(zmq.PUB) socket.bind("tcp://*:%s" % self.conport) else: socket = None # Create and start console logger status = self.console.probe() if status is False: print('Probe of the %s console failed!' % (self.console.variant), file=sys.stderr) return False self.console_logger = ConsoleLogger(self, self.console, socket, self.power_controller) self.console_logger.start() return True def _check_expired(self, session): self.mtda.debug(3, "main._check_expired()") if self._lock_owner: now = time.monotonic() if session == self._lock_owner: self._lock_expiry = now + (self._lock_timeout * 60) elif now >= self._lock_expiry: self._lock_owner = None def _check_locked(self, session): self.mtda.debug(3, "main._check_locked()") owner = self.target_owner() if owner is None: return False status = False if session == owner else True return status