Ejemplo n.º 1
0
    def __init__(self):
        """
        Construct a new AMQPClientHandler instance based on the configuration
        stored in the environment.

        @type env: Environment
        @param env: L{Environment} object
        """
        env = Environment.getInstance()
        self.log = logging.getLogger(__name__)
        self.log.debug("initializing AMQP client handler")
        self.env = env

        # Load configuration
        self.url = parseURL(self.env.config.get('amqp.url', None))
        self.domain = self.env.config.get('ampq.domain', default="org.clacks")
        self.dns_domain = socket.getfqdn().split('.', 1)[1]

        # Use zeroconf if there's no URL
        if self.url:
            o = urlparse(self.url['source'])

        else:
            url = ZeroconfClient.discover(['_amqps._tcp', '_amqp._tcp'],
                                          domain=self.domain)[0]
            o = urlparse(url)

            # pylint: disable=E1101
            self.domain = o.path[1::]

        # Configure system
        user = self.env.uuid

        key = self.env.config.get('amqp.key')
        if key:
            # pylint: disable=E1101
            self.url = parseURL(
                '%s://%s:%s@%s%s' % (o.scheme, user, key, o.netloc, o.path))
        else:
            self.url = parseURL(url)

        # Make proxy connection
        self.log.info(
            "using service '%s/%s'" % (self.url['host'], self.url['path']))
        self.__proxy = AMQPServiceProxy(self.url['source'])

        # Set params and go for it
        self.reconnect = self.env.config.get('amqp.reconnect', True)
        self.reconnect_interval = self.env.config.get(
            'amqp.reconnect-interval', 3)
        self.reconnect_limit = self.env.config.get('amqp.reconnect-limit', 0)

        # Check if credentials are supplied
        if not self.env.config.get("amqp.key"):
            raise Exception("no key supplied - please join the client")

        # Start connection
        self.start()
Ejemplo n.º 2
0
def main():
    env = Environment.getInstance()
    config = env.config

    # Load configuration
    path = config.get('backend-monitor.audit-log', default='/var/lib/clacks/ldap-audit.log')
    modifier = config.get('backend-monitor.modifier')
    user = config.get('core.id')
    password = config.get('amqp.key')
    url = parseURL(makeAuthURL(config.get('amqp.url'), user, password))

    # Connect to Clacks BUS
    proxy = AMQPServiceProxy(url['source'] + "/" + env.domain)

    # Main loop
    while True:
        sleep(1)

        # Wait for file to pop up
        if not os.path.exists(path):
            continue

        # Wait for file to be file
        if not os.path.isfile(path):
            continue

        # Check if it is effectively readable
        try:
            with open(path) as f:
                pass
        except IOError as e:
            continue

        # Listen for changes
        monitor(path, modifier, proxy)
Ejemplo n.º 3
0
    def serve(self):
        """ Start AMQP service for this clacks service provider. """
        # Load AMQP and Command registry instances
        amqp = PluginRegistry.getInstance('AMQPHandler')
        self.__cr = PluginRegistry.getInstance('CommandRegistry')

        # Create a list of queues we need here
        queues = {}
        for dsc in self.__cr.commands.values():
            queues[dsc['target']] = True

        # Finally create the queues
        for queue in queues:
            # Add round robin processor for queue
            self.__cmdWorker = AMQPWorker(self.env, connection=amqp.getConnection(),
                r_address='%s.command.%s; { create:always, node:{ type:queue, x-bindings:[ { exchange:"amq.direct", queue:"%s.command.%s" } ] } }' % (self.env.domain, queue, self.env.domain, queue),
                workers=int(self.env.config.get('amqp.worker', default=1)),
                callback=self.commandReceived)

            # Add private processor for queue
            self.__cmdWorker = AMQPWorker(self.env, connection=amqp.getConnection(),
                    r_address='%s.command.%s.%s; { create:always, delete:receiver, node:{ type:queue, x-bindings:[ { exchange:"amq.direct", queue:"%s.command.%s.%s" } ] } }' % (self.env.domain, queue, self.env.id, self.env.domain, queue, self.env.id),
                workers=int(self.env.config.get('amqp.worker', default=1)),
                callback=self.commandReceived)

        # Announce service
        if self.env.config.get("amqp.announce", default="True").lower() == "true":
            url = parseURL(self.env.config.get("amqp.url"))
            self.__zeroconf = ZeroconfService(name="Clacks RPC service",
                    port=url['port'],
                    stype="_%s._tcp" % url['scheme'],
                    text=dict_to_txt_array({'path': self.env.domain, 'service': 'clacks'}))
            self.__zeroconf.publish()

        self.log.info("ready to process incoming requests")
Ejemplo n.º 4
0
    def __init__(self, url, domain="org.clacks", xquery=".", callback=None):

        # Build connection
        url = parseURL(url)

        _url = "%s:%s" % (url['host'], url['port'])
        self.__conn = Connection.establish(_url, reconnect=True,
            username=url['user'],
            password=url['password'],
            transport=url['transport'],
            reconnect_interval=3,
            reconnect_limit=0)

        # Do automatic broker failover if requested
        #TODO: configure reconnect
        #auto_fetch_reconnect_urls(self.__conn)

        # Assemble subscription query
        queue = 'event-listener-%s' % uuid4()
        address = """%s; {
            create: always,
            delete:always,
            node: {
                durable: False,
                x-declare: {
                    exclusive: True,
                    auto-delete: True }
            },
            link: {
                x-bindings: [
                        {
                            exchange: '%s',
                            queue: %s,
                            key: event,
                            arguments: { xquery: %r}
                        }
                    ]
                }
            }""" % (queue, domain, queue, xquery)

        # Add processor for core.event queue
        self.__callback = callback
        self.__eventWorker = AMQPStandaloneWorker(
                        self.__conn,
                        r_address=address,
                        workers=1,
                        callback=self.__eventProcessor)
Ejemplo n.º 5
0
    def __init__(self):
        env = Environment.getInstance()
        self.log = logging.getLogger(__name__)
        self.log.debug("initializing AMQP handler")
        self.env = env
        self.config = env.config

        # Initialize parser
        schema_root = etree.XML(PluginRegistry.getEventSchema())
        schema = etree.XMLSchema(schema_root)
        self._parser = objectify.makeparser(schema=schema)

        # Evaluate username
        user = self.env.uuid
        password = self.config.get("amqp.key")

        # Load configuration
        self.url = parseURL(makeAuthURL(self.config.get('amqp.url'), user, password))
        self.reconnect = self.config.get('amqp.reconnect', True)
        self.reconnect_interval = self.config.get('amqp.reconnect_interval', 3)
        self.reconnect_limit = self.config.get('amqp.reconnect_limit', 0)

        # Go for it
        self.start()
Ejemplo n.º 6
0
    def __init__(self, serviceURL, serviceAddress=None, serviceName=None,
                 conn=None, worker=None, methods=None):
        self.__URL = url = parseURL(serviceURL)
        self.__serviceURL = serviceURL
        self.__serviceName = serviceName
        self.__serviceAddress = serviceAddress
        self.__worker = worker
        self.__domain = url['path']
        self.__methods = methods

        # Prepare AMQP connection if not already there
        if not conn:

            _url = "%s:%s" % (url['host'], url['port'])
            conn = Connection.establish(_url, reconnect=True,
                username=url['user'],
                password=url['password'],
                transport=url['transport'],
                reconnect_interval=3,
                reconnect_limit=0)

            #TODO: configure reconnect
            #auto_fetch_reconnect_urls(conn)

            # Prefill __serviceAddress correctly if domain is given
            if self.__domain:
                self.__serviceAddress = '%s.command.core' % self.__domain

            if not self.__serviceAddress:
                raise AMQPException("no serviceAddress or domain specified")

            if not self.__worker:
                self.__worker = {self.__serviceAddress: {}}

            # Pre instanciate core sessions
            for i in range(0, WORKERS):
                ssn = conn.session(str(uuid4()))
                self.__worker[self.__serviceAddress][i] = {
                        'ssn': ssn,
                        'sender': ssn.sender(self.__serviceAddress),
                        'receiver': ssn.receiver('reply-%s; {create:always, delete:always, node: { type: queue, durable: False, x-declare: { exclusive: False, auto-delete: True } }}' % ssn.name),
                        'locked': False}

        # Store connection
        self.__conn = conn
        self.__ssn = None
        self.__sender = None
        self.__receiver = None
        self.__sess = None

        # Retrieve methods
        if not self.__methods:
            self.__serviceName = "getMethods"
            self.__methods = self.__call__()
            self.__serviceName = None

            # If we've no direct queue, we need to push to different queues
            if self.__domain:
                queues = set([
                        x['target'] for x in self.__methods.itervalues()
                        if x['target'] != 'core'
                    ])

                # Pre instanciate queue sessions
                for queue in queues:
                    for i in range(0, WORKERS):
                        ssn = conn.session(str(uuid4()))
                        self.__worker[queue] = {}
                        self.__worker[queue][i] = {
                                'ssn': ssn,
                                'sender': ssn.sender("%s.command.%s" %
                                    (self.__domain, queue)),
                                'receiver': ssn.receiver('reply-%s; {create:always, delete:always, node: { type: queue, durable: False, x-declare: { exclusive: False, auto-delete: True } }}' % ssn.name),
                                'locked': False}
Ejemplo n.º 7
0
def connect(service_uri='', username='', password=''):
    """ Creates a service proxy object from the arguments. """

    # Clean arguments
    username = username.strip()
    password = password.strip()
    service_uri = service_uri.strip()
    domain = socket.getfqdn().split('.', 1)[1]

    if len(service_uri) <= 0:
        print(_("Searching service provider..."))
        try:
            service_uri = ZeroconfClient.discover(['_amqps._tcp', '_amqp._tcp',
                '_https._tcp', '_http._tcp'], domain=domain)[0]

        except DBusException as e:
            print(_("DBUS error: %s") % str(e))
            sys.exit(1)

        except Exception as e:
            print(e.__dict__)

    # Test if one argument is still needed.
    if len(service_uri) <= 0:
        tmp = service_uri
        service_uri = raw_input('Service URI: [%s]' % service_uri).strip()
        if len(service_uri) <= 0:
            service_uri = tmp

    # Chek if URL is parsable
    url = parseURL(service_uri)

    # If we have still no service host, quit, because the connect will fail
    # pylint: disable-msg=E1101
    if not url:
        print(_("Need at least a service URI!"))
        sys.exit(1)

    # TRANSLATOR: Conected to URL, i.e. https://amqp.local:8080/rpc
    print(_("Connected to %s://%s:%s/%s") %
            (url['scheme'], url['host'], url['port'], url['path']))

    # Check weather to use method parameters or the URI elements.
    # If URI username is set and the method username is not set
    if url['user']:
        username = url['user']
    # If URI password is set and the username is set and the method password is not set
    if url['password']:
        password = url['password']

    # If we have still no credentials query for them
    if len(username) <= 0:
        # TRANSLATOR: This is a prompt - Username [joe]:
        username = raw_input(_("Username") + " [%s]: " % getpass.getuser()).strip()
        if len(username) <= 0:
            username = getpass.getuser()

    if len(password) <= 0:
        # TRANSLATOR: This is a prompt - Password:
        password = getpass.getpass(_("Password") + ': ')

    # Create service proxy
    if url['scheme'][0:4] == "amqp":
        connection = '%s://%s:%s@%s:%s/%s' % (
                url['scheme'],
                username,
                password,
                url['host'],
                url['port'],
                url['path'])

        proxy = AMQPServiceProxy(connection)

    elif url['scheme'][0:4] == "http":
        connection = '%s://%s:%s/%s' % (
                url['scheme'],
                url['host'],
                url['port'],
                url['path'])

        proxy = JSONServiceProxy(connection)
    else:
        print(_("The selected protocol is not supported!"))
        sys.exit(1)

    # Try to log in
    try:
        if not proxy.login(username, password):
            print(_("Login of user '%s' failed") % username)
            sys.exit(1)
    except Exception, e:
        print(e)
        sys.exit(1)