Skip to content

Commit

Permalink
Add option to shutdown or reboot coreserver system
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Buesch <m@bues.ch>
  • Loading branch information
mbuesch committed Jan 25, 2019
1 parent 28b2e86 commit 226e28c
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 26 deletions.
12 changes: 11 additions & 1 deletion awlsim-client
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ def usage():
print("Actions to be performed on the server:")
print(" -r|--runstate RUN/STOP Set the run state of the CPU.")
print(" -S|--stats Fetch and display CPU statistics.")
print(" --shutdown Shutdown the core server system.")
print(" --reboot Reboot the core server system.")

def main():
opt_connect = (AwlSimServer.DEFAULT_HOST, AwlSimServer.DEFAULT_PORT)
Expand All @@ -114,7 +116,7 @@ def main():
"hc:t:L:sP:r:S",
[ "help", "connect=", "timeout=", "loglevel=",
"ssh-tunnel", "ssh-passphrase=", "ssh-user=", "ssh-port=", "ssh-localport=", "ssh-exe=",
"runstate=", "stats", ])
"runstate=", "stats", "shutdown", "reboot", ])
except getopt.GetoptError as e:
printError(str(e))
usage()
Expand Down Expand Up @@ -177,6 +179,10 @@ def main():
sys.exit(1)
if o in ("-S", "--stats"):
actions.append(("stats", None))
if o == "--shutdown":
actions.append(("shutdown", None))
if o == "--reboot":
actions.append(("reboot", None))
if args:
usage()
return ExitCodes.EXIT_ERR_CMDLINE
Expand Down Expand Up @@ -213,6 +219,10 @@ def main():
client.setRunState(actionValue)
elif action == "stats":
printCpuStats(client.getCpuStats(sync=True))
elif action == "shutdown":
client.shutdownCoreServerSystem()
elif action == "reboot":
client.rebootCoreServerSystem()
else:
assert(0)
except AwlSimError as e:
Expand Down
43 changes: 26 additions & 17 deletions awlsim-server
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# AWL simulator - Server interface
#
# Copyright 2013-2016 Michael Buesch <m@bues.ch>
# Copyright 2013-2019 Michael Buesch <m@bues.ch>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -51,6 +51,7 @@ def usage():
print(" -6|--force-ipv6 Force the use of IPv6.")
print(" -B|--background Fork a background process")
print(" -w|--rw-project Enable project file writing")
print(" -S|--allow-shutdown Allow remote system shutdown")
print(" -L|--loglevel LVL Set the log level:")
print(" 0: Log nothing")
print(" 1: Log errors")
Expand All @@ -68,13 +69,14 @@ def main():
opt_listen = (AwlSimServer.DEFAULT_HOST, AwlSimServer.DEFAULT_PORT)
opt_family = None
opt_background = False
opt_allowShutdown = False
opt_loglevel = Logging.LOG_INFO

try:
(opts, args) = getopt.getopt(sys.argv[1:],
"hl:46BwL:",
"hl:46BwSL:",
[ "help", "listen=", "force-ipv4", "force-ipv6",
"background", "rw-project",
"background", "rw-project", "allow-shutdown",
"loglevel=", ])
except getopt.GetoptError as e:
printError(str(e))
Expand Down Expand Up @@ -104,6 +106,8 @@ def main():
opt_background = True
if o in ("-w", "--rw-project"):
opt_rwProject = True
if o in ("-S", "--allow-shutdown"):
opt_allowShutdown = True
if o in ("-L", "--loglevel"):
try:
opt_loglevel = int(v)
Expand All @@ -119,30 +123,35 @@ def main():
exitCode = ExitCodes.EXIT_OK
try:
Logging.setLoglevel(opt_loglevel)

commandMask = 0
if opt_allowShutdown:
commandMask |= AwlSimServer.CMDMSK_SHUTDOWN

