Example #1
0
    def test_limit_update_retry(self, mock_dumps):
        limits = [
            mock.Mock(**{'dehydrate.return_value': 'limit1'}),
            mock.Mock(**{'dehydrate.return_value': 'limit2'}),
            mock.Mock(**{'dehydrate.return_value': 'limit3'}),
            mock.Mock(**{'dehydrate.return_value': 'limit4'}),
            mock.Mock(**{'dehydrate.return_value': 'limit5'}),
            mock.Mock(**{'dehydrate.return_value': 'limit6'}),
        ]
        pipe = mock.MagicMock(**{
            'zrange.return_value': [
                'limit2',
                'limit4',
                'limit6',
                'limit8',
            ],
            'execute.side_effect': [redis.WatchError, None],
        })
        pipe.__enter__.return_value = pipe
        pipe.__exit__.return_value = False
        db = mock.Mock(**{'pipeline.return_value': pipe})

        database.limit_update(db, 'limit_key', limits)
        for lim in limits:
            lim.dehydrate.assert_called_once_with()
        mock_dumps.assert_has_calls([
            mock.call('limit1'),
            mock.call('limit2'),
            mock.call('limit3'),
            mock.call('limit4'),
            mock.call('limit5'),
            mock.call('limit6'),
        ])
        db.pipeline.assert_called_once_with()
        pipe.assert_has_calls([
            mock.call.__enter__(),
            mock.call.watch('limit_key'),
            mock.call.zrange('limit_key', 0, -1),
            mock.call.multi(),
            mock.call.zrem('limit_key', 'limit8'),
            mock.call.zadd('limit_key', 10, 'limit1'),
            mock.call.zadd('limit_key', 20, 'limit2'),
            mock.call.zadd('limit_key', 30, 'limit3'),
            mock.call.zadd('limit_key', 40, 'limit4'),
            mock.call.zadd('limit_key', 50, 'limit5'),
            mock.call.zadd('limit_key', 60, 'limit6'),
            mock.call.execute(),
            mock.call.watch('limit_key'),
            mock.call.zrange('limit_key', 0, -1),
            mock.call.multi(),
            mock.call.zrem('limit_key', 'limit8'),
            mock.call.zadd('limit_key', 10, 'limit1'),
            mock.call.zadd('limit_key', 20, 'limit2'),
            mock.call.zadd('limit_key', 30, 'limit3'),
            mock.call.zadd('limit_key', 40, 'limit4'),
            mock.call.zadd('limit_key', 50, 'limit5'),
            mock.call.zadd('limit_key', 60, 'limit6'),
            mock.call.execute(),
            mock.call.__exit__(None, None, None),
        ])
Example #2
0
    def test_limit_update(self, mock_dumps):
        limits = [
            mock.Mock(**{'dehydrate.return_value': 'limit1'}),
            mock.Mock(**{'dehydrate.return_value': 'limit2'}),
            mock.Mock(**{'dehydrate.return_value': 'limit3'}),
            mock.Mock(**{'dehydrate.return_value': 'limit4'}),
            mock.Mock(**{'dehydrate.return_value': 'limit5'}),
            mock.Mock(**{'dehydrate.return_value': 'limit6'}),
        ]
        pipe = mock.MagicMock(**{
            'zrange.return_value': [
                'limit2',
                'limit4',
                'limit6',
                'limit8',
            ],
        })
        pipe.__enter__.return_value = pipe
        pipe.__exit__.return_value = False
        db = mock.Mock(**{'pipeline.return_value': pipe})

        database.limit_update(db, 'limit_key', limits)
        for lim in limits:
            lim.dehydrate.assert_called_once_with()
        mock_dumps.assert_has_calls([
            mock.call('limit1'),
            mock.call('limit2'),
            mock.call('limit3'),
            mock.call('limit4'),
            mock.call('limit5'),
            mock.call('limit6'),
        ])
        db.pipeline.assert_called_once_with()
        pipe.assert_has_calls([
            mock.call.__enter__(),
            mock.call.watch('limit_key'),
            mock.call.zrange('limit_key', 0, -1),
            mock.call.multi(),
            mock.call.zrem('limit_key', 'limit8'),
            mock.call.zadd('limit_key', 10, 'limit1'),
            mock.call.zadd('limit_key', 20, 'limit2'),
            mock.call.zadd('limit_key', 30, 'limit3'),
            mock.call.zadd('limit_key', 40, 'limit4'),
            mock.call.zadd('limit_key', 50, 'limit5'),
            mock.call.zadd('limit_key', 60, 'limit6'),
            mock.call.execute(),
            mock.call.__exit__(None, None, None),
        ])
