Beispiel #1
0
def zk_main_02():
    url = '127.0.0.1:2181'
    zk_test_node = '/zk_test_02'
    zkc = KazooClient(hosts=url, timeout=3)
    zkc.start()
    print('\npid=%d, zookeeper version: %s' %
          (os.getpid(), zkc.server_version()))

    try:
        # ephemeral=False: cannot create child for ephemeral node
        ret_path = zkc.create(path=zk_test_node,
                              value=b'zk_test_02_init',
                              ephemeral=False)
        print('\ncreate a zk test node:', ret_path)
        time.sleep(1)

        zk_watcher = zkWatcher(url, zk_test_node)
        p = multiprocessing.Process(target=zk_watcher.exec)
        p.start()
        time.sleep(1)

        zk_test_02(zkc, zk_test_node)

        if p is not None:
            p.join(timeout=8)
            if p.is_alive():
                print('pid=%d is pending, and kill!' % p.pid)
                p.kill()
    finally:
        if zkc.exists(zk_test_node, watch=None):
            zkc.delete(zk_test_node, recursive=True)
        # close zk session, and all ephemeral nodes will be removed
        zkc.stop()
Beispiel #2
0
def run(args, helpers):
    version = None
    if KazooClient is None:
        logging.warning(
            "Skipping zookeper discovery as Kazoo python library is absent")
    else:
        try:
            zk = KazooClient(hosts="%s:%d" % (args.ip, args.port),
                             read_only=True)
            zk.start()
            version = zk.server_version()
            logging.info("Detected Zookeeper version: %s" %
                         ('.'.join(str(i) for i in version)))
        except Exception:
            logging.exception(
                "Zookeeper might not be running a client listener on this port"
            )
    return (version)
Beispiel #3
0
    def exec(self):
        zkc = KazooClient(hosts=self._url, timeout=3)
        zkc.start()
        print('\npid=%d, zookeeper version: %s' %
              (os.getpid(), zkc.server_version()))

        try:
            self._list_ori = zkc.get_children(self._zk_node)

            print('\nattach data and child watch')
            # watch func trigger for each change
            DataWatch(client=zkc, path=self._zk_node, func=self._data_change)
            ChildrenWatch(client=zkc,
                          path=self._zk_node,
                          func=self._child_change)
            print('\nzk watch is running ...')
            time.sleep(6)
        finally:
            if zkc is not None:
                zkc.stop()
Beispiel #4
0
def run(zk_host):

    client = KazooClient(zk_host)
    client.start(timeout=15)

    zk_server_version = client.server_version()

    client.add_listener()
    print 'Server Version: {0}'.format(zk_server_version)

    queue = Queue()
    queue.enqueue('/')

    while queue.size() > 0:
        path = queue.dequeue()
        path_node = client.get(path)

        print '[{0}] {1}'.format(path_node[1].created, path)
        path_children = client.get_children(path)

        for child in path_children:
            queue.enqueue(path + child + '/')

    client.stop()
Beispiel #5
0
def zk_test_01(url, test_node):
    # if run in multi process, should init a new zk client.
    zkc = KazooClient(hosts=url, timeout=3)
    zkc.start()

    print('\npid=%d, zookeeper version: %s' %
          (os.getpid(), zkc.server_version()))
    try:
        stat = zkc.set(test_node, b'zk_test_01_new_1')
        print('\nzk test node updated, and stat version:', stat.version)
        time.sleep(2)

        stat = zkc.set(test_node, b'zk_test_01_new_2')
        print('\nzk test node updated, and stat version:', stat.version)
        time.sleep(1)

        data, stat = zkc.get(test_node, watch=None)
        print('\nzk node stat:')
        print('\tnode data="%s", length=%d' % (data, stat.dataLength))
        print('\tnode stat version:', stat.version)
        print()
    finally:
        if zkc is not None:
            zkc.stop()
Beispiel #6
0
class ZookeeperServiceRegistry(BaseServiceRegistry):
    def __init__(self, hosts=DEFAULT_HOSTS, chroot=DEFAULT_CHROOT):
        super(ZookeeperServiceRegistry, self).__init__()
        self.chroot = chroot
        self.client = KazooClient(
            hosts=hosts,
            handler=SequentialGeventHandler(),
        )
        self.client.add_listener(self.on_kazoo_state_change)
        self.start_count = 0

    @classmethod
    def from_config(cls, config, **kwargs):
        return cls(hosts=config.get('hosts', DEFAULT_HOSTS),
                   chroot=config.get('chroot', DEFAULT_CHROOT),
                   **kwargs)

    def on_start(self, timeout=10):
        self.start_count += 1
        if self.start_count > 1:
            return
        started = self.client.start_async()
        started.wait(timeout=timeout)
        if not self.client.connected:
            raise RuntimeError('could not connect to zookeeper')
        logger.debug('connected to zookeeper (version=%s)',
                     '.'.join(map(str, self.client.server_version())))

    def on_stop(self):
        self.start_count -= 1
        if self.start_count != 0:
            return
        self.client.stop()

    def on_kazoo_state_change(self, state):
        logger.info('kazoo connection state changed to %s', state)

    def on_service_type_watch(self, service, event):
        try:
            if event.type == EventType.CHILD:
                # FIXME: figure out proper retry strategy
                self.client.retry(self.lookup, service.container, service)
        except Exception:
            logger.exception('error in service type watcher')

    def on_service_watch(self, service, event):
        try:
            prefix, service_type, identity = event.path.rsplit('/', 2)
            if event.type == EventType.DELETED:
                service.remove(identity)
        except Exception:
            logger.exception('error in service watcher')

    def _get_service_znode(self, service, service_type, identity):
        path = self._get_zk_path(service_type, identity)
        result = self.client.get_async(path,
                                       watch=functools.partial(
                                           self.on_service_watch, service))
        value, znode = result.get()
        items = six.iteritems(json.loads(value.decode('utf-8')))
        return {str(k): str(v) for k, v in items}

    def discover(self, container):
        result = self.client.get_children_async(path='%s/services' %
                                                self.chroot, )
        return list(result.get())

    def lookup(self, container, service, watch=True, timeout=1):
        def child_watch(event):
            print(event)

        service_type = service.service_type
        result = self.client.get_children_async(
            path='%s/services/%s' % (self.chroot, service_type),
            watch=functools.partial(self.on_service_type_watch, service),
        )
        try:
            names = result.get(timeout=timeout)
        except NoNodeError:
            raise LookupFailure(None,
                                "failed to resolve %s" % service.service_type)
        logger.info("lookup %s %r", service_type, names)
        identities = set(service.identities())
        for name in names:
            kwargs = self._get_service_znode(service, service_type, name)
            identity = kwargs.pop('identity')
            service.update(identity, **kwargs)
            try:
                identities.remove(identity)
            except KeyError:
                pass
        for identity in identities:
            service.remove(identity)
        return service

    def _get_zk_path(self, service_type, identity):
        return '%s/services/%s/%s' % (self.chroot, service_type, identity)

    def register(self, container, service_type, timeout=1):
        path = self._get_zk_path(service_type, container.identity)
        value = json.dumps({
            'endpoint': container.endpoint,
            'identity': container.identity,
            'log_endpoint': container.log_endpoint,
        })
        result = self.client.create_async(path,
                                          value.encode('utf-8'),
                                          ephemeral=True,
                                          makepath=True)
        # FIXME: result.set_exception(RegistrationFailure())
        result.get(timeout=timeout)

    def unregister(self, container, service_type, timeout=1):
        path = self._get_zk_path(service_type, container.identity)
        result = self.client.delete_async(path)
        result.set_exception(RegistrationFailure())
        result.get(timeout=timeout)
