Exemple #1
0
class TestCircus(unittest.TestCase):

    def setUp(self):
        self.arbiters = []
        self.files = []
        self.tmpfiles = []
        self.cli = CircusClient()

    def tearDown(self):
        self._stop_runners()
        for file in self.files + self.tmpfiles:
            if os.path.exists(file):
                os.remove(file)
        self.cli.stop()

    def get_tmpfile(self, content=None):
        fd, file = mkstemp()
        os.close(fd)
        self.tmpfiles.append(file)
        if content is not None:
            with open(file, 'w') as f:
                f.write(content)
        return file

    @classmethod
    def _create_circus(cls, callable, plugins=None, stats=False, **kw):
        resolve_name(callable)   # used to check the callable
        fd, testfile = mkstemp()
        os.close(fd)
        wdir = os.path.dirname(__file__)
        args = ['generic.py', callable, testfile]
        worker = {'cmd': _CMD, 'args': args, 'working_dir': wdir,
                  'name': 'test', 'graceful_timeout': 4}
        worker.update(kw)
        if stats:
            arbiter = get_arbiter([worker], background=True, plugins=plugins,
                                  stats_endpoint=DEFAULT_ENDPOINT_STATS,
                                  debug=kw.get('debug', False))
        else:
            arbiter = get_arbiter([worker], background=True, plugins=plugins,
                                  debug=kw.get('debug', False))
        arbiter.start()
        return testfile, arbiter

    def _run_circus(self, callable, plugins=None, stats=False, **kw):

        testfile, arbiter = TestCircus._create_circus(callable, plugins, stats,
                                                      **kw)
        self.arbiters.append(arbiter)
        self.files.append(testfile)
        return testfile

    def _stop_runners(self):
        for arbiter in self.arbiters:
            arbiter.stop()
        self.arbiters = []

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)
class TestWatcher(TestCircus):
    def setUp(self):
        super(TestWatcher, self).setUp()
        self.stream = QueueStream()
        dummy_process = 'circus.tests.test_watcher.run_process'
        self.test_file = self._run_circus(
            dummy_process, stdout_stream={'stream': self.stream})
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()

    def status(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('status')

    def numprocesses(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('numprocesses')

    def test_signal(self):
        self.assertEquals(self.numprocesses('incr', name='test'), 2)

        def get_pids():
            return self.call('list', name='test').get('pids')

        pids = get_pids()
        self.assertEquals(len(pids), 2)
        to_kill = pids[0]
        self.assertEquals(
            self.status('signal',
                        name='test',
                        pid=to_kill,
                        signum=signal.SIGKILL), 'ok')

        time.sleep(1)  # wait for the process to die

        # we still should have two processes, but not the same pids for them
        pids = get_pids()
        self.assertEquals(len(pids), 2)
        self.assertTrue(to_kill not in pids)

    def test_stats(self):
        resp = self.call("stats").get('infos')
        self.assertTrue("test" in resp)
        watchers = resp['test']

        self.assertEqual(watchers[watchers.keys()[0]]['cmdline'],
                         sys.executable.split(os.sep)[-1])

    def test_streams(self):
        time.sleep(1.)
        # let's see what we got
        self.assertTrue(self.stream.qsize() > 1)
Exemple #3
0
class TestWatcher(TestCircus):
    def setUp(self):
        super(TestWatcher, self).setUp()
        self.stream = QueueStream()
        dummy_process = 'circus.tests.test_watcher.run_process'
        self.test_file = self._run_circus(
            dummy_process, stdout_stream={'stream': self.stream})
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()

    def status(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('status')

    def numprocesses(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('numprocesses')

    def testSignal(self):
        self.assertEquals(self.numprocesses("incr", name="test"), 2)
        self.assertEquals(
            self.call("list", name="test").get('processes'), [1, 2])
        self.assertEquals(
            self.status("signal",
                        name="test",
                        process=2,
                        signum=signal.SIGKILL), "ok")

        time.sleep(1.0)
        self.assertEquals(
            self.call("list", name="test").get('processes'), [1, 3])

        processes = self.call("list", name="test").get('processes')
        self.assertEquals(
            self.status("signal", name="test", signum=signal.SIGKILL), "ok")

        time.sleep(1.0)
        self.assertNotEqual(
            self.call("list", name="test").get('processes'), processes)

    def testStats(self):
        resp = self.call("stats").get('infos')
        self.assertTrue("test" in resp)

        self.assertEqual(resp['test']['1']['cmdline'],
                         sys.executable.split(os.sep)[-1])

    def test_streams(self):
        time.sleep(2.)
        # let's see what we got
        self.assertTrue(self.stream.qsize() > 1)
Exemple #4
0
class TestWatcher(TestCircus):

    def setUp(self):
        super(TestWatcher, self).setUp()
        self.stream = QueueStream()
        dummy_process = 'circus.tests.test_watcher.run_process'
        self.test_file = self._run_circus(dummy_process,
                stdout_stream={'stream': self.stream})
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()

    def status(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('status')

    def numprocesses(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('numprocesses')

    def test_signal(self):
        self.assertEquals(self.numprocesses('incr', name='test'), 2)

        def get_pids():
            return self.call('list', name='test').get('pids')

        pids = get_pids()
        self.assertEquals(len(pids), 2)
        to_kill = pids[0]
        self.assertEquals(self.status('signal', name='test', pid=to_kill,
                                      signum=signal.SIGKILL), 'ok')

        time.sleep(1)  # wait for the process to die

        # we still should have two processes, but not the same pids for them
        pids = get_pids()
        self.assertEquals(len(pids), 2)
        self.assertTrue(to_kill not in pids)

    def test_stats(self):
        resp = self.call("stats").get('infos')
        self.assertTrue("test" in resp)
        watchers = resp['test']

        self.assertEqual(watchers[watchers.keys()[0]]['cmdline'],
                         sys.executable.split(os.sep)[-1])

    def test_streams(self):
        time.sleep(1.)
        # let's see what we got
        self.assertTrue(self.stream.qsize() > 1)
Exemple #5
0
class TestWatcher(TestCircus):

    def setUp(self):
        super(TestWatcher, self).setUp()
        self.stream = QueueStream()
        dummy_process = 'circus.tests.test_watcher.run_process'
        self.test_file = self._run_circus(dummy_process,
                stdout_stream={'stream': self.stream})
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()

    def status(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('status')

    def numprocesses(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('numprocesses')

    def testSignal(self):
        self.assertEquals(self.numprocesses("incr", name="test"), 2)
        self.assertEquals(self.call("list", name="test").get('processes'),
                          [1, 2])
        self.assertEquals(self.status("signal", name="test", process=2,
            signum=signal.SIGKILL), "ok")

        time.sleep(1.0)
        self.assertEquals(self.call("list", name="test").get('processes'),
                          [1, 3])

        processes = self.call("list", name="test").get('processes')
        self.assertEquals(self.status("signal", name="test",
            signum=signal.SIGKILL), "ok")

        time.sleep(1.0)
        self.assertNotEqual(self.call("list", name="test").get('processes'),
                processes)

    def testStats(self):
        resp = self.call("stats").get('infos')
        self.assertTrue("test" in resp)

        self.assertEqual(resp['test']['1']['cmdline'],
                         sys.executable.split(os.sep)[-1])

    def test_streams(self):
        time.sleep(2.)
        # let's see what we got
        self.assertTrue(self.stream.qsize() > 1)
Exemple #6
0
 def _rm_process(self, name):
     client = CircusClient(endpoint=self.circus_endpoint)
     # https://github.com/circus-tent/circus/issues/927
     name = name.lower()
     cmd_rm = {"command": "rm", "properties": {"name": name}}
     try:
         call_rm = client.call(cmd_rm)
         self.log.debug("_rm_device circus client call: %s", str(call_rm))
     except CallError:
         self.log.debug("Could not rm process: %s", name, exc_info=True)
Exemple #7
0
    def _test_stop(self):
        resp = self.cli.call(make_message("quit"))
        self.assertEqual(resp.get("status"), "ok")
        self.assertRaises(CallError, self.cli.call, make_message("list"))

        self._stop_runners()
        cli = CircusClient()
        dummy_process = 'circus.tests.support.run_process'
        self.test_file = self._run_circus(dummy_process)
        msg = make_message("numprocesses")
        resp = cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
Exemple #8
0
    def _test_stop(self):
        resp = self.cli.call(make_message("quit"))
        self.assertEqual(resp.get("status"), "ok")
        self.assertRaises(CallError, self.cli.call, make_message("list"))

        self._stop_runners()
        cli = CircusClient()
        dummy_process = 'circus.tests.support.run_process'
        self.test_file = self._run_circus(dummy_process)
        msg = make_message("numprocesses")
        resp = cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
Exemple #9
0
 def _running(self):
     """Return Brewpi instances running using suffix as filter"""
     client = CircusClient(endpoint=self.circus_endpoint)
     try:
         call = client.call({"command": "list", "properties": {}})
     except CallError:
         self.log.error("Could not get running processes", exc_info=True)
         return []
     running_devices = [
         x for x in call['watchers'] if x.startswith(self.prefix)
     ]
     return running_devices
Exemple #10
0
    def test_plugins(self):
        # killing the setUp runner
        self._stop_runners()
        self.cli.stop()

        # setting up a circusd with a plugin
        dummy_process = 'circus.tests.test_arbiter.run_dummy'
        plugin = 'circus.tests.test_arbiter.Plugin'
        plugins = [{'use': plugin}]
        self._run_circus(dummy_process, plugins=plugins)

        # doing a few operations
        cli = CircusClient()
        msg1 = make_message("list", name="test")
        resp = cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1])
        msg2 = make_message("incr", name="test")
        cli.call(msg2)
        resp = cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1, 2])

        # checking what the plugin did
        wanted = [('test', 'spawn'), ('test', 'start'), ('test', 'spawn')]
        self.assertEqual(Plugin.events, wanted)
Exemple #11
0
class TestWatcher(TestCircus):

    def setUp(self):
        super(TestWatcher, self).setUp()
        dummy_process = 'circus.tests.test_watcher.run_process'
        self.test_file = self._run_circus(dummy_process)
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()

    def status(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('status')

    def numprocesses(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('numprocesses')

    def testSignal(self):
        self.assertEquals(self.numprocesses("incr", name="test"), 2)
        self.assertEquals(self.call("list", name="test").get('processes'),
                          [1, 2])
        self.assertEquals(self.status("signal", name="test", process=2,
            signum=signal.SIGKILL), "ok")

        time.sleep(1.0)
        self.assertEquals(self.call("list", name="test").get('processes'),
                          [1, 3])

        processes = self.call("list", name="test").get('processes')
        self.assertEquals(self.status("signal", name="test",
            signum=signal.SIGKILL), "ok")

        time.sleep(1.0)
        self.assertNotEqual(self.call("list", name="test").get('processes'),
                processes)

    def testStats(self):
        resp = self.call("stats").get('infos')
        self.assertTrue("test" in resp)

        self.assertEqual(resp['test']['1']['cmdline'], 'python')
Exemple #12
0
class TestWatcher(TestCircus):

    def setUp(self):
        super(TestWatcher, self).setUp()
        dummy_process = 'circus.tests.test_stream.run_process'
        fd, log = tempfile.mkstemp()
        self.log = log
        os.close(fd)
        stream = {'stream': FileStream(log)}
        self.test_file = self._run_circus(dummy_process,
                stdout_stream=stream, stderr_stream=stream, debug=True)
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()
        os.remove(self.log)

    def test_stream(self):
        time.sleep(2.)
        self.call("stats").get('infos')
        # let's see what we got in the file
        with open(self.log) as f:
            data = f.read()

        self.assertTrue('stderr' in data)
        self.assertTrue('stdout' in data)

        # restarting
        self.call('restart')
        time.sleep(1.)

        current = time.time()
        # should be running
        with open(self.log) as f:
            data = f.readlines()

        # last log should be less than one second old
        last = data[-1]
        delta = abs(current - int(last.split('-')[0]))
        self.assertTrue(delta < 1, delta)
Exemple #13
0
 def _stop_process(self, name):
     client = CircusClient(endpoint=self.circus_endpoint)
     # https://github.com/circus-tent/circus/issues/927
     name = name.lower()
     cmd_stop = {
         "command": "stop",
         "properties": {
             "waiting": False,
             "name": name,
             "match": "glob"
         }
     }
     try:
         call_stop = client.call(cmd_stop)
         self.log.debug("_stop_process circus client call: %s",
                        str(call_stop))
     except CallError:
         self.log.debug("Could not stop process: %s", name, exc_info=True)
Exemple #14
0
class CircusMgr(object):
    """Fermentrack Circus Handler, It is a simple wrapper around
    circus client, any errors raised as CircusException"""

    def __init__(self, connection_timeout=2, circus_endpoint=DEFAULT_ENDPOINT_DEALER):
        self._client = CircusClient(
            timeout=connection_timeout, endpoint=circus_endpoint)

    def _call(self, command, **props):
        message = {"command": command, "properties": props or {}}
        try:
            res = self._client.call(message)
        except CallError, callerr:
            LOG.debug("Error from circus", exc_info=True)
            raise CircusException("Could send message to circus: {}".format(callerr))
        if res['status'] == u'error':
            raise CircusException("Error: {}".format(res['reason']))
        return res
Exemple #15
0
class TestWatcher(TestCircus):
    def setUp(self):
        super(TestWatcher, self).setUp()
        dummy_process = "circus.tests.test_stream.run_process"
        fd, self.stdout = tempfile.mkstemp()
        os.close(fd)
        fd, self.stderr = tempfile.mkstemp()
        os.close(fd)
        self.test_file = self._run_circus(
            dummy_process,
            stdout_stream={"stream": FileStream(self.stdout)},
            stderr_stream={"stream": FileStream(self.stderr)},
            debug=True,
        )
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()
        os.remove(self.stdout)
        os.remove(self.stderr)

    def test_stream(self):
        # wait for the process to be started
        self.assertTrue(poll_for(self.stdout, "stdout"))
        self.assertTrue(poll_for(self.stderr, "stderr"))

        # clean slate
        truncate_file(self.stdout)
        truncate_file(self.stderr)
        # restart and make sure streams are still working
        self.call("restart")

        # wait for the process to be restarted
        self.assertTrue(poll_for(self.stdout, "stdout"))
        self.assertTrue(poll_for(self.stderr, "stderr"))
Exemple #16
0
class TestWatcher(TestCircus):

    def setUp(self):
        super(TestWatcher, self).setUp()
        dummy_process = 'circus.tests.test_stream.run_process'
        fd, self.stdout = tempfile.mkstemp()
        os.close(fd)
        fd, self.stderr = tempfile.mkstemp()
        os.close(fd)
        self.test_file = self._run_circus(
            dummy_process,
            stdout_stream={'stream': FileStream(self.stdout)},
            stderr_stream={'stream': FileStream(self.stderr)},
            debug=True)
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()
        os.remove(self.stdout)
        os.remove(self.stderr)

    def test_stream(self):
        # wait for the process to be started
        self.assertTrue(poll_for(self.stdout, 'stdout'))
        self.assertTrue(poll_for(self.stderr, 'stderr'))

        # clean slate
        truncate_file(self.stdout)
        truncate_file(self.stderr)
        # restart and make sure streams are still working
        self.call('restart')

        # wait for the process to be restarted
        self.assertTrue(poll_for(self.stdout, 'stdout'))
        self.assertTrue(poll_for(self.stderr, 'stderr'))
Exemple #17
0
 def _add_process(self, name):
     """Spawn a new brewpi.py process via circus, 'dev-' is appended to the name to
     keep brewpi devices seperated from other devices
     """
     client = CircusClient(endpoint=self.circus_endpoint)
     proc_name = self.prefix + name
     # https://github.com/circus-tent/circus/issues/927
     proc_name = proc_name.lower()
     try:
         call = client.call({
             "command": "add",
             "properties": {
                 "cmd": self.command_tmpl % name,
                 "name": proc_name,
                 "options": {
                     "copy_env": True,
                     "stdout_stream": {
                         "class":
                         "FileStream",
                         "filename":
                         "%s/%s-stdout.log" % (self.logfilepath, proc_name),
                     },
                     "stderr_stream": {
                         "class":
                         "FileStream",
                         "filename":
                         "%s/%s-stderr.log" % (self.logfilepath, proc_name),
                     }
                 },
                 "start": True
             }
         })
         self.log.debug("_add_process circus client call: %s", str(call))
     except CallError:
         self.log.error("Could not spawn process: %s",
                        proc_name,
                        exc_info=True)
Exemple #18
0
    def test_plugins(self):
        # killing the setUp runner
        self._stop_runners()
        self.cli.stop()

        fd, datafile = mkstemp()
        os.close(fd)

        # setting up a circusd with a plugin
        dummy_process = 'circus.tests.test_arbiter.run_dummy'
        plugin = 'circus.tests.test_arbiter.Plugin'
        plugins = [{'use': plugin, 'file': datafile}]
        self._run_circus(dummy_process, plugins=plugins)

        # doing a few operations
        cli = CircusClient()
        msg1 = make_message("list", name="test")
        resp = cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1])
        msg2 = make_message("incr", name="test")
        cli.call(msg2)
        resp = cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1, 2])
        cli.call(msg2)
        resp = cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1, 2, 3])

        # wait a bit
        time.sleep(.2)

        # checking what the plugin did
        with open(datafile) as f:
            data = [line for line in f.read().split('\n') if line != '']

        wanted = ['test:spawn', 'test:spawn']
        self.assertEqual(data, wanted)
