def get_project_limits(self, project_id, resource_names): """Get all the limits for given project a resource_name list We will raise ClaimExceedsLimit if no limit is found to ensure that all clients of this library react to this situation in the same way. :param project_id: :param resource_names: list of resource_name strings :return: list of (resource_name,limit) pairs :raises exception.ClaimExceedsLimit: if no limit is found """ # Using a list to preserver the resource_name order project_limits = [] missing_limits = [] for resource_name in resource_names: try: limit = self._get_limit(project_id, resource_name) project_limits.append((resource_name, limit)) except _LimitNotFound: missing_limits.append(resource_name) if len(missing_limits) > 0: over_limit_list = [ exception.OverLimitInfo(name, 0, 0, 0) for name in missing_limits ] raise exception.ProjectOverLimit(project_id, over_limit_list) return project_limits
def enforce_limits(project_id, limits, current_usage, deltas): """Check that proposed usage is not over given limits :param project_id: project being checked :param limits: list of (resource_name,limit) pairs :param current_usage: dict of resource name and current usage :param deltas: dict of resource name and proposed additional usage :raises exception.ClaimExceedsLimit: raise if over limit """ over_limit_list = [] for resource_name, limit in limits: if resource_name not in current_usage: msg = "unable to get current usage for %s" % resource_name raise ValueError(msg) current = int(current_usage[resource_name]) delta = int(deltas[resource_name]) proposed_usage_total = current + delta if proposed_usage_total > limit: over_limit_list.append( exception.OverLimitInfo(resource_name, limit, current, delta)) if len(over_limit_list) > 0: LOG.debug("hit limit for project: %s", over_limit_list) raise exception.ProjectOverLimit(project_id, over_limit_list)
def test_enforce_raises_on_missing_limit(self, mock_get_limits): mock_usage = mock.MagicMock() project_id = uuid.uuid4().hex deltas = {"a": 0, "b": 0} mock_get_limits.side_effect = exception.ProjectOverLimit( project_id, [exception.OverLimitInfo("a", 0, 0, 0)]) enforcer = limit._FlatEnforcer(mock_usage) self.assertRaises(exception.ProjectOverLimit, enforcer.enforce, project_id, deltas)
def test_enforce_num_instances_and_flavor_fails(self, mock_limit): mock_enforcer = mock.MagicMock() mock_limit.return_value = mock_enforcer over_limit_info_list = [ limit_exceptions.OverLimitInfo("class:VCPU", 12, 0, 20), limit_exceptions.OverLimitInfo("servers", 2, 1, 2) ] expected = limit_exceptions.ProjectOverLimit(uuids.project_id, over_limit_info_list) mock_enforcer.enforce.side_effect = expected # Verify that the oslo.limit ProjectOverLimit gets translated to a # TooManyInstances that the API knows how to handle e = self.assertRaises( exception.TooManyInstances, placement_limits.enforce_num_instances_and_flavor, self.context, uuids.project_id, self.flavor, True, 2, 4) self.assertEqual(str(expected), str(e)) self.assertEqual(3, mock_enforcer.enforce.call_count)
def test_enforce_num_instances_and_flavor_retry(self, mock_limit): mock_enforcer = mock.MagicMock() mock_limit.return_value = mock_enforcer over_limit_info_list = [ limit_exceptions.OverLimitInfo("class:VCPU", 12, 0, 30) ] mock_enforcer.enforce.side_effect = [ limit_exceptions.ProjectOverLimit(uuids.project_id, over_limit_info_list), None ] count = placement_limits.enforce_num_instances_and_flavor( self.context, uuids.project_id, self.flavor, True, 0, 3) self.assertEqual(2, count) self.assertEqual(2, mock_enforcer.enforce.call_count) mock_enforcer.enforce.assert_called_with( uuids.project_id, { 'servers': 2, 'class:VCPU': 20, 'class:MEMORY_MB': 200, 'class:DISK_GB': 4 })