Skip to content
This repository has been archived by the owner on Sep 23, 2020. It is now read-only.

Commit

Permalink
supd driver initially speced out
Browse files Browse the repository at this point in the history
refactered fork (might be broken)
  • Loading branch information
buzztroll committed Oct 19, 2011
1 parent f29c901 commit bf31c19
Show file tree
Hide file tree
Showing 13 changed files with 521 additions and 257 deletions.
60 changes: 0 additions & 60 deletions pidantic/__init__.py
@@ -1,60 +0,0 @@
import logging
from pidantic.pidfork import PIDanticFork


_pidantic_classes = {}
_pidantic_classes['fork'] = PIDanticFork


def pidantic_factory(pid_string, event_callback, log=logging, use_channel=False, channel_is_stdio=False, **kwargs):
"""
Create an object with the PIDantic interface. The specific type of object created will depend on the pid_string
argument.
Parameters
pid_string:
The pid string has the following format:
<driver name>:<driver specific string>
In the case of the fork driver an example string were the program "/bin/true" is run would be:
fork:/bin/true
the keywords are driver specific as well.
event_callback:
This is a function with the signature callback(PIDantic, PIDanticEvents). It is called whenever events o
log:
A python logging object for recording events specific to the operation of this library. It does not record
events in the process being run
use_channel:
Establish a special communication channel between this object and the child process that ill be run. How
the channel is created is driver specific. In the fork driver it is a pipe to the child process. In
XXXX supervisord it will use a file, or a header on the stdio output. TBD
channel_is_stdio
A boolean that determines if the channel will be the exact same thing as stdout/stdin. There are times when
a child process may be willing to use special handling code for messaging with its supervisor and times when
it may not. This features allows the channel messaging to code to operate in the same way for the parent
process when dealing with a channel aware process and a process that will just go through stdio.
Keyword Arguments:
These are determined by the driver. supD will likely need arguments to determine if a new sup must be start
or the unix domain socket to an existing supD etc.
"""


ndx = pid_string.find(":")
if ndx < 0:
return None

driver_name = pid_string[:ndx]
argv = pid_string[ndx + 1:]

global _pidantic_classes
PIDClass = _pidantic_classes[driver_name]
if not PIDClass:
return None

pidantic = PIDClass(argv, event_callback, log=log, use_channel=use_channel, channel_is_stdio=channel_is_stdio)

return pidantic
21 changes: 21 additions & 0 deletions pidantic/fork/__init__.py
@@ -0,0 +1,21 @@
from pidantic.fork.pidfork import PIDanticFork
from pidantic.pidbase import _set_param_or_default

class ForkPidanticFactory(object):

driver_name = "fork"

def __init__(self, **kwvals):
pass

def get_pidantic(self, **kwvals):

cb = _set_param_or_default(kwvals, "event_callback")
argv = _set_param_or_default(kwvals, "argv")
log = _set_param_or_default(kwvals, "log")
pidfork = PIDanticFork(argv, event_callback=cb, log=log, kwargs)
pidfork.start()
return pidfork

def stored_instances(self):
return []
1 change: 1 addition & 0 deletions pidantic/pidfork.py → pidantic/fork/pidfork.py
Expand Up @@ -103,6 +103,7 @@ class PIDanticFork(PIDanticStateMachineBase):

def __init__(self, argv, event_callback=None, log=logging, use_channel=False, channel_is_stdio=False, **kwargs):
PIDanticStateMachineBase.__init__(self, argv, event_callback=event_callback, log=log, use_channel=use_channel, channel_is_stdio=channel_is_stdio, **kwargs)
self._argv = argv

def starting(self):
self._p = None
Expand Down
Expand Up @@ -16,7 +16,7 @@ def setUp(self):
self.dirpath = tempfile.mkdtemp()
self.supd_db_path = "sqlite:///" + os.path.join(self.dirpath, "sup.db")
self.supd_db = SupDDB(self.supd_db_path)
self.supd = SupD(self.supd_db, self.name, executable="supervisord", dirpath=self.dirpath)
self.supd = SupD(self.supd_db, self.name, executable="/home/bresnaha/pycharmVE/bin/supervisord", dirpath=self.dirpath)

def tearDown(self):
self.supd.terminate()
Expand Down Expand Up @@ -46,6 +46,37 @@ def test_run_status(self):
proc_name = "testcat"
self.supd.run_program("/bin/cat", process_name=proc_name)
rc = self.supd.get_program_status(proc_name)
self.assertEqual(rc['group'], proc_name)
self.assertEqual(rc['name'], proc_name)

def test_run_two_status(self):
proc_name1 = "testcat"
proc_name2 = "true"
self.supd.run_program("/bin/cat", process_name=proc_name1)
self.supd.run_program("/bin/true", process_name=proc_name2)
rc = self.supd.get_program_status(proc_name1)
self.assertEqual(rc['group'], proc_name1)
self.assertEqual(rc['name'], proc_name1)

rc = self.supd.get_program_status(proc_name2)
self.assertEqual(rc['group'], proc_name2)
self.assertEqual(rc['name'], proc_name2)

states = self.supd.get_all_state()
self.assertEqual(len(states), 2)
# find each
s1 = None
s2 = None
for s in states:
if s['name'] == proc_name1:
s1 = s
elif s['name'] == proc_name2:
s2 = s