if opt_background:
interpreter = sys.executable
assert(interpreter)
serverProcess = AwlSimServer.start(listenHost = opt_listen[0],
listenPort = opt_listen[1],
listenFamily = opt_family,
forkInterpreter = interpreter,
commandMask = 0,
projectFile = opt_project,
projectWriteBack = opt_rwProject)
serverProcess = AwlSimServer.start(listenHost=opt_listen[0],
listenPort=opt_listen[1],
listenFamily=opt_family,
forkInterpreter=interpreter,
commandMask=commandMask,
projectFile=opt_project,
projectWriteBack=opt_rwProject)
printInfo("Started awlsim server process (PID: %d)" %\
serverProcess.pid)
else:
if cython_helper.shouldUseCython():
printInfo("*** Using accelerated CYTHON core "
"(AWLSIM_CYTHON environment variable is set)")

exitCode = AwlSimServer.start(listenHost = opt_listen[0],
listenPort = opt_listen[1],
listenFamily = opt_family,
forkInterpreter = None,
commandMask = 0,
projectFile = opt_project,
projectWriteBack = opt_rwProject)
exitCode = AwlSimServer.start(listenHost=opt_listen[0],
listenPort=opt_listen[1],
listenFamily=opt_family,
forkInterpreter=None,
commandMask=commandMask,
projectFile=opt_project,
projectWriteBack=opt_rwProject)
except AwlSimError as e:
printError(e.getReport())
return ExitCodes.EXIT_ERR_SIM
Expand Down
2 changes: 1 addition & 1 deletion awlsim-server.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ User=@USER@
Group=@GROUP@
Nice=-15

ExecStart=@PYTHON@ @PREFIX@/bin/awlsim-server -l localhost -4 -w @PROJECT@
ExecStart=@PYTHON@ @PREFIX@/bin/awlsim-server -l localhost -4 -S -w @PROJECT@
ExecStartPost=-@PYTHON@ @PREFIX@/bin/awlsim-client -c localhost -r RUN

Environment=PYTHONPATH=@PYTHON_SITE@ PYTHONHASHSEED=0 PYTHONOPTIMIZE=2 PYTHONDONTWRITEBYTECODE=1 AWLSIM_CYTHON=1 AWLSIM_SCHED=realtime AWLSIM_PRIO=50 AWLSIM_AFFINITY=-1,-2,-3
Expand Down
31 changes: 28 additions & 3 deletions awlsim/coreclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,7 @@ def killSpawnedServer(self):

if self.__transceiver:
with contextlib.suppress(AwlSimError, MaintenanceRequest):
msg = AwlSimMessage_SHUTDOWN()
status = self.__sendAndWaitFor_REPLY(msg)
if status != AwlSimMessage_REPLY.STAT_OK:
if not self.shutdownCoreServer():
printError("AwlSimClient: Failed to shut "
"down server via message")

Expand Down Expand Up @@ -860,3 +858,30 @@ def getCpuStats(self, sync=False):
else:
self.__send(msg)
return True

def shutdownCoreServer(self):
"""Shut down the core server.
"""
if not self.__transceiver:
return False
msg = AwlSimMessage_SHUTDOWN(AwlSimMessage_SHUTDOWN.SHUTDOWN_CORE)
status = self.__sendAndWaitFor_REPLY(msg)
return status == AwlSimMessage_REPLY.STAT_OK

def shutdownCoreServerSystem(self):
"""Shut down the core server and the system it runs on.
"""
if not self.__transceiver:
return False
msg = AwlSimMessage_SHUTDOWN(AwlSimMessage_SHUTDOWN.SHUTDOWN_SYSTEM_HALT)
self.__send(msg)
return True

def rebootCoreServerSystem(self):
"""Reboot the core server and the system it runs on.
"""
if not self.__transceiver:
return False
msg = AwlSimMessage_SHUTDOWN(AwlSimMessage_SHUTDOWN.SHUTDOWN_SYSTEM_REBOOT)
self.__send(msg)
return True
82 changes: 81 additions & 1 deletion awlsim/coreserver/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,78 @@ class AwlSimMessage_PONG(AwlSimMessage):
class AwlSimMessage_RESET(AwlSimMessage):
msgId = AwlSimMessage.MSG_ID_RESET

# Payload struct:
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)

plStruct = struct.Struct(str(">IIIIIIII"))

def __init__(self):
pass

def toBytes(self):
pl = self.plStruct.pack(0, 0, 0, 0, 0, 0, 0, 0)
return AwlSimMessage.toBytes(self, len(pl)) + pl