Exemple #19
0
    def test_plugins(self):
        # killing the setUp runner
        self._stop_runners()
        self.cli.stop()

        fd, datafile = mkstemp()
        os.close(fd)

        # setting up a circusd with a plugin
        dummy_process = "circus.tests.test_arbiter.run_dummy"
        plugin = "circus.tests.test_arbiter.Plugin"
        plugins = [{"use": plugin, "file": datafile}]
        self._run_circus(dummy_process, plugins=plugins)

        # doing a few operations
        cli = CircusClient()
        msg1 = make_message("list", name="test")
        resp = cli.call(msg1)
        self.assertEqual(resp.get("processes"), [1])
        msg2 = make_message("incr", name="test")
        cli.call(msg2)
        resp = cli.call(msg1)
        self.assertEqual(resp.get("processes"), [1, 2])
        cli.call(msg2)
        resp = cli.call(msg1)
        self.assertEqual(resp.get("processes"), [1, 2, 3])

        # wait a bit
        time.sleep(0.2)

        # checking what the plugin did
        with open(datafile) as f:
            data = [line for line in f.read().split("\n") if line != ""]

        wanted = ["test:spawn", "test:spawn"]
        self.assertEqual(data, wanted)
Exemple #20
0
class DaemonTamer(object):
    _DAEMON_MAP_FILE = 'daemon_map.yaml'
    _ENDPOINT_TPL = '{host}:{port}'

    def __init__(self, profile):
        self.profile = profile
        self.daemon_name = get_daemon_name(profile)
        self.config = self.get_update_profile()
        self._client = CircusClient()  # endpoint=self.endpoint)

    def generate_new_portnum(self, config=None):
        port = 6000
        used_ports = [profile['port'] for profile in config.values()]
        while port in used_ports:
            port += 2
        return port

    def read_config(self):
        if not path.isfile(self._DAEMON_MAP_FILE):
            return {}
        with open(self._DAEMON_MAP_FILE, 'r') as daemon_map_fo:
            config = yaml.load(daemon_map_fo) or {}
        return config

    def write_config(self, config):
        with open(self._DAEMON_MAP_FILE, 'w') as daemon_map_fo:
            yaml.dump(config, daemon_map_fo)

    def get_update_profile(self):
        config = self.read_config()
        profile_config = config.get(self.profile, {})
        profile_config['uuid'] = get_profile_uuid(self.profile)
        profile_config['host'] = profile_config.get('host', 'tcp://127.0.0.1')
        profile_config['port'] = profile_config.get('port', self.generate_new_portnum(config))
        config[self.profile] = profile_config
        self.write_config(config)
        return config

    @property
    def profile_config(self):
        return self.config[self.profile]

    @property
    def endpoint(self):
        return self._ENDPOINT_TPL.format(host=self.profile_config['host'], port=self.profile_config['port'])

    @property
    def pubsub_endpoint(self):
        return self._ENDPOINT_TPL.format(host=self.profile_config['host'], port=self.profile_config['port'] + 1)

    @property
    def stats_endpoint(self):
        return self._ENDPOINT_TPL.format(host=self.profile_config['host'], port=self.profile_config['port'] + 2)

    @property
    def arbiter_config(self):
        return {
            'logoutput': 'aiida-circus.log',
            'loglevel': 'INFO',
            'debug': False,
            'statsd': True,
            # ~ 'controller': self.endpoint,
            # ~ 'pubsub_endpoint': self.pubsub_endpoint,
            # ~ 'stats_endpoint': self.stats_endpoint
        }

    @property
    def watcher_config(self):
        return get_daemon_properties(self.profile)

    def make_arbiter(self):
        print self.arbiter_config
        print self.watcher_config
        return get_arbiter([self.watcher_config], **self.arbiter_config)

    def pause_daemon(self):
        self._client.stop()

    def unpause_daemon(self):
        self._client.call({
            'command': 'start',
            'properties': {}
        })

    def status(self):
        response = self._client.call({
            'command': 'status',
            'properties': {
                'name': self.daemon_name
            }
        })
        if response.get('status', None):
            return str(response['status'])

    def quit(self):
        try:
            self._client.call({
                'command': 'quit',
                'properties': {}
            })
        except CallError:
            pass
class CircusManager(object):

    def __init__(self, config):
        #self._arbiter = get_arbiter([])
        #self._arbiter.start()
        self._config = config
        self._client = CircusClient(timeout=15, endpoint=self._config['circus_endpoint'])


    def __call(self, message):
        return self._client.call(message)


    def add_application(self, name, command, arguments=[], autostart=True):
        response = self.__call({
            'command':'add',
            'properties':{
                'cmd': command,
                'name':name,
                'start': autostart,
                'args':arguments,
                'options':{
                    'singleton': True,
                    'stop_children': True,
                    'stop_signal': 9,
                    'env': self._config.get('environment', {}),
                    'graceful_timeout': self._config['graceful_timeout'],
                    'max_retry': self._config['max_retry'],
                    'stdout_stream': {
                        'class': self._config['logging']['stdout_stream'],
                        'filename': '{path}/{filename}.{ext}'.format(path=self._config['logging']['path'],
                                                                     filename=name,
                                                                     ext=self._config['logging']['stdout_extension'])
                    },
                    'stderr_stream': {
                        'class':self._config['logging']['stderr_stream'],
                        'filename': '{path}/{filename}.{ext}'.format(path=self._config['logging']['path'],
                                                                     filename=name,
                                                                     ext=self._config['logging']['stderr_extension'])
                    }
                }
            }
        })
        return (True, None) if response['status'] == u'ok' else (False, response['reason'])


    def application_status(self, name):
        response = self.__call({
            'command': 'status',
            'properties': {
                'name': name
            }
        })
        return str(response['status']) if response['status'] != u'error' else 'not running'


    def kill_application(self, name):
        self.__call({
            'command': 'signal',
            'properties':{
                'name': name,
                'signal': self._config['stop_signal']
            }
        })


    def remove_application(self, name, nonstop=False):
        response = self.__call({
            'command': 'rm',
            'properties':{
                'name': name,
                'nonstop': nonstop,
                'waiting': False
            }
        })
        return True if response['status'] == u'ok' else False

    def reload_application(self, name, waiting=False, graceful=True, sequential=False):
        response = self.__call({
            'command': 'reload',
            'properties':{
                'name': name,
                'graceful': graceful,
                'sequential': sequential,
                'waiting': waiting
            }
        })
        return True if response['status'] == u'ok' else False


    def start_application(self, name, waiting=False):
        response = self.__call({
            'command': 'start',
            'properties':{
                'name': name,
                'waiting': waiting
            }
        })
        return True if response['status'] == u'ok' else False


    def stop_application(self, name, waiting=False):
        response = self.__call({
            'command': 'stop',
            'properties':{
                'name': name,
                'waiting': waiting
            }
        })
        return True if response['status'] == u'ok' else False


    def stop_and_remove_application(self, name):
        self.stop_application(name)
        return self.remove_application(name)


    def get_applications(self, verbose=False):
        response = self.__call({
            'command': 'list'
        })
        if not verbose:
            return [{'name':str(w)} for w in response['watchers']] if response['status'] == u'ok' else []
        return [{'name':str(w), 'status': self.application_status(str(w))} for w in response['watchers']] if response['status'] == u'ok' else []


    def stop(self):
        self._arbiter.stop()
Exemple #22
0
import sys

from circus.client import CircusClient
from circus.util import DEFAULT_ENDPOINT_DEALER

client = CircusClient(endpoint=DEFAULT_ENDPOINT_DEALER)

command = '../bin/python dummy_fly.py 111'
name = 'dummy'

for i in range(50):
    print client.call("""
    {
        "command": "add",
        "properties": {
            "cmd": "%s",
            "name": "%s",
            "options": {
            "copy_env": true,
            "stdout_stream": {
                "filename": "stdout.log"
            },
            "stderr_stream": {
                "filename": "stderr.log"
            }
            },
            "start": true
        }
    }
    """ % (command, name + str(i)))
Exemple #23
0
class ProcfileWatcher(CircusPlugin):
    name = "procfile_watcher"

    def __init__(self, *args, **config):
        super(ProcfileWatcher, self).__init__(*args, **config)
        self.loop_rate = config.get("loop_rate", 3)  # in seconds
        self.procfile_path = config.get("app_path",
                                        "/home/application/current/Procfile")
        self.working_dir = config.get("working_dir",
                                      "/home/application/current")
        self.apprc = config.get("apprc", "/home/application/apprc")
        self.port = config.get("port", "8888")
        self.uid = config.get("uid", "ubuntu")
        self.stderr_stream = {"class": config.get("stderr_stream",
                                                  "tsuru.stream.Stream")}
        self.stdout_stream = {"class": config.get("stdout_stream",
                                                  "tsuru.stream.Stream")}
        file_watcher = FileWatcher(self.procfile_path, self.reload_procfile)
        self.period = ioloop.PeriodicCallback(file_watcher,
                                              self.loop_rate * 1000,
                                              self.loop)
        self.circus_client = CircusClient()

    def get_cmd(self, name):
        return self.call("get", name=name, keys=["cmd"])["options"]["cmd"]

    def handle_init(self):
        self.period.start()

    def handle_stop(self):
        self.period.stop()

    def handle_recv(self, data):
        pass

    def add_watcher(self, name, cmd):
        env = {"port": self.port, "PORT": self.port}
        env.update(common.load_envs(self.apprc))
        cmd = replace_args(cmd, **env)
        options = {
            "env": env,
            "copy_env": True,
            "working_dir": self.working_dir,
            "stderr_stream": self.stderr_stream,
            "stdout_stream": self.stdout_stream,
            "uid": self.uid,
            "hooks": {
                "before_start": "tsuru.hooks.before_start",
                "after_start": "tsuru.hooks.after_start",
            }
        }
        self.circus_client.call(json.dumps({
            "command": "add",
            "properties": {
                "cmd": cmd,
                "name": name,
                "args": [],
                "options": options,
                "start": True,
            },
        }))

    def remove_watcher(self, name):
        self.call("rm", name=name)

    def change_cmd(self, name, cmd):
        env = {"port": self.port}
        env.update(common.load_envs(self.apprc))
        cmd = replace_args(cmd, **env)
        self.call("set", name=name, options={"cmd": cmd})

    def commands(self, procfile):
        cmds = self.call("status")["statuses"]
        cmds_names = set([k for k in cmds.keys()
                          if not k.startswith("plugin:")])
        new_cmds = set(procfile.commands.keys())
        to_remove = cmds_names.difference(new_cmds)
        to_add = new_cmds.difference(cmds_names)
        to_change_names = cmds_names.intersection(new_cmds)
        to_change = {}
        for name in to_change_names:
            if self.get_cmd(name) != procfile.commands.get(name):
                to_change[name] = procfile.commands[name]
        return to_add, to_remove, to_change

    def reload_procfile(self):
        with open(self.procfile_path) as file:
            procfile = Procfile(file.read())
            to_add, to_remove, to_change = self.commands(procfile)

            for name in to_remove:
                self.remove_watcher(name)

            for name in to_add:
                self.add_watcher(name=name, cmd=procfile.commands[name])

            for name, cmd in to_change.items():
                self.change_cmd(name=name, cmd=procfile.commands[name])
