示例#1
0
 def execute(self, subscription, messages, **kwargs):
     subscriber = urllib_parse.urlparse(subscription['subscriber'])
     params = urllib_parse.parse_qs(subscriber.query)
     params = dict((k.lower(), v) for k, v in params.items())
     conf = kwargs.get('conf')
     try:
         for message in messages:
             p = subprocess.Popen(conf.notification.smtp_command.split(' '),
                                  stdin=subprocess.PIPE)
             # NOTE(Eva-i): Unfortunately this will add 'queue_name' key to
             # our original messages(dicts) which will be later consumed in
             # the storage controller. It seems safe though.
             message['queue_name'] = subscription['source']
             msg = text.MIMEText(json.dumps(message))
             msg["to"] = subscriber.path
             msg["from"] = subscription['options'].get('from', '')
             subject_opt = subscription['options'].get('subject', '')
             msg["subject"] = params.get('subject', subject_opt)
             p.communicate(msg.as_string())
     except OSError as err:
         LOG.exception(
             _LE('Failed to create process for sendmail, '
                 'because %s.') % str(err))
     except Exception as exc:
         LOG.exception(_LE('Failed to send email because %s.') % str(exc))
示例#2
0
    def transport(self):
        transport_name = self.driver_conf.transport
        LOG.debug(u'Loading transport driver: %s', transport_name)

        # FIXME(vkmc): Find a better way to init args
        if transport_name == 'websocket':
            args = [self.conf, self.api, self.cache]
        else:
            args = [
                self.conf,
                self.storage,
                self.cache,
                self.control,
            ]

        try:
            mgr = driver.DriverManager('zaqar.transport',
                                       transport_name,
                                       invoke_on_load=True,
                                       invoke_args=args)
            return mgr.driver
        except RuntimeError as exc:
            LOG.exception(exc)
            LOG.error(_LE(u'Failed to load transport driver zaqar.transport.'
                          u'%(driver)s with args %(args)s'),
                      {'driver': transport_name, 'args': args})
            raise errors.InvalidDriver(exc)
示例#3
0
    def wrapper(self, *args, **kwargs):
        # TODO(kgriffs): Figure out a way to not have to rely on the
        # presence of `mongodb_conf`
        max_attemps = self.driver.mongodb_conf.max_reconnect_attempts
        sleep_sec = self.driver.mongodb_conf.reconnect_sleep

        last_ex = None
        for attempt in range(max_attemps):
            try:
                return func(self, *args, **kwargs)
                break

            except errors.AutoReconnect as ex:
                LOG.warning(
                    _LW(u'Caught AutoReconnect, retrying the '
                        'call to {0}').format(func))

                last_ex = ex
                time.sleep(sleep_sec * (2**attempt))
        else:
            LOG.error(
                _LE(u'Caught AutoReconnect, maximum attempts '
                    'to {0} exceeded.').format(func))

            raise last_ex
示例#4
0
文件: bootstrap.py 项目: therve/zaqar
    def transport(self):
        transport_name = self.driver_conf.transport
        LOG.debug(u'Loading transport driver: %s', transport_name)

        if transport_name == consts.TRANSPORT_WEBSOCKET:
            args = [self.conf, self.api, self.cache]
        else:
            args = [
                self.conf,
                self.storage,
                self.cache,
                self.control,
            ]

        try:
            mgr = driver.DriverManager('zaqar.transport',
                                       transport_name,
                                       invoke_on_load=True,
                                       invoke_args=args)
            return mgr.driver
        except RuntimeError as exc:
            LOG.exception(exc)
            LOG.error(_LE(u'Failed to load transport driver zaqar.transport.'
                          u'%(driver)s with args %(args)s'),
                      {'driver': transport_name, 'args': args})
            raise errors.InvalidDriver(exc)
示例#5
0
    def _migrate_up(self, engine, version, with_data=False):
        """migrate up to a new version of the db.

        We allow for data insertion and post checks at every
        migration version with special _pre_upgrade_### and
        _check_### functions in the main test.
        """
        # NOTE(sdague): try block is here because it's impossible to debug
        # where a failed data migration happens otherwise
        check_version = version
        try:
            if with_data:
                data = None
                pre_upgrade = getattr(self, "_pre_upgrade_%s" % check_version,
                                      None)
                if pre_upgrade:
                    data = pre_upgrade(engine)
            self._migrate(engine, version, 'upgrade')
            self.assertEqual(version, self._get_version_from_db(engine))
            if with_data:
                check = getattr(self, "_check_%s" % check_version, None)
                if check:
                    check(engine, data)
        except Exception:
            LOG.error(
                _LE("Failed to migrate to version {version} on engine "
                    "{engine}").format(version=version, engine=engine))
            raise
示例#6
0
 def post(self, queue_name, messages, client_uuid, project=None):
     """Send messages to the subscribers."""
     if self.subscription_controller:
         if not isinstance(self.subscription_controller,
                           pooling.SubscriptionController):
             marker = None
             while True:
                 subscribers = self.subscription_controller.list(
                     queue_name, project, marker=marker)
                 for sub in next(subscribers):
                     LOG.debug("Notifying subscriber %r" % (sub,))
                     s_type = urllib_parse.urlparse(
                         sub['subscriber']).scheme
                     # If the subscriber doesn't contain 'confirmed', it
                     # means that this kind of subscriber was created before
                     # the confirm feature be introduced into Zaqar. We
                     # should allow them be subscribed.
                     if (self.require_confirmation and
                             not sub.get('confirmed', True)):
                         LOG.info(_LI('The subscriber %s is not '
                                      'confirmed.'), sub['subscriber'])
                         continue
                     for msg in messages:
                         msg['Message_Type'] = MessageType.Notification.name
                     self._execute(s_type, sub, messages)
                 marker = next(subscribers)
                 if not marker:
                     break
     else:
         LOG.error(_LE('Failed to get subscription controller.'))
示例#7
0
 def post(self, queue_name, messages, client_uuid, project=None):
     """Send messages to the subscribers."""
     if self.subscription_controller:
         if not isinstance(self.subscription_controller,
                           pooling.SubscriptionController):
             marker = None
             while True:
                 subscribers = self.subscription_controller.list(
                     queue_name, project, marker=marker)
                 for sub in next(subscribers):
                     LOG.debug("Notifying subscriber %r" % (sub, ))
                     s_type = urllib_parse.urlparse(
                         sub['subscriber']).scheme
                     # If the subscriber doesn't contain 'confirmed', it
                     # means that this kind of subscriber was created before
                     # the confirm feature be introduced into Zaqar. We
                     # should allow them be subscribed.
                     if (self.require_confirmation
                             and not sub.get('confirmed', True)):
                         LOG.info(
                             _LI('The subscriber %s is not '
                                 'confirmed.'), sub['subscriber'])
                         continue
                     for msg in messages:
                         msg['Message_Type'] = MessageType.Notification.name
                     self._execute(s_type, sub, messages)
                 marker = next(subscribers)
                 if not marker:
                     break
     else:
         LOG.error(_LE('Failed to get subscription controller.'))
示例#8
0
def load_storage_driver(conf,
                        cache,
                        storage_type=None,
                        control_mode=False,
                        control_driver=None):
    """Loads a storage driver and returns it.

    The driver's initializer will be passed conf and cache as
    its positional args.

    :param conf: Configuration instance to use for loading the
        driver. Must include a 'drivers' group.
    :param cache: Cache instance that the driver can (optionally)
        use to reduce latency for some operations.
    :param storage_type: The storage_type to load. If None, then
        the `drivers` option will be used.
    :param control_mode: (Default False). Determines which
        driver type to load; if False, the data driver is
        loaded. If True, the control driver is loaded.
    :param control_driver: (Default None). The control driver
        instance to pass to the storage driver. Needed to access
        the queue controller, mainly.
    """
    if control_mode:
        mode = 'control'
        storage_type = storage_type or conf['drivers'].management_store
    else:
        mode = 'data'
        storage_type = storage_type or conf['drivers'].message_store

    driver_type = 'zaqar.{0}.storage'.format(mode)

    _invoke_args = [conf, cache]
    if control_driver is not None:
        _invoke_args.append(control_driver)

    try:
        mgr = driver.DriverManager(driver_type,
                                   storage_type,
                                   invoke_on_load=True,
                                   invoke_args=_invoke_args)

        if conf.profiler.enabled:
            if ((mode == "control" and conf.profiler.trace_management_store)
                    or (mode == "data" and conf.profiler.trace_message_store)):
                trace_name = '{0}_{1}_driver'.format(storage_type, mode)
                return profiler.trace_cls(trace_name,
                                          trace_private=True)(mgr.driver)
        else:
            return mgr.driver

    except Exception as exc:
        LOG.error(
            _LE('Failed to load "{}" driver for "{}"').format(
                driver_type, storage_type))
        LOG.exception(exc)
        raise errors.InvalidDriver(exc)
示例#9
0
 def execute(self, subscription, messages, **kwargs):
     subscriber = urllib_parse.urlparse(subscription['subscriber'])
     params = urllib_parse.parse_qs(subscriber.query)
     params = dict((k.lower(), v) for k, v in params.items())
     conf_n = kwargs.get('conf').notification
     try:
         for message in messages:
             p = subprocess.Popen(conf_n.smtp_command.split(' '),
                                  stdin=subprocess.PIPE)
             # Send confirmation email to subscriber.
             if (message.get('Message_Type') ==
                     MessageType.SubscriptionConfirmation.name):
                 content = conf_n.subscription_confirmation_email_template
                 msg = self._make_confirmation_email(
                     content['body'], subscription, message, conf_n)
                 msg["to"] = subscriber.path
                 msg["from"] = content['sender']
                 msg["subject"] = content['topic']
             elif (message.get('Message_Type') ==
                   MessageType.UnsubscribeConfirmation.name):
                 content = conf_n.unsubscribe_confirmation_email_template
                 msg = self._make_confirmation_email(
                     content['body'], subscription, message, conf_n)
                 msg["to"] = subscriber.path
                 msg["from"] = content['sender']
                 msg["subject"] = content['topic']
             else:
                 # NOTE(Eva-i): Unfortunately this will add 'queue_name' key
                 # to our original messages(dicts) which will be later
                 # consumed in the storage controller. It seems safe though.
                 message['queue_name'] = subscription['source']
                 msg = text.MIMEText(json.dumps(message))
                 msg["to"] = subscriber.path
                 msg["from"] = subscription['options'].get('from', '')
                 subject_opt = subscription['options'].get('subject', '')
                 msg["subject"] = params.get('subject', subject_opt)
             p.communicate(msg.as_string())
             LOG.debug("Send mail successfully: %s", msg.as_string())
     except OSError as err:
         LOG.exception(
             _LE('Failed to create process for sendmail, '
                 'because %s.') % str(err))
     except Exception as exc:
         LOG.exception(_LE('Failed to send email because %s.') % str(exc))
示例#10
0
文件: mailto.py 项目: wenchma/zaqar
 def execute(self, subscription, messages, **kwargs):
     subscriber = urllib_parse.urlparse(subscription['subscriber'])
     params = urllib_parse.parse_qs(subscriber.query)
     params = dict((k.lower(), v) for k, v in params.items())
     conf = kwargs.get('conf')
     try:
         for message in messages:
             p = subprocess.Popen(conf.notification.smtp_command.split(' '),
                                  stdin=subprocess.PIPE)
             msg = text.MIMEText(json.dumps(message))
             msg["to"] = subscriber.path
             msg["from"] = subscription['options'].get('from', '')
             subject_opt = subscription['options'].get('subject', '')
             msg["subject"] = params.get('subject', subject_opt)
             p.communicate(msg.as_string())
     except OSError as err:
         LOG.error(_LE('Failed to create process for sendmail, '
                       'because %s') % str(err))
     except Exception as exc:
         LOG.exception(_LE('Failed to send email'))
         LOG.exception(exc)
示例#11
0
    def on_post(self, req, resp, project_id, queue_name):
        LOG.debug(
            u'Pre-Signed URL Creation for queue: %(queue)s, '
            u'project: %(project)s', {
                'queue': queue_name,
                'project': project_id
            })

        try:
            document = wsgi_utils.deserialize(req.stream, req.content_length)
        except ValueError as ex:
            LOG.debug(ex)
            raise wsgi_errors.HTTPBadRequestAPI(six.text_type(ex))

        diff = set(document.keys()) - _KNOWN_KEYS
        if diff:
            msg = six.text_type(_LE('Unknown keys: %s') % diff)
            raise wsgi_errors.HTTPBadRequestAPI(msg)

        key = self._conf.signed_url.secret_key
        paths = document.pop('paths', None)
        if not paths:
            paths = [os.path.join(req.path[:-6], 'messages')]
        else:
            diff = set(paths) - _VALID_PATHS
            if diff:
                msg = six.text_type(_LE('Invalid paths: %s') % diff)
                raise wsgi_errors.HTTPBadRequestAPI(msg)
            paths = [os.path.join(req.path[:-6], path) for path in paths]

        try:
            data = urls.create_signed_url(key,
                                          paths,
                                          project=project_id,
                                          **document)
        except ValueError as err:
            raise wsgi_errors.HTTPBadRequestAPI(str(err))

        resp.body = utils.to_json(data)
示例#12
0
文件: mailto.py 项目: ISCAS-VDI/zaqar
 def execute(self, subscription, messages, **kwargs):
     subscriber = urllib_parse.urlparse(subscription['subscriber'])
     params = urllib_parse.parse_qs(subscriber.query)
     params = dict((k.lower(), v) for k, v in params.items())
     conf = kwargs.get('conf')
     try:
         for message in messages:
             p = subprocess.Popen(conf.notification.smtp_command.split(' '),
                                  stdin=subprocess.PIPE)
             # NOTE(Eva-i): Unfortunately this will add 'queue_name' key to
             # our original messages(dicts) which will be later consumed in
             # the storage controller. It seems safe though.
             message['queue_name'] = subscription['source']
             msg = text.MIMEText(json.dumps(message))
             msg["to"] = subscriber.path
             msg["from"] = subscription['options'].get('from', '')
             subject_opt = subscription['options'].get('subject', '')
             msg["subject"] = params.get('subject', subject_opt)
             p.communicate(msg.as_string())
     except OSError as err:
         LOG.exception(_LE('Failed to create process for sendmail, '
                           'because %s.') % str(err))
     except Exception as exc:
         LOG.exception(_LE('Failed to send email because %s.') % str(exc))
示例#13
0
def load_storage_driver(conf, cache, storage_type=None,
                        control_mode=False, control_driver=None):
    """Loads a storage driver and returns it.

    The driver's initializer will be passed conf and cache as
    its positional args.

    :param conf: Configuration instance to use for loading the
        driver. Must include a 'drivers' group.
    :param cache: Cache instance that the driver can (optionally)
        use to reduce latency for some operations.
    :param storage_type: The storage_type to load. If None, then
        the `drivers` option will be used.
    :param control_mode: (Default False). Determines which
        driver type to load; if False, the data driver is
        loaded. If True, the control driver is loaded.
    :param control_driver: (Default None). The control driver
        instance to pass to the storage driver. Needed to access
        the queue controller, mainly.
    """

    if control_mode:
        mode = 'control'
        storage_type = storage_type or conf['drivers'].management_store
    else:
        mode = 'data'
        storage_type = storage_type or conf['drivers'].message_store

    driver_type = 'zaqar.{0}.storage'.format(mode)

    _invoke_args = [conf, cache]
    if control_driver is not None:
        _invoke_args.append(control_driver)

    try:
        mgr = driver.DriverManager(driver_type,
                                   storage_type,
                                   invoke_on_load=True,
                                   invoke_args=_invoke_args)

        return mgr.driver

    except Exception as exc:
        LOG.error(_LE('Failed to load "{}" driver for "{}"').format(
            driver_type, storage_type))
        LOG.exception(exc)
        raise errors.InvalidDriver(exc)
示例#14
0
    def post(self, queue_name, messages, client_uuid, project=None):
        """Send messages to the subscribers."""
        if (self.subscription_controller and
            not isinstance(self.subscription_controller,
                           pooling.SubscriptionController)):
            subscribers = self.subscription_controller.list(queue_name,
                                                            project)

            for sub in next(subscribers):
                s_type = urllib_parse.urlparse(sub['subscriber']).scheme
                data_driver = self.subscription_controller.driver
                mgr = driver.DriverManager('zaqar.notification.tasks',
                                           s_type,
                                           invoke_on_load=True)
                self.executor.submit(mgr.driver.execute, sub, messages,
                                     conf=data_driver.conf)
        else:
            LOG.error(_LE('Failed to get subscription controller.'))
示例#15
0
    def send_confirm_notification(self, queue, subscription, conf,
                                  project=None, expires=None,
                                  api_version=None):
        key = conf.signed_url.secret_key
        if not key:
            LOG.error(_LE("Can't send confirm notification due to the value of"
                          " secret_key option is None"))
            return
        url = "/%s/queues/%s/subscriptions/%s/confirm" % (api_version, queue,
                                                          subscription['id'])
        pre_url = urls.create_signed_url(key, [url], project=project,
                                         expires=expires, methods=['PUT'])
        message_type = MessageType.SubscriptionConfirmation.name

        messages = {}
        endpoint_dict = auth.get_public_endpoint()
        if endpoint_dict:
            wsgi_endpoint = endpoint_dict.get('zaqar', None)
            if wsgi_endpoint:
                wsgi_subscribe_url = urllib_parse.urljoin(
                    wsgi_endpoint, url)
                messages['WSGISubscribeURL'] = wsgi_subscribe_url
            websocket_endpoint = endpoint_dict.get('zaqar-websocket', None)
            if websocket_endpoint:
                websocket_subscribe_url = urllib_parse.urljoin(
                    websocket_endpoint, url)
                messages['WebSocketSubscribeURL'] = websocket_subscribe_url
        messages.update({'Message_Type': message_type,
                         'Message': 'You have chosen to subscribe to the '
                                    'queue: %s' % queue,
                         'URL-Signature': pre_url['signature'],
                         'URL-Methods': pre_url['methods'][0],
                         'URL-Paths': pre_url['paths'][0],
                         'X-Project-ID': pre_url['project'],
                         'URL-Expires': pre_url['expires'],
                         'SubscribeBody': {'confirmed': True},
                         'UnsubscribeBody': {'confirmed': False}})
        s_type = urllib_parse.urlparse(subscription['subscriber']).scheme
        LOG.info(_LI('Begin to send %(type)s confirm notification. The request'
                     'body is %(messages)s'),
                 {'type': s_type, 'messages': messages})

        self._execute(s_type, subscription, [messages], conf)
示例#16
0
 def execute(self, subscription, messages, headers=None, **kwargs):
     if headers is None:
         headers = {'Content-Type': 'application/json'}
     headers.update(subscription['options'].get('post_headers', {}))
     try:
         for msg in messages:
             # NOTE(Eva-i): Unfortunately this will add 'queue_name' key to
             # our original messages(dicts) which will be later consumed in
             # the storage controller. It seems safe though.
             msg['queue_name'] = subscription['source']
             if 'post_data' in subscription['options']:
                 data = subscription['options']['post_data']
                 data = data.replace('"$zaqar_message$"', json.dumps(msg))
             else:
                 data = json.dumps(msg)
             requests.post(subscription['subscriber'],
                           data=data,
                           headers=headers)
     except Exception as e:
         LOG.exception(_LE('webhook task got exception: %s.') % str(e))
示例#17
0
 def execute(self, subscription, messages, headers=None, **kwargs):
     if headers is None:
         headers = {'Content-Type': 'application/json'}
     headers.update(subscription['options'].get('post_headers', {}))
     try:
         for msg in messages:
             # NOTE(Eva-i): Unfortunately this will add 'queue_name' key to
             # our original messages(dicts) which will be later consumed in
             # the storage controller. It seems safe though.
             msg['queue_name'] = subscription['source']
             if 'post_data' in subscription['options']:
                 data = subscription['options']['post_data']
                 data = data.replace('"$zaqar_message$"', json.dumps(msg))
             else:
                 data = json.dumps(msg)
             requests.post(subscription['subscriber'],
                           data=data,
                           headers=headers)
     except Exception as e:
         LOG.exception(_LE('webhook task got exception: %s.') % str(e))
示例#18
0
    def wrapper(self, *args, **kwargs):
        # TODO(prashanthr_) : Try to reuse this utility. Violates DRY
        # Can pass config parameters into the decorator and create a
        # storage level utility.

        max_attemps = self.driver.redis_conf.max_reconnect_attempts
        sleep_sec = self.driver.redis_conf.reconnect_sleep

        for attempt in range(max_attemps):
            try:
                return func(self, *args, **kwargs)

            except redis.exceptions.ConnectionError:
                # NOTE(kgriffs): redis-py will retry once itself,
                # but if the command cannot be sent the second time after
                # disconnecting and reconnecting, the error is raised
                # and we will catch it here.
                #
                # NOTE(kgriffs): When using a sentinel, if a master fails
                # the initial retry will gracefully fail over to the
                # new master if the sentinel failover delay is low enough;
                # if the delay is too long, then redis-py will get a
                # MasterNotFoundError (a subclass of ConnectionError) on
                # it's retry, which will then just get raised and caught
                # here, in which case we will keep retrying until the
                # sentinel completes the failover and stops raising
                # MasterNotFoundError.

                ex = sys.exc_info()[1]
                LOG.warning(
                    _LW(u'Caught ConnectionError, retrying the '
                        'call to {0}').format(func))

                time.sleep(sleep_sec * (2**attempt))
        else:
            LOG.error(
                _LE(u'Caught ConnectionError, maximum attempts '
                    'to {0} exceeded.').format(func))
            raise ex
示例#19
0
文件: utils.py 项目: AvnishPal/zaqar
    def wrapper(self, *args, **kwargs):
        # TODO(kgriffs): Figure out a way to not have to rely on the
        # presence of `mongodb_conf`
        max_attemps = self.driver.mongodb_conf.max_reconnect_attempts
        sleep_sec = self.driver.mongodb_conf.reconnect_sleep

        last_ex = None
        for attempt in range(max_attemps):
            try:
                return func(self, *args, **kwargs)
                break

            except errors.AutoReconnect as ex:
                LOG.warning(_LW(u'Caught AutoReconnect, retrying the '
                                'call to {0}').format(func))

                last_ex = ex
                time.sleep(sleep_sec * (2 ** attempt))
        else:
            LOG.error(_LE(u'Caught AutoReconnect, maximum attempts '
                          'to {0} exceeded.').format(func))

            raise last_ex
示例#20
0
文件: utils.py 项目: ISCAS-VDI/zaqar
    def wrapper(self, *args, **kwargs):
        # TODO(prashanthr_) : Try to reuse this utility. Violates DRY
        # Can pass config parameters into the decorator and create a
        # storage level utility.

        max_attemps = self.driver.redis_conf.max_reconnect_attempts
        sleep_sec = self.driver.redis_conf.reconnect_sleep

        for attempt in range(max_attemps):
            try:
                return func(self, *args, **kwargs)

            except redis.exceptions.ConnectionError:
                # NOTE(kgriffs): redis-py will retry once itself,
                # but if the command cannot be sent the second time after
                # disconnecting and reconnecting, the error is raised
                # and we will catch it here.
                #
                # NOTE(kgriffs): When using a sentinel, if a master fails
                # the initial retry will gracefully fail over to the
                # new master if the sentinel failover delay is low enough;
                # if the delay is too long, then redis-py will get a
                # MasterNotFoundError (a subclass of ConnectionError) on
                # it's retry, which will then just get raised and caught
                # here, in which case we will keep retrying until the
                # sentinel completes the failover and stops raising
                # MasterNotFoundError.

                ex = sys.exc_info()[1]
                LOG.warning(_LW(u'Caught ConnectionError, retrying the '
                                'call to {0}').format(func))

                time.sleep(sleep_sec * (2 ** attempt))
        else:
            LOG.error(_LE(u'Caught ConnectionError, maximum attempts '
                          'to {0} exceeded.').format(func))
            raise ex
示例#21
0
    def send_confirm_notification(self,
                                  queue,
                                  subscription,
                                  conf,
                                  project=None,
                                  expires=None,
                                  api_version=None,
                                  is_unsubscribed=False):
        # NOTE(flwang): If the confirmation feature isn't enabled, just do
        # nothing. Here we're getting the require_confirmation from conf
        # object instead of using self.require_confirmation, because the
        # variable from self object really depends on the kwargs when
        # initializing the NotifierDriver object. See bug 1655812 for more
        # information.
        if not conf.notification.require_confirmation:
            return

        key = conf.signed_url.secret_key
        if not key:
            LOG.error(
                _LE("Can't send confirm notification due to the value of"
                    " secret_key option is None"))
            return
        url = "/%s/queues/%s/subscriptions/%s/confirm" % (api_version, queue,
                                                          subscription['id'])
        pre_url = urls.create_signed_url(key, [url],
                                         project=project,
                                         expires=expires,
                                         methods=['PUT'])
        message = None
        if is_unsubscribed:
            message_type = MessageType.UnsubscribeConfirmation.name
            message = ('You have unsubscribed successfully to the queue: %s, '
                       'you can resubscribe it by using confirmed=True.' %
                       queue)
        else:
            message_type = MessageType.SubscriptionConfirmation.name
            message = 'You have chosen to subscribe to the queue: %s' % queue

        messages = {}
        endpoint_dict = auth.get_public_endpoint()
        if endpoint_dict:
            wsgi_endpoint = endpoint_dict.get('zaqar', None)
            if wsgi_endpoint:
                wsgi_subscribe_url = urllib_parse.urljoin(wsgi_endpoint, url)
                messages['WSGISubscribeURL'] = wsgi_subscribe_url
            websocket_endpoint = endpoint_dict.get('zaqar-websocket', None)
            if websocket_endpoint:
                websocket_subscribe_url = urllib_parse.urljoin(
                    websocket_endpoint, url)
                messages['WebSocketSubscribeURL'] = websocket_subscribe_url
        messages.update({
            'Message_Type': message_type,
            'Message': message,
            'URL-Signature': pre_url['signature'],
            'URL-Methods': pre_url['methods'][0],
            'URL-Paths': pre_url['paths'][0],
            'X-Project-ID': pre_url['project'],
            'URL-Expires': pre_url['expires'],
            'SubscribeBody': {
                'confirmed': True
            },
            'UnsubscribeBody': {
                'confirmed': False
            }
        })
        s_type = urllib_parse.urlparse(subscription['subscriber']).scheme
        LOG.info(
            _LI('Begin to send %(type)s confirm/unsubscribe notification.'
                ' The request body is %(messages)s'), {
                    'type': s_type,
                    'messages': messages
                })

        self._execute(s_type, subscription, [messages], conf)
示例#22
0
文件: urls.py 项目: AvnishPal/zaqar
def create_signed_url(key, paths, project=None, expires=None, methods=None):
    """Creates a signed url for the specified path

    This function will create a pre-signed URL for `path` using the
    specified `options` or the default ones. The signature will be the
    hex value of the hmac created using `key`

    :param key: A string to use as a `key` for the hmac generation.
    :param paths: A list of strings representing URL paths.
    :param project: (Default None) The ID of the project this URL belongs to.
    :param methods: (Default ['GET']) A list of methods that will be
        supported by the generated URL.
    :params expires: (Default time() + 86400) The expiration date for
        the generated URL.
    """

    methods = methods or ['GET']

    if key is None:
        raise ValueError(_LE('The `key` can\'t be None'))

    if not isinstance(paths, list) or not paths:
        raise ValueError(_LE('`paths` must be a non-empty list'))

    if not isinstance(methods, list):
        raise ValueError(_LE('`methods` should be a list'))

    # NOTE(flaper87): The default expiration time is 1day
    # Evaluate whether this should be configurable. We may
    # also want to have a "maximum" expiration time. Food
    # for thoughts.
    if expires is not None:
        # NOTE(flaper87): Verify if the format is correct
        # and normalize the value to UTC.
        check_expires = None
        try:
            check_expires = int(expires)
        except ValueError:
            pass
        if check_expires:
            raise ValueError(_LE('`expires` should be date format, '
                                 'for example 2016-01-01T00:00:00, '
                                 'not integer value: %s') % check_expires)
        parsed = timeutils.parse_isotime(expires)
        expires = timeutils.normalize_time(parsed)
    else:
        delta = datetime.timedelta(days=1)
        expires = timeutils.utcnow() + delta

    if expires <= timeutils.utcnow():
        raise ValueError(_LE('`expires` is lower than the current time'))

    methods = sorted(methods)
    paths = sorted(paths)
    expires_str = expires.strftime(_DATE_FORMAT)
    hmac_body = six.b(r'%(paths)s\n%(methods)s\n%(project)s\n%(expires)s' %
                      {'paths': ','.join(paths), 'methods': ','.join(methods),
                       'project': project, 'expires': expires_str})

    if not isinstance(key, six.binary_type):
        key = six.binary_type(key.encode('utf-8'))

    return {'paths': paths,
            'methods': methods,
            'project': project,
            'expires': expires_str,
            'signature': hmac.new(key, hmac_body, hashlib.sha256).hexdigest()}
示例#23
0
def create_signed_url(key, paths, project=None, expires=None, methods=None):
    """Creates a signed url for the specified path

    This function will create a pre-signed URL for `path` using the
    specified `options` or the default ones. The signature will be the
    hex value of the hmac created using `key`

    :param key: A string to use as a `key` for the hmac generation.
    :param paths: A list of strings representing URL paths.
    :param project: (Default None) The ID of the project this URL belongs to.
    :param methods: (Default ['GET']) A list of methods that will be
        supported by the generated URL.
    :params expires: (Default time() + 86400) The expiration date for
        the generated URL.
    """

    methods = methods or ['GET']

    if key is None:
        raise ValueError(_LE('The `key` can\'t be None'))

    if not isinstance(paths, list) or not paths:
        raise ValueError(_LE('`paths` must be a non-empty list'))

    if not isinstance(methods, list):
        raise ValueError(_LE('`methods` should be a list'))

    # NOTE(flaper87): The default expiration time is 1day
    # Evaluate whether this should be configurable. We may
    # also want to have a "maximum" expiration time. Food
    # for thoughts.
    if expires is not None:
        # NOTE(flaper87): Verify if the format is correct
        # and normalize the value to UTC.
        check_expires = None
        try:
            check_expires = int(expires)
        except ValueError:
            pass
        if check_expires:
            raise ValueError(
                _LE('`expires` should be date format, '
                    'for example 2016-01-01T00:00:00, '
                    'not integer value: %s') % check_expires)
        parsed = timeutils.parse_isotime(expires)
        expires = timeutils.normalize_time(parsed)
    else:
        delta = datetime.timedelta(days=1)
        expires = timeutils.utcnow() + delta

    if expires <= timeutils.utcnow():
        raise ValueError(_LE('`expires` is lower than the current time'))

    methods = sorted(methods)
    paths = sorted(paths)
    expires_str = expires.strftime(_DATE_FORMAT)
    hmac_body = six.b(
        r'%(paths)s\n%(methods)s\n%(project)s\n%(expires)s' % {
            'paths': ','.join(paths),
            'methods': ','.join(methods),
            'project': project,
            'expires': expires_str
        })

    if not isinstance(key, six.binary_type):
        key = six.binary_type(key.encode('utf-8'))

    return {
        'paths': paths,
        'methods': methods,
        'project': project,
        'expires': expires_str,
        'signature': hmac.new(key, hmac_body, hashlib.sha256).hexdigest()
    }
示例#24
0
    def send_confirm_notification(self,
                                  queue,
                                  subscription,
                                  conf,
                                  project=None,
                                  expires=None,
                                  api_version=None):
        key = conf.signed_url.secret_key
        if not key:
            LOG.error(
                _LE("Can't send confirm notification due to the value of"
                    " secret_key option is None"))
            return
        url = "/%s/queues/%s/subscriptions/%s/confirm" % (api_version, queue,
                                                          subscription['id'])
        pre_url = urls.create_signed_url(key, [url],
                                         project=project,
                                         expires=expires,
                                         methods=['PUT'])
        message_type = MessageType.SubscriptionConfirmation.name

        messages = {}
        endpoint_dict = auth.get_public_endpoint()
        if endpoint_dict:
            wsgi_endpoint = endpoint_dict.get('zaqar', None)
            if wsgi_endpoint:
                wsgi_subscribe_url = urllib_parse.urljoin(wsgi_endpoint, url)
                messages['WSGISubscribeURL'] = wsgi_subscribe_url
            websocket_endpoint = endpoint_dict.get('zaqar-websocket', None)
            if websocket_endpoint:
                websocket_subscribe_url = urllib_parse.urljoin(
                    websocket_endpoint, url)
                messages['WebSocketSubscribeURL'] = websocket_subscribe_url
        messages.update({
            'Message_Type':
            message_type,
            'Message':
            'You have chosen to subscribe to the '
            'queue: %s' % queue,
            'URL-Signature':
            pre_url['signature'],
            'URL-Methods':
            pre_url['methods'][0],
            'URL-Paths':
            pre_url['paths'][0],
            'X-Project-ID':
            pre_url['project'],
            'URL-Expires':
            pre_url['expires'],
            'SubscribeBody': {
                'confirmed': True
            },
            'UnsubscribeBody': {
                'confirmed': False
            }
        })
        s_type = urllib_parse.urlparse(subscription['subscriber']).scheme
        LOG.info(
            _LI('Begin to send %(type)s confirm notification. The request'
                'body is %(messages)s'), {
                    'type': s_type,
                    'messages': messages
                })

        self._execute(s_type, subscription, [messages], conf)