Beispiel #7
0
class ZookeeperWatcher(object):
    zoo_client = None  # The KazooClient to manage the config
    point_path = None  # Zookeeper path to pointed to file
    pointed_at_expired = None  # is True when the assignment has been set to
                               # None but we cannot remove the config listener
    valid_handler = None  # the function to call when the validity changes
    config_handler = None  # the function to call when the config changes
    error_handler = None  # the function to call when an error occurs in reading
    valid_file = False  # the current state of the ConfigWatcher with ZK
    do_not_restart = False  # used when closing via ^C
    old_data = ''  # The current file contents, to see if a change occurred
    old_pointed = ''  # the current pointed path, to see if change occurred

    INVALID_PATH = "Invalid pointer path"
    INVALID_GET = "Invalid get on file path"
    BAD_CONNECTION = "Connection interrupted with Zookeeper, re-establishing"

    def __init__(self, hosts, filepath, valid_handler=None,
                 config_handler=None, error_handler=None, pointer=False,
                 ensure=False, valid_init=True):
        '''
        Zookeeper file watcher, used to tell a program their zookeeper file has
        changed. Can be used to watch a single file, or both a file and path of
        its contents. Manages all connections, drops, reconnections for you.

        @param hosts: The zookeeper hosts to use
        @param filepath: The full path to the file to watch
        @param valid_handler: The method to call for a 'is valid' state change
        @param config_handler: The method to call when a content change occurs
        @param error_handler: The method to call when an error occurs
        @param pointer: Set to true if the file contents are actually a path to
                        another zookeeper file, where the real config resides
        @param ensure: Set to true for the ZooWatcher to create the watched file
        @param valid_init: Ensure the client can connect to Zookeeper first try

        Ex 1. /stuff/A: "stuff I care about"
        Ex 2. /stuff/A: "/other/stuff", /other/stuff: "contents I care about"
            - in Ex 2 you care about /other/stuff contents
              but are only aware of your assignment /stuff/A

        You can use this class as any combination of event driven or polling.
        Polling:
            In the main loop of your program, check if is_valid() is
            True, otherwise clear your contents as there is some ZK error.
        Event:
            You will be notified via the various handlers when content changes.
        '''
        self.hosts = hosts
        self.my_file = filepath
        self.pointer = pointer
        self.ensure = ensure
        self.valid_handler = valid_handler
        self.config_handler = config_handler
        self.error_handler = error_handler

        if valid_init:
            # this will throw an exception if it can't start right away
            self.zoo_client = KazooClient(hosts=self.hosts)
            self.zoo_client.start()

        self.threaded_start(no_init=True)

    def threaded_start(self, no_init=False):
        '''
        Spawns a worker thread to set up the zookeeper connection
        '''
        thread = Thread(target=self.init_connections, kwargs={
                        'no_init': no_init})
        thread.setDaemon(True)
        thread.start()
        thread.join()

    def init_connections(self, no_init=False):
        '''
        Sets up the initial Kazoo Client and watches
        '''
        success = False
        self.set_valid(False)

        if not no_init:
            if self.zoo_client:
                self.zoo_client.remove_listener(self.state_listener)
                self.old_data = ''
                self.old_pointed = ''

            while not success:
                try:
                    if self.zoo_client is None:
                        self.zoo_client = KazooClient(hosts=self.hosts)
                        self.zoo_client.start()
                    else:
                        # self.zoo_client.stop()
                        self.zoo_client._connection.connection_stopped.set()
                        self.zoo_client.close()
                        self.zoo_client = KazooClient(hosts=self.hosts)
                        self.zoo_client.start()
                except Exception as e:
                    log.error("ZKWatcher Exception: " + e.message)
                    sleep(1)
                    continue

                self.setup()
                success = self.update_file(self.my_file)
                sleep(5)
        else:
            self.setup()
            self.update_file(self.my_file)

    def setup(self):
        '''
        Ensures the path to the watched file exists and we have a state
        listener
        '''
        self.zoo_client.add_listener(self.state_listener)

        if self.ensure:
            self.zoo_client.ensure_path(self.my_file)

    def state_listener(self, state):
        '''
        Restarts the session if we get anything besides CONNECTED
        '''
        if state == KazooState.SUSPENDED:
            self.set_valid(False)
            self.call_error(self.BAD_CONNECTION)
        elif state == KazooState.LOST and not self.do_not_restart:
            self.threaded_start()
        elif state == KazooState.CONNECTED:
            # This is going to throw a SUSPENDED kazoo error
            # which will cause the sessions to be wiped and re established.
            # Used b/c of massive connection pool issues
            self.zoo_client.stop()

    def is_valid(self):
        '''
        @return: True if the currently watch file is valid
        '''
        return self.valid_file

    def ping(self):
        '''
        Simple command to test if the zookeeper session is able to connect
        at this very moment
        '''
        try:
            # dummy ping to ensure we are still connected
            self.zoo_client.server_version()
            return True
        except KazooException:
            return False

    def close(self, kill_restart=True):
        '''
        Use when you would like to close everything down
        @param kill_restart= Prevent kazoo restarting from occurring
        '''
        self.do_not_restart = kill_restart
        self.zoo_client.stop()
        self.zoo_client.close()

    def get_file_contents(self, pointer=False):
        '''
        Gets any file contents you care about. Defaults to the main file
        @param pointer: The the contents of the file pointer, not the pointed
        at file
        @return: A string of the contents
        '''
        if self.pointer:
            if pointer:
                return self.old_pointed
            else:
                return self.old_data
        else:
            return self.old_data

    def watch_file(self, event):
        '''
        Fired when changes made to the file
        '''
        if not self.update_file(self.my_file):
            self.threaded_start()

    def update_file(self, path):
        '''
        Updates the file watcher and calls the appropriate method for results
        @return: False if we need to keep trying the connection
        '''
        try:
            # grab the file
            result, stat = self.zoo_client.get(path, watch=self.watch_file)
        except ZookeeperError:
            self.set_valid(False)
            self.call_error(self.INVALID_GET)
            return False

        if self.pointer:
            if result is not None and len(result) > 0:
                self.pointed_at_expired = False
                # file is a pointer, go update and watch other file
                self.point_path = result
                if self.compare_pointer(result):
                    self.update_pointed()
            else:
                self.pointed_at_expired = True
                self.old_pointed = ''
                self.old_data = ''
                self.set_valid(False)
                self.call_error(self.INVALID_PATH)
        else:
            # file is not a pointer, return contents
            if self.compare_data(result):
                self.call_config(result)
            self.set_valid(True)

        return True

    def watch_pointed(self, event):
        '''
        Fired when changes made to pointed file
        '''
        self.update_pointed()

    def update_pointed(self):
        '''
        Grabs the latest file contents based on the pointer uri
        '''
        # only grab file if our pointer is still good (not None)
        if not self.pointed_at_expired:
            try:
                conf_string, stat2 = self.zoo_client.get(self.point_path,
                                                    watch=self.watch_pointed)
            except ZookeeperError:
                self.old_data = ''
                self.set_valid(False)
                self.pointed_at_expired = True
                self.call_error(self.INVALID_PATH)
                return

            if self.compare_data(conf_string):
                self.call_config(conf_string)
            self.set_valid(True)

    def set_valid(self, boolean):
        '''
        Sets the state and calls the change if needed
        @param bool: The state (true or false)
        '''
        old_state = self.is_valid()
        self.valid_file = boolean

        if old_state != self.valid_file:
            self.call_valid(self.valid_file)

    def call_valid(self, state):
        '''
        Calls the valid change function passed in
        @param valid_state: The new config
        '''
        if self.valid_handler is not None:
            self.valid_handler(self.is_valid())

    def call_config(self, new_config):
        '''
        Calls the config function passed in
        @param new_config: The new config
        '''
        if self.config_handler is not None:
            self.config_handler(new_config)

    def call_error(self, message):
        '''
        Calls the error function passed in
        @param message: The message to throw
        '''
        if self.error_handler is not None:
            self.error_handler(message)

    def compare_data(self, data):
        '''
        Compares the string data
        @return: True if the data is different
        '''
        if self.old_data != data:
            self.old_data = data
            return True
        return False

    def compare_pointer(self, data):
        '''
        Compares the string data
        @return: True if the data is different
        '''
        if self.old_pointed != data:
            self.old_pointed = data
            return True
        return False
