Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc fixes #199

Merged
merged 18 commits into from
Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions mtda-cli
Original file line number Diff line number Diff line change
Expand Up @@ -747,13 +747,16 @@ class Application:
print("MTDA version: %s" % agent.version)

def main(self):
config = None
daemonize = False
detach = True

options, stuff = getopt.getopt(
sys.argv[1:], 'dhnr:v',
sys.argv[1:], 'c:dhnr:v',
['daemon', 'help', 'no-detach', 'remote=', 'version'])
for opt, arg in options:
if opt in ('-c', '--config'):
config = arg
if opt in ('-d', '--daemon'):
daemonize = True
if opt in ('-h', '--help'):
Expand All @@ -770,7 +773,7 @@ class Application:
# Start our server
if daemonize is True:
self.agent = MultiTenantDeviceAccess()
self.agent.load_config(self.remote, daemonize)
self.agent.load_config(self.remote, daemonize, config)
self.remote = self.agent.remote
if detach is True:
status = self.daemonize()
Expand Down Expand Up @@ -805,7 +808,7 @@ class Application:
if cmd in cmds:
if cmd != 'help':
# Start our agent
self.agent = Client(self.remote)
self.agent = Client(self.remote, config_files=config)
self.remote = self.agent.remote()
self.agent.start()
status = cmds[cmd](stuff)
Expand Down
10 changes: 8 additions & 2 deletions mtda/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@

class Client:

def __init__(self, host=None, session=None):
def __init__(self, host=None, session=None, config_files=None):
agent = MultiTenantDeviceAccess()
agent.load_config(host)
agent.load_config(host, config_files=config_files)
if agent.remote is not None:
uri = "tcp://%s:%d" % (agent.remote, agent.ctrlport)
self._impl = zerorpc.Client(heartbeat=CONSTS.RPC.HEARTBEAT,
Expand Down Expand Up @@ -54,6 +54,12 @@ def __init__(self, host=None, session=None):
def agent_version(self):
return self._impl.agent_version()

def config_set_power_timeout(self, timeout):
return self._impl.config_set_power_timeout(timeout, self._session)

def config_set_session_timeout(self, timeout):
return self._impl.config_set_session_timeout(timeout, self._session)

def console_prefix_key(self):
return self._agent.console_prefix_key()

Expand Down
4 changes: 1 addition & 3 deletions mtda/console/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import sys
import threading
import time
import zmq


class ConsoleLogger:
Expand Down Expand Up @@ -210,8 +209,7 @@ def toggle_timestamps(self):
def _print(self, data):
if self.prints is True:
if self.socket is not None:
self.socket.send(self.topic, flags=zmq.SNDMORE)
self.socket.send(data)
self.mtda.publish(self.topic, data)
else:
# Write to stdout if received are not pushed to the network
sys.stdout.buffer.write(data)
Expand Down
11 changes: 11 additions & 0 deletions mtda/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,22 @@ class MDNS:
TYPE = '_MTDA._tcp.local.'


class POWER:
OFF = "OFF"
ON = "ON"
UNSURE = "???"
LOCKED = "LOCKED"


class RPC:
HEARTBEAT = 20
TIMEOUT = 2*60


class SESSION:
MIN_TIMEOUT = 10


class WRITER:
QUEUE_SLOTS = 16
QUEUE_TIMEOUT = 5
Expand Down
126 changes: 91 additions & 35 deletions mtda/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def __init__(self):
self._session_lock = threading.Lock()
self._session_timer = None
self._sessions = {}
self._socket_lock = threading.Lock()
self._time_from_pwr = None
self._time_from_str = None
self._time_until_str = None
Expand Down Expand Up @@ -121,6 +122,40 @@ def command(self, args, session=None):
self.mtda.debug(3, "main.command(): %s" % str(result))
return result

def config_set_power_timeout(self, timeout, session=None):
self.mtda.debug(3, "main.config_set_power_timeout()")

result = self._power_timeout
self._power_timeout = timeout
if timeout == 0:
self._power_expiry = None
self._session_check()

self.mtda.debug(3, "main.config_set_power_timeout(): "
"{}".format(result))
return result

def config_set_session_timeout(self, timeout, session=None):
self.mtda.debug(3, "main.config_set_session_timeout()")

if timeout < CONSTS.SESSION.MIN_TIMEOUT:
timeout = CONSTS.SESSION.MIN_TIMEOUT

result = self._session_timeout
self._session_timeout = timeout

with self._session_lock:
now = time.monotonic()
for s in self._sessions:
left = self._sessions[s] - now
if left > timeout:
self._sessions[s] = now + timeout
self._session_check()

self.mtda.debug(3, "main.config_set_session_timeout(): "
"{}".format(result))
return result

def console_prefix_key(self):
self.mtda.debug(3, "main.console_prefix_key()")
return self.prefix_key
Expand Down Expand Up @@ -218,7 +253,7 @@ def console_lines(self, session=None):
self.mtda.debug(3, "main.console_lines()")

self._session_check(session)
result = None
result = 0
if self.console_logger is not None:
result = self.console_logger.lines()

Expand Down Expand Up @@ -459,6 +494,12 @@ def power_locked(self, session=None):
self.mtda.debug(3, "main.power_locked(): %s" % str(result))
return result

def publish(self, topic, data):
if self.socket is not None:
with self._socket_lock:
self.socket.send(topic, flags=zmq.SNDMORE)
self.socket.send(data)

def _storage_event(self, status):
self.notify("STORAGE %s" % status)

Expand Down Expand Up @@ -719,9 +760,9 @@ def target_owner(self):

def _power_event(self, status):
self._power_expiry = None
if status == self.power_controller.POWER_ON:
if status == CONSTS.POWER.ON:
self._uptime = time.monotonic()
elif status == self.power_controller.POWER_OFF:
elif status == CONSTS.POWER.OFF:
self._uptime = 0

for m in self.power_monitors:
Expand Down Expand Up @@ -761,7 +802,7 @@ def _target_on(self, session=None):
if self.console_logger is not None:
self.console_logger.resume()
self.exec_power_on_script()
self._power_event(self.power_controller.POWER_ON)
self._power_event(CONSTS.POWER.ON)

self.mtda.debug(3, "main._target_on(): %s" % str(result))
return result
Expand All @@ -773,7 +814,7 @@ def target_on(self, session=None):
self._session_check(session)

status = self.target_status()
if status != self.power_controller.POWER_ON:
if status != CONSTS.POWER.ON:
result = False
if self.power_locked(session) is False:
result = self._target_on(session)
Expand All @@ -790,15 +831,17 @@ def exec_power_off_script(self):
def _target_off(self, session=None):
self.mtda.debug(3, "main._target_off()")

result = self.power_controller.off()
result = True
if self.power_controller is not None:
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._power_event(CONSTS.POWER.OFF)

self.mtda.debug(3, "main._target_off(): %s" % str(result))
return result
Expand All @@ -810,7 +853,7 @@ def target_off(self, session=None):
self._session_check(session)

status = self.target_status()
if status != self.power_controller.POWER_OFF:
if status != CONSTS.POWER.OFF:
result = False
if self.power_locked(session) is False:
result = self._target_off(session)
Expand All @@ -821,9 +864,8 @@ def target_off(self, session=None):
def target_status(self, session=None):
self.mtda.debug(3, "main.target_status()")

self._session_check(session)
if self.power_controller is None:
result = "???"
result = CONSTS.POWER.UNSURE
else:
result = self.power_controller.status()

Expand All @@ -836,19 +878,19 @@ def target_toggle(self, session=None):
self._session_check(session)
if self.power_locked(session) is False:
result = self.power_controller.toggle()
if result == self.power_controller.POWER_ON:
if result == CONSTS.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._power_event(CONSTS.POWER.ON)
elif result == CONSTS.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)
self._power_event(CONSTS.POWER.OFF)
else:
result = self.power_controller.POWER_LOCKED
result = CONSTS.POWER.LOCKED

self.mtda.debug(3, "main.target_toggle(): %s" % str(result))
return result
Expand Down Expand Up @@ -984,14 +1026,20 @@ def video_url(self, host="", opts=None):
self.mtda.debug(3, "main.video_url(): %s" % str(result))
return result