Example #3
0
def setup_limits(conf_file,
                 limits_file,
                 do_reload=True,
                 dry_run=False,
                 debug=False):
    """
    Set up or update limits in the Redis database.

    :param conf_file: Name of the configuration file, for connecting
                      to the Redis database.
    :param limits_file: Name of the XML file describing the limits to
                        configure.
    :param do_reload: Controls reloading behavior.  If True (the
                      default), a reload command is issued.  If False,
                      no reload command is issued.  String values
                      result in a reload command of the given load
                      type, and integer or float values result in a
                      reload command of type 'spread' with the given
                      spread interval.
    :param dry_run: If True, no changes are made to the database.
                    Implies debug=True.
    :param debug: If True, debugging messages are emitted while
                  loading the limits and updating the database.
    """

    # If dry_run is set, default debug to True
    if dry_run:
        debug = True

    # Connect to the database...
    conf = config.Config(conf_file=conf_file)
    db = conf.get_database()
    limits_key = conf['control'].get('limits_key', 'limits')
    control_channel = conf['control'].get('channel', 'control')

    # Parse the limits file
    limits_tree = etree.parse(limits_file)

    # Now, we parse the limits XML file
    lims = []
    for idx, lim in enumerate(limits_tree.getroot()):
        # Skip tags we don't recognize
        if lim.tag != 'limit':
            warnings.warn("Unrecognized tag %r in limits file at index %d" %
                          (lim.tag, idx))
            continue

        # Construct the limit and add it to the list of limits
        try:
            lims.append(parse_limit_node(db, idx, lim))
        except Exception as exc:
            warnings.warn("Couldn't understand limit at index %d: %s" %
                          (idx, exc))
            continue

    # Now that we have the limits, let's install them
    if debug:
        print >> sys.stderr, "Installing the following limits:"
        for lim in lims:
            print >> sys.stderr, "  %r" % lim
    if not dry_run:
        database.limit_update(db, limits_key, lims)

    # Were we requested to reload the limits?
    if do_reload is False:
        return

    # OK, figure out what kind of reload to do
    params = []
    if do_reload is True:
        # Nothing to do; use default semantics
        pass
    elif (isinstance(do_reload, (int, long, float))
          or (isinstance(do_reload, basestring) and do_reload.isdigit())):
        params = ['spread', do_reload]
    else:
        params = [str(do_reload)]

    # Issue the reload command
    if debug:
        cmd = ['reload']
        cmd.extend(params)
        print >> sys.stderr, ("Issuing command: %s" %
                              ' '.join(str(c) for c in cmd))
    if not dry_run:
        database.command(db, control_channel, 'reload', *params)
Example #4
0
def setup_limits(conf_file, limits_file, do_reload=True, dry_run=False, debug=False):
    """
    Set up or update limits in the Redis database.

    :param conf_file: Name of the configuration file, for connecting
                      to the Redis database.
    :param limits_file: Name of the XML file describing the limits to
                        configure.
    :param do_reload: Controls reloading behavior.  If True (the
                      default), a reload command is issued.  If False,
                      no reload command is issued.  String values
                      result in a reload command of the given load
                      type, and integer or float values result in a
                      reload command of type 'spread' with the given
                      spread interval.
    :param dry_run: If True, no changes are made to the database.
                    Implies debug=True.
    :param debug: If True, debugging messages are emitted while
                  loading the limits and updating the database.
    """

    # If dry_run is set, default debug to True
    if dry_run:
        debug = True

    # Connect to the database...
    conf = config.Config(conf_file=conf_file)
    db = conf.get_database()
    limits_key = conf["control"].get("limits_key", "limits")
    control_channel = conf["control"].get("channel", "control")

    # Parse the limits file
    limits_tree = etree.parse(limits_file)

    # Now, we parse the limits XML file
    lims = []
    for idx, lim in enumerate(limits_tree.getroot()):
        # Skip tags we don't recognize
        if lim.tag != "limit":
            warnings.warn("Unrecognized tag %r in limits file at index %d" % (lim.tag, idx))
            continue

        # Construct the limit and add it to the list of limits
        try:
            lims.append(parse_limit_node(db, idx, lim))
        except Exception as exc:
            warnings.warn("Couldn't understand limit at index %d: %s" % (idx, exc))
            continue

    # Now that we have the limits, let's install them
    if debug:
        print >> sys.stderr, "Installing the following limits:"
        for lim in lims:
            print >> sys.stderr, "  %r" % lim
    if not dry_run:
        database.limit_update(db, limits_key, lims)

    # Were we requested to reload the limits?
    if do_reload is False:
        return

    # OK, figure out what kind of reload to do
    params = []
    if do_reload is True:
        # Nothing to do; use default semantics
        pass
    elif isinstance(do_reload, (int, long, float)) or (isinstance(do_reload, basestring) and do_reload.isdigit()):
        params = ["spread", do_reload]
    else:
        params = [str(do_reload)]

    # Issue the reload command
    if debug:
        cmd = ["reload"]
        cmd.extend(params)
        print >> sys.stderr, ("Issuing command: %s" % " ".join(str(c) for c in cmd))
    if not dry_run:
        database.command(db, control_channel, "reload", *params)