class ZookeeperWatcher(object):
    zoo_client = None  # The KazooClient to manage the config
    point_path = None  # Zookeeper path to pointed to file
    pointed_at_expired = None  # is True when the assignment has been set to
    # None but we cannot remove the config listener
    valid_handler = None  # the function to call when the validity changes
    config_handler = None  # the function to call when the config changes
    error_handler = None  # the function to call when an error occurs in reading
    valid_file = False  # the current state of the ConfigWatcher with ZK
    do_not_restart = False  # used when closing via ^C
    old_data = ''  # The current file contents, to see if a change occurred
    old_pointed = ''  # the current pointed path, to see if change occurred

    INVALID_PATH = "Invalid pointer path"
    INVALID_GET = "Invalid get on file path"
    BAD_CONNECTION = "Connection interrupted with Zookeeper, re-establishing"

    def __init__(self,
                 hosts,
                 filepath,
                 valid_handler=None,
                 config_handler=None,
                 error_handler=None,
                 pointer=False,
                 ensure=False,
                 valid_init=True):
        '''
        Zookeeper file watcher, used to tell a program their zookeeper file has
        changed. Can be used to watch a single file, or both a file and path of
        its contents. Manages all connections, drops, reconnections for you.

        @param hosts: The zookeeper hosts to use
        @param filepath: The full path to the file to watch
        @param valid_handler: The method to call for a 'is valid' state change
        @param config_handler: The method to call when a content change occurs
        @param error_handler: The method to call when an error occurs
        @param pointer: Set to true if the file contents are actually a path to
                        another zookeeper file, where the real config resides
        @param ensure: Set to true for the ZooWatcher to create the watched file
        @param valid_init: Ensure the client can connect to Zookeeper first try

        Ex 1. /stuff/A: "stuff I care about"
        Ex 2. /stuff/A: "/other/stuff", /other/stuff: "contents I care about"
            - in Ex 2 you care about /other/stuff contents
              but are only aware of your assignment /stuff/A

        You can use this class as any combination of event driven or polling.
        Polling:
            In the main loop of your program, check if is_valid() is
            True, otherwise clear your contents as there is some ZK error.
        Event:
            You will be notified via the various handlers when content changes.
        '''
        self.hosts = hosts
        self.my_file = filepath
        self.pointer = pointer
        self.ensure = ensure
        self.valid_handler = valid_handler
        self.config_handler = config_handler
        self.error_handler = error_handler

        if valid_init:
            # this will throw an exception if it can't start right away
            self.zoo_client = KazooClient(hosts=self.hosts)
            self.zoo_client.start()

        self.threaded_start(no_init=True)

    def threaded_start(self, no_init=False):
        '''
        Spawns a worker thread to set up the zookeeper connection
        '''
        thread = Thread(target=self.init_connections,
                        kwargs={'no_init': no_init})
        thread.setDaemon(True)
        thread.start()
        thread.join()

    def init_connections(self, no_init=False):
        '''
        Sets up the initial Kazoo Client and watches
        '''
        success = False
        self.set_valid(False)

        if not no_init:
            if self.zoo_client:
                self.zoo_client.remove_listener(self.state_listener)
                self.old_data = ''
                self.old_pointed = ''

            while not success:
                try:
                    if self.zoo_client is None:
                        self.zoo_client = KazooClient(hosts=self.hosts)
                        self.zoo_client.start()
                    else:
                        # self.zoo_client.stop()
                        self.zoo_client._connection.connection_stopped.set()
                        self.zoo_client.close()
                        self.zoo_client = KazooClient(hosts=self.hosts)
                        self.zoo_client.start()
                except Exception as e:
                    log.error("ZKWatcher Exception: " + e.message)
                    sleep(1)
                    continue

                self.setup()
                success = self.update_file(self.my_file)
                sleep(5)
        else:
            self.setup()
            self.update_file(self.my_file)

    def setup(self):
        '''
        Ensures the path to the watched file exists and we have a state
        listener
        '''
        self.zoo_client.add_listener(self.state_listener)

        if self.ensure:
            self.zoo_client.ensure_path(self.my_file)

    def state_listener(self, state):
        '''
        Restarts the session if we get anything besides CONNECTED
        '''
        if state == KazooState.SUSPENDED:
            self.set_valid(False)
            self.call_error(self.BAD_CONNECTION)
        elif state == KazooState.LOST and not self.do_not_restart:
            self.threaded_start()
        elif state == KazooState.CONNECTED:
            # This is going to throw a SUSPENDED kazoo error
            # which will cause the sessions to be wiped and re established.
            # Used b/c of massive connection pool issues
            self.zoo_client.stop()

    def is_valid(self):
        '''
        @return: True if the currently watch file is valid
        '''
        return self.valid_file

    def ping(self):
        '''
        Simple command to test if the zookeeper session is able to connect
        at this very moment
        '''
        try:
            # dummy ping to ensure we are still connected
            self.zoo_client.server_version()
            return True
        except KazooException:
            return False

    def close(self, kill_restart=True):
        '''
        Use when you would like to close everything down
        @param kill_restart= Prevent kazoo restarting from occurring
        '''
        self.do_not_restart = kill_restart
        self.zoo_client.stop()
        self.zoo_client.close()

    def get_file_contents(self, pointer=False):
        '''
        Gets any file contents you care about. Defaults to the main file
        @param pointer: The the contents of the file pointer, not the pointed
        at file
        @return: A string of the contents
        '''
        if self.pointer:
            if pointer:
                return self.old_pointed
            else:
                return self.old_data
        else:
            return self.old_data

    def watch_file(self, event):
        '''
        Fired when changes made to the file
        '''
        if not self.update_file(self.my_file):
            self.threaded_start()

    def update_file(self, path):
        '''
        Updates the file watcher and calls the appropriate method for results
        @return: False if we need to keep trying the connection
        '''
        try:
            # grab the file
            result, stat = self.zoo_client.get(path, watch=self.watch_file)
        except ZookeeperError:
            self.set_valid(False)
            self.call_error(self.INVALID_GET)
            return False

        if self.pointer:
            if result is not None and len(result) > 0:
                self.pointed_at_expired = False
                # file is a pointer, go update and watch other file
                self.point_path = result
                if self.compare_pointer(result):
                    self.update_pointed()
            else:
                self.pointed_at_expired = True
                self.old_pointed = ''
                self.old_data = ''
                self.set_valid(False)
                self.call_error(self.INVALID_PATH)
        else:
            # file is not a pointer, return contents
            if self.compare_data(result):
                self.call_config(result)
            self.set_valid(True)

        return True

    def watch_pointed(self, event):
        '''
        Fired when changes made to pointed file
        '''
        self.update_pointed()

    def update_pointed(self):
        '''
        Grabs the latest file contents based on the pointer uri
        '''
        # only grab file if our pointer is still good (not None)
        if not self.pointed_at_expired:
            try:
                conf_string, stat2 = self.zoo_client.get(
                    self.point_path, watch=self.watch_pointed)
            except ZookeeperError:
                self.old_data = ''
                self.set_valid(False)
                self.pointed_at_expired = True
                self.call_error(self.INVALID_PATH)
                return

            if self.compare_data(conf_string):
                self.call_config(conf_string)
            self.set_valid(True)

    def set_valid(self, boolean):
        '''
        Sets the state and calls the change if needed
        @param bool: The state (true or false)
        '''
        old_state = self.is_valid()
        self.valid_file = boolean

        if old_state != self.valid_file:
            self.call_valid(self.valid_file)

    def call_valid(self, state):
        '''
        Calls the valid change function passed in
        @param valid_state: The new config
        '''
        if self.valid_handler is not None:
            self.valid_handler(self.is_valid())

    def call_config(self, new_config):
        '''
        Calls the config function passed in
        @param new_config: The new config
        '''
        if self.config_handler is not None:
            self.config_handler(new_config)

    def call_error(self, message):
        '''
        Calls the error function passed in
        @param message: The message to throw
        '''
        if self.error_handler is not None:
            self.error_handler(message)

    def compare_data(self, data):
        '''
        Compares the string data
        @return: True if the data is different
        '''
        if self.old_data != data:
            self.old_data = data
            return True
        return False

    def compare_pointer(self, data):
        '''
        Compares the string data
        @return: True if the data is different
        '''
        if self.old_pointed != data:
            self.old_pointed = data
            return True
        return False
