Example #1
0
    def modify_state(self, modifier_callable, *args, **kwargs):
        """
        see :meth:`otter.models.interface.IScalingGroup.modify_state`
        """
        def _write_state(new_state):
            assert (new_state.tenant_id == self.tenant_id and
                    new_state.group_id == self.uuid)
            params = {
                'tenantId': new_state.tenant_id,
                'groupId': new_state.group_id,
                'active': serialize_json_data(new_state.active, 1),
                'pending': serialize_json_data(new_state.pending, 1),
                'paused': new_state.paused,
                'groupTouched': new_state.group_touched,
                'policyTouched': serialize_json_data(new_state.policy_touched, 1)
            }
            return self.connection.execute(_cql_update_group_state, params,
                                           get_consistency_level('update', 'state'))

        def _modify_state():
            d = self.view_state()
            d.addCallback(lambda state: modifier_callable(self, state, *args, **kwargs))
            return d.addCallback(_write_state)
        lock = BasicLock(self.connection, LOCK_TABLE_NAME, self.uuid)
        return with_lock(lock, _modify_state)
Example #2
0
    def modify_state(self, modifier_callable, *args, **kwargs):
        """
        see :meth:`otter.models.interface.IScalingGroup.modify_state`
        """
        log = self.log.bind(system='CassScalingGroup.modify_state')

        def _write_state(new_state):
            assert (new_state.tenant_id == self.tenant_id and
                    new_state.group_id == self.uuid)
            params = {
                'tenantId': new_state.tenant_id,
                'groupId': new_state.group_id,
                'active': serialize_json_data(new_state.active, 1),
                'pending': serialize_json_data(new_state.pending, 1),
                'paused': new_state.paused,
                'groupTouched': new_state.group_touched,
                'policyTouched': serialize_json_data(new_state.policy_touched, 1)
            }
            return self.connection.execute(_cql_insert_group_state.format(cf=self.group_table),
                                           params, get_consistency_level('update', 'state'))

        def _modify_state():
            d = self.view_state()
            d.addCallback(lambda state: modifier_callable(self, state, *args, **kwargs))
            return d.addCallback(_write_state)

        lock = BasicLock(self.connection, LOCK_TABLE_NAME, self.uuid,
                         max_retry=5, retry_wait=random.uniform(3, 5),
                         log=log.bind(category='locking'))

        return with_lock(lock, _modify_state)
Example #3
0
 def _do_check():
     d = with_lock(self.lock, self.fetch_and_process, batchsize)
     d.addCallback(check_for_more)
     d.addErrback(ignore_and_log, BusyLockError, self.log,
                  "Couldn't get lock to process events")
     d.addErrback(self.log.err)
     return d
Example #4
0
    def modify_state(self, modifier_callable, *args, **kwargs):
        """
        see :meth:`otter.models.interface.IScalingGroup.modify_state`
        """
        def _write_state(new_state):
            assert (new_state.tenant_id == self.tenant_id
                    and new_state.group_id == self.uuid)
            params = {
                'tenantId': new_state.tenant_id,
                'groupId': new_state.group_id,
                'active': serialize_json_data(new_state.active, 1),
                'pending': serialize_json_data(new_state.pending, 1),
                'paused': new_state.paused,
                'groupTouched': new_state.group_touched,
                'policyTouched': serialize_json_data(new_state.policy_touched,
                                                     1)
            }
            return self.connection.execute(
                _cql_insert_group_state.format(cf=self.group_table), params,
                get_consistency_level('update', 'state'))

        def _modify_state():
            d = self.view_state()
            d.addCallback(
                lambda state: modifier_callable(self, state, *args, **kwargs))
            return d.addCallback(_write_state)

        lock = BasicLock(self.connection,
                         LOCK_TABLE_NAME,
                         self.uuid,
                         max_retry=5,
                         retry_wait=random.uniform(3, 5))
        return with_lock(lock, _modify_state)
Example #5
0
 def _do_check():
     lock_log = self.log.bind(category='locking')
     lock = BasicLock(self.slv_client, self.lock_table, 'schedule', max_retry=0,
                      log=lock_log)
     d = with_lock(lock, self.fetch_and_process, batchsize)
     d.addCallback(check_for_more)
     d.addErrback(ignore_and_log, BusyLockError, lock_log,
                  "Couldn't get lock to process events")
     d.addErrback(self.log.err)
     return d
Example #6
0
    def test_with_lock(self):
        """
        Acquire the lock, run the function, and release the lock.
        """
        lock_uuid = uuid.uuid1()

        def _func():
            return defer.succeed('Success')

        lock = self.BasicLock(None, 'lock', lock_uuid)
        d = with_lock(lock, _func)

        result = self.successResultOf(d)
        self.assertEqual(result, 'Success')
        self.lock.acquire.assert_called_once_with()
        self.lock.release.assert_called_once_with()
Example #7
0
    def test_with_lock(self):
        """
        Acquire the lock, run the function, and release the lock.
        """
        lock_uuid = uuid.uuid1()

        def _func():
            return defer.succeed('Success')

        lock = self.BasicLock(None, 'lock', lock_uuid)
        d = with_lock(lock, _func)

        result = self.successResultOf(d)
        self.assertEqual(result, 'Success')
        self.lock.acquire.assert_called_once_with()
        self.lock.release.assert_called_once_with()
Example #8
0
    def delete_group(self):
        """
        see :meth:`otter.models.interface.IScalingGroup.delete_group`
        """
        log = self.log.bind(system='CassScalingGroup.delete_group')

        # Events can only be deleted by policy id, since that and trigger are
        # the only parts of the compound key
        def _delete_everything(policies):
            params = {
                'tenantId': self.tenant_id,
                'groupId': self.uuid
            }
            queries = [
                _cql_delete_all_in_group.format(cf=table) for table in
                (self.group_table, self.policies_table, self.webhooks_table)]

            if len(policies) > 0:
                events_query, events_params = _delete_many_query_and_params(
                    self.event_table, '"policyId"', [p['id'] for p in policies])
                queries.append(events_query)
                params.update(events_params)

            b = Batch(queries, params,
                      consistency=get_consistency_level('delete', 'group'))

            return b.execute(self.connection)

        def _maybe_delete(state):
            if len(state.active) + len(state.pending) > 0:
                raise GroupNotEmptyError(self.tenant_id, self.uuid)

            d = self._naive_list_policies()
            d.addCallback(_delete_everything)
            return d

        def _delete_group():
            d = self.view_state()
            d.addCallback(_maybe_delete)
            return d

        lock = BasicLock(self.connection, LOCK_TABLE_NAME, self.uuid,
                         max_retry=5, retry_wait=random.uniform(3, 5),
                         log=log.bind(category='locking'))

        return with_lock(lock, _delete_group)
Example #9
0
    def delete_group(self):
        """
        see :meth:`otter.models.interface.IScalingGroup.delete_group`
        """

        # Events can only be deleted by policy id, since that and trigger are
        # the only parts of the compound key
        def _delete_everything(policies):
            params = {'tenantId': self.tenant_id, 'groupId': self.uuid}
            queries = [
                _cql_delete_all_in_group.format(cf=table)
                for table in (self.group_table, self.policies_table,
                              self.webhooks_table)
            ]

            if len(policies) > 0:
                events_query, events_params = _delete_many_query_and_params(
                    self.event_table, '"policyId"', policies.keys())
                queries.append(events_query)
                params.update(events_params)

            b = Batch(queries,
                      params,
                      consistency=get_consistency_level('delete', 'group'))

            return b.execute(self.connection)

        def _maybe_delete(state):
            if len(state.active) + len(state.pending) > 0:
                raise GroupNotEmptyError(self.tenant_id, self.uuid)

            d = self._naive_list_policies()
            d.addCallback(_delete_everything)
            return d

        def _delete_group():
            d = self.view_state()
            d.addCallback(_maybe_delete)
            return d

        lock = BasicLock(self.connection,
                         LOCK_TABLE_NAME,
                         self.uuid,
                         max_retry=5,
                         retry_wait=random.uniform(3, 5))
        return with_lock(lock, _delete_group)
Example #10
0
    def test_with_lock_func_errors(self):
        """
        If the func raises an error, the lock is released and the error passsed on.
        """
        lock_uuid = uuid.uuid1()

        def _func():
            return defer.fail(TypeError('The samoflange is broken.'))

        lock = self.BasicLock(None, 'lock', lock_uuid)
        d = with_lock(lock, _func)

        result = self.failureResultOf(d)
        self.assertTrue(result.check(TypeError))
        self.assertEqual(result.getErrorMessage(), 'The samoflange is broken.')

        self.lock.acquire.assert_called_once_with()
        self.lock.release.assert_called_once_with()
Example #11
0
    def test_with_lock_func_errors(self):
        """
        If the func raises an error, the lock is released and the error passsed on.
        """
        lock_uuid = uuid.uuid1()

        def _func():
            return defer.fail(TypeError('The samoflange is broken.'))

        lock = self.BasicLock(None, 'lock', lock_uuid)
        d = with_lock(lock, _func)

        result = self.failureResultOf(d)
        self.assertTrue(result.check(TypeError))
        self.assertEqual(result.getErrorMessage(), 'The samoflange is broken.')

        self.lock.acquire.assert_called_once_with()
        self.lock.release.assert_called_once_with()
Example #12
0
    def delete_group(self):
        """
        see :meth:`otter.models.interface.IScalingGroup.delete_group`
        """
        # Events can only be deleted by policy id, since that and trigger are
        # the only parts of the compound key
        def _delete_everything(policies):
            params = {
                'tenantId': self.tenant_id,
                'groupId': self.uuid
            }
            queries = [
                _cql_delete_all_in_group.format(cf=table) for table in
                (self.config_table, self.launch_table, self.policies_table,
                 self.webhooks_table, self.state_table)]

            if len(policies) > 0:
                events_query, events_params = _delete_events_query_and_params(
                    policies.keys(), self.event_table)
                queries.append(events_query.rstrip(';'))
                params.update(events_params)

            b = Batch(queries, params,
                      consistency=get_consistency_level('delete', 'group'))

            return b.execute(self.connection)

        def _maybe_delete(state):
            if len(state.active) + len(state.pending) > 0:
                raise GroupNotEmptyError(self.tenant_id, self.uuid)

            d = self._naive_list_policies()
            d.addCallback(_delete_everything)
            return d

        def _delete_group():
            d = self.view_state()
            d.addCallback(_maybe_delete)
            return d

        lock = BasicLock(self.connection, LOCK_TABLE_NAME, self.uuid)
        return with_lock(lock, _delete_group)
Example #13
0
    def test_with_lock_not_acquired(self):
        """
        Raise an error if the lock isn't acquired.
        """
        def _side_effect(*args, **kwargs):
            return defer.fail(BusyLockError('', ''))
        self.lock.acquire.side_effect = _side_effect

        lock_uuid = uuid.uuid1()

        called = [False]

        def _func():
            called[0] = True
            return defer.succeed(None)

        lock = self.BasicLock(None, 'lock', lock_uuid)
        d = with_lock(lock, _func)

        result = self.failureResultOf(d)
        self.assertTrue(result.check(BusyLockError))
        self.assertFalse(called[0])
        self.assertEqual(self.lock.release.call_count, 0)
Example #14
0
    def test_with_lock_not_acquired(self):
        """
        Raise an error if the lock isn't acquired.
        """
        def _side_effect(*args, **kwargs):
            return defer.fail(BusyLockError('', ''))

        self.lock.acquire.side_effect = _side_effect

        lock_uuid = uuid.uuid1()

        called = [False]

        def _func():
            called[0] = True
            return defer.succeed(None)

        lock = self.BasicLock(None, 'lock', lock_uuid)
        d = with_lock(lock, _func)

        result = self.failureResultOf(d)
        self.assertTrue(result.check(BusyLockError))
        self.assertFalse(called[0])
        self.assertEqual(self.lock.release.call_count, 0)