Pass correct project ID to get tenant_usages
The current implementation of tenant_quota_usages did not allow for queries regarding projects that were not the currently active project, this meant that when an admin went to edit or create a project it tried to verify the usages against the wrong project. This patch adds the code for passing a project id to the tenant_quota_usages function so that the usages can be fetched for a specific project, as well as removes the need for usage validation on creation of a new project. Change-Id: I3ec84d14c8be7e3aae066119e963c4093f8aa345 Closes-Bug: 1380701
This commit is contained in:
parent
d471bae2cc
commit
193d40a414
@ -217,7 +217,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
['<CreateProjectInfo: createprojectinfoaction>',
|
||||
'<UpdateProjectMembers: update_members>',
|
||||
'<UpdateProjectGroups: update_group_members>',
|
||||
'<UpdateProjectQuota: update_quotas>'])
|
||||
'<CreateProjectQuota: create_quotas>'])
|
||||
|
||||
def test_add_project_get_domain(self):
|
||||
domain = self.domains.get(id="1")
|
||||
@ -305,7 +305,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
users = self._get_all_users(domain_id)
|
||||
groups = self._get_all_groups(domain_id)
|
||||
roles = self.roles.list()
|
||||
quota_usages = self.quota_usages.first()
|
||||
|
||||
# init
|
||||
quotas.get_disabled_quotas(IsA(http.HttpRequest)) \
|
||||
@ -325,8 +324,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
.AndReturn(groups)
|
||||
|
||||
# handle
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
project_details = self._get_project_info(project)
|
||||
quota_data = self._get_quota_info(quota)
|
||||
|
||||
@ -459,7 +456,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
users = self._get_all_users(domain_id)
|
||||
groups = self._get_all_groups(domain_id)
|
||||
roles = self.roles.list()
|
||||
quota_usages = self.quota_usages.first()
|
||||
|
||||
# init
|
||||
api.keystone.get_default_domain(IsA(http.HttpRequest)) \
|
||||
@ -478,8 +474,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
.AndReturn(groups)
|
||||
|
||||
# handle
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
project_details = self._get_project_info(project)
|
||||
|
||||
api.keystone.tenant_create(IsA(http.HttpRequest), **project_details) \
|
||||
@ -501,57 +495,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
domain_context_name=domain.name)
|
||||
self.test_add_project_tenant_create_error()
|
||||
|
||||
@test.create_stubs({api.keystone: ('user_list',
|
||||
'role_list',
|
||||
'group_list',
|
||||
'get_default_domain',
|
||||
'get_default_role',
|
||||
'add_tenant_user_role'),
|
||||
quotas: ('get_default_quota_data',
|
||||
'get_disabled_quotas',
|
||||
'tenant_quota_usages'),
|
||||
api.nova: ('tenant_quota_update',)})
|
||||
def test_project_quota_update_invalid_value(self):
|
||||
project = self.tenants.first()
|
||||
quota = self.quotas.first()
|
||||
default_role = self.roles.first()
|
||||
default_domain = self._get_default_domain()
|
||||
domain_id = default_domain.id
|
||||
users = self._get_all_users(domain_id)
|
||||
groups = self._get_all_groups(domain_id)
|
||||
roles = self.roles.list()
|
||||
quota_usages = self.quota_usages.first()
|
||||
quota_usages['instances']['used'] = 5
|
||||
|
||||
# init
|
||||
api.keystone.get_default_domain(IsA(http.HttpRequest)) \
|
||||
.AndReturn(default_domain)
|
||||
quotas.get_disabled_quotas(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.disabled_quotas.first())
|
||||
quotas.get_default_quota_data(IsA(http.HttpRequest)).AndReturn(quota)
|
||||
|
||||
api.keystone.get_default_role(IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(default_role)
|
||||
api.keystone.user_list(IsA(http.HttpRequest), domain=domain_id) \
|
||||
.AndReturn(users)
|
||||
api.keystone.role_list(IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(roles)
|
||||
api.keystone.group_list(IsA(http.HttpRequest), domain=domain_id) \
|
||||
.AndReturn(groups)
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
workflow_data = {}
|
||||
workflow_data.update(self._get_workflow_data(project, quota))
|
||||
workflow_data['instances'] = 2
|
||||
url = reverse('horizon:identity:projects:create')
|
||||
res = self.client.post(url, workflow_data)
|
||||
msg = 'Quota value(s) cannot be less than the current usage ' \
|
||||
'value(s): 5 Instances used.'
|
||||
self.assertContains(res, msg)
|
||||
|
||||
@test.create_stubs({api.keystone: ('tenant_create',
|
||||
'user_list',
|
||||
'role_list',
|
||||
@ -572,7 +515,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
users = self._get_all_users(domain_id)
|
||||
groups = self._get_all_groups(domain_id)
|
||||
roles = self.roles.list()
|
||||
quota_usages = self.quota_usages.first()
|
||||
|
||||
# init
|
||||
api.keystone.get_default_domain(IsA(http.HttpRequest)) \
|
||||
@ -591,8 +533,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
.AndReturn(groups)
|
||||
|
||||
# handle
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
project_details = self._get_project_info(project)
|
||||
quota_data = self._get_quota_info(quota)
|
||||
|
||||
@ -661,7 +601,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
users = self._get_all_users(domain_id)
|
||||
groups = self._get_all_groups(domain_id)
|
||||
roles = self.roles.list()
|
||||
quota_usages = self.quota_usages.first()
|
||||
|
||||
# init
|
||||
api.keystone.get_default_domain(IsA(http.HttpRequest)) \
|
||||
@ -680,8 +619,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
.AndReturn(groups)
|
||||
|
||||
# handle
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
project_details = self._get_project_info(project)
|
||||
quota_data = self._get_quota_info(quota)
|
||||
|
||||
@ -746,7 +683,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
users = self._get_all_users(domain_id)
|
||||
groups = self._get_all_groups(domain_id)
|
||||
roles = self.roles.list()
|
||||
quota_usages = self.quota_usages.first()
|
||||
|
||||
# init
|
||||
api.keystone.get_default_domain(IsA(http.HttpRequest)) \
|
||||
@ -764,9 +700,6 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
api.keystone.group_list(IsA(http.HttpRequest), domain=domain_id) \
|
||||
.AndReturn(groups)
|
||||
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
workflow_data = self._get_workflow_data(project, quota)
|
||||
@ -1101,7 +1034,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
group='3',
|
||||
project=self.tenant.id)
|
||||
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest), tenant_id=project.id) \
|
||||
.AndReturn(quota_usages)
|
||||
|
||||
nova_updated_quota = dict([(key, updated_quota[key]) for key in
|
||||
@ -1264,7 +1197,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
updated_quota = self._get_quota_info(quota)
|
||||
|
||||
# handle
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest), tenant_id=project.id) \
|
||||
.AndReturn(quota_usages)
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest),
|
||||
project.id,
|
||||
@ -1438,7 +1371,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
group='3',
|
||||
project=self.tenant.id)
|
||||
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest), tenant_id=project.id) \
|
||||
.AndReturn(quota_usages)
|
||||
|
||||
nova_updated_quota = dict([(key, updated_quota[key]) for key in
|
||||
@ -1556,7 +1489,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
updated_quota = self._get_quota_info(quota)
|
||||
|
||||
# handle
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest), tenant_id=project.id) \
|
||||
.AndReturn(quota_usages)
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest),
|
||||
project.id,
|
||||
|
@ -150,14 +150,14 @@ class CreateProjectView(workflows.WorkflowView):
|
||||
except Exception:
|
||||
error_msg = _('Unable to retrieve default Neutron quota '
|
||||
'values.')
|
||||
self.add_error_to_step(error_msg, 'update_quotas')
|
||||
self.add_error_to_step(error_msg, 'create_quotas')
|
||||
|
||||
for field in quotas.QUOTA_FIELDS:
|
||||
initial[field] = quota_defaults.get(field).limit
|
||||
|
||||
except Exception:
|
||||
error_msg = _('Unable to retrieve default quota values.')
|
||||
self.add_error_to_step(error_msg, 'update_quotas')
|
||||
self.add_error_to_step(error_msg, 'create_quotas')
|
||||
|
||||
return initial
|
||||
|
||||
|
@ -40,7 +40,7 @@ PROJECT_USER_MEMBER_SLUG = "update_members"
|
||||
PROJECT_GROUP_MEMBER_SLUG = "update_group_members"
|
||||
|
||||
|
||||
class UpdateProjectQuotaAction(workflows.Action):
|
||||
class ProjectQuotaAction(workflows.Action):
|
||||
ifcb_label = _("Injected File Content (Bytes)")
|
||||
metadata_items = forms.IntegerField(min_value=-1,
|
||||
label=_("Metadata Items"))
|
||||
@ -74,23 +74,21 @@ class UpdateProjectQuotaAction(workflows.Action):
|
||||
subnet = forms.IntegerField(min_value=-1, label=_("Subnets"))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(UpdateProjectQuotaAction, self).__init__(request,
|
||||
*args,
|
||||
**kwargs)
|
||||
super(ProjectQuotaAction, self).__init__(request,
|
||||
*args,
|
||||
**kwargs)
|
||||
disabled_quotas = quotas.get_disabled_quotas(request)
|
||||
for field in disabled_quotas:
|
||||
if field in self.fields:
|
||||
self.fields[field].required = False
|
||||
self.fields[field].widget = forms.HiddenInput()
|
||||
|
||||
class Meta:
|
||||
name = _("Quota")
|
||||
slug = 'update_quotas'
|
||||
help_text = _("Set maximum quotas for the project.")
|
||||
|
||||
class UpdateProjectQuotaAction(ProjectQuotaAction):
|
||||
def clean(self):
|
||||
cleaned_data = super(UpdateProjectQuotaAction, self).clean()
|
||||
usages = quotas.tenant_quota_usages(self.request)
|
||||
usages = quotas.tenant_quota_usages(
|
||||
self.request, tenant_id=self.initial['project_id'])
|
||||
# Validate the quota values before updating quotas.
|
||||
bad_values = []
|
||||
for key, value in cleaned_data.items():
|
||||
@ -107,6 +105,18 @@ class UpdateProjectQuotaAction(workflows.Action):
|
||||
raise forms.ValidationError(msg)
|
||||
return cleaned_data
|
||||
|
||||
class Meta:
|
||||
name = _("Quota")
|
||||
slug = 'update_quotas'
|
||||
help_text = _("Set maximum quotas for the project.")
|
||||
|
||||
|
||||
class CreateProjectQuotaAction(ProjectQuotaAction):
|
||||
class Meta:
|
||||
name = _("Quota")
|
||||
slug = 'create_quotas'
|
||||
help_text = _("Set maximum quotas for the project.")
|
||||
|
||||
|
||||
class UpdateProjectQuota(workflows.Step):
|
||||
action_class = UpdateProjectQuotaAction
|
||||
@ -114,6 +124,12 @@ class UpdateProjectQuota(workflows.Step):
|
||||
contributes = quotas.QUOTA_FIELDS
|
||||
|
||||
|
||||
class CreateProjectQuota(workflows.Step):
|
||||
action_class = CreateProjectQuotaAction
|
||||
depends_on = ("project_id",)
|
||||
contributes = quotas.QUOTA_FIELDS
|
||||
|
||||
|
||||
class CreateProjectInfoAction(workflows.Action):
|
||||
# Hide the domain_id and domain_name by default
|
||||
domain_id = forms.CharField(label=_("Domain ID"),
|
||||
@ -362,7 +378,7 @@ class CreateProject(workflows.Workflow):
|
||||
success_url = "horizon:identity:projects:index"
|
||||
default_steps = (CreateProjectInfo,
|
||||
UpdateProjectMembers,
|
||||
UpdateProjectQuota)
|
||||
CreateProjectQuota)
|
||||
|
||||
def __init__(self, request=None, context_seed=None, entry_point=None,
|
||||
*args, **kwargs):
|
||||
@ -370,7 +386,7 @@ class CreateProject(workflows.Workflow):
|
||||
self.default_steps = (CreateProjectInfo,
|
||||
UpdateProjectMembers,
|
||||
UpdateProjectGroups,
|
||||
UpdateProjectQuota)
|
||||
CreateProjectQuota)
|
||||
super(CreateProject, self).__init__(request=request,
|
||||
context_seed=context_seed,
|
||||
entry_point=entry_point,
|
||||
|
@ -245,13 +245,15 @@ def get_disabled_quotas(request):
|
||||
|
||||
|
||||
@memoized
|
||||
def tenant_quota_usages(request):
|
||||
# Get our quotas and construct our usage object.
|
||||
def tenant_quota_usages(request, tenant_id=None):
|
||||
"""Get our quotas and construct our usage object."""
|
||||
|
||||
disabled_quotas = get_disabled_quotas(request)
|
||||
|
||||
usages = QuotaUsage()
|
||||
for quota in get_tenant_quota_data(request,
|
||||
disabled_quotas=disabled_quotas):
|
||||
disabled_quotas=disabled_quotas,
|
||||
tenant_id=tenant_id):
|
||||
usages.add_quota(quota)
|
||||
|
||||
# Get our usages.
|
||||
@ -262,7 +264,13 @@ def tenant_quota_usages(request):
|
||||
except Exception:
|
||||
pass
|
||||
flavors = dict([(f.id, f) for f in nova.flavor_list(request)])
|
||||
instances, has_more = nova.server_list(request)
|
||||
|
||||
if tenant_id:
|
||||
instances, has_more = nova.server_list(
|
||||
request, search_opts={'tenant_id': tenant_id}, all_tenants=True)
|
||||
else:
|
||||
instances, has_more = nova.server_list(request)
|
||||
|
||||
# Fetch deleted flavors if necessary.
|
||||
missing_flavors = [instance.flavor['id'] for instance in instances
|
||||
if instance.flavor['id'] not in flavors]
|
||||
@ -285,16 +293,25 @@ def tenant_quota_usages(request):
|
||||
if 'network' not in disabled_quotas:
|
||||
networks = []
|
||||
networks = neutron.network_list(request, shared=False)
|
||||
if tenant_id:
|
||||
networks = filter(lambda net: net.tenant_id == tenant_id, networks)
|
||||
usages.tally('networks', len(networks))
|
||||
|
||||
if 'router' not in disabled_quotas:
|
||||
routers = []
|
||||
routers = neutron.router_list(request)
|
||||
if tenant_id:
|
||||
routers = filter(lambda rou: rou.tenant_id == tenant_id, routers)
|
||||
usages.tally('routers', len(routers))
|
||||
|
||||
if 'volumes' not in disabled_quotas:
|
||||
volumes = cinder.volume_list(request)
|
||||
snapshots = cinder.volume_snapshot_list(request)
|
||||
if tenant_id:
|
||||
opts = {'alltenants': 1, 'tenant_id': tenant_id}
|
||||
volumes = cinder.volume_list(request, opts)
|
||||
snapshots = cinder.volume_snapshot_list(request, opts)
|
||||
else:
|
||||
volumes = cinder.volume_list(request)
|
||||
snapshots = cinder.volume_snapshot_list(request)
|
||||
usages.tally('gigabytes', sum([int(v.size) for v in volumes]))
|
||||
usages.tally('volumes', len(volumes))
|
||||
usages.tally('snapshots', len(snapshots))
|
||||
|
Loading…
Reference in New Issue
Block a user