@classmethod
def fromBytes(cls, payload):
try:
_, _, _, _, _, _, _, _ =\
cls.plStruct.unpack(payload)
except struct.error as e:
raise TransferError("RESET: Invalid data format")
return cls()

class AwlSimMessage_SHUTDOWN(AwlSimMessage):
msgId = AwlSimMessage.MSG_ID_SHUTDOWN

EnumGen.start
SHUTDOWN_CORE = EnumGen.item
SHUTDOWN_SYSTEM_HALT = EnumGen.item
SHUTDOWN_SYSTEM_REBOOT = EnumGen.item
EnumGen.end

SHUTDOWN_MAGIC = 0x7B8F

# Payload struct:
# magic number (16 bit)
# shutdownType (16 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)

plStruct = struct.Struct(str(">HHIIIIIII"))

def __init__(self, shutdownType):
self.shutdownType = shutdownType & 0xFFFF

def toBytes(self):
pl = self.plStruct.pack(self.SHUTDOWN_MAGIC,
self.shutdownType,
0, 0, 0, 0, 0, 0, 0)
return AwlSimMessage.toBytes(self, len(pl)) + pl

@classmethod
def fromBytes(cls, payload):
try:
magic, shutdownType, _, _, _, _, _, _, _ =\
cls.plStruct.unpack(payload)
if magic != cls.SHUTDOWN_MAGIC:
raise TransferError("SHUTDOWN: Incorrect magic number")
except struct.error as e:
raise TransferError("SHUTDOWN: Invalid data format")
return cls(shutdownType)

class AwlSimMessage_RUNSTATE(AwlSimMessage):
msgId = AwlSimMessage.MSG_ID_RUNSTATE

Expand All @@ -288,6 +357,17 @@ class AwlSimMessage_RUNSTATE(AwlSimMessage):
STATE_RUN = EnumGen.item
EnumGen.end

# Payload struct:
# runState (16 bit)
# reserved (16 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)
# reserved (32 bit)

plStruct = struct.Struct(str(">HHIIIIIII"))

def __init__(self, runState):
Expand Down Expand Up @@ -620,7 +700,7 @@ def fromBytes(cls, payload):
class AwlSimMessage_BUILD(AwlSimMessage):
msgId = AwlSimMessage.MSG_ID_BUILD

plStruct = struct.Struct(str(">16x"))
plStruct = struct.Struct(str(">32x"))

def toBytes(self):
try:
Expand Down
29 changes: 26 additions & 3 deletions awlsim/coreserver/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -956,9 +956,32 @@ def __rx_SHUTDOWN(self, client, msg):
printDebug("Received message: SHUTDOWN")
status = AwlSimMessage_REPLY.STAT_FAIL
if self.__commandMask & AwlSimServer.CMDMSK_SHUTDOWN:
printInfo("Exiting due to shutdown command")
self.setRunState(self.STATE_EXIT)
status = AwlSimMessage_REPLY.STAT_OK
if msg.shutdownType == msg.SHUTDOWN_CORE:
printInfo("Exiting due to shutdown command")
self.setRunState(self.STATE_EXIT)
status = AwlSimMessage_REPLY.STAT_OK
elif msg.shutdownType == msg.SHUTDOWN_SYSTEM_HALT:
if osIsLinux:
printInfo("Halting system due to shutdown command")
self.setRunState(self.STATE_EXIT)
process = PopenWrapper(["/sbin/shutdown"],
AwlSimEnv.getEnv())
process.wait()
status = AwlSimMessage_REPLY.STAT_OK
else:
printError("Halting system is not supported.")
elif msg.shutdownType == msg.SHUTDOWN_SYSTEM_REBOOT:
if osIsLinux:
printInfo("Rebooting system due to shutdown command")
self.setRunState(self.STATE_EXIT)
process = PopenWrapper(["/sbin/reboot"],
AwlSimEnv.getEnv())
process.wait()
status = AwlSimMessage_REPLY.STAT_OK
else:
printError("Rebooting system is not supported.")
else:
printError("Unknown shutdown command")
client.transceiver.send(AwlSimMessage_REPLY.make(msg, status))

def __rx_RUNSTATE(self, client, msg):
Expand Down

0 comments on commit 226e28c

Please sign in to comment.