Exemple #24
0
class TestTrainer(TestCircus):
    def setUp(self):
        super(TestTrainer, self).setUp()
        dummy_process = 'circus.tests.test_arbiter.run_dummy'
        self.test_file = self._run_circus(dummy_process)
        self.cli = CircusClient()

    def tearDown(self):
        super(TestTrainer, self).tearDown()
        self.cli.stop()

    def test_numwatchers(self):
        msg = make_message("numwatchers")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_numprocesses(self):
        msg = make_message("numprocesses")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numprocesses"), 1)

    def test_processes(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1])

        msg2 = make_message("incr", name="test")
        self.cli.call(msg2)

        resp = self.cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1, 2])

    def test_watchers(self):
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test"])

    def _get_cmd(self):
        fd, testfile = mkstemp()
        os.close(fd)
        cmd = '%s generic.py %s %s' % (
            sys.executable, 'circus.tests.test_arbiter.run_dummy', testfile)

        return cmd

    def _get_cmd_args(self):
        cmd = sys.executable
        args = ['generic.py', 'circus.tests.test_arbiter.run_dummy1']
        return cmd, args

    def test_add_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher1(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test", "test1"])

    def test_add_watcher2(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 2)

    def test_add_watcher3(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(msg)
        self.assertTrue(resp.get('status'), 'error')

    def test_add_watcher4(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher5(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher6(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args, start=True)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher7(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add",
                           name="test1",
                           cmd=cmd,
                           args=args,
                           start=True,
                           options={"flapping_window": 100})
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

        resp = self.cli.call(make_message("options", name="test1"))
        options = resp.get('options', {})
        self.assertEqual(options.get("flapping_window"), 100)

    def test_rm_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        msg = make_message("rm", name="test1")
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_stop(self):
        resp = self.cli.call(make_message("quit"))
        self.assertEqual(resp.get("status"), "ok")
        self.assertRaises(CallError, self.cli.call, make_message("list"))

    def test_reload(self):
        resp = self.cli.call(make_message("reload"))
        self.assertEqual(resp.get("status"), "ok")

    def test_reload1(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('processes')

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        msg2 = make_message("list", name="test")
        resp = self.cli.call(msg2)
        processes2 = resp.get('processes')

        self.assertNotEqual(processes1, processes2)

    def test_reload2(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('processes')
        self.assertEqual(processes1, [1])

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        make_message("list", name="test")
        resp = self.cli.call(msg1)

        processes2 = resp.get('processes')
        self.assertEqual(processes2, [2])

    def test_stop_watchers(self):
        resp = self.cli.call(make_message("stop"))
        self.assertEqual(resp.get("status"), "ok")

    def test_stop_watchers1(self):
        self.cli.call(make_message("stop"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get("status"), "stopped")

    def test_stop_watchers2(self):
        self.cli.call(make_message("stop", name="test"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "stopped")

    def test_stop_watchers3(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        self.cli.call(make_message("stop", name="test1"))
        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get('status'), "stopped")

        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "active")
Exemple #25
0
class TestTrainer(TestCircus):

    def setUp(self):
        super(TestTrainer, self).setUp()
        self.test_file = self._run_circus('circus.tests.test_trainer.run_dummy')
        time.sleep(0.5)
        self.cli = CircusClient(TEST_ENDPOINT)

    def tearDown(self):
        super(TestTrainer, self).tearDown()
        self.cli.stop()

    def test_numshows(self):
        resp = self.cli.call("numshows")
        self.assertEqual(resp, "1")

    def test_numflies(self):
        resp = self.cli.call("numflies")
        self.assertEqual(resp, "1")

    def test_flies(self):
        resp = self.cli.call("flies")
        self.assertEqual(resp, "test: 1")

    def test_shows(self):
        resp = self.cli.call("shows")
        self.assertEqual(resp, "test")

    def _get_cmd(self):
        fd, testfile = mkstemp()
        os.close(fd)
        cmd = '%s generic.py %s %s' % (sys.executable,
                        'circus.tests.test_trainer.run_dummy', testfile)

        return cmd

    def test_add_show(self):
        cmd = self._get_cmd()
        resp = self.cli.call("add_show test1 %s" % cmd)
        self.assertEqual(resp, "ok")

    def test_add_show1(self):
        cmd = self._get_cmd()
        self.cli.call("add_show test1 %s" % cmd)
        resp = self.cli.call("shows")
        self.assertTrue(resp.endswith("test1"))

    def test_add_show2(self):
        cmd = self._get_cmd()
        self.cli.call("add_show test1 %s" % cmd)
        resp = self.cli.call("numshows")
        self.assertEqual(resp, "2")

    def test_add_show3(self):
        cmd = self._get_cmd()
        self.cli.call("add_show test1 %s" % cmd)
        resp = self.cli.call("add_show test1 %s" % cmd)
        self.assertTrue(resp.startswith("error:"))

    def test_del_show(self):
        cmd = self._get_cmd()
        self.cli.call("add_show test1 %s" % cmd)
        self.cli.call("del_show test1")
        resp = self.cli.call("numshows")
        self.assertEqual(resp, "1")

    def test_stop(self):
        self.cli.call("stop")
        self.assertRaises(CallError, self.cli.call, "shows")

    def test_reload(self):
        resp = self.cli.call("reload")
        self.assertEqual(resp, "ok")


    def test_reload1(self):
        flies0 = self.cli.call("flies")
        resp = self.cli.call("reload")
        time.sleep(0.5)
        flies1 = self.cli.call("flies")
        self.assertNotEqual(flies0, flies1)

    def test_reload(self):
        self.cli.call("reload")
        time.sleep(0.5)
        flies = self.cli.call("flies")
        self.assertEqual(flies, "test: 2")

    def test_stop_shows(self):
        resp = self.cli.call("stop_shows")
        self.assertEqual(resp, "ok")

    def test_stop_shows1(self):
        self.cli.call("stop_shows")
        resp = self.cli.call("status test")
        self.assertEqual(resp, "stopped")
Exemple #26
0
class LiveClient(object):
    def __init__(self, endpoint):
        self.endpoint = str(endpoint)
        self.stats_endpoint = None
        self.client = CircusClient(endpoint=self.endpoint)
        self.connected = False
        self.watchers = []
        self.stats = defaultdict(list)
        self.refresher = Refresher(self)
        self.dstats = []

    def stop(self):
        self.client.stop()
        self.refresher.running = False
        self.refresher.join()

    def verify(self):
        self.watchers = []
        # trying to list the watchers
        msg = cmds['list'].make_message()
        try:
            res = self.client.call(msg)
            self.connected = True
            for watcher in res['watchers']:
                if watcher == 'circusd-stats':
                    continue
                msg = cmds['options'].make_message(name=watcher)
                options = self.client.call(msg)
                self.watchers.append((watcher, options['options']))
            self.watchers.sort()
            self.stats_endpoint = self.get_global_options()['stats_endpoint']
            if not self.refresher.running:
                self.refresher.start()
        except CallError:
            self.connected = False

    def killproc(self, name, pid):
        msg = cmds['signal'].make_message(name=name,
                                          process=int(pid),
                                          signum=9)
        res = self.client.call(msg)
        self.verify()  # will do better later
        return res['status'] == 'ok'

    def get_option(self, name, option):
        watchers = dict(self.watchers)
        return watchers[name][option]

    def get_global_options(self):
        msg = cmds['globaloptions'].make_message()
        options = self.client.call(msg)
        return options['options']

    def get_options(self, name):
        watchers = dict(self.watchers)
        return watchers[name].items()

    def incrproc(self, name):
        msg = cmds['incr'].make_message(name=name)
        res = self.client.call(msg)
        self.verify()  # will do better later
        return res['numprocesses']

    def decrproc(self, name):
        msg = cmds['decr'].make_message(name=name)
        res = self.client.call(msg)
        self.verify()  # will do better later
        return res['numprocesses']

    def get_stats(self, name, start=0, end=-1):
        return self.stats[name][start:end]

    def get_dstats(self, field, start=0, end=-1):
        stats = self.dstats[start:end]
        res = []
        for stat in stats:
            res.append(stat[field])
        return res

    def get_pids(self, name):
        msg = cmds['listpids'].make_message(name=name)
        res = self.client.call(msg)
        return res['pids']

    def get_series(self, name, pid, field, start=0, end=-1):
        stats = self.get_stats(name, start, end)
        res = []
        for stat in stats:
            pids = stat['pid']
            if isinstance(pids, list):
                continue
            if str(pid) == str(stat['pid']):
                res.append(stat[field])
        return res

    def get_status(self, name):
        msg = cmds['status'].make_message(name=name)
        res = self.client.call(msg)
        return res['status']

    def switch_status(self, name):
        msg = cmds['status'].make_message(name=name)
        res = self.client.call(msg)
        status = res['status']
        if status == 'active':
            # stopping the watcher
            msg = cmds['stop'].make_message(name=name)
        else:
            msg = cmds['start'].make_message(name=name)
        res = self.client.call(msg)
        return res

    def add_watcher(self, name, cmd, **kw):
        msg = cmds['add'].make_message(name=name, cmd=cmd)
        res = self.client.call(msg)
        if res['status'] == 'ok':
            # now configuring the options
            options = {}
            options['numprocesses'] = int(kw.get('numprocesses', '5'))
            options['working_dir'] = kw.get('working_dir')
            options['shell'] = kw.get('shell', 'off') == 'on'
            msg = cmds['set'].make_message(name=name, options=options)
            res = self.client.call(msg)
            self.verify()  # will do better later
            return res['status'] == 'ok'
        else:
            return False
Exemple #27
0
class TestTrainer(TestCircus):
    def setUp(self):
        super(TestTrainer, self).setUp()
        dummy_process = "circus.tests.test_arbiter.run_dummy"
        self.test_file = self._run_circus(dummy_process)
        self.cli = CircusClient()

    def tearDown(self):
        super(TestTrainer, self).tearDown()
        self.cli.stop()

    def test_numwatchers(self):
        msg = make_message("numwatchers")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_numprocesses(self):
        msg = make_message("numprocesses")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numprocesses"), 1)

    def test_processes(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        self.assertEqual(resp.get("processes"), [1])

        msg2 = make_message("incr", name="test")
        self.cli.call(msg2)

        resp = self.cli.call(msg1)
        self.assertEqual(resp.get("processes"), [1, 2])

    def test_watchers(self):
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get("watchers"), ["test"])

    def _get_cmd(self):
        fd, testfile = mkstemp()
        os.close(fd)
        cmd = "%s generic.py %s %s" % (sys.executable, "circus.tests.test_arbiter.run_dummy", testfile)

        return cmd

    def _get_cmd_args(self):
        cmd = sys.executable
        args = ["generic.py", "circus.tests.test_arbiter.run_dummy1"]
        return cmd, args

    def test_add_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher1(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get("watchers"), ["test", "test1"])

    def test_add_watcher2(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 2)

    def test_add_watcher3(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(msg)
        self.assertTrue(resp.get("status"), "error")

    def test_add_watcher4(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher5(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher6(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args, start=True)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher7(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args, start=True, options={"flapping_window": 100})
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

        resp = self.cli.call(make_message("options", name="test1"))
        options = resp.get("options", {})
        self.assertEqual(options.get("flapping_window"), 100)

    def test_rm_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        msg = make_message("rm", name="test1")
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_stop(self):
        resp = self.cli.call(make_message("quit"))
        self.assertEqual(resp.get("status"), "ok")
        self.assertRaises(CallError, self.cli.call, make_message("list"))

    def test_reload(self):
        resp = self.cli.call(make_message("reload"))
        self.assertEqual(resp.get("status"), "ok")

    def test_reload1(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get("processes")

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        msg2 = make_message("list", name="test")
        resp = self.cli.call(msg2)
        processes2 = resp.get("processes")

        self.assertNotEqual(processes1, processes2)

    def test_reload2(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get("processes")
        self.assertEqual(processes1, [1])

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        make_message("list", name="test")
        resp = self.cli.call(msg1)

        processes2 = resp.get("processes")
        self.assertEqual(processes2, [2])

    def test_stop_watchers(self):
        resp = self.cli.call(make_message("stop"))
        self.assertEqual(resp.get("status"), "ok")

    def test_stop_watchers1(self):
        self.cli.call(make_message("stop"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get("status"), "stopped")

    def test_stop_watchers2(self):
        self.cli.call(make_message("stop", name="test"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get("status"), "stopped")

    def test_stop_watchers3(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        self.cli.call(make_message("stop", name="test1"))
        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "stopped")

        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get("status"), "active")

    def test_plugins(self):
        # killing the setUp runner
        self._stop_runners()
        self.cli.stop()

        fd, datafile = mkstemp()
        os.close(fd)

        # setting up a circusd with a plugin
        dummy_process = "circus.tests.test_arbiter.run_dummy"
        plugin = "circus.tests.test_arbiter.Plugin"
        plugins = [{"use": plugin, "file": datafile}]
        self._run_circus(dummy_process, plugins=plugins)

        # doing a few operations
        cli = CircusClient()
        msg1 = make_message("list", name="test")
        resp = cli.call(msg1)
        self.assertEqual(resp.get("processes"), [1])
        msg2 = make_message("incr", name="test")
        cli.call(msg2)
        resp = cli.call(msg1)
        self.assertEqual(resp.get("processes"), [1, 2])
        cli.call(msg2)
        resp = cli.call(msg1)
        self.assertEqual(resp.get("processes"), [1, 2, 3])

        # wait a bit
        time.sleep(0.2)

        # checking what the plugin did
        with open(datafile) as f:
            data = [line for line in f.read().split("\n") if line != ""]

        wanted = ["test:spawn", "test:spawn"]
        self.assertEqual(data, wanted)

    def test_singleton(self):
        self._stop_runners()

        dummy_process = "circus.tests.test_arbiter.run_dummy"
        self._run_circus(dummy_process, singleton=True)
        cli = CircusClient()

        # adding more than one process should fail
        res = cli.send_message("incr", name="test")
        self.assertEqual(res["numprocesses"], 1)
Exemple #28
0
class TestTrainer(TestCircus):

    def setUp(self):
        super(TestTrainer, self).setUp()
        dummy_process = 'circus.tests.support.run_process'
        self.test_file = self._run_circus(dummy_process)
        self.cli = CircusClient()

    def tearDown(self):
        super(TestTrainer, self).tearDown()
        self.cli.stop()

    def test_numwatchers(self):
        msg = make_message("numwatchers")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_numprocesses(self):
        msg = make_message("numprocesses")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numprocesses"), 1)

    def test_processes(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        self.assertEqual(len(resp.get('pids')), 1)

        msg2 = make_message("incr", name="test")
        self.cli.call(msg2)

        resp = self.cli.call(msg1)
        self.assertEqual(len(resp.get('pids')), 2)

        self.cli.send_message("incr", name="test", nb=2)
        resp = self.cli.call(msg1)
        self.assertEqual(len(resp.get('pids')), 4)

    def test_watchers(self):
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test"])

    def _get_cmd(self):
        fd, testfile = mkstemp()
        os.close(fd)
        cmd = '%s generic.py %s %s' % (
            sys.executable,
            'circus.tests.support.run_process',
            testfile)

        return cmd

    def _get_cmd_args(self):
        cmd = sys.executable
        args = ['generic.py', 'circus.tests.support.run_process']
        return cmd, args

    def _get_options(self, **kwargs):
        if 'graceful_timeout' not in kwargs:
            kwargs['graceful_timeout'] = 4
        return kwargs

    def test_add_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd(),
                           options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher1(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd(),
                           options=self._get_options())
        self.cli.call(msg)
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test", "test1"])

    def test_add_watcher2(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd(),
                           options=self._get_options())
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 2)

    def test_add_watcher3(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd(),
                           options=self._get_options())
        self.cli.call(msg)
        resp = self.cli.call(msg)
        self.assertTrue(resp.get('status'), 'error')

    def test_add_watcher4(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args,
                           options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher5(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args,
                           options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher6(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args,
                           start=True, options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher7(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args, start=True,
                           options=self._get_options(flapping_window=100))
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

        resp = self.cli.call(make_message("options", name="test1"))
        options = resp.get('options', {})
        self.assertEqual(options.get("flapping_window"), 100)

    def test_rm_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd(),
                           options=self._get_options())
        self.cli.call(msg)
        msg = make_message("rm", name="test1")
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_stop(self):
        resp = self.cli.call(make_message("quit"))
        self.assertEqual(resp.get("status"), "ok")
        self.assertRaises(CallError, self.cli.call, make_message("list"))

    def test_reload(self):
        resp = self.cli.call(make_message("reload"))
        self.assertEqual(resp.get("status"), "ok")

    def test_reload1(self):
        self.assertTrue(poll_for(self.test_file, 'START'))  # process started
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('pids')

        truncate_file(self.test_file)  # clean slate
        self.cli.call(make_message("reload"))
        self.assertTrue(poll_for(self.test_file, 'START'))  # restarted

        msg2 = make_message("list", name="test")
        resp = self.cli.call(msg2)
        processes2 = resp.get('pids')

        self.assertNotEqual(processes1, processes2)

    def test_reload2(self):
        self.assertTrue(poll_for(self.test_file, 'START'))  # process started
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('pids')
        self.assertEqual(len(processes1), 1)

        truncate_file(self.test_file)  # clean slate
        self.cli.call(make_message("reload"))
        self.assertTrue(poll_for(self.test_file, 'START'))  # restarted

        make_message("list", name="test")
        resp = self.cli.call(msg1)

        processes2 = resp.get('pids')
        self.assertEqual(len(processes2), 1)
        self.assertNotEqual(processes1[0], processes2[0])

    def test_stop_watchers(self):
        resp = self.cli.call(make_message("stop"))
        self.assertEqual(resp.get("status"), "ok")

    def test_stop_watchers1(self):
        self.cli.call(make_message("stop"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get("status"), "stopped")

    def test_stop_watchers2(self):
        self.cli.call(make_message("stop", name="test"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "stopped")

    def test_stop_watchers3(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args,
                           options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        self.cli.call(make_message("stop", name="test1"))
        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get('status'), "stopped")

        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "active")

    def test_plugins(self):
        # killing the setUp runner
        self._stop_runners()
        self.cli.stop()

        fd, datafile = mkstemp()
        os.close(fd)

        # setting up a circusd with a plugin
        dummy_process = 'circus.tests.support.run_process'
        plugin = 'circus.tests.test_arbiter.Plugin'
        plugins = [{'use': plugin, 'file': datafile}]
        self._run_circus(dummy_process, plugins=plugins)

        # doing a few operations
        def nb_processes():
            return len(cli.send_message('list', name='test').get('pids'))

        def incr_processes():
            return cli.send_message('incr', name='test')

        # wait for the plugin to be started
        self.assertTrue(poll_for(datafile, 'PLUGIN STARTED'))

        cli = CircusClient()
        self.assertEqual(nb_processes(), 1)
        incr_processes()
        self.assertEqual(nb_processes(), 2)
        # wait for the plugin to receive the signal
        self.assertTrue(poll_for(datafile, 'test:spawn'))
        truncate_file(datafile)
        incr_processes()
        self.assertEqual(nb_processes(), 3)
        # wait for the plugin to receive the signal
        self.assertTrue(poll_for(datafile, 'test:spawn'))

    def test_singleton(self):
        self._stop_runners()

        dummy_process = 'circus.tests.support.run_process'
        self._run_circus(dummy_process, singleton=True)
        cli = CircusClient()

        # adding more than one process should fail
        res = cli.send_message('incr', name='test')
        self.assertEqual(res['numprocesses'], 1)
Exemple #29
0
class TestWatcher(TestCircus):

    def setUp(self):
        super(TestWatcher, self).setUp()
        self.stream = QueueStream()
        dummy_process = 'circus.tests.test_watcher.run_process'
        self.test_file = self._run_circus(dummy_process,
                stdout_stream={'stream': self.stream})
        self.arbiter = self.arbiters[-1]
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()

    def status(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('status')

    def numprocesses(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('numprocesses')

    def pids(self):
        return self.call('list', name='test').get('pids')

    def test_signal(self):
        self.assertEquals(self.numprocesses('incr', name='test'), 2)

        pids = self.pids()
        self.assertEquals(len(pids), 2)
        to_kill = pids[0]
        self.assertEquals(self.status('signal', name='test', pid=to_kill,
                                      signum=signal.SIGKILL), 'ok')

        time.sleep(1)  # wait for the process to die

        # we still should have two processes, but not the same pids for them
        pids = self.pids()
        self.assertEquals(len(pids), 2)
        self.assertTrue(to_kill not in pids)

    def test_unexisting(self):
        watcher = self.arbiter.get_watcher("test")

        self.assertEquals(len(watcher.processes), 1)
        process = watcher.processes.values()[0]
        to_kill = process.pid
        # the process is killed in an unsual way
        os.kill(to_kill, signal.SIGSEGV)
        # and wait for it to die
        pid, status = os.waitpid(to_kill, 0)
        # ansure the old process is considered "unexisting"
        self.assertEquals(process.status, UNEXISTING)

        # this should clean up and create a new process
        watcher.reap_and_manage_processes()

        # we should have a new process here now
        self.assertEquals(len(watcher.processes), 1)
        process = watcher.processes.values()[0]
        # and that one needs to have a new pid.
        self.assertNotEqual(process.pid, to_kill)
        # and should not be unexisting...
        self.assertNotEqual(process.status, UNEXISTING)

    def test_stats(self):
        resp = self.call("stats").get('infos')
        self.assertTrue("test" in resp)
        watchers = resp['test']

        self.assertEqual(watchers[watchers.keys()[0]]['cmdline'],
                         sys.executable.split(os.sep)[-1])

    def test_streams(self):
        time.sleep(1.)
        # let's see what we got
        self.assertTrue(self.stream.qsize() > 1)

    def test_max_age(self):
        result = self.call('set', name='test',
                           options={'max_age': 1, 'max_age_variance': 0})
        self.assertEquals(result.get('status'), 'ok')
        initial_pids = self.pids()
        time.sleep(3.0)  # allow process to reach max_age and restart
        current_pids = self.pids()
        self.assertEqual(len(current_pids), 1)
        self.assertNotEqual(initial_pids, current_pids)
Exemple #30
0
class TestCircus(unittest.TestCase):
    def setUp(self):
        self.arbiters = []
        self.files = []
        self.dirs = []
        self.tmpfiles = []
        self.cli = CircusClient()

    def tearDown(self):
        self._stop_runners()
        for file in self.files + self.tmpfiles:
            if os.path.exists(file):
                os.remove(file)

        for dir in self.dirs:
            shutil.rmtree(dir)

        self.cli.stop()

    def get_tmpdir(self):
        dir_ = mkdtemp()
        self.dirs.append(dir_)
        return dir_

    def get_tmpfile(self, content=None):
        fd, file = mkstemp()
        os.close(fd)
        self.tmpfiles.append(file)
        if content is not None:
            with open(file, "w") as f:
                f.write(content)
        return file

    @classmethod
    def _create_circus(cls, callable, plugins=None, stats=False, **kw):
        resolve_name(callable)  # used to check the callable
        fd, testfile = mkstemp()
        os.close(fd)
        wdir = os.path.dirname(__file__)
        args = ["generic.py", callable, testfile]
        worker = {"cmd": _CMD, "args": args, "working_dir": wdir, "name": "test", "graceful_timeout": 4}
        worker.update(kw)
        debug = kw.get("debug", False)

        if stats:
            arbiter = get_arbiter(
                [worker],
                background=True,
                plugins=plugins,
                stats_endpoint=DEFAULT_ENDPOINT_STATS,
                statsd=True,
                debug=debug,
                statsd_close_outputs=not debug,
            )
        else:
            arbiter = get_arbiter([worker], background=True, plugins=plugins, debug=debug)
        arbiter.start()
        return testfile, arbiter

    def _run_circus(self, callable, plugins=None, stats=False, **kw):

        testfile, arbiter = TestCircus._create_circus(callable, plugins, stats, **kw)
        self.arbiters.append(arbiter)
        self.files.append(testfile)
        return testfile

    def _stop_runners(self):
        for arbiter in self.arbiters:
            arbiter.stop()
        self.arbiters = []

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)
Exemple #31
0
class ProcfileWatcher(CircusPlugin):
    name = "procfile_watcher"

    def __init__(self, *args, **config):
        super(ProcfileWatcher, self).__init__(*args, **config)
        self.loop_rate = config.get("loop_rate", 3)  # in seconds
        self.procfile_path = config.get("app_path",
                                        "/home/application/current/Procfile")
        self.working_dir = config.get("working_dir",
                                      "/home/application/current")
        self.apprc = config.get("apprc", "/home/application/apprc")
        self.port = config.get("port", "8888")
        self.uid = config.get("uid", "ubuntu")
        self.gid = config.get("gid", self.uid)
        self.stderr_stream = {
            "class": config.get("stderr_stream", "tsuru.stream.Stream")
        }
        self.stdout_stream = {
            "class": config.get("stdout_stream", "tsuru.stream.Stream")
        }
        file_watcher = FileWatcher(self.procfile_path, self.reload_procfile)
        self.period = ioloop.PeriodicCallback(file_watcher,
                                              self.loop_rate * 1000, self.loop)
        self.circus_client = CircusClient()

    def get_cmd(self, name):
        return self.call("get", name=name, keys=["cmd"])["options"]["cmd"]

    def handle_init(self):
        self.period.start()

    def handle_stop(self):
        self.period.stop()

    def handle_recv(self, data):
        pass

    def load_envs(self):
        env = {"port": self.port, "PORT": self.port}
        env.update(common.load_envs(self.apprc))
        return env

    def add_watcher(self, name, cmd):
        env = self.load_envs()
        cmd = replace_args(cmd, **env)
        stderr_stream = self.stderr_stream.copy()
        stdout_stream = self.stdout_stream.copy()
        stdout_stream["watcher_name"] = stderr_stream["watcher_name"] = name
        options = {
            "env": env,
            "copy_env": True,
            "working_dir": self.working_dir,
            "stderr_stream": stderr_stream,
            "stdout_stream": stdout_stream,
            "uid": self.uid,
            "gid": self.gid,
        }
        self.circus_client.call({
            "command": "add",
            "properties": {
                "cmd": cmd,
                "name": name,
                "args": [],
                "options": options,
                "start": True,
                "priority": 2,
            },
        })

    def remove_watcher(self, name):
        self.call("rm", name=name)

    def change_cmd(self, name, cmd):
        env = self.load_envs()
        cmd = replace_args(cmd, **env)
        self.call("set", name=name, options={"cmd": cmd})

    def commands(self, procfile):
        cmds = self.call("status")["statuses"]
        if "tsuru-hooks" in cmds:
            del cmds["tsuru-hooks"]
        cmds_names = set(
            [k for k in cmds.keys() if not k.startswith("plugin:")])
        new_cmds = set(procfile.commands.keys())
        to_remove = cmds_names.difference(new_cmds)
        to_add = new_cmds.difference(cmds_names)
        to_change_names = cmds_names.intersection(new_cmds)
        to_change = {}
        for name in to_change_names:
            if self.get_cmd(name) != procfile.commands.get(name):
                to_change[name] = procfile.commands[name]
        return to_add, to_remove, to_change

    def reload_procfile(self):
        with open(self.procfile_path) as file:
            procfile = Procfile(file.read())
            to_add, to_remove, to_change = self.commands(procfile)

            for name in to_remove:
                self.remove_watcher(name)

            for name in to_add:
                self.add_watcher(name=name, cmd=procfile.commands[name])

            for name, cmd in to_change.items():
                self.change_cmd(name=name, cmd=procfile.commands[name])
Exemple #32
0
class TestWatcher(TestCircus):
    def setUp(self):
        super(TestWatcher, self).setUp()
        self.stream = QueueStream()
        dummy_process = 'circus.tests.test_watcher.run_process'
        self.test_file = self._run_circus(
            dummy_process, stdout_stream={'stream': self.stream})
        self.arbiter = self.arbiters[-1]
        self.cli = CircusClient()

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)

    def tearDown(self):
        super(TestWatcher, self).tearDown()
        self.cli.stop()

    def status(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('status')

    def numprocesses(self, cmd, **props):
        resp = self.call(cmd, **props)
        return resp.get('numprocesses')

    def pids(self):
        return self.call('list', name='test').get('pids')

    def test_signal(self):
        self.assertEquals(self.numprocesses('incr', name='test'), 2)

        pids = self.pids()
        self.assertEquals(len(pids), 2)
        to_kill = pids[0]
        self.assertEquals(
            self.status('signal',
                        name='test',
                        pid=to_kill,
                        signum=signal.SIGKILL), 'ok')

        time.sleep(1)  # wait for the process to die

        # we still should have two processes, but not the same pids for them
        pids = self.pids()
        self.assertEquals(len(pids), 2)
        self.assertTrue(to_kill not in pids)

    def test_unexisting(self):
        watcher = self.arbiter.get_watcher("test")

        self.assertEquals(len(watcher.processes), 1)
        process = watcher.processes.values()[0]
        to_kill = process.pid
        # the process is killed in an unsual way
        os.kill(to_kill, signal.SIGSEGV)
        # and wait for it to die
        pid, status = os.waitpid(to_kill, 0)
        # ansure the old process is considered "unexisting"
        self.assertEquals(process.status, UNEXISTING)

        # this should clean up and create a new process
        watcher.reap_and_manage_processes()

        # we should have a new process here now
        self.assertEquals(len(watcher.processes), 1)
        process = watcher.processes.values()[0]
        # and that one needs to have a new pid.
        self.assertNotEqual(process.pid, to_kill)
        # and should not be unexisting...
        self.assertNotEqual(process.status, UNEXISTING)

    def test_stats(self):
        resp = self.call("stats").get('infos')
        self.assertTrue("test" in resp)
        watchers = resp['test']

        self.assertEqual(watchers[watchers.keys()[0]]['cmdline'],
                         sys.executable.split(os.sep)[-1])

    def test_streams(self):
        time.sleep(1.)
        # let's see what we got
        self.assertTrue(self.stream.qsize() > 1)

    def test_max_age(self):
        result = self.call('set',
                           name='test',
                           options={
                               'max_age': 1,
                               'max_age_variance': 0
                           })
        self.assertEquals(result.get('status'), 'ok')
        initial_pids = self.pids()
        time.sleep(3.0)  # allow process to reach max_age and restart
        current_pids = self.pids()
        self.assertEqual(len(current_pids), 1)
        self.assertNotEqual(initial_pids, current_pids)
Exemple #33
0
class TestTrainer(TestCircus):

    def setUp(self):
        super(TestTrainer, self).setUp()
        dummy_process = 'circus.tests.test_arbiter.run_dummy'
        self.test_file = self._run_circus(dummy_process)
        self.cli = CircusClient()

    def tearDown(self):
        super(TestTrainer, self).tearDown()
        self.cli.stop()

    def test_numwatchers(self):
        msg = make_message("numwatchers")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_numprocesses(self):
        msg = make_message("numprocesses")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numprocesses"), 1)

    def test_processes(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1])

        msg2 = make_message("incr", name="test")
        self.cli.call(msg2)

        resp = self.cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1, 2])

    def test_watchers(self):
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test"])

    def _get_cmd(self):
        fd, testfile = mkstemp()
        os.close(fd)
        cmd = '%s generic.py %s %s' % (sys.executable,
                        'circus.tests.test_arbiter.run_dummy', testfile)

        return cmd

    def _get_cmd_args(self):
        fd, testfile = mkstemp()
        os.close(fd)
        cmd = sys.executable
        args = ['generic.py', 'circus.tests.test_arbiter.run_dummy',
                testfile]
        return cmd, args

    def test_add_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher1(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test", "test1"])

    def test_add_watcher2(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 2)

    def test_add_watcher3(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(msg)
        self.assertTrue(resp.get('status'), 'error')

    def test_add_watcher4(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher5(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_rm_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        msg = make_message("rm", name="test1")
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_stop(self):
        resp = self.cli.call(make_message("quit"))
        self.assertEqual(resp.get("status"), "ok")
        self.assertRaises(CallError, self.cli.call, make_message("list"))

    def test_reload(self):
        resp = self.cli.call(make_message("reload"))
        self.assertEqual(resp.get("status"), "ok")

    def test_reload1(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('processes')

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        msg2 = make_message("list", name="test")
        resp = self.cli.call(msg2)
        processes2 = resp.get('processes')

        self.assertNotEqual(processes1, processes2)

    def test_reload2(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('processes')
        self.assertEqual(processes1, [1])

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        make_message("list", name="test")
        resp = self.cli.call(msg1)

        processes2 = resp.get('processes')
        self.assertEqual(processes2, [2])

    def test_stop_watchers(self):
        resp = self.cli.call(make_message("stop"))
        self.assertEqual(resp.get("status"), "ok")

    def test_stop_watchers1(self):
        self.cli.call(make_message("stop"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get("status"), "stopped")

    def test_stop_watchers2(self):
        self.cli.call(make_message("stop", name="test"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "stopped")

    def test_stop_watchers3(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        self.cli.call(make_message("stop", name="test1"))
        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get('status'), "stopped")

        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "active")
Exemple #34
0
class StatsStreamer(object):
    def __init__(self, endpoint, pubsub_endoint, stats_endpoint):
        self.topic = 'watcher.'
        self.ctx = zmq.Context()
        self.pubsub_endpoint = pubsub_endoint
        self.sub_socket = self.ctx.socket(zmq.SUB)
        self.sub_socket.setsockopt(zmq.SUBSCRIBE, self.topic)
        self.sub_socket.connect(self.pubsub_endpoint)
        self.loop = ioloop.IOLoop()
        self.substream = zmqstream.ZMQStream(self.sub_socket, self.loop)
        self.substream.on_recv(self.handle_recv)
        self.client = CircusClient(context=self.ctx, endpoint=endpoint)
        self.cmds = get_commands()
        self.watchers = defaultdict(list)
        self._pids = defaultdict(list)
        self.running = False
        self.stopped = False
        self.lock = threading.RLock()
        self.results = Queue.Queue()
        self.stats = StatsCollector(self)
        self.publisher = StatsPublisher(self, stats_endpoint, context=self.ctx)

    def get_watchers(self):
        return self._pids.keys()

    def get_pids(self, watcher=None):
        if watcher is not None:
            return self._pids[watcher]
        return chain(self._pid.values())

    def get_circus_pids(self):
        # getting the circusd pid
        msg = self.cmds['dstats'].make_message()
        res = self.client.call(msg)
        return [('circusd-stats', os.getpid()),
                ('circusd', res['info']['pid'])]

    def _init(self):
        with self.lock:
            self.stopped = False
            self._pids.clear()
            # getting the initial list of watchers/pids
            msg = self.cmds['list'].make_message()
            res = self.client.call(msg)
            for watcher in res['watchers']:
                msg = self.cmds['listpids'].make_message(name=watcher)
                res = self.client.call(msg)
                for pid in res['pids']:
                    if pid in self._pids[watcher]:
                        continue
                    self._pids[watcher].append(pid)

    def remove_pid(self, watcher, pid):
        logger.debug('Removing %d from %s' % (pid, watcher))
        if pid in self._pids[watcher]:
            with self.lock:
                self._pids[watcher].remove(pid)

    def append_pid(self, watcher, pid):
        logger.debug('Adding %d in %s' % (pid, watcher))
        if pid in self._pids[watcher]:
            return
        with self.lock:
            self._pids[watcher].append(pid)

    def start(self):
        logger.info('Starting the stats streamer')
        self._init()
        logger.debug('Initial list is ' + str(self._pids))
        self.running = True
        self.stats.start()
        self.publisher.start()
        logger.debug('Now looping to get circusd events')

        while self.running:
            try:
                self.loop.start()
            except zmq.ZMQError as e:
                logger.debug(str(e))

                if e.errno == errno.EINTR:
                    continue
                elif e.errno == zmq.ETERM:
                    break
                else:
                    logger.debug("got an unexpected error %s (%s)", str(e),
                                 e.errno)
                    raise
            else:
                break

        self.sub_socket.close()

    def handle_recv(self, data):
        topic, msg = data
        try:
            __, watcher, action = topic.split('.')
            msg = json.loads(msg)
            if action != 'start' and self.stopped:
                self._init()
            if action in ('reap', 'kill'):
                # a process was reaped
                pid = msg['process_pid']
                self.remove_pid(watcher, pid)
            elif action == 'spawn':
                pid = msg['process_pid']
                self.append_pid(watcher, pid)
            elif action == 'start':
                self._init()
            elif action == 'stop':
                # nothing to do
                self.stopped = True
            else:
                logger.debug('Unknown action: %r' % action)
                logger.debug(msg)
        except Exception:
            logger.exception('Failed to treat %r' % msg)

    def stop(self):
        self.running = False
        self.publisher.stop()
        self.stats.stop()
        self.ctx.destroy(0)
        logger.info('Stats streamer stopped')
Exemple #35
0
class Client(object):
    def __init__(self, host, port, timeout=15):
        assert type(host) == str
        assert type(port) == int and port >= 0 and port <= 65535
        assert type(timeout) == int and timeout > 0
        self._host = host
        self._port = port
        self._timeout = timeout
        self._arbiter = get_arbiter([])
        self._arbiter.start()
        self._client = CircusClient(timeout=self._timeout,
                                    endpoint='tcp://{0}:{1}'.format(
                                        self._host, self._port))

    """
    Add a watcher:
        This command add a watcher dynamically to a arbiter
    """

    def add_watcher(self, name, command, args=[], autostart=False):
        assert type(name) == str
        assert type(command) == str
        assert type(args) == list
        assert type(autostart) == bool

        addWatcher_command = Dict()
        addWatcher_command.command = 'add'
        addWatcher_command.properties.cmd = command
        addWatcher_command.properties.name = name
        addWatcher_command.properties.args = args
        addWatcher_command.properties.start = autostart

        response = self._client.call(addWatcher_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Reload the arbiter or a watcher:
        This command reloads all the process in a watcher or all watchers
    """

    def reload(self,
               watcher='',
               graceful=True,
               sequential=False,
               waiting=False):
        assert type(watcher) == str
        assert type(graceful) == bool
        assert type(sequential) == bool
        assert type(waiting) == bool

        reload_command = Dict()
        reload_command.command = 'reload'
        reload_command.properties.name = watcher
        reload_command.properties.graceful = graceful
        reload_command.properties.sequential = sequential
        reload_command.properties.waiting = waiting

        response = self._client.call(reload_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Restart the arbiter or a watcher:
        This command restart all the process in a watcher or all watchers
    """

    def restart(self, watcher='', waiting=False):
        assert type(watcher) == str
        assert type(waiting) == bool

        restart_command = Dict()
        restart_command.command = 'restart'
        restart_command.properties.name = watcher
        restart_command.properties.waiting = waiting

        response = self._client.call(restart_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Remove a watcher:
        This command removes a watcher dynamically from the arbiter
    """

    def rm_watcher(self, watcher, nonstop=False, waiting=False):
        assert type(watcher) == str
        assert type(nonstop) == bool
        assert type(waiting) == bool

        rm_command = Dict()
        rm_command.command = 'rm'
        rm_command.properties.name = watcher
        rm_command.properties.nonstop = nonstop
        rm_command.properties.waiting = waiting

        response = self._client.call(rm_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Get the number of watchers:
        Get the number of watchers in a arbiter
    """

    def num_watchers(self):
        numwatchers_command = Dict()
        numwatchers_command.command = 'numwatchers'

        response = self._client.call(numwatchers_command)
        status = response.get('status', None)

        if status and status == 'ok':
            return response.get('numwatchers', 0)
        return 0

    """
        Get list of watchers or processes in a watcher
    """

    # TODO pids not being shown when using a watcher
    def list(self, watcher=''):
        assert type(watcher) == str

        list_command = Dict()
        list_command.command = 'list'

        if watcher:
            list_command.properties.name = watcher
            response = self._client.call(list_command)
            return [int(pid) for pid in response['pids']
                    ] if response['status'] == u'ok' else []
        else:
            response = self._client.call(list_command)
            return [str(w) for w in response['watchers']
                    ] if response['status'] == u'ok' else []

    """
    Start the arbiter or a watcher:
        This command starts all the processes in a watcher or all watchers.
    """

    def start(self, watcher='', waiting=False):
        assert type(watcher) == str
        assert type(waiting) == bool

        start_command = Dict()
        start_command.command = 'start'
        start_command.properties.name = watcher
        start_command.properties.waiting = waiting

        response = self._client.call(start_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Stop watchers:
        This command stops a given watcher or all watchers.
    """

    def stop(self, watcher='', waiting=False):
        assert type(watcher) == str
        assert type(waiting) == bool

        stop_command = Dict()
        stop_command.command = 'stop'
        stop_command.properties.name = watcher
        stop_command.properties.waiting = waiting

        response = self._client.call(stop_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Get the number of processes:
        Get the number of processes in a watcher or in a arbiter
    """

    def num_processes(self, watcher):
        assert type(watcher) == str

        num_command = Dict()
        num_command.command = 'numprocesses'
        num_command.properties.name = watcher

        response = self._client.call(num_command)
        status = response.get('status', None)

        if status and status == 'ok':
            return response.get('numprocesses', 0)
        return 0

    """
    Quit the arbiter immediately:
        When the arbiter receive this command, the arbiter exit.
    """

    def quit(self, waiting=False):
        assert type(waiting) == bool

        quit_command = Dict()
        quit_command.command = 'quit'
        quit_command.waiting = waiting

        response = self._client.call(quit_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Get circusd stats:
       You can get at any time some statistics about circus with the dstat command.
    """

    def dstats(self):
        stats_command = Dict()
        stats_command.command = 'dstats'

        response = self._client.call(stats_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('info', None):
                return literal_eval(str(response['info']))
        return {}

    """
    Get the status of a watcher or all watchers:
        This command start get the status of a watcher or all watchers
    """

    def status(self, watcher=''):
        assert type(watcher) == str

        status_command = Dict()
        status_command.command = 'status'

        if watcher:
            status_command.properties.name = watcher
            response = self._client.call(status_command)
            if response.get('status', None):
                return str(response['status'])
        else:
            response = self._client.call(status_command)
            if response.get('statuses', None):
                s = []
                watchers = literal_eval(str(response[u'statuses']))

                for w in response['statuses']:
                    s.append({'name': str(w), 'status': str(watchers[w])})
                return s
        return None

    """
    Reload the configuration file:
        This command reloads the configuration file, so changes in the
        configuration file will be reflected in the configuration of
        circus.
    """

    def reload_configuration(self, waiting=False):
        assert type(waiting) == bool

        reload_command = Dict()
        reload_command.command = 'reloadconfig'
        reload_command.properties.waiting = waiting

        response = self._client.call(reload_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """"
    Send a signal:
        This command allows you to send a signal to all processes in a watcher,
        a specific process in a watcher or its children.
    """

    def send_signal(self,
                    watcher,
                    signum,
                    pid=0,
                    children=False,
                    childpid=0,
                    recursive=False):
        assert type(watcher) == str
        assert type(signum) == int and signum > 0 and signum < 32
        assert type(pid) == int and pid >= 0
        assert type(childpid) == int and childpid >= 0
        assert type(children) == bool
        assert type(recursive) == bool

        signal_command = Dict()
        signal_command.command = 'signal'
        signal_command.properties.name = watcher
        signal_command.properties.signum = signum
        signal_command.properties.pid = pid if pid > 0 else ''
        signal_command.properties.children = children
        signal_command.properties.childpid = childpid if childpid > 0 else ''
        signal_command.properties.recursive = recursive

        signal_command.prune()
        response = self._client.call(signal_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Set a watcher option
    """

    def set(self, watcher, options=[], waiting=False):
        assert type(watcher) == str
        assert type(options) == list
        assert type(waiting) == bool

        for option in options:
            assert type(option) == tuple

        set_command = Dict()
        set_command.command = 'set'
        set_command.properties.name = watcher

        for option in options:
            set_command.properties.options[option[0]] = option[1]

        response = self._client.call(set_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Get process infos:
       You can get at any time some statistics about your processes
       with the stat command.
    """

    def stats(self, watcher, process='', extended=False):
        assert type(watcher) == str
        assert type(process) == str
        assert type(extended) == bool

        stats_command = Dict()
        stats_command.command = 'stats'
        stats_command.properties.name = watcher

        if process:
            stats_command.properties.process = process
            stats_command.properties.extended = extended

        response = self._client.call(stats_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('info', None):
                return literal_eval(str(response['info']))
        return {}

    """
    Get the value of all options for a watcher:
        This command returns all option values for a given watcher.
    """

    def options(self, watcher):
        assert type(watcher) == str

        options_command = Dict()
        options_command.command = 'options'
        options_command.properties.name = watcher

        response = self._client.call(options_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('options', None):
                return literal_eval(str(response['options']))
        return {}

    """
    Increment the number of processes in a watcher:
        This comment increment the number of processes in a watcher by num.
    """

    def inc(self, watcher, num=1, waiting=False):
        assert type(watcher) == str
        assert type(num) == int and num > 0
        assert type(waiting) == bool

        inc_command = Dict()
        inc_command.command = 'incr'
        inc_command.properties.name = watcher
        inc_command.properties.nb = num
        inc_command.properties.waiting = waiting

        response = self._client.call(inc_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('numprocesses', None):
                return response['numprocesses']
        return 0

    """
    Decrement the number of processes in a watcher:
        This comment decrement the number of processes in a watcher by num
    """

    def decr(self, watcher, num=1, waiting=False):
        assert type(watcher) == str
        assert type(num) == int and num > 0
        assert type(waiting) == bool

        decr_command = Dict()
        decr_command.command = 'decr'
        decr_command.properties.name = watcher
        decr_command.properties.nb = num
        decr_command.properties.waiting = waiting

        response = self._client.call(decr_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('numprocesses', None):
                return response['numprocesses']
        return 0

    """
    Get the arbiter options:
        This command return the arbiter options
    """

    def global_options(self, options=[]):
        assert type(options) == list

        global_options_command = Dict()
        global_options_command.command = 'globaloptions'

        response = self._client.call(global_options_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('options', None):
                _options = literal_eval(str(response['options']))

                if options:
                    selected_options = Dict()
                    for option in options:
                        if option in ("endpoint", "pubsub_endpoint",
                                      "check_delay", "multicast_endpoint"):
                            selected_options[option] = _options[option]
                    return selected_options
                else:
                    return _options
        return {}

    """
    Get the value of specific watcher options:
        This command can be used to query the current value of one or more watcher options.
    """

    def get(self, watcher, options=[]):
        assert type(watcher) == str
        assert type(options) == list and options

        get_command = Dict()
        get_command.command = 'get'
        get_command.properties.name = watcher
        get_command.properties['keys'] = options

        response = self._client.call(get_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('options', None):
                return literal_eval(str(response['options']))
        return {}
Exemple #36
0
from circus.client import CircusClient
from circus.util import DEFAULT_ENDPOINT_DEALER

client = CircusClient(endpoint=DEFAULT_ENDPOINT_DEALER)

command = '../bin/python dummy_fly.py 111'
name = 'dummy'


for i in range(50):
    print(client.call("""
    {
        "command": "add",
        "properties": {
            "cmd": "%s",
            "name": "%s",
            "options": {
            "copy_env": true,
            "stdout_stream": {
                "filename": "stdout.log"
            },
            "stderr_stream": {
                "filename": "stderr.log"
            }
            },
            "start": true
        }
    }
    """ % (command, name + str(i))))

Exemple #37
0
class ProcfileWatcher(CircusPlugin):
    name = "procfile_watcher"

    def __init__(self, *args, **config):
        super(ProcfileWatcher, self).__init__(*args, **config)
        self.loop_rate = config.get("loop_rate", 60)  # in seconds
        self.procfile_path = config.get("app_path", "/home/application/current/Procfile")
        self.working_dir = config.get("working_dir", "/home/application/current")
        self.port = config.get("port", "8888")
        self.uid = config.get("uid", "ubuntu")
        self.stderr_stream = {"class": config.get("stderr_stream", "tsuru.stream.Stream")}
        self.stdout_stream = {"class": config.get("stdout_stream", "tsuru.stream.Stream")}
        self.period = ioloop.PeriodicCallback(self.look_after, self.loop_rate * 1000, self.loop)
        self.circus_client = CircusClient()

    def handle_init(self):
        self.period.start()

    def handle_stop(self):
        self.period.stop()

    def handle_recv(self, data):
        pass

    def add_watcher(self, name, cmd):
        options = {
            "env": {"port": self.port},
            "copy_env": True,
            "working_dir": self.working_dir,
            "stderr_stream": self.stderr_stream,
            "stdout_stream": self.stdout_stream,
            "uid": self.uid,
        }
        self.circus_client.call(json.dumps({
            "command": "add",
            "properties": {
            "cmd":  cmd,
            "name": name,
            "args": [],
            "options": options,
            "start": True,
        }}))

    def remove_watcher(self, name):
        self.call("rm", name=name)

    def commands(self, procfile):
        cmds = set(self.call("status")["statuses"].keys())
        new_cmds = set(procfile.commands.keys())
        to_remove = cmds.difference(new_cmds)
        to_add = new_cmds.difference(cmds)
        return to_add, to_remove

    def look_after(self):
        if os.path.exists(self.procfile_path):
            with open(self.procfile_path) as file:
                procfile = Procfile(file.read())
                to_add, to_remove = self.commands(procfile)

                for name in to_remove:
                    self.remove_watcher(name)

                for name in to_add:
                    self.add_watcher(name=name, cmd=procfile.commands[name])
Exemple #38
0
class MetWorkCircusClient(object):
    def __init__(self, timeout=10):
        self.module = os.environ["MFMODULE"]
        self.endpoint = os.environ["%s_CIRCUS_ENDPOINT" % self.module]
        self.timeout = timeout
        self.client = CircusClient(endpoint=self.endpoint,
                                   timeout=self.timeout)

    def check(self):
        if not os.path.exists(self.endpoint.replace('ipc://', '')):
            return False
        tmp = self.cmd("globaloptions")
        if tmp is None or (tmp.get('status', None) != 'ok'):
            return False
        return True

    def wait(self, timeout=10, cli_display=True):
        with self._mfprogress(cli_display=cli_display) as progress:
            txt = "- Waiting for circus daemon..."
            before = datetime.datetime.now()
            after = datetime.datetime.now()
            t = progress.add_task(txt, total=timeout)
            while (after - before).total_seconds() < timeout:
                if self.check():
                    progress.complete_task(t)
                    return True
                time.sleep(1)
                after = datetime.datetime.now()
                delta = (after - before).total_seconds()
                progress.update(t, completed=int(delta))
            progress.complete_task_nok(t)
            return False

    def _cmd(self, cmd, **properties):
        reply = self.client.call({"command": cmd, "properties": properties})
        status = "nok"
        try:
            status = reply["status"]
        except Exception:
            pass
        if status != "ok":
            try:
                if "arbiter is already running" in reply['reason']:
                    return {"status": "already_running"}
            except Exception:
                pass
            return None
        return reply

    def cmd(self, cmd, **properties):
        before = datetime.datetime.now()
        while ((datetime.datetime.now() - before).total_seconds()) < 10:
            try:
                tmp = self._cmd(cmd, **properties)
            except CallError:
                return None
            if tmp is None or (tmp.get('status', None) != "already_running"):
                return tmp
            time.sleep(0.2)

    def list_watchers(self):
        tmp = self.cmd("list")
        if tmp is None:
            return None
        return tmp["watchers"]

    def list_watchers_by_plugin_pattern(self, plugin_name_pattern):
        plugin_key = self.module.lower() + "_plugin"
        watchers = self.list_watchers()
        res = []
        if watchers is None:
            return res
        for watcher in watchers:
            options = self.options(name=watcher)
            if plugin_key not in options:
                continue
            if fnmatch.fnmatch(options[plugin_key], plugin_name_pattern):
                res.append(watcher)
        return res

    def stop_watcher(self,
                     cli_display=True,
                     indent=0,
                     timeout=10,
                     **properties):
        name = properties["name"]
        with self._mfprogress(cli_display=cli_display) as progress:
            txt = " " * indent + "- Scheduling stop of %s" % name
            t = progress.add_task(txt, total=timeout)
            statuses = self.statuses()
            if name not in statuses:
                progress.complete_task_warning(t)
                return None
            if statuses[name] == "stopped":
                progress.complete_task_warning(t, "already stopped")
                return "stopped"
            if statuses[name] == "stopping":
                progress.complete_task_warning(t, "already stopping")
                return "stopping"
            before = datetime.datetime.now()
            after = datetime.datetime.now()
            while (after - before).total_seconds() < timeout:
                self.cmd("stop", **properties)
                statuses = self.statuses()
                if name not in statuses or statuses[name] in ("stopping",
                                                              "stopped"):
                    progress.complete_task(t)
                    return statuses[name]
                time.sleep(1)
                after = datetime.datetime.now()
                delta = (after - before).total_seconds()
                progress.update(t, completed=int(delta))
            progress.complete_task_nok(t)
            return "failed"

    def start_watcher(self,
                      cli_display=True,
                      indent=0,
                      timeout=10,
                      **properties):
        name = properties["name"]
        with self._mfprogress(cli_display=cli_display) as progress:
            txt = " " * indent + "- Starting of %s" % name
            t = progress.add_task(txt, total=timeout)
            statuses = self.statuses()
            if name not in statuses:
                progress.complete_task_nok(t)
                return None
            if statuses[name] == "starting":
                progress.complete_task_warning(t, "already starting")
                return "starting"
            if statuses[name] == "active":
                progress.complete_task_warning(t, "already started")
                return "active"
            before = datetime.datetime.now()
            after = datetime.datetime.now()
            while (after - before).total_seconds() < timeout:
                tmp = self.cmd("start", **properties)
                status = tmp.get("status", None) if tmp is not None else None
                if status == "ok":
                    progress.complete_task(t)
                    return status
                time.sleep(1)
                after = datetime.datetime.now()
                delta = (after - before).total_seconds()
                progress.update(t, completed=int(delta))
            progress.complete_task_nok(t)
            return "failed"

    def start_watchers(self, cli_display=True, indent=0, **properties):
        names = properties["names"]
        for name in names:
            self.start_watcher(cli_display=cli_display,
                               indent=indent,
                               name=name,
                               **properties)

    def wait_watcher_started(self,
                             cli_display=True,
                             timeout=20,
                             indent=0,
                             **properties):
        name = properties["name"]
        with self._mfprogress(cli_display=cli_display) as progress:
            txt = " " * indent + "- Waiting for start of %s..." % name
            t = progress.add_task(txt, total=timeout)
            before = datetime.datetime.now()
            after = datetime.datetime.now()
            while (after - before).total_seconds() < timeout:
                statuses = self.statuses()
                if name in statuses:
                    if statuses[name] == "active":
                        progress.complete_task(t)
                        return True
                time.sleep(1)
                after = datetime.datetime.now()
                delta = (after - before).total_seconds()
                progress.update(t, completed=int(delta))
            progress.complete_task_nok(t)
            return False

    def _mfprogress(self, cli_display=True):
        console = None
        if not cli_display:
            console = rich.console.Console(file=open(os.devnull, "w"))
        return MFProgress(console=console)

    def wait_watcher_stopped(self,
                             cli_display=True,
                             timeout=None,
                             indent=0,
                             **properties):
        name = properties["name"]
        if timeout is None:
            timeout = 300
            try:
                timeout = int(self.options(name=name)['graceful_timeout'])
            except Exception:
                pass
        with self._mfprogress(cli_display=cli_display) as progress:
            txt = " " * indent + "- Waiting for stop of %s..." % name
            t = progress.add_task(txt, total=timeout)
            before = datetime.datetime.now()
            after = datetime.datetime.now()
            while (after - before).total_seconds() < timeout:
                statuses = self.statuses()
                if name not in statuses or statuses[name] == "stopped":
                    progress.complete_task(t)
                    return True
                time.sleep(1)
                after = datetime.datetime.now()
                delta = (after - before).total_seconds()
                progress.update(t, completed=int(delta))
            progress.complete_task_nok(t)
            return False

    def statuses(self):
        tmp = self.cmd("status")
        if tmp is None:
            return None
        return tmp["statuses"]

    def list_pids(self, **properties):
        tmp = self.cmd("list", **properties)
        if tmp is None:
            return None
        return tmp["pids"]

    def options(self, **properties):
        tmp = self.cmd("options", **properties)
        if tmp is None:
            return None
        return tmp["options"]
Exemple #39
0
class TestCircus(unittest.TestCase):
    def setUp(self):
        self.arbiters = []
        self.files = []
        self.tmpfiles = []
        self.cli = CircusClient()

    def tearDown(self):
        self._stop_runners()
        for file in self.files + self.tmpfiles:
            if os.path.exists(file):
                os.remove(file)
        self.cli.stop()

    def get_tmpfile(self, content=None):
        fd, file = mkstemp()
        os.close(fd)
        self.tmpfiles.append(file)
        if content is not None:
            with open(file, 'w') as f:
                f.write(content)
        return file

    def _run_circus(self, callable, plugins=None, stats=False, **kw):
        resolve_name(callable)  # used to check the callable
        fd, testfile = mkstemp()
        os.close(fd)
        wdir = os.path.dirname(__file__)
        args = ['generic.py', callable, testfile]
        worker = {
            'cmd': _CMD,
            'args': args,
            'working_dir': wdir,
            'name': 'test',
            'graceful_timeout': 4
        }
        worker.update(kw)
        if stats:
            arbiter = get_arbiter([worker],
                                  background=True,
                                  plugins=plugins,
                                  stats_endpoint=DEFAULT_ENDPOINT_STATS,
                                  debug=kw.get('debug', False))
        else:
            arbiter = get_arbiter([worker],
                                  background=True,
                                  plugins=plugins,
                                  debug=kw.get('debug', False))

        arbiter.start()
        time.sleep(.3)
        self.arbiters.append(arbiter)
        self.files.append(testfile)
        return testfile

    def _stop_runners(self):
        for arbiter in self.arbiters:
            arbiter.stop()
        self.arbiters = []

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)
Exemple #40
0
class TestCircus(unittest.TestCase):

    arbiter_factory = get_arbiter

    def setUp(self):
        self.arbiters = []
        self.files = []
        self.dirs = []
        self.tmpfiles = []
        self.cli = CircusClient()

    def tearDown(self):
        self._stop_runners()
        for file in self.files + self.tmpfiles:
            if os.path.exists(file):
                os.remove(file)

        for dir in self.dirs:
            shutil.rmtree(dir)

        self.cli.stop()

    def get_tmpdir(self):
        dir_ = mkdtemp()
        self.dirs.append(dir_)
        return dir_

    def get_tmpfile(self, content=None):
        fd, file = mkstemp()
        os.close(fd)
        self.tmpfiles.append(file)
        if content is not None:
            with open(file, 'w') as f:
                f.write(content)
        return file

    @classmethod
    def _create_circus(cls, callable, plugins=None, stats=False, **kw):
        resolve_name(callable)   # used to check the callable
        fd, testfile = mkstemp()
        os.close(fd)
        wdir = os.path.dirname(__file__)
        args = ['generic.py', callable, testfile]
        worker = {'cmd': _CMD, 'args': args, 'working_dir': wdir,
                  'name': 'test', 'graceful_timeout': 2}
        worker.update(kw)
        debug = kw.get('debug', False)

        fact = cls.arbiter_factory
        if stats:
            arbiter = fact([worker], background=True, plugins=plugins,
                           stats_endpoint=DEFAULT_ENDPOINT_STATS,
                           statsd=True,
                           debug=debug, statsd_close_outputs=not debug)
        else:
            arbiter = fact([worker], background=True, plugins=plugins,
                           debug=debug)
        arbiter.start()
        return testfile, arbiter

    def _run_circus(self, callable, plugins=None, stats=False, **kw):

        testfile, arbiter = TestCircus._create_circus(callable, plugins, stats,
                                                      **kw)
        self.arbiters.append(arbiter)
        self.files.append(testfile)
        return testfile

    def _stop_runners(self):
        for arbiter in self.arbiters:
            arbiter.stop()
        self.arbiters = []

    def call(self, cmd, **props):
        msg = make_message(cmd, **props)
        return self.cli.call(msg)
Exemple #41
0
class LiveClient(object):
    def __init__(self, endpoint):
        self.endpoint = str(endpoint)
        self.stats_endpoint = None
        self.client = CircusClient(endpoint=self.endpoint)
        self.connected = False
        self.watchers = []
        self.plugins = []
        self.stats = defaultdict(list)
        self.dstats = []

    def stop(self):
        self.client.stop()

    def update_watchers(self):
        """Calls circus and initialize the list of watchers.

        If circus is not connected raises an error.
        """
        self.watchers = []
        # trying to list the watchers
        try:
            self.connected = True
            for watcher in self.client.send_message('list')['watchers']:
                if watcher == 'circusd-stats':
                    continue
                options = self.client.send_message('options', name=watcher)
                self.watchers.append((watcher, options['options']))
                if watcher.startswith('plugin:'):
                    self.plugins.append(watcher)

            self.watchers.sort()
            self.stats_endpoint = self.get_global_options()['stats_endpoint']
        except CallError:
            self.connected = False

    def killproc(self, name, pid):
        res = self.client.send_message('signal',
                                       name=name,
                                       process=int(pid),
                                       signum=9)
        self.update_watchers()  # will do better later
        return res

    def get_option(self, name, option):
        watchers = dict(self.watchers)
        return watchers[name][option]

    def get_global_options(self):
        return self.client.send_message('globaloptions')['options']

    def get_options(self, name):
        watchers = dict(self.watchers)
        return watchers[name].items()

    def incrproc(self, name):
        res = self.client.send_message('incr', name=name)
        self.update_watchers()  # will do better later
        return res

    def decrproc(self, name):
        res = self.client.send_message('decr', name=name)
        self.update_watchers()  # will do better later
        return res

    def get_stats(self, name, start=0, end=-1):
        return self.stats[name][start:end]

    def get_dstats(self, field, start=0, end=-1):
        stats = self.dstats[start:end]
        res = []
        for stat in stats:
            res.append(stat[field])
        return res

    def get_pids(self, name):
        res = self.client.send_message('list', name=name)
        return res['pids']

    def get_series(self, name, pid, field, start=0, end=-1):
        stats = self.get_stats(name, start, end)
        res = []
        for stat in stats:
            pids = stat['pid']
            if isinstance(pids, list):
                continue
            if str(pid) == str(stat['pid']):
                res.append(stat[field])
        return res

    def get_status(self, name):
        return self.client.send_message('status', name=name)['status']

    def switch_status(self, name):
        msg = cmds['status'].make_message(name=name)
        res = self.client.call(msg)
        status = res['status']
        if status == 'active':
            # stopping the watcher
            msg = cmds['stop'].make_message(name=name)
        else:
            msg = cmds['start'].make_message(name=name)
        res = self.client.call(msg)
        return res

    def add_watcher(self, name, cmd, **kw):
        res = self.client.send_message('add', name=name, cmd=cmd)
        if res['status'] == 'ok':
            # now configuring the options
            options = {}
            options['numprocesses'] = int(kw.get('numprocesses', '5'))
            options['working_dir'] = kw.get('working_dir')
            options['shell'] = kw.get('shell', 'off') == 'on'
            res = self.client.send_message('set', name=name, options=options)
            self.update_watchers()  # will do better later
        return res
Exemple #42
0
class CircusMgr(object):
    """Fermentrack Circus Handler, It is a simple wrapper around
    circus client, any errors raised as CircusException"""
    def __init__(self,
                 connection_timeout=2,
                 circus_endpoint=DEFAULT_ENDPOINT_DEALER):
        self._client = CircusClient(timeout=connection_timeout,
                                    endpoint=circus_endpoint)

    def _call(self, command, **props):
        message = {"command": command, "properties": props or {}}
        try:
            res = self._client.call(message)
        except (CallError) as callerr:
            LOG.debug("Error from circus", exc_info=True)
            raise CircusException(
                "Could not send message to circus: {}".format(callerr))
        if res['status'] == u'error':
            raise CircusException("Error: {}".format(res['reason']))
        return res

    def signal(self, name, signal=9):
        """Send signal to process, signal defaults to 9 (SIGTERM)"""
        self._call("signal", name=name, signal=signal)

    def reload(self, name, waiting=False, graceful=True, sequential=False):
        """Reload the arbiter/watcher

        If ``waiting`` is False (default), the call will return immediately
        after calling ``reload`` process.
        """
        response = self._call("reload",
                              name=name,
                              graceful=graceful,
                              sequential=sequential,
                              waiting=waiting)
        return True if response['status'] == u'ok' else False

    def start(self, name, waiting=False):
        """Start circus process that has been stopped

        If ``waiting`` is False (default), the call will return immediately
        after calling ``start`` process.
        """
        response = self._call("start", name=name, waiting=waiting)
        return True if response['status'] == u'ok' else False

    def restart(self, name=None):
        """Restart a or all circus process(es)

        If ``name`` is None all processes under circus will be restarted
        """
        if name:
            response = self._call("restart", name=name)
        else:
            response = self._call("restart")
        return True if response['status'] == u'ok' else False

    def stop(self, name, waiting=False):
        """Stop a circus process, like suspend, the processess is stopped but still
        in circus, to resume use ``start``

        If ``waiting`` is False (default), the call will return immediately
        after calling ``stop`` process.
        """
        response = self._call("stop", name=name, waiting=waiting)
        return True if response['status'] == u'ok' else False

    def add_controller(self, cmd, name, logpath):
        """Add a new brewpi controller script"""
        response = self._call("add",
                              cmd=cmd,
                              name=name,
                              start=True,
                              options={
                                  "copy_env": True,
                                  "stdout_stream": {
                                      "class":
                                      "FileStream",
                                      "filename":
                                      u"%s/%s-stdout.log" % (logpath, name),
                                      "max_bytes":
                                      2097152,
                                      "backup_count":
                                      2,
                                  },
                                  "stderr_stream": {
                                      "class":
                                      "FileStream",
                                      "filename":
                                      u"%s/%s-stderr.log" % (logpath, name),
                                      "max_bytes":
                                      2097152,
                                      "backup_count":
                                      2,
                                  }
                              })
        return response

    def remove(self, name):
        """Stop and Remove ``name`` from circus fully"""
        response = self._call("rm", name=name)
        return response

    def get_applications(self, verbose=False):
        """Get currently running processes

        If ``verbose`` is False a simple list will be returned
        if True circus information will be included.
        """
        response = self._call("list")
        if verbose:
            return response
        return response.get("watchers")

    def application_status(self, name, verbose=False):
        """Get process status

        If ``verbose`` is False it will return status, or "not running"
        if True circus information will be included.
        """
        response = self._call("status", name=name)
        if verbose:
            return response
        return str(response['status']
                   ) if response['status'] != u'error' else 'not running'

    def quit_circus(self):
        """quit_circus will quit the circus daemon, and need to be started again
        by some other means
        """
        response = self._call("quit")
        return response
Exemple #43
0
class TestTrainer(TestCircus):
    def setUp(self):
        super(TestTrainer, self).setUp()
        dummy_process = 'circus.tests.test_arbiter.run_dummy'
        self.test_file = self._run_circus(dummy_process)
        self.cli = CircusClient()

    def tearDown(self):
        super(TestTrainer, self).tearDown()
        self.cli.stop()

    def test_numwatchers(self):
        msg = make_message("numwatchers")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_numprocesses(self):
        msg = make_message("numprocesses")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numprocesses"), 1)

    def test_processes(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        self.assertEqual(len(resp.get('pids')), 1)

        msg2 = make_message("incr", name="test")
        self.cli.call(msg2)

        resp = self.cli.call(msg1)
        self.assertEqual(len(resp.get('pids')), 2)

        self.cli.send_message("incr", name="test", nb=2)
        resp = self.cli.call(msg1)
        self.assertEqual(len(resp.get('pids')), 4)

    def test_watchers(self):
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test"])

    def _get_cmd(self):
        fd, testfile = mkstemp()
        os.close(fd)
        cmd = '%s generic.py %s %s' % (
            sys.executable, 'circus.tests.test_arbiter.run_dummy', testfile)

        return cmd

    def _get_cmd_args(self):
        cmd = sys.executable
        args = ['generic.py', 'circus.tests.test_arbiter.run_dummy1']
        return cmd, args

    def _get_options(self, **kwargs):
        if 'graceful_timeout' not in kwargs:
            kwargs['graceful_timeout'] = 4
        return kwargs

    def test_add_watcher(self):
        msg = make_message("add",
                           name="test1",
                           cmd=self._get_cmd(),
                           options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher1(self):
        msg = make_message("add",
                           name="test1",
                           cmd=self._get_cmd(),
                           options=self._get_options())
        self.cli.call(msg)
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test", "test1"])

    def test_add_watcher2(self):
        msg = make_message("add",
                           name="test1",
                           cmd=self._get_cmd(),
                           options=self._get_options())
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 2)

    def test_add_watcher3(self):
        msg = make_message("add",
                           name="test1",
                           cmd=self._get_cmd(),
                           options=self._get_options())
        self.cli.call(msg)
        resp = self.cli.call(msg)
        self.assertTrue(resp.get('status'), 'error')

    def test_add_watcher4(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add",
                           name="test1",
                           cmd=cmd,
                           args=args,
                           options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher5(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add",
                           name="test1",
                           cmd=cmd,
                           args=args,
                           options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher6(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add",
                           name="test1",
                           cmd=cmd,
                           args=args,
                           start=True,
                           options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher7(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add",
                           name="test1",
                           cmd=cmd,
                           args=args,
                           start=True,
                           options=self._get_options(flapping_window=100))
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

        resp = self.cli.call(make_message("options", name="test1"))
        options = resp.get('options', {})
        self.assertEqual(options.get("flapping_window"), 100)

    def test_rm_watcher(self):
        msg = make_message("add",
                           name="test1",
                           cmd=self._get_cmd(),
                           options=self._get_options())
        self.cli.call(msg)
        msg = make_message("rm", name="test1")
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_stop(self):
        resp = self.cli.call(make_message("quit"))
        self.assertEqual(resp.get("status"), "ok")
        self.assertRaises(CallError, self.cli.call, make_message("list"))

    def test_reload(self):
        resp = self.cli.call(make_message("reload"))
        self.assertEqual(resp.get("status"), "ok")

    def test_reload1(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('pids')

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        msg2 = make_message("list", name="test")
        resp = self.cli.call(msg2)
        processes2 = resp.get('pids')

        self.assertNotEqual(processes1, processes2)

    def test_reload2(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('pids')
        self.assertEqual(len(processes1), 1)

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        make_message("list", name="test")
        resp = self.cli.call(msg1)

        processes2 = resp.get('pids')
        self.assertEqual(len(processes2), 1)
        self.assertNotEqual(processes1[0], processes2[0])

    def test_stop_watchers(self):
        resp = self.cli.call(make_message("stop"))
        self.assertEqual(resp.get("status"), "ok")

    def test_stop_watchers1(self):
        self.cli.call(make_message("stop"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get("status"), "stopped")

    def test_stop_watchers2(self):
        self.cli.call(make_message("stop", name="test"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "stopped")

    def test_stop_watchers3(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add",
                           name="test1",
                           cmd=cmd,
                           args=args,
                           options=self._get_options())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        self.cli.call(make_message("stop", name="test1"))
        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get('status'), "stopped")

        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "active")

    def test_plugins(self):
        # killing the setUp runner
        self._stop_runners()
        self.cli.stop()

        fd, datafile = mkstemp()
        os.close(fd)

        # setting up a circusd with a plugin
        dummy_process = 'circus.tests.test_arbiter.run_dummy'
        plugin = 'circus.tests.test_arbiter.Plugin'
        plugins = [{'use': plugin, 'file': datafile}]
        self._run_circus(dummy_process, plugins=plugins)

        # doing a few operations
        def nb_processes():
            return len(cli.send_message('list', name='test').get('pids'))

        def incr_processes():
            return cli.send_message('incr', name='test')

        cli = CircusClient()
        self.assertEqual(nb_processes(), 1)
        incr_processes()
        self.assertEqual(nb_processes(), 2)
        incr_processes()
        self.assertEqual(nb_processes(), 3)

        # wait a bit
        time.sleep(.2)

        # checking what the plugin did
        with open(datafile) as f:
            data = [line for line in f.read().split('\n') if line != '']

        wanted = ['test:spawn', 'test:spawn']
        self.assertEqual(data, wanted)

    def test_singleton(self):
        self._stop_runners()

        dummy_process = 'circus.tests.test_arbiter.run_dummy'
        self._run_circus(dummy_process, singleton=True)
        cli = CircusClient()

        # adding more than one process should fail
        res = cli.send_message('incr', name='test')
        self.assertEqual(res['numprocesses'], 1)
Exemple #44
0
class Client(object):

    def __init__(self, host, port, timeout=15):
        assert type(host) == str
        assert type(port) == int and port >= 0 and port <= 65535
        assert type(timeout) == int and timeout > 0
        self._host = host
        self._port = port
        self._timeout = timeout
        self._arbiter = get_arbiter([])
        self._arbiter.start()
        self._client = CircusClient(timeout=self._timeout,
                                    endpoint='tcp://{0}:{1}'.format(self._host,
                                                                    self._port))

    """
    Add a watcher:
        This command add a watcher dynamically to a arbiter
    """
    def add_watcher(self, name, command, args=[], autostart=False):
        assert type(name) == str
        assert type(command) == str
        assert type(args) == list
        assert type(autostart) == bool

        addWatcher_command = Dict()
        addWatcher_command.command = 'add'
        addWatcher_command.properties.cmd = command
        addWatcher_command.properties.name = name
        addWatcher_command.properties.args = args
        addWatcher_command.properties.start = autostart

        response = self._client.call(addWatcher_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False


    """
    Reload the arbiter or a watcher:
        This command reloads all the process in a watcher or all watchers
    """
    def reload(self, watcher='', graceful=True, sequential=False, waiting=False):
        assert type(watcher) == str
        assert type(graceful) == bool
        assert type(sequential) == bool
        assert type(waiting) == bool

        reload_command = Dict()
        reload_command.command = 'reload'
        reload_command.properties.name = watcher
        reload_command.properties.graceful = graceful
        reload_command.properties.sequential = sequential
        reload_command.properties.waiting = waiting

        response = self._client.call(reload_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Restart the arbiter or a watcher:
        This command restart all the process in a watcher or all watchers
    """
    def restart(self, watcher='', waiting=False):
        assert type(watcher) == str
        assert type(waiting) == bool

        restart_command = Dict()
        restart_command.command = 'restart'
        restart_command.properties.name = watcher
        restart_command.properties.waiting = waiting

        response = self._client.call(restart_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Remove a watcher:
        This command removes a watcher dynamically from the arbiter
    """
    def rm_watcher(self, watcher, nonstop=False, waiting=False):
        assert type(watcher) == str
        assert type(nonstop) == bool
        assert type(waiting) == bool

        rm_command = Dict()
        rm_command.command = 'rm'
        rm_command.properties.name = watcher
        rm_command.properties.nonstop = nonstop
        rm_command.properties.waiting = waiting

        response = self._client.call(rm_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Get the number of watchers:
        Get the number of watchers in a arbiter
    """
    def num_watchers(self):
        numwatchers_command = Dict()
        numwatchers_command.command = 'numwatchers'

        response = self._client.call(numwatchers_command)
        status = response.get('status', None)

        if status and status == 'ok':
            return response.get('numwatchers', 0)
        return 0

    """
        Get list of watchers or processes in a watcher
    """
    # TODO pids not being shown when using a watcher
    def list(self, watcher=''):
        assert type(watcher) == str

        list_command = Dict()
        list_command.command = 'list'

        if watcher:
            list_command.properties.name = watcher
            response = self._client.call(list_command)
            return [int(pid)
                    for pid
                    in response['pids']] if response['status'] == u'ok' else []
        else:
            response = self._client.call(list_command)
            return [str(w)
                    for w
                    in response['watchers']] if response['status'] == u'ok' else []

    """
    Start the arbiter or a watcher:
        This command starts all the processes in a watcher or all watchers.
    """
    def start(self, watcher='', waiting=False):
        assert type(watcher) == str
        assert type(waiting) == bool

        start_command = Dict()
        start_command.command = 'start'
        start_command.properties.name = watcher
        start_command.properties.waiting = waiting

        response = self._client.call(start_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Stop watchers:
        This command stops a given watcher or all watchers.
    """
    def stop(self, watcher='', waiting=False):
        assert type(watcher) == str
        assert type(waiting) == bool

        stop_command = Dict()
        stop_command.command = 'stop'
        stop_command.properties.name = watcher
        stop_command.properties.waiting = waiting

        response = self._client.call(stop_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Get the number of processes:
        Get the number of processes in a watcher or in a arbiter
    """
    def num_processes(self, watcher):
        assert type(watcher) == str

        num_command = Dict()
        num_command.command = 'numprocesses'
        num_command.properties.name = watcher

        response = self._client.call(num_command)
        status = response.get('status', None)

        if status and status == 'ok':
            return response.get('numprocesses', 0)
        return 0

    """
    Quit the arbiter immediately:
        When the arbiter receive this command, the arbiter exit.
    """
    def quit(self, waiting=False):
        assert type(waiting) == bool

        quit_command = Dict()
        quit_command.command = 'quit'
        quit_command.waiting = waiting

        response = self._client.call(quit_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Get circusd stats:
       You can get at any time some statistics about circus with the dstat command.
    """
    def dstats(self):
        stats_command = Dict()
        stats_command.command = 'dstats'

        response = self._client.call(stats_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('info', None):
                return literal_eval(str(response['info']))
        return {}

    """
    Get the status of a watcher or all watchers:
        This command start get the status of a watcher or all watchers
    """
    def status(self, watcher=''):
        assert type(watcher) == str

        status_command = Dict()
        status_command.command = 'status'

        if watcher:
            status_command.properties.name = watcher
            response = self._client.call(status_command)
            if response.get('status', None):
                return str(response['status'])
        else:
            response = self._client.call(status_command)
            if response.get('statuses', None):
                s = []
                watchers = literal_eval(str(response[u'statuses']))

                for w in response['statuses']:
                    s.append({'name':str(w), 'status':str(watchers[w])})
                return s
        return None

    """
    Reload the configuration file:
        This command reloads the configuration file, so changes in the
        configuration file will be reflected in the configuration of
        circus.
    """
    def reload_configuration(self, waiting=False):
        assert type(waiting) == bool

        reload_command = Dict()
        reload_command.command = 'reloadconfig'
        reload_command.properties.waiting = waiting

        response = self._client.call(reload_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """"
    Send a signal:
        This command allows you to send a signal to all processes in a watcher,
        a specific process in a watcher or its children.
    """
    def send_signal(self, watcher, signum, pid=0, children=False, childpid=0, recursive=False):
        assert type(watcher) == str
        assert type(signum) == int and signum > 0 and signum < 32
        assert type(pid) == int and pid >= 0
        assert type(childpid) == int and childpid >= 0
        assert type(children) == bool
        assert type(recursive) == bool

        signal_command = Dict()
        signal_command.command = 'signal'
        signal_command.properties.name = watcher
        signal_command.properties.signum = signum
        signal_command.properties.pid = pid if pid > 0 else ''
        signal_command.properties.children = children
        signal_command.properties.childpid = childpid if childpid > 0 else ''
        signal_command.properties.recursive = recursive

        signal_command.prune()
        response = self._client.call(signal_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Set a watcher option
    """
    def set(self, watcher, options=[], waiting=False):
        assert type(watcher) == str
        assert type(options) == list
        assert type(waiting) == bool

        for option in options:
            assert type(option) == tuple

        set_command = Dict()
        set_command.command = 'set'
        set_command.properties.name = watcher

        for option in options:
            set_command.properties.options[option[0]] = option[1]

        response = self._client.call(set_command)
        response = response.get('status', None)

        if response and response == 'ok':
            return True
        return False

    """
    Get process infos:
       You can get at any time some statistics about your processes
       with the stat command.
    """
    def stats(self, watcher, process='', extended=False):
        assert type(watcher) == str
        assert type(process) == str
        assert type(extended) == bool

        stats_command = Dict()
        stats_command.command = 'stats'
        stats_command.properties.name = watcher

        if process:
            stats_command.properties.process = process
            stats_command.properties.extended = extended

        response = self._client.call(stats_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('info', None):
                return literal_eval(str(response['info']))
        return {}

    """
    Get the value of all options for a watcher:
        This command returns all option values for a given watcher.
    """
    def options(self, watcher):
        assert type(watcher) == str

        options_command = Dict()
        options_command.command = 'options'
        options_command.properties.name = watcher

        response = self._client.call(options_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('options', None):
                return literal_eval(str(response['options']))
        return {}

    """
    Increment the number of processes in a watcher:
        This comment increment the number of processes in a watcher by num.
    """
    def inc(self, watcher, num=1, waiting=False):
        assert type(watcher) == str
        assert type(num) == int and num > 0
        assert type(waiting) == bool

        inc_command = Dict()
        inc_command.command = 'incr'
        inc_command.properties.name = watcher
        inc_command.properties.nb = num
        inc_command.properties.waiting = waiting

        response = self._client.call(inc_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('numprocesses', None):
                return response['numprocesses']
        return 0

    """
    Decrement the number of processes in a watcher:
        This comment decrement the number of processes in a watcher by num
    """
    def decr(self, watcher, num=1, waiting=False):
        assert type(watcher) == str
        assert type(num) == int and num > 0
        assert type(waiting) == bool

        decr_command = Dict()
        decr_command.command = 'decr'
        decr_command.properties.name = watcher
        decr_command.properties.nb = num
        decr_command.properties.waiting = waiting

        response = self._client.call(decr_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('numprocesses', None):
                return response['numprocesses']
        return 0

    """
    Get the arbiter options:
        This command return the arbiter options
    """
    def global_options(self, options=[]):
        assert type(options) == list

        global_options_command = Dict()
        global_options_command.command = 'globaloptions'

        response = self._client.call(global_options_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('options', None):
                _options =  literal_eval(str(response['options']))

                if options:
                    selected_options = Dict()
                    for option in options:
                        if option in ("endpoint", "pubsub_endpoint", "check_delay", "multicast_endpoint"):
                            selected_options[option] = _options[option]
                    return selected_options
                else:
                    return _options
        return {}

    """
    Get the value of specific watcher options:
        This command can be used to query the current value of one or more watcher options.
    """
    def get(self, watcher, options=[]):
        assert type(watcher) == str
        assert type(options) == list and options

        get_command = Dict()
        get_command.command = 'get'
        get_command.properties.name = watcher
        get_command.properties['keys'] = options


        response = self._client.call(get_command)
        status = response.get('status', None)

        if status and status == 'ok':
            if response.get('options', None):
                return literal_eval(str(response['options']))
        return {}
class LiveClient(object):
    def __init__(self, endpoint, ssh_server=None):
        self.endpoint = str(endpoint)
        self.stats_endpoint = None
        self.client = CircusClient(endpoint=self.endpoint,
                                   ssh_server=ssh_server)
        self.connected = False
        self.watchers = []
        self.plugins = []
        self.stats = defaultdict(list)
        self.dstats = []
        self.sockets = None
        self.use_sockets = False
        self.embed_httpd = False

    def stop(self):
        self.client.stop()

    def update_watchers(self):
        """Calls circus and initialize the list of watchers.

        If circus is not connected raises an error.
        """
        self.watchers = []
        self.plugins = []

        # trying to list the watchers
        try:
            self.connected = True
            for watcher in self.client.send_message('list')['watchers']:
                if watcher in ('circusd-stats', 'circushttpd'):
                    if watcher == 'circushttpd':
                        self.embed_httpd = True
                    continue

                options = self.client.send_message('options',
                                                   name=watcher)['options']
                self.watchers.append((watcher, options))
                if watcher.startswith('plugin:'):
                    self.plugins.append(watcher)

                if not self.use_sockets and options.get('use_sockets', False):
                    self.use_sockets = True

            self.watchers.sort()
            self.stats_endpoint = self.get_global_options()['stats_endpoint']
            if self.endpoint.startswith('tcp://'):
                # In case of multi interface binding i.e: tcp://0.0.0.0:5557
                anyaddr = '0.0.0.0'
                ip = self.endpoint.lstrip('tcp://').split(':')[0]
                self.stats_endpoint = self.stats_endpoint.replace(anyaddr, ip)
        except CallError:
            self.connected = False

    def killproc(self, name, pid):
        # killing a proc and its children
        res = self.client.send_message('signal', name=name, pid=int(pid),
                                       signum=9, recursive=True)
        self.update_watchers()  # will do better later
        return res

    def get_option(self, name, option):
        watchers = dict(self.watchers)
        return watchers[name][option]

    def get_global_options(self):
        return self.client.send_message('globaloptions')['options']

    def get_options(self, name):
        watchers = dict(self.watchers)
        return watchers[name].items()

    def incrproc(self, name):
        res = self.client.send_message('incr', name=name)
        self.update_watchers()  # will do better later
        return res

    def decrproc(self, name):
        res = self.client.send_message('decr', name=name)
        self.update_watchers()  # will do better later
        return res

    def get_stats(self, name, start=0, end=-1):
        return self.stats[name][start:end]

    def get_dstats(self, field, start=0, end=-1):
        stats = self.dstats[start:end]
        res = []
        for stat in stats:
            res.append(stat[field])
        return res

    def get_pids(self, name):
        res = self.client.send_message('list', name=name)
        return res['pids']

    def get_sockets(self, force_reload=False):
        if not self.sockets or force_reload:
            res = self.client.send_message('listsockets')
            self.sockets = res['sockets']
        return self.sockets

    def get_series(self, name, pid, field, start=0, end=-1):
        stats = self.get_stats(name, start, end)
        res = []
        for stat in stats:
            pids = stat['pid']
            if isinstance(pids, list):
                continue
            if str(pid) == str(stat['pid']):
                res.append(stat[field])
        return res

    def get_status(self, name):
        return self.client.send_message('status', name=name)['status']

    def switch_status(self, name):
        msg = cmds['status'].make_message(name=name)
        res = self.client.call(msg)
        status = res['status']
        if status == 'active':
            # stopping the watcher
            msg = cmds['stop'].make_message(name=name)
        else:
            msg = cmds['start'].make_message(name=name)
        res = self.client.call(msg)
        return res

    def add_watcher(self, name, cmd, **kw):
        res = self.client.send_message('add', name=name, cmd=cmd)
        if res['status'] == 'ok':
            # now configuring the options
            options = {}
            options['numprocesses'] = int(kw.get('numprocesses', '5'))
            options['working_dir'] = kw.get('working_dir')
            options['shell'] = kw.get('shell', 'off') == 'on'
            res = self.client.send_message('set', name=name, options=options)
            self.update_watchers()  # will do better later
        return res
Exemple #46
0
class LiveClient(object):
    def __init__(self, endpoint):
        self.endpoint = str(endpoint)
        self.stats_endpoint = None
        self.client = CircusClient(endpoint=self.endpoint)
        self.connected = False
        self.watchers = []
        self.plugins = []
        self.stats = defaultdict(list)
        self.dstats = []
        self.sockets = None
        self.use_sockets = False
        self.embed_httpd = False

    def stop(self):
        self.client.stop()

    def update_watchers(self):
        """Calls circus and initialize the list of watchers.

        If circus is not connected raises an error.
        """
        self.watchers = []
        # trying to list the watchers
        try:
            self.connected = True
            for watcher in self.client.send_message('list')['watchers']:
                if watcher in ('circusd-stats', 'circushttpd'):
                    if watcher == 'circushttpd':
                        self.embed_httpd = True
                    continue

                options = self.client.send_message('options',
                                                   name=watcher)['options']
                self.watchers.append((watcher, options))
                if watcher.startswith('plugin:'):
                    self.plugins.append(watcher)

                if not self.use_sockets and options.get('use_sockets', False):
                    self.use_sockets = True

            self.watchers.sort()
            self.stats_endpoint = self.get_global_options()['stats_endpoint']
        except CallError:
            self.connected = False

    def killproc(self, name, pid):
        res = self.client.send_message('signal', name=name, pid=int(pid),
                                       signum=9, children=True)
        self.update_watchers()  # will do better later
        return res

    def get_option(self, name, option):
        watchers = dict(self.watchers)
        return watchers[name][option]

    def get_global_options(self):
        return self.client.send_message('globaloptions')['options']

    def get_options(self, name):
        watchers = dict(self.watchers)
        return watchers[name].items()

    def incrproc(self, name):
        res = self.client.send_message('incr', name=name)
        self.update_watchers()  # will do better later
        return res

    def decrproc(self, name):
        res = self.client.send_message('decr', name=name)
        self.update_watchers()  # will do better later
        return res

    def get_stats(self, name, start=0, end=-1):
        return self.stats[name][start:end]

    def get_dstats(self, field, start=0, end=-1):
        stats = self.dstats[start:end]
        res = []
        for stat in stats:
            res.append(stat[field])
        return res

    def get_pids(self, name):
        res = self.client.send_message('list', name=name)
        return res['pids']

    def get_sockets(self, force_reload=False):
        if not self.sockets or force_reload:
            res = self.client.send_message('listsockets')
            self.sockets = res['sockets']
        return self.sockets

    def get_series(self, name, pid, field, start=0, end=-1):
        stats = self.get_stats(name, start, end)
        res = []
        for stat in stats:
            pids = stat['pid']
            if isinstance(pids, list):
                continue
            if str(pid) == str(stat['pid']):
                res.append(stat[field])
        return res

    def get_status(self, name):
        return self.client.send_message('status', name=name)['status']

    def switch_status(self, name):
        msg = cmds['status'].make_message(name=name)
        res = self.client.call(msg)
        status = res['status']
        if status == 'active':
            # stopping the watcher
            msg = cmds['stop'].make_message(name=name)
        else:
            msg = cmds['start'].make_message(name=name)
        res = self.client.call(msg)
        return res

    def add_watcher(self, name, cmd, **kw):
        res = self.client.send_message('add', name=name, cmd=cmd)
        if res['status'] == 'ok':
            # now configuring the options
            options = {}
            options['numprocesses'] = int(kw.get('numprocesses', '5'))
            options['working_dir'] = kw.get('working_dir')
            options['shell'] = kw.get('shell', 'off') == 'on'
            res = self.client.send_message('set', name=name, options=options)
            self.update_watchers()  # will do better later
        return res
Exemple #47
0
class Client(object):

    def __init__(self, port=6000):
        self._client = CircusClient(endpoint='tcp://127.0.0.1:{}'.format(port))

    def startup(self):
        click.echo('startup')
        sp.call(['circusd', 'basic.ini', '--daemon'])

    def quit(self):
        self._client.call({
            'command': 'quit',
            'properties': {}
        })

    def stop(self):
        self._client.stop()

    def start_aiida_daemon(self, profile):
        if not get_daemon_name(profile) in self.list_watchers():
            # ~ command = {
                # ~ 'command': 'add',
                # ~ 'properties': {
                    # ~ 'name': WATCHER_NAME,
                    # ~ 'cmd': 'verdi devel run_daemon',
                    # ~ 'virtualenv': path.abspath(path.join(executable, '../../')),
                    # ~ 'copy_env': True,
                    # ~ 'pidfile': '{}/circus-aiida-{}'.format(path.dirname(path.abspath(__file__)), PROFILE_UUID),
                    # ~ 'autostart': True,
                    # ~ 'warmup_delay': 5
                # ~ }
            # ~ }
            click.echo('adding the watcher...')
            command = {
                'command': 'add',
                'properties': get_daemon_properties(profile)
            }
            click.echo(command)
            self._client.call(command)
            return self.start_watcher()
        elif not self.is_watcher_active(get_daemon_name(profile)):
            click.echo('starting the watcher...')
            return self.start_watcher(get_daemon_name(profile))
        return None

    def start_outstreamer(self, msg):
        if not streamer_name(msg) in self.list_watchers():
            streamer = get_streamer(msg)
            command = {
                'command': 'add',
                'properties': streamer,
            }
            self._client.call(command)
            return self.start_watcher(streamer_name(msg))
            self._client.call({
                'command': 'set',
                'properties': {
                    'name': streamer_name(msg),
                    'options': {'stdout_stream.filename': 'stream.log'}
                }
            })
        elif not self.is_watcher_active(streamer_name(msg)):
            return self.start_watcher(streamer_name(msg))

    def stop_aiida_daemon(self, profile):
        if get_daemon_name(profile) in self.list_watchers():
            return self._client.call({
                'command': 'stop',
                'properties': {
                    'name': get_daemon_name(profile)
                }
            })
        return None

    def start_watcher(self, name=None):
        response = self._client.call({
            'command': 'start',
            'properties': {
                'name': name
            }
        })

        return bool(response.get('status', None) == 'ok')

    def status(self, name=None):
        response = self._client.call({
            'command': 'status',
            'properties': {
                'name': name
            }
        })
        if response.get('status', None):
            return str(response['status'])

    def is_watcher_active(self, name):
        return bool(self.status(name) == 'active')

    def list_watchers(self):
        response = self._client.call({
            'command': 'list',
            'properties': {}
        })
        return [str(watcher) for watcher in response['watchers']] if response['status'] == u'ok' else []
Exemple #48
0
class LiveClient(object):
    def __init__(self, endpoint):
        self.endpoint = str(endpoint)
        self.client = CircusClient(endpoint=self.endpoint)
        self.connected = False
        self.watchers = []
        self.stats = defaultdict(list)
        self.refresher = Refresher(self)
        self.dstats = []

    def stop(self):
        self.client.stop()
        self.refresher.running = False
        self.refresher.join()

    def verify(self):
        self.watchers = []
        # trying to list the watchers
        msg = cmds['list'].make_message()
        try:
            res = self.client.call(msg)
            self.connected = True
            for watcher in res['watchers']:
                msg = cmds['options'].make_message(name=watcher)
                options = self.client.call(msg)
                self.watchers.append((watcher, options['options']))
            self.watchers.sort()
            if not self.refresher.running:
                self.refresher.start()
        except CallError:
            self.connected = False

    def killproc(self, name, pid):
        msg = cmds['signal'].make_message(name=name, process=int(pid),
                signum=9)
        res = self.client.call(msg)
        self.verify()  # will do better later
        return res['status'] == 'ok'

    def get_option(self, name, option):
        watchers = dict(self.watchers)
        return watchers[name][option]

    def get_global_options(self):
        msg = cmds['globaloptions'].make_message()
        options = self.client.call(msg)
        return options['options']

    def get_options(self, name):
        watchers = dict(self.watchers)
        return watchers[name].items()

    def incrproc(self, name):
        msg = cmds['incr'].make_message(name=name)
        res = self.client.call(msg)
        self.verify()  # will do better later
        return res['numprocesses']

    def decrproc(self, name):
        msg = cmds['decr'].make_message(name=name)
        res = self.client.call(msg)
        self.verify()  # will do better later
        return res['numprocesses']

    def get_stats(self, name, start=0, end=-1):
        return self.stats[name][start:end]

    def get_dstats(self, field, start=0, end=-1):
        stats = self.dstats[start:end]
        res = []
        for stat in stats:
            res.append(stat[field])
        return res

    def get_pids(self, name):
        msg = cmds['list'].make_message(name=name)
        res = self.client.call(msg)
        return res['processes']

    def get_series(self, name, pid, field, start=0, end=-1):
        stats = self.get_stats(name, start, end)
        res = []
        pid = str(pid)
        for stat in stats:
            if pid not in stat:
                continue
            res.append(stat[pid][field])
        return res

    def get_status(self, name):
        msg = cmds['status'].make_message(name=name)
        res = self.client.call(msg)
        return res['status']

    def switch_status(self, name):
        msg = cmds['status'].make_message(name=name)
        res = self.client.call(msg)
        status = res['status']
        if status == 'active':
            # stopping the watcher
            msg = cmds['stop'].make_message(name=name)
        else:
            msg = cmds['start'].make_message(name=name)
        res = self.client.call(msg)
        return res

    def add_watcher(self, name, cmd, **kw):
        msg = cmds['add'].make_message(name=name, cmd=cmd)
        res = self.client.call(msg)
        if res['status'] == 'ok':
            # now configuring the options
            options = {}
            options['numprocesses'] = int(kw.get('numprocesses', '5'))
            options['working_dir'] = kw.get('working_dir')
            options['shell'] = kw.get('shell', 'off') == 'on'
            msg = cmds['set'].make_message(name=name, options=options)
            res = self.client.call(msg)
            self.verify()  # will do better later
            return res['status'] == 'ok'
        else:
            return False
Exemple #49
0
class TestTrainer(TestCircus):

    def setUp(self):
        super(TestTrainer, self).setUp()
        dummy_process = 'circus.tests.test_arbiter.run_dummy'
        self.test_file = self._run_circus(dummy_process)
        self.cli = CircusClient()

    def tearDown(self):
        super(TestTrainer, self).tearDown()
        self.cli.stop()

    def test_numwatchers(self):
        msg = make_message("numwatchers")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_numprocesses(self):
        msg = make_message("numprocesses")
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("numprocesses"), 1)

    def test_processes(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1])

        msg2 = make_message("incr", name="test")
        self.cli.call(msg2)

        resp = self.cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1, 2])

    def test_watchers(self):
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test"])

    def _get_cmd(self):
        fd, testfile = mkstemp()
        os.close(fd)
        cmd = '%s generic.py %s %s' % (sys.executable,
                        'circus.tests.test_arbiter.run_dummy', testfile)

        return cmd

    def _get_cmd_args(self):
        cmd = sys.executable
        args = ['generic.py', 'circus.tests.test_arbiter.run_dummy1']
        return cmd, args

    def test_add_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher1(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(make_message("list"))
        self.assertEqual(resp.get('watchers'), ["test", "test1"])

    def test_add_watcher2(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 2)

    def test_add_watcher3(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        resp = self.cli.call(msg)
        self.assertTrue(resp.get('status'), 'error')

    def test_add_watcher4(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

    def test_add_watcher5(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher6(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args,
                start=True)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

    def test_add_watcher7(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args,
                start=True, options={"flapping_window": 100})
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")

        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get("status"), "active")

        resp = self.cli.call(make_message("options", name="test1"))
        options = resp.get('options', {})
        self.assertEqual(options.get("flapping_window"), 100)

    def test_rm_watcher(self):
        msg = make_message("add", name="test1", cmd=self._get_cmd())
        self.cli.call(msg)
        msg = make_message("rm", name="test1")
        self.cli.call(msg)
        resp = self.cli.call(make_message("numwatchers"))
        self.assertEqual(resp.get("numwatchers"), 1)

    def test_stop(self):
        resp = self.cli.call(make_message("quit"))
        self.assertEqual(resp.get("status"), "ok")
        self.assertRaises(CallError, self.cli.call, make_message("list"))

    def test_reload(self):
        resp = self.cli.call(make_message("reload"))
        self.assertEqual(resp.get("status"), "ok")

    def test_reload1(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('processes')

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        msg2 = make_message("list", name="test")
        resp = self.cli.call(msg2)
        processes2 = resp.get('processes')

        self.assertNotEqual(processes1, processes2)

    def test_reload2(self):
        msg1 = make_message("list", name="test")
        resp = self.cli.call(msg1)
        processes1 = resp.get('processes')
        self.assertEqual(processes1, [1])

        self.cli.call(make_message("reload"))
        time.sleep(0.5)

        make_message("list", name="test")
        resp = self.cli.call(msg1)

        processes2 = resp.get('processes')
        self.assertEqual(processes2, [2])

    def test_stop_watchers(self):
        resp = self.cli.call(make_message("stop"))
        self.assertEqual(resp.get("status"), "ok")

    def test_stop_watchers1(self):
        self.cli.call(make_message("stop"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get("status"), "stopped")

    def test_stop_watchers2(self):
        self.cli.call(make_message("stop", name="test"))
        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "stopped")

    def test_stop_watchers3(self):
        cmd, args = self._get_cmd_args()
        msg = make_message("add", name="test1", cmd=cmd, args=args)
        resp = self.cli.call(msg)
        self.assertEqual(resp.get("status"), "ok")
        resp = self.cli.call(make_message("start", name="test1"))
        self.assertEqual(resp.get("status"), "ok")

        self.cli.call(make_message("stop", name="test1"))
        resp = self.cli.call(make_message("status", name="test1"))
        self.assertEqual(resp.get('status'), "stopped")

        resp = self.cli.call(make_message("status", name="test"))
        self.assertEqual(resp.get('status'), "active")

    def test_plugins(self):
        # killing the setUp runner
        self._stop_runners()
        self.cli.stop()

        # setting up a circusd with a plugin
        dummy_process = 'circus.tests.test_arbiter.run_dummy'
        plugin = 'circus.tests.test_arbiter.Plugin'
        plugins = [{'use': plugin}]
        self._run_circus(dummy_process, plugins=plugins)

        # doing a few operations
        cli = CircusClient()
        msg1 = make_message("list", name="test")
        resp = cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1])
        msg2 = make_message("incr", name="test")
        cli.call(msg2)
        resp = cli.call(msg1)
        self.assertEqual(resp.get('processes'), [1, 2])

        # checking what the plugin did
        wanted = [('test', 'spawn'), ('test', 'start'), ('test', 'spawn')]
        self.assertEqual(Plugin.events, wanted)