self.assertNotEqual(s1, None)
self.assertNotEqual(s2, None)



if __name__ == '__main__':
unittest.main()
70 changes: 70 additions & 0 deletions pidantic/nosetests/piddler_supd_basic_test.py
@@ -0,0 +1,70 @@
import tempfile
from pidantic.supd.pidsupd import SupDPidanticFactory

__author__ = 'bresnaha'

import unittest

class PIDSupBasicTest(unittest.TestCase):

def simple_api_walk_through_test(self):

tempdir = tempfile.mkdtemp()
factory = SupDPidanticFactory(directory=tempdir, name="tester")
pidantic = factory.get_pidantic(command="/bin/sleep 1", process_name="sleep", directory='tempdir')
state = pidantic.get_state()
while not pidantic.is_done():
factory.poll()
factory.terminate()

def simple_cleanup_test(self):

tempdir = tempfile.mkdtemp()
factory = SupDPidanticFactory(directory=tempdir, name="tester")
pidantic = factory.get_pidantic(command="/bin/sleep 1", process_name="sleep", directory='tempdir')
state = pidantic.get_state()
while not pidantic.is_done():
factory.poll()
pidantic.cleanup()
factory.terminate()

def simple_return_code_success_test(self):

tempdir = tempfile.mkdtemp()
factory = SupDPidanticFactory(directory=tempdir, name="tester")
pidantic = factory.get_pidantic(command="/bin/true", process_name="true", directory='tempdir')
while not pidantic.is_done():
factory.poll()
rc = pidantic.get_result_code()
self.assertEqual(rc, 0)
factory.terminate()

def simple_return_code_success_test(self):

tempdir = tempfile.mkdtemp()
factory = SupDPidanticFactory(directory=tempdir, name="tester")
pidantic = factory.get_pidantic(command="/bin/false", process_name="false", directory='tempdir')
while not pidantic.is_done():
factory.poll()
rc = pidantic.get_result_code()
self.assertNotEqual(rc, 0)
factory.terminate()

def two_processes_one_sup_test(self):

tempdir = tempfile.mkdtemp()
factory = SupDPidanticFactory(directory=tempdir, name="tester")
false_pid = factory.get_pidantic(command="/bin/false", process_name="false", directory='tempdir')
true_pid = factory.get_pidantic(command="/bin/false", process_name="false", directory='tempdir')
while not false_pid.is_done() or not true_pid.is_done():
factory.poll()
rc = false_pid.get_result_code()
self.assertNotEqual(rc, 0)
rc = true_pid.get_result_code()
self.assertEqual(rc, 0)
factory.terminate()



if __name__ == '__main__':
unittest.main()
107 changes: 9 additions & 98 deletions pidantic/pidbase.py
Expand Up @@ -2,71 +2,20 @@
import inspect
import logging
from pidantic.pidantic_exceptions import PIDanticUsageException
from pidantic.ui import PIDantic


class PIDantic(object):

"""
This is the main interface class. It is implemented by specific lower level drivers (like fork, supervisord and
pyon). I/O operations are blocking and must be implemented in a pyon friendly way (gevents)
"""
def __init__(self, pid_string, event_callback=None, log=logging, use_channel=False, channel_is_stdio=False):
self._argv = pid_string
self._log = log
self._use_channel = use_channel
self._channel_is_stdio = channel_is_stdio
self._event_callback = event_callback

def is_done(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def get_state(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def start(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def terminate(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def restart(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def send_stdin(self, data):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def recv_stdout(self, len=None):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def recv_stderr(self, len=None):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def send_channel(self, data):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def recv_channel(self, len=None):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_read_channel(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_write_channel(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_stdin(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_stdout(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_stderr(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))
def _set_param_or_default(kwvals, key, default=None):
try:
rc = kwvals[key]
except:
rc = default
return rc


class PIDanticStateMachineBase(PIDantic):

def __init__(self, argv, event_callback=None, log=logging, use_channel=False, channel_is_stdio=False, **kwargs):
PIDantic.__init__(self, argv, event_callback=event_callback, log=log, use_channel=use_channel, channel_is_stdio=channel_is_stdio)
def __init__(self, event_callback=None, log=logging, use_channel=False, channel_is_stdio=False, **kwargs):
PIDantic.__init__(self, event_callback=event_callback, log=log, use_channel=use_channel, channel_is_stdio=channel_is_stdio)
self._sm = PIDanticStateMachine(self, log=log)

def is_done(self):
Expand All @@ -83,41 +32,6 @@ def terminate(self):
event = "EVENT_STOP_REQUEST"
self._send_event(event)

def restart(self):
event = "EVENT_RESTART_REQUEST"
self._send_event(event)

# interface functions. called by the event library not the user
def send_stdin(self, data):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def recv_stdout(self, len=None):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def recv_stderr(self, len=None):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def send_channel(self, data):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def recv_channel(self, len=None):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_read_channel(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_write_channel(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_stdin(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_stdout(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

def has_stderr(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))

# Interface function for the state machine callbacks
def starting(self):
raise PIDanticUsageException("function %s must be implemented" % (inspect.stack()[1][3]))
Expand Down Expand Up @@ -156,6 +70,3 @@ def stop_fault(self):
def _send_event(self, event):
return self._sm.event_occurred(event)

def _get_db_cols(self):
return None

0 comments on commit bf31c19

Please sign in to comment.