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)
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)
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
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)
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
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()
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)
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)
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()
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)
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)