def test_handler(self):
        if os.getenv('TRAVIS', False):
            return

        log = self._get_file()
        stream = {'stream': FileStream(log)}

        self._run_circus('circus.tests.test_stats_client.run_process',
                         stdout_stream=stream, stderr_stream=stream,
                         stats=True)
        time.sleep(.5)

        # checking that our system is live and running
        client = CircusClient()
        res = client.send_message('list')
        watchers = res['watchers']
        watchers.sort()
        self.assertEqual(['circusd-stats', 'test'], watchers)

        # making sure the stats process run
        res = client.send_message('status', name='test')
        self.assertEqual(res['status'], 'active')

        res = client.send_message('status', name='circusd-stats')
        self.assertEqual(res['status'], 'active')

        # playing around with the stats now: we should get some !
        from circus.stats.client import StatsClient
        client = StatsClient()
        next = client.iter_messages().next

        for i in range(10):
            watcher, pid, stat = next()
            self.assertTrue(watcher in ('test', 'circusd-stats', 'circus'),
                            watcher)
Exemple #2
0
def circus_status(endpoint=None, process=None):
    default = {
        'pid': 'unknown',
        'status': 'unknown',
        'uptime': 'unknown'
    }

    if endpoint and process:
        client = CircusClient(endpoint=endpoint, timeout=2)
        try:
            status = client.send_message('status')
            stats = client.send_message('stats')
            # Assuming here there's only a process
            pid = stats['infos'][process].keys()[0]
            try:
                uptime = int(stats['infos'][process][pid]['age'])
                default['uptime'] = humanize.naturaltime(datetime.datetime.now() - datetime.timedelta(seconds=uptime))
                default['pid'] = pid
            except:
                # circus running but process stopped
                pass
            default['status'] = status['statuses'][process].lower()

        except Exception as exc:
            if'TIMED OUT' in exc.message.upper():
                # circus stopped
                default['status'] = 'unknown'
    return default
Exemple #3
0
    def test_handler(self):
        log = self._get_file()
        stream = {'stream': FileStream(log)}

        self._run_circus('circus.tests.test_stats_client.run_process',
                         stdout_stream=stream,
                         stderr_stream=stream,
                         stats=True)
        time.sleep(.5)

        # checking that our system is live and running
        client = CircusClient()
        res = client.send_message('list')
        watchers = res['watchers']
        watchers.sort()
        self.assertEqual(['circusd-stats', 'test'], watchers)

        # making sure the stats process run
        res = client.send_message('status', name='test')
        self.assertEqual(res['status'], 'active')

        res = client.send_message('status', name='circusd-stats')
        self.assertEqual(res['status'], 'active')

        # playing around with the stats now: we should get some !
        from circus.stats.client import StatsClient
        client = StatsClient()
        next = client.iter_messages().next

        for i in range(10):
            watcher, pid, stat = next()
            self.assertTrue(watcher in ('test', 'circusd-stats', 'circus'),
                            watcher)
def _send_message(command, **properties):
    # check if circusct.endpoint is in minion config
    endpoint = __salt__['config.get']('circusctl.endpoint') or \
                DEFAULT_ENDPOINT_DEALER
    # sending keys with None values in the message to circus will result
    # an error. removing them from properties
    props = dict((k, v) for k, v in properties.iteritems() if v)
    client = CircusClient(endpoint=endpoint)
    return client.send_message(command, **props)
Exemple #5
0
    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)
    def _test_singleton(self):
        yield 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 #7
0
    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 #8
0
    def test_handler(self):
        if os.getenv('TRAVIS', False):
            return

        log = self._get_file()
        stream = {'stream': FileStream(log)}
        self._run_circus('circus.tests.test_stats_client.run_process',
                         stdout_stream=stream,
                         stderr_stream=stream,
                         stats=True)

        # waiting for data to appear in the file stream
        empty = True
        while empty:
            with open(log) as f:
                empty = f.read() == ''

            time.sleep(.1)

        # checking that our system is live and running
        client = CircusClient()
        res = client.send_message('list')
        watchers = res['watchers']
        watchers.sort()
        self.assertEqual(['circusd-stats', 'test'], watchers)

        # making sure the stats process run
        res = client.send_message('status', name='test')
        self.assertEqual(res['status'], 'active')

        res = client.send_message('status', name='circusd-stats')
        self.assertEqual(res['status'], 'active')

        # playing around with the stats now: we should get some !
        from circus.stats.client import StatsClient
        client = StatsClient()
        next = client.iter_messages().next

        for i in range(10):
            watcher, pid, stat = next()
            self.assertTrue(watcher in ('test', 'circusd-stats', 'circus'),
                            watcher)
    def test_handler(self):
        log = self._get_file()
        stream = {'stream': FileStream(log)}
        self._run_circus('circus.tests.test_stats_client.run_process',
                         stdout_stream=stream, stderr_stream=stream,
                         stats=True)

        # waiting for data to appear in the file stream
        empty = True
        while empty:
            with open(log) as f:
                empty = f.read() == ''

            time.sleep(.1)

        # checking that our system is live and running
        client = CircusClient()
        res = client.send_message('list')
        watchers = res['watchers']
        watchers.sort()
        self.assertEqual(['circusd-stats', 'test'], watchers)

        # making sure the stats process run
        res = client.send_message('status', name='test')
        self.assertEqual(res['status'], 'active')

        res = client.send_message('status', name='circusd-stats')
        self.assertEqual(res['status'], 'active')

        # playing around with the stats now: we should get some !
        from circus.stats.client import StatsClient
        client = StatsClient()
        next = client.iter_messages().next

        for i in range(10):
            watcher, pid, stat = next()
            self.assertTrue(watcher in ('test', 'circusd-stats', 'circus'),
                            watcher)