Beispiel #9
0
#!/bin/env python
# -*- coding: UTF-8 -*-

from kazoo.client import KazooClient
from kazoo.exceptions import *
import traceback
zk = KazooClient(hosts='127.0.0.1:2181')
zk.start()
# children = zk.get_children('/')
print "zk version:" + (".".join(str(x) for x in zk.server_version()))
print "client id :" + str(zk.client_id[0])
servicePath = "/{root}/{service}/provider".format(root="zkpyro", service="serviceName01")
nodeId = zk.client_id[0]
nodePath = "{servicePath}/{node}".format(servicePath=servicePath, node=nodeId)
print "servicePath:" + servicePath
try:
    zk.create(nodePath, ephemeral=True, makepath=True)
    zk.set(nodePath, "pyro.url")
    print "Znode value:" + zk.get(nodePath)[0]
except NodeExistsError:
    traceback.print_stack()
zk.stop()
Beispiel #10
0
class ZookeeperServiceRegistry(BaseServiceRegistry):
    def __init__(self, hosts=DEFAULT_HOSTS, chroot=DEFAULT_CHROOT):
        super(ZookeeperServiceRegistry, self).__init__()
        self.chroot = chroot
        self.client = KazooClient(
            hosts=hosts,
            handler=SequentialGeventHandler(),
        )
        self.client.add_listener(self.on_kazoo_state_change)
        self.start_count = 0

    @classmethod
    def from_config(cls, config, **kwargs):
        return cls(
            hosts=config.get('hosts', DEFAULT_HOSTS),
            chroot=config.get('chroot', DEFAULT_CHROOT),
            **kwargs
        )

    def on_start(self, timeout=10):
        self.start_count += 1
        if self.start_count > 1:
            return
        started = self.client.start_async()
        started.wait(timeout=timeout)
        if not self.client.connected:
            raise RuntimeError('could not connect to zookeeper')
        logger.debug('connected to zookeeper (version=%s)', '.'.join(map(str, self.client.server_version())))

    def on_stop(self):
        self.start_count -= 1
        if self.start_count != 0:
            return
        self.client.stop()

    def on_kazoo_state_change(self, state):
        logger.info('kazoo connection state changed to %s', state)

    def on_service_type_watch(self, service, event):
        try:
            if event.type == EventType.CHILD:
                # FIXME: figure out proper retry strategy
                self.client.retry(self.lookup, service.container, service)
        except Exception:
            logger.exception('error in service type watcher')

    def on_service_watch(self, service, event):
        try:
            prefix, service_type, identity = event.path.rsplit('/', 2)
            if event.type == EventType.DELETED:
                service.remove(identity)
        except Exception:
            logger.exception('error in service watcher')

    def _get_service_znode(self, service, service_type, identity):
        path = self._get_zk_path(service_type, identity)
        result = self.client.get_async(
            path, watch=functools.partial(self.on_service_watch, service))
        value, znode = result.get()
        items = six.iteritems(json.loads(value.decode('utf-8')))
        return {str(k): str(v) for k, v in items}

    def discover(self, container):
        result = self.client.get_children_async(
            path='%s/services' % self.chroot,
        )
        return list(result.get())

    def lookup(self, container, service, watch=True, timeout=1):
        def child_watch(event):
            print(event)
        service_type = service.service_type
        result = self.client.get_children_async(
            path='%s/services/%s' % (self.chroot, service_type),
            watch=functools.partial(self.on_service_type_watch, service),
        )
        try:
            names = result.get(timeout=timeout)
        except NoNodeError:
            raise LookupFailure(None, "failed to resolve %s" % service.service_type)
        logger.info("lookup %s %r", service_type, names)
        identities = set(service.identities())
        for name in names:
            kwargs = self._get_service_znode(service, service_type, name)
            identity = kwargs.pop('identity')
            service.update(identity, **kwargs)
            try:
                identities.remove(identity)
            except KeyError:
                pass
        for identity in identities:
            service.remove(identity)
        return service

    def _get_zk_path(self, service_type, identity):
        return '%s/services/%s/%s' % (self.chroot, service_type, identity)

    def register(self, container, service_type, timeout=1):
        path = self._get_zk_path(service_type, container.identity)
        value = json.dumps({
            'endpoint': container.endpoint,
            'identity': container.identity,
            'log_endpoint': container.log_endpoint,
        })
        result = self.client.create_async(
            path,
            value.encode('utf-8'),
            ephemeral=True, makepath=True)
        # FIXME: result.set_exception(RegistrationFailure())
        result.get(timeout=timeout)

    def unregister(self, container, service_type, timeout=1):
        path = self._get_zk_path(service_type, container.identity)
        result = self.client.delete_async(path)
        result.set_exception(RegistrationFailure())
        result.get(timeout=timeout)
