Add support of share groups
To both existing dashboards - admin and project. Change-Id: Ice335de858c234799405f7592b9f08e58e6dec6e Implements BluePrint share-groups
This commit is contained in:
parent
3fbc64a6e9
commit
087948ae1a
@ -93,9 +93,11 @@ It is possible to enable or disable some Manila UI features. To do so,
|
||||
look for files located in "manila_ui/local/local_settings.d/" directory,
|
||||
where you can redefine the values of the OPENSTACK_MANILA_FEATURES dict::
|
||||
|
||||
* enable_share_groups
|
||||
* enable_replication
|
||||
* enable_migration
|
||||
* enable_public_share_type_creation
|
||||
* enable_public_share_group_type_creation
|
||||
* enable_public_shares
|
||||
* enabled_share_protocols
|
||||
|
||||
@ -108,9 +110,11 @@ expected to redefine enabled_share_protocols as follows:
|
||||
.. code-block:: python
|
||||
|
||||
OPENSTACK_MANILA_FEATURES = {
|
||||
'enable_share_groups': True,
|
||||
'enable_replication': True,
|
||||
'enable_migration': True,
|
||||
'enable_public_share_type_creation': True,
|
||||
'enable_public_share_group_type_creation': True,
|
||||
'enable_public_shares': True,
|
||||
'enabled_share_protocols': ['NFS'],
|
||||
}
|
||||
|
@ -19,20 +19,19 @@
|
||||
# under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from manilaclient import client as manila_client
|
||||
from horizon import exceptions
|
||||
import logging
|
||||
from openstack_dashboard.api import base
|
||||
import six
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon.utils.memoized import memoized # noqa
|
||||
from openstack_dashboard.api import base
|
||||
|
||||
from manilaclient import client as manila_client
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MANILA_UI_USER_AGENT_REPR = "manila_ui_plugin_for_horizon"
|
||||
# NOTE(vponomaryov): update version to 2.34 when manilaclient is released with
|
||||
# its support. It will allow to show 'availability zones' for share groups.
|
||||
MANILA_VERSION = "2.32" # requires manilaclient 1.13.0 or newer
|
||||
MANILA_SERVICE_TYPE = "sharev2"
|
||||
|
||||
@ -80,16 +79,21 @@ def share_get(request, share_id):
|
||||
|
||||
def share_create(request, size, name, description, proto, snapshot_id=None,
|
||||
metadata=None, share_network=None, share_type=None,
|
||||
is_public=None, availability_zone=None):
|
||||
is_public=None, availability_zone=None, share_group_id=None):
|
||||
return manilaclient(request).shares.create(
|
||||
proto, size, name=name, description=description,
|
||||
share_network=share_network, snapshot_id=snapshot_id,
|
||||
metadata=metadata, share_type=share_type, is_public=is_public,
|
||||
availability_zone=availability_zone)
|
||||
availability_zone=availability_zone,
|
||||
share_group_id=share_group_id,
|
||||
)
|
||||
|
||||
|
||||
def share_delete(request, share_id):
|
||||
return manilaclient(request).shares.delete(share_id)
|
||||
def share_delete(request, share_id, share_group_id=None):
|
||||
return manilaclient(request).shares.delete(
|
||||
share_id,
|
||||
share_group_id=share_group_id,
|
||||
)
|
||||
|
||||
|
||||
def share_update(request, share_id, name, description, is_public=''):
|
||||
@ -481,13 +485,144 @@ def pool_list(request, detailed=False):
|
||||
return manilaclient(request).pools.list(detailed=detailed)
|
||||
|
||||
|
||||
@memoized
|
||||
def is_replication_enabled():
|
||||
manila_config = getattr(settings, 'OPENSTACK_MANILA_FEATURES', {})
|
||||
return manila_config.get('enable_replication', True)
|
||||
# ####### Share Groups # #######
|
||||
|
||||
def share_group_create(request, name, description=None,
|
||||
share_group_type=None,
|
||||
share_types=None,
|
||||
share_network=None,
|
||||
source_share_group_snapshot=None,
|
||||
availability_zone=None):
|
||||
return manilaclient(request).share_groups.create(
|
||||
name=name,
|
||||
description=description,
|
||||
share_group_type=share_group_type,
|
||||
share_types=share_types,
|
||||
share_network=share_network,
|
||||
source_share_group_snapshot=source_share_group_snapshot,
|
||||
availability_zone=availability_zone,
|
||||
)
|
||||
|
||||
|
||||
@memoized
|
||||
def is_migration_enabled():
|
||||
manila_config = getattr(settings, 'OPENSTACK_MANILA_FEATURES', {})
|
||||
return manila_config.get('enable_migration', True)
|
||||
def share_group_get(request, share_group):
|
||||
return manilaclient(request).share_groups.get(share_group)
|
||||
|
||||
|
||||
def share_group_update(request, share_group, name, description):
|
||||
return manilaclient(request).share_groups.update(
|
||||
share_group,
|
||||
name=name,
|
||||
description=description,
|
||||
)
|
||||
|
||||
|
||||
def share_group_delete(request, share_group, force=False):
|
||||
return manilaclient(request).share_groups.delete(share_group, force=force)
|
||||
|
||||
|
||||
def share_group_reset_state(request, share_group, state):
|
||||
return manilaclient(request).share_groups.reset_state(share_group, state)
|
||||
|
||||
|
||||
def share_group_list(request, detailed=True, search_opts=None, sort_key=None,
|
||||
sort_dir=None):
|
||||
return manilaclient(request).share_groups.list(
|
||||
detailed=detailed,
|
||||
search_opts=search_opts,
|
||||
sort_key=sort_key,
|
||||
sort_dir=sort_dir,
|
||||
)
|
||||
|
||||
|
||||
# ####### Share Group Snapshots # #######
|
||||
|
||||
def share_group_snapshot_create(request, share_group, name, description=None):
|
||||
return manilaclient(request).share_group_snapshots.create(
|
||||
share_group=share_group,
|
||||
name=name,
|
||||
description=description,
|
||||
)
|
||||
|
||||
|
||||
def share_group_snapshot_get(request, share_group_snapshot):
|
||||
return manilaclient(request).share_group_snapshots.get(
|
||||
share_group_snapshot)
|
||||
|
||||
|
||||
def share_group_snapshot_update(request, share_group_snapshot, name,
|
||||
description):
|
||||
return manilaclient(request).share_group_snapshots.update(
|
||||
share_group_snapshot,
|
||||
name=name,
|
||||
description=description,
|
||||
)
|
||||
|
||||
|
||||
def share_group_snapshot_delete(request, share_group_snapshot, force=False):
|
||||
return manilaclient(request).share_group_snapshots.delete(
|
||||
share_group_snapshot, force=force)
|
||||
|
||||
|
||||
def share_group_snapshot_reset_state(request, share_group_snapshot, state):
|
||||
return manilaclient(request).share_group_snapshots.reset_state(
|
||||
share_group_snapshot, state)
|
||||
|
||||
|
||||
def share_group_snapshot_list(request, detailed=True, search_opts=None,
|
||||
sort_key=None, sort_dir=None):
|
||||
return manilaclient(request).share_group_snapshots.list(
|
||||
detailed=detailed,
|
||||
search_opts=search_opts,
|
||||
sort_key=sort_key,
|
||||
sort_dir=sort_dir,
|
||||
)
|
||||
|
||||
|
||||
# ####### Share Group Types # ########
|
||||
|
||||
def share_group_type_create(request, name, share_types, is_public=False,
|
||||
group_specs=None):
|
||||
return manilaclient(request).share_group_types.create(
|
||||
name=name, share_types=share_types, is_public=is_public,
|
||||
group_specs=group_specs)
|
||||
|
||||
|
||||
def share_group_type_get(request, share_group_type):
|
||||
return manilaclient(request).share_group_types.get(share_group_type)
|
||||
|
||||
|
||||
def share_group_type_list(request, show_all=True):
|
||||
return manilaclient(request).share_group_types.list(show_all=show_all)
|
||||
|
||||
|
||||
def share_group_type_delete(request, share_group_type):
|
||||
return manilaclient(request).share_group_types.delete(share_group_type)
|
||||
|
||||
|
||||
def share_group_type_access_list(request, share_group_type):
|
||||
return manilaclient(request).share_group_type_access.list(share_group_type)
|
||||
|
||||
|
||||
def share_group_type_access_add(request, share_group_type, project):
|
||||
return manilaclient(request).share_group_type_access.add_project_access(
|
||||
share_group_type, project)
|
||||
|
||||
|
||||
def share_group_type_access_remove(request, share_group_type, project):
|
||||
return manilaclient(request).share_group_type_access.remove_project_access(
|
||||
share_group_type, project)
|
||||
|
||||
|
||||
def share_group_type_set_specs(request, share_group_type, group_specs):
|
||||
return manilaclient(request).share_group_types.get(
|
||||
share_group_type).set_keys(group_specs)
|
||||
|
||||
|
||||
def share_group_type_unset_specs(request, share_group_type, keys):
|
||||
return manilaclient(request).share_group_types.get(
|
||||
share_group_type).unset_keys(keys)
|
||||
|
||||
|
||||
def share_group_type_get_specs(request, share_group_type):
|
||||
return manilaclient(request).share_group_types.get(
|
||||
share_group_type).get_keys()
|
||||
|
55
manila_ui/dashboards/admin/share_group_snapshots/forms.py
Normal file
55
manila_ui/dashboards/admin/share_group_snapshots/forms.py
Normal file
@ -0,0 +1,55 @@
|
||||
# Copyright (c) 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
|
||||
from manila_ui.api import manila
|
||||
|
||||
|
||||
class ResetShareGroupSnapshotStatusForm(forms.SelfHandlingForm):
|
||||
status = forms.ChoiceField(
|
||||
label=_("Status"),
|
||||
required=True,
|
||||
choices=(
|
||||
('available', 'available'),
|
||||
('error', 'error'),
|
||||
)
|
||||
)
|
||||
|
||||
def handle(self, request, data):
|
||||
s_id = self.initial['share_group_snapshot_id']
|
||||
try:
|
||||
manila.share_group_snapshot_reset_state(
|
||||
request, s_id, data["status"])
|
||||
message = _(
|
||||
"Reseting share group snapshot ('%(id)s') status "
|
||||
"from '%(from)s' to '%(to)s'.") % {
|
||||
"id": self.initial['share_group_snapshot_name'] or s_id,
|
||||
"from": self.initial['share_group_snapshot_status'],
|
||||
"to": data["status"]}
|
||||
messages.success(request, message)
|
||||
return True
|
||||
except Exception:
|
||||
redirect = reverse("horizon:admin:share_group_snapshots:index")
|
||||
exceptions.handle(
|
||||
request,
|
||||
_("Unable to reset status of share group snapshot "
|
||||
"'%s'.") % s_id,
|
||||
redirect=redirect)
|
||||
return False
|
29
manila_ui/dashboards/admin/share_group_snapshots/panel.py
Normal file
29
manila_ui/dashboards/admin/share_group_snapshots/panel.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
from openstack_dashboard.dashboards.admin import dashboard
|
||||
|
||||
|
||||
class ShareGroupSnapshots(horizon.Panel):
|
||||
name = _("Share Group Snapshots")
|
||||
slug = 'share_group_snapshots'
|
||||
permissions = (
|
||||
'openstack.services.share',
|
||||
)
|
||||
|
||||
|
||||
dashboard.Admin.register(ShareGroupSnapshots)
|
142
manila_ui/dashboards/admin/share_group_snapshots/tables.py
Normal file
142
manila_ui/dashboards/admin/share_group_snapshots/tables.py
Normal file
@ -0,0 +1,142 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template.defaultfilters import title # noqa
|
||||
from django.utils.translation import pgettext_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy
|
||||
from horizon import exceptions
|
||||
from horizon import tables
|
||||
from horizon.utils import filters
|
||||
|
||||
from manila_ui.api import manila
|
||||
|
||||
|
||||
class ShareGroupSnapshotShareGroupNameColumn(tables.Column):
|
||||
def get_link_url(self, snapshot):
|
||||
return reverse(self.link, args=(snapshot.share_group_id,))
|
||||
|
||||
|
||||
class DeleteShareGroupSnapshot(tables.DeleteAction):
|
||||
|
||||
@staticmethod
|
||||
def action_present(count):
|
||||
return ungettext_lazy(
|
||||
u"Delete Share Group Snapshot",
|
||||
u"Delete Share Group Snapshots",
|
||||
count
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def action_past(count):
|
||||
return ungettext_lazy(
|
||||
u"Deleted Share Group Snapshot",
|
||||
u"Deleted Share Group Snapshots",
|
||||
count
|
||||
)
|
||||
|
||||
def delete(self, request, obj_id):
|
||||
obj = self.table.get_object_by_id(obj_id)
|
||||
name = self.table.get_object_display(obj)
|
||||
try:
|
||||
manila.share_group_snapshot_delete(request, obj_id)
|
||||
except Exception:
|
||||
msg = _('Unable to delete share group snapshot "%s". '
|
||||
'One or more share groups depend on it.')
|
||||
exceptions.check_message(["snapshots", "dependent"], msg % name)
|
||||
raise
|
||||
|
||||
def allowed(self, request, snapshot=None):
|
||||
if snapshot:
|
||||
return snapshot.status.lower() in ('available', 'error')
|
||||
return True
|
||||
|
||||
|
||||
class ResetShareGroupSnapshotStatus(tables.LinkAction):
|
||||
name = "reset_share_group_snapshot_status"
|
||||
verbose_name = _("Reset status")
|
||||
url = "horizon:admin:share_group_snapshots:reset_status"
|
||||
classes = ("ajax-modal", "btn-create")
|
||||
|
||||
def allowed(self, request, share_group=None):
|
||||
return True
|
||||
|
||||
|
||||
class UpdateShareGroupSnapshotRow(tables.Row):
|
||||
ajax = True
|
||||
|
||||
def get_data(self, request, share_group_snapshot_id):
|
||||
snapshot = manila.share_group_snapshot_get(
|
||||
request, share_group_snapshot_id)
|
||||
if not snapshot.name:
|
||||
snapshot.name = share_group_snapshot_id
|
||||
return snapshot
|
||||
|
||||
|
||||
class ShareGroupSnapshotsTable(tables.DataTable):
|
||||
STATUS_CHOICES = (
|
||||
("available", True),
|
||||
("creating", None),
|
||||
("error", False),
|
||||
)
|
||||
STATUS_DISPLAY_CHOICES = (
|
||||
("available",
|
||||
pgettext_lazy("Current status of snapshot", u"Available")),
|
||||
("creating", pgettext_lazy("Current status of snapshot", u"Creating")),
|
||||
("error", pgettext_lazy("Current status of snapshot", u"Error")),
|
||||
)
|
||||
name = tables.WrappingColumn(
|
||||
"name", verbose_name=_("Name"),
|
||||
link="horizon:admin:share_group_snapshots:detail")
|
||||
description = tables.Column(
|
||||
"description",
|
||||
verbose_name=_("Description"),
|
||||
truncate=40)
|
||||
created_at = tables.Column(
|
||||
"created_at",
|
||||
verbose_name=_("Created at"),
|
||||
filters=(
|
||||
filters.parse_isotime,
|
||||
))
|
||||
status = tables.Column(
|
||||
"status",
|
||||
filters=(title,),
|
||||
verbose_name=_("Status"),
|
||||
status=True,
|
||||
status_choices=STATUS_CHOICES,
|
||||
display_choices=STATUS_DISPLAY_CHOICES)
|
||||
source = ShareGroupSnapshotShareGroupNameColumn(
|
||||
"share_group",
|
||||
verbose_name=_("Source"),
|
||||
link="horizon:admin:share_groups:detail")
|
||||
|
||||
def get_object_display(self, obj):
|
||||
return obj.name
|
||||
|
||||
class Meta(object):
|
||||
name = "share_group_snapshots"
|
||||
verbose_name = _("Share Group Snapshots")
|
||||
status_columns = ["status"]
|
||||
row_class = UpdateShareGroupSnapshotRow
|
||||
table_actions = (
|
||||
tables.NameFilterAction,
|
||||
DeleteShareGroupSnapshot,
|
||||
)
|
||||
row_actions = (
|
||||
ResetShareGroupSnapshotStatus,
|
||||
DeleteShareGroupSnapshot,
|
||||
)
|
34
manila_ui/dashboards/admin/share_group_snapshots/tabs.py
Normal file
34
manila_ui/dashboards/admin/share_group_snapshots/tabs.py
Normal file
@ -0,0 +1,34 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
|
||||
class ShareGroupSnapshotOverviewTab(tabs.Tab):
|
||||
name = _("Share Group Snapshot Overview")
|
||||
slug = "share_group_snapshot_overview_tab"
|
||||
template_name = "admin/share_group_snapshots/_detail.html"
|
||||
|
||||
def get_context_data(self, request):
|
||||
return {"share_group_snapshot": self.tab_group.kwargs[
|
||||
"share_group_snapshot"]}
|
||||
|
||||
|
||||
class ShareGroupSnapshotDetailTabs(tabs.TabGroup):
|
||||
slug = "share_group_snapshot_details"
|
||||
tabs = (
|
||||
ShareGroupSnapshotOverviewTab,
|
||||
)
|
@ -0,0 +1,23 @@
|
||||
{% load i18n sizeformat parse_date %}
|
||||
|
||||
<h3>{% trans "Share Group Snapshot Overview" %}</h3>
|
||||
<div class="detail">
|
||||
<hr class="header_rule">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ share_group_snapshot.name }}</dd>
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ share_group_snapshot.id }}</dd>
|
||||
{% url 'horizon:admin:share_groups:detail' share_group_snapshot.share_group_id as sg_url %}
|
||||
<dt>{% trans "Source Share Group" %}</dt>
|
||||
<dd><a href="{{ sg_url }}">{{ share_group_snapshot.sg_name_or_id }}</a></dd>
|
||||
{% if share_group_snapshot.description %}
|
||||
<dt>{% trans "Description" %}</dt>
|
||||
<dd>{{ share_group_snapshot.description }}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>{{ share_group_snapshot.status|capfirst }}</dd>
|
||||
<dt>{% trans "Created" %}</dt>
|
||||
<dd>{{ share_group_snapshot.created_at|parse_date }}</dd>
|
||||
</dl>
|
||||
</div>
|
@ -0,0 +1,5 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
<p>"Reset status of <b>'{{ share_group_snapshot_name }}'</b> share group snapshot."</p>
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Share Group Snapshot Details" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Share Group Snapshots" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ share_group_snapshots_table.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Reset Share Group Snapshot Status" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/share_group_snapshots/_reset_status.html' %}
|
||||
{% endblock %}
|
36
manila_ui/dashboards/admin/share_group_snapshots/urls.py
Normal file
36
manila_ui/dashboards/admin/share_group_snapshots/urls.py
Normal file
@ -0,0 +1,36 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.conf import urls
|
||||
|
||||
from manila_ui.dashboards.admin.share_group_snapshots import views
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
urlpatterns = [
|
||||
urls.url(
|
||||
r'^$',
|
||||
views.ShareGroupSnapshotsView.as_view(),
|
||||
name='index'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_snapshot_id>[^/]+)/$',
|
||||
views.ShareGroupSnapshotDetailView.as_view(),
|
||||
name='detail'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_snapshot_id>[^/]+)/reset_status$',
|
||||
views.ResetShareGroupSnapshotStatusView.as_view(),
|
||||
name='reset_status'),
|
||||
]
|
137
manila_ui/dashboards/admin/share_group_snapshots/views.py
Normal file
137
manila_ui/dashboards/admin/share_group_snapshots/views.py
Normal file
@ -0,0 +1,137 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Admin views for managing share group snapshots.
|
||||
"""
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon.utils import memoized
|
||||
|
||||
from manila_ui.api import manila
|
||||
import manila_ui.dashboards.admin.share_group_snapshots.forms as sgs_forms
|
||||
import manila_ui.dashboards.admin.share_group_snapshots.tables as sgs_tables
|
||||
import manila_ui.dashboards.admin.share_group_snapshots.tabs as sgs_tabs
|
||||
|
||||
|
||||
class ShareGroupSnapshotsView(tables.MultiTableView):
|
||||
table_classes = (
|
||||
sgs_tables.ShareGroupSnapshotsTable,
|
||||
)
|
||||
template_name = "admin/share_group_snapshots/index.html"
|
||||
page_title = _("Share Group Snapshots")
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_share_group_snapshots_data(self):
|
||||
share_group_snapshots = []
|
||||
try:
|
||||
share_group_snapshots = manila.share_group_snapshot_list(
|
||||
self.request, search_opts={'all_tenants': True})
|
||||
share_groups = manila.share_group_list(self.request)
|
||||
sg_names = dict([(sg.id, sg.name or sg.id) for sg in share_groups])
|
||||
for snapshot in share_group_snapshots:
|
||||
snapshot.share_group = sg_names.get(snapshot.share_group_id)
|
||||
except Exception:
|
||||
msg = _("Unable to retrieve share group snapshot list.")
|
||||
exceptions.handle(self.request, msg)
|
||||
return share_group_snapshots
|
||||
|
||||
|
||||
class ShareGroupSnapshotDetailView(tabs.TabView):
|
||||
tab_group_class = sgs_tabs.ShareGroupSnapshotDetailTabs
|
||||
template_name = "admin/share_group_snapshots/detail.html"
|
||||
redirect_url = reverse_lazy("horizon:admin:share_group_snapshots:index")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ShareGroupSnapshotDetailView, self).get_context_data(
|
||||
**kwargs)
|
||||
snapshot = self.get_data()
|
||||
snapshot_display_name = snapshot.name or snapshot.id
|
||||
context["snapshot"] = snapshot
|
||||
context["snapshot_display_name"] = snapshot_display_name
|
||||
context["page_title"] = _(
|
||||
"Share Group Snapshot Details: %(sgs_display_name)s") % (
|
||||
{'sgs_display_name': snapshot_display_name})
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
share_group_snapshot = manila.share_group_snapshot_get(
|
||||
self.request, self.kwargs['share_group_snapshot_id'])
|
||||
sg = manila.share_group_get(
|
||||
self.request, share_group_snapshot.share_group_id)
|
||||
share_group_snapshot.sg_name_or_id = sg.name or sg.id
|
||||
except Exception:
|
||||
exceptions.handle(
|
||||
self.request,
|
||||
_('Unable to retrieve share group snapshot details.'),
|
||||
redirect=self.redirect_url)
|
||||
return share_group_snapshot
|
||||
|
||||
def get_tabs(self, request, *args, **kwargs):
|
||||
return self.tab_group_class(
|
||||
request, share_group_snapshot=self.get_data(), **kwargs)
|
||||
|
||||
|
||||
class ResetShareGroupSnapshotStatusView(forms.ModalFormView):
|
||||
form_class = sgs_forms.ResetShareGroupSnapshotStatusForm
|
||||
form_id = "reset_share_group_snapshot_status"
|
||||
template_name = 'admin/share_group_snapshots/reset_status.html'
|
||||
modal_header = _("Reset Status")
|
||||
modal_id = "reset_share_group_snapshot_status_modal"
|
||||
submit_label = _("Reset status")
|
||||
submit_url = "horizon:admin:share_group_snapshots:reset_status"
|
||||
success_url = reverse_lazy("horizon:admin:share_group_snapshots:index")
|
||||
page_title = _("Reset Share Group Snapshot Status")
|
||||
|
||||
def get_object(self):
|
||||
if not hasattr(self, "_object"):
|
||||
s_id = self.kwargs["share_group_snapshot_id"]
|
||||
try:
|
||||
self._object = manila.share_group_snapshot_get(
|
||||
self.request, s_id)
|
||||
except Exception:
|
||||
msg = _("Unable to retrieve share group snapshot '%s'.") % s_id
|
||||
url = reverse('horizon:admin:share_group_snapshots:index')
|
||||
exceptions.handle(self.request, msg, redirect=url)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(self.__class__, self).get_context_data(**kwargs)
|
||||
sgs = self.get_object()
|
||||
context['share_group_snapshot_id'] = self.kwargs[
|
||||
'share_group_snapshot_id']
|
||||
context['share_group_snapshot_name'] = sgs.name or sgs.id
|
||||
context['share_group_snapshot_status'] = sgs.status
|
||||
context['share_group_id'] = sgs.share_group_id
|
||||
context['submit_url'] = reverse(
|
||||
self.submit_url, args=(context['share_group_snapshot_id'], ))
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
sgs = self.get_object()
|
||||
return {
|
||||
"share_group_snapshot_id": self.kwargs["share_group_snapshot_id"],
|
||||
"share_group_snapshot_name": sgs.name or sgs.id,
|
||||
"share_group_snapshot_status": sgs.status,
|
||||
"share_group_id": sgs.share_group_id,
|
||||
}
|
141
manila_ui/dashboards/admin/share_group_types/forms.py
Normal file
141
manila_ui/dashboards/admin/share_group_types/forms.py
Normal file
@ -0,0 +1,141 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.conf import settings
|
||||
from django.forms import ValidationError # noqa
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
|
||||
from manila_ui.api import manila
|
||||
from manila_ui.dashboards import utils
|
||||
|
||||
|
||||
SGT_GROUP_SPECS_FORM_ATTRS = {
|
||||
"rows": 5,
|
||||
"cols": 40,
|
||||
"style": "height: 135px; width: 100%;", # in case 'rows' not picked up
|
||||
}
|
||||
|
||||
|
||||
class CreateShareGroupTypeForm(forms.SelfHandlingForm):
|
||||
name = forms.CharField(max_length="255", label=_("Name"), required=True)
|
||||
group_specs = forms.CharField(
|
||||
required=False, label=_("Group specs"),
|
||||
widget=forms.widgets.Textarea(attrs=SGT_GROUP_SPECS_FORM_ATTRS))
|
||||
share_types = forms.MultipleChoiceField(
|
||||
label=_("Share Types"),
|
||||
required=True,
|
||||
widget=forms.SelectMultiple(attrs={
|
||||
"style": "height: 155px;",
|
||||
}),
|
||||
error_messages={
|
||||
'required': _("At least one share type must be specified.")
|
||||
})
|
||||
is_public = forms.BooleanField(
|
||||
label=_("Public"), required=False, initial=True,
|
||||
help_text=("Defines whether this share group type is available for "
|
||||
"all or not. List of allowed tenants should be set "
|
||||
"separately."))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(request, *args, **kwargs)
|
||||
manila_features = getattr(settings, 'OPENSTACK_MANILA_FEATURES', {})
|
||||
self.enable_public_share_group_type_creation = manila_features.get(
|
||||
'enable_public_share_group_type_creation', True)
|
||||
if not self.enable_public_share_group_type_creation:
|
||||
self.fields.pop('is_public')
|
||||
share_type_choices = manila.share_type_list(request)
|
||||
self.fields['share_types'].choices = [
|
||||
(choice.id, choice.name) for choice in share_type_choices]
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(CreateShareGroupTypeForm, self).clean()
|
||||
return cleaned_data
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
set_dict, unset_list = utils.parse_str_meta(data['group_specs'])
|
||||
if unset_list:
|
||||
msg = _("Expected only pairs of key=value.")
|
||||
raise ValidationError(message=msg)
|
||||
|
||||
is_public = (
|
||||
self.enable_public_share_group_type_creation and
|
||||
data["is_public"])
|
||||
share_group_type = manila.share_group_type_create(
|
||||
request, data["name"], share_types=data['share_types'],
|
||||
is_public=is_public)
|
||||
if set_dict:
|
||||
manila.share_group_type_set_specs(
|
||||
request, share_group_type.id, set_dict)
|
||||
|
||||
msg = _("Successfully created share group type: "
|
||||
"%s") % share_group_type.name
|
||||
messages.success(request, msg)
|
||||
return True
|
||||
except ValidationError as e:
|
||||
# handle error without losing dialog
|
||||
self.api_error(e.messages[0])
|
||||
return False
|
||||
except Exception:
|
||||
exceptions.handle(request, _('Unable to create share group type.'))
|
||||
return False
|
||||
|
||||
|
||||
class UpdateShareGroupTypeForm(forms.SelfHandlingForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(*args, **kwargs)
|
||||
# NOTE(vponomaryov): parse existing group specs
|
||||
# to str view for textarea html element
|
||||
es_str = ""
|
||||
for k, v in self.initial["group_specs"].items():
|
||||
es_str += "%s=%s\r\n" % (k, v)
|
||||
self.initial["group_specs"] = es_str
|
||||
|
||||
group_specs = forms.CharField(
|
||||
required=False, label=_("Group specs"),
|
||||
widget=forms.widgets.Textarea(attrs=SGT_GROUP_SPECS_FORM_ATTRS))
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
set_dict, unset_list = utils.parse_str_meta(data['group_specs'])
|
||||
if set_dict:
|
||||
manila.share_group_type_set_specs(
|
||||
request, self.initial["id"], set_dict)
|
||||
if unset_list:
|
||||
get = manila.share_group_type_get_specs(
|
||||
request, self.initial["id"])
|
||||
|
||||
# NOTE(vponomaryov): skip keys that are already unset
|
||||
to_unset = set(unset_list).intersection(set(get.keys()))
|
||||
if to_unset:
|
||||
manila.share_group_type_unset_specs(
|
||||
request, self.initial["id"], to_unset)
|
||||
msg = _(
|
||||
"Successfully updated group specs for share group type '%s'.")
|
||||
msg = msg % self.initial['name']
|
||||
messages.success(request, msg)
|
||||
return True
|
||||
except ValidationError as e:
|
||||
# handle error without losing dialog
|
||||
self.api_error(e.messages[0])
|
||||
return False
|
||||
except Exception:
|
||||
msg = _("Unable to update group_specs for share group type.")
|
||||
exceptions.handle(request, msg)
|
||||
return False
|
29
manila_ui/dashboards/admin/share_group_types/panel.py
Normal file
29
manila_ui/dashboards/admin/share_group_types/panel.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
from openstack_dashboard.dashboards.admin import dashboard
|
||||
|
||||
|
||||
class ShareGroupTypes(horizon.Panel):
|
||||
name = _("Share Group Types")
|
||||
slug = 'share_group_types'
|
||||
permissions = (
|
||||
'openstack.services.share',
|
||||
)
|
||||
|
||||
|
||||
dashboard.Admin.register(ShareGroupTypes)
|
111
manila_ui/dashboards/admin/share_group_types/tables.py
Normal file
111
manila_ui/dashboards/admin/share_group_types/tables.py
Normal file
@ -0,0 +1,111 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy
|
||||
from horizon import tables
|
||||
import six
|
||||
|
||||
from manila_ui.api import manila
|
||||
|
||||
|
||||
class CreateShareGroupType(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Create Share Group Type")
|
||||
url = "horizon:admin:share_group_types:create"
|
||||
classes = ("ajax-modal", "btn-create")
|
||||
icon = "plus"
|
||||
|
||||
|
||||
class DeleteShareGroupType(tables.DeleteAction):
|
||||
@staticmethod
|
||||
def action_present(count):
|
||||
return ungettext_lazy(
|
||||
u"Delete Share Group Type",
|
||||
u"Delete Share Group Types",
|
||||
count
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def action_past(count):
|
||||
return ungettext_lazy(
|
||||
u"Deleted Share Group Type",
|
||||
u"Deleted Share Group Types",
|
||||
count
|
||||
)
|
||||
|
||||
def delete(self, request, obj_id):
|
||||
manila.share_group_type_delete(request, obj_id)
|
||||
|
||||
|
||||
class ManageShareGroupTypeAccess(tables.LinkAction):
|
||||
name = "manage"
|
||||
verbose_name = _("Manage Share Group Type Access")
|
||||
url = "horizon:admin:share_group_types:manage_access"
|
||||
classes = ("ajax-modal", "btn-create")
|
||||
|
||||
def allowed(self, request, obj_id):
|
||||
sgt = manila.share_group_type_get(request, obj_id)
|
||||
# Enable it only for private share group types
|
||||
return not sgt.is_public
|
||||
|
||||
def get_policy_target(self, request, datum=None):
|
||||
project_id = None
|
||||
if datum:
|
||||
project_id = getattr(datum, "os-share-tenant-attr:tenant_id", None)
|
||||
return {"project_id": project_id}
|
||||
|
||||
|
||||
class UpdateShareGroupType(tables.LinkAction):
|
||||
name = "update share group type"
|
||||
verbose_name = _("Update Share group Type")
|
||||
url = "horizon:admin:share_group_types:update"
|
||||
classes = ("ajax-modal", "btn-create")
|
||||
|
||||
def get_policy_target(self, request, datum=None):
|
||||
project_id = None
|
||||
if datum:
|
||||
project_id = getattr(datum, "os-share-tenant-attr:tenant_id", None)
|
||||
return {"project_id": project_id}
|
||||
|
||||
|
||||
class ShareGroupTypesTable(tables.DataTable):
|
||||
name = tables.WrappingColumn("name", verbose_name=_("Name"))
|
||||
group_specs = tables.Column("group_specs", verbose_name=_("Group specs"))
|
||||
share_types = tables.Column("share_types", verbose_name=_("Share types"))
|
||||
visibility = tables.Column(
|
||||
"is_public", verbose_name=_("Visibility"),
|
||||
filters=(lambda d: 'public' if d is True else 'private', ),
|
||||
)
|
||||
|
||||
def get_object_display(self, share_group_type):
|
||||
return share_group_type.name
|
||||
|
||||
def get_object_id(self, share_group_type):
|
||||
return six.text_type(share_group_type.id)
|
||||
|
||||
class Meta(object):
|
||||
name = "share_group_types"
|
||||
verbose_name = _("Share Group Types")
|
||||
table_actions = (
|
||||
tables.NameFilterAction,
|
||||
CreateShareGroupType,
|
||||
DeleteShareGroupType,
|
||||
)
|
||||
row_actions = (
|
||||
UpdateShareGroupType,
|
||||
ManageShareGroupTypeAccess,
|
||||
DeleteShareGroupType,
|
||||
)
|
@ -0,0 +1,11 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
<h3>{% trans "Description" %}:</h3>
|
||||
<p>{% trans "The share group type defines the characteristics of a share group backend." %}
|
||||
<br /><br /><strong>Extra specs</strong> field:<br />
|
||||
{% trans "One line - one action. Empty strings will be ignored." %}<br />
|
||||
{% trans "To add group-specs use:" %}
|
||||
<pre>key=value</pre>
|
||||
</p>
|
||||
{% endblock %}
|
@ -0,0 +1,59 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block form_id %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:share_group_types:manage_access' share_group_type.id %}{% endblock %}
|
||||
|
||||
{% block modal_id %}manage_share_group_type_access_modal{% endblock %}
|
||||
{% block modal-header %}{% trans "Manage Share Group Type Access" %}{% endblock %}
|
||||
|
||||
|
||||
{% block modal-body %}
|
||||
<div class="left">
|
||||
<fieldset>
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="right">
|
||||
<h3>{% trans "Description" %}:</h3>
|
||||
<p>{% blocktrans %}
|
||||
Placeholder for description of share group type access managing form.
|
||||
{% endblocktrans %}</p>
|
||||
</div>
|
||||
<table class="table-fixed" id="projectListSortContainer">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="actions">
|
||||
<label id="selected_project_label">{% trans "Selected Projects" %}</label>
|
||||
<ul id="selected_project" class="projectlist">
|
||||
</ul>
|
||||
<label>{% trans "Available projects" %}</label>
|
||||
<ul id="available_project" class="projectlist">
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table-fixed" id="projectListIdContainer">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="actions">
|
||||
<div id="projectListId">
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="help_text">
|
||||
{{ step.get_help_text }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Submit" %}" />
|
||||
<a href="{% url 'horizon:admin:share_group_types:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
@ -0,0 +1,14 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
<h3>{% trans "Description" %}:</h3>
|
||||
<p>
|
||||
{% trans "Here can be modified group-specs for share group type." %}<br />
|
||||
{% trans "One line - one action. Empty strings will be ignored." %}<br />
|
||||
{% trans "To add group-specs use:" %}
|
||||
<pre>key=value</pre>
|
||||
{% trans "To unset group-specs use:" %}
|
||||
<pre>key</pre>
|
||||
{% trans "All pairs that are in field for left are set for this share group type." %}
|
||||
</p>
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Create Group Share Type" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/share_group_types/_create.html' %}
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Share Group Types" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ share_group_types_table.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Manage Share Group Type Access" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/share_group_types/_manage_access.html' %}
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Update Share Group Type" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/share_group_types/_update.html' %}
|
||||
{% endblock %}
|
40
manila_ui/dashboards/admin/share_group_types/urls.py
Normal file
40
manila_ui/dashboards/admin/share_group_types/urls.py
Normal file
@ -0,0 +1,40 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.conf import urls
|
||||
|
||||
from manila_ui.dashboards.admin.share_group_types import views
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
urlpatterns = [
|
||||
urls.url(
|
||||
r'^$',
|
||||
views.ShareGroupTypesView.as_view(),
|
||||
name='index'),
|
||||
urls.url(
|
||||
r'^create$',
|
||||
views.CreateShareGroupTypeView.as_view(),
|
||||
name='create'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_type_id>[^/]+)/update$',
|
||||
views.UpdateShareGroupTypeView.as_view(),
|
||||
name='update'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_type_id>[^/]+)/manage_access$',
|
||||
views.ManageShareGroupTypeAccessView.as_view(),
|
||||
name='manage_access'),
|
||||
]
|
130
manila_ui/dashboards/admin/share_group_types/views.py
Normal file
130
manila_ui/dashboards/admin/share_group_types/views.py
Normal file
@ -0,0 +1,130 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Admin views for managing share group types.
|
||||
"""
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon.utils import memoized
|
||||
from horizon import workflows
|
||||
|
||||
from manila_ui.api import manila
|
||||
from manila_ui.dashboards.admin.share_group_types import forms as sgt_forms
|
||||
from manila_ui.dashboards.admin.share_group_types import tables as sgt_tables
|
||||
import manila_ui.dashboards.admin.share_group_types.workflows as sgt_workflows
|
||||
from manila_ui.dashboards import utils as common_utils
|
||||
|
||||
|
||||
class ShareGroupTypesView(tables.MultiTableView):
|
||||
table_classes = (
|
||||
sgt_tables.ShareGroupTypesTable,
|
||||
)
|
||||
template_name = "admin/share_group_types/index.html"
|
||||
page_title = _("Share Group Types")
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_share_group_types_data(self):
|
||||
try:
|
||||
share_group_types = manila.share_group_type_list(self.request)
|
||||
except Exception:
|
||||
exceptions.handle(
|
||||
self.request, _('Unable to retrieve share group types.'))
|
||||
return []
|
||||
|
||||
share_types = manila.share_type_list(self.request)
|
||||
st_mapping = {}
|
||||
for st in share_types:
|
||||
st_mapping[st.id] = st.name
|
||||
for sgt in share_group_types:
|
||||
sgt.group_specs = common_utils.metadata_to_str(
|
||||
sgt.group_specs, 8, 45)
|
||||
sgt.share_types = ", ".join(
|
||||
[st_mapping[st] for st in sgt.share_types])
|
||||
return share_group_types
|
||||
|
||||
|
||||
class CreateShareGroupTypeView(forms.ModalFormView):
|
||||
form_class = sgt_forms.CreateShareGroupTypeForm
|
||||
form_id = "create_share_group_type"
|
||||
template_name = 'admin/share_group_types/create.html'
|
||||
modal_header = _("Create Share Group Type")
|
||||
modal_id = "create_share_group_type_modal"
|
||||
submit_label = _("Create")
|
||||
submit_url = reverse_lazy("horizon:admin:share_group_types:create")
|
||||
success_url = reverse_lazy("horizon:admin:share_group_types:index")
|
||||
page_title = _("Create Share Group Type")
|
||||
|
||||
|
||||
class ManageShareGroupTypeAccessView(workflows.WorkflowView):
|
||||
workflow_class = sgt_workflows.ManageShareGroupTypeAccessWorkflow
|
||||
template_name = "admin/share_group_types/manage_access.html"
|
||||
success_url = 'horizon:admin:share_group_types:index'
|
||||
page_title = _("Manage Share Group Type Access")
|
||||
|
||||
def get_initial(self):
|
||||
return {'id': self.kwargs["share_group_type_id"]}
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ManageShareGroupTypeAccessView, self).get_context_data(
|
||||
**kwargs)
|
||||
context['id'] = self.kwargs['share_group_type_id']
|
||||
return context
|
||||
|
||||
|
||||
class UpdateShareGroupTypeView(forms.ModalFormView):
|
||||
form_class = sgt_forms.UpdateShareGroupTypeForm
|
||||
form_id = "update_share_group_type"
|
||||
template_name = "admin/share_group_types/update.html"
|
||||
modal_header = _("Update Share Group Type")
|
||||
modal_id = "update_share_group_type_modal"
|
||||
submit_label = _("Update")
|
||||
submit_url = "horizon:admin:share_group_types:update"
|
||||
success_url = reverse_lazy("horizon:admin:share_group_types:index")
|
||||
page_title = _("Update Share Group Type")
|
||||
|
||||
def get_object(self):
|
||||
if not hasattr(self, "_object"):
|
||||
sgt_id = self.kwargs["share_group_type_id"]
|
||||
try:
|
||||
self._object = manila.share_group_type_get(
|
||||
self.request, sgt_id)
|
||||
except Exception:
|
||||
msg = _("Unable to retrieve share_gruop_type.")
|
||||
url = reverse("horizon:admin:share_group_types:index")
|
||||
exceptions.handle(self.request, msg, redirect=url)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateShareGroupTypeView, self).get_context_data(
|
||||
**kwargs)
|
||||
args = (
|
||||
self.get_object().id,
|
||||
)
|
||||
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
share_group_type = self.get_object()
|
||||
return {
|
||||
"id": self.kwargs["share_group_type_id"],
|
||||
"name": share_group_type.name,
|
||||
"group_specs": share_group_type.group_specs,
|
||||
}
|
115
manila_ui/dashboards/admin/share_group_types/workflows.py
Normal file
115
manila_ui/dashboards/admin/share_group_types/workflows.py
Normal file
@ -0,0 +1,115 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
from openstack_dashboard.api import keystone
|
||||
|
||||
from manila_ui.api import manila
|
||||
|
||||
|
||||
class AddProjectAction(workflows.MembershipAction):
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(AddProjectAction, self).__init__(request, *args, **kwargs)
|
||||
default_role_field_name = self.get_default_role_field_name()
|
||||
self.fields[default_role_field_name] = forms.CharField(required=False)
|
||||
self.fields[default_role_field_name].initial = 'member'
|
||||
|
||||
field_name = self.get_member_field_name('member')
|
||||
self.fields[field_name] = forms.MultipleChoiceField(required=False)
|
||||
share_group_type_id = self.initial['id']
|
||||
|
||||
# Get list of existing projects
|
||||
try:
|
||||
projects, __ = keystone.tenant_list(request)
|
||||
except Exception:
|
||||
err_msg = _('Unable to get list of projects.')
|
||||
exceptions.handle(request, err_msg)
|
||||
|
||||
# Get list of projects with access to this Share Group Type
|
||||
try:
|
||||
share_group_type = manila.share_group_type_get(
|
||||
request, share_group_type_id)
|
||||
self.share_group_type_name = share_group_type.name
|
||||
projects_initial = manila.share_group_type_access_list(
|
||||
request, share_group_type)
|
||||
except Exception:
|
||||
err_msg = _(
|
||||
'Unable to get information about share group type access.')
|
||||
exceptions.handle(request, err_msg)
|
||||
|
||||
self.fields[field_name].choices = [
|
||||
(project.id, project.name or project.id) for project in projects]
|
||||
self.fields[field_name].initial = [
|
||||
pr.project_id for pr in projects_initial]
|
||||
self.projects_initial = set(self.fields[field_name].initial)
|
||||
|
||||
class Meta(object):
|
||||
name = _("Projects with access to share group type")
|
||||
slug = "update_members"
|
||||
|
||||
def handle(self, request, context):
|
||||
context.update({
|
||||
'name': self.share_group_type_name,
|
||||
'projects_add': self.projects_allow - self.projects_initial,
|
||||
'projects_remove': self.projects_initial - self.projects_allow,
|
||||
})
|
||||
return context
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(AddProjectAction, self).clean()
|
||||
self.projects_allow = set(
|
||||
cleaned_data[self.get_member_field_name('member')])
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class AddProjectStep(workflows.UpdateMembersStep):
|
||||
action_class = AddProjectAction
|
||||
available_list_title = _("Available projects")
|
||||
help_text = _("Allow project access to share group type.")
|
||||
members_list_title = _("Selected projects")
|
||||
no_available_text = _("No projects found.")
|
||||
no_members_text = _("No projects selected.")
|
||||
depends_on = ("id", )
|
||||
show_roles = False
|
||||
|
||||
|
||||
class ManageShareGroupTypeAccessWorkflow(workflows.Workflow):
|
||||
slug = "manage_share_group_type_access"
|
||||
name = _("Manage Share Group Type Access")
|
||||
finalize_button_name = _("Manage Share Group Type Access")
|
||||
success_message = _('Updated access for share group type "%s".')
|
||||
failure_message = _('Unable to update access for share group type "%s".')
|
||||
success_url = 'horizon:admin:share_group_types:index'
|
||||
default_steps = (AddProjectStep, )
|
||||
|
||||
def format_status_message(self, message):
|
||||
return message % self.context['name']
|
||||
|
||||
def handle(self, request, context):
|
||||
try:
|
||||
for project in self.context['projects_remove']:
|
||||
manila.share_group_type_access_remove(
|
||||
request, self.context['id'], project)
|
||||
for project in self.context['projects_add']:
|
||||
manila.share_group_type_access_add(
|
||||
request, self.context['id'], project)
|
||||
return True
|
||||
except Exception:
|
||||
exceptions.handle(request, _('Unable to update share group type.'))
|
||||
return False
|
0
manila_ui/dashboards/admin/share_groups/__init__.py
Normal file
0
manila_ui/dashboards/admin/share_groups/__init__.py
Normal file
54
manila_ui/dashboards/admin/share_groups/forms.py
Normal file
54
manila_ui/dashboards/admin/share_groups/forms.py
Normal file
@ -0,0 +1,54 @@
|
||||
# Copyright (c) 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
|
||||
from manila_ui.api import manila
|
||||
|
||||
|
||||
class ResetShareGroupStatusForm(forms.SelfHandlingForm):
|
||||
status = forms.ChoiceField(
|
||||
label=_("Status"),
|
||||
required=True,
|
||||
choices=(
|
||||
('available', 'available'),
|
||||
('error', 'error'),
|
||||
)
|
||||
)
|
||||
|
||||
def handle(self, request, data):
|
||||
sg_id = self.initial['share_group_id']
|
||||
try:
|
||||
manila.share_group_reset_state(request, sg_id, data["status"])
|
||||
message = _(
|
||||
"Reseting share group ('%(id)s') status from '%(from)s' "
|
||||
"to '%(to)s'.") % {
|
||||
"id": (self.initial['share_group_name'] or
|
||||
self.initial['share_group_id']),
|
||||
"from": self.initial['share_group_status'],
|
||||
"to": data["status"]}
|
||||
messages.success(request, message)
|
||||
return True
|
||||
except Exception:
|
||||
redirect = reverse("horizon:admin:share_groups:index")
|
||||
exceptions.handle(
|
||||
request,
|
||||
_("Unable to reset status of share group '%s'.") % sg_id,
|
||||
redirect=redirect)
|
||||
return False
|
29
manila_ui/dashboards/admin/share_groups/panel.py
Normal file
29
manila_ui/dashboards/admin/share_groups/panel.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
from openstack_dashboard.dashboards.admin import dashboard
|
||||
|
||||
|
||||
class ShareGroups(horizon.Panel):
|
||||
name = _("Share Groups")
|
||||
slug = 'share_groups'
|
||||
permissions = (
|
||||
'openstack.services.share',
|
||||
)
|
||||
|
||||
|
||||
dashboard.Admin.register(ShareGroups)
|
127
manila_ui/dashboards/admin/share_groups/tables.py
Normal file
127
manila_ui/dashboards/admin/share_groups/tables.py
Normal file
@ -0,0 +1,127 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy
|
||||
from horizon import tables
|
||||
import six
|
||||
|
||||
from manila_ui.api import manila
|
||||
|
||||
|
||||
class DeleteShareGroup(tables.DeleteAction):
|
||||
|
||||
@staticmethod
|
||||
def action_present(count):
|
||||
return ungettext_lazy(
|
||||
u"Delete Share Group",
|
||||
u"Delete Share Groups",
|
||||
count
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def action_past(count):
|
||||
return ungettext_lazy(
|
||||
u"Deleted Share Group",
|
||||
u"Deleted Share Groups",
|
||||
count
|
||||
)
|
||||
|
||||
def delete(self, request, obj_id):
|
||||
manila.share_group_delete(request, obj_id)
|
||||
|
||||
|
||||
class ResetShareGroupStatus(tables.LinkAction):
|
||||
name = "reset_share_group_status"
|
||||
verbose_name = _("Reset status")
|
||||
url = "horizon:admin:share_groups:reset_status"
|
||||
classes = ("ajax-modal", "btn-create")
|
||||
|
||||
def allowed(self, request, share_group=None):
|
||||
return True
|
||||
|
||||
|
||||
class ShareGroupsTable(tables.DataTable):
|
||||
def get_share_network_link(share_group):
|
||||
if getattr(share_group, 'share_network_id', None):
|
||||
return reverse("horizon:admin:share_networks:share_network_detail",
|
||||
args=(share_group.share_network_id,))
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_share_server_link(share_group):
|
||||
if getattr(share_group, 'share_server_id', None):
|
||||
return reverse("horizon:admin:share_servers:share_server_detail",
|
||||
args=(share_group.share_server_id,))
|
||||
else:
|
||||
return None
|
||||
|
||||
STATUS_CHOICES = (
|
||||
("available", True),
|
||||
("creating", None),
|
||||
("deleting", None),
|
||||
("error", False),
|
||||
("error_deleting", False),
|
||||
)
|
||||
STATUS_DISPLAY_CHOICES = (
|
||||
("available", u"Available"),
|
||||
("creating", u"Creating"),
|
||||
("deleting", u"Deleting"),
|
||||
("error", u"Error"),
|
||||
("error_deleting", u"Error deleting"),
|
||||
)
|
||||
name = tables.Column(
|
||||
"name",
|
||||
verbose_name=_("Name"),
|
||||
link="horizon:admin:share_groups:detail")
|
||||
host = tables.Column("host", verbose_name=_("Host"))
|
||||
status = tables.Column(
|
||||
"status",
|
||||
verbose_name=_("Status"),
|
||||
status=True,
|
||||
status_choices=STATUS_CHOICES,
|
||||
display_choices=STATUS_DISPLAY_CHOICES,
|
||||
)
|
||||
availability_zone = tables.Column(
|
||||
"availability_zone",
|
||||
verbose_name=_("Availability Zone"))
|
||||
share_network_id = tables.Column(
|
||||
"share_network_id",
|
||||
verbose_name=_("Share Network"),
|
||||
link=get_share_network_link)
|
||||
share_server_id = tables.Column(
|
||||
"share_server_id",
|
||||
verbose_name=_("Share Server"),
|
||||
link=get_share_server_link)
|
||||
|
||||
def get_object_display(self, share_group):
|
||||
return six.text_type(share_group.id)
|
||||
|
||||
def get_object_id(self, share_group):
|
||||
return six.text_type(share_group.id)
|
||||
|
||||
class Meta(object):
|
||||
name = "share_groups"
|
||||
verbose_name = _("Share Groups")
|
||||
status_columns = ("status", )
|
||||
table_actions = (
|
||||
tables.NameFilterAction,
|
||||
DeleteShareGroup,
|
||||
)
|
||||
row_actions = (
|
||||
ResetShareGroupStatus,
|
||||
DeleteShareGroup,
|
||||
)
|
33
manila_ui/dashboards/admin/share_groups/tabs.py
Normal file
33
manila_ui/dashboards/admin/share_groups/tabs.py
Normal file
@ -0,0 +1,33 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
|
||||
class ShareGroupOverviewTab(tabs.Tab):
|
||||
name = _("Share Group Overview")
|
||||
slug = "share_group_overview_tab"
|
||||
template_name = "admin/share_groups/_detail.html"
|
||||
|
||||
def get_context_data(self, request):
|
||||
return {"share_group": self.tab_group.kwargs["share_group"]}
|
||||
|
||||
|
||||
class ShareGroupDetailTabs(tabs.TabGroup):
|
||||
slug = "share_group_details"
|
||||
tabs = (
|
||||
ShareGroupOverviewTab,
|
||||
)
|
@ -0,0 +1,61 @@
|
||||
{% load i18n sizeformat parse_date %}
|
||||
|
||||
<h3>{% trans "Share Group Overview" %}</h3>
|
||||
<div class="detail">
|
||||
<hr class="header_rule">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ share_group.id }}</dd>
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ share_group.name }}</dd>
|
||||
<dt>{% trans "Description" %}</dt>
|
||||
<dd>{{ share_group.description }}</dd>
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>{{ share_group.status|capfirst }}</dd>
|
||||
<dt>{% trans "Created" %}</dt>
|
||||
<dd>{{ share_group.created_at|parse_date }}</dd>
|
||||
<dt>{% trans "Host" %}</dt>
|
||||
<dd>{{ share_group.host}}</dd>
|
||||
{% if share_group.source_share_group_snapshot_id %}
|
||||
<dt>{% trans "Source share group snapshot" %}</dt>
|
||||
<dd>{{ share_group.source_share_group_snapshot_id}}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Share Group Type" %}</dt>
|
||||
<dd>{{ share_group.share_group_type_id}}</dd>
|
||||
{% if share_group.availability_zone %}
|
||||
<dt>{% trans "Availability Zone" %}</dt>
|
||||
<dd>{{ share_group.availability_zone }}</dd>
|
||||
{% endif %}
|
||||
{% if share_group.share_network_id %}
|
||||
<dt>{% trans "Share network" %}</dt>
|
||||
{% url 'horizon:admin:share_networks:share_network_detail' share_group.share_network_id as sn_url%}
|
||||
<dd><a href="{{ sn_url }}">{{ share_group.share_network_id }}</a></dd>
|
||||
{% endif %}
|
||||
{% if share_group.share_server_id %}
|
||||
<dt>{% trans "Share server" %}</dt>
|
||||
{% url 'horizon:admin:share_servers:share_server_detail' share_group.share_server_id as share_server_url%}
|
||||
<dd><a href="{{ share_server_url }}">{{ share_group.share_server_id }}</a></dd>
|
||||
{% endif %}
|
||||
{% if share_group.share_types %}
|
||||
<dt>{% trans "Share Types" %}</dt>
|
||||
{% for st in share_group.share_types %}
|
||||
<dd><p>
|
||||
<div><b>Share Type Name:</b> {{ st.name }}</div>
|
||||
<div><b>Share Type Visibility:</b> {% if st.is_public %}Public{% else %}Private{% endif %}</div>
|
||||
<div><b>Network handling enabled:</b> {{ st.dhss }}</div>
|
||||
</p></dd>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if share_group.members %}
|
||||
<dt>{% trans "Shares" %}</dt>
|
||||
{% for m in share_group.members %}
|
||||
{% url 'horizon:admin:shares:detail' m.id as share_url%}
|
||||
<dd>
|
||||
<div>
|
||||
<a href="{{ share_url }}">{% if m.name %}{{ m.name }}{% else %}{{ m.id }}{% endif %}</a>
|
||||
</div>
|
||||
</dd>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
@ -0,0 +1,5 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
<p>"Reset status of <b>'{{ share_group_name }}'</b> share group."</p>
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Share Group Details" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Share Groups" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ share_groups_table.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Reset Share Group Status" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/share_groups/_reset_status.html' %}
|
||||
{% endblock %}
|
36
manila_ui/dashboards/admin/share_groups/urls.py
Normal file
36
manila_ui/dashboards/admin/share_groups/urls.py
Normal file
@ -0,0 +1,36 @@
|
||||
# Copyright 2017 Mirantis Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.conf import urls
|
||||
|
||||
from manila_ui.dashboards.admin.share_groups import views
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
urlpatterns = [
|
||||
urls.url(
|
||||
r'^$',
|
||||
views.ShareGroupsView.as_view(),
|
||||
name='index'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_id>[^/]+)/$',
|
||||
views.ShareGroupDetailView.as_view(),
|
||||
name='detail'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_id>[^/]+)/reset_status$',
|
||||
views.ResetShareGroupStatusView.as_view(),
|
||||
name='reset_status'),
|
||||
]
|
133
manila_ui/dashboards/admin/share_groups/views.py
Normal file
133
manila_ui/dashboards/admin/share_groups/views.py
Normal file
@ -0,0 +1,133 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Admin views for managing share groups.
|
||||
"""
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon.utils import memoized
|
||||
|
||||
from manila_ui.api import manila
|
||||
from manila_ui.dashboards.admin.share_groups import forms as sg_forms
|
||||
from manila_ui.dashboards.admin.share_groups import tables as sg_tables
|
||||
from manila_ui.dashboards.admin.share_groups import tabs as sg_tabs
|
||||
|
||||
|
||||
class ShareGroupsView(tables.MultiTableView):
|
||||
table_classes = (
|
||||
sg_tables.ShareGroupsTable,
|
||||
)
|
||||
template_name = "admin/share_groups/index.html"
|
||||
page_title = _("Share Groups")
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_share_groups_data(self):
|
||||
try:
|
||||
share_groups = manila.share_group_list(
|
||||
self.request, detailed=True)
|
||||
except Exception:
|
||||
share_groups = []
|
||||
exceptions.handle(
|
||||
self.request, _("Unable to retrieve share groups."))
|
||||
return share_groups
|
||||
|
||||
|
||||
class ShareGroupDetailView(tabs.TabView):
|
||||
tab_group_class = sg_tabs.ShareGroupDetailTabs
|
||||
template_name = 'admin/share_groups/detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(self.__class__, self).get_context_data(**kwargs)
|
||||
share_group = self.get_data()
|
||||
context["share_group"] = share_group
|
||||
context["page_title"] = (
|
||||
_("Share Group Details: %s") % share_group.id)
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
share_group_id = self.kwargs['share_group_id']
|
||||
share_group = manila.share_group_get(self.request, share_group_id)
|
||||
members = manila.share_list(
|
||||
self.request, search_opts={"share_group_id": share_group_id})
|
||||
share_group.members = members
|
||||
share_types = manila.share_type_list(self.request)
|
||||
share_group.share_types = [
|
||||
{"id": st.id,
|
||||
"name": st.name,
|
||||
"is_public": getattr(st, 'share_type_access:is_public'),
|
||||
"dhss": st.extra_specs.get('driver_handles_share_servers')}
|
||||
for st in share_types if st.id in share_group.share_types
|
||||
]
|
||||
return share_group
|
||||
except Exception:
|
||||
redirect = reverse('horizon:admin:share_groups:index')
|
||||
exceptions.handle(
|
||||
self.request,
|
||||
_('Unable to retrieve share group details.'),
|
||||
redirect=redirect)
|
||||
|
||||
def get_tabs(self, request, *args, **kwargs):
|
||||
share_group = self.get_data()
|
||||
return self.tab_group_class(request, share_group=share_group, **kwargs)
|
||||
|
||||
|
||||
class ResetShareGroupStatusView(forms.ModalFormView):
|
||||
form_class = sg_forms.ResetShareGroupStatusForm
|
||||
form_id = "reset_share_group_status"
|
||||
template_name = 'admin/share_groups/reset_status.html'
|
||||
modal_header = _("Reset Status")
|
||||
modal_id = "reset_share_group_status_modal"
|
||||
submit_label = _("Reset status")
|
||||
submit_url = "horizon:admin:share_groups:reset_status"
|
||||
success_url = reverse_lazy("horizon:admin:share_groups:index")
|
||||
page_title = _("Reset Share Group Status")
|
||||
|
||||
def get_object(self):
|
||||
if not hasattr(self, "_object"):
|
||||
sg_id = self.kwargs["share_group_id"]
|
||||
try:
|
||||
self._object = manila.share_group_get(self.request, sg_id)
|
||||
except Exception:
|
||||
msg = _("Unable to retrieve share group '%s'.") % sg_id
|
||||
url = reverse('horizon:admin:share_groups:index')
|
||||
exceptions.handle(self.request, msg, redirect=url)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(self.__class__, self).get_context_data(**kwargs)
|
||||
sg = self.get_object()
|
||||
context['share_group_id'] = self.kwargs['share_group_id']
|
||||
context['share_group_name'] = sg.name or sg.id
|
||||
context['share_group_status'] = sg.status
|
||||
context['submit_url'] = reverse(
|
||||
self.submit_url, args=(context['share_group_id'], ))
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
sg = self.get_object()
|
||||
return {
|
||||
"share_group_id": self.kwargs["share_group_id"],
|
||||
"share_group_name": sg.name or sg.id,
|
||||
"share_group_status": sg.status,
|
||||
}
|
@ -14,8 +14,8 @@ from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
|
||||
from manila_ui.api import manila
|
||||
from manila_ui.dashboards.project.shares import tables as shares_tables
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
class MigrationStartAction(tables.LinkAction):
|
||||
@ -30,7 +30,7 @@ class MigrationStartAction(tables.LinkAction):
|
||||
if share:
|
||||
return (share.status.upper() == "AVAILABLE" and
|
||||
not getattr(share, 'has_snapshot', False) and
|
||||
manila.is_migration_enabled())
|
||||
features.is_migration_enabled())
|
||||
return False
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ class MigrationCompleteAction(tables.LinkAction):
|
||||
|
||||
def allowed(self, request, share=None):
|
||||
if (share and share.status.upper() == "MIGRATING" and
|
||||
manila.is_migration_enabled()):
|
||||
features.is_migration_enabled()):
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -59,7 +59,7 @@ class MigrationCancelAction(tables.LinkAction):
|
||||
|
||||
def allowed(self, request, share=None):
|
||||
if (share and share.status.upper() == "MIGRATING" and
|
||||
manila.is_migration_enabled()):
|
||||
features.is_migration_enabled()):
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -74,7 +74,7 @@ class MigrationGetProgressAction(tables.LinkAction):
|
||||
|
||||
def allowed(self, request, share=None):
|
||||
if (share and share.status.upper() == "MIGRATING" and
|
||||
manila.is_migration_enabled()):
|
||||
features.is_migration_enabled()):
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -115,7 +115,7 @@ class ManageReplicas(tables.LinkAction):
|
||||
|
||||
def allowed(self, request, share):
|
||||
share_replication_enabled = share.replication_type is not None
|
||||
return manila.is_replication_enabled() and share_replication_enabled
|
||||
return features.is_replication_enabled() and share_replication_enabled
|
||||
|
||||
|
||||
class SharesTable(shares_tables.SharesTable):
|
||||
@ -156,7 +156,9 @@ class SharesTable(shares_tables.SharesTable):
|
||||
UnmanageShareAction,
|
||||
shares_tables.DeleteShare,
|
||||
)
|
||||
columns = (
|
||||
columns = [
|
||||
'tenant', 'host', 'name', 'size', 'status', 'visibility',
|
||||
'share_type', 'protocol', 'share_server',
|
||||
)
|
||||
]
|
||||
if features.is_share_groups_enabled():
|
||||
columns.append('share_group_id')
|
||||
|
@ -57,10 +57,15 @@
|
||||
</p></dd>
|
||||
{% endif %}
|
||||
{% if share.share_network_id %}
|
||||
<dt>{% trans "Share network" %}</dt>
|
||||
<dt>{% trans "Share Network" %}</dt>
|
||||
{% url 'horizon:admin:share_networks:share_network_detail' share.share_network_id as sn_url%}
|
||||
<dd><a href="{{ sn_url }}">{{ share.share_network_id }}</a></dd>
|
||||
{% endif %}
|
||||
{% if share.share_group_id %}
|
||||
<dt>{% trans "Share Group" %}</dt>
|
||||
{% url 'horizon:admin:share_groups:detail' share.share_group_id as sg_url%}
|
||||
<dd><a href="{{ sg_url }}">{{ share.share_group_id }}</a></dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Mount snapshot support" %}</dt>
|
||||
<dd>{{ share.mount_snapshot_support }}</dd>
|
||||
<dt>{% trans "Created" %}</dt>
|
||||
|
@ -12,9 +12,9 @@
|
||||
|
||||
from django.conf import urls
|
||||
|
||||
from manila_ui.api import manila
|
||||
from manila_ui.dashboards.admin.shares.replicas import views as replica_views
|
||||
from manila_ui.dashboards.admin.shares import views
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
@ -36,7 +36,7 @@ urlpatterns = [
|
||||
name='unmanage'),
|
||||
]
|
||||
|
||||
if manila.is_replication_enabled():
|
||||
if features.is_replication_enabled():
|
||||
urlpatterns.extend([
|
||||
urls.url(
|
||||
r'^(?P<share_id>[^/]+)/replicas/$',
|
||||
@ -60,7 +60,7 @@ if manila.is_replication_enabled():
|
||||
name='reset_replica_state'),
|
||||
])
|
||||
|
||||
if manila.is_migration_enabled():
|
||||
if features.is_migration_enabled():
|
||||
urlpatterns.extend([
|
||||
urls.url(
|
||||
r'^migration_start/(?P<share_id>[^/]+)$',
|
||||
|
75
manila_ui/dashboards/project/share_group_snapshots/forms.py
Normal file
75
manila_ui/dashboards/project/share_group_snapshots/forms.py
Normal file
@ -0,0 +1,75 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
|
||||
from manila_ui.api import manila
|
||||
|
||||
|
||||
class CreateShareGroupSnapshotForm(forms.SelfHandlingForm):
|
||||
name = forms.CharField(max_length="255", label=_("Name"), required=True)
|
||||
description = forms.CharField(
|
||||
widget=forms.Textarea,
|
||||
label=_("Description"),
|
||||
required=False)
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(request, *args, **kwargs)
|
||||
# populate share_group_id
|
||||
sg_id = kwargs.get('initial', {}).get('share_group_id', [])
|
||||
self.fields['share_group_id'] = forms.CharField(
|
||||
widget=forms.HiddenInput(), initial=sg_id)
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
snapshot = manila.share_group_snapshot_create(
|
||||
request,
|
||||
data['share_group_id'], data['name'], data['description'])
|
||||
message = _('Creating share group snapshot "%s".') % data['name']
|
||||
messages.success(request, message)
|
||||
return snapshot
|
||||
except Exception:
|
||||
redirect = reverse("horizon:project:share_group_snapshots:index")
|
||||
exceptions.handle(
|
||||
request,
|
||||
_('Unable to create share group snapshot.'),
|
||||
redirect=redirect)
|
||||
return False
|
||||
|
||||
|
||||
class UpdateShareGroupSnapshotForm(forms.SelfHandlingForm):
|
||||
name = forms.CharField(
|
||||
max_length="255", label=_("Name"))
|
||||
description = forms.CharField(
|
||||
widget=forms.Textarea, label=_("Description"), required=False)
|
||||
|
||||
def handle(self, request, data):
|
||||
sgs_id = self.initial['share_group_snapshot_id']
|
||||
try:
|
||||
manila.share_group_snapshot_update(
|
||||
request, sgs_id, data['name'], data['description'])
|
||||
message = _('Updating share group snapshot "%s"') % data['name']
|
||||
messages.success(request, message)
|
||||
return True
|
||||
except Exception:
|
||||
redirect = reverse("horizon:project:share_group_snapshots:index")
|
||||
exceptions.handle(
|
||||
request, _('Unable to update share group snapshot.'),
|
||||
redirect=redirect)
|
||||
return False
|
29
manila_ui/dashboards/project/share_group_snapshots/panel.py
Normal file
29
manila_ui/dashboards/project/share_group_snapshots/panel.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
from openstack_dashboard.dashboards.project import dashboard
|
||||
|
||||
|
||||
class ShareGroupSnapshots(horizon.Panel):
|
||||
name = _("Share Group Snapshots")
|
||||
slug = 'share_group_snapshots'
|
||||
permissions = (
|
||||
'openstack.services.share',
|
||||
)
|
||||
|
||||
|
||||
dashboard.Project.register(ShareGroupSnapshots)
|
173
manila_ui/dashboards/project/share_group_snapshots/tables.py
Normal file
173
manila_ui/dashboards/project/share_group_snapshots/tables.py
Normal file
@ -0,0 +1,173 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template.defaultfilters import title # noqa
|
||||
from django.utils.http import urlencode # noqa
|
||||
from django.utils.translation import pgettext_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy
|
||||
from horizon import exceptions
|
||||
from horizon import tables
|
||||
from horizon.utils import filters
|
||||
|
||||
from manila_ui.api import manila
|
||||
|
||||
|
||||
class UpdateShareGroupSnapshot(tables.LinkAction):
|
||||
name = "update_share_group_snapshot"
|
||||
verbose_name = _("Update")
|
||||
url = "horizon:project:share_group_snapshots:update"
|
||||
classes = ("ajax-modal", "btn-camera")
|
||||
|
||||
def allowed(self, request, share_group_snapshot=None):
|
||||
return share_group_snapshot.status in ("available", "error")
|
||||
|
||||
|
||||
class CreateShareGroupSnapshot(tables.LinkAction):
|
||||
name = "create_share_group_snapshot"
|
||||
verbose_name = _("Create Share Group Snapshot")
|
||||
url = "horizon:project:share_group_snapshots:create"
|
||||
classes = ("ajax-modal", "btn-camera")
|
||||
|
||||
def allowed(self, request, share_group=None):
|
||||
self.verbose_name = _("Create Share Group Snapshot")
|
||||
classes = [c for c in self.classes if c != "disabled"]
|
||||
self.classes = classes
|
||||
return share_group.status == "available"
|
||||
|
||||
|
||||
class CreateShareGroupFromSnapshot(tables.LinkAction):
|
||||
name = "create_share_group_from_snapshot"
|
||||
verbose_name = _("Create Share Group")
|
||||
url = "horizon:project:share_groups:create"
|
||||
classes = ("ajax-modal", "btn-camera")
|
||||
|
||||
def get_link_url(self, datum):
|
||||
base_url = reverse(self.url)
|
||||
params = urlencode({
|
||||
"snapshot_id": self.table.get_object_id(datum)})
|
||||
return "?".join([base_url, params])
|
||||
|
||||
def allowed(self, request, share_group=None):
|
||||
return share_group.status == "available"
|
||||
|
||||
|
||||
class ShareGroupSnapshotShareGroupNameColumn(tables.Column):
|
||||
def get_link_url(self, snapshot):
|
||||
return reverse(self.link, args=(snapshot.share_group_id,))
|
||||
|
||||
|
||||
class DeleteShareGroupSnapshot(tables.DeleteAction):
|
||||
|
||||
@staticmethod
|
||||
def action_present(count):
|
||||
return ungettext_lazy(
|
||||
u"Delete Share Group Snapshot",
|
||||
u"Delete Share Group Snapshots",
|
||||
count
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def action_past(count):
|
||||
return ungettext_lazy(
|
||||
u"Deleted Share Group Snapshot",
|
||||
u"Deleted Share Group Snapshots",
|
||||
count
|
||||
)
|
||||
|
||||
def delete(self, request, obj_id):
|
||||
obj = self.table.get_object_by_id(obj_id)
|
||||
name = self.table.get_object_display(obj)
|
||||
try:
|
||||
manila.share_group_snapshot_delete(request, obj_id)
|
||||
except Exception:
|
||||
msg = _('Unable to delete share group snapshot "%s". '
|
||||
'One or more share groups depend on it.')
|
||||
exceptions.check_message(["snapshots", "dependent"], msg % name)
|
||||
raise
|
||||
|
||||
def allowed(self, request, snapshot=None):
|
||||
if snapshot:
|
||||
return snapshot.status.lower() in ('available', 'error')
|
||||
return True
|
||||
|
||||
|
||||
class UpdateShareGroupSnapshotRow(tables.Row):
|
||||
ajax = True
|
||||
|
||||
def get_data(self, request, share_group_snapshot_id):
|
||||
snapshot = manila.share_group_snapshot_get(
|
||||
request, share_group_snapshot_id)
|
||||
if not snapshot.name:
|
||||
snapshot.name = share_group_snapshot_id
|
||||
return snapshot
|
||||
|
||||
|
||||
class ShareGroupSnapshotsTable(tables.DataTable):
|
||||
STATUS_CHOICES = (
|
||||
("available", True),
|
||||
("creating", None),
|
||||
("error", False),
|
||||
)
|
||||
STATUS_DISPLAY_CHOICES = (
|
||||
("available",
|
||||
pgettext_lazy("Current status of snapshot", u"Available")),
|
||||
("creating", pgettext_lazy("Current status of snapshot", u"Creating")),
|
||||
("error", pgettext_lazy("Current status of snapshot", u"Error")),
|
||||
)
|
||||
name = tables.WrappingColumn(
|
||||
"name", verbose_name=_("Name"),
|
||||
link="horizon:project:share_group_snapshots:detail")
|
||||
description = tables.Column(
|
||||
"description",
|
||||
verbose_name=_("Description"),
|
||||
truncate=40)
|
||||
created_at = tables.Column(
|
||||
"created_at",
|
||||
verbose_name=_("Created at"),
|
||||
filters=(
|
||||
filters.parse_isotime,
|
||||
))
|
||||
status = tables.Column(
|
||||
"status",
|
||||
filters=(title,),
|
||||
verbose_name=_("Status"),
|
||||
status=True,
|
||||
status_choices=STATUS_CHOICES,
|
||||
display_choices=STATUS_DISPLAY_CHOICES)
|
||||
source = ShareGroupSnapshotShareGroupNameColumn(
|
||||
"share_group",
|
||||
verbose_name=_("Source"),
|
||||
link="horizon:project:share_groups:detail")
|
||||
|
||||
def get_object_display(self, obj):
|
||||
return obj.name
|
||||
|
||||
class Meta(object):
|
||||
name = "share_group_snapshots"
|
||||
verbose_name = _("Share Group Snapshots")
|
||||
status_columns = ["status"]
|
||||
row_class = UpdateShareGroupSnapshotRow
|
||||
table_actions = (
|
||||
tables.NameFilterAction,
|
||||
DeleteShareGroupSnapshot,
|
||||
)
|
||||
row_actions = (
|
||||
CreateShareGroupFromSnapshot,
|
||||
UpdateShareGroupSnapshot,
|
||||
DeleteShareGroupSnapshot,
|
||||
)
|
34
manila_ui/dashboards/project/share_group_snapshots/tabs.py
Normal file
34
manila_ui/dashboards/project/share_group_snapshots/tabs.py
Normal file
@ -0,0 +1,34 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
|
||||
class ShareGroupSnapshotOverviewTab(tabs.Tab):
|
||||
name = _("Share Group Snapshot Overview")
|
||||
slug = "share_group_snapshot_overview_tab"
|
||||
template_name = "project/share_group_snapshots/_detail.html"
|
||||
|
||||
def get_context_data(self, request):
|
||||
return {"share_group_snapshot": self.tab_group.kwargs[
|
||||
"share_group_snapshot"]}
|
||||
|
||||
|
||||
class ShareGroupSnapshotDetailTabs(tabs.TabGroup):
|
||||
slug = "share_group_snapshot_details"
|
||||
tabs = (
|
||||
ShareGroupSnapshotOverviewTab,
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
<div>
|
||||
Please, choose a name for the new share group snapshot,
|
||||
that will be created from <b>'{{ share_group_name }}'</b> share group.
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,23 @@
|
||||
{% load i18n sizeformat parse_date %}
|
||||
|
||||
<h3>{% trans "Share Group Snapshot Overview" %}</h3>
|
||||
<div class="detail">
|
||||
<hr class="header_rule">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ share_group_snapshot.name }}</dd>
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ share_group_snapshot.id }}</dd>
|
||||
{% url 'horizon:project:share_groups:detail' share_group_snapshot.share_group_id as sg_url %}
|
||||
<dt>{% trans "Source Share Group" %}</dt>
|
||||
<dd><a href="{{ sg_url }}">{{ share_group_snapshot.sg_name_or_id }}</a></dd>
|
||||
{% if share_group_snapshot.description %}
|
||||
<dt>{% trans "Description" %}</dt>
|
||||
<dd>{{ share_group_snapshot.description }}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>{{ share_group_snapshot.status|capfirst }}</dd>
|
||||
<dt>{% trans "Created" %}</dt>
|
||||
<dd>{{ share_group_snapshot.created_at|parse_date }}</dd>
|
||||
</dl>
|
||||
</div>
|
@ -0,0 +1,6 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
<h3>{% trans "Description" %}:</h3>
|
||||
<p>{% trans "From here you can modify name and description of a share group snapshot." %}</p>
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Create Share Group Snapshot" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'project/share_group_snapshots/_create.html' %}
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Share Group Snapshot Details" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Share Group Snapshots" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ share_group_snapshots_table.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Update Share Group Snapshot" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'project/share_group_snapshots/_update.html' %}
|
||||
{% endblock %}
|
40
manila_ui/dashboards/project/share_group_snapshots/urls.py
Normal file
40
manila_ui/dashboards/project/share_group_snapshots/urls.py
Normal file
@ -0,0 +1,40 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.conf import urls
|
||||
|
||||
from manila_ui.dashboards.project.share_group_snapshots import views
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
urlpatterns = [
|
||||
urls.url(
|
||||
r'^$',
|
||||
views.ShareGroupSnapshotsView.as_view(),
|
||||
name='index'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_id>[^/]+)/snapshot_create/$',
|
||||
views.CreateShareGroupSnapshotView.as_view(),
|
||||
name='create'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_snapshot_id>[^/]+)/$',
|
||||
views.ShareGroupSnapshotDetailView.as_view(),
|
||||
name='detail'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_snapshot_id>[^/]+)/update/$',
|
||||
views.UpdateShareGroupSnapshotView.as_view(),
|
||||
name='update'),
|
||||
]
|
164
manila_ui/dashboards/project/share_group_snapshots/views.py
Normal file
164
manila_ui/dashboards/project/share_group_snapshots/views.py
Normal file
@ -0,0 +1,164 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Project views for managing share group snapshots.
|
||||
"""
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon.utils import memoized
|
||||
|
||||
from manila_ui.api import manila
|
||||
import manila_ui.dashboards.project.share_group_snapshots.forms as sgs_forms
|
||||
import manila_ui.dashboards.project.share_group_snapshots.tables as sgs_tables
|
||||
import manila_ui.dashboards.project.share_group_snapshots.tabs as sgs_tabs
|
||||
|
||||
|
||||
class ShareGroupSnapshotsView(tables.MultiTableView):
|
||||
table_classes = (
|
||||
sgs_tables.ShareGroupSnapshotsTable,
|
||||
)
|
||||
template_name = "project/share_group_snapshots/index.html"
|
||||
page_title = _("Share Group Snapshots")
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_share_group_snapshots_data(self):
|
||||
share_group_snapshots = []
|
||||
try:
|
||||
share_group_snapshots = manila.share_group_snapshot_list(
|
||||
self.request, search_opts={'all_tenants': True})
|
||||
share_groups = manila.share_group_list(self.request)
|
||||
sg_names = dict([(sg.id, sg.name or sg.id) for sg in share_groups])
|
||||
for snapshot in share_group_snapshots:
|
||||
snapshot.share_group = sg_names.get(snapshot.share_group_id)
|
||||
except Exception:
|
||||
msg = _("Unable to retrieve share group snapshot list.")
|
||||
exceptions.handle(self.request, msg)
|
||||
|
||||
return share_group_snapshots
|
||||
|
||||
|
||||
class ShareGroupSnapshotDetailView(tabs.TabView):
|
||||
tab_group_class = sgs_tabs.ShareGroupSnapshotDetailTabs
|
||||
template_name = "project/share_group_snapshots/detail.html"
|
||||
redirect_url = reverse_lazy("horizon:project:share_group_snapshots:index")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ShareGroupSnapshotDetailView, self).get_context_data(
|
||||
**kwargs)
|
||||
snapshot = self.get_data()
|
||||
snapshot_display_name = snapshot.name or snapshot.id
|
||||
context["snapshot"] = snapshot
|
||||
context["snapshot_display_name"] = snapshot_display_name
|
||||
context["page_title"] = _(
|
||||
"Share Group Snapshot Details: %(sgs_display_name)s") % (
|
||||
{'sgs_display_name': snapshot_display_name})
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
share_group_snapshot = manila.share_group_snapshot_get(
|
||||
self.request, self.kwargs['share_group_snapshot_id'])
|
||||
sg = manila.share_group_get(
|
||||
self.request, share_group_snapshot.share_group_id)
|
||||
share_group_snapshot.sg_name_or_id = sg.name or sg.id
|
||||
except Exception:
|
||||
exceptions.handle(
|
||||
self.request,
|
||||
_('Unable to retrieve share group snapshot details.'),
|
||||
redirect=self.redirect_url)
|
||||
return share_group_snapshot
|
||||
|
||||
def get_tabs(self, request, *args, **kwargs):
|
||||
return self.tab_group_class(
|
||||
request, share_group_snapshot=self.get_data(), **kwargs)
|
||||
|
||||
|
||||
class CreateShareGroupSnapshotView(forms.ModalFormView):
|
||||
form_class = sgs_forms.CreateShareGroupSnapshotForm
|
||||
form_id = "create_share_group_snapshot"
|
||||
template_name = 'project/share_group_snapshots/create.html'
|
||||
modal_header = _("Create Share Group Snapshot")
|
||||
modal_id = "create_share_group_snapshot_modal"
|
||||
submit_label = _("Create Share Group Snapshot")
|
||||
submit_url = "horizon:project:share_group_snapshots:create"
|
||||
success_url = reverse_lazy('horizon:project:share_group_snapshots:index')
|
||||
page_title = _('Create Share Group Snapshot')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(self.__class__, self).get_context_data(**kwargs)
|
||||
sg_id = self.kwargs['share_group_id']
|
||||
try:
|
||||
sg = manila.share_group_get(self.request, sg_id)
|
||||
context['share_group_name'] = sg.name or sg_id
|
||||
except Exception:
|
||||
exceptions.handle(
|
||||
self.request,
|
||||
_("Unable to get the specified share group '%s' for "
|
||||
"snapshot creation.") % sg_id)
|
||||
context['share_group_name'] = sg_id
|
||||
context['share_group_id'] = sg_id
|
||||
# TODO(vponomaryov): add support of quotas when it is implemented
|
||||
# for share group snapshots on server side.
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
self.submit_url = reverse(self.submit_url, kwargs=self.kwargs)
|
||||
return {'share_group_id': self.kwargs["share_group_id"]}
|
||||
|
||||
|
||||
class UpdateShareGroupSnapshotView(forms.ModalFormView):
|
||||
form_class = sgs_forms.UpdateShareGroupSnapshotForm
|
||||
form_id = "update_share_group_snapshot"
|
||||
template_name = 'project/share_group_snapshots/update.html'
|
||||
modal_header = _("Update Share Group Snapshot")
|
||||
modal_id = "update_share_group_snapshot_modal"
|
||||
submit_label = _("Update")
|
||||
submit_url = "horizon:project:share_group_snapshots:update"
|
||||
success_url = reverse_lazy('horizon:project:share_group_snapshots:index')
|
||||
page_title = _('Update Share Group')
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_object(self):
|
||||
if not hasattr(self, "_object"):
|
||||
try:
|
||||
self._object = manila.share_group_snapshot_get(
|
||||
self.request, self.kwargs['share_group_snapshot_id'])
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve share group snapshot.')
|
||||
url = reverse('horizon:project:share_group_snapshots:index')
|
||||
exceptions.handle(self.request, msg, redirect=url)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(self.__class__, self).get_context_data(**kwargs)
|
||||
args = (self.get_object().id,)
|
||||
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
snapshot = self.get_object()
|
||||
return {
|
||||
'share_group_snapshot_id': self.kwargs["share_group_snapshot_id"],
|
||||
'name': snapshot.name,
|
||||
'description': snapshot.description,
|
||||
}
|
265
manila_ui/dashboards/project/share_groups/forms.py
Normal file
265
manila_ui/dashboards/project/share_groups/forms.py
Normal file
@ -0,0 +1,265 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.forms import ValidationError # noqa
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from horizon.utils import memoized
|
||||
import six
|
||||
|
||||
from manila_ui.api import manila
|
||||
|
||||
|
||||
class CreateShareGroupForm(forms.SelfHandlingForm):
|
||||
name = forms.CharField(label=_("Name"), max_length="255", required=True)
|
||||
description = forms.CharField(
|
||||
label=_("Description"),
|
||||
max_length="255",
|
||||
widget=forms.Textarea(attrs={"rows": 3}),
|
||||
required=False)
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(CreateShareGroupForm, self).__init__(request, *args, **kwargs)
|
||||
self.st_field_name_prefix = "share-type-choices-"
|
||||
self.fields["source_type"] = forms.ChoiceField(
|
||||
label=_("Source Type"),
|
||||
widget=forms.Select(attrs={
|
||||
"class": "switchable",
|
||||
"data-slug": "source",
|
||||
}),
|
||||
required=False)
|
||||
|
||||
self.fields["snapshot"] = forms.ChoiceField(
|
||||
label=_("Use share group snapshot as a source"),
|
||||
widget=forms.SelectWidget(attrs={
|
||||
"class": "switched",
|
||||
"data-switch-on": "source",
|
||||
"data-source-snapshot": _("Share Group Snapshot"),
|
||||
}),
|
||||
required=True)
|
||||
|
||||
if ("snapshot_id" in request.GET or
|
||||
kwargs.get("data", {}).get("snapshot")):
|
||||
try:
|
||||
snapshot = self.get_share_group_snapshot(
|
||||
request,
|
||||
request.GET.get(
|
||||
"snapshot_id",
|
||||
kwargs.get("data", {}).get("snapshot")))
|
||||
self.fields["name"].initial = snapshot.name
|
||||
self.fields["snapshot"].choices = (
|
||||
(snapshot.id, snapshot.name or snapshot.id),
|
||||
)
|
||||
try:
|
||||
# Set the share group type from the original share group
|
||||
orig_sg = manila.share_group_get(
|
||||
request, snapshot.share_group_id)
|
||||
self.fields["sgt"].initial = orig_sg.share_group_type_id
|
||||
except Exception:
|
||||
pass
|
||||
del self.fields["source_type"]
|
||||
except Exception:
|
||||
exceptions.handle(
|
||||
request,
|
||||
_("Unable to load the specified share group snapshot."))
|
||||
else:
|
||||
source_type_choices = []
|
||||
try:
|
||||
snapshot_list = manila.share_group_snapshot_list(request)
|
||||
snapshots = [s for s in snapshot_list
|
||||
if s.status == "available"]
|
||||
if snapshots:
|
||||
source_type_choices.append(("snapshot", _("Snapshot")))
|
||||
self.fields["snapshot"].choices = (
|
||||
[("", _("Choose a snapshot"))] +
|
||||
[(s.id, s.name or s.id) for s in snapshots]
|
||||
)
|
||||
else:
|
||||
del self.fields["snapshot"]
|
||||
except Exception:
|
||||
exceptions.handle(
|
||||
request,
|
||||
_("Unable to retrieve share group snapshots."))
|
||||
|
||||
if source_type_choices:
|
||||
choices = ([('none', _("No source, empty share group"))] +
|
||||
source_type_choices)
|
||||
self.fields["source_type"].choices = choices
|
||||
else:
|
||||
del self.fields["source_type"]
|
||||
|
||||
self.fields["az"] = forms.ChoiceField(
|
||||
label=_("Availability Zone"),
|
||||
widget=forms.SelectWidget(attrs={
|
||||
"class": "switched",
|
||||
"data-switch-on": "source",
|
||||
"data-source-none": _("Availability Zone"),
|
||||
}),
|
||||
required=False)
|
||||
|
||||
availability_zones = manila.availability_zone_list(request)
|
||||
self.fields["az"].choices = (
|
||||
[("", "")] + [(az.name, az.name) for az in availability_zones])
|
||||
|
||||
share_group_types = manila.share_group_type_list(request)
|
||||
self.fields["sgt"] = forms.ChoiceField(
|
||||
label=_("Share Group Type"),
|
||||
widget=forms.fields.SelectWidget(attrs={
|
||||
"class": "switched switchable",
|
||||
"data-switch-on": "source",
|
||||
"data-source-none": _("Share Group Type"),
|
||||
"data-slug": "sgt",
|
||||
}),
|
||||
required=True)
|
||||
self.fields["sgt"].choices = (
|
||||
[("", "")] + [(sgt.id, sgt.name) for sgt in share_group_types])
|
||||
|
||||
# NOTE(vponomaryov): create separate set of available share types
|
||||
# for each of share group types.
|
||||
share_types = manila.share_type_list(request)
|
||||
for sgt in share_group_types:
|
||||
st_choices = (
|
||||
[(st.id, st.name)
|
||||
for st in share_types if st.id in sgt.share_types])
|
||||
amount_of_choices = len(st_choices)
|
||||
st_field_name = self.st_field_name_prefix + sgt.id
|
||||
if amount_of_choices < 2:
|
||||
st_field = forms.ChoiceField(
|
||||
label=_("Share Types"),
|
||||
choices=st_choices,
|
||||
widget=forms.fields.SelectWidget(attrs={
|
||||
"class": "switched",
|
||||
"data-switch-on": "sgt",
|
||||
"data-sgt-%s" % sgt.id: _(
|
||||
"Share Types (one available)"),
|
||||
}),
|
||||
required=True)
|
||||
else:
|
||||
height = min(30 * amount_of_choices, 155)
|
||||
st_field = forms.MultipleChoiceField(
|
||||
label=_("Share Types"),
|
||||
choices=st_choices,
|
||||
widget=forms.fields.widgets.SelectMultiple(attrs={
|
||||
"style": "max-height: %spx;" % height,
|
||||
"class": "switched",
|
||||
"data-switch-on": "sgt",
|
||||
"data-sgt-%s" % sgt.id: _(
|
||||
"Share Types (multiple available)"),
|
||||
}),
|
||||
required=False)
|
||||
st_field.initial = st_choices[0]
|
||||
self.fields[st_field_name] = st_field
|
||||
|
||||
self.fields["share_network"] = forms.ChoiceField(
|
||||
label=_("Share Network"),
|
||||
widget=forms.fields.SelectWidget(attrs={
|
||||
"class": "switched",
|
||||
"data-switch-on": "source",
|
||||
"data-source-none": _("Share Network"),
|
||||
}),
|
||||
required=False)
|
||||
share_networks = manila.share_network_list(request)
|
||||
self.fields["share_network"].choices = (
|
||||
[("", "")] +
|
||||
[(sn.id, sn.name or sn.id) for sn in share_networks])
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(CreateShareGroupForm, self).clean()
|
||||
errors = [k for k in self.errors.viewkeys()]
|
||||
|
||||
for k in errors:
|
||||
sgt_name = k.split(self.st_field_name_prefix)[-1]
|
||||
chosen_sgt = cleaned_data.get("sgt")
|
||||
if (k.startswith(self.st_field_name_prefix) and
|
||||
sgt_name != chosen_sgt):
|
||||
cleaned_data[k] = "Not set"
|
||||
self.errors.pop(k, None)
|
||||
|
||||
source_type = cleaned_data.get("source_type")
|
||||
if source_type != "snapshot":
|
||||
self.errors.pop("snapshot", None)
|
||||
share_group_type = cleaned_data.get("sgt")
|
||||
if share_group_type:
|
||||
cleaned_data["share_types"] = cleaned_data.get(
|
||||
self.st_field_name_prefix + share_group_type)
|
||||
if isinstance(cleaned_data["share_types"], six.string_types):
|
||||
cleaned_data["share_types"] = [cleaned_data["share_types"]]
|
||||
else:
|
||||
self.errors.pop("sgt", None)
|
||||
|
||||
return cleaned_data
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
source_type = data.get('source_type')
|
||||
if (data.get("snapshot") and source_type in (None, 'snapshot')):
|
||||
snapshot = self.get_share_group_snapshot(
|
||||
request, data["snapshot"])
|
||||
snapshot_id = snapshot.id
|
||||
source_sg = manila.share_group_get(
|
||||
request, snapshot.share_group_id)
|
||||
data['sgt'] = source_sg.share_group_type_id
|
||||
else:
|
||||
snapshot_id = None
|
||||
|
||||
share_group = manila.share_group_create(
|
||||
request,
|
||||
name=data['name'],
|
||||
description=data['description'],
|
||||
share_group_type=data['sgt'],
|
||||
share_types=None if snapshot_id else data.get('share_types'),
|
||||
share_network=(
|
||||
None if snapshot_id else data.get('share_network')),
|
||||
source_share_group_snapshot=snapshot_id,
|
||||
availability_zone=None if snapshot_id else data['az'])
|
||||
|
||||
message = _('Creating share group "%s"') % data['name']
|
||||
messages.success(request, message)
|
||||
return share_group
|
||||
except ValidationError as e:
|
||||
self.api_error(e.messages[0])
|
||||
return False
|
||||
except Exception:
|
||||
exceptions.handle(request, ignore=True)
|
||||
self.api_error(_("Unable to create share group."))
|
||||
return False
|
||||
|
||||
@memoized.memoized
|
||||
def get_share_group_snapshot(self, request, sg_snapshot_id):
|
||||
return manila.share_group_snapshot_get(request, sg_snapshot_id)
|
||||
|
||||
|
||||
class UpdateShareGroupForm(forms.SelfHandlingForm):
|
||||
name = forms.CharField(
|
||||
max_length="255", label=_("Share Group Name"))
|
||||
description = forms.CharField(
|
||||
widget=forms.Textarea, label=_("Description"), required=False)
|
||||
|
||||
def handle(self, request, data):
|
||||
sg_id = self.initial['share_group_id']
|
||||
try:
|
||||
manila.share_group_update(
|
||||
request, sg_id, data['name'], data['description'])
|
||||
message = _('Updating share group "%s"') % data['name']
|
||||
messages.success(request, message)
|
||||
return True
|
||||
except Exception:
|
||||
redirect = reverse("horizon:project:share_groups:index")
|
||||
exceptions.handle(
|
||||
request, _('Unable to update share group.'), redirect=redirect)
|
||||
return False
|
29
manila_ui/dashboards/project/share_groups/panel.py
Normal file
29
manila_ui/dashboards/project/share_groups/panel.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
from openstack_dashboard.dashboards.project import dashboard
|
||||
|
||||
|
||||
class ShareGroups(horizon.Panel):
|
||||
name = _("Share Groups")
|
||||
slug = 'share_groups'
|
||||
permissions = (
|
||||
'openstack.services.share',
|
||||
)
|
||||
|
||||
|
||||
dashboard.Project.register(ShareGroups)
|
161
manila_ui/dashboards/project/share_groups/tables.py
Normal file
161
manila_ui/dashboards/project/share_groups/tables.py
Normal file
@ -0,0 +1,161 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy
|
||||
from horizon import tables
|
||||
import six
|
||||
|
||||
from manila_ui.api import manila
|
||||
import manila_ui.dashboards.project.share_group_snapshots.tables as sgs_tables
|
||||
|
||||
|
||||
class UpdateShareGroup(tables.LinkAction):
|
||||
name = "update"
|
||||
verbose_name = _("Update")
|
||||
url = "horizon:project:share_groups:update"
|
||||
classes = ("ajax-modal", "btn-create")
|
||||
|
||||
def allowed(self, request, share_group=None):
|
||||
return share_group.status in ("available", "error")
|
||||
|
||||
|
||||
class DeleteShareGroup(tables.DeleteAction):
|
||||
|
||||
@staticmethod
|
||||
def action_present(count):
|
||||
return ungettext_lazy(
|
||||
u"Delete Share Group",
|
||||
u"Delete Share Groups",
|
||||
count
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def action_past(count):
|
||||
return ungettext_lazy(
|
||||
u"Deleted Share Group",
|
||||
u"Deleted Share Groups",
|
||||
count
|
||||
)
|
||||
|
||||
def delete(self, request, obj_id):
|
||||
manila.share_group_delete(request, obj_id)
|
||||
|
||||
def allowed(self, request, share_group=None):
|
||||
if share_group:
|
||||
# Row button
|
||||
return (share_group.status.lower() in ('available', 'error'))
|
||||
# Table button. Always return 'True'
|
||||
return True
|
||||
|
||||
|
||||
class CreateShareGroup(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Create Share Group")
|
||||
url = "horizon:project:share_groups:create"
|
||||
classes = ("ajax-modal", "btn-create")
|
||||
icon = "plus"
|
||||
policy_rules = (("share", "share_group:create"),)
|
||||
|
||||
def allowed(self, request, share=None):
|
||||
# TODO(vponomaryov): implement quota restriction when quota support
|
||||
# is implemented for share groups.
|
||||
return True
|
||||
|
||||
|
||||
class UpdateShareGroupRow(tables.Row):
|
||||
ajax = True
|
||||
|
||||
def get_data(self, request, sg_id):
|
||||
sg = manila.share_group_get(request, sg_id)
|
||||
return sg
|
||||
|
||||
|
||||
class ShareGroupsTable(tables.DataTable):
|
||||
def get_share_network_link(share_group):
|
||||
if getattr(share_group, 'share_network_id', None):
|
||||
return reverse(
|
||||
"horizon:project:share_networks:share_network_detail",
|
||||
args=(share_group.share_network_id,))
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_source_share_group_snapshot_link(share_group):
|
||||
if getattr(share_group, 'source_share_group_snapshot_id', None):
|
||||
return reverse(
|
||||
"horizon:project:share_group_snapshots:detail",
|
||||
args=(share_group.source_share_group_snapshot_id,))
|
||||
else:
|
||||
return None
|
||||
|
||||
STATUS_CHOICES = (
|
||||
("available", True),
|
||||
("creating", None),
|
||||
("deleting", None),
|
||||
("error", False),
|
||||
("error_deleting", False),
|
||||
)
|
||||
STATUS_DISPLAY_CHOICES = (
|
||||
("available", u"Available"),
|
||||
("creating", u"Creating"),
|
||||
("deleting", u"Deleting"),
|
||||
("error", u"Error"),
|
||||
("error_deleting", u"Error deleting"),
|
||||
)
|
||||
name = tables.Column(
|
||||
"name",
|
||||
verbose_name=_("Name"),
|
||||
link="horizon:project:share_groups:detail")
|
||||
status = tables.Column(
|
||||
"status",
|
||||
verbose_name=_("Status"),
|
||||
status=True,
|
||||
status_choices=STATUS_CHOICES,
|
||||
display_choices=STATUS_DISPLAY_CHOICES,
|
||||
)
|
||||
availability_zone = tables.Column(
|
||||
"availability_zone",
|
||||
verbose_name=_("Availability Zone"))
|
||||
share_network_id = tables.Column(
|
||||
"share_network_id",
|
||||
verbose_name=_("Share Network"),
|
||||
link=get_share_network_link)
|
||||
source_share_group_snapshot_id = tables.Column(
|
||||
"source_share_group_snapshot_id",
|
||||
verbose_name=_("Source Share Group Snapshot"),
|
||||
link=get_source_share_group_snapshot_link)
|
||||
|
||||
def get_object_display(self, share_group):
|
||||
return six.text_type(share_group.id)
|
||||
|
||||
def get_object_id(self, share_group):
|
||||
return six.text_type(share_group.id)
|
||||
|
||||
class Meta(object):
|
||||
name = "share_groups"
|
||||
verbose_name = _("Share Groups")
|
||||
status_columns = ("status", )
|
||||
row_class = UpdateShareGroupRow
|
||||
table_actions = (
|
||||
CreateShareGroup,
|
||||
tables.NameFilterAction,
|
||||
DeleteShareGroup,
|
||||
)
|
||||
row_actions = (
|
||||
sgs_tables.CreateShareGroupSnapshot,
|
||||
UpdateShareGroup,
|
||||
DeleteShareGroup,
|
||||
)
|
33
manila_ui/dashboards/project/share_groups/tabs.py
Normal file
33
manila_ui/dashboards/project/share_groups/tabs.py
Normal file
@ -0,0 +1,33 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tabs
|
||||
|
||||
|
||||
class ShareGroupOverviewTab(tabs.Tab):
|
||||
name = _("Share Group Overview")
|
||||
slug = "share_group_overview_tab"
|
||||
template_name = "project/share_groups/_detail.html"
|
||||
|
||||
def get_context_data(self, request):
|
||||
return {"share_group": self.tab_group.kwargs["share_group"]}
|
||||
|
||||
|
||||
class ShareGroupDetailTabs(tabs.TabGroup):
|
||||
slug = "share_group_details"
|
||||
tabs = (
|
||||
ShareGroupOverviewTab,
|
||||
)
|
@ -0,0 +1,6 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
<h3>{% trans "Description" %}:</h3>
|
||||
<p>{% trans "Select parameters of share group you want to create. " %}</p>
|
||||
{% endblock %}
|
@ -0,0 +1,55 @@
|
||||
{% load i18n sizeformat parse_date %}
|
||||
|
||||
<h3>{% trans "Share Group Overview" %}</h3>
|
||||
<div class="detail">
|
||||
<hr class="header_rule">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ share_group.id }}</dd>
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ share_group.name }}</dd>
|
||||
<dt>{% trans "Description" %}</dt>
|
||||
<dd>{{ share_group.description }}</dd>
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>{{ share_group.status|capfirst }}</dd>
|
||||
<dt>{% trans "Created" %}</dt>
|
||||
<dd>{{ share_group.created_at|parse_date }}</dd>
|
||||
{% if share_group.source_share_group_snapshot_id %}
|
||||
<dt>{% trans "Source SG Snapshot" %}</dt>
|
||||
{% url 'horizon:project:share_group_snapshots:detail' share_group.source_share_group_snapshot_id as ssgs_url%}
|
||||
<dd><a href="{{ ssgs_url }}">{{ share_group.source_share_group_snapshot_id }}</a></dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Share Group Type" %}</dt>
|
||||
<dd>{{ share_group.share_group_type_id}}</dd>
|
||||
{% if share_group.availability_zone %}
|
||||
<dt>{% trans "Availability Zone" %}</dt>
|
||||
<dd>{{ share_group.availability_zone }}</dd>
|
||||
{% endif %}
|
||||
{% if share_group.share_network_id %}
|
||||
<dt>{% trans "Share Network" %}</dt>
|
||||
{% url 'horizon:project:share_networks:share_network_detail' share_group.share_network_id as sn_url%}
|
||||
<dd><a href="{{ sn_url }}">{{ share_group.share_network_id }}</a></dd>
|
||||
{% endif %}
|
||||
{% if share_group.share_types %}
|
||||
<dt>{% trans "Share Types" %}</dt>
|
||||
{% for st in share_group.share_types %}
|
||||
<dd><p>
|
||||
<div><b>Share Type Name:</b> {{ st.name }}</div>
|
||||
<div><b>Share Type Visibility:</b> {% if st.is_public %}Public{% else %}Private{% endif %}</div>
|
||||
<div><b>Network handling enabled:</b> {{ st.dhss }}</div>
|
||||
</p></dd>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if share_group.members %}
|
||||
<dt>{% trans "Shares" %}</dt>
|
||||
{% for m in share_group.members %}
|
||||
{% url 'horizon:project:shares:detail' m.id as share_url%}
|
||||
<dd>
|
||||
<div>
|
||||
<a href="{{ share_url }}">{% if m.name %}{{ m.name }}{% else %}{{ m.id }}{% endif %}</a>
|
||||
</div>
|
||||
</dd>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
@ -0,0 +1,6 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
<h3>{% trans "Description" %}:</h3>
|
||||
<p>{% trans "From here you can modify name, description and visibility of a share group." %}</p>
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Create Share Group" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'project/share_groups/_create.html' %}
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Share Group Details" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Share Groups" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{{ share_groups_table.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,7 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Update Share Group" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'project/share_groups/_update.html' %}
|
||||
{% endblock %}
|
40
manila_ui/dashboards/project/share_groups/urls.py
Normal file
40
manila_ui/dashboards/project/share_groups/urls.py
Normal file
@ -0,0 +1,40 @@
|
||||
# Copyright 2017 Mirantis Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from django.conf import urls
|
||||
|
||||
from manila_ui.dashboards.project.share_groups import views
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
urlpatterns = [
|
||||
urls.url(
|
||||
r'^$',
|
||||
views.ShareGroupsView.as_view(),
|
||||
name='index'),
|
||||
urls.url(
|
||||
r'^create/$',
|
||||
views.ShareGroupCreateView.as_view(),
|
||||
name='create'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_id>[^/]+)/$',
|
||||
views.ShareGroupDetailView.as_view(),
|
||||
name='detail'),
|
||||
urls.url(
|
||||
r'^(?P<share_group_id>[^/]+)/update/$',
|
||||
views.ShareGroupUpdateView.as_view(),
|
||||
name='update'),
|
||||
]
|
150
manila_ui/dashboards/project/share_groups/views.py
Normal file
150
manila_ui/dashboards/project/share_groups/views.py
Normal file
@ -0,0 +1,150 @@
|
||||
# Copyright 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Project views for managing share groups.
|
||||
"""
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon import tabs
|
||||
from horizon.utils import memoized
|
||||
|
||||
from manila_ui.api import manila
|
||||
from manila_ui.dashboards.project.share_groups import forms as sg_forms
|
||||
from manila_ui.dashboards.project.share_groups import tables as sg_tables
|
||||
from manila_ui.dashboards.project.share_groups import tabs as sg_tabs
|
||||
|
||||
|
||||
class ShareGroupsView(tables.MultiTableView):
|
||||
table_classes = (
|
||||
sg_tables.ShareGroupsTable,
|
||||
)
|
||||
template_name = "project/share_groups/index.html"
|
||||
page_title = _("Share Groups")
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_share_groups_data(self):
|
||||
try:
|
||||
share_groups = manila.share_group_list(
|
||||
self.request, detailed=True)
|
||||
except Exception:
|
||||
share_groups = []
|
||||
exceptions.handle(
|
||||
self.request, _("Unable to retrieve share groups."))
|
||||
return share_groups
|
||||
|
||||
|
||||
class ShareGroupDetailView(tabs.TabView):
|
||||
tab_group_class = sg_tabs.ShareGroupDetailTabs
|
||||
template_name = 'project/share_groups/detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(self.__class__, self).get_context_data(**kwargs)
|
||||
share_group = self.get_data()
|
||||
context["share_group"] = share_group
|
||||
context["page_title"] = (
|
||||
_("Share Group Details: %s") % share_group.id)
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_data(self):
|
||||
try:
|
||||
share_group_id = self.kwargs['share_group_id']
|
||||
share_group = manila.share_group_get(self.request, share_group_id)
|
||||
members = manila.share_list(
|
||||
self.request, search_opts={"share_group_id": share_group_id})
|
||||
share_group.members = members
|
||||
share_types = manila.share_type_list(self.request)
|
||||
share_group.share_types = [
|
||||
{"id": st.id,
|
||||
"name": st.name,
|
||||
"is_public": getattr(st, 'share_type_access:is_public'),
|
||||
"dhss": st.extra_specs.get('driver_handles_share_servers')}
|
||||
for st in share_types if st.id in share_group.share_types
|
||||
]
|
||||
return share_group
|
||||
except Exception:
|
||||
redirect = reverse('horizon:project:share_groups:index')
|
||||
exceptions.handle(
|
||||
self.request,
|
||||
_('Unable to retrieve share group details.'),
|
||||
redirect=redirect)
|
||||
|
||||
def get_tabs(self, request, *args, **kwargs):
|
||||
share_group = self.get_data()
|
||||
return self.tab_group_class(request, share_group=share_group, **kwargs)
|
||||
|
||||
|
||||
class ShareGroupCreateView(forms.ModalFormView):
|
||||
form_class = sg_forms.CreateShareGroupForm
|
||||
form_id = "create_share_group"
|
||||
template_name = 'project/share_groups/create.html'
|
||||
modal_header = _("Create Share Group")
|
||||
modal_id = "create_share_group_modal"
|
||||
submit_label = _("Create")
|
||||
submit_url = reverse_lazy("horizon:project:share_groups:create")
|
||||
success_url = reverse_lazy("horizon:project:share_groups:index")
|
||||
page_title = _('Create a Share')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ShareGroupCreateView, self).get_context_data(**kwargs)
|
||||
try:
|
||||
# TODO(vponomaryov): add quota logic here when quotas are
|
||||
# implemented for share groups.
|
||||
pass
|
||||
except Exception:
|
||||
exceptions.handle(self.request)
|
||||
return context
|
||||
|
||||
|
||||
class ShareGroupUpdateView(forms.ModalFormView):
|
||||
form_class = sg_forms.UpdateShareGroupForm
|
||||
form_id = "update_share_group"
|
||||
template_name = 'project/share_groups/update.html'
|
||||
modal_header = _("Update")
|
||||
modal_id = "update_share_group_modal"
|
||||
submit_label = _("Update")
|
||||
submit_url = "horizon:project:share_groups:update"
|
||||
success_url = reverse_lazy("horizon:project:share_groups:index")
|
||||
page_title = _("Update Share Group")
|
||||
|
||||
def get_object(self):
|
||||
if not hasattr(self, "_object"):
|
||||
sg_id = self.kwargs['share_group_id']
|
||||
try:
|
||||
self._object = manila.share_group_get(self.request, sg_id)
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve share group.')
|
||||
url = reverse('horizon:project:share_groups:index')
|
||||
exceptions.handle(self.request, msg, redirect=url)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ShareGroupUpdateView, self).get_context_data(**kwargs)
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
self.submit_url = reverse(self.submit_url, kwargs=self.kwargs)
|
||||
sg = self.get_object()
|
||||
return {
|
||||
'share_group_id': self.kwargs["share_group_id"],
|
||||
'name': sg.name,
|
||||
'description': sg.description,
|
||||
}
|
@ -18,16 +18,17 @@ from django.core.urlresolvers import reverse
|
||||
from django.forms import ValidationError # noqa
|
||||
from django.template.defaultfilters import filesizeformat # noqa
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
import six
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from horizon.utils.memoized import memoized # noqa
|
||||
from openstack_dashboard.usage import quotas
|
||||
import six
|
||||
|
||||
from manila_ui.api import manila
|
||||
from manila_ui.dashboards import utils
|
||||
from openstack_dashboard.usage import quotas
|
||||
from manila_ui import features
|
||||
from manilaclient.common.apiclient import exceptions as m_exceptions
|
||||
|
||||
|
||||
class CreateForm(forms.SelfHandlingForm):
|
||||
@ -65,6 +66,14 @@ class CreateForm(forms.SelfHandlingForm):
|
||||
self.fields['availability_zone'].choices = (
|
||||
[("", "")] + [(az.name, az.name) for az in availability_zones])
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
share_groups = manila.share_group_list(request)
|
||||
self.fields['sg'] = forms.ChoiceField(
|
||||
label=_("Share Group"),
|
||||
choices=[("", "")] + [(sg.id, sg.name or sg.id)
|
||||
for sg in share_groups],
|
||||
required=False)
|
||||
|
||||
self.sn_field_name_prefix = 'share-network-choices-'
|
||||
for st in share_types:
|
||||
extra_specs = st.get_keys()
|
||||
@ -226,17 +235,20 @@ class CreateForm(forms.SelfHandlingForm):
|
||||
share_type=data['share_type'],
|
||||
is_public=is_public,
|
||||
metadata=metadata,
|
||||
availability_zone=data['availability_zone'])
|
||||
availability_zone=data['availability_zone'],
|
||||
share_group_id=data.get('sg') or None,
|
||||
)
|
||||
message = _('Creating share "%s"') % data['name']
|
||||
messages.success(request, message)
|
||||
return share
|
||||
except ValidationError as e:
|
||||
self.api_error(e.messages[0])
|
||||
return False
|
||||
except m_exceptions.BadRequest as e:
|
||||
self.api_error(_("Unable to create share. %s") % e.message)
|
||||
except Exception:
|
||||
exceptions.handle(request, ignore=True)
|
||||
self.api_error(_("Unable to create share."))
|
||||
return False
|
||||
return False
|
||||
|
||||
@memoized
|
||||
def get_snapshot(self, request, id):
|
||||
|
@ -22,10 +22,12 @@ from django.utils.translation import ungettext_lazy
|
||||
from horizon import exceptions
|
||||
from horizon import messages
|
||||
from horizon import tables
|
||||
from openstack_dashboard.usage import quotas
|
||||
|
||||
from manila_ui.api import manila
|
||||
from manila_ui.dashboards.project.share_snapshots import tables as ss_tables
|
||||
from manila_ui.dashboards import utils
|
||||
from openstack_dashboard.usage import quotas
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
DELETABLE_STATES = (
|
||||
@ -60,8 +62,10 @@ class DeleteShare(tables.DeleteAction):
|
||||
return {"project_id": project_id}
|
||||
|
||||
def delete(self, request, obj_id):
|
||||
share = manila.share_get(request, obj_id)
|
||||
try:
|
||||
manila.share_delete(request, obj_id)
|
||||
manila.share_delete(
|
||||
request, share.id, share_group_id=share.share_group_id)
|
||||
except Exception:
|
||||
msg = _('Unable to delete share "%s". ') % obj_id
|
||||
messages.error(request, msg)
|
||||
@ -250,6 +254,21 @@ class SharesTableBase(tables.DataTable):
|
||||
def get_object_display(self, obj):
|
||||
return obj.name or obj.id
|
||||
|
||||
def get_share_group_link(share):
|
||||
if features.is_share_groups_enabled() and share.share_group_id:
|
||||
return reverse(
|
||||
"horizon:project:share_groups:detail",
|
||||
args=(share.share_group_id,))
|
||||
else:
|
||||
return None
|
||||
|
||||
share_group_id = tables.Column(
|
||||
"share_group_id",
|
||||
verbose_name=_("Share Group"),
|
||||
empty_value="-",
|
||||
link=get_share_group_link,
|
||||
)
|
||||
|
||||
|
||||
class ManageRules(tables.LinkAction):
|
||||
name = "manage_rules"
|
||||
@ -268,7 +287,7 @@ class ManageReplicas(tables.LinkAction):
|
||||
|
||||
def allowed(self, request, share):
|
||||
share_replication_enabled = share.replication_type is not None
|
||||
return manila.is_replication_enabled() and share_replication_enabled
|
||||
return features.is_replication_enabled() and share_replication_enabled
|
||||
|
||||
|
||||
class AddRule(tables.LinkAction):
|
||||
@ -387,3 +406,10 @@ class SharesTable(SharesTableBase):
|
||||
ManageReplicas,
|
||||
EditShareMetadata,
|
||||
DeleteShare)
|
||||
|
||||
columns = [
|
||||
'name', 'description', 'metadata', 'size', 'status',
|
||||
'proto', 'visibility', 'share_network',
|
||||
]
|
||||
if features.is_share_groups_enabled():
|
||||
columns.append('share_group_id')
|
||||
|
@ -57,10 +57,15 @@
|
||||
</p></dd>
|
||||
{% endif %}
|
||||
{% if share.share_network_id %}
|
||||
<dt>{% trans "Share network" %}</dt>
|
||||
<dt>{% trans "Share Network" %}</dt>
|
||||
{% url 'horizon:project:share_networks:share_network_detail' share.share_network_id as sn_url%}
|
||||
<dd><a href="{{ sn_url }}">{{ share.share_network_id }}</a></dd>
|
||||
{% endif %}
|
||||
{% if share.share_group_id %}
|
||||
<dt>{% trans "Share Group" %}</dt>
|
||||
{% url 'horizon:project:share_groups:detail' share.share_group_id as sg_url%}
|
||||
<dd><a href="{{ sg_url }}">{{ share.share_group_id }}</a></dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Mount snapshot support" %}</dt>
|
||||
<dd>{{ share.mount_snapshot_support }}</dd>
|
||||
<dt>{% trans "Created" %}</dt>
|
||||
|
@ -14,9 +14,9 @@
|
||||
|
||||
from django.conf import urls
|
||||
|
||||
from manila_ui.api import manila
|
||||
from manila_ui.dashboards.project.shares.replicas import views as replica_views
|
||||
from manila_ui.dashboards.project.shares import views as shares_views
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
@ -58,7 +58,7 @@ urlpatterns = [
|
||||
name='revert'),
|
||||
]
|
||||
|
||||
if manila.is_replication_enabled():
|
||||
if features.is_replication_enabled():
|
||||
urlpatterns.extend([
|
||||
urls.url(
|
||||
r'^(?P<share_id>[^/]+)/create_replica/$',
|
||||
|
50
manila_ui/features.py
Normal file
50
manila_ui/features.py
Normal file
@ -0,0 +1,50 @@
|
||||
# Copyright 2017 Mirantis Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
This module stores functions that return boolean values and say
|
||||
which manila features are enabled and which are disabled among those
|
||||
that are optional for manila UI.
|
||||
These functions are required mostly for complex features, which consist
|
||||
of more than one logical part in manila UI and requires appropriate logic
|
||||
change in more than 1 place. For example, to disable share groups feature
|
||||
we need to do following:
|
||||
- Remove 'share_groups' panel from 'share groups' panel group in each
|
||||
dashboard.
|
||||
- Disable or do not register URLs for disabled features, so, no one
|
||||
will be able to request disabled features knowing direct URL.
|
||||
- Add/remove buttons for other (not disabled) features that are related
|
||||
to it somehow.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from horizon.utils import memoized
|
||||
|
||||
|
||||
@memoized.memoized
|
||||
def is_share_groups_enabled():
|
||||
manila_config = getattr(settings, 'OPENSTACK_MANILA_FEATURES', {})
|
||||
return manila_config.get('enable_share_groups', True)
|
||||
|
||||
|
||||
@memoized.memoized
|
||||
def is_replication_enabled():
|
||||
manila_config = getattr(settings, 'OPENSTACK_MANILA_FEATURES', {})
|
||||
return manila_config.get('enable_replication', True)
|
||||
|
||||
|
||||
@memoized.memoized
|
||||
def is_migration_enabled():
|
||||
manila_config = getattr(settings, 'OPENSTACK_MANILA_FEATURES', {})
|
||||
return manila_config.get('enable_migration', True)
|
@ -0,0 +1,25 @@
|
||||
# Copyright 2017 Mirantis Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
PANEL_DASHBOARD = 'admin'
|
||||
PANEL_GROUP = 'share'
|
||||
PANEL = 'share_groups'
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
ADD_PANEL = 'manila_ui.dashboards.admin.share_groups.panel.ShareGroups'
|
||||
else:
|
||||
REMOVE_PANEL = not features.is_share_groups_enabled()
|
@ -0,0 +1,25 @@
|
||||
# Copyright 2017 Mirantis Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
PANEL_DASHBOARD = 'project'
|
||||
PANEL_GROUP = 'share'
|
||||
PANEL = 'share_groups'
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
ADD_PANEL = 'manila_ui.dashboards.project.share_groups.panel.ShareGroups'
|
||||
else:
|
||||
REMOVE_PANEL = not features.is_share_groups_enabled()
|
@ -0,0 +1,26 @@
|
||||
# Copyright 2017 Mirantis Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
PANEL_DASHBOARD = 'admin'
|
||||
PANEL_GROUP = 'share'
|
||||
PANEL = 'share_group_snapshots'
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
ADD_PANEL = ('manila_ui.dashboards.admin.share_group_snapshots.panel.'
|
||||
'ShareGroupSnapshots')
|
||||
else:
|
||||
REMOVE_PANEL = not features.is_share_groups_enabled()
|
@ -0,0 +1,26 @@
|
||||
# Copyright 2017 Mirantis Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
PANEL_DASHBOARD = 'project'
|
||||
PANEL_GROUP = 'share'
|
||||
PANEL = 'share_group_snapshots'
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
ADD_PANEL = ('manila_ui.dashboards.project.share_group_snapshots.panel.'
|
||||
'ShareGroupSnapshots')
|
||||
else:
|
||||
REMOVE_PANEL = not features.is_share_groups_enabled()
|
@ -0,0 +1,26 @@
|
||||
# Copyright 2017 Mirantis Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from manila_ui import features
|
||||
|
||||
|
||||
PANEL_DASHBOARD = 'admin'
|
||||
PANEL_GROUP = 'share'
|
||||
PANEL = 'share_group_types'
|
||||
|
||||
if features.is_share_groups_enabled():
|
||||
ADD_PANEL = (
|
||||
'manila_ui.dashboards.admin.share_group_types.panel.ShareGroupTypes')
|
||||
else:
|
||||
REMOVE_PANEL = not features.is_share_groups_enabled()
|
@ -15,9 +15,11 @@
|
||||
# The OPENSTACK_MANILA_FEATURES settings can be used to enable or disable
|
||||
# the UI for the various services provided by Manila.
|
||||
OPENSTACK_MANILA_FEATURES = {
|
||||
'enable_share_groups': True,
|
||||
'enable_replication': True,
|
||||
'enable_migration': True,
|
||||
'enable_public_share_type_creation': True,
|
||||
'enable_public_share_group_type_creation': True,
|
||||
'enable_public_shares': True,
|
||||
'enabled_share_protocols': ['NFS', 'CIFS', 'GlusterFS', 'HDFS', 'CephFS',
|
||||
'MapRFS'],
|
||||
|
@ -26,6 +26,37 @@ class ManilaApiTests(base.APITestCase):
|
||||
super(self.__class__, self).setUp()
|
||||
self.id = "fake_id"
|
||||
|
||||
@ddt.data((None, True), ("some_fake_sg_id", False))
|
||||
@ddt.unpack
|
||||
def test_share_create(self, sg_id, is_public):
|
||||
kwargs = {
|
||||
"share_network": "fake_sn",
|
||||
"snapshot_id": "fake_snapshot_id",
|
||||
"metadata": {"k1": "v1", "k2": "v2"},
|
||||
"share_type": "fake_st",
|
||||
"is_public": is_public,
|
||||
"availability_zone": "fake_az",
|
||||
"share_group_id": sg_id,
|
||||
}
|
||||
size = 5
|
||||
name = "fake_name"
|
||||
desc = "fake_description"
|
||||
proto = "fake_share_protocol"
|
||||
|
||||
api.share_create(self.request, size, name, desc, proto, **kwargs)
|
||||
|
||||
self.manilaclient.shares.create.assert_called_once_with(
|
||||
proto, size, name=name, description=desc, **kwargs)
|
||||
|
||||
@ddt.data(None, "some_fake_sg_id")
|
||||
def test_share_delete(self, sg_id):
|
||||
s_id = "fake_share_id"
|
||||
|
||||
api.share_delete(self.request, s_id, sg_id)
|
||||
|
||||
self.manilaclient.shares.delete.assert_called_once_with(
|
||||
s_id, share_group_id=sg_id)
|
||||
|
||||
def test_list_share_export_locations(self):
|
||||
api.share_export_location_list(self.request, self.id)
|
||||
|
||||
@ -346,3 +377,294 @@ class ManilaApiTests(base.APITestCase):
|
||||
|
||||
mock_sn_create = self.manilaclient.share_networks.create
|
||||
mock_sn_create.assert_called_once_with(**expected_kwargs)
|
||||
|
||||
# Share groups tests
|
||||
|
||||
def test_share_group_create(self):
|
||||
name = "fake_sg_name"
|
||||
kwargs = {
|
||||
"description": "fake_desc",
|
||||
"share_group_type": "fake_sg_type",
|
||||
"share_types": ["fake", "list", "of", "fake", "share", "types"],
|
||||
"share_network": "fake_sn",
|
||||
"source_share_group_snapshot": "fake_source_share_group_snapshot",
|
||||
"availability_zone": "fake_az",
|
||||
}
|
||||
|
||||
result = api.share_group_create(self.request, name, **kwargs)
|
||||
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_groups.create.return_value, result)
|
||||
self.manilaclient.share_groups.create.assert_called_once_with(
|
||||
name=name, **kwargs)
|
||||
|
||||
def test_share_group_get(self):
|
||||
sg = "fake_share_group"
|
||||
|
||||
result = api.share_group_get(self.request, sg)
|
||||
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_groups.get.return_value, result)
|
||||
self.manilaclient.share_groups.get.assert_called_once_with(sg)
|
||||
|
||||
def test_share_group_update(self):
|
||||
sg = "fake_share_group"
|
||||
name = "fake_name"
|
||||
desc = "fake_desc"
|
||||
|
||||
result = api.share_group_update(self.request, sg, name, desc)
|
||||
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_groups.update.return_value, result)
|
||||
self.manilaclient.share_groups.update.assert_called_once_with(
|
||||
sg, name=name, description=desc)
|
||||
|
||||
@ddt.data({}, {"force": True}, {"force": False})
|
||||
def test_share_group_delete(self, kwargs):
|
||||
sg = 'fake_share_group'
|
||||
|
||||
api.share_group_delete(self.request, sg, **kwargs)
|
||||
|
||||
self.manilaclient.share_groups.delete.assert_called_once_with(
|
||||
sg, force=kwargs.get("force", False))
|
||||
|
||||
def test_share_group_reset_state(self):
|
||||
sg = 'fake_share_group'
|
||||
state = 'fake_state'
|
||||
|
||||
result = api.share_group_reset_state(self.request, sg, state)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_groups.reset_state.return_value,
|
||||
result)
|
||||
self.manilaclient.share_groups.reset_state.assert_called_once_with(
|
||||
sg, state)
|
||||
|
||||
@ddt.data(
|
||||
{},
|
||||
{"detailed": True},
|
||||
{"detailed": False},
|
||||
{"search_opts": {"foo": "bar"}},
|
||||
{"sort_key": "id", "sort_dir": "asc"},
|
||||
)
|
||||
def test_share_group_list(self, kwargs):
|
||||
result = api.share_group_list(self.request, **kwargs)
|
||||
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_groups.list.return_value, result)
|
||||
self.manilaclient.share_groups.list.assert_called_once_with(
|
||||
detailed=kwargs.get("detailed", True),
|
||||
search_opts=kwargs.get("search_opts"),
|
||||
sort_key=kwargs.get("sort_key"),
|
||||
sort_dir=kwargs.get("sort_dir"),
|
||||
)
|
||||
|
||||
# Share Group Snapshots tests
|
||||
|
||||
def test_share_group_snapshot_create(self):
|
||||
sg = 'fake_share_group'
|
||||
name = 'fake_name'
|
||||
desc = 'fake_description'
|
||||
|
||||
result = api.share_group_snapshot_create(self.request, sg, name, desc)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_snapshots.create.return_value,
|
||||
result)
|
||||
self.manilaclient.share_group_snapshots.create.assert_called_once_with(
|
||||
share_group=sg, name=name, description=desc)
|
||||
|
||||
def test_share_group_snapshot_get(self):
|
||||
sgs = 'fake_share_group_snapshot'
|
||||
|
||||
result = api.share_group_snapshot_get(self.request, sgs)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_snapshots.get.return_value, result)
|
||||
self.manilaclient.share_group_snapshots.get.assert_called_once_with(
|
||||
sgs)
|
||||
|
||||
def test_share_group_snapshot_update(self):
|
||||
sgs = 'fake_share_group_snapshot'
|
||||
name = 'fake_name'
|
||||
desc = 'fake_description'
|
||||
|
||||
result = api.share_group_snapshot_update(self.request, sgs, name, desc)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_snapshots.update.return_value,
|
||||
result)
|
||||
self.manilaclient.share_group_snapshots.update.assert_called_once_with(
|
||||
sgs, name=name, description=desc)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_share_group_snapshot_delete(self, force):
|
||||
sgs = 'fake_share_group_snapshot'
|
||||
|
||||
result = api.share_group_snapshot_delete(self.request, sgs, force)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_snapshots.delete.return_value,
|
||||
result)
|
||||
self.manilaclient.share_group_snapshots.delete.assert_called_once_with(
|
||||
sgs, force=force)
|
||||
|
||||
def test_share_group_snapshot_reset_state(self):
|
||||
sgs = 'fake_share_group_snapshot'
|
||||
state = 'fake_state'
|
||||
|
||||
result = api.share_group_snapshot_reset_state(self.request, sgs, state)
|
||||
|
||||
rs_method = self.manilaclient.share_group_snapshots.reset_state
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(rs_method.return_value, result)
|
||||
rs_method.assert_called_once_with(sgs, state)
|
||||
|
||||
@ddt.data(
|
||||
{},
|
||||
{'detailed': False},
|
||||
{'detailed': True, 'search_opts': 'foo',
|
||||
'sort_key': 'k', 'sort_dir': 'v'},
|
||||
)
|
||||
def test_share_group_snapshot_list(self, kwargs):
|
||||
result = api.share_group_snapshot_list(self.request, **kwargs)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_snapshots.list.return_value,
|
||||
result)
|
||||
self.manilaclient.share_group_snapshots.list.assert_called_once_with(
|
||||
detailed=kwargs.get('detailed', True),
|
||||
search_opts=kwargs.get('search_opts'),
|
||||
sort_key=kwargs.get('sort_key'),
|
||||
sort_dir=kwargs.get('sort_dir'))
|
||||
|
||||
# Share Group Types tests
|
||||
|
||||
@ddt.data(
|
||||
{'is_public': True},
|
||||
{'is_public': False, 'group_specs': {'foo': 'bar'}},
|
||||
{'group_specs': {}},
|
||||
)
|
||||
def test_share_group_type_create(self, kwargs):
|
||||
name = 'fake_sgt_name'
|
||||
sts = ['fake', 'list', 'of', 'share', 'types']
|
||||
|
||||
result = api.share_group_type_create(self.request, name, sts, **kwargs)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_types.create.return_value,
|
||||
result)
|
||||
self.manilaclient.share_group_types.create.assert_called_once_with(
|
||||
name=name, share_types=sts,
|
||||
is_public=kwargs.get('is_public', False),
|
||||
group_specs=kwargs.get('group_specs'))
|
||||
|
||||
def test_share_group_type_get(self):
|
||||
sgt = "fake_sgt"
|
||||
|
||||
result = api.share_group_type_get(self.request, sgt)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_types.get.return_value, result)
|
||||
self.manilaclient.share_group_types.get.assert_called_once_with(sgt)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_share_group_type_list(self, show_all):
|
||||
result = api.share_group_type_list(self.request, show_all)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_types.list.return_value, result)
|
||||
self.manilaclient.share_group_types.list.assert_called_once_with(
|
||||
show_all=show_all)
|
||||
|
||||
def test_share_group_type_delete(self):
|
||||
sgt = 'fake_share_group_type'
|
||||
|
||||
result = api.share_group_type_delete(self.request, sgt)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_types.delete.return_value, result)
|
||||
self.manilaclient.share_group_types.delete.assert_called_once_with(sgt)
|
||||
|
||||
def test_share_group_type_access_list(self):
|
||||
sgt = 'fake_share_group_type'
|
||||
|
||||
result = api.share_group_type_access_list(self.request, sgt)
|
||||
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
self.manilaclient.share_group_type_access.list.return_value,
|
||||
result)
|
||||
self.manilaclient.share_group_type_access.list.assert_called_once_with(
|
||||
sgt)
|
||||
|
||||
def test_share_group_type_access_add(self):
|
||||
sgt = 'fake_share_group_type'
|
||||
project = 'fake_project'
|
||||
|
||||
result = api.share_group_type_access_add(self.request, sgt, project)
|
||||
|
||||
sgt_access = self.manilaclient.share_group_type_access
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
sgt_access.add_project_access.return_value, result)
|
||||
sgt_access.add_project_access.assert_called_once_with(sgt, project)
|
||||
|
||||
def test_share_group_type_access_remove(self):
|
||||
sgt = 'fake_share_group_type'
|
||||
project = 'fake_project'
|
||||
|
||||
result = api.share_group_type_access_remove(self.request, sgt, project)
|
||||
|
||||
sgt_access = self.manilaclient.share_group_type_access
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
sgt_access.remove_project_access.return_value, result)
|
||||
sgt_access.remove_project_access.assert_called_once_with(sgt, project)
|
||||
|
||||
def test_share_group_type_set_specs(self):
|
||||
sgt = 'fake_share_group_type'
|
||||
group_specs = 'fake_specs'
|
||||
|
||||
result = api.share_group_type_set_specs(self.request, sgt, group_specs)
|
||||
|
||||
get_method = self.manilaclient.share_group_types.get
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(get_method.return_value.set_keys.return_value, result)
|
||||
get_method.assert_called_once_with(sgt)
|
||||
get_method.return_value.set_keys.assert_called_once_with(group_specs)
|
||||
|
||||
def test_share_group_type_unset_specs(self):
|
||||
sgt = 'fake_share_group_type'
|
||||
keys = ['fake', 'list', 'of', 'keys', 'for', 'deletion']
|
||||
|
||||
result = api.share_group_type_unset_specs(self.request, sgt, keys)
|
||||
|
||||
get_method = self.manilaclient.share_group_types.get
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
get_method.return_value.unset_keys.return_value, result)
|
||||
get_method.assert_called_once_with(sgt)
|
||||
get_method.return_value.unset_keys.assert_called_once_with(keys)
|
||||
|
||||
def test_share_group_type_get_specs(self):
|
||||
sgt = 'fake_share_group_type'
|
||||
|
||||
result = api.share_group_type_get_specs(self.request, sgt)
|
||||
|
||||
get_method = self.manilaclient.share_group_types.get
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(
|
||||
get_method.return_value.get_keys.return_value, result)
|
||||
get_method.assert_called_once_with(sgt)
|
||||
get_method.return_value.get_keys.assert_called_once_with()
|
||||
|
200
manila_ui/tests/dashboards/admin/share_group_snapshots/tests.py
Normal file
200
manila_ui/tests/dashboards/admin/share_group_snapshots/tests.py
Normal file
@ -0,0 +1,200 @@
|
||||
# Copyright (c) 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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 ddt
|
||||
from django.core.urlresolvers import reverse
|
||||
import mock
|
||||
|
||||
from manila_ui.api import manila as api_manila
|
||||
from manila_ui.tests.dashboards.project import test_data
|
||||
from manila_ui.tests import helpers as test
|
||||
|
||||
INDEX_URL = reverse('horizon:admin:share_group_snapshots:index')
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareGroupSnapshotTests(test.BaseAdminViewTests):
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.sg = test_data.share_group
|
||||
self.sg_nl = test_data.share_group_nameless
|
||||
self.sg_dhss_true = test_data.share_group_dhss_true
|
||||
self.sgs = test_data.share_group_snapshot
|
||||
self.sgs_nl = test_data.share_group_snapshot_nameless
|
||||
|
||||
def test_share_group_snapshots_list_get(self):
|
||||
share_groups = [self.sg, self.sg_nl, self.sg_dhss_true]
|
||||
sgss = [self.sgs, self.sgs_nl]
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_list',
|
||||
mock.Mock(return_value=sgss))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_list',
|
||||
mock.Mock(return_value=share_groups))
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertMessageCount(error=0)
|
||||
self.assertNoMessages()
|
||||
api_manila.share_group_snapshot_list.assert_called_once_with(
|
||||
mock.ANY, search_opts={'all_tenants': True})
|
||||
api_manila.share_group_list.assert_called_once_with(mock.ANY)
|
||||
self.assertTemplateUsed(res, 'admin/share_group_snapshots/index.html')
|
||||
self.assertContains(res, "<h1>Share Group Snapshots</h1>")
|
||||
self.assertContains(
|
||||
res, 'Delete Share Group Snapshot</button>', len(sgss))
|
||||
self.assertContains(res, 'Delete Share Group Snapshots</button>', 1)
|
||||
for sgs in sgss:
|
||||
self.assertContains(
|
||||
res,
|
||||
'href="/admin/share_group_snapshots/%s/reset_status"> '
|
||||
'Reset status</a>' % sgs.id, 1)
|
||||
self.assertContains(
|
||||
res, 'value="share_group_snapshots__delete__%s' % sgs.id, 1)
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/admin/share_group_snapshots/%(id)s/" >%(name)s</a>' % {
|
||||
'id': self.sgs.id, 'name': self.sgs.name}, 1)
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/admin/share_group_snapshots/%s/" '
|
||||
'>-</a>' % self.sgs_nl.id, 1)
|
||||
|
||||
def test_share_group_snapshots_list_error_get(self):
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_list',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertTemplateUsed(res, 'admin/share_group_snapshots/index.html')
|
||||
self.assertContains(res, "<h1>Share Group Snapshots</h1>")
|
||||
self.assertContains(res, 'Delete Share Group Snapshot</button>', 0)
|
||||
self.assertContains(res, 'Delete Share Group Snapshots</button>', 0)
|
||||
self.assertNoMessages()
|
||||
|
||||
@ddt.data(
|
||||
test_data.share_group_snapshot,
|
||||
test_data.share_group_snapshot_nameless,
|
||||
)
|
||||
def test_share_group_snapshot_detailed_page_get(self, sgs):
|
||||
sg = test_data.share_group_nameless
|
||||
url = reverse(
|
||||
'horizon:admin:share_group_snapshots:detail', args=[sgs.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(return_value=sgs))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(return_value=sg))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res, 'admin/share_group_snapshots/detail.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, sgs.id)
|
||||
api_manila.share_group_get.assert_called_once_with(
|
||||
mock.ANY, sgs.share_group_id)
|
||||
|
||||
def test_share_group_snapshot_detailed_page_error_get(self):
|
||||
url = reverse(
|
||||
'horizon:admin:share_group_snapshots:detail', args=[self.sgs.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateNotUsed(
|
||||
res, 'admin/share_group_snapshots/detail.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(error=1)
|
||||
self.assertMessageCount(success=0)
|
||||
|
||||
def test_share_group_snapshot_reset_status_get(self):
|
||||
url = reverse(
|
||||
'horizon:admin:share_group_snapshots:reset_status',
|
||||
args=[self.sgs.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(return_value=self.sgs))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'admin/share_group_snapshots/reset_status.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertMessageCount(error=0)
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id)
|
||||
|
||||
def test_share_group_snapshot_reset_status_error_get(self):
|
||||
url = reverse(
|
||||
'horizon:admin:share_group_snapshots:reset_status',
|
||||
args=[self.sgs.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateNotUsed(
|
||||
res, 'admin/share_group_snapshots/reset_status.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(error=1)
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id)
|
||||
|
||||
def test_share_group_snapshot_reset_status_post(self):
|
||||
url = reverse(
|
||||
'horizon:admin:share_group_snapshots:reset_status',
|
||||
args=[self.sgs.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(return_value=self.sgs))
|
||||
self.mock_object(api_manila, 'share_group_snapshot_reset_state')
|
||||
form_data = {'status': 'error'}
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertTemplateNotUsed(
|
||||
res, 'admin/share_group_snapshots/reset_status.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(error=0)
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id)
|
||||
api_manila.share_group_snapshot_reset_state.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id, form_data['status'])
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_share_group_snapshot_delete_post(self):
|
||||
data = {'action': 'share_group_snapshots__delete__%s' % self.sgs.id}
|
||||
self.mock_object(api_manila, "share_group_snapshot_delete")
|
||||
self.mock_object(
|
||||
api_manila, "share_group_snapshot_list",
|
||||
mock.Mock(return_value=[self.sgs]))
|
||||
|
||||
res = self.client.post(INDEX_URL, data)
|
||||
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(success=1)
|
||||
api_manila.share_group_snapshot_delete.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id)
|
||||
api_manila.share_group_snapshot_list.assert_called_once_with(
|
||||
mock.ANY, search_opts={'all_tenants': True})
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
142
manila_ui/tests/dashboards/admin/share_group_types/tests.py
Normal file
142
manila_ui/tests/dashboards/admin/share_group_types/tests.py
Normal file
@ -0,0 +1,142 @@
|
||||
# Copyright (c) 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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 copy
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
import mock
|
||||
|
||||
from manila_ui.api import manila as api_manila
|
||||
from manila_ui.tests.dashboards.project import test_data
|
||||
from manila_ui.tests import helpers as test
|
||||
|
||||
INDEX_URL = reverse('horizon:admin:share_group_types:index')
|
||||
|
||||
|
||||
class ShareGroupTypeTests(test.BaseAdminViewTests):
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.sgt = copy.copy(test_data.share_group_type)
|
||||
self.sgt_p = copy.copy(test_data.share_group_type_private)
|
||||
self.url = reverse(
|
||||
'horizon:admin:share_group_types:update', args=[self.sgt.id])
|
||||
self.mock_object(
|
||||
api_manila, "share_group_type_get",
|
||||
mock.Mock(return_value=self.sgt))
|
||||
|
||||
def test_list_share_group_types_get(self):
|
||||
sgts = [self.sgt, self.sgt_p]
|
||||
self.mock_object(
|
||||
api_manila, "share_group_type_list", mock.Mock(return_value=sgts))
|
||||
self.mock_object(
|
||||
api_manila, "share_type_list",
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_type, test_data.share_type_private]))
|
||||
self.mock_object(
|
||||
api_manila, "share_group_type_get",
|
||||
mock.Mock(side_effect=lambda req, sgt_id: (
|
||||
self.sgt
|
||||
if sgt_id in (self.sgt, self.sgt.id, self.sgt.name) else
|
||||
self.sgt_p)))
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
api_manila.share_group_type_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_type_list.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual(len(sgts), api_manila.share_group_type_get.call_count)
|
||||
self.assertContains(res, "<h1>Share Group Types</h1>")
|
||||
self.assertContains(res, 'href="/admin/share_group_types/create"')
|
||||
self.assertContains(res, 'Delete Share Group Type</button>', len(sgts))
|
||||
self.assertContains(res, 'Delete Share Group Types</button>', 1)
|
||||
for sgt in (self.sgt, self.sgt_p):
|
||||
for s in (
|
||||
'href="/admin/share_group_types/%s/update">' % sgt.id,
|
||||
'value="share_group_types__delete__%s"' % sgt.id):
|
||||
self.assertContains(res, s, 1, 200)
|
||||
self.assertContains(
|
||||
res,
|
||||
'href="/admin/share_group_types/%s/manage_access"' % sgt.id,
|
||||
0 if sgt.is_public else 1)
|
||||
|
||||
def test_create_share_group_type_post(self):
|
||||
url = reverse('horizon:admin:share_group_types:create')
|
||||
data = {
|
||||
'method': u'CreateShareGroupTypeForm',
|
||||
'is_public': True,
|
||||
'name': 'my_share_group_type',
|
||||
'share_types': ['foo'],
|
||||
'group_specs': 'key=value',
|
||||
}
|
||||
self.mock_object(
|
||||
api_manila, "share_group_type_create",
|
||||
mock.Mock(return_value=type(
|
||||
'SGT', (object, ), {'id': 'sgt_id', 'name': 'sgt_name'})))
|
||||
self.mock_object(api_manila, "share_group_type_set_specs")
|
||||
self.mock_object(
|
||||
api_manila, "share_type_list",
|
||||
mock.Mock(return_value=[
|
||||
type('ST', (object, ), {'id': s_id, 'name': s_id + '_name'})
|
||||
for s_id in ('foo', 'bar')
|
||||
]))
|
||||
|
||||
res = self.client.post(url, data)
|
||||
|
||||
api_manila.share_group_type_create.assert_called_once_with(
|
||||
mock.ANY,
|
||||
data['name'],
|
||||
is_public=data['is_public'],
|
||||
share_types=['foo'])
|
||||
api_manila.share_type_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_group_type_set_specs.assert_called_once_with(
|
||||
mock.ANY, 'sgt_id', {'key': 'value'})
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_update_share_group_type_get(self):
|
||||
res = self.client.get(self.url)
|
||||
|
||||
api_manila.share_group_type_get.assert_called_once_with(
|
||||
mock.ANY, self.sgt.id)
|
||||
self.assertNoMessages()
|
||||
self.assertTemplateUsed(res, 'admin/share_group_types/update.html')
|
||||
|
||||
def test_update_share_group_type_post(self):
|
||||
form_data = {'group_specs': 'foo=bar'}
|
||||
data = {'group_specs': {'foo': 'bar'}}
|
||||
self.mock_object(api_manila, "share_group_type_set_specs")
|
||||
|
||||
res = self.client.post(self.url, form_data)
|
||||
|
||||
api_manila.share_group_type_set_specs.assert_called_once_with(
|
||||
mock.ANY, self.sgt.id, data['group_specs'])
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_delete_share_group_type(self):
|
||||
data = {'action': 'share_group_types__delete__%s' % self.sgt.id}
|
||||
self.mock_object(api_manila, "share_group_type_delete")
|
||||
self.mock_object(
|
||||
api_manila, "share_group_type_list",
|
||||
mock.Mock(return_value=[self.sgt]))
|
||||
self.mock_object(
|
||||
api_manila, "share_type_list",
|
||||
mock.Mock(return_value=[test_data.share_type]))
|
||||
|
||||
res = self.client.post(INDEX_URL, data)
|
||||
|
||||
api_manila.share_group_type_delete.assert_called_once_with(
|
||||
mock.ANY, self.sgt.id)
|
||||
api_manila.share_group_type_list.assert_called_once_with(
|
||||
mock.ANY)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
186
manila_ui/tests/dashboards/admin/share_groups/tests.py
Normal file
186
manila_ui/tests/dashboards/admin/share_groups/tests.py
Normal file
@ -0,0 +1,186 @@
|
||||
# Copyright (c) 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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 ddt
|
||||
from django.core.urlresolvers import reverse
|
||||
import mock
|
||||
|
||||
from manila_ui.api import manila as api_manila
|
||||
from manila_ui.tests.dashboards.project import test_data
|
||||
from manila_ui.tests import helpers as test
|
||||
|
||||
INDEX_URL = reverse('horizon:admin:share_groups:index')
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareGroupTests(test.BaseAdminViewTests):
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.sg = test_data.share_group
|
||||
self.sg_nl = test_data.share_group_nameless
|
||||
self.sg_dhss_true = test_data.share_group_dhss_true
|
||||
|
||||
def test_share_groups_list_get(self):
|
||||
sgs = [self.sg, self.sg_nl, self.sg_dhss_true]
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_list', mock.Mock(return_value=sgs))
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertStatusCode(res, 200)
|
||||
api_manila.share_group_list.assert_called_once_with(
|
||||
mock.ANY, detailed=True)
|
||||
self.assertTemplateUsed(res, 'admin/share_groups/index.html')
|
||||
self.assertContains(res, "<h1>Share Groups</h1>")
|
||||
self.assertContains(res, 'Delete Share Group</button>', len(sgs))
|
||||
self.assertContains(res, 'Delete Share Groups</button>', 1)
|
||||
for sg in sgs:
|
||||
self.assertContains(
|
||||
res,
|
||||
'href="/admin/share_groups/%s/reset_status"> '
|
||||
'Reset status</a>' % sg.id, 1)
|
||||
self.assertContains(
|
||||
res, 'value="share_groups__delete__%s' % sg.id, 1)
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/admin/share_networks/%s"' % (
|
||||
self.sg_dhss_true.share_network_id), 1)
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/admin/share_servers/%s"' % (
|
||||
self.sg_dhss_true.share_server_id), 1)
|
||||
for sg in (self.sg, self.sg_dhss_true):
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/admin/share_groups/%(id)s/" >%(name)s</a>' % {
|
||||
'id': sg.id, 'name': sg.name}, 1)
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/admin/share_groups/%s/" >-</a>' % self.sg_nl.id, 1)
|
||||
self.assertNoMessages()
|
||||
|
||||
def test_share_group_list_error_get(self):
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_list',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertTemplateUsed(res, 'admin/share_groups/index.html')
|
||||
self.assertContains(res, "<h1>Share Groups</h1>")
|
||||
self.assertContains(res, 'Delete Share Group</button>', 0)
|
||||
self.assertContains(res, 'Delete Share Groups</button>', 0)
|
||||
self.assertNoMessages()
|
||||
|
||||
@ddt.data(
|
||||
test_data.share_group_nameless,
|
||||
test_data.share_group_dhss_true,
|
||||
)
|
||||
def test_share_group_detailed_page_get(self, sg):
|
||||
url = reverse('horizon:admin:share_groups:detail', args=[sg.id])
|
||||
shares = [test_data.share, test_data.nameless_share]
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(return_value=sg))
|
||||
self.mock_object(
|
||||
api_manila, 'share_list', mock.Mock(return_value=shares))
|
||||
self.mock_object(
|
||||
api_manila, 'share_type_list', mock.Mock(return_value=[
|
||||
test_data.share_type, test_data.share_type_dhss_true]))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res, 'admin/share_groups/detail.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
for share in shares:
|
||||
data = {'id': share.id, 'name': share.name or share.id}
|
||||
self.assertContains(
|
||||
res, '<a href="/admin/shares/%(id)s/">%(name)s</a>' % data)
|
||||
|
||||
def test_share_group_detailed_page_error_get(self):
|
||||
sg = test_data.share_group_dhss_true
|
||||
url = reverse('horizon:admin:share_groups:detail', args=[sg.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(side_effect=type(
|
||||
'CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateNotUsed(res, 'admin/share_groups/detail.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(error=1)
|
||||
self.assertMessageCount(success=0)
|
||||
|
||||
def test_share_group_reset_status_get(self):
|
||||
sg = test_data.share_group_dhss_true
|
||||
url = reverse('horizon:admin:share_groups:reset_status', args=[sg.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(return_value=sg))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res, 'admin/share_groups/reset_status.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertMessageCount(error=0)
|
||||
api_manila.share_group_get.assert_called_once_with(mock.ANY, sg.id)
|
||||
|
||||
def test_share_group_reset_status_error_get(self):
|
||||
sg = test_data.share_group_dhss_true
|
||||
url = reverse('horizon:admin:share_groups:reset_status', args=[sg.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateNotUsed(res, 'admin/share_groups/reset_status.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(error=1)
|
||||
api_manila.share_group_get.assert_called_once_with(mock.ANY, sg.id)
|
||||
|
||||
def test_share_group_reset_status_post(self):
|
||||
sg = test_data.share_group_dhss_true
|
||||
url = reverse('horizon:admin:share_groups:reset_status', args=[sg.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(return_value=sg))
|
||||
self.mock_object(api_manila, 'share_group_reset_state')
|
||||
form_data = {'status': 'error'}
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertTemplateNotUsed(res, 'admin/share_groups/reset_status.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(error=0)
|
||||
api_manila.share_group_get.assert_called_once_with(mock.ANY, sg.id)
|
||||
api_manila.share_group_reset_state.assert_called_once_with(
|
||||
mock.ANY, sg.id, form_data['status'])
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_share_group_delete_post(self):
|
||||
sg = test_data.share_group_dhss_true
|
||||
data = {'action': 'share_groups__delete__%s' % sg.id}
|
||||
self.mock_object(api_manila, "share_group_delete")
|
||||
self.mock_object(
|
||||
api_manila, "share_group_list", mock.Mock(return_value=[sg]))
|
||||
|
||||
res = self.client.post(INDEX_URL, data)
|
||||
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(success=1)
|
||||
api_manila.share_group_delete.assert_called_once_with(mock.ANY, sg.id)
|
||||
api_manila.share_group_list.assert_called_once_with(
|
||||
mock.ANY, detailed=True)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
@ -85,7 +85,8 @@ class SharesTests(test.BaseAdminViewTests):
|
||||
res = self.client.post(url, formData)
|
||||
|
||||
api_keystone.tenant_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_delete.assert_called_once_with(mock.ANY, share.id)
|
||||
api_manila.share_delete.assert_called_once_with(
|
||||
mock.ANY, share.id, share_group_id=share.share_group_id)
|
||||
api_manila.share_list.assert_called_once_with(
|
||||
mock.ANY, search_opts={'all_tenants': True})
|
||||
api_manila.share_snapshot_list.assert_called_once_with(
|
||||
|
@ -0,0 +1,295 @@
|
||||
# Copyright (c) 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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 ddt
|
||||
from django.core.urlresolvers import reverse
|
||||
import mock
|
||||
|
||||
from manila_ui.api import manila as api_manila
|
||||
from manila_ui.tests.dashboards.project import test_data
|
||||
from manila_ui.tests import helpers as test
|
||||
|
||||
INDEX_URL = reverse('horizon:project:share_group_snapshots:index')
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareGroupSnapshotTests(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.sg = test_data.share_group
|
||||
self.sg_nl = test_data.share_group_nameless
|
||||
self.sg_dhss_true = test_data.share_group_dhss_true
|
||||
self.sgs = test_data.share_group_snapshot
|
||||
self.sgs_nl = test_data.share_group_snapshot_nameless
|
||||
|
||||
def test_share_group_snapshots_list_get(self):
|
||||
share_groups = [self.sg, self.sg_nl, self.sg_dhss_true]
|
||||
sgss = [self.sgs, self.sgs_nl]
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_list',
|
||||
mock.Mock(return_value=sgss))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_list',
|
||||
mock.Mock(return_value=share_groups))
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertMessageCount(error=0)
|
||||
self.assertNoMessages()
|
||||
api_manila.share_group_snapshot_list.assert_called_once_with(
|
||||
mock.ANY, search_opts={'all_tenants': True})
|
||||
api_manila.share_group_list.assert_called_once_with(mock.ANY)
|
||||
self.assertTemplateUsed(
|
||||
res, 'project/share_group_snapshots/index.html')
|
||||
self.assertContains(res, "<h1>Share Group Snapshots</h1>")
|
||||
self.assertContains(
|
||||
res, 'Delete Share Group Snapshot</button>', len(sgss))
|
||||
self.assertContains(res, 'Delete Share Group Snapshots</button>', 1)
|
||||
for sgs in sgss:
|
||||
self.assertContains(
|
||||
res, 'value="share_group_snapshots__delete__%s' % sgs.id, 1)
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/project/share_group_snapshots/%(id)s/" >%(name)s</a' % {
|
||||
'id': self.sgs.id, 'name': self.sgs.name}, 1)
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/project/share_group_snapshots/%s/" '
|
||||
'>-</a>' % self.sgs_nl.id, 1)
|
||||
|
||||
def test_share_group_snapshots_list_error_get(self):
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_list',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertTemplateUsed(
|
||||
res, 'project/share_group_snapshots/index.html')
|
||||
self.assertContains(res, "<h1>Share Group Snapshots</h1>")
|
||||
self.assertContains(res, 'Delete Share Group Snapshot</button>', 0)
|
||||
self.assertContains(res, 'Delete Share Group Snapshots</button>', 0)
|
||||
self.assertNoMessages()
|
||||
|
||||
@ddt.data(
|
||||
test_data.share_group_snapshot,
|
||||
test_data.share_group_snapshot_nameless,
|
||||
)
|
||||
def test_share_group_snapshot_detailed_page_get(self, sgs):
|
||||
sg = test_data.share_group_nameless
|
||||
url = reverse(
|
||||
'horizon:project:share_group_snapshots:detail', args=[sgs.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(return_value=sgs))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(return_value=sg))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'project/share_group_snapshots/detail.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, sgs.id)
|
||||
api_manila.share_group_get.assert_called_once_with(
|
||||
mock.ANY, sgs.share_group_id)
|
||||
|
||||
def test_share_group_snapshot_detailed_page_error_get(self):
|
||||
url = reverse(
|
||||
'horizon:project:share_group_snapshots:detail', args=[self.sgs.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateNotUsed(
|
||||
res, 'admin/share_group_snapshots/detail.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(error=1)
|
||||
self.assertMessageCount(success=0)
|
||||
|
||||
@ddt.data(
|
||||
lambda *args, **kwargs: test_data.share_group,
|
||||
type('CustomExc', (Exception, ), {}),
|
||||
)
|
||||
def test_share_group_snapshot_create_get(self, sg_get_side_effect):
|
||||
url = reverse(
|
||||
'horizon:project:share_group_snapshots:create', args=[self.sg.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get',
|
||||
mock.Mock(side_effect=sg_get_side_effect))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'project/share_group_snapshots/create.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertNoMessages()
|
||||
api_manila.share_group_get.assert_called_once_with(
|
||||
mock.ANY, self.sg.id)
|
||||
self.assertMessageCount(error=0)
|
||||
|
||||
def test_share_group_snapshot_create_post(self):
|
||||
url = reverse(
|
||||
'horizon:project:share_group_snapshots:create', args=[self.sg.id])
|
||||
form_data = {
|
||||
'method': 'CreateShareGroupSnapshotForm',
|
||||
'name': 'fake_SG_snapshot_name',
|
||||
'description': 'fake SG snapshot description',
|
||||
'share_group_id': self.sg.id,
|
||||
}
|
||||
self.mock_object(
|
||||
api_manila, "share_group_snapshot_create",
|
||||
mock.Mock(return_value=self.sgs))
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertTemplateNotUsed(
|
||||
res, 'project/share_group_snapshots/create.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
self.assertMessageCount(error=0)
|
||||
self.assertMessageCount(success=1)
|
||||
api_manila.share_group_snapshot_create.assert_called_once_with(
|
||||
mock.ANY, self.sg.id, form_data['name'], form_data['description'])
|
||||
|
||||
def test_share_group_snapshot_create_error_post(self):
|
||||
url = reverse(
|
||||
'horizon:project:share_group_snapshots:create', args=[self.sg.id])
|
||||
form_data = {
|
||||
'method': 'CreateShareGroupSnapshotForm',
|
||||
'name': 'fake_SG_snapshot_name',
|
||||
'description': 'fake SG snapshot description',
|
||||
'share_group_id': self.sg.id,
|
||||
}
|
||||
self.mock_object(
|
||||
api_manila, "share_group_snapshot_create",
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertTemplateNotUsed(
|
||||
res, 'project/share_group_snapshots/create.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
self.assertMessageCount(error=1)
|
||||
self.assertMessageCount(success=0)
|
||||
api_manila.share_group_snapshot_create.assert_called_once_with(
|
||||
mock.ANY, self.sg.id, form_data['name'], form_data['description'])
|
||||
|
||||
def test_share_group_snapshot_update_get(self):
|
||||
url = reverse(
|
||||
'horizon:project:share_group_snapshots:update', args=[self.sgs.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(return_value=self.sgs))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'project/share_group_snapshots/update.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertNoMessages()
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id)
|
||||
|
||||
def test_share_group_snapshot_update_error_get(self):
|
||||
url = reverse(
|
||||
'horizon:project:share_group_snapshots:update', args=[self.sgs.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateNotUsed(
|
||||
res, 'project/share_group_snapshots/update.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
self.assertMessageCount(error=1)
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id)
|
||||
|
||||
def test_share_group_snapshot_update_post(self):
|
||||
self.mock_object(api_manila, "share_group_snapshot_update")
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(return_value=self.sgs))
|
||||
form_data = {
|
||||
'method': 'UpdateShareGroupSnapshotForm',
|
||||
'name': self.sgs.name,
|
||||
'description': self.sgs.description,
|
||||
}
|
||||
url = reverse(
|
||||
'horizon:project:share_group_snapshots:update', args=[self.sgs.id])
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
api_manila.share_group_snapshot_update.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id, form_data['name'], form_data['description'])
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id)
|
||||
self.assertMessageCount(error=0)
|
||||
self.assertMessageCount(success=1)
|
||||
|
||||
def test_share_group_snapshot_update_error_post(self):
|
||||
self.mock_object(
|
||||
api_manila, "share_group_snapshot_update",
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_get',
|
||||
mock.Mock(return_value=self.sgs))
|
||||
form_data = {
|
||||
'method': 'UpdateShareGroupSnapshotForm',
|
||||
'name': self.sgs.name,
|
||||
'description': self.sgs.description,
|
||||
}
|
||||
url = reverse(
|
||||
'horizon:project:share_group_snapshots:update', args=[self.sgs.id])
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
api_manila.share_group_snapshot_update.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id, form_data['name'], form_data['description'])
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id)
|
||||
self.assertMessageCount(error=1)
|
||||
self.assertMessageCount(success=0)
|
||||
|
||||
def test_share_group_snapshot_delete_post(self):
|
||||
data = {'action': 'share_group_snapshots__delete__%s' % self.sgs.id}
|
||||
self.mock_object(api_manila, "share_group_snapshot_delete")
|
||||
self.mock_object(
|
||||
api_manila, "share_group_snapshot_list",
|
||||
mock.Mock(return_value=[self.sgs]))
|
||||
|
||||
res = self.client.post(INDEX_URL, data)
|
||||
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(success=1)
|
||||
api_manila.share_group_snapshot_delete.assert_called_once_with(
|
||||
mock.ANY, self.sgs.id)
|
||||
api_manila.share_group_snapshot_list.assert_called_once_with(
|
||||
mock.ANY, search_opts={'all_tenants': True})
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
383
manila_ui/tests/dashboards/project/share_groups/tests.py
Normal file
383
manila_ui/tests/dashboards/project/share_groups/tests.py
Normal file
@ -0,0 +1,383 @@
|
||||
# Copyright (c) 2017 Mirantis, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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 ddt
|
||||
from django.core.urlresolvers import reverse
|
||||
import mock
|
||||
|
||||
from manila_ui.api import manila as api_manila
|
||||
from manila_ui.tests.dashboards.project import test_data
|
||||
from manila_ui.tests import helpers as test
|
||||
|
||||
INDEX_URL = reverse('horizon:project:share_groups:index')
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareGroupTests(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.sg = test_data.share_group
|
||||
self.sg_nl = test_data.share_group_nameless
|
||||
self.sg_dhss_true = test_data.share_group_dhss_true
|
||||
|
||||
def test_share_groups_list_get(self):
|
||||
sgs = [self.sg, self.sg_nl, self.sg_dhss_true]
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_list', mock.Mock(return_value=sgs))
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertStatusCode(res, 200)
|
||||
api_manila.share_group_list.assert_called_once_with(
|
||||
mock.ANY, detailed=True)
|
||||
self.assertTemplateUsed(res, 'project/share_groups/index.html')
|
||||
self.assertContains(res, "<h1>Share Groups</h1>")
|
||||
self.assertContains(res, 'Delete Share Group</button>', len(sgs))
|
||||
self.assertContains(res, 'Delete Share Groups</button>', 1)
|
||||
for sg in sgs:
|
||||
self.assertContains(
|
||||
res, 'value="share_groups__delete__%s' % sg.id, 1)
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/project/share_networks/%s"' % (
|
||||
self.sg_dhss_true.share_network_id), 1)
|
||||
for sg in (self.sg, self.sg_dhss_true):
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/project/share_groups/%(id)s/" >%(name)s</a>' % {
|
||||
'id': sg.id, 'name': sg.name}, 1)
|
||||
self.assertContains(
|
||||
res,
|
||||
'<a href="/project/share_groups/%s/" >-</a>' % self.sg_nl.id, 1)
|
||||
self.assertNoMessages()
|
||||
|
||||
def test_share_group_list_error_get(self):
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_list',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertTemplateUsed(res, 'project/share_groups/index.html')
|
||||
self.assertContains(res, "<h1>Share Groups</h1>")
|
||||
self.assertContains(res, 'Delete Share Group</button>', 0)
|
||||
self.assertContains(res, 'Delete Share Groups</button>', 0)
|
||||
self.assertNoMessages()
|
||||
|
||||
@ddt.data(
|
||||
test_data.share_group_nameless,
|
||||
test_data.share_group_dhss_true,
|
||||
)
|
||||
def test_share_group_detailed_page_get(self, sg):
|
||||
url = reverse('horizon:project:share_groups:detail', args=[sg.id])
|
||||
shares = [test_data.share, test_data.nameless_share]
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(return_value=sg))
|
||||
self.mock_object(
|
||||
api_manila, 'share_list', mock.Mock(return_value=shares))
|
||||
self.mock_object(
|
||||
api_manila, 'share_type_list', mock.Mock(return_value=[
|
||||
test_data.share_type, test_data.share_type_dhss_true]))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res, 'project/share_groups/detail.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
for share in shares:
|
||||
data = {'id': share.id, 'name': share.name or share.id}
|
||||
self.assertContains(
|
||||
res, '<a href="/project/shares/%(id)s/">%(name)s</a>' % data)
|
||||
|
||||
def test_share_group_detailed_page_error_get(self):
|
||||
url = reverse('horizon:project:share_groups:detail', args=[self.sg.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateNotUsed(res, 'project/share_groups/detail.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(error=1)
|
||||
self.assertMessageCount(success=0)
|
||||
|
||||
def test_share_group_update_get(self):
|
||||
url = reverse('horizon:project:share_groups:update', args=[self.sg.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(return_value=self.sg))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res, 'project/share_groups/update.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertNoMessages()
|
||||
api_manila.share_group_get.assert_called_once_with(
|
||||
mock.ANY, self.sg.id)
|
||||
|
||||
def test_share_group_update_error_get(self):
|
||||
url = reverse('horizon:project:share_groups:update', args=[self.sg.id])
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateNotUsed(res, 'project/share_groups/update.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
self.assertMessageCount(error=1)
|
||||
api_manila.share_group_get.assert_called_once_with(
|
||||
mock.ANY, self.sg.id)
|
||||
|
||||
def test_share_group_update_post(self):
|
||||
self.mock_object(api_manila, "share_group_update")
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(return_value=self.sg))
|
||||
form_data = {
|
||||
'method': 'UpdateShareGroupForm',
|
||||
'name': self.sg.name,
|
||||
'description': self.sg.description,
|
||||
}
|
||||
url = reverse('horizon:project:share_groups:update', args=[self.sg.id])
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
api_manila.share_group_update.assert_called_once_with(
|
||||
mock.ANY, self.sg.id, form_data['name'], form_data['description'])
|
||||
api_manila.share_group_get.assert_called_once_with(
|
||||
mock.ANY, self.sg.id)
|
||||
self.assertMessageCount(error=0)
|
||||
self.assertMessageCount(success=1)
|
||||
|
||||
def test_share_group_update_error_post(self):
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_update',
|
||||
mock.Mock(side_effect=type('CustomExc', (Exception, ), {})))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_get', mock.Mock(return_value=self.sg))
|
||||
form_data = {
|
||||
'method': 'UpdateShareGroupForm',
|
||||
'name': self.sg.name,
|
||||
'description': self.sg.description,
|
||||
}
|
||||
url = reverse('horizon:project:share_groups:update', args=[self.sg.id])
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
api_manila.share_group_update.assert_called_once_with(
|
||||
mock.ANY, self.sg.id, form_data['name'], form_data['description'])
|
||||
api_manila.share_group_get.assert_called_once_with(
|
||||
mock.ANY, self.sg.id)
|
||||
self.assertMessageCount(error=1)
|
||||
self.assertMessageCount(success=0)
|
||||
|
||||
def test_share_group_delete_post(self):
|
||||
sg = test_data.share_group_dhss_true
|
||||
data = {'action': 'share_groups__delete__%s' % sg.id}
|
||||
self.mock_object(api_manila, "share_group_delete")
|
||||
self.mock_object(
|
||||
api_manila, "share_group_list", mock.Mock(return_value=[sg]))
|
||||
|
||||
res = self.client.post(INDEX_URL, data)
|
||||
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertMessageCount(success=1)
|
||||
api_manila.share_group_delete.assert_called_once_with(mock.ANY, sg.id)
|
||||
api_manila.share_group_list.assert_called_once_with(
|
||||
mock.ANY, detailed=True)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_share_group_create_get(self):
|
||||
url = reverse('horizon:project:share_groups:create')
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_type_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_group_type,
|
||||
test_data.share_group_type_private,
|
||||
test_data.share_group_type_dhss_true,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_group_snapshot,
|
||||
test_data.share_group_snapshot_nameless,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'share_network_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.inactive_share_network,
|
||||
test_data.active_share_network,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'share_type_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_type,
|
||||
test_data.share_type_private,
|
||||
test_data.share_type_dhss_true,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'availability_zone_list',
|
||||
mock.Mock(return_value=[]))
|
||||
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res, 'project/share_groups/create.html')
|
||||
self.assertStatusCode(res, 200)
|
||||
self.assertNoMessages()
|
||||
self.assertMessageCount(error=0)
|
||||
api_manila.share_group_type_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_group_snapshot_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_network_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_type_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.availability_zone_list.assert_called_once_with(mock.ANY)
|
||||
|
||||
def test_share_group_create_post(self):
|
||||
url = reverse('horizon:project:share_groups:create')
|
||||
form_data = {
|
||||
'method': 'CreateShareGroupForm',
|
||||
'name': 'fake_sg_name',
|
||||
'description': 'fake SG description',
|
||||
'sgt': test_data.share_group_type.id,
|
||||
'share-type-choices-%s' % test_data.share_group_type.id: (
|
||||
test_data.share_group_type.share_types[0]),
|
||||
'availability_zone': '',
|
||||
'share_network': test_data.inactive_share_network.id,
|
||||
'snapshot': '',
|
||||
}
|
||||
self.mock_object(
|
||||
api_manila, "share_group_create", mock.Mock(return_value=self.sg))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_type_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_group_type,
|
||||
test_data.share_group_type_private,
|
||||
test_data.share_group_type_dhss_true,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_group_snapshot,
|
||||
test_data.share_group_snapshot_nameless,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'share_network_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.inactive_share_network,
|
||||
test_data.active_share_network,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'share_type_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_type,
|
||||
test_data.share_type_private,
|
||||
test_data.share_type_dhss_true,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'availability_zone_list',
|
||||
mock.Mock(return_value=[]))
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertTemplateNotUsed(res, 'project/share_groups/create.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
api_manila.share_group_type_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_group_snapshot_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_network_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_type_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.availability_zone_list.assert_called_once_with(mock.ANY)
|
||||
api_manila.share_group_create.assert_called_once_with(
|
||||
mock.ANY,
|
||||
name=form_data['name'],
|
||||
description=form_data['description'],
|
||||
share_group_type=test_data.share_group_type.id,
|
||||
share_types=[test_data.share_type.id],
|
||||
share_network=form_data['share_network'],
|
||||
source_share_group_snapshot=None,
|
||||
availability_zone=form_data['availability_zone'])
|
||||
|
||||
def test_share_group_create_from_snapshot_post(self):
|
||||
url = reverse('horizon:project:share_groups:create')
|
||||
form_data = {
|
||||
'method': 'CreateShareGroupForm',
|
||||
'name': 'fake_sg_name',
|
||||
'description': 'fake SG description',
|
||||
'sgt': '',
|
||||
'snapshot': test_data.share_group_snapshot.id,
|
||||
}
|
||||
self.mock_object(
|
||||
api_manila, "share_group_snapshot_get",
|
||||
mock.Mock(return_value=test_data.share_group_snapshot))
|
||||
self.mock_object(
|
||||
api_manila, "share_group_get", mock.Mock(return_value=self.sg_nl))
|
||||
self.mock_object(
|
||||
api_manila, "share_group_create", mock.Mock(return_value=self.sg))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_type_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_group_type,
|
||||
test_data.share_group_type_private,
|
||||
test_data.share_group_type_dhss_true,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'share_group_snapshot_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_group_snapshot,
|
||||
test_data.share_group_snapshot_nameless,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'share_network_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.inactive_share_network,
|
||||
test_data.active_share_network,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'share_type_list',
|
||||
mock.Mock(return_value=[
|
||||
test_data.share_type,
|
||||
test_data.share_type_private,
|
||||
test_data.share_type_dhss_true,
|
||||
]))
|
||||
self.mock_object(
|
||||
api_manila, 'availability_zone_list',
|
||||
mock.Mock(return_value=[]))
|
||||
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertTemplateNotUsed(res, 'project/share_groups/create.html')
|
||||
self.assertStatusCode(res, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
api_manila.share_group_snapshot_list.assert_not_called()
|
||||
api_manila.share_group_type_list.assert_not_called()
|
||||
api_manila.share_network_list.assert_not_called()
|
||||
api_manila.share_type_list.assert_not_called()
|
||||
api_manila.availability_zone_list.assert_not_called()
|
||||
api_manila.share_group_snapshot_get.assert_called_once_with(
|
||||
mock.ANY, test_data.share_group_snapshot.id)
|
||||
api_manila.share_group_create.assert_called_once_with(
|
||||
mock.ANY,
|
||||
name=form_data['name'],
|
||||
description=form_data['description'],
|
||||
share_group_type=test_data.share_group_type.id,
|
||||
share_types=None,
|
||||
share_network=None,
|
||||
source_share_group_snapshot=test_data.share_group_snapshot.id,
|
||||
availability_zone=None)
|
@ -45,6 +45,9 @@ class ShareViewTests(test.APITestCase):
|
||||
self.fake_share_type.get_keys = mock.Mock(
|
||||
return_value={'driver_handles_share_servers': 'True'})
|
||||
self.share = test_data.share
|
||||
self.mock_object(
|
||||
api_manila, "share_group_list",
|
||||
mock.Mock(return_value=[]))
|
||||
self.mock_object(
|
||||
api_manila, "share_get", mock.Mock(return_value=self.share))
|
||||
self.mock_object(
|
||||
@ -114,12 +117,14 @@ class ShareViewTests(test.APITestCase):
|
||||
api_manila, "share_type_list",
|
||||
mock.Mock(return_value=[self.fake_share_type, ]))
|
||||
|
||||
self.client.post(url, formData)
|
||||
res = self.client.post(url, formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
api_manila.share_create.assert_called_once_with(
|
||||
mock.ANY, size=formData['size'], name=formData['name'],
|
||||
description=formData['description'], proto=formData['share_proto'],
|
||||
snapshot_id=None, is_public=False, share_network=share_net.id,
|
||||
snapshot_id=None, is_public=False,
|
||||
share_group_id=None, share_network=share_net.id,
|
||||
metadata={}, share_type=formData['share_type'],
|
||||
availability_zone=formData['availability_zone'])
|
||||
api_manila.share_snapshot_list.assert_called_once_with(mock.ANY)
|
||||
@ -173,7 +178,7 @@ class ShareViewTests(test.APITestCase):
|
||||
mock.ANY, size=formData['size'], name=formData['name'],
|
||||
description=formData['description'], proto=formData['share_proto'],
|
||||
snapshot_id=snapshot.id, is_public=False,
|
||||
share_network=share_net.id, metadata={},
|
||||
share_group_id=None, share_network=share_net.id, metadata={},
|
||||
share_type=formData['share_type'],
|
||||
availability_zone=formData['availability_zone'])
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
@ -185,6 +190,8 @@ class ShareViewTests(test.APITestCase):
|
||||
self.mock_object(
|
||||
api_manila, "share_network_list", mock.Mock(return_value=[]))
|
||||
self.mock_object(api_manila, "share_delete")
|
||||
self.mock_object(
|
||||
api_manila, "share_get", mock.Mock(return_value=self.share))
|
||||
self.mock_object(
|
||||
api_manila, "share_list", mock.Mock(return_value=[self.share]))
|
||||
|
||||
@ -194,8 +201,9 @@ class ShareViewTests(test.APITestCase):
|
||||
api_manila.share_snapshot_list.assert_called_once_with(
|
||||
mock.ANY, detailed=True)
|
||||
api_manila.share_list.assert_called_with(mock.ANY)
|
||||
api_manila.share_get.assert_called_with(mock.ANY, self.share.id)
|
||||
api_manila.share_delete.assert_called_with(
|
||||
mock.ANY, self.share.id)
|
||||
mock.ANY, self.share.id, share_group_id=self.share.share_group_id)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_detail_view(self):
|
||||
@ -669,6 +677,7 @@ class ShareViewTests(test.APITestCase):
|
||||
metadata=utils.parse_str_meta(data['metadata'])[0],
|
||||
name=data['name'],
|
||||
proto=data['share_proto'],
|
||||
share_group_id=None,
|
||||
share_network=test_data.active_share_network.id,
|
||||
share_type=data['share_type'],
|
||||
size=data['size'],
|
||||
|
@ -32,6 +32,9 @@ except ImportError:
|
||||
from manilaclient.v1 import shares
|
||||
|
||||
from manilaclient.v2 import share_export_locations
|
||||
from manilaclient.v2 import share_group_snapshots
|
||||
from manilaclient.v2 import share_group_types
|
||||
from manilaclient.v2 import share_groups
|
||||
from manilaclient.v2 import share_instances
|
||||
from manilaclient.v2 import share_replicas
|
||||
from manilaclient.v2 import share_servers
|
||||
@ -59,6 +62,7 @@ share = shares.Share(
|
||||
'share_network_id': '7f3d1c33-8d00-4511-29df-a2def31f3b5d',
|
||||
'availability_zone': 'Test AZ',
|
||||
'replication_type': 'readable',
|
||||
'share_group_id': 'fake_share_group_id',
|
||||
'mount_snapshot_support': False})
|
||||
|
||||
nameless_share = shares.Share(
|
||||
@ -332,13 +336,136 @@ share_server_errored = share_servers.ShareServer(
|
||||
share_type = share_types.ShareType(
|
||||
share_types.ShareTypeManager(FakeAPIClient),
|
||||
{'id': 'share-type-id1',
|
||||
'name': 'test-share-type',
|
||||
'name': 'test-share-type1',
|
||||
'share_type_access:is_public': True,
|
||||
'extra_specs': {
|
||||
'snapshot_support': True,
|
||||
'driver_handles_share_servers': False}
|
||||
}
|
||||
)
|
||||
|
||||
share_type_private = share_types.ShareType(
|
||||
share_types.ShareTypeManager(FakeAPIClient),
|
||||
{'id': 'share-type-id2',
|
||||
'name': 'test-share-type2',
|
||||
'share_type_access:is_public': False,
|
||||
'extra_specs': {'driver_handles_share_servers': False}}
|
||||
)
|
||||
|
||||
share_type_dhss_true = share_types.ShareType(
|
||||
share_types.ShareTypeManager(FakeAPIClient),
|
||||
{'id': 'share-type-id3',
|
||||
'name': 'test-share-type3',
|
||||
'share_type_access:is_public': True,
|
||||
'extra_specs': {'driver_handles_share_servers': True}}
|
||||
)
|
||||
|
||||
share_group_type = share_group_types.ShareGroupType(
|
||||
share_group_types.ShareGroupTypeManager(FakeAPIClient),
|
||||
{'id': 'fake_share_group_type_id1',
|
||||
'name': 'fake_share_group_type_name',
|
||||
'share_types': [share_type.id],
|
||||
'group_specs': {'k1': 'v1', 'k2': 'v2'},
|
||||
'is_public': True}
|
||||
)
|
||||
|
||||
share_group_type_private = share_group_types.ShareGroupType(
|
||||
share_group_types.ShareGroupTypeManager(FakeAPIClient),
|
||||
{'id': 'fake_private_share_group_type_id2',
|
||||
'name': 'fake_private_share_group_type_name',
|
||||
'share_types': [share_type.id, share_type_private.id],
|
||||
'group_specs': {'k1': 'v1', 'k2': 'v2'},
|
||||
'is_public': False}
|
||||
)
|
||||
|
||||
share_group_type_dhss_true = share_group_types.ShareGroupType(
|
||||
share_group_types.ShareGroupTypeManager(FakeAPIClient),
|
||||
{'id': 'fake_share_group_type_id3',
|
||||
'name': 'fake_share_group_type_name',
|
||||
'share_types': [share_type_dhss_true.id],
|
||||
'group_specs': {'k3': 'v3', 'k4': 'v4'},
|
||||
'is_public': True}
|
||||
)
|
||||
|
||||
share_group = share_groups.ShareGroup(
|
||||
share_groups.ShareGroupManager(FakeAPIClient),
|
||||
{'id': 'fake_share_group_id',
|
||||
'name': 'fake_share_group_name',
|
||||
'description': 'fake sg description',
|
||||
'status': 'available',
|
||||
'share_types': [share_type.id],
|
||||
'share_group_type_id': share_group_type.id,
|
||||
'source_share_group_snapshot_id': None,
|
||||
'share_network_id': None,
|
||||
'share_server_id': None,
|
||||
'availability_zone': None,
|
||||
'host': 'fake_host_987654321',
|
||||
'consistent_snapshot_support': None,
|
||||
'created_at': '2017-05-31T13:36:15.000000',
|
||||
'project_id': 'fake_project_id_987654321'}
|
||||
)
|
||||
|
||||
share_group_nameless = share_groups.ShareGroup(
|
||||
share_groups.ShareGroupManager(FakeAPIClient),
|
||||
{'id': 'fake_nameless_share_group_id',
|
||||
'name': None,
|
||||
'status': 'available',
|
||||
'share_types': [share_type.id],
|
||||
'share_group_type_id': share_group_type.id,
|
||||
'source_share_group_snapshot_id': None,
|
||||
'share_network_id': None,
|
||||
'share_server_id': None,
|
||||
'availability_zone': None,
|
||||
'host': 'fake_host_987654321',
|
||||
'consistent_snapshot_support': None,
|
||||
'created_at': '2017-05-31T13:36:15.000000',
|
||||
'project_id': 'fake_project_id_987654321'}
|
||||
)
|
||||
|
||||
share_group_dhss_true = share_groups.ShareGroup(
|
||||
share_groups.ShareGroupManager(FakeAPIClient),
|
||||
{'id': 'fake_dhss_true_share_group_id',
|
||||
'name': 'fake_dhss_true_share_group_name',
|
||||
'status': 'available',
|
||||
'share_types': [share_type_dhss_true.id],
|
||||
'share_group_type_id': share_group_type_dhss_true.id,
|
||||
'source_share_group_snapshot_id': None,
|
||||
'share_network_id': 'fake_share_network_id',
|
||||
'share_server_id': 'fake_share_server_id',
|
||||
'availability_zone': None,
|
||||
'host': 'fake_host_987654321',
|
||||
'consistent_snapshot_support': None,
|
||||
'created_at': '2017-05-31T23:59:59.000000',
|
||||
'project_id': 'fake_project_id_987654321'}
|
||||
)
|
||||
|
||||
share_group_snapshot = share_group_snapshots.ShareGroupSnapshot(
|
||||
share_group_snapshots.ShareGroupSnapshotManager(FakeAPIClient),
|
||||
{'id': 'fake_share_group_snapshot_id_1',
|
||||
'name': 'fake_share_group_snapshot_name',
|
||||
'status': 'available',
|
||||
'share_group_id': share_group.id,
|
||||
'description': 'fake sgs description',
|
||||
'created_at': '2017-06-01T13:13:13.000000',
|
||||
'project_id': 'fake_project_id_987654321',
|
||||
'members': [
|
||||
{'share_id': 'fake_share_id_1', 'id': 'fake_ssi_id_1', 'size': 1},
|
||||
{'share_id': 'fake_share_id_2', 'id': 'fake_ssi_id_2', 'size': 2},
|
||||
]}
|
||||
)
|
||||
|
||||
share_group_snapshot_nameless = share_group_snapshots.ShareGroupSnapshot(
|
||||
share_group_snapshots.ShareGroupSnapshotManager(FakeAPIClient),
|
||||
{'id': 'fake_share_group_snapshot_id_2_nameless',
|
||||
'name': None,
|
||||
'status': 'available',
|
||||
'share_group_id': share_group_nameless.id,
|
||||
'description': 'fake nameless sgs description',
|
||||
'created_at': '2017-06-02T14:14:14.000000',
|
||||
'project_id': 'fake_project_id_987654321',
|
||||
'members': []}
|
||||
)
|
||||
|
||||
# Quota Sets
|
||||
quota_data = dict(shares='1',
|
||||
share_snapshots='1',
|
||||
|
Loading…
x
Reference in New Issue
Block a user