def load_config(self, remote=None, is_server=False):
def load_config(self, remote=None, is_server=False, config_files=None):
self.mtda.debug(3, "main.load_config()")

if config_files is None:
config_files = os.getenv('MTDA_CONFIG', self.config_files)

self.mtda.debug(2, "main.load_config(): "
"config_files={}".format(config_files))

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)
configs_found = parser.read(config_files)
if configs_found is False:
return

Expand Down Expand Up @@ -1224,6 +1272,10 @@ def load_timeouts_config(self, parser):
self._session_timeout = int(parser.get(s, "session",
fallback=CONSTS.DEFAULTS.SESSION_TIMEOUT))

self._lock_timeout = self._lock_timeout * 60
self._power_timeout = self._power_timeout * 60
self._session_timeout = self._session_timeout * 60

self.mtda.debug(3, "main.load_timeouts_config: %s" % str(result))
return result

Expand Down Expand Up @@ -1303,8 +1355,9 @@ def notify(self, what):

result = None
if self.socket is not None:
self.socket.send(CONSTS.CHANNEL.EVENTS, flags=zmq.SNDMORE)
self.socket.send_string(what)
with self._socket_lock:
self.socket.send(CONSTS.CHANNEL.EVENTS, flags=zmq.SNDMORE)
self.socket.send_string(what)

self.mtda.debug(3, "main.notify: %s" % str(result))
return result
Expand Down Expand Up @@ -1391,8 +1444,8 @@ def start(self):
self._www.start()

if self.is_server is True:
self._session_timer = mtda.utils.RepeatTimer(60,
self._session_check)
handler = self._session_check
self._session_timer = mtda.utils.RepeatTimer(10, handler)
self._session_timer.start()

# Start from a known state
Expand Down Expand Up @@ -1448,37 +1501,40 @@ def _session_check(self, session=None):
if session is not None:
if session not in self._sessions:
events.append("ACTIVE %s" % session)
self._sessions[session] = now + (self._session_timeout * 60)
self._sessions[session] = now + self._session_timeout

# Check for inactive sessions
inactive = []
for s in self._sessions:
left = self._sessions[s] - now
self.mtda.debug(2, "session %s: %d seconds" % (s, left))
self.mtda.debug(3, "session %s: %d seconds" % (s, left))
if left <= 0:
inactive.append(s)
for s in inactive:
events.append("INACTIVE %s" % s)
self._sessions.pop(s, "")

# Check if we should arm the auto power-off timer
if (self._power_expiry is not None and
self._power_timeout > 0 and
len(self._sessions) == 0):

self.mtda.debug(2, "device will be powered down in %d "
"minutes" % self._power_timeout)
self._power_expiry = now + (self._power_timeout * 60)

if len(self._sessions) == 0:
# i.e. when the last session is removed and a power timeout
# was set
if len(self._sessions) == 0 and self._power_timeout > 0:
self._power_expiry = now + self._power_timeout
self.mtda.debug(2, "device will be powered down in {} "
"seconds".format(self._power_timeout))

if len(self._sessions) > 0:
# There are active sessions: reset power expiry
self._power_expiry = None
else:
# Otherwise check if we should auto-power off the target
if self._power_expiry is not None and now > self._power_expiry:
self._lock_expiry = 0
power_off = True

# Release device if the session owning the lock is idle
if self._lock_owner is not None:
if session == self._lock_owner:
self._lock_expiry = now + (self._lock_timeout * 60)
self._lock_expiry = now + self._lock_timeout
elif now >= self._lock_expiry:
events.append("UNLOCKED %s" % self._lock_owner)
self._lock_owner = None
Expand All @@ -1490,8 +1546,8 @@ def _session_check(self, session=None):
# Check if we should auto power-off the device
if power_off is True:
self._target_off()
self.mtda.debug(2, "device powered down after %d minutes of "
"inactivity" % self._power_timeout)
self.mtda.debug(2, "device powered down after {} seconds of "
"inactivity".format(self._power_timeout))

self.mtda.debug(3, "main._session_check: %s" % str(result))
return result
Expand Down
Loading