Beispiel #11
0
def watch(zookeepers, node, leader=False):
    """
    Watch a particular zookeeper node for changes.
    """

    zk_hosts = parse_zk_hosts(zookeepers, leader=leader)[0]

    def my_listener(state):
        if state == KazooState.LOST:
            # Register somewhere that the session was lost
            print(style_text('Connection Lost', ERROR_STYLE, pad=2))
        elif state == KazooState.SUSPENDED:
            # Handle being disconnected from Zookeeper
            print(style_text('Connection Suspended', ERROR_STYLE, pad=2))
        else:
            # Handle being connected/reconnected to Zookeeper
            # what are we supposed to do here?
            print(style_text('Connected/Reconnected', INFO_STYLE, pad=2))

    zk = KazooClient(hosts=zk_hosts, read_only=True)
    try:
        zk.start()
    except KazooTimeoutError as e:
        print('ZK Timeout host: [%s], %s' % (host, e))

    zk_ver = '.'.join(map(str, zk.server_version()))
    zk_host = zk.hosts[zk.last_zxid]
    zk_host = ':'.join(map(str, zk_host))

    zk.add_listener(my_listener)

    # check if the node exists ...
    if not zk.exists(node):
        node_str = style_text(node, BLUE_STYLE, restore=ERROR_STYLE)
        zk_str = style_text(zk_host, BLUE_STYLE, restore=ERROR_STYLE)
        print('')
        print(
            style_text('No node [%s] on %s' % (node_str, zk_str),
                       ERROR_STYLE,
                       pad=2))
        return

    print(style_header('Watching [%s] on %s v%s' % (node, zk_host, zk_ver)))

    # put a watch on my znode
    children = zk.get_children(node)

    # If there are children, watch them.
    if children or node.endswith('/'):

        @zk.ChildrenWatch(node)
        def watch_children(children):
            global WATCH_COUNTER
            WATCH_COUNTER += 1

            if WATCH_COUNTER <= 1:
                child_watch_str = 'Child Nodes:'
            else:
                child_watch_str = 'Node Watch Event: '

            children.sort()
            print('')
            print(style_text(child_watch_str, TITLE_STYLE))
            for ch in children:
                print(style_text(ch, INFO_STYLE, lpad=2))
            print('')

    else:
        # otherwise watch the node itself.
        @zk.DataWatch(node)
        def watch_data(data, stat, event):
            global WATCH_COUNTER
            WATCH_COUNTER += 1

            data = data.decode('utf-8')

            if WATCH_COUNTER <= 1:
                data_watch_str = 'Content: (%s)'
            else:
                data_watch_str = 'Data Watch Event: (v%s)'

            print('')
            print(style_text(data_watch_str % stat.version, TITLE_STYLE))
            print(style_multiline(data, INFO_STYLE, lpad=2))
            print('')

    CHAR_WIDTH = 60
    counter = 0
    while True:
        # draw a .... animation while we wait, so the user knows its working.
        counter += 1
        if not counter % CHAR_WIDTH:
            print('\r', ' ' * CHAR_WIDTH, '\r', end='')

        print(style_text('.', INFO_STYLE), end='')
        time.sleep(0.05)

    zk.stop()