Exemple #10
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 #11
0
class StatsStreamer(object):
    def __init__(self,
                 endpoint,
                 pubsub_endoint,
                 stats_endpoint,
                 ssh_server,
                 delay=1.):
        self.topic = 'watcher.'
        self.delay = delay
        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.instance()  # events coming from circusd
        self.substream = zmqstream.ZMQStream(self.sub_socket, self.loop)
        self.substream.on_recv(self.handle_recv)
        self.client = CircusClient(context=self.ctx,
                                   endpoint=endpoint,
                                   ssh_server=ssh_server)
        self.cmds = get_commands()
        self._pids = defaultdict(list)
        self._callbacks = dict()
        self.publisher = StatsPublisher(stats_endpoint, self.ctx)
        self.running = False  # should the streamer be running?
        self.stopped = False  # did the collect started yet?
        self.circus_pids = {}
        self.sockets = []

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

    def get_sockets(self):
        return self.sockets

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

    def get_circus_pids(self):
        # getting the circusd, circusd-stats and circushttpd pids
        res = self.client.send_message('dstats')
        pids = {os.getpid(): 'circusd-stats', res['info']['pid']: 'circusd'}

        httpd_pids = self.client.send_message('list', name='circushttpd')

        if 'pids' in httpd_pids:
            httpd_pids = httpd_pids['pids']
            if len(httpd_pids) == 1:
                pids[httpd_pids[0]] = 'circushttpd'
        return pids

    def _add_callback(self, name, start=True, kind='watcher'):
        logger.debug('Callback added for %s' % name)

        if kind == 'watcher':
            klass = WatcherStatsCollector
        elif kind == 'socket':
            klass = SocketStatsCollector
        else:
            raise ValueError('Unknown callback kind %r' % kind)

        self._callbacks[name] = klass(self, name, self.delay, self.loop)
        if start:
            self._callbacks[name].start()

    def _init(self):
        self._pids.clear()

        # getting the initial list of watchers/pids
        res = self.client.send_message('list')

        for watcher in res['watchers']:
            if watcher in ('circusd', 'circushttpd', 'circusd-stats'):
                # this is dealt by the special 'circus' collector
                continue

            pids = self.client.send_message('list', name=watcher)['pids']
            for pid in pids:
                self.append_pid(watcher, pid)

        # getting the circus pids
        self.circus_pids = self.get_circus_pids()
        if 'circus' not in self._callbacks:
            self._add_callback('circus')
        else:
            self._callbacks['circus'].start()

        # getting the initial list of sockets
        res = self.client.send_message('listsockets')
        for sock in res['sockets']:
            fd = sock['fd']
            address = '%s:%s' % (sock['host'], sock['port'])
            # XXX type / family ?
            sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
            self.sockets.append((sock, address, fd))

        self._add_callback('sockets', kind='socket')

    def remove_pid(self, watcher, pid):
        if pid in self._pids[watcher]:
            logger.debug('Removing %d from %s' % (pid, watcher))
            self._pids[watcher].remove(pid)
            if len(self._pids[watcher]) == 0:
                logger.debug(
                    'Stopping the periodic callback for {0}'.format(watcher))
                self._callbacks[watcher].stop()

    def append_pid(self, watcher, pid):
        if watcher not in self._pids or len(self._pids[watcher]) == 0:
            logger.debug(
                'Starting the periodic callback for {0}'.format(watcher))
            if watcher not in self._callbacks:
                self._add_callback(watcher)
            else:
                self._callbacks[watcher].start()

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

    def start(self):
        self.running = True
        logger.info('Starting the stats streamer')
        self._init()
        logger.debug('Initial list is ' + str(self._pids))
        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.stop()

    def handle_recv(self, data):
        """called each time circusd sends an event"""
        # maintains a periodic callback to compute mem and cpu consumption for
        # each pid.
        logger.debug('Received an event from circusd: %s' % data)

        topic, msg = data
        try:
            __, watcher, action = topic.split('.')
            msg = json.loads(msg)
            if action == 'start' or (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':
                self.stop()
            else:
                logger.debug('Unknown action: %r' % action)
                logger.debug(msg)
        except Exception:
            logger.exception('Failed to handle %r' % msg)

    def stop(self):
        # stop all the periodic callbacks running
        for callback in self._callbacks.values():
            callback.stop()

        self.loop.stop()
        self.ctx.destroy(0)
        self.publisher.stop()
        self.stopped = True
        self.running = False
        logger.info('Stats streamer stopped')
Exemple #12
0
class StatsStreamer(object):
    def __init__(self, endpoint, pubsub_endoint, stats_endpoint, ssh_server,
                 delay=1., loop=None):
        self.topic = 'watcher.'
        self.delay = delay
        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 = loop or ioloop.IOLoop.instance()
        self.substream = zmqstream.ZMQStream(self.sub_socket, self.loop)
        self.substream.on_recv(self.handle_recv)
        self.client = CircusClient(context=self.ctx, endpoint=endpoint,
                                   ssh_server=ssh_server)
        self.cmds = get_commands()
        self._pids = defaultdict(list)
        self._callbacks = dict()
        self.publisher = StatsPublisher(stats_endpoint, self.ctx)
        self.running = False  # should the streamer be running?
        self.stopped = False  # did the collect started yet?
        self.circus_pids = {}
        self.sockets = []

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

    def get_sockets(self):
        return self.sockets

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

    def get_circus_pids(self):
        watchers = self.client.send_message('list').get('watchers', [])

        # getting the circusd, circusd-stats and circushttpd pids
        res = self.client.send_message('dstats')
        pids = {os.getpid(): 'circusd-stats'}

        if 'info' in res:
            pids[res['info']['pid']] = 'circusd'

        if 'circushttpd' in watchers:
            httpd_pids = self.client.send_message('list', name='circushttpd')

            if 'pids' in httpd_pids:
                httpd_pids = httpd_pids['pids']
                if len(httpd_pids) == 1:
                    pids[httpd_pids[0]] = 'circushttpd'

        return pids

    def _add_callback(self, name, start=True, kind='watcher'):
        logger.debug('Callback added for %s' % name)

        if kind == 'watcher':
            klass = WatcherStatsCollector
        elif kind == 'socket':
            klass = SocketStatsCollector
        else:
            raise ValueError('Unknown callback kind %r' % kind)

        self._callbacks[name] = klass(self, name, self.delay, self.loop)
        if start:
            self._callbacks[name].start()

    def _init(self):
        self._pids.clear()

        # getting the initial list of watchers/pids
        res = self.client.send_message('list')

        for watcher in res['watchers']:
            if watcher in ('circusd', 'circushttpd', 'circusd-stats'):
                # this is dealt by the special 'circus' collector
                continue

            pid_list = self.client.send_message('list', name=watcher)
            pids = pid_list.get('pids', [])
            for pid in pids:
                self._append_pid(watcher, pid)

        # getting the circus pids
        self.circus_pids = self.get_circus_pids()
        if 'circus' not in self._callbacks:
            self._add_callback('circus')
        else:
            self._callbacks['circus'].start()

        # getting the initial list of sockets
        res = self.client.send_message('listsockets')
        for sock in res.get('sockets', []):
            fd = sock['fd']
            address = '%s:%s' % (sock['host'], sock['port'])
            # XXX type / family ?
            sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
            self.sockets.append((sock, address, fd))

        self._add_callback('sockets', kind='socket')

    def stop_watcher(self, watcher):
        for pid in self._pids[watcher]:
            self.remove_pid(watcher, pid)

    def remove_pid(self, watcher, pid):
        if pid in self._pids[watcher]:
            logger.debug('Removing %d from %s' % (pid, watcher))
            self._pids[watcher].remove(pid)
            if len(self._pids[watcher]) == 0:
                logger.debug(
                    'Stopping the periodic callback for {0}' .format(watcher))
                self._callbacks[watcher].stop()

    def _append_pid(self, watcher, pid):
        if watcher not in self._pids or len(self._pids[watcher]) == 0:
            logger.debug(
                'Starting the periodic callback for {0}'.format(watcher))
            if watcher not in self._callbacks:
                self._add_callback(watcher)
            else:
                self._callbacks[watcher].start()

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

    def start(self):
        self.running = True
        logger.info('Starting the stats streamer')
        self._init()
        logger.debug('Initial list is ' + str(self._pids))
        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.stop()

    def handle_recv(self, data):
        """called each time circusd sends an event"""
        # maintains a periodic callback to compute mem and cpu consumption for
        # each pid.
        logger.debug('Received an event from circusd: %s' % data)
        topic, msg = data
        try:
            watcher = topic.split('.')[1:-1][0]
            action = topic.split('.')[-1]
            msg = json.loads(msg)

            if action in ('reap', 'kill'):
                # a process was reaped
                pid = msg['process_pid']
                self.remove_pid(watcher, pid)
            elif action == 'spawn':
                # a process was added
                pid = msg['process_pid']
                self._append_pid(watcher, pid)
            elif action == 'stop':
                # the whole watcher was stopped.
                self.stop_watcher(watcher)
            else:
                logger.debug('Unknown action: %r' % action)
                logger.debug(msg)
        except Exception:
            logger.exception('Failed to handle %r' % msg)

    def stop(self):
        # stop all the periodic callbacks running
        for callback in self._callbacks.values():
            callback.stop()

        self.loop.stop()
        self.ctx.destroy(0)
        self.publisher.stop()
        self.stopped = True
        self.running = False
        logger.info('Stats streamer stopped')
Exemple #13
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 #14
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 #15
0
class StatsStreamer(object):
    def __init__(self, endpoint, pubsub_endoint, stats_endpoint, delay=1.):
        self.topic = 'watcher.'
        self.delay = delay
        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()  # events coming from circusd
        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._pids = defaultdict(list)
        self._callbacks = dict()
        self.collector = StatsCollector()
        self.publisher = StatsPublisher(stats_endpoint, self.ctx)
        self.running = False  # should the streamer be running?
        self.stopped = False  # did the collect started yet?
        self.circus_pids = {}

    def publish_stats(self, watcher=None):
        """Get and publish the stats for the given watcher"""
        logger.debug('Publishing stats about {0}'.format(watcher))
        process_name = None
        for watcher, pid, stats in self.collector.collect_stats(
                watcher, self.get_pids(watcher)):
            if watcher == 'circus':
                if pid in self.circus_pids:
                    process_name = self.circus_pids[pid]

            self.publisher.publish(watcher, process_name, pid, stats)

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

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

    def get_circus_pids(self):
        # getting the circusd pid
        res = self.client.send_message('dstats')
        return {os.getpid(): 'circusd-stats',
                res['info']['pid']: 'circusd'}

    def _init(self):
        self.circus_pids = self.get_circus_pids()
        if 'circus' not in self._callbacks:
            self._callbacks['circus'] = ioloop.PeriodicCallback(
                    lambda: self.publish_stats("circus"),
                    self.delay * 1000, self.loop)
        self._callbacks['circus'].start()
        self._pids.clear()
        # getting the initial list of watchers/pids
        res = self.client.send_message('list')

        for watcher in res['watchers']:
            pids = self.client.send_message('list', name=watcher)['pids']
            for pid in pids:
                self.append_pid(watcher, pid)

    def remove_pid(self, watcher, pid):
        if pid in self._pids[watcher]:
            logger.debug('Removing %d from %s' % (pid, watcher))
            self._pids[watcher].remove(pid)
            if len(self._pids[watcher]) == 0:
                logger.debug('Stopping the periodic callback for {0}'\
                             .format(watcher))
                self._callbacks[watcher].stop()

    def append_pid(self, watcher, pid):
        if watcher not in self._pids or len(self._pids[watcher]) == 0:
            if watcher not in self._callbacks:
                self._callbacks[watcher] = ioloop.PeriodicCallback(
                        lambda: self.publish_stats(watcher),
                        self.delay * 1000, self.loop)
            logger.debug('Starting the periodic callback for {0}'\
                         .format(watcher))
            self._callbacks[watcher].start()

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

    def start(self):
        self.running = True
        logger.info('Starting the stats streamer')
        self._init()
        logger.debug('Initial list is ' + str(self._pids))
        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.stop()

    def handle_recv(self, data):
        """called each time circusd sends an event"""
        # maintains a periodic callback to compute mem and cpu consumption for
        # each pid.
        logger.debug('Received an event from circusd: %s' % data)

        topic, msg = data
        try:
            __, watcher, action = topic.split('.')
            msg = json.loads(msg)
            if action == 'start' or (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':
                self.stop()
            else:
                logger.debug('Unknown action: %r' % action)
                logger.debug(msg)
        except Exception:
            logger.exception('Failed to handle %r' % msg)

    def stop(self):
        # stop all the periodic callbacks running
        for callback in self._callbacks.values():
            callback.stop()

        self.loop.stop()
        self.ctx.destroy(0)
        self.publisher.stop()
        self.stopped = True
        self.running = False
        logger.info('Stats streamer stopped')
Exemple #16
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 #17
0
def circus_control(action, endpoint=None, process=None):
    if endpoint and process:
        client = CircusClient(endpoint=endpoint, timeout=2)
        client.send_message(action)
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