The UI component for Manila
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

395 lines
14 KiB

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import functools
import sys
from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _
import horizon
from manila_ui.api import manila
from openstack_dashboard.api import base
from openstack_dashboard.dashboards.admin.defaults import tables as quota_tbl
from openstack_dashboard.dashboards.admin.defaults import views \
as default_views
from openstack_dashboard.dashboards.admin.defaults import workflows \
as default_workflows
from openstack_dashboard.dashboards.identity.projects import views \
as project_views
from openstack_dashboard.dashboards.identity.projects import workflows \
as project_workflows
from openstack_dashboard.dashboards.project.overview import views \
as overview_views
from openstack_dashboard.usage import base as usage_base
from openstack_dashboard.usage import quotas
def wrap(orig_func):
"""decorator to wrap an existing function
Modified post from http://downgra.de/2009/05/16/python-monkey-patching/
to work with functions
e.g.
@wrap(quotas.tenant_limit_usages)
def tenant_limit_usages(orig, self):
limits = orig(request)
limits['disksUsed'] = 100
return limits
the first parameter of the new function is the the original,
overwritten function ('orig').
"""
def outer(new_func):
@functools.wraps(orig_func)
def wrapper(*args, **kwargs):
return new_func(orig_func, *args, **kwargs)
# Replace the original function in the module with the wrapper
orig_module = sys.modules[orig_func.__module__]
setattr(orig_module, orig_func.__name__, wrapper)
return wrapper
return outer
# All public methods in openstack_dashboard.usage.quotas are hardcoded to
# only look at a fixed set of services (nova, cinder, etc.). In order to
# incorporate manila quotas and usage, all public functions must be
# monkey-patched to add that information in.
MANILA_QUOTA_FIELDS = {
"shares",
"share_gigabytes",
"share_snapshots",
"share_snapshot_gigabytes",
"share_networks",
}
MANILA_QUOTA_NAMES = {
'shares': _('Shares'),
'share_gigabytes': _('Share gigabytes'),
'share_snapshots': _('Share snapshots'),
'share_snapshot_gigabytes': _('Share snapshot gigabytes'),
'share_networks': _('Shares Networks'),
}
quotas.QUOTA_FIELDS = quotas.QUOTA_FIELDS | MANILA_QUOTA_FIELDS
def _get_manila_disabled_quotas(request):
disabled_quotas = []
if not base.is_service_enabled(request, 'share'):
disabled_quotas.extend(MANILA_QUOTA_FIELDS)
return disabled_quotas
def _get_manila_quota_data(request, method_name, disabled_quotas=None,
tenant_id=None):
if not tenant_id:
tenant_id = request.user.tenant_id
if disabled_quotas is None:
disabled_quotas = _get_manila_disabled_quotas(request)
if 'shares' not in disabled_quotas:
manila_quotas = getattr(manila, method_name)(request, tenant_id)
for quota in manila_quotas:
if quota.name == 'gigabytes':
quota.name = 'share_gigabytes'
elif quota.name == 'snapshots':
quota.name = 'share_snapshots'
elif quota.name == 'snapshot_gigabytes':
quota.name = 'share_snapshot_gigabytes'
return manila_quotas
else:
return None
@wrap(quotas.get_default_quota_data)
def get_default_quota_data(f, request, disabled_quotas=None, tenant_id=None):
qs = f(request, disabled_quotas, tenant_id)
manila_quota = _get_manila_quota_data(request, "default_quota_get",
disabled_quotas=disabled_quotas,
tenant_id=tenant_id)
if manila_quota:
qs.add(manila_quota)
return qs
@wrap(quotas.get_tenant_quota_data)
def get_tenant_quota_data(f, request, disabled_quotas=None, tenant_id=None):
qs = f(request, disabled_quotas, tenant_id)
manila_quota = _get_manila_quota_data(request, "tenant_quota_get",
disabled_quotas=disabled_quotas,
tenant_id=tenant_id)
if manila_quota:
qs.add(manila_quota)
return qs
@wrap(quotas.get_disabled_quotas)
def get_disabled_quotas(f, request):
disabled_quotas = f(request)
disabled_quotas.update(_get_manila_disabled_quotas(request))
return disabled_quotas
@wrap(quotas.tenant_quota_usages)
def tenant_quota_usages(f, request, tenant_id=None, targets=None):
usages = f(request, tenant_id, targets)
if 'shares' not in _get_manila_disabled_quotas(request):
shares = manila.share_list(request)
snapshots = manila.share_snapshot_list(request)
sn_l = manila.share_network_list(request)
gig_s = sum([int(v.size) for v in shares])
gig_ss = sum([int(v.size) for v in snapshots])
usages.tally('shares', len(shares))
usages.tally('share_gigabytes', gig_s)
usages.tally('share_snapshots', len(snapshots))
usages.tally('share_snapshot_gigabytes', gig_ss)
usages.tally('share_networks', len(sn_l))
return usages
@wrap(quotas.tenant_limit_usages)
def tenant_limit_usages(f, request):
limits = f(request)
if base.is_service_enabled(request, 'share'):
try:
limits.update(manila.tenant_absolute_limits(request))
shares = manila.share_list(request)
snapshots = manila.share_snapshot_list(request)
share_networks = manila.share_network_list(request)
total_s_size = sum([getattr(share, 'size', 0) for share in shares])
total_ss_size = sum([getattr(ss, 'size', 0) for ss in snapshots])
limits['totalSharesUsed'] = len(shares)
limits['totalShareGigabytesUsed'] = total_s_size
limits['totalSnapshotsUsed'] = len(snapshots)
limits['totalSnapshotGigabytesUsed'] = total_ss_size
limits['totalShareNetworksUsed'] = len(share_networks)
except Exception:
msg = _("Unable to retrieve share limit information.")
horizon.exceptions.handle(request, msg)
return limits
@wrap(quota_tbl.get_quota_name)
def get_quota_name(f, quota):
if quota.name in MANILA_QUOTA_NAMES:
return MANILA_QUOTA_NAMES.get(quota.name)
else:
return f(quota)
#
# Add manila fields to Admin/Defaults/Update Defaults
#
class ManilaUpdateDefaultQuotaAction(
default_workflows.UpdateDefaultQuotasAction):
shares = horizon.forms.IntegerField(min_value=-1, label=_("Shares"))
share_gigabytes = horizon.forms.IntegerField(
min_value=-1, label=_("Share gigabytes"))
share_snapshots = horizon.forms.IntegerField(
min_value=-1, label=_("Share snapshots"))
share_snapshot_gigabytes = horizon.forms.IntegerField(
min_value=-1, label=_("Share snapshot gigabytes"))
share_networks = horizon.forms.IntegerField(
min_value=-1, label=_("Share Networks"))
class Meta(object):
name = _("Default Quotas")
slug = 'update_default_quotas'
help_text = _("From here you can update the default quotas "
"(max limits).")
class ManilaUpdateDefaultQuotasStep(default_workflows.UpdateDefaultQuotasStep):
action_class = ManilaUpdateDefaultQuotaAction
contributes = quotas.QUOTA_FIELDS
class ManilaUpdateDefaultQuotas(default_workflows.UpdateDefaultQuotas):
default_steps = (ManilaUpdateDefaultQuotasStep,)
def handle(self, request, data):
try:
super(ManilaUpdateDefaultQuotas, self).handle(request, data)
if base.is_service_enabled(request, 'share'):
manila_data = dict([(key, data[key]) for key in
MANILA_QUOTA_FIELDS])
manila.default_quota_update(request, **manila_data)
except Exception:
horizon.exceptions.handle(request,
_('Unable to update default quotas.'))
return True
default_views.UpdateDefaultQuotasView.workflow_class = (
ManilaUpdateDefaultQuotas)
#
# Add manila fields to Identity/Projects/Modify Quotas
#
class ManilaUpdateProjectQuotaAction(
project_workflows.UpdateProjectQuotaAction):
shares = horizon.forms.IntegerField(min_value=-1, label=_("Shares"))
share_gigabytes = horizon.forms.IntegerField(
min_value=-1, label=_("Share gigabytes"))
share_snapshots = horizon.forms.IntegerField(
min_value=-1, label=_("Share snapshots"))
share_snapshot_gigabytes = horizon.forms.IntegerField(
min_value=-1, label=_("Share snapshot gigabytes"))
share_networks = horizon.forms.IntegerField(
min_value=-1, label=_("Share Networks"))
class Meta(object):
name = _("Quota")
slug = 'update_quotas'
help_text = _("Set maximum quotas for the project.")
project_workflows.UpdateProjectQuota.action_class = (
ManilaUpdateProjectQuotaAction)
project_workflows.UpdateProjectQuota.contributes = quotas.QUOTA_FIELDS
class ManilaUpdateProject(project_workflows.UpdateProject):
def handle(self, request, data):
try:
super(ManilaUpdateProject, self).handle(request, data)
if base.is_service_enabled(request, 'share'):
manila_data = dict([(key, data[key]) for key in
MANILA_QUOTA_FIELDS])
manila.tenant_quota_update(request,
data['project_id'],
**manila_data)
except Exception:
horizon.exceptions.handle(request,
_('Modified project information and '
'members, but unable to modify '
'project quotas.'))
return True
project_views.UpdateProjectView.workflow_class = ManilaUpdateProject
#
# Add manila fields to Identity/Projects/Create Project
#
class ManilaCreateProjectQuotaAction(
project_workflows.CreateProjectQuotaAction):
shares = horizon.forms.IntegerField(min_value=-1, label=_("Shares"))
share_gigabytes = horizon.forms.IntegerField(
min_value=-1, label=_("Share gigabytes"))
share_snapshots = horizon.forms.IntegerField(
min_value=-1, label=_("Share snapshots"))
share_snapshot_gigabytes = horizon.forms.IntegerField(
min_value=-1, label=_("Share snapshot gigabytes"))
share_networks = horizon.forms.IntegerField(
min_value=-1, label=_("Share Networks"))
class Meta(object):
name = _("Quota")
slug = 'create_quotas'
help_text = _("Set maximum quotas for the project.")
project_workflows.CreateProjectQuota.action_class = (
ManilaCreateProjectQuotaAction)
project_workflows.CreateProjectQuota.contributes = quotas.QUOTA_FIELDS
class ManilaCreateProject(project_workflows.CreateProject):
def handle(self, request, data):
try:
super(ManilaCreateProject, self).handle(request, data)
if base.is_service_enabled(request, 'share'):
manila_data = dict([(key, data[key]) for key in
MANILA_QUOTA_FIELDS])
manila.tenant_quota_update(request,
self.object.id,
**manila_data)
except Exception:
horizon.exceptions.handle(request,
_('Unable to set project quotas.'))
return True
project_views.CreateProjectView.workflow_class = ManilaCreateProject
#
# Add extra pie charts to Project/Compute Overview
#
class ManilaUsage(usage_base.ProjectUsage):
def get_manila_limits(self):
"""Get share limits if manila is enabled."""
if not base.is_service_enabled(self.request, 'share'):
return
try:
self.limits.update(manila.tenant_absolute_limits(self.request))
except Exception:
msg = _("Unable to retrieve share limit information.")
horizon.exceptions.handle(self.request, msg)
return
def get_limits(self):
super(self.__class__, self).get_limits()
self.get_manila_limits()
def get_context_data(self, **kwargs):
context = super(self.__class__, self).get_context_data(**kwargs)
types = (
("totalSharesUsed", "maxTotalShares", _("Shares")),
("totalShareGigabytesUsed", "maxTotalShareGigabytes",
_("Share Storage")),
("totalShareSnapshotsUsed", "maxTotalShareSnapshots",
_("Share Snapshots")),
("totalSnapshotGigabytesUsed", "maxTotalSnapshotGigabytes",
_("Share Snapshots Storage")),
("totalShareNetworksUsed", "maxTotalShareNetworks",
_("Share Networks")),
)
for t in types:
if t[0] in self.usage.limits and t[1] in self.usage.limits:
text = pgettext_lazy('Label in the limit summary', 'Used')
context['charts'].append({
'type': t[0],
'name': t[2],
'used': self.usage.limits[t[0]],
'max': self.usage.limits[t[1]],
'text': text
})
return context
overview_views.ProjectOverview.get_context_data = get_context_data
overview_views.ProjectOverview.usage_class = ManilaUsage