Commit 1db23353 authored by Jérome Perrin's avatar Jérome Perrin

standalone wip shutdown

parent d7c27e53
......@@ -111,6 +111,7 @@ class SupervisorConfigWriter(ConfigWriter):
"""Iterator on parts of formatted config.
"""
standalone_slapos = self._standalone_slapos
pid = os.getpid()
yield textwrap.dedent(
"""
[unix_http_server]
......@@ -132,6 +133,11 @@ class SupervisorConfigWriter(ConfigWriter):
startretries = 0
startsecs = 0
[program:standalone-auto-shutdown]
command = python {standalone_slapos._auto_shutdown_script} {pid} {standalone_slapos._supervisor_config}
startretries = 0
startsecs = 0
""".format(**locals()))
for program, program_config in standalone_slapos._slapos_commands.items():
......@@ -192,6 +198,46 @@ class SlapOSCommandWriter(ConfigWriter):
os.chmod(path, 0o755)
class AutoShutownScriptWriter(ConfigWriter):
"""Write an etc/standalone_auto_shutdown.py script.
"""
def writeConfig(self, path):
with open(path, 'w') as f:
f.write(
textwrap.dedent(
"""\
#!/usr/bin/env python
from __future__ import print_function
import os
import sys
import time
import subprocess
monitored_pid = int(sys.argv[1])
config_file = sys.argv[2]
def isAlive(pid):
try:
os.kill(pid, 0)
except OSError:
return False
return True
print ("Watching PID", monitored_pid)
while True:
is_alive = isAlive(monitored_pid)
if not is_alive:
print ("Process is no longer alive, terminating")
subprocess.call([
'supervisorctl', '-c', config_file,
'start', 'slapos-node-shutdown-instance', ])
time.sleep(1)
subprocess.call(['supervisorctl', '-c', config_file, 'shutdown'])
time.sleep(1)
"""))
@zope.interface.implementer(ISupply, IRequester)
class StandaloneSlapOS(object):
"""A SlapOS that can be embedded in other applications, also useful for testing.
......@@ -295,6 +341,7 @@ class StandaloneSlapOS(object):
ensureDirectoryExists(etc_directory)
self._supervisor_config = os.path.join(etc_directory, 'supervisord.conf')
self._slapos_config = os.path.join(etc_directory, 'slapos.cfg')
self._auto_shutdown_script = os.path.join(etc_directory, 'standalone_auto_shutdown.py')
var_directory = os.path.join(base_directory, 'var')
ensureDirectoryExists(var_directory)
......@@ -322,6 +369,7 @@ class StandaloneSlapOS(object):
SupervisorConfigWriter(self).writeConfig(self._supervisor_config)
SlapOSConfigWriter(self).writeConfig(self._slapos_config)
SlapOSCommandWriter(self).writeConfig(self._slapos_bin)
AutoShutownScriptWriter(self).writeConfig(self._auto_shutdown_script)
self.start()
......@@ -541,6 +589,20 @@ class StandaloneSlapOS(object):
time.sleep(i * 0.01)
raise RuntimeError("Shutdown failed")
def detach(self):
"""By default, StandaloneSlapOS will automatically stop when the process which
started it is no longer alive, calling `detach` disable this behavior. After
detaching, the process will no longer be watched.
"""
with self.system_supervisor_rpc as supervisor:
supervisor.stopProcess("standalone-auto-shutdown", True)
def reattach(self):
"""Reattach a detached StandaloneSlapOS
"""
# TODO: update command with new PID and restart
raise NotImplementedError()
def waitForSoftware(self, max_retry=0, debug=False, error_lines=30):
"""Synchronously install or uninstall all softwares previously supplied/removed.
......
......@@ -34,6 +34,8 @@ import shutil
import hashlib
import socket
import errno
import time
import multiprocessing
from contextlib import closing
from slapos.slap.standalone import StandaloneSlapOS
......@@ -337,3 +339,63 @@ class TestSlapOSStandaloneInstance(SlapOSStandaloneTestCase):
self.standalone.waitForReport()
self.assertFalse(
os.path.exists(os.path.join(parition_directory, 'instance.check')))
class TestAutoShutdown(unittest.TestCase):
def setUp(self):
checkPortIsFree()
self.working_dir = tempfile.mkdtemp(prefix=__name__)
self.addCleanup(shutil.rmtree, self.working_dir)
def f(working_dir, q):
"""This process will start a StandaloneSlapOS and execute action put in q.
"""
standalone = StandaloneSlapOS(
working_dir, SLAPOS_TEST_IPV4, SLAPOS_TEST_PORT)
standalone.format(1, SLAPOS_TEST_IPV4, SLAPOS_TEST_IPV6)
q.put("ready")
command = q.get()
if command == "detach":
standalone.detach()
for i in range(100):
time.sleep(.1)
self.q = multiprocessing.Queue()
# Start the subprocess and wait for it to start its StandaloneSlapOS.
self.p = multiprocessing.Process(target=f, args=(self.working_dir, self.q))
self.p.start()
self.assertEqual("ready", self.q.get())
def test_autoshutdown(self):
self.q.put("nothing")
# the slapos is usable
# TODO
import pdb
pdb.set_trace()
# terminate the process
self.p.terminate()
self.p.join()
self.assertFalse(self.p.is_alive())
# the slapos is terminated
# TODO
def test_detach(self):
self.q.put("detach")
# slapos instance is usable
# TODO
# terminate the process
self.p.terminate()
self.p.join()
self.assertFalse(self.p.is_alive())
# the slapos is not terminated
# TODO
# terminate it
# TODO
# TODO:
# test_reattach
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment