Esempio n. 1
0
def export(args=None):
    """Usage: %prog [options] connection [path]
    """
    if args is None:
        args = sys.argv[1:]

    parser = optparse.OptionParser(export.__doc__)
    parser.add_option('-e', '--ephemeral', action='store_true')
    parser.add_option('-o', '--output')

    options, args = parser.parse_args(args)
    connection = args.pop(0)
    if args:
        [path] = args
    else:
        path = '/'

    logging.basicConfig(level=logging.WARNING)

    zk = zc.zk.ZooKeeper(connection)
    data = zk.export_tree(path, ephemeral=options.ephemeral)

    if options.output:
        with open(options.output, 'w') as f:
            f.write(data)
    else:
        print data,

    zk.close()
Esempio n. 2
0
def worker(app, global_conf, zookeeper, path, loggers=None, address=':0',
           threads=None, backdoor=False, description=None, version=None,
           run=True, **kw):
    """Paste deploy server runner
    """
    if loggers:
        if re.match(r'\d+$', loggers):
            logging.basicConfig(level=int(loggers))
        elif loggers in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'):
            logging.basicConfig(level=getattr(logging, loggers))
        else:
            import ZConfig
            ZConfig.configureLoggers(loggers)

    zk = zc.zk.ZooKeeper(zookeeper)
    address = zc.parse_addr.parse_addr(address)
    from zc.resumelb.worker import Worker

    worker = Worker(app, address, threads=threads and int(threads),
                    **kw)

    # Set up notification of settings changes.
    settings = zk.properties(path)
    watcher = gevent.get_hub().loop.async()
    watcher.start(lambda : worker.update_settings(settings))
    settings(lambda _: watcher.send())

    registration_data = {}
    if backdoor == 'true':
        from gevent import backdoor
        bd = backdoor.BackdoorServer(('127.0.0.1', 0), locals())
        bd.start()
        registration_data['backdoor'] = '127.0.0.1:%s' % bd.server_port
        worker.__bd = bd

    if description:
        registration_data['description'] = description

    if version:
        registration_data['version'] = version

    zk.register_server(path+'/providers', worker.addr, **registration_data)
    worker.zk = zk
    worker.__zksettings = settings

    def shutdown():
        zk.close()
        worker.shutdown()

    gevent.signal(signal.SIGTERM, shutdown)

    if run:
        try:
            worker.server.serve_forever()
        finally:
            logging.getLogger(__name__+'.worker').info('exiting')
            zk.close()
    else:
        gevent.sleep(.01)
        return worker
Esempio n. 3
0
def sync_with_canonical(url, dry_run=False, force=False, tree_directory=None):
    zk = zc.zk.ZK(ZK_LOCATION)
    zk_version = get_zk_version(zk)
    if zk_version is None:
        logger.critical("ALL STOP, cluster version is None")
        if not force:
            return

    retries = 0
    while True:
        try:
            if url.startswith('svn') or url.startswith('file://'):
                vcs = SVN(url)
            else:
                vcs = GIT(url, tree_directory)
            break
        except RuntimeError:
            retries += 1
            if retries > MAX_VCS_RETRIES:
                raise
            time.sleep(3)

    logger.info("VCS Version: " + str(vcs.version))
    logger.info("ZK Version: " + str(zk_version))
    if zk_version != vcs.version:
        if not (force or zk_version is False):
            for child in zk.get_children('/hosts'):
                host_version = zk.properties('/hosts/' + child)['version']
                if host_version != zk_version:
                    logger.error(
                        "Version mismatch detected, can't resync since " +
                        "host %s has not converged (%s -> %s)" %
                        (child, host_version, zk_version))
                    return

        cluster_lock = zk.client.Lock('/hosts-lock', str(os.getpid()))
        if cluster_lock.acquire(0):
            try:
                logger.info("Version mismatch detected, resyncing")

                # Import changes
                for fi, contents in vcs:
                    output = ' '.join(('Importing', fi))
                    if dry_run:
                        output += ' (dry run, no action taken)'
                    logger.info(output)
                    if not dry_run:
                        zk.import_tree(contents, trim=fi.endswith('.zk'))
                # bump version number
                if not dry_run:
                    zk.properties('/hosts').update(version=vcs.version)
            finally:
                cluster_lock.release()
        else:
            logger.error("Refused to update zookeeper tree, "
                         "couldn't obtain cluster lock")

    zk.close()
Esempio n. 4
0
def import_(args=None):
    """Usage: %prog [options] connection [import-file [path]]

    Import a tree definition from a file.

    If no import-file is provided or if the import file is -, then
    data are read from standard input.
    """

    if args is None:
        args = sys.argv[1:]

    parser = optparse.OptionParser(import_.__doc__)
    parser.add_option('-d', '--dry-run', action='store_true')
    parser.add_option('-t', '--trim', action='store_true')
    parser.add_option(
        '-p', '--permission', type='int',
        default=kazoo.security.Permissions.ALL,
        help='ZooKeeper permission bits as integer,'
        ' kazoo.security.Permissions.ALL',
        )

    options, args = parser.parse_args(args)
    if not (1 <= len(args) <= 3):
        parser.parse_args(['-h'])

    connection = args.pop(0)
    if args:
        import_file = args.pop(0)
    else:
        import_file = '-'

    if args:
        [path] = args
    else:
        path = '/'

    logging.basicConfig(level=logging.WARNING)

    zk = zc.zk.ZooKeeper(connection)
    if import_file == '-':
        import_file = sys.stdin
    else:
        import_file = open(import_file)

    zk.import_tree(
        import_file.read(), path,
        trim=options.trim,
        dry_run=options.dry_run,
        acl=[world_acl(options.permission)],
        )

    zk.close()
Esempio n. 5
0
def tearDown(test):
    """The matching tearDown for setUp.

    The single argument is the test case passed to setUp.
    """
    setupstack.tearDown(test)
    real_zk = testing_with_real_zookeeper()
    if real_zk:
        zk = zc.zk.ZooKeeper(real_zk)
        root = setupstack.globs(test)['/zc.zk.testing.test-root']
        if zk.exists(root):
            zk.delete_recursive(root)
        zk.close()
Esempio n. 6
0
def set_property(args=None):
    if args is None:
        args = sys.argv[1:]

    connection = args.pop(0)
    path = args.pop(0)
    zk = zc.zk.ZooKeeper(connection)

    def _property(arg):
        name, expr = arg.split('=', 1)
        return name, eval(expr, {})

    zk.properties(path).update(dict(map(_property, args)))

    zk.close()
Esempio n. 7
0
def main(args=None):
    if args is None:
        args = sys.argv[1:]

    args = parser.parse_args(args)
    config = zc.zkdeployment.agent.Configuration(args.configuration)
    zk = zc.zk.ZK(args.zookeeper)
    try:
        host_properties = dict(zk.properties('/hosts/' + config.host_id))
    except kazoo.exceptions.NoNodeError:
        return error('Host not registered')
    zkversion = zk.properties('/hosts', False).get('version')
    zk.close()
    if zkversion is None:
        return warn('Cluster version is None')
    try:
        with open(os.path.join(config.run_directory, 'status')) as f:
            t, _, version, status = f.read().strip().split(None, 3)
    except IOError, err:
        return error(str(err))
Esempio n. 8
0
def setup_tree(tree, connection_string, root='/test-root',
               zookeeper_node=False):
    zk = zc.zk.ZooKeeper(connection_string)
    if zk.exists(root):
        zk.delete_recursive(root)
    zk.create(root, '', zc.zk.OPEN_ACL_UNSAFE)
    zk.import_tree(tree or """
    /fooservice
      /providers
      database = '/databases/foomain'
      threads = 1
      favorite_color = 'red'
    """, root)

    if zookeeper_node:
        zk.import_tree("""
        /zookeeper
          /quota
        """, root)

    zk.close()
Esempio n. 9
0
def find_server(zookeeper, path, monitor_address):
    server = None
    if monitor_address:
        try:
            fp, s = connect(monitor_address)
        except socket.error as err:
            return print("Can't connect %s" % err)

        s.settimeout(1.0)
        fp.write('servers %s\n' % path)
        fp.flush()
        data = fp.read().strip()
        fp.close(); s.close()
        if data.lower().startswith("invalid "):
            return print(data + ' at %r' % monitor_address)
        servers = list(set(data.split())) # dedup
        if not servers:
            return print("No servers at: %r" % monitor_address)
        if len(servers) > 1:
            return print("Too many servers, %r, at: %r" %
                         (sorted(servers), monitor_address))
        server = servers[0]

    zk = zc.zk.ZK(zookeeper)
    children = zk.get_children(path)
    zk.close()
    if server:
        host, port = server.split(':')
        if host:
            children = [c for c in children if c == server]
        else:
            children = [c for c in children if c.split(':')[1] == port]

    if len(children) != 1:
        return print("Couldn't find server in ZooKeeper")
    addr = children[0]
    return addr
Esempio n. 10
0
import zc.zk

zk = None
try:
    host = '10.251.22.99:2181'
    zk = zc.zk.ZooKeeper(host)
    print zk
    zk.delete_recursive('brokers/topics/test')
    zk.close()
except Exception as e:
    zk.close()


Esempio n. 11
0
def setUp(test, tree=None, connection_string='zookeeper.example.com:2181'):
    """Set up zookeeper emulation.

    Standard (mock) testing
    -----------------------

    The first argument is a test case object (either doctest or unittest).

    You can optionally pass:

    tree
       An initial ZooKeeper tree expressed as an import string.
       If not passed, an initial tree will be created with examples
       used in the zc.zk doctests.

    connection_string
       The connection string to use for the emulation server. This
       defaults to 'zookeeper.example.com:2181'.

    Testing with a real ZooKeeper Server
    ------------------------------------

    You can test against a real ZooKeeper server, instead of a mock by
    setting the environment variable TEST_ZOOKEEPER_CONNECTION to the
    connection string of a test server.

    The tests will create a top-level node with a random name that
    starts with 'zc.zk.testing.test-roo', and use that as the virtual
    root for your tests.  Although this is the virtual root, of the
    zookeeper tree in your tests, the presense of the node may be
    shown in your tests. In particularm ``zookeeper.create`` returns
    the path created and the string returned is real, not virtual.
    This node is cleaned up by the ``tearDown``.

    A doctest can determine if it's running with a stub ZooKeeper by
    checking whether the value of the ZooKeeper gloval variable is None.
    A regular unit test can check the ZooKeeper test attribute.
    """

    globs = setupstack.globs(test)
    faux_zookeeper = None
    real_zk = testing_with_real_zookeeper()
    if real_zk:
        test_root = '/zc.zk.testing.test-root%s' % random.randint(0, sys.maxsize)
        globs['/zc.zk.testing.test-root'] = test_root
        setup_tree(tree, real_zk, test_root, True)

        orig_init = zookeeper.init

        @side_effect(
            setupstack.context_manager(test, mock.patch('zookeeper.init')))
        def init(addr, watch=None, session_timeout=1000):
            if addr != connection_string:
                return orig_init(addr, watch, session_timeout)
            else:
                return orig_init(real_zk+test_root, watch, session_timeout)

        setupstack.register(
            test, lambda : setattr(zc.zk.ZooKeeper, 'test_sleep', 0))
        zc.zk.ZooKeeper.test_sleep = .01
        time.sleep(float(os.environ.get('TEST_ZOOKEEPER_SLEEP', 0)))

    else:
        if tree:
            faux_zookeeper = ZooKeeper(connection_string, Node())
        else:
            faux_zookeeper = ZooKeeper(
                connection_string,
                Node(
                    fooservice = Node(
                        json.dumps(dict(
                            database = "/databases/foomain",
                            threads = 1,
                            favorite_color= "red",
                            )),
                        providers = Node()
                        ),
                    zookeeper = Node('', quota=Node()),
                    ),
                )
        for name in ZooKeeper.__dict__:
            if name[0] == '_':
                continue
            m = setupstack.context_manager(test, mock.patch('zookeeper.'+name))
            m.side_effect = getattr(faux_zookeeper, name)

        if tree:
            zk = zc.zk.ZooKeeper(connection_string)
            zk.import_tree(tree)
            zk.close()

    globs['wait_until'] = wait_until # BBB
    globs['ZooKeeper'] = faux_zookeeper
    globs.setdefault('assert_', assert_)
Esempio n. 12
0
    def __init__(self, buildout, name, options):
        super(Recipe, self).__init__(buildout, name, options)

        if len(options) < 2:
            zk = zc.zk.ZK('zookeeper:2181')
            path = '/' + name.rsplit('.', 1)[0].replace(',', '/')
            options.update(flatten(zk, path))
            zk.close()

        user = self.user = options.get('user', 'root')

        self['deployment'] = dict(
            recipe='zc.recipe.deployment',
            name=name,
            user=user,
        )

        client = docker.Client()

        image_spec = options['image']
        image_name, tag = image_spec.rsplit(':', 1)

        images = [
            image for image in client.images(image_name) if image['Tag'] == tag
        ]

        if not images:
            container = client.create_container(
                'registry',
                '/docker-registry/run.sh',
                environment=dict(SETTINGS_FLAVOR='prod'),
                detach=True,
                ports=["5000/tcp"])
            try:
                client.start(container)
                try:
                    port = client.inspect_container(container)[
                        'NetworkSettings']['PortMapping']['Tcp']['5000']
                    repo_name = "127.0.0.1:%s/%s" % (port, image_name)
                    time.sleep(9)  # give registry plenty of time to start
                    client.pull(repo_name, tag=tag)
                finally:
                    client.stop(container)
            finally:
                client.remove_container(container)

            images = [
                image for image in client.images(repo_name)
                if tag is None or image['Tag'] == tag
            ]
            if not images:
                raise ValueError("Couldn't pull", image_spec)
            [image] = images
            client.tag(image['Id'], image_name, tag)
        else:
            [image] = images

        image = client.inspect_image(image['Id'])['container_config']

        run_command = ['docker run -rm']

        hostname = '.'.join(reversed(name.rsplit('.', 1)[0].split(',')))
        n = name.rsplit('.', 1)[1]
        if n != '0':
            hostname = 'n%s.%s' % (n, hostname)
        hostname += ".o-o." + socket.getfqdn()
        run_command.append("-h " + hostname)

        ports = options.get('ports', ())
        if ports == '*':
            run_command.append('-P')
        elif ports:
            if ports == '=:*':
                ports = [
                    '%s:%s' % (port, port) for port in sorted(
                        image['PortSpecs']
                        # 0.7: parse_exposed(image['ExposedPorts'])
                    )
                ]
            else:
                ports = parse_ports(
                    ports,
                    set(image['PortSpecs']
                        # 0.7: parse_exposed(image['ExposedPorts'])
                        ))

            for port in ports:
                run_command.extend(('-p', port))

        for option, value in sorted(options.items()):
            if option.startswith('volumes/'):
                run_command.append('-v=%s:%s' % (value, option[7:]))
            elif option.startswith('environment/'):
                run_command.append('-e=%s=%s' % (option[12:], value))

        run_command.append(image_spec)
        run_command = ' '.join(run_command)

        self['container'] = dict(  # TODO: start-test-program
            recipe='zc.zdaemonrecipe',
            deployment='deployment',
            program=run_command)

        self['rc'] = dict(recipe='zc.recipe.rhrc',
                          deployment='deployment',
                          parts='container',
                          chkconfig='345 99 10',
                          digest=hashlib.md5(run_command).hexdigest(),
                          **{'process-management': 'true'})
Esempio n. 13
0
 def shutdown():
     zk.close()
     worker.shutdown()
Esempio n. 14
0
 def shutdown():
     zk.close()
     server.close()
     if status_server is not None:
         status_server.close()
     lb.shutdown()
Esempio n. 15
0
def lbmain(args=None, run=True):
    """%prog [options] zookeeper_connection path

    Run a resume-based load balancer on addr.
    """
    if args is None:
        args = sys.argv[1:]
    elif isinstance(args, str):
        args = args.split()
        run = False
    import optparse
    parser = optparse.OptionParser(lbmain.__doc__)
    parser.add_option(
        '-a', '--address', default=':0',
        help="Address to listed on for web requests"
        )
    parser.add_option(
        '-b', '--backlog', type='int',
        help="Server backlog setting.")
    parser.add_option(
        '-d', '--backdoor', action='store_true',
        help="Run a backdoor server. Use with caution!")
    parser.add_option(
        '-e', '--disconnect-message',
        help="Path to error page to use when a request is lost due to "
        "worker disconnection"
        )
    parser.add_option(
        '-L', '--logger-configuration',
        help=
        "Read logger configuration from the given configuration file path.\n"
        "\n"
        "The configuration file must be in ZConfig logger configuration syntax."
        "\n"
        "Alternatively, you can give a Python logger level name or number."
        )
    parser.add_option('-l', '--access-logger', help='Access-log logger name.')
    parser.add_option(
        '-m', '--max-connections', type='int',
        help="Maximum number of simultanious accepted connections.")
    parser.add_option(
        '-r', '--request-classifier', default='zc.resumelb.lb:host_classifier',
        help="Request classification function (module:expr)"
        )
    parser.add_option(
        '-s', '--status-server',
        help=("Run a status server for getting pool information. "
              "The argument is a unix-domain socket path to listen on."))
    parser.add_option(
        '-t', '--socket-timeout', type='float', default=99.,
        help=('HTTP socket timeout.'))
    parser.add_option(
        '-v', '--single-version', action='store_true',
        help=('Only use a single worker version.'))

    try:
        options, args = parser.parse_args(args)
        if len(args) != 2:
            print 'Error: must supply a zookeeper connection string and path.'
            parser.parse_args(['-h'])
        zookeeper, path = args
    except SystemExit:
        if run:
            raise
        else:
            return

    if options.logger_configuration:
        logger_config = options.logger_configuration
        if re.match(r'\d+$', logger_config):
            logging.basicConfig(level=int(logger_config))
        elif logger_config in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'):
            logging.basicConfig(level=getattr(logging, logger_config))
        else:
            import ZConfig
            with open(logger_config) as f:
                ZConfig.configureLoggers(f.read())

    zk = zc.zk.ZooKeeper(zookeeper)
    addrs = zk.children(path+'/workers/providers')
    rcmod, rcexpr = options.request_classifier.split(':')
    __import__(rcmod)
    rcmod = sys.modules[rcmod]
    request_classifier = eval(rcexpr, rcmod.__dict__)

    disconnect_message = options.disconnect_message
    if disconnect_message:
        with open(disconnect_message) as f:
            disconnect_message = f.read()
    else:
        disconnect_message = zc.resumelb.lb.default_disconnect_message

    from zc.resumelb.lb import LB
    lb = LB(map(zc.parse_addr.parse_addr, ()),
            request_classifier, disconnect_message,
            single_version=options.single_version)


    to_send = [[]]
    # Set up notification of address changes.
    awatcher = gevent.get_hub().loop.async()
    @awatcher.start
    def _():
        lb.set_worker_addrs(to_send[0])

    if options.single_version:
        @addrs
        def get_addrs(a):
            to_send[0] = dict(
                (zc.parse_addr.parse_addr(addr),
                 zk.get_properties(
                     path+'/workers/providers/'+addr).get('version')
                 )
                for addr in addrs)
            awatcher.send()
    else:
        @addrs
        def get_addrs(a):
            to_send[0] = map(zc.parse_addr.parse_addr, addrs)
            awatcher.send()

    # Set up notification of address changes.
    settings = zk.properties(path)
    swatcher = gevent.get_hub().loop.async()
    swatcher.start(lambda : lb.update_settings(settings))
    settings(lambda a: swatcher.send())

    lb.zk = zk
    lb.__zk = addrs, settings

    # Now, start a wsgi server
    addr = zc.parse_addr.parse_addr(options.address)
    if options.max_connections:
        spawn= gevent.pool.Pool(options.max_connections)
    else:
        spawn = 'default'

    if options.access_logger:
        accesslog = AccessLog(options.access_logger)
    else:
        accesslog = None

    server = WSGIServer(
        addr, lb.handle_wsgi, backlog=options.backlog,
        spawn=spawn, log=accesslog, socket_timeout=options.socket_timeout)
    server.start()

    registration_data = {}
    if options.backdoor:
        from gevent import backdoor
        bd = backdoor.BackdoorServer(('127.0.0.1', 0), locals())
        bd.start()
        registration_data['backdoor'] = '127.0.0.1:%s' % bd.server_port

    status_server = None
    if options.status_server:
        def status(socket, addr):
            pool = lb.pool
            writer = socket.makefile('w')
            writer.write(json.dumps(
                dict(
                    backlog = pool.backlog,
                    mean_backlog = pool.mbacklog,
                    workers = [
                        (worker.__name__,
                         worker.backlog,
                         worker.mbacklog,
                         (int(worker.oldest_time)
                          if worker.oldest_time else None),
                         )
                        for worker in sorted(
                            pool.workers, key=lambda w: w.__name__)
                        ]
                    ))+'\n')
            writer.close()
            socket.close()

        status_server_address = options.status_server
        if os.path.exists(status_server_address):
            os.remove(status_server_address)
        sock = gevent.socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        sock.bind(status_server_address)
        sock.listen(5)
        status_server = gevent.server.StreamServer(sock, status)
        status_server.start()

    zk.register_server(path+'/providers', (addr[0], server.server_port),
                       **registration_data)

    def shutdown():
        zk.close()
        server.close()
        if status_server is not None:
            status_server.close()
        lb.shutdown()

    gevent.signal(signal.SIGTERM, shutdown)

    if run:
        try:
            server.serve_forever()
        finally:
            logging.getLogger(__name__+'.lbmain').info('exiting')
            zk.close()
    else:
        gevent.sleep(.01)
        return lb, server