class USSMetadataManager(object):
    """Interfaces with the locking system to get, put, and delete USS metadata.

  Metadata gets/stores/deletes the USS information for a partiular grid,
  including current version number, a list of USSs with active operations,
  and the endpoints to get that information. Locking is assured through a
  snapshot token received when getting, and used when putting.
  """
    def __init__(self, connectionstring=DEFAULT_CONNECTION, testgroupid=None):
        """Initializes the class.

    Args:
      connectionstring:
        Zookeeper connection string - server:port,server:port,...
      testgroupid:
        ID to use if in test mode, none for normal mode
    """
        if testgroupid:
            self.set_testmode(testgroupid)
        if not connectionstring:
            connectionstring = DEFAULT_CONNECTION
        log.debug(
            'Creating metadata manager object and connecting to zookeeper...')
        try:
            if set(BAD_CHARACTER_CHECK) & set(connectionstring):
                raise ValueError
            self.zk = KazooClient(hosts=connectionstring,
                                  timeout=CONNECTION_TIMEOUT)
            self.zk.add_listener(self.zookeeper_connection_listener)
            self.zk.start()
            if testgroupid:
                self.delete_testdata(testgroupid)
        except KazooTimeoutError:
            log.error(
                'Unable to connect to zookeeper using %s connection string...',
                connectionstring)
            raise
        except ValueError:
            log.error('Connection string %s seems invalid...',
                      connectionstring)
            raise

    def __del__(self):
        log.debug(
            'Destroying metadata manager object and disconnecting from zk...')
        self.zk.stop()

    def get_state(self):
        return self.zk.state

    def get_version(self):
        try:
            return True, self.zk.server_version()
        except KazooException as e:
            msg = str(e)
            return False, type(e).__name__ + (' ' + msg if msg else '')

    def set_verbose(self):
        log.setLevel(logging.DEBUG)

    def set_testmode(self, testgroupid='UNDEFINED_TESTER'):
        """Sets the mode to testing with the specific test ID, cannot be undone.

    Args:
      testgroupid: ID to use if in test mode, none for normal mode
    """
        global GRID_PATH
        global CONNECTION_TIMEOUT
        # Adjust parameters specifically for the test
        GRID_PATH = TEST_BASE_PREFIX + testgroupid + USS_BASE_PREFIX
        log.debug('Setting test path to %s...', GRID_PATH)
        CONNECTION_TIMEOUT = 1.0

    def zookeeper_connection_listener(self, state):
        if state == KazooState.LOST:
            # Register somewhere that the session was lost
            log.error('Lost connection with the zookeeper servers...')
        elif state == KazooState.SUSPENDED:
            # Handle being disconnected from Zookeeper
            log.error('Suspended connection with the zookeeper servers...')
        elif state == KazooState.CONNECTED:
            # Handle being connected/reconnected to Zookeeper
            log.info('Connection restored with the zookeeper servers...')

    def delete_testdata(self, testgroupid=None):
        """Removes the test data from the servers.

    Be careful when using this in parallel as it removes everything under
    the testgroupid, or everything if no tetgroupid is provided.

    Args:
      testgroupid: ID to use if in test mode, none will remove all test data
    """
        if testgroupid:
            path = TEST_BASE_PREFIX + testgroupid
        else:
            path = TEST_BASE_PREFIX
        self.zk.delete(path, recursive=True)

    def get(self, z, x, y):
        """Gets the metadata and snapshot token for a GridCell.

    Reads data from zookeeper, including a snapshot token. The
    snapshot token is used as a reference when writing to ensure
    the data has not been updated between read and write.

    Args:
      z: zoom level in slippy tile format
      x: x tile number in slippy tile format
      y: y tile number in slippy tile format
    Returns:
      JSend formatted response (https://labs.omniti.com/labs/jsend)
    """
        # TODO(hikevin): Change to use our own error codes and let the server
        #                   convert them to http error codes. For now, this is
        #                   at least in a standard JSend format.
        status = 500
        if slippy_util.validate_slippy(z, x, y):
            (content, metadata) = self._get_raw(z, x, y)
            if metadata:
                try:
                    m = uss_metadata.USSMetadata(content)
                    status = 200
                    result = {
                        'status': 'success',
                        'sync_token': metadata.last_modified_transaction_id,
                        'data': m.to_json()
                    }
                except ValueError:
                    status = 424
            else:
                status = 404
        else:
            status = 400
        if status != 200:
            result = self._format_status_code_to_jsend(status)
        return result

    def set(self, z, x, y, sync_token, uss_id, ws_scope, operation_format,
            operation_ws, earliest_operation, latest_operation):
        """Sets the metadata for a GridCell.

    Writes data, using the snapshot token for confirming data
    has not been updated since it was last read.

    Args:
      z: zoom level in slippy tile format
      x: x tile number in slippy tile format
      y: y tile number in slippy tile format
      sync_token: token retrieved in the original GET GridCellMetadata,
      uss_id: plain text identifier for the USS,
      ws_scope: scope to use to obtain OAuth token,
      operation_format: output format for operation ws (i.e. NASA, GUTMA),
      operation_ws: submitting USS endpoint where all flights in
        this cell can be retrieved from,
      earliest_operation: lower bound of active or planned flight timestamp,
        used for quick filtering conflicts.
      latest_operation: upper bound of active or planned flight timestamp,
        used for quick filtering conflicts.
    Returns:
      JSend formatted response (https://labs.omniti.com/labs/jsend)
    """
        if slippy_util.validate_slippy(z, x, y):
            # first we have to get the cell
            (content, metadata) = self._get_raw(z, x, y)
            if metadata:
                # Quick check of the token, another is done on the actual set to be sure
                #    but this check fails early and fast
                if str(metadata.last_modified_transaction_id) == str(
                        sync_token):
                    try:
                        m = uss_metadata.USSMetadata(content)
                        log.debug('Setting metadata for %s...', uss_id)
                        if not m.upsert_operator(
                                uss_id, ws_scope, operation_format,
                                operation_ws, earliest_operation,
                                latest_operation, z, x, y):
                            log.error(
                                'Failed setting operator for %s with token %s...',
                                uss_id, str(sync_token))
                            raise ValueError
                        status = self._set_raw(z, x, y, m, metadata.version)
                    except ValueError:
                        status = 424
                else:
                    status = 409
            else:
                status = 404
        else:
            status = 400
        if status == 200:
            # Success, now get the metadata back to send back
            result = self.get(z, x, y)
        else:
            result = self._format_status_code_to_jsend(status)
        return result

    def delete(self, z, x, y, uss_id):
        """Sets the metadata for a GridCell by removing the entry for the USS.

    Args:
      z: zoom level in slippy tile format
      x: x tile number in slippy tile format
      y: y tile number in slippy tile format
      uss_id: is the plain text identifier for the USS
    Returns:
      JSend formatted response (https://labs.omniti.com/labs/jsend)
    """
        status = 500
        if slippy_util.validate_slippy(z, x, y):
            # first we have to get the cell
            (content, metadata) = self._get_raw(z, x, y)
            if metadata:
                try:
                    m = uss_metadata.USSMetadata(content)
                    m.remove_operator(uss_id)
                    # TODO(pelletierb): Automatically retry on delete
                    status = self._set_raw(z, x, y, m, metadata.version)
                except ValueError:
                    status = 424
            else:
                status = 404
        else:
            status = 400
        if status == 200:
            # Success, now get the metadata back to send back
            (content, metadata) = self._get_raw(z, x, y)
            result = {
                'status': 'success',
                'sync_token': metadata.last_modified_transaction_id,
                'data': m.to_json()
            }
        else:
            result = self._format_status_code_to_jsend(status)
        return result

    def get_multi(self, z, grids):
        """Gets the metadata and snapshot token for multiple GridCells.

    Reads data from zookeeper, including a composite snapshot token. The
    snapshot token is used as a reference when writing to ensure
    the data has not been updated between read and write.

    Args:
      z: zoom level in slippy tile format
      grids: list of (x,y) tiles to retrieve
    Returns:
      JSend formatted response (https://labs.omniti.com/labs/jsend)
    """
        try:
            combined_meta, syncs = self._get_multi_raw(z, grids)
            log.debug('Found sync token %s for %d grids...',
                      self._hash_sync_tokens(syncs), len(syncs))
            result = {
                'status': 'success',
                'sync_token': self._hash_sync_tokens(syncs),
                'data': combined_meta.to_json()
            }
        except ValueError as e:
            result = self._format_status_code_to_jsend(400, e.message)
        except IndexError as e:
            result = self._format_status_code_to_jsend(404, e.message)
        return result

    def set_multi(self, z, grids, sync_token, uss_id, ws_scope,
                  operation_format, operation_ws, earliest_operation,
                  latest_operation):
        """Sets multiple GridCells metadata at once.

    Writes data, using the hashed snapshot token for confirming data
    has not been updated since it was last read.

    Args:
      z: zoom level in slippy tile format
      grids: list of (x,y) tiles to update
      sync_token: token retrieved in the original get_multi,
      uss_id: plain text identifier for the USS,
      ws_scope: scope to use to obtain OAuth token,
      operation_format: output format for operation ws (i.e. NASA, GUTMA),
      operation_ws: submitting USS endpoint where all flights in
        this cell can be retrieved from,
      earliest_operation: lower bound of active or planned flight timestamp,
        used for quick filtering conflicts.
      latest_operation: upper bound of active or planned flight timestamp,
        used for quick filtering conflicts.
    Returns:
      JSend formatted response (https://labs.omniti.com/labs/jsend)
    """
        log.debug('Setting multiple grid metadata for %s...', uss_id)
        try:
            # first, get the affected grid's sync tokens
            m, syncs = self._get_multi_raw(z, grids)
            del m
            # Quick check of the token, another is done on the actual set to be sure
            #    but this check fails early and fast
            log.debug('Found sync token %d for %d grids...',
                      self._hash_sync_tokens(syncs), len(syncs))
            if str(self._hash_sync_tokens(syncs)) == str(sync_token):
                log.debug('Composite sync_token matches, continuing...')
                self._set_multi_raw(z, grids, syncs, uss_id, ws_scope,
                                    operation_format, operation_ws,
                                    earliest_operation, latest_operation)
                log.debug('Completed updating multiple grids...')
            else:
                raise KeyError('Composite sync_token has changed')
            combined_meta, new_syncs = self._get_multi_raw(z, grids)
            result = {
                'status': 'success',
                'sync_token': self._hash_sync_tokens(new_syncs),
                'data': combined_meta.to_json()
            }
        except (KeyError, RolledBackError) as e:
            result = self._format_status_code_to_jsend(409, e.message)
        except ValueError as e:
            result = self._format_status_code_to_jsend(400, e.message)
        except IndexError as e:
            result = self._format_status_code_to_jsend(404, e.message)
        return result

    def delete_multi(self, z, grids, uss_id):
        """Sets multiple GridCells metadata by removing the entry for the USS.

    Removes the operator from multiple cells. Does not return 404 on
    not finding the USS in a cell, since this should be a remove all
    type function, as some cells might have the ussid and some might not.
    
    Args:
      z: zoom level in slippy tile format
      grids: list of (x,y) tiles to delete
      uss_id: is the plain text identifier for the USS
    Returns:
      JSend formatted response (https://labs.omniti.com/labs/jsend)
    """
        log.debug('Deleting multiple grid metadata for %s...', uss_id)
        try:
            if not uss_id:
                raise ValueError('Invalid uss_id for deleting multi')
            for x, y in grids:
                if slippy_util.validate_slippy(z, x, y):
                    (content, metadata) = self._get_raw(z, x, y)
                    if metadata:
                        m = uss_metadata.USSMetadata(content)
                        m.remove_operator(uss_id)
                        # TODO(pelletierb): Automatically retry on delete
                        status = self._set_raw(z, x, y, m, metadata.version)
                else:
                    raise ValueError('Invalid slippy grids for lookup')
            result = self.get_multi(z, grids)
        except ValueError as e:
            result = self._format_status_code_to_jsend(400, e.message)
        return result

    ######################################################################
    ################       INTERNAL FUNCTIONS    #########################
    ######################################################################
    def _get_raw(self, z, x, y):
        """Gets the raw content and metadata for a GridCell from zookeeper.

    Args:
      z: zoom level in slippy tile format
      x: x tile number in slippy tile format
      y: y tile number in slippy tile format
    Returns:
      content: USS metadata
      metadata: straight from zookeeper
    """
        path = '%s/%s/%s/%s/%s' % (GRID_PATH, str(z), str(x), str(y),
                                   USS_METADATA_FILE)
        log.debug('Getting metadata from zookeeper@%s...', path)
        try:
            c, m = self.zk.get(path)
        except NoNodeError:
            self.zk.ensure_path(path)
            c, m = self.zk.get(path)
        if c:
            log.debug('Received raw content and metadata from zookeeper: %s',
                      c)
        if m:
            log.debug('Received raw metadata from zookeeper: %s', m)
        return c, m

    def _set_raw(self, z, x, y, m, version):
        """Grabs the lock and updates the raw content for a GridCell in zookeeper.

    Args:
      z: zoom level in slippy tile format
      x: x tile number in slippy tile format
      y: y tile number in slippy tile format
      m: metadata object to write
      version: the metadata version verified from the sync_token match
    Returns:
      200 for success, 409 for conflict, 408 for unable to get the lock
    """
        path = '%s/%s/%s/%s/%s' % (GRID_PATH, str(z), str(x), str(y),
                                   USS_METADATA_FILE)
        try:
            log.debug('Setting metadata to %s...', str(m))
            self.zk.set(path, json.dumps(m.to_json()), version)
            status = 200
        except BadVersionError:
            log.error('Sync token updated before write for %s...', path)
            status = 409
        return status

    def _get_multi_raw(self, z, grids):
        """Gets the raw content and metadata for multiple GridCells from zookeeper.

    Args:
      z: zoom level in slippy tile format
      grids: list of (x,y) tiles to retrieve
    Returns:
      content: Combined USS metadata
      syncs: list of sync tokens in the same order as the grids
    Raises:
      IndexError: if it cannot find anything in zookeeper
      ValueError: if the grid data is not in the right format
    """
        log.debug('Getting multiple grid metadata for %s...', str(grids))
        combined_meta = None
        syncs = []
        for x, y in grids:
            if slippy_util.validate_slippy(z, x, y):
                (content, metadata) = self._get_raw(z, x, y)
                if metadata:
                    combined_meta += uss_metadata.USSMetadata(content)
                    syncs.append(metadata.last_modified_transaction_id)
                else:
                    raise IndexError('Unable to find metadata in platform')
            else:
                raise ValueError('Invalid slippy grids for lookup')
        if len(syncs) == 0:
            raise IndexError('Unable to find metadata in platform')
        return combined_meta, syncs

    def _set_multi_raw(self, z, grids, sync_tokens, uss_id, ws_scope,
                       operation_format, operation_ws, earliest_operation,
                       latest_operation):
        """Grabs the lock and updates the raw content for multiple GridCells

    Args:
      z: zoom level in slippy tile format
      grids: list of (x,y) tiles to retrieve
      sync_tokens: list of the sync tokens received during get operation
      uss_id: plain text identifier for the USS,
      ws_scope: scope to use to obtain OAuth token,
      operation_format: output format for operation ws (i.e. NASA, GUTMA),
      operation_ws: submitting USS endpoint where all flights in
        this cell can be retrieved from,
      earliest_operation: lower bound of active or planned flight timestamp,
        used for quick filtering conflicts.
      latest_operation: upper bound of active or planned flight timestamp,
        used for quick filtering conflicts.
    Raises:
      IndexError: if it cannot find anything in zookeeper
      ValueError: if the grid data is not in the right format
    """
        log.debug('Setting multiple grid metadata for %s...', str(grids))
        try:
            contents = []
            for i in range(len(grids)):
                # First, get and update them all in memory, validate the sync_token
                x = grids[i][0]
                y = grids[i][1]
                sync_token = sync_tokens[i]
                path = '%s/%s/%s/%s/%s' % (GRID_PATH, str(z), str(x), str(y),
                                           USS_METADATA_FILE)
                (content, metadata) = self._get_raw(z, x, y)
                if str(metadata.last_modified_transaction_id) == str(
                        sync_token):
                    log.debug('Sync_token matches for %d, %d...', x, y)
                    m = uss_metadata.USSMetadata(content)
                    if not m.upsert_operator(
                            uss_id, ws_scope, operation_format, operation_ws,
                            earliest_operation, latest_operation, z, x, y):
                        raise ValueError('Failed to set operator content')
                    contents.append((path, m, metadata.version))
                else:
                    log.error(
                        'Sync token from USS (%s) does not match token from zk (%s)...',
                        str(sync_token),
                        str(metadata.last_modified_transaction_id))
                    raise KeyError('Composite sync_token has changed')
            # Now, start a transaction to update them all
            #  the version will catch any changes and roll back any attempted
            #  updates to the grids
            log.debug('Starting transaction to write all grids at once...')
            t = self.zk.transaction()
            for path, m, version in contents:
                t.set_data(path, json.dumps(m.to_json()), version)
            log.debug('Committing transaction...')
            results = t.commit()
            if isinstance(results[0], RolledBackError):
                raise KeyError(
                    'Rolled back multi-grid transaction due to grid change')
            log.debug('Committed transaction successfully.')
        except (KeyError, ValueError, IndexError) as e:
            log.error('Error caught in set_multi_raw %s.', e.message)
            raise e

    def _format_status_code_to_jsend(self, status, message=None):
        """Formats a response based on HTTP status code.

    Args:
      status: HTTP status code
      message: optional message to override preset message for codes
    Returns:
      JSend formatted response (https://labs.omniti.com/labs/jsend)
    """

        if status == 200 or status == 204:
            result = {
                'status': 'success',
                'code': 204,
                'message': 'Empty data set.'
            }
        elif status == 400:
            result = {
                'status': 'fail',
                'code': status,
                'message': 'Parameters are not following the correct format.'
            }
        elif status == 404:
            result = {
                'status': 'fail',
                'code': status,
                'message': 'Unable to pull metadata from lock system.'
            }
        elif status == 408:
            result = {
                'status': 'fail',
                'code': status,
                'message': 'Timeout trying to get lock.'
            }
        elif status == 409:
            result = {
                'status':
                'fail',
                'code':
                status,
                'message':
                'Content in metadata has been updated since provided sync token.'
            }
        elif status == 424:
            result = {
                'status':
                'fail',
                'code':
                status,
                'message':
                'Content in metadata is not following JSON format guidelines.'
            }
        else:
            result = {
                'status': 'fail',
                'code': status,
                'message': 'Unknown error code occurred.'
            }
        if message:
            result['message'] = message
        return result

    @staticmethod
    def _hash_sync_tokens(syncs):
        """Hashes a list of sync tokens into a single, positive 64-bit int.

    For various languages, the limit to integers may be different, therefore
    we truncate to ensure the hash is the same on all implementations.
    """
        return abs(hash(tuple(sorted(syncs)))) % MAX_SAFE_INTEGER
Beispiel #13
0
打印zookeeper树

'''

from kazoo.client import KazooClient
from kazoo.client import KazooState
import datetime
import time

hosts = '10.48.57.42:8581,10.48.57.42:8582,10.48.57.42:8583'
zk = KazooClient(hosts=hosts)
zk.start()

print "hosts", hosts
print "version", zk.server_version()


#
#
#
def printTreeNode(basepath, node, i):

    if isinstance(node, list):

        for item in node:

            # current
            current_base_path = basepath + "/" + item
            data, stat = zk.get(current_base_path)
            ahead = ""
Beispiel #14
0
@author: liaoqiqi

打印zookeeper树

"""

from kazoo.client import KazooClient
import time

hosts = '127.0.0.1:3307'
zk = KazooClient(hosts=hosts)
zk.start()

print "hosts", hosts
print "version", zk.server_version()

#
#
#
def printTreeNode(basepath, node, i):
    if isinstance(node, list):

        for item in node:

            # current
            current_base_path = basepath + "/" + item
            data, stat = zk.get(current_base_path)
            ahead = ""
            j = 1
            while j < i: