Refactor admin dashboard
Separating tabs of single panel to separate panels. It will reduce amount of redundant calls, because it is very unlikely that someone will need all tabs at once. Also, it is current approach that is used by core projects. Change-Id: I874253e0e9a35ede8239bc1bdf0a330a44ade413 Partially-Implements BluePrint create-share-panel-group
This commit is contained in:
parent
3c7864717e
commit
6dcc671543
@ -57,7 +57,7 @@ Install Manila UI with all dependencies in your virtual environment::
|
|||||||
|
|
||||||
And enable it in Horizon::
|
And enable it in Horizon::
|
||||||
|
|
||||||
cp ../manila-ui/manila_ui/local/enabled/_90_manila_*.py openstack_dashboard/local/enabled
|
cp ../manila-ui/manila_ui/local/enabled/_*.py openstack_dashboard/local/enabled
|
||||||
cp ../manila-ui/manila_ui/local/local_settings.d/_90_manila_*.py openstack_dashboard/local/local_settings.d
|
cp ../manila-ui/manila_ui/local/local_settings.d/_90_manila_*.py openstack_dashboard/local/local_settings.d
|
||||||
|
|
||||||
|
|
||||||
|
30
manila_ui/dashboards/admin/security_services/panel.py
Normal file
30
manila_ui/dashboards/admin/security_services/panel.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.admin import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityServices(horizon.Panel):
|
||||||
|
name = _("Security Services")
|
||||||
|
slug = 'security_services'
|
||||||
|
permissions = (
|
||||||
|
'openstack.services.share',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Admin.register(SecurityServices)
|
68
manila_ui/dashboards/admin/security_services/tables.py
Normal file
68
manila_ui/dashboards/admin/security_services/tables.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
from manila_ui.api import manila
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteSecurityService(tables.DeleteAction):
|
||||||
|
policy_rules = (("share", "security_service:delete"),)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Delete Security Service",
|
||||||
|
u"Delete Security Services",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Deleted Security Service",
|
||||||
|
u"Deleted Security Services",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete(self, request, obj_id):
|
||||||
|
manila.security_service_delete(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityServicesTable(tables.DataTable):
|
||||||
|
name = tables.WrappingColumn(
|
||||||
|
"name", verbose_name=_("Name"),
|
||||||
|
link="horizon:admin:security_services:security_service_detail")
|
||||||
|
project = tables.Column("project_name", verbose_name=_("Project"))
|
||||||
|
dns_ip = tables.Column("dns_ip", verbose_name=_("DNS IP"))
|
||||||
|
server = tables.Column("server", verbose_name=_("Server"))
|
||||||
|
domain = tables.Column("domain", verbose_name=_("Domain"))
|
||||||
|
user = tables.Column("user", verbose_name=_("Sid"))
|
||||||
|
|
||||||
|
def get_object_display(self, security_service):
|
||||||
|
return security_service.name
|
||||||
|
|
||||||
|
def get_object_id(self, security_service):
|
||||||
|
return str(security_service.id)
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "security_services"
|
||||||
|
verbose_name = _("Security Services")
|
||||||
|
table_actions = (
|
||||||
|
tables.NameFilterAction,
|
||||||
|
DeleteSecurityService,
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
DeleteSecurityService,
|
||||||
|
)
|
32
manila_ui/dashboards/admin/security_services/tabs.py
Normal file
32
manila_ui/dashboards/admin/security_services/tabs.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
from horizon import tabs
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityServiceOverviewTab(tabs.Tab):
|
||||||
|
name = _("Security Service Overview")
|
||||||
|
slug = "security_service_overview_tab"
|
||||||
|
template_name = "admin/security_services/_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {"sec_service": self.tab_group.kwargs["sec_service"]}
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityServiceDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "security_service_details"
|
||||||
|
tabs = (
|
||||||
|
SecurityServiceOverviewTab,
|
||||||
|
)
|
@ -0,0 +1,37 @@
|
|||||||
|
{% load i18n sizeformat parse_date %}
|
||||||
|
|
||||||
|
<h3>{% trans "Security Service Overview" %}</h3>
|
||||||
|
<div class="detail">
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Type" %}</dt>
|
||||||
|
<dd>{{ sec_service.type }}</dd>
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd>{{ sec_service.name }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ sec_service.id }}</dd>
|
||||||
|
{% if sec_service.description %}
|
||||||
|
<dt>{% trans "Description" %}</dt>
|
||||||
|
<dd>{{ sec_service.description }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<dt>{% trans "Created at" %}</dt>
|
||||||
|
<dd>{{ sec_service.created_at|parse_date }}</dd>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<h4>{% trans "Security Service Details" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "DNS IP" %}</dt>
|
||||||
|
<dd>{{ sec_service.dns_ip }}</dd>
|
||||||
|
<dt>{% trans "Server" %}</dt>
|
||||||
|
<dd>{{ sec_service.server }}</dd>
|
||||||
|
<dt>{% trans "Domain" %}</dt>
|
||||||
|
<dd>{{ sec_service.domain }}</dd>
|
||||||
|
<dt>{% trans "User" %}</dt>
|
||||||
|
<dd>{{ sec_service.user }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Security Service 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 "Shares" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ security_services_table.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
27
manila_ui/dashboards/admin/security_services/urls.py
Normal file
27
manila_ui/dashboards/admin/security_services/urls.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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.security_services import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
urls.url(
|
||||||
|
r'^$',
|
||||||
|
views.SecurityServicesView.as_view(),
|
||||||
|
name='index'),
|
||||||
|
urls.url(
|
||||||
|
r'^(?P<sec_service_id>[^/]+)$',
|
||||||
|
views.SecurityServiceDetailView.as_view(),
|
||||||
|
name='security_service_detail'),
|
||||||
|
]
|
55
manila_ui/dashboards/admin/security_services/views.py
Normal file
55
manila_ui/dashboards/admin/security_services/views.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Admin views for managing security services.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse_lazy
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tables
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from manila_ui.api import manila
|
||||||
|
import manila_ui.dashboards.admin.security_services.tables as ss_tables
|
||||||
|
import manila_ui.dashboards.admin.security_services.tabs as ss_tabs
|
||||||
|
from manila_ui.dashboards.admin import utils
|
||||||
|
import manila_ui.dashboards.project.shares.security_services.views as ss_views
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityServicesView(tables.MultiTableView):
|
||||||
|
table_classes = (
|
||||||
|
ss_tables.SecurityServicesTable,
|
||||||
|
)
|
||||||
|
template_name = "admin/security_services/index.html"
|
||||||
|
page_title = _("Security Services")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_security_services_data(self):
|
||||||
|
try:
|
||||||
|
security_services = manila.security_service_list(
|
||||||
|
self.request, search_opts={'all_tenants': True})
|
||||||
|
utils.set_project_name_to_objects(self.request, security_services)
|
||||||
|
except Exception:
|
||||||
|
security_services = []
|
||||||
|
exceptions.handle(
|
||||||
|
self.request, _("Unable to retrieve security services"))
|
||||||
|
return security_services
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityServiceDetailView(ss_views.Detail):
|
||||||
|
tab_group_class = ss_tabs.SecurityServiceDetailTabs
|
||||||
|
template_name = "admin/security_services/detail.html"
|
||||||
|
redirect_url = reverse_lazy('horizon:admin:security_services:index')
|
0
manila_ui/dashboards/admin/share_instances/forms.py
Normal file
0
manila_ui/dashboards/admin/share_instances/forms.py
Normal file
28
manila_ui/dashboards/admin/share_instances/panel.py
Normal file
28
manila_ui/dashboards/admin/share_instances/panel.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
import horizon
|
||||||
|
from openstack_dashboard.dashboards.admin import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class ShareInstances(horizon.Panel):
|
||||||
|
name = _("Share Instances")
|
||||||
|
slug = 'share_instances'
|
||||||
|
permissions = (
|
||||||
|
'openstack.services.share',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Admin.register(ShareInstances)
|
93
manila_ui/dashboards/admin/share_instances/tables.py
Normal file
93
manila_ui/dashboards/admin/share_instances/tables.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
# 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 tables
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
class ShareInstancesTable(tables.DataTable):
|
||||||
|
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"),
|
||||||
|
)
|
||||||
|
uuid = tables.Column(
|
||||||
|
"id", verbose_name=_("ID"),
|
||||||
|
link="horizon:admin:share_instances:share_instance_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"))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "share_instances"
|
||||||
|
verbose_name = _("Share Instances")
|
||||||
|
status_columns = ("status", )
|
||||||
|
table_actions = (
|
||||||
|
tables.NameFilterAction,)
|
||||||
|
multi_select = False
|
||||||
|
|
||||||
|
def get_share_network_link(share_instance):
|
||||||
|
if getattr(share_instance, 'share_network_id', None):
|
||||||
|
return reverse("horizon:admin:share_networks:share_network_detail",
|
||||||
|
args=(share_instance.share_network_id,))
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_share_server_link(share_instance):
|
||||||
|
if getattr(share_instance, 'share_server_id', None):
|
||||||
|
return reverse("horizon:admin:share_servers:share_server_detail",
|
||||||
|
args=(share_instance.share_server_id,))
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_share_link(share_instance):
|
||||||
|
if getattr(share_instance, 'share_id', None):
|
||||||
|
return reverse("horizon:admin:shares:detail",
|
||||||
|
args=(share_instance.share_id,))
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
share_net_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 Id"),
|
||||||
|
link=get_share_server_link)
|
||||||
|
share_id = tables.Column(
|
||||||
|
"share_id",
|
||||||
|
verbose_name=_("Share ID"),
|
||||||
|
link=get_share_link)
|
||||||
|
|
||||||
|
def get_object_display(self, share_instance):
|
||||||
|
return six.text_type(share_instance.id)
|
||||||
|
|
||||||
|
def get_object_id(self, share_instance):
|
||||||
|
return six.text_type(share_instance.id)
|
32
manila_ui/dashboards/admin/share_instances/tabs.py
Normal file
32
manila_ui/dashboards/admin/share_instances/tabs.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
from horizon import tabs
|
||||||
|
|
||||||
|
|
||||||
|
class ShareInstanceOverviewTab(tabs.Tab):
|
||||||
|
name = _("Share Instance Overview")
|
||||||
|
slug = "share_instance_overview_tab"
|
||||||
|
template_name = "admin/share_instances/_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {"share_instance": self.tab_group.kwargs["share_instance"]}
|
||||||
|
|
||||||
|
|
||||||
|
class ShareInstanceDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "share_instance_details"
|
||||||
|
tabs = (
|
||||||
|
ShareInstanceOverviewTab,
|
||||||
|
)
|
@ -29,16 +29,16 @@
|
|||||||
<dt>{% trans "Availability Zone" %}</dt>
|
<dt>{% trans "Availability Zone" %}</dt>
|
||||||
<dd>{{ share_instance.availability_zone}}</dd>
|
<dd>{{ share_instance.availability_zone}}</dd>
|
||||||
<dt>{% trans "Share ID" %}</dt>
|
<dt>{% trans "Share ID" %}</dt>
|
||||||
{% url 'horizon:project:shares:detail' share_instance.share_id as share_url %}
|
{% url 'horizon:admin:shares:detail' share_instance.share_id as share_url %}
|
||||||
<dd><a href="{{ share_url }}">{{ share_instance.share_id }}</a></dd>
|
<dd><a href="{{ share_url }}">{{ share_instance.share_id }}</a></dd>
|
||||||
{% if share_instance.share_network_id %}
|
{% if share_instance.share_network_id %}
|
||||||
<dt>{% trans "Share network" %}</dt>
|
<dt>{% trans "Share network" %}</dt>
|
||||||
{% url 'horizon:project:shares:share_network_detail' share_instance.share_network_id as sn_url%}
|
{% url 'horizon:admin:share_networks:share_network_detail' share_instance.share_network_id as sn_url%}
|
||||||
<dd><a href="{{ sn_url }}">{{ share_instance.share_network_id }}</a></dd>
|
<dd><a href="{{ sn_url }}">{{ share_instance.share_network_id }}</a></dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if share_instance.share_server_id %}
|
{% if share_instance.share_server_id %}
|
||||||
<dt>{% trans "Share server" %}</dt>
|
<dt>{% trans "Share server" %}</dt>
|
||||||
{% url 'horizon:admin:shares:share_server_detail' share_instance.share_server_id as share_server_url%}
|
{% url 'horizon:admin:share_servers:share_server_detail' share_instance.share_server_id as share_server_url%}
|
||||||
<dd><a href="{{ share_server_url }}">{{ share_instance.share_server_id }}</a></dd>
|
<dd><a href="{{ share_server_url }}">{{ share_instance.share_server_id }}</a></dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<dt>{% trans "Created" %}</dt>
|
<dt>{% trans "Created" %}</dt>
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Share Instances" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ share_instances_table.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
27
manila_ui/dashboards/admin/share_instances/urls.py
Normal file
27
manila_ui/dashboards/admin/share_instances/urls.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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_instances import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
urls.url(
|
||||||
|
r'^$',
|
||||||
|
views.ShareInstancesView.as_view(),
|
||||||
|
name='index'),
|
||||||
|
urls.url(
|
||||||
|
r'^(?P<share_instance_id>[^/]+)$',
|
||||||
|
views.ShareInstanceDetailView.as_view(),
|
||||||
|
name='share_instance_detail'),
|
||||||
|
]
|
87
manila_ui/dashboards/admin/share_instances/views.py
Normal file
87
manila_ui/dashboards/admin/share_instances/views.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Admin views for managing share instances.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from horizon import exceptions
|
||||||
|
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_instances import tables as si_tables
|
||||||
|
from manila_ui.dashboards.admin.share_instances import tabs as si_tabs
|
||||||
|
from manila_ui.dashboards import utils as ui_utils
|
||||||
|
|
||||||
|
|
||||||
|
class ShareInstancesView(tables.MultiTableView):
|
||||||
|
table_classes = (
|
||||||
|
si_tables.ShareInstancesTable,
|
||||||
|
)
|
||||||
|
template_name = "admin/share_instances/index.html"
|
||||||
|
page_title = _("Share Instances")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_share_instances_data(self):
|
||||||
|
try:
|
||||||
|
share_instances = manila.share_instance_list(self.request)
|
||||||
|
except Exception:
|
||||||
|
share_instances = []
|
||||||
|
exceptions.handle(
|
||||||
|
self.request, _("Unable to retrieve share instances."))
|
||||||
|
return share_instances
|
||||||
|
|
||||||
|
|
||||||
|
class ShareInstanceDetailView(tabs.TabView):
|
||||||
|
tab_group_class = si_tabs.ShareInstanceDetailTabs
|
||||||
|
template_name = 'admin/share_instances/detail.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(self.__class__, self).get_context_data(**kwargs)
|
||||||
|
share_instance = self.get_data()
|
||||||
|
context["share_instance"] = share_instance
|
||||||
|
context["page_title"] = (
|
||||||
|
_("Share Instance Details: %s") % share_instance.id)
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
try:
|
||||||
|
share_instance_id = self.kwargs['share_instance_id']
|
||||||
|
share_instance = manila.share_instance_get(
|
||||||
|
self.request, share_instance_id)
|
||||||
|
share_instance.export_locations = (
|
||||||
|
manila.share_instance_export_location_list(
|
||||||
|
self.request, share_instance_id))
|
||||||
|
export_locations = [
|
||||||
|
exp['path'] for exp in share_instance.export_locations
|
||||||
|
]
|
||||||
|
share_instance.el_size = ui_utils.calculate_longest_str_size(
|
||||||
|
export_locations)
|
||||||
|
return share_instance
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse('horizon:admin:share_instances:index')
|
||||||
|
exceptions.handle(
|
||||||
|
self.request,
|
||||||
|
_('Unable to retrieve share instance details.'),
|
||||||
|
redirect=redirect)
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
share_instance = self.get_data()
|
||||||
|
return self.tab_group_class(
|
||||||
|
request, share_instance=share_instance, **kwargs)
|
0
manila_ui/dashboards/admin/share_networks/forms.py
Normal file
0
manila_ui/dashboards/admin/share_networks/forms.py
Normal file
28
manila_ui/dashboards/admin/share_networks/panel.py
Normal file
28
manila_ui/dashboards/admin/share_networks/panel.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
import horizon
|
||||||
|
from openstack_dashboard.dashboards.admin import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class ShareNetworks(horizon.Panel):
|
||||||
|
name = _("Share Networks")
|
||||||
|
slug = 'share_networks'
|
||||||
|
permissions = (
|
||||||
|
'openstack.services.share',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Admin.register(ShareNetworks)
|
50
manila_ui/dashboards/admin/share_networks/tables.py
Normal file
50
manila_ui/dashboards/admin/share_networks/tables.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# 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 tables
|
||||||
|
import six
|
||||||
|
|
||||||
|
import manila_ui.dashboards.project.shares.share_networks.tables as sn_tables
|
||||||
|
|
||||||
|
|
||||||
|
class ShareNetworksTable(tables.DataTable):
|
||||||
|
name = tables.WrappingColumn(
|
||||||
|
"name", verbose_name=_("Name"),
|
||||||
|
link="horizon:admin:share_networks:share_network_detail")
|
||||||
|
project = tables.Column("project_name", verbose_name=_("Project"))
|
||||||
|
neutron_net = tables.Column("neutron_net", verbose_name=_("Neutron Net"))
|
||||||
|
neutron_subnet = tables.Column(
|
||||||
|
"neutron_subnet", verbose_name=_("Neutron Subnet"))
|
||||||
|
ip_version = tables.Column("ip_version", verbose_name=_("IP Version"))
|
||||||
|
network_type = tables.Column(
|
||||||
|
"network_type", verbose_name=_("Network Type"))
|
||||||
|
segmentation_id = tables.Column(
|
||||||
|
"segmentation_id", verbose_name=_("Segmentation Id"))
|
||||||
|
|
||||||
|
def get_object_display(self, share_network):
|
||||||
|
return share_network.name or six.text_type(share_network.id)
|
||||||
|
|
||||||
|
def get_object_id(self, share_network):
|
||||||
|
return six.text_type(share_network.id)
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "share_networks"
|
||||||
|
verbose_name = _("Share Networks")
|
||||||
|
table_actions = (
|
||||||
|
tables.NameFilterAction,
|
||||||
|
sn_tables.Delete,
|
||||||
|
)
|
||||||
|
row_class = sn_tables.UpdateRow
|
||||||
|
row_actions = (
|
||||||
|
sn_tables.Delete,
|
||||||
|
)
|
32
manila_ui/dashboards/admin/share_networks/tabs.py
Normal file
32
manila_ui/dashboards/admin/share_networks/tabs.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
from horizon import tabs
|
||||||
|
|
||||||
|
|
||||||
|
class ShareNetworkOverviewTab(tabs.Tab):
|
||||||
|
name = _("Share Network Overview")
|
||||||
|
slug = "share_network_overview_tab"
|
||||||
|
template_name = "admin/share_networks/_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {"share_network": self.tab_group.kwargs["share_network"]}
|
||||||
|
|
||||||
|
|
||||||
|
class ShareNetworkDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "share_network_details"
|
||||||
|
tabs = (
|
||||||
|
ShareNetworkOverviewTab,
|
||||||
|
)
|
@ -0,0 +1,56 @@
|
|||||||
|
{% load i18n sizeformat parse_date %}
|
||||||
|
|
||||||
|
<h3>{% trans "Share Network Overview" %}</h3>
|
||||||
|
<div class="detail">
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd>{{ share_network.name }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ share_network.id }}</dd>
|
||||||
|
{% if share_network.description %}
|
||||||
|
<dt>{% trans "Description" %}</dt>
|
||||||
|
<dd>{{ share_network.description }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
{% if share_network.share_servers %}
|
||||||
|
<dt>{% trans "Share Servers" %}</dt>
|
||||||
|
{% for server in share_network.share_servers %}
|
||||||
|
{% url 'horizon:admin:share_servers:share_server_detail' server.id as server_url %}
|
||||||
|
<dd><a href="{{ server_url }}">{{ server.id }}</a></dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<h4>{% trans "Net Details" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Network" %}</dt>
|
||||||
|
{% if share_network.neutron_net %}
|
||||||
|
<dd>{{ share_network.neutron_net }}</dd>
|
||||||
|
<dt>{% trans "Subnet" %}</dt>
|
||||||
|
<dd>{{ share_network.neutron_subnet}}</dd>
|
||||||
|
{% endif %}
|
||||||
|
{% if share_network.nova_net %}
|
||||||
|
<dd>{{ share_network.nova_net }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<h4>{% trans "Security Services" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
{% for sec_service in share_network.sec_services %}
|
||||||
|
{% url 'horizon:admin:security_services:security_service_detail' sec_service.id as sec_service_url%}
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Id" %}</dt>
|
||||||
|
<dd><a href="{{ sec_service_url }}">{{ sec_service.id }}</a></dd>
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd><a href="{{ sec_service_url }}">{{ sec_service.name }}</a></dd>
|
||||||
|
<dt>{% trans "Type" %}</dt>
|
||||||
|
<dd>{{ sec_service.type }}</dd>
|
||||||
|
</dl>
|
||||||
|
<br />
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Share Network 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 Networks" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ share_networks_table.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
27
manila_ui/dashboards/admin/share_networks/urls.py
Normal file
27
manila_ui/dashboards/admin/share_networks/urls.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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_networks import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
urls.url(
|
||||||
|
r'^$',
|
||||||
|
views.ShareNetworksView.as_view(),
|
||||||
|
name='index'),
|
||||||
|
urls.url(
|
||||||
|
r'^(?P<share_network_id>[^/]+)$',
|
||||||
|
views.ShareNetworkDetailView.as_view(),
|
||||||
|
name='share_network_detail'),
|
||||||
|
]
|
69
manila_ui/dashboards/admin/share_networks/views.py
Normal file
69
manila_ui/dashboards/admin/share_networks/views.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Admin views for managing share networks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse_lazy
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tables
|
||||||
|
from horizon.utils import memoized
|
||||||
|
from openstack_dashboard.api import base
|
||||||
|
from openstack_dashboard.api import neutron
|
||||||
|
|
||||||
|
from manila_ui.api import manila
|
||||||
|
from manila_ui.dashboards.admin.share_networks import tables as sn_tables
|
||||||
|
from manila_ui.dashboards.admin.share_networks import tabs as sn_tabs
|
||||||
|
from manila_ui.dashboards.admin import utils
|
||||||
|
import manila_ui.dashboards.project.shares.share_networks.views as p_views
|
||||||
|
|
||||||
|
|
||||||
|
class ShareNetworksView(tables.MultiTableView):
|
||||||
|
table_classes = (
|
||||||
|
sn_tables.ShareNetworksTable,
|
||||||
|
)
|
||||||
|
template_name = "admin/share_networks/index.html"
|
||||||
|
page_title = _("Share Networks")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_share_networks_data(self):
|
||||||
|
try:
|
||||||
|
share_networks = manila.share_network_list(
|
||||||
|
self.request, detailed=True, search_opts={'all_tenants': True})
|
||||||
|
if base.is_service_enabled(self.request, 'network'):
|
||||||
|
neutron_net_names = dict(
|
||||||
|
(net.id, net.name)
|
||||||
|
for net in neutron.network_list(self.request))
|
||||||
|
neutron_subnet_names = dict(
|
||||||
|
(net.id, net.name)
|
||||||
|
for net in neutron.subnet_list(self.request))
|
||||||
|
for sn in share_networks:
|
||||||
|
sn.neutron_net = neutron_net_names.get(
|
||||||
|
sn.neutron_net_id) or sn.neutron_net_id or "-"
|
||||||
|
sn.neutron_subnet = neutron_subnet_names.get(
|
||||||
|
sn.neutron_subnet_id) or sn.neutron_subnet_id or "-"
|
||||||
|
except Exception:
|
||||||
|
share_networks = []
|
||||||
|
exceptions.handle(
|
||||||
|
self.request, _("Unable to retrieve share networks"))
|
||||||
|
utils.set_project_name_to_objects(self.request, share_networks)
|
||||||
|
return share_networks
|
||||||
|
|
||||||
|
|
||||||
|
class ShareNetworkDetailView(p_views.Detail):
|
||||||
|
tab_group_class = sn_tabs.ShareNetworkDetailTabs
|
||||||
|
template_name = "admin/share_networks/detail.html"
|
||||||
|
redirect_url = reverse_lazy("horizon:admin:share_networks:index")
|
0
manila_ui/dashboards/admin/share_servers/forms.py
Normal file
0
manila_ui/dashboards/admin/share_servers/forms.py
Normal file
28
manila_ui/dashboards/admin/share_servers/panel.py
Normal file
28
manila_ui/dashboards/admin/share_servers/panel.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
import horizon
|
||||||
|
from openstack_dashboard.dashboards.admin import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServers(horizon.Panel):
|
||||||
|
name = _("Share Servers")
|
||||||
|
slug = 'share_servers'
|
||||||
|
permissions = (
|
||||||
|
'openstack.services.share',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Admin.register(ShareServers)
|
118
manila_ui/dashboards/admin/share_servers/tables.py
Normal file
118
manila_ui/dashboards/admin/share_servers/tables.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# 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 tables
|
||||||
|
import six
|
||||||
|
|
||||||
|
from manila_ui.api import manila
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteShareServer(tables.DeleteAction):
|
||||||
|
policy_rules = (("share", "share_server:delete"),)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Delete Share Server",
|
||||||
|
u"Delete Share Server",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Deleted Share Server",
|
||||||
|
u"Deleted Share Server",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete(self, request, obj_id):
|
||||||
|
manila.share_server_delete(request, obj_id)
|
||||||
|
|
||||||
|
def allowed(self, request, share_serv):
|
||||||
|
if share_serv:
|
||||||
|
share_search_opts = {'share_server_id': share_serv.id}
|
||||||
|
shares_list = manila.share_list(
|
||||||
|
request, search_opts=share_search_opts)
|
||||||
|
if shares_list:
|
||||||
|
return False
|
||||||
|
return share_serv.status not in ("deleting", "creating")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateShareServerRow(tables.Row):
|
||||||
|
ajax = True
|
||||||
|
|
||||||
|
def get_data(self, request, share_serv_id):
|
||||||
|
share_serv = manila.share_server_get(request, share_serv_id)
|
||||||
|
return share_serv
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServersTable(tables.DataTable):
|
||||||
|
STATUS_CHOICES = (
|
||||||
|
("active", True),
|
||||||
|
("deleting", None),
|
||||||
|
("creating", None),
|
||||||
|
("error", False),
|
||||||
|
)
|
||||||
|
STATUS_DISPLAY_CHOICES = (
|
||||||
|
("in-use", pgettext_lazy("Current status of share server", u"In-use")),
|
||||||
|
("active", pgettext_lazy("Current status of share server", u"Active")),
|
||||||
|
("creating", pgettext_lazy("Current status of share server",
|
||||||
|
u"Creating")),
|
||||||
|
("error", pgettext_lazy("Current status of share server",
|
||||||
|
u"Error")),
|
||||||
|
)
|
||||||
|
uid = tables.Column(
|
||||||
|
"id", verbose_name=_("Id"),
|
||||||
|
link="horizon:admin:share_servers:share_server_detail")
|
||||||
|
host = tables.Column("host", verbose_name=_("Host"))
|
||||||
|
project = tables.Column("project_name", verbose_name=_("Project"))
|
||||||
|
|
||||||
|
def get_share_server_link(share_serv):
|
||||||
|
if hasattr(share_serv, 'share_network_id'):
|
||||||
|
return reverse("horizon:admin:share_networks:share_network_detail",
|
||||||
|
args=(share_serv.share_network_id,))
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
share_net_name = tables.Column(
|
||||||
|
"share_network_name", verbose_name=_("Share Network"),
|
||||||
|
link=get_share_server_link)
|
||||||
|
status = tables.Column(
|
||||||
|
"status", verbose_name=_("Status"),
|
||||||
|
status=True, filters=(title,), status_choices=STATUS_CHOICES,
|
||||||
|
display_choices=STATUS_DISPLAY_CHOICES)
|
||||||
|
|
||||||
|
def get_object_display(self, share_server):
|
||||||
|
return six.text_type(share_server.id)
|
||||||
|
|
||||||
|
def get_object_id(self, share_server):
|
||||||
|
return six.text_type(share_server.id)
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "share_servers"
|
||||||
|
status_columns = ["status"]
|
||||||
|
verbose_name = _("Share Server")
|
||||||
|
table_actions = (
|
||||||
|
tables.NameFilterAction,
|
||||||
|
DeleteShareServer,
|
||||||
|
)
|
||||||
|
row_class = UpdateShareServerRow
|
||||||
|
row_actions = (
|
||||||
|
DeleteShareServer,
|
||||||
|
)
|
32
manila_ui/dashboards/admin/share_servers/tabs.py
Normal file
32
manila_ui/dashboards/admin/share_servers/tabs.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Copyright 2014 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# 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 ShareServerOverviewTab(tabs.Tab):
|
||||||
|
name = _("Share Server Overview")
|
||||||
|
slug = "share_server_overview_tab"
|
||||||
|
template_name = "admin/share_servers/_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {"share_server": self.tab_group.kwargs["share_server"]}
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "share_server_details"
|
||||||
|
tabs = (
|
||||||
|
ShareServerOverviewTab,
|
||||||
|
)
|
@ -12,7 +12,7 @@
|
|||||||
<dd>{{ share_server.host}}</dd>
|
<dd>{{ share_server.host}}</dd>
|
||||||
<dt>{% trans "Share Network" %}</dt>
|
<dt>{% trans "Share Network" %}</dt>
|
||||||
{% if share_server.share_network_id %}
|
{% if share_server.share_network_id %}
|
||||||
{% url 'horizon:admin:shares:share_network_detail' share_server.share_network_id as share_net_url %}
|
{% url 'horizon:admin:share_networks:share_network_detail' share_server.share_network_id as share_net_url %}
|
||||||
<dd><a href="{{ share_net_url }}">{{ share_server.share_network_name }}</a></dd>
|
<dd><a href="{{ share_net_url }}">{{ share_server.share_network_name }}</a></dd>
|
||||||
{% else %}
|
{% else %}
|
||||||
<dd>{{ share_server.share_network_name }}</dd>
|
<dd>{{ share_server.share_network_name }}</dd>
|
||||||
@ -30,9 +30,9 @@
|
|||||||
<h4>{% trans "Specs" %}</h4>
|
<h4>{% trans "Specs" %}</h4>
|
||||||
<hr class="header_rule">
|
<hr class="header_rule">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
{% for key in share_server.backend_details %}
|
{% for key, value in share_server.backend_details.items %}
|
||||||
<dt>{{ key }}</dt>
|
<dt>{{ key }}</dt>
|
||||||
<dd>{{ share_server.backend_details|get_item:key }}</dd>
|
<dd>{{ value }}</dd>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Share Server 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 Servers" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ share_servers_table.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
27
manila_ui/dashboards/admin/share_servers/urls.py
Normal file
27
manila_ui/dashboards/admin/share_servers/urls.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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_servers import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
urls.url(
|
||||||
|
r'^$',
|
||||||
|
views.ShareServersView.as_view(),
|
||||||
|
name='index'),
|
||||||
|
urls.url(
|
||||||
|
r'^(?P<share_server_id>[^/]+)$',
|
||||||
|
views.ShareServerDetailView.as_view(),
|
||||||
|
name='share_server_detail'),
|
||||||
|
]
|
91
manila_ui/dashboards/admin/share_servers/views.py
Normal file
91
manila_ui/dashboards/admin/share_servers/views.py
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# Copyright 2012 Nebula, 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Admin views for managing share servers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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 tables
|
||||||
|
from horizon import tabs
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from manila_ui.api import manila
|
||||||
|
from manila_ui.dashboards.admin.share_servers import tables as ss_tables
|
||||||
|
from manila_ui.dashboards.admin.share_servers import tabs as ss_tabs
|
||||||
|
from manila_ui.dashboards.admin import utils
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServersView(tables.MultiTableView):
|
||||||
|
table_classes = (
|
||||||
|
ss_tables.ShareServersTable,
|
||||||
|
)
|
||||||
|
template_name = "admin/share_servers/index.html"
|
||||||
|
page_title = _("Share Servers")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_share_servers_data(self):
|
||||||
|
try:
|
||||||
|
share_servers = manila.share_server_list(self.request)
|
||||||
|
except Exception:
|
||||||
|
share_servers = []
|
||||||
|
exceptions.handle(
|
||||||
|
self.request, _("Unable to retrieve share servers"))
|
||||||
|
utils.set_project_name_to_objects(self.request, share_servers)
|
||||||
|
return share_servers
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerDetailView(tabs.TabView):
|
||||||
|
tab_group_class = ss_tabs.ShareServerDetailTabs
|
||||||
|
template_name = "admin/share_servers/detail.html"
|
||||||
|
redirect_url = reverse_lazy('horizon:admin:share_servers:index')
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(self.__class__, self).get_context_data(**kwargs)
|
||||||
|
share_server = self.get_data()
|
||||||
|
share_server_display_name = share_server.id
|
||||||
|
context["share_server"] = share_server
|
||||||
|
context["share_server_display_name"] = share_server_display_name
|
||||||
|
context["page_title"] = _("Share Server Details: %(server_name)s") % {
|
||||||
|
'server_name': share_server_display_name}
|
||||||
|
return context
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
try:
|
||||||
|
share_serv_id = self.kwargs['share_server_id']
|
||||||
|
share_serv = manila.share_server_get(self.request, share_serv_id)
|
||||||
|
share_search_opts = {'share_server_id': share_serv.id}
|
||||||
|
shares_list = manila.share_list(
|
||||||
|
self.request, search_opts=share_search_opts)
|
||||||
|
for share in shares_list:
|
||||||
|
share.name_or_id = share.name or share.id
|
||||||
|
share_serv.shares_list = shares_list
|
||||||
|
if not hasattr(share_serv, 'share_network_id'):
|
||||||
|
share_serv.share_network_id = None
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse('horizon:admin:share_servers:index')
|
||||||
|
exceptions.handle(
|
||||||
|
self.request,
|
||||||
|
_('Unable to retrieve share server details.'),
|
||||||
|
redirect=redirect)
|
||||||
|
return share_serv
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
share_server = self.get_data()
|
||||||
|
return self.tab_group_class(
|
||||||
|
request, share_server=share_server, **kwargs)
|
0
manila_ui/dashboards/admin/share_snapshots/forms.py
Normal file
0
manila_ui/dashboards/admin/share_snapshots/forms.py
Normal file
28
manila_ui/dashboards/admin/share_snapshots/panel.py
Normal file
28
manila_ui/dashboards/admin/share_snapshots/panel.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
import horizon
|
||||||
|
from openstack_dashboard.dashboards.admin import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class ShareSnapshots(horizon.Panel):
|
||||||
|
name = _("Share Snapshots")
|
||||||
|
slug = 'share_snapshots'
|
||||||
|
permissions = (
|
||||||
|
'openstack.services.share',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Admin.register(ShareSnapshots)
|
128
manila_ui/dashboards/admin/share_snapshots/tables.py
Normal file
128
manila_ui/dashboards/admin/share_snapshots/tables.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# 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 manila_ui.api import manila
|
||||||
|
from manila_ui.dashboards.project.shares.shares import tables as shares_tables
|
||||||
|
import manila_ui.dashboards.project.shares.snapshots.tables as ss_tables
|
||||||
|
|
||||||
|
|
||||||
|
def get_size(share):
|
||||||
|
return _("%sGiB") % share.size
|
||||||
|
|
||||||
|
|
||||||
|
class ShareSnapshotShareNameColumn(tables.Column):
|
||||||
|
def get_link_url(self, snapshot):
|
||||||
|
return reverse(self.link, args=(snapshot.share_id,))
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteShareSnapshot(tables.DeleteAction):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Delete Snapshot",
|
||||||
|
u"Delete Snapshots",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Deleted Snapshot",
|
||||||
|
u"Deleted Snapshots",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_policy_target(self, request, datum=None):
|
||||||
|
project_id = None
|
||||||
|
if datum:
|
||||||
|
project_id = getattr(datum, "project_id", None)
|
||||||
|
return {"project_id": project_id}
|
||||||
|
|
||||||
|
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_snapshot_delete(request, obj_id)
|
||||||
|
except Exception:
|
||||||
|
msg = _('Unable to delete snapshot "%s". One or more shares '
|
||||||
|
'depend on it.')
|
||||||
|
exceptions.check_message(["snapshots", "dependent"], msg % name)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def allowed(self, request, snapshot=None):
|
||||||
|
if snapshot:
|
||||||
|
return snapshot.status.upper() in shares_tables.DELETABLE_STATES
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ShareSnapshotsTable(tables.DataTable):
|
||||||
|
STATUS_CHOICES = (
|
||||||
|
("in-use", True),
|
||||||
|
("available", True),
|
||||||
|
("creating", None),
|
||||||
|
("error", False),
|
||||||
|
)
|
||||||
|
STATUS_DISPLAY_CHOICES = (
|
||||||
|
("in-use", pgettext_lazy("Current status of snapshot", u"In-use")),
|
||||||
|
("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_snapshots:share_snapshot_detail")
|
||||||
|
description = tables.Column(
|
||||||
|
"description",
|
||||||
|
verbose_name=_("Description"),
|
||||||
|
truncate=40)
|
||||||
|
size = tables.Column(
|
||||||
|
get_size,
|
||||||
|
verbose_name=_("Size"),
|
||||||
|
attrs={'data-type': 'size'})
|
||||||
|
status = tables.Column(
|
||||||
|
"status",
|
||||||
|
filters=(title,),
|
||||||
|
verbose_name=_("Status"),
|
||||||
|
status=True,
|
||||||
|
status_choices=STATUS_CHOICES,
|
||||||
|
display_choices=STATUS_DISPLAY_CHOICES)
|
||||||
|
source = ShareSnapshotShareNameColumn(
|
||||||
|
"share",
|
||||||
|
verbose_name=_("Source"),
|
||||||
|
link="horizon:admin:shares:detail")
|
||||||
|
|
||||||
|
def get_object_display(self, obj):
|
||||||
|
return obj.name
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "share_snapshots"
|
||||||
|
verbose_name = _("Share Snapshots")
|
||||||
|
status_columns = ["status"]
|
||||||
|
row_class = ss_tables.UpdateRow
|
||||||
|
table_actions = (
|
||||||
|
tables.NameFilterAction,
|
||||||
|
DeleteShareSnapshot,
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
DeleteShareSnapshot,
|
||||||
|
)
|
32
manila_ui/dashboards/admin/share_snapshots/tabs.py
Normal file
32
manila_ui/dashboards/admin/share_snapshots/tabs.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
from horizon import tabs
|
||||||
|
|
||||||
|
|
||||||
|
class ShareSnapshotOverviewTab(tabs.Tab):
|
||||||
|
name = _("Share Snapshot Overview")
|
||||||
|
slug = "share_snapshot_overview_tab"
|
||||||
|
template_name = "admin/share_snapshots/_detail.html"
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
return {"snapshot": self.tab_group.kwargs["snapshot"]}
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "share_snapshot_details"
|
||||||
|
tabs = (
|
||||||
|
ShareSnapshotOverviewTab,
|
||||||
|
)
|
@ -0,0 +1,66 @@
|
|||||||
|
{% load i18n sizeformat parse_date %}
|
||||||
|
|
||||||
|
<h3>{% trans "Share Snapshot Overview" %}</h3>
|
||||||
|
<div class="detail">
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd>{{ snapshot.name }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ snapshot.id }}</dd>
|
||||||
|
{% url 'horizon:admin:shares:detail' snapshot.share_id as share_url %}
|
||||||
|
<dt>{% trans "Source" %}</dt>
|
||||||
|
<dd><a href="{{ share_url }}">{{ snapshot.share_name_or_id }}</a></dd>
|
||||||
|
{% if snapshot.description %}
|
||||||
|
<dt>{% trans "Description" %}</dt>
|
||||||
|
<dd>{{ snapshot.description }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<dt>{% trans "Status" %}</dt>
|
||||||
|
<dd>{{ snapshot.status|capfirst }}</dd>
|
||||||
|
{% if snapshot.export_locations %}
|
||||||
|
<dt>{% trans "Export locations" %}</dt>
|
||||||
|
{% for el in snapshot.export_locations %}
|
||||||
|
<dd><p>
|
||||||
|
<div><b>Path:</b>
|
||||||
|
<input type="text" readonly="true"
|
||||||
|
value="{{ el.path }}" size="{{ snapshot.el_size }}"
|
||||||
|
onClick="this.setSelectionRange(0, this.value.length)">
|
||||||
|
</div>
|
||||||
|
{% if el.is_admin_only != None %}
|
||||||
|
<div><b>Is admin only:</b> {{ el.is_admin_only }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if el.share_snapshot_instance_id %}
|
||||||
|
<div><b>Snapshot Replica ID:</b> {{ el.share_snapshot_instance_id }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</p></dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if snapshot.rules != None %}
|
||||||
|
<div class="detail">
|
||||||
|
<h4>{% trans "Access Rules" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
{% for rule in snapshot.rules %}
|
||||||
|
<dt>{{ rule.access_type }}</dt>
|
||||||
|
<dd><p>
|
||||||
|
<div><b>Access to: </b>{{ rule.access_to }}</div>
|
||||||
|
<div><b>Status: </b>{{ rule.state }}</div>
|
||||||
|
</p></dd>
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<h4>{% trans "Specs" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Size" %}</dt>
|
||||||
|
<dd>{{ snapshot.size }} {% trans "GiB" %}</dd>
|
||||||
|
<dt>{% trans "Created" %}</dt>
|
||||||
|
<dd>{{ snapshot.created_at|parse_date }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Shares" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ share_snapshots_table.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
27
manila_ui/dashboards/admin/share_snapshots/urls.py
Normal file
27
manila_ui/dashboards/admin/share_snapshots/urls.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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_snapshots import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
urls.url(
|
||||||
|
r'^$',
|
||||||
|
views.ShareSnapshotsView.as_view(),
|
||||||
|
name='index'),
|
||||||
|
urls.url(
|
||||||
|
r'^(?P<snapshot_id>[^/]+)$',
|
||||||
|
views.ShareSnapshotDetailView.as_view(),
|
||||||
|
name='share_snapshot_detail'),
|
||||||
|
]
|
63
manila_ui/dashboards/admin/share_snapshots/views.py
Normal file
63
manila_ui/dashboards/admin/share_snapshots/views.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Admin views for managing share snapshots.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.core.urlresolvers import reverse_lazy
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from horizon import exceptions
|
||||||
|
from horizon import tables
|
||||||
|
from horizon.utils import memoized
|
||||||
|
|
||||||
|
from manila_ui.api import manila
|
||||||
|
from manila_ui.dashboards.admin.share_snapshots import tables as ss_tables
|
||||||
|
from manila_ui.dashboards.admin.share_snapshots import tabs as ss_tabs
|
||||||
|
from manila_ui.dashboards.admin import utils
|
||||||
|
import manila_ui.dashboards.project.shares.snapshots.views as snapshot_views
|
||||||
|
|
||||||
|
|
||||||
|
class ShareSnapshotsView(tables.MultiTableView):
|
||||||
|
table_classes = (
|
||||||
|
ss_tables.ShareSnapshotsTable,
|
||||||
|
)
|
||||||
|
template_name = "admin/share_snapshots/index.html"
|
||||||
|
page_title = _("Share Snapshots")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_share_snapshots_data(self):
|
||||||
|
snapshots = []
|
||||||
|
try:
|
||||||
|
snapshots = manila.share_snapshot_list(
|
||||||
|
self.request, search_opts={'all_tenants': True})
|
||||||
|
shares = manila.share_list(self.request)
|
||||||
|
share_names = dict([(share.id, share.name or share.id)
|
||||||
|
for share in shares])
|
||||||
|
for snapshot in snapshots:
|
||||||
|
snapshot.share = share_names.get(snapshot.share_id)
|
||||||
|
except Exception:
|
||||||
|
msg = _("Unable to retrieve share snapshot list.")
|
||||||
|
exceptions.handle(self.request, msg)
|
||||||
|
|
||||||
|
# Gather our projects to correlate against IDs
|
||||||
|
utils.set_project_name_to_objects(self.request, snapshots)
|
||||||
|
|
||||||
|
return snapshots
|
||||||
|
|
||||||
|
|
||||||
|
class ShareSnapshotDetailView(snapshot_views.SnapshotDetailView):
|
||||||
|
tab_group_class = ss_tabs.SnapshotDetailTabs
|
||||||
|
template_name = "admin/share_snapshots/detail.html"
|
||||||
|
redirect_url = reverse_lazy("horizon:admin:share_snapshots:index")
|
0
manila_ui/dashboards/admin/share_types/__init__.py
Normal file
0
manila_ui/dashboards/admin/share_types/__init__.py
Normal file
133
manila_ui/dashboards/admin/share_types/forms.py
Normal file
133
manila_ui/dashboards/admin/share_types/forms.py
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
# Copyright (c) 2014 NetApp, 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
|
||||||
|
|
||||||
|
|
||||||
|
ST_EXTRA_SPECS_FORM_ATTRS = {
|
||||||
|
"rows": 5,
|
||||||
|
"cols": 40,
|
||||||
|
"style": "height: 135px; width: 100%;", # in case 'rows' not picked up
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CreateShareType(forms.SelfHandlingForm):
|
||||||
|
name = forms.CharField(max_length="255", label=_("Name"), required=True)
|
||||||
|
spec_driver_handles_share_servers = forms.ChoiceField(
|
||||||
|
label=_("Driver handles share servers"), required=True,
|
||||||
|
choices=(('False', 'False'), ('True', 'True')))
|
||||||
|
extra_specs = forms.CharField(
|
||||||
|
required=False, label=_("Extra specs"),
|
||||||
|
widget=forms.widgets.Textarea(attrs=ST_EXTRA_SPECS_FORM_ATTRS))
|
||||||
|
is_public = forms.BooleanField(
|
||||||
|
label=_("Public"), required=False, initial=True,
|
||||||
|
help_text=("Defines whether this share type is available for all "
|
||||||
|
"or not. List of allowed tenants should be set "
|
||||||
|
"separately."))
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(CreateShareType, self).__init__(*args, **kwargs)
|
||||||
|
manila_features = getattr(settings, 'OPENSTACK_MANILA_FEATURES', {})
|
||||||
|
self.enable_public_share_type_creation = manila_features.get(
|
||||||
|
'enable_public_share_type_creation', True)
|
||||||
|
if not self.enable_public_share_type_creation:
|
||||||
|
self.fields.pop('is_public')
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
spec_dhss = data['spec_driver_handles_share_servers'].lower()
|
||||||
|
allowed_dhss_values = ('true', 'false')
|
||||||
|
if spec_dhss not in allowed_dhss_values:
|
||||||
|
msg = _("Improper value set to required extra spec "
|
||||||
|
"'spec_driver_handles_share_servers'. "
|
||||||
|
"Allowed values are %s. "
|
||||||
|
"Case insensitive.") % allowed_dhss_values
|
||||||
|
raise ValidationError(message=msg)
|
||||||
|
|
||||||
|
set_dict, unset_list = utils.parse_str_meta(data['extra_specs'])
|
||||||
|
if unset_list:
|
||||||
|
msg = _("Expected only pairs of key=value.")
|
||||||
|
raise ValidationError(message=msg)
|
||||||
|
|
||||||
|
is_public = (self.enable_public_share_type_creation
|
||||||
|
and data["is_public"])
|
||||||
|
share_type = manila.share_type_create(
|
||||||
|
request, data["name"], spec_dhss, is_public=is_public)
|
||||||
|
if set_dict:
|
||||||
|
manila.share_type_set_extra_specs(
|
||||||
|
request, share_type.id, set_dict)
|
||||||
|
|
||||||
|
msg = _("Successfully created share type: %s") % share_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 type.'))
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateShareType(forms.SelfHandlingForm):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(UpdateShareType, self).__init__(*args, **kwargs)
|
||||||
|
# NOTE(vponomaryov): parse existing extra specs
|
||||||
|
# to str view for textarea html element
|
||||||
|
es_str = ""
|
||||||
|
for k, v in self.initial["extra_specs"].iteritems():
|
||||||
|
es_str += "%s=%s\r\n" % (k, v)
|
||||||
|
self.initial["extra_specs"] = es_str
|
||||||
|
|
||||||
|
extra_specs = forms.CharField(
|
||||||
|
required=False, label=_("Extra specs"),
|
||||||
|
widget=forms.widgets.Textarea(attrs=ST_EXTRA_SPECS_FORM_ATTRS))
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
set_dict, unset_list = utils.parse_str_meta(data['extra_specs'])
|
||||||
|
if set_dict:
|
||||||
|
manila.share_type_set_extra_specs(
|
||||||
|
request, self.initial["id"], set_dict)
|
||||||
|
if unset_list:
|
||||||
|
get = manila.share_type_get_extra_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_type_unset_extra_specs(
|
||||||
|
request, self.initial["id"], to_unset)
|
||||||
|
msg = _("Successfully updated extra specs for share 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 extra_specs for share type.")
|
||||||
|
exceptions.handle(request, msg)
|
||||||
|
return False
|
30
manila_ui/dashboards/admin/share_types/panel.py
Normal file
30
manila_ui/dashboards/admin/share_types/panel.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# 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 django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.admin import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class ShareTypes(horizon.Panel):
|
||||||
|
name = _("Share Types")
|
||||||
|
slug = 'share_types'
|
||||||
|
permissions = (
|
||||||
|
'openstack.services.share',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Admin.register(ShareTypes)
|
111
manila_ui/dashboards/admin/share_types/tables.py
Normal file
111
manila_ui/dashboards/admin/share_types/tables.py
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
def get_size(share):
|
||||||
|
return _("%sGiB") % share.size
|
||||||
|
|
||||||
|
|
||||||
|
class CreateShareType(tables.LinkAction):
|
||||||
|
name = "create"
|
||||||
|
verbose_name = _("Create Share Type")
|
||||||
|
url = "horizon:admin:share_types:create_type"
|
||||||
|
classes = ("ajax-modal", "btn-create")
|
||||||
|
icon = "plus"
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteShareType(tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Delete Share Type",
|
||||||
|
u"Delete Share Types",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Deleted Share Type",
|
||||||
|
u"Deleted Share Types",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete(self, request, obj_id):
|
||||||
|
manila.share_type_delete(request, obj_id)
|
||||||
|
|
||||||
|
|
||||||
|
class ManageShareTypeAccess(tables.LinkAction):
|
||||||
|
name = "manage"
|
||||||
|
verbose_name = _("Manage Share Type Access")
|
||||||
|
url = "horizon:admin:share_types:manage_share_type_access"
|
||||||
|
classes = ("ajax-modal", "btn-create")
|
||||||
|
|
||||||
|
def allowed(self, request, obj_id):
|
||||||
|
st = manila.share_type_get(request, obj_id)
|
||||||
|
# Enable it only for private share types
|
||||||
|
return not st.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 UpdateShareType(tables.LinkAction):
|
||||||
|
name = "update share type"
|
||||||
|
verbose_name = _("Update Share Type")
|
||||||
|
url = "horizon:admin:share_types:update_type"
|
||||||
|
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 ShareTypesTable(tables.DataTable):
|
||||||
|
name = tables.WrappingColumn("name", verbose_name=_("Name"))
|
||||||
|
extra_specs = tables.Column("extra_specs", verbose_name=_("Extra specs"), )
|
||||||
|
visibility = tables.Column(
|
||||||
|
"is_public", verbose_name=_("Visibility"),
|
||||||
|
filters=(lambda d: 'public' if d is True else 'private', ),
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_object_display(self, share_type):
|
||||||
|
return share_type.name
|
||||||
|
|
||||||
|
def get_object_id(self, share_type):
|
||||||
|
return six.text_type(share_type.id)
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "share_types"
|
||||||
|
verbose_name = _("Share Types")
|
||||||
|
table_actions = (
|
||||||
|
tables.NameFilterAction,
|
||||||
|
CreateShareType,
|
||||||
|
DeleteShareType,
|
||||||
|
)
|
||||||
|
row_actions = (
|
||||||
|
UpdateShareType,
|
||||||
|
ManageShareTypeAccess,
|
||||||
|
DeleteShareType,
|
||||||
|
)
|
@ -2,9 +2,9 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block form_id %}{% endblock %}
|
{% block form_id %}{% endblock %}
|
||||||
{% block form_action %}{% url 'horizon:admin:shares:manage_share_type_access' share_type.id %}{% endblock %}
|
{% block form_action %}{% url 'horizon:admin:share_types:manage_share_type_access' share_type.id %}{% endblock %}
|
||||||
|
|
||||||
{% block modal_id %}add_security_service_modal{% endblock %}
|
{% block modal_id %}manage_share_type_access_modal{% endblock %}
|
||||||
{% block modal-header %}{% trans "Manage Share Type Access" %}{% endblock %}
|
{% block modal-header %}{% trans "Manage Share Type Access" %}{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
@ -55,5 +55,5 @@
|
|||||||
|
|
||||||
{% block modal-footer %}
|
{% block modal-footer %}
|
||||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Submit" %}" />
|
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Submit" %}" />
|
||||||
<a href="{% url 'horizon:admin:shares:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
<a href="{% url 'horizon:admin:share_types:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -3,5 +3,5 @@
|
|||||||
{% block title %}{% trans "Create Share Type" %}{% endblock %}
|
{% block title %}{% trans "Create Share Type" %}{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% include 'admin/shares/_create_share_type.html' %}
|
{% include 'admin/share_types/_create.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Share Types" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
{{ share_types_table.render }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -3,5 +3,5 @@
|
|||||||
{% block title %}{% trans "Manage Share Type Access" %}{% endblock %}
|
{% block title %}{% trans "Manage Share Type Access" %}{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% include 'admin/shares/_manage_share_type_access.html' %}
|
{% include 'admin/share_types/_manage_access.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -3,5 +3,5 @@
|
|||||||
{% block title %}{% trans "Update Share Type" %}{% endblock %}
|
{% block title %}{% trans "Update Share Type" %}{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% include 'admin/shares/_update_share_type.html' %}
|
{% include 'admin/share_types/_update.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
35
manila_ui/dashboards/admin/share_types/urls.py
Normal file
35
manila_ui/dashboards/admin/share_types/urls.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# 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_types import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
urls.url(
|
||||||
|
r'^$',
|
||||||
|
views.ShareTypesView.as_view(),
|
||||||
|
name='index'),
|
||||||
|
urls.url(
|
||||||
|
r'^create_type$',
|
||||||
|
views.CreateShareTypeView.as_view(),
|
||||||
|
name='create_type'),
|
||||||
|
urls.url(
|
||||||
|
r'^update_type/(?P<share_type_id>[^/]+)/extra_specs$',
|
||||||
|
views.UpdateShareTypeView.as_view(),
|
||||||
|
name='update_type'),
|
||||||
|
urls.url(
|
||||||
|
r'^manage_share_type_access/(?P<share_type_id>[^/]+)$',
|
||||||
|
views.ManageShareTypeAccessView.as_view(),
|
||||||
|
name='manage_share_type_access'),
|
||||||
|
]
|
119
manila_ui/dashboards/admin/share_types/views.py
Normal file
119
manila_ui/dashboards/admin/share_types/views.py
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
# 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 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_types import forms as project_forms
|
||||||
|
from manila_ui.dashboards.admin.share_types import tables as st_tables
|
||||||
|
import manila_ui.dashboards.admin.share_types.workflows as st_workflows
|
||||||
|
from manila_ui.dashboards import utils as common_utils
|
||||||
|
|
||||||
|
|
||||||
|
class ShareTypesView(tables.MultiTableView):
|
||||||
|
table_classes = (
|
||||||
|
st_tables.ShareTypesTable,
|
||||||
|
)
|
||||||
|
template_name = "admin/share_types/index.html"
|
||||||
|
page_title = _("Share Types")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_share_types_data(self):
|
||||||
|
try:
|
||||||
|
share_types = manila.share_type_list(self.request)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(
|
||||||
|
self.request, _('Unable to retrieve share types.'))
|
||||||
|
return []
|
||||||
|
# Convert dict with extra specs to friendly view
|
||||||
|
for st in share_types:
|
||||||
|
st.extra_specs = common_utils.metadata_to_str(
|
||||||
|
st.extra_specs, 8, 45)
|
||||||
|
return share_types
|
||||||
|
|
||||||
|
|
||||||
|
class CreateShareTypeView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.CreateShareType
|
||||||
|
form_id = "create_share_type"
|
||||||
|
template_name = 'admin/share_types/create.html'
|
||||||
|
modal_header = _("Create Share Type")
|
||||||
|
submit_label = _("Create")
|
||||||
|
submit_url = reverse_lazy("horizon:admin:share_types:create_type")
|
||||||
|
success_url = 'horizon:admin:share_types:index'
|
||||||
|
page_title = _("Create Share Type")
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse(self.success_url)
|
||||||
|
|
||||||
|
|
||||||
|
class ManageShareTypeAccessView(workflows.WorkflowView):
|
||||||
|
workflow_class = st_workflows.ManageShareTypeAccessWorkflow
|
||||||
|
template_name = "admin/share_types/manage_access.html"
|
||||||
|
success_url = 'horizon:project:share_types:index'
|
||||||
|
page_title = _("Manage Share Type Access")
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
return {'id': self.kwargs["share_type_id"]}
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(ManageShareTypeAccessView, self).get_context_data(
|
||||||
|
**kwargs)
|
||||||
|
context['id'] = self.kwargs['share_type_id']
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateShareTypeView(forms.ModalFormView):
|
||||||
|
form_class = project_forms.UpdateShareType
|
||||||
|
form_id = "update_share_type"
|
||||||
|
template_name = "admin/share_types/update.html"
|
||||||
|
modal_header = _("Update Share Type")
|
||||||
|
modal_id = "update_share_type_modal"
|
||||||
|
submit_label = _("Update")
|
||||||
|
submit_url = "horizon:admin:share_types:update_type"
|
||||||
|
success_url = reverse_lazy("horizon:admin:share_types:index")
|
||||||
|
page_title = _("Update Share Type")
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
|
if not hasattr(self, "_object"):
|
||||||
|
st_id = self.kwargs["share_type_id"]
|
||||||
|
try:
|
||||||
|
self._object = manila.share_type_get(self.request, st_id)
|
||||||
|
except Exception:
|
||||||
|
msg = _("Unable to retrieve share_type.")
|
||||||
|
url = reverse("horizon:admin:share_types:index")
|
||||||
|
exceptions.handle(self.request, msg, redirect=url)
|
||||||
|
return self._object
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UpdateShareTypeView, 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_type = self.get_object()
|
||||||
|
return {
|
||||||
|
"id": self.kwargs["share_type_id"],
|
||||||
|
"name": share_type.name,
|
||||||
|
"extra_specs": share_type.extra_specs,
|
||||||
|
}
|
@ -92,7 +92,7 @@ class ManageShareTypeAccessWorkflow(workflows.Workflow):
|
|||||||
finalize_button_name = _("Manage Share Type Access")
|
finalize_button_name = _("Manage Share Type Access")
|
||||||
success_message = _('Updated access for share type "%s".')
|
success_message = _('Updated access for share type "%s".')
|
||||||
failure_message = _('Unable to update access for share type "%s".')
|
failure_message = _('Unable to update access for share type "%s".')
|
||||||
success_url = 'horizon:admin:shares:index'
|
success_url = 'horizon:admin:share_types:index'
|
||||||
default_steps = (AddProjectStep, )
|
default_steps = (AddProjectStep, )
|
||||||
|
|
||||||
def format_status_message(self, message):
|
def format_status_message(self, message):
|
@ -17,25 +17,23 @@ from django.conf import settings
|
|||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.forms import ValidationError # noqa
|
from django.forms import ValidationError # noqa
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from oslo_utils import strutils
|
|
||||||
import six
|
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from horizon import forms
|
from horizon import forms
|
||||||
from horizon import messages
|
from horizon import messages
|
||||||
|
from oslo_utils import strutils
|
||||||
|
import six
|
||||||
|
|
||||||
from manila_ui.api import manila
|
from manila_ui.api import manila
|
||||||
from manila_ui.dashboards import utils
|
from manila_ui.dashboards import utils
|
||||||
|
|
||||||
from openstack_dashboard.api import keystone
|
|
||||||
from openstack_dashboard.api import neutron
|
|
||||||
|
|
||||||
|
def _get_id_if_name_empty(data):
|
||||||
ST_EXTRA_SPECS_FORM_ATTRS = {
|
result = data.get('name', None)
|
||||||
"rows": 5,
|
if not result:
|
||||||
"cols": 40,
|
result = data.get('id')
|
||||||
"style": "height: 135px; width: 100%;", # in case 'rows' not picked up
|
if not result:
|
||||||
}
|
result = ''
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class MigrationStart(forms.SelfHandlingForm):
|
class MigrationStart(forms.SelfHandlingForm):
|
||||||
@ -310,189 +308,3 @@ class UnmanageShare(forms.SelfHandlingForm):
|
|||||||
except Exception:
|
except Exception:
|
||||||
exceptions.handle(request, _("Unable to unmanage share."))
|
exceptions.handle(request, _("Unable to unmanage share."))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class CreateShareType(forms.SelfHandlingForm):
|
|
||||||
name = forms.CharField(max_length="255", label=_("Name"), required=True)
|
|
||||||
spec_driver_handles_share_servers = forms.ChoiceField(
|
|
||||||
label=_("Driver handles share servers"), required=True,
|
|
||||||
choices=(('False', 'False'), ('True', 'True')))
|
|
||||||
extra_specs = forms.CharField(
|
|
||||||
required=False, label=_("Extra specs"),
|
|
||||||
widget=forms.widgets.Textarea(attrs=ST_EXTRA_SPECS_FORM_ATTRS))
|
|
||||||
is_public = forms.BooleanField(
|
|
||||||
label=_("Public"), required=False, initial=True,
|
|
||||||
help_text=("Defines whether this share type is available for all "
|
|
||||||
"or not. List of allowed tenants should be set "
|
|
||||||
"separately."))
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(CreateShareType, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
manila_features = getattr(settings, 'OPENSTACK_MANILA_FEATURES', {})
|
|
||||||
self.enable_public_share_type_creation = manila_features.get(
|
|
||||||
'enable_public_share_type_creation', True)
|
|
||||||
if not self.enable_public_share_type_creation:
|
|
||||||
self.fields.pop('is_public')
|
|
||||||
|
|
||||||
def handle(self, request, data):
|
|
||||||
try:
|
|
||||||
spec_dhss = data['spec_driver_handles_share_servers'].lower()
|
|
||||||
allowed_dhss_values = ('true', 'false')
|
|
||||||
if spec_dhss not in allowed_dhss_values:
|
|
||||||
msg = _("Improper value set to required extra spec "
|
|
||||||
"'spec_driver_handles_share_servers'. "
|
|
||||||
"Allowed values are %s. "
|
|
||||||
"Case insensitive.") % allowed_dhss_values
|
|
||||||
raise ValidationError(message=msg)
|
|
||||||
|
|
||||||
set_dict, unset_list = utils.parse_str_meta(data['extra_specs'])
|
|
||||||
if unset_list:
|
|
||||||
msg = _("Expected only pairs of key=value.")
|
|
||||||
raise ValidationError(message=msg)
|
|
||||||
|
|
||||||
is_public = (self.enable_public_share_type_creation
|
|
||||||
and data["is_public"])
|
|
||||||
share_type = manila.share_type_create(
|
|
||||||
request, data["name"], spec_dhss, is_public=is_public)
|
|
||||||
if set_dict:
|
|
||||||
manila.share_type_set_extra_specs(
|
|
||||||
request, share_type.id, set_dict)
|
|
||||||
|
|
||||||
msg = _("Successfully created share type: %s") % share_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 type.'))
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateShareType(forms.SelfHandlingForm):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(UpdateShareType, self).__init__(*args, **kwargs)
|
|
||||||
# NOTE(vponomaryov): parse existing extra specs
|
|
||||||
# to str view for textarea html element
|
|
||||||
es_str = ""
|
|
||||||
for k, v in self.initial["extra_specs"].iteritems():
|
|
||||||
es_str += "%s=%s\r\n" % (k, v)
|
|
||||||
self.initial["extra_specs"] = es_str
|
|
||||||
|
|
||||||
extra_specs = forms.CharField(
|
|
||||||
required=False, label=_("Extra specs"),
|
|
||||||
widget=forms.widgets.Textarea(attrs=ST_EXTRA_SPECS_FORM_ATTRS))
|
|
||||||
|
|
||||||
def handle(self, request, data):
|
|
||||||
try:
|
|
||||||
set_dict, unset_list = utils.parse_str_meta(data['extra_specs'])
|
|
||||||
if set_dict:
|
|
||||||
manila.share_type_set_extra_specs(
|
|
||||||
request, self.initial["id"], set_dict)
|
|
||||||
if unset_list:
|
|
||||||
get = manila.share_type_get_extra_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_type_unset_extra_specs(
|
|
||||||
request, self.initial["id"], to_unset)
|
|
||||||
msg = _("Successfully updated extra specs for share 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 extra_specs for share type.")
|
|
||||||
exceptions.handle(request, msg)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class CreateSecurityService(forms.SelfHandlingForm):
|
|
||||||
name = forms.CharField(max_length="255", label=_("Name"))
|
|
||||||
dns_ip = forms.CharField(max_length="15", label=_("DNS IP"))
|
|
||||||
server = forms.CharField(max_length="255", label=_("Server"))
|
|
||||||
domain = forms.CharField(max_length="255", label=_("Domain"))
|
|
||||||
user = forms.CharField(max_length="255", label=_("User"))
|
|
||||||
password = forms.CharField(max_length="255", label=_("Password"))
|
|
||||||
type = forms.ChoiceField(choices=(("", ""),
|
|
||||||
("active_directory", "Active Directory"),
|
|
||||||
("ldap", "LDAP"),
|
|
||||||
("kerberos", "Kerberos")),
|
|
||||||
label=_("Type"))
|
|
||||||
description = forms.CharField(widget=forms.Textarea,
|
|
||||||
label=_("Description"), required=False)
|
|
||||||
|
|
||||||
def handle(self, request, data):
|
|
||||||
try:
|
|
||||||
# Remove any new lines in the public key
|
|
||||||
security_service = manila.security_service_create(
|
|
||||||
request, **data)
|
|
||||||
messages.success(request,
|
|
||||||
_('Successfully created security service: %s')
|
|
||||||
% data['name'])
|
|
||||||
return security_service
|
|
||||||
except Exception:
|
|
||||||
exceptions.handle(request,
|
|
||||||
_('Unable to create security service.'))
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class CreateShareNetworkForm(forms.SelfHandlingForm):
|
|
||||||
name = forms.CharField(max_length="255", label=_("Name"))
|
|
||||||
neutron_net_id = forms.ChoiceField(choices=(), label=_("Neutron Net ID"))
|
|
||||||
neutron_subnet_id = forms.ChoiceField(choices=(),
|
|
||||||
label=_("Neutron Subnet ID"))
|
|
||||||
# security_service = forms.MultipleChoiceField(
|
|
||||||
# widget=forms.SelectMultiple,
|
|
||||||
# label=_("Security Service"))
|
|
||||||
project = forms.ChoiceField(choices=(), label=_("Project"))
|
|
||||||
description = forms.CharField(widget=forms.Textarea,
|
|
||||||
label=_("Description"), required=False)
|
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
|
||||||
super(CreateShareNetworkForm, self).__init__(
|
|
||||||
request, *args, **kwargs)
|
|
||||||
net_choices = neutron.network_list(request)
|
|
||||||
subnet_choices = neutron.subnet_list(request)
|
|
||||||
self.fields['neutron_net_id'].choices = [(' ', ' ')] + \
|
|
||||||
[(choice.id, choice.name_or_id)
|
|
||||||
for choice in net_choices]
|
|
||||||
self.fields['neutron_subnet_id'].choices = [(' ', ' ')] + \
|
|
||||||
[(choice.id,
|
|
||||||
choice.name_or_id) for
|
|
||||||
choice in subnet_choices]
|
|
||||||
tenants, has_more = keystone.tenant_list(request)
|
|
||||||
self.fields['project'].choices = [(' ', ' ')] + \
|
|
||||||
[(choice.id,
|
|
||||||
choice.name) for
|
|
||||||
choice in tenants]
|
|
||||||
|
|
||||||
def handle(self, request, data):
|
|
||||||
try:
|
|
||||||
# Remove any new lines in the public key
|
|
||||||
share_network = manila.share_network_create(request, **data)
|
|
||||||
messages.success(request,
|
|
||||||
_('Successfully created share network: %s')
|
|
||||||
% data['name'])
|
|
||||||
return share_network
|
|
||||||
except Exception:
|
|
||||||
exceptions.handle(request,
|
|
||||||
_('Unable to create share network.'))
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _get_id_if_name_empty(data):
|
|
||||||
result = data.get('name', None)
|
|
||||||
if not result:
|
|
||||||
result = data.get('id')
|
|
||||||
if not result:
|
|
||||||
result = ''
|
|
||||||
return result
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# Copyright 2017 Mirantis, Inc.
|
||||||
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -11,15 +13,16 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
import horizon
|
import horizon
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.admin import dashboard
|
from openstack_dashboard.dashboards.admin import dashboard
|
||||||
|
|
||||||
|
|
||||||
class Shares(horizon.Panel):
|
class Shares(horizon.Panel):
|
||||||
name = _("Shares")
|
name = _("Shares")
|
||||||
slug = "shares"
|
slug = "shares"
|
||||||
permissions = ('openstack.services.share',)
|
permissions = (
|
||||||
|
'openstack.services.share',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
dashboard.Admin.register(Shares)
|
dashboard.Admin.register(Shares)
|
||||||
|
@ -10,77 +10,12 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
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 ugettext_lazy as _
|
||||||
from django.utils.translation import ungettext_lazy
|
|
||||||
|
|
||||||
from horizon import exceptions
|
|
||||||
from horizon import tables
|
from horizon import tables
|
||||||
|
|
||||||
from manila_ui.api import manila
|
from manila_ui.api import manila
|
||||||
from manila_ui.dashboards.project.shares.share_networks \
|
|
||||||
import tables as share_networks_tables
|
|
||||||
from manila_ui.dashboards.project.shares.shares import tables as shares_tables
|
from manila_ui.dashboards.project.shares.shares import tables as shares_tables
|
||||||
from manila_ui.dashboards.project.shares.snapshots \
|
|
||||||
import tables as snapshot_tables
|
|
||||||
|
|
||||||
|
|
||||||
def get_size(share):
|
|
||||||
return _("%sGiB") % share.size
|
|
||||||
|
|
||||||
|
|
||||||
class CreateShareType(tables.LinkAction):
|
|
||||||
name = "create"
|
|
||||||
verbose_name = _("Create Share Type")
|
|
||||||
url = "horizon:admin:shares:create_type"
|
|
||||||
classes = ("ajax-modal", "btn-create")
|
|
||||||
icon = "plus"
|
|
||||||
policy_rules = (("share", "share_extension:types_manage"),)
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteShareType(tables.DeleteAction):
|
|
||||||
policy_rules = (("share", "share_extension:types_manage"),)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def action_present(count):
|
|
||||||
return ungettext_lazy(
|
|
||||||
u"Delete Share Type",
|
|
||||||
u"Delete Share Types",
|
|
||||||
count
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def action_past(count):
|
|
||||||
return ungettext_lazy(
|
|
||||||
u"Deleted Share Type",
|
|
||||||
u"Deleted Share Types",
|
|
||||||
count
|
|
||||||
)
|
|
||||||
|
|
||||||
def delete(self, request, obj_id):
|
|
||||||
manila.share_type_delete(request, obj_id)
|
|
||||||
|
|
||||||
|
|
||||||
class ManageShareTypeAccess(tables.LinkAction):
|
|
||||||
name = "manage"
|
|
||||||
verbose_name = _("Manage Share Type Access")
|
|
||||||
url = "horizon:admin:shares:manage_share_type_access"
|
|
||||||
classes = ("ajax-modal", "btn-create")
|
|
||||||
policy_rules = (("share", "share_extension:share_type_access"),)
|
|
||||||
|
|
||||||
def allowed(self, request, obj_id):
|
|
||||||
st = manila.share_type_get(request, obj_id)
|
|
||||||
# Enable it only for private share types
|
|
||||||
return not st.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 MigrationStartAction(tables.LinkAction):
|
class MigrationStartAction(tables.LinkAction):
|
||||||
@ -171,46 +106,6 @@ class UnmanageShareAction(tables.LinkAction):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class UpdateShareType(tables.LinkAction):
|
|
||||||
name = "update share type"
|
|
||||||
verbose_name = _("Update Share Type")
|
|
||||||
url = "horizon:admin:shares:update_type"
|
|
||||||
classes = ("ajax-modal", "btn-create")
|
|
||||||
policy_rules = (("share", "share_extension:types_manage"),)
|
|
||||||
|
|
||||||
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 ShareTypesTable(tables.DataTable):
|
|
||||||
name = tables.WrappingColumn("name", verbose_name=_("Name"))
|
|
||||||
extra_specs = tables.Column("extra_specs", verbose_name=_("Extra specs"), )
|
|
||||||
visibility = tables.Column(
|
|
||||||
"is_public", verbose_name=_("Visibility"),
|
|
||||||
filters=(lambda d: 'public' if d is True else 'private', ),)
|
|
||||||
|
|
||||||
def get_object_display(self, share_type):
|
|
||||||
return share_type.name
|
|
||||||
|
|
||||||
def get_object_id(self, share_type):
|
|
||||||
return str(share_type.id)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = "share_types"
|
|
||||||
verbose_name = _("Share Types")
|
|
||||||
table_actions = (
|
|
||||||
tables.NameFilterAction,
|
|
||||||
CreateShareType,
|
|
||||||
DeleteShareType)
|
|
||||||
row_actions = (
|
|
||||||
UpdateShareType,
|
|
||||||
ManageShareTypeAccess,
|
|
||||||
DeleteShareType)
|
|
||||||
|
|
||||||
|
|
||||||
class ManageReplicas(tables.LinkAction):
|
class ManageReplicas(tables.LinkAction):
|
||||||
name = "manage_replicas"
|
name = "manage_replicas"
|
||||||
verbose_name = _("Manage Replicas")
|
verbose_name = _("Manage Replicas")
|
||||||
@ -232,14 +127,15 @@ class SharesTable(shares_tables.SharesTable):
|
|||||||
|
|
||||||
def get_share_server_link(share):
|
def get_share_server_link(share):
|
||||||
if getattr(share, 'share_server_id', None):
|
if getattr(share, 'share_server_id', None):
|
||||||
return reverse("horizon:admin:shares:share_server_detail",
|
return reverse("horizon:admin:share_servers:share_server_detail",
|
||||||
args=(share.share_server_id,))
|
args=(share.share_server_id,))
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
share_server = tables.Column("share_server_id",
|
share_server = tables.Column(
|
||||||
verbose_name=_("Share Server"),
|
"share_server_id",
|
||||||
link=get_share_server_link)
|
verbose_name=_("Share Server"),
|
||||||
|
link=get_share_server_link)
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = "shares"
|
name = "shares"
|
||||||
@ -249,7 +145,8 @@ class SharesTable(shares_tables.SharesTable):
|
|||||||
table_actions = (
|
table_actions = (
|
||||||
tables.NameFilterAction,
|
tables.NameFilterAction,
|
||||||
ManageShareAction,
|
ManageShareAction,
|
||||||
shares_tables.DeleteShare)
|
shares_tables.DeleteShare,
|
||||||
|
)
|
||||||
row_actions = (
|
row_actions = (
|
||||||
ManageReplicas,
|
ManageReplicas,
|
||||||
MigrationStartAction,
|
MigrationStartAction,
|
||||||
@ -257,382 +154,9 @@ class SharesTable(shares_tables.SharesTable):
|
|||||||
MigrationGetProgressAction,
|
MigrationGetProgressAction,
|
||||||
MigrationCancelAction,
|
MigrationCancelAction,
|
||||||
UnmanageShareAction,
|
UnmanageShareAction,
|
||||||
shares_tables.DeleteShare)
|
shares_tables.DeleteShare,
|
||||||
|
)
|
||||||
columns = (
|
columns = (
|
||||||
'tenant', 'host', 'name', 'size', 'status', 'visibility',
|
'tenant', 'host', 'name', 'size', 'status', 'visibility',
|
||||||
'share_type', 'protocol', 'share_server',
|
'share_type', 'protocol', 'share_server',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SnapshotShareNameColumn(tables.Column):
|
|
||||||
def get_link_url(self, snapshot):
|
|
||||||
return reverse(self.link, args=(snapshot.share_id,))
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteSnapshot(tables.DeleteAction):
|
|
||||||
policy_rules = (("snapshot", "snapshot:delete"),)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def action_present(count):
|
|
||||||
return ungettext_lazy(
|
|
||||||
u"Delete Snapshot",
|
|
||||||
u"Delete Snapshots",
|
|
||||||
count
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def action_past(count):
|
|
||||||
return ungettext_lazy(
|
|
||||||
u"Deleted Snapshot",
|
|
||||||
u"Deleted Snapshots",
|
|
||||||
count
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_policy_target(self, request, datum=None):
|
|
||||||
project_id = None
|
|
||||||
if datum:
|
|
||||||
project_id = getattr(datum, "project_id", None)
|
|
||||||
return {"project_id": project_id}
|
|
||||||
|
|
||||||
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_snapshot_delete(request, obj_id)
|
|
||||||
except Exception:
|
|
||||||
msg = _('Unable to delete snapshot "%s". One or more shares '
|
|
||||||
'depend on it.')
|
|
||||||
exceptions.check_message(["snapshots", "dependent"], msg % name)
|
|
||||||
raise
|
|
||||||
|
|
||||||
def allowed(self, request, snapshot=None):
|
|
||||||
if snapshot:
|
|
||||||
return snapshot.status.upper() in shares_tables.DELETABLE_STATES
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class SnapshotsTable(tables.DataTable):
|
|
||||||
STATUS_CHOICES = (
|
|
||||||
("in-use", True),
|
|
||||||
("available", True),
|
|
||||||
("creating", None),
|
|
||||||
("error", False),
|
|
||||||
)
|
|
||||||
STATUS_DISPLAY_CHOICES = (
|
|
||||||
("in-use", pgettext_lazy("Current status of snapshot", u"In-use")),
|
|
||||||
("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:shares:snapshot-detail")
|
|
||||||
description = tables.Column("description",
|
|
||||||
verbose_name=_("Description"),
|
|
||||||
truncate=40)
|
|
||||||
size = tables.Column(get_size,
|
|
||||||
verbose_name=_("Size"),
|
|
||||||
attrs={'data-type': 'size'})
|
|
||||||
status = tables.Column("status",
|
|
||||||
filters=(title,),
|
|
||||||
verbose_name=_("Status"),
|
|
||||||
status=True,
|
|
||||||
status_choices=STATUS_CHOICES,
|
|
||||||
display_choices=STATUS_DISPLAY_CHOICES)
|
|
||||||
source = SnapshotShareNameColumn("share",
|
|
||||||
verbose_name=_("Source"),
|
|
||||||
link="horizon:admin:shares:detail")
|
|
||||||
|
|
||||||
def get_object_display(self, obj):
|
|
||||||
return obj.name
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = "snapshots"
|
|
||||||
verbose_name = _("Snapshots")
|
|
||||||
status_columns = ["status"]
|
|
||||||
row_class = snapshot_tables.UpdateRow
|
|
||||||
table_actions = (
|
|
||||||
tables.NameFilterAction,
|
|
||||||
DeleteSnapshot)
|
|
||||||
row_actions = (
|
|
||||||
DeleteSnapshot,)
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteSecurityService(tables.DeleteAction):
|
|
||||||
policy_rules = (("share", "security_service:delete"),)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def action_present(count):
|
|
||||||
return ungettext_lazy(
|
|
||||||
u"Delete Security Service",
|
|
||||||
u"Delete Security Services",
|
|
||||||
count
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def action_past(count):
|
|
||||||
return ungettext_lazy(
|
|
||||||
u"Deleted Security Service",
|
|
||||||
u"Deleted Security Services",
|
|
||||||
count
|
|
||||||
)
|
|
||||||
|
|
||||||
def delete(self, request, obj_id):
|
|
||||||
manila.security_service_delete(request, obj_id)
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteShareServer(tables.DeleteAction):
|
|
||||||
policy_rules = (("share", "share_server:delete"),)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def action_present(count):
|
|
||||||
return ungettext_lazy(
|
|
||||||
u"Delete Share Server",
|
|
||||||
u"Delete Share Server",
|
|
||||||
count
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def action_past(count):
|
|
||||||
return ungettext_lazy(
|
|
||||||
u"Deleted Share Server",
|
|
||||||
u"Deleted Share Server",
|
|
||||||
count
|
|
||||||
)
|
|
||||||
|
|
||||||
def delete(self, request, obj_id):
|
|
||||||
manila.share_server_delete(request, obj_id)
|
|
||||||
|
|
||||||
def allowed(self, request, share_serv):
|
|
||||||
if share_serv:
|
|
||||||
share_search_opts = {'share_server_id': share_serv.id}
|
|
||||||
shares_list = manila.share_list(request,
|
|
||||||
search_opts=share_search_opts)
|
|
||||||
if shares_list:
|
|
||||||
return False
|
|
||||||
return share_serv.status not in ["deleting", "creating"]
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityServiceTable(tables.DataTable):
|
|
||||||
name = tables.WrappingColumn(
|
|
||||||
"name", verbose_name=_("Name"),
|
|
||||||
link="horizon:admin:shares:security_service_detail")
|
|
||||||
project = tables.Column("project_name", verbose_name=_("Project"))
|
|
||||||
dns_ip = tables.Column("dns_ip", verbose_name=_("DNS IP"))
|
|
||||||
server = tables.Column("server", verbose_name=_("Server"))
|
|
||||||
domain = tables.Column("domain", verbose_name=_("Domain"))
|
|
||||||
user = tables.Column("user", verbose_name=_("Sid"))
|
|
||||||
|
|
||||||
def get_object_display(self, security_service):
|
|
||||||
return security_service.name
|
|
||||||
|
|
||||||
def get_object_id(self, security_service):
|
|
||||||
return str(security_service.id)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = "security_services"
|
|
||||||
verbose_name = _("Security Services")
|
|
||||||
table_actions = (
|
|
||||||
tables.NameFilterAction,
|
|
||||||
DeleteSecurityService)
|
|
||||||
row_actions = (
|
|
||||||
DeleteSecurityService,)
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateShareServerRow(tables.Row):
|
|
||||||
ajax = True
|
|
||||||
|
|
||||||
def get_data(self, request, share_serv_id):
|
|
||||||
share_serv = manila.share_server_get(request, share_serv_id)
|
|
||||||
return share_serv
|
|
||||||
|
|
||||||
|
|
||||||
class NovaShareNetworkTable(tables.DataTable):
|
|
||||||
name = tables.WrappingColumn(
|
|
||||||
"name", verbose_name=_("Name"),
|
|
||||||
link="horizon:admin:shares:share_network_detail")
|
|
||||||
project = tables.Column("project_name", verbose_name=_("Project"))
|
|
||||||
nova_net = tables.Column("nova_net", verbose_name=_("Nova Net"))
|
|
||||||
ip_version = tables.Column("ip_version", verbose_name=_("IP Version"))
|
|
||||||
network_type = tables.Column("network_type",
|
|
||||||
verbose_name=_("Network Type"))
|
|
||||||
segmentation_id = tables.Column("segmentation_id",
|
|
||||||
verbose_name=_("Segmentation Id"))
|
|
||||||
|
|
||||||
def get_object_display(self, share_network):
|
|
||||||
return share_network.name or str(share_network.id)
|
|
||||||
|
|
||||||
def get_object_id(self, share_network):
|
|
||||||
return str(share_network.id)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = "share_networks"
|
|
||||||
verbose_name = _("Share Networks")
|
|
||||||
table_actions = (
|
|
||||||
tables.NameFilterAction,
|
|
||||||
share_networks_tables.Delete)
|
|
||||||
row_class = share_networks_tables.UpdateRow
|
|
||||||
row_actions = (
|
|
||||||
share_networks_tables.Delete,)
|
|
||||||
|
|
||||||
|
|
||||||
class NeutronShareNetworkTable(tables.DataTable):
|
|
||||||
name = tables.WrappingColumn(
|
|
||||||
"name", verbose_name=_("Name"),
|
|
||||||
link="horizon:project:shares:share_network_detail")
|
|
||||||
project = tables.Column("project_name", verbose_name=_("Project"))
|
|
||||||
neutron_net = tables.Column("neutron_net", verbose_name=_("Neutron Net"))
|
|
||||||
neutron_subnet = tables.Column(
|
|
||||||
"neutron_subnet", verbose_name=_("Neutron Subnet"))
|
|
||||||
ip_version = tables.Column("ip_version", verbose_name=_("IP Version"))
|
|
||||||
network_type = tables.Column("network_type",
|
|
||||||
verbose_name=_("Network Type"))
|
|
||||||
segmentation_id = tables.Column("segmentation_id",
|
|
||||||
verbose_name=_("Segmentation Id"))
|
|
||||||
|
|
||||||
def get_object_display(self, share_network):
|
|
||||||
return share_network.name or str(share_network.id)
|
|
||||||
|
|
||||||
def get_object_id(self, share_network):
|
|
||||||
return str(share_network.id)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = "share_networks"
|
|
||||||
verbose_name = _("Share Networks")
|
|
||||||
table_actions = (
|
|
||||||
tables.NameFilterAction,
|
|
||||||
share_networks_tables.Delete)
|
|
||||||
row_class = share_networks_tables.UpdateRow
|
|
||||||
row_actions = (
|
|
||||||
share_networks_tables.Delete,)
|
|
||||||
|
|
||||||
|
|
||||||
class ShareServerTable(tables.DataTable):
|
|
||||||
STATUS_CHOICES = (
|
|
||||||
("active", True),
|
|
||||||
("deleting", None),
|
|
||||||
("creating", None),
|
|
||||||
("error", False),
|
|
||||||
)
|
|
||||||
STATUS_DISPLAY_CHOICES = (
|
|
||||||
("in-use", pgettext_lazy("Current status of share server", u"In-use")),
|
|
||||||
("active", pgettext_lazy("Current status of share server", u"Active")),
|
|
||||||
("creating", pgettext_lazy("Current status of share server",
|
|
||||||
u"Creating")),
|
|
||||||
("error", pgettext_lazy("Current status of share server",
|
|
||||||
u"Error")),
|
|
||||||
)
|
|
||||||
uid = tables.Column("id", verbose_name=_("Id"),
|
|
||||||
link="horizon:admin:shares:share_server_detail")
|
|
||||||
host = tables.Column("host", verbose_name=_("Host"))
|
|
||||||
project = tables.Column("project_name", verbose_name=_("Project"))
|
|
||||||
|
|
||||||
def get_share_server_link(share_serv):
|
|
||||||
if hasattr(share_serv, 'share_network_id'):
|
|
||||||
return reverse("horizon:admin:shares:share_network_detail",
|
|
||||||
args=(share_serv.share_network_id,))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
share_net_name = tables.Column("share_network_name",
|
|
||||||
verbose_name=_("Share Network"),
|
|
||||||
link=get_share_server_link)
|
|
||||||
status = tables.Column("status", verbose_name=_("Status"),
|
|
||||||
status=True, filters=(title,),
|
|
||||||
status_choices=STATUS_CHOICES,
|
|
||||||
display_choices=STATUS_DISPLAY_CHOICES)
|
|
||||||
|
|
||||||
def get_object_display(self, share_server):
|
|
||||||
return six.text_type(share_server.id)
|
|
||||||
|
|
||||||
def get_object_id(self, share_server):
|
|
||||||
return six.text_type(share_server.id)
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = "share_servers"
|
|
||||||
status_columns = ["status"]
|
|
||||||
verbose_name = _("Share Server")
|
|
||||||
table_actions = (
|
|
||||||
tables.NameFilterAction,
|
|
||||||
DeleteShareServer)
|
|
||||||
row_class = UpdateShareServerRow
|
|
||||||
row_actions = (
|
|
||||||
DeleteShareServer,)
|
|
||||||
|
|
||||||
|
|
||||||
class ShareInstancesTable(tables.DataTable):
|
|
||||||
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"),
|
|
||||||
)
|
|
||||||
uuid = tables.Column(
|
|
||||||
"id", verbose_name=_("ID"),
|
|
||||||
link="horizon:admin:shares:share_instance_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"))
|
|
||||||
|
|
||||||
class Meta(object):
|
|
||||||
name = "share_instances"
|
|
||||||
verbose_name = _("Share Instances")
|
|
||||||
status_columns = ("status", )
|
|
||||||
table_actions = (
|
|
||||||
tables.NameFilterAction,)
|
|
||||||
multi_select = False
|
|
||||||
|
|
||||||
def get_share_network_link(share_instance):
|
|
||||||
if getattr(share_instance, 'share_network_id', None):
|
|
||||||
return reverse("horizon:admin:shares:share_network_detail",
|
|
||||||
args=(share_instance.share_network_id,))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_share_server_link(share_instance):
|
|
||||||
if getattr(share_instance, 'share_server_id', None):
|
|
||||||
return reverse("horizon:admin:shares:share_server_detail",
|
|
||||||
args=(share_instance.share_server_id,))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_share_link(share_instance):
|
|
||||||
if getattr(share_instance, 'share_id', None):
|
|
||||||
return reverse("horizon:project:shares:detail",
|
|
||||||
args=(share_instance.share_id,))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
share_net_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 Id"),
|
|
||||||
link=get_share_server_link)
|
|
||||||
share_id = tables.Column(
|
|
||||||
"share_id",
|
|
||||||
verbose_name=_("Share ID"),
|
|
||||||
link=get_share_link)
|
|
||||||
|
|
||||||
def get_object_display(self, share_instance):
|
|
||||||
return six.text_type(share_instance.id)
|
|
||||||
|
|
||||||
def get_object_id(self, share_instance):
|
|
||||||
return six.text_type(share_instance.id)
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright 2014 OpenStack Foundation
|
# Copyright 2017 Mirantis, Inc.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
@ -13,241 +13,20 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from horizon import exceptions
|
|
||||||
from horizon import tabs
|
from horizon import tabs
|
||||||
|
|
||||||
from openstack_dashboard.api import base
|
|
||||||
from openstack_dashboard.api import neutron
|
|
||||||
|
|
||||||
from manila_ui.api import manila
|
class ShareOverviewTab(tabs.Tab):
|
||||||
from manila_ui.api import network
|
name = _("Share Overview")
|
||||||
from manila_ui.dashboards.admin.shares import tables
|
slug = "share_overview_tab"
|
||||||
from manila_ui.dashboards.admin.shares import utils
|
template_name = "admin/shares/_detail.html"
|
||||||
from manila_ui.dashboards import utils as common_utils
|
|
||||||
|
|
||||||
|
|
||||||
class SnapshotsTab(tabs.TableTab):
|
|
||||||
table_classes = (tables.SnapshotsTable, )
|
|
||||||
name = _("Snapshots")
|
|
||||||
slug = "snapshots_tab"
|
|
||||||
template_name = "horizon/common/_detail_table.html"
|
|
||||||
|
|
||||||
def _set_id_if_nameless(self, snapshots):
|
|
||||||
for snap in snapshots:
|
|
||||||
if not snap.name:
|
|
||||||
snap.name = snap.id
|
|
||||||
|
|
||||||
def get_snapshots_data(self):
|
|
||||||
snapshots = []
|
|
||||||
try:
|
|
||||||
snapshots = manila.share_snapshot_list(
|
|
||||||
self.request, search_opts={'all_tenants': True})
|
|
||||||
shares = manila.share_list(self.request)
|
|
||||||
share_names = dict([(share.id, share.name or share.id)
|
|
||||||
for share in shares])
|
|
||||||
for snapshot in snapshots:
|
|
||||||
snapshot.share = share_names.get(snapshot.share_id)
|
|
||||||
except Exception:
|
|
||||||
msg = _("Unable to retrieve snapshot list.")
|
|
||||||
exceptions.handle(self.request, msg)
|
|
||||||
|
|
||||||
# Gather our projects to correlate against IDs
|
|
||||||
utils.set_project_name_to_objects(self.request, snapshots)
|
|
||||||
|
|
||||||
return snapshots
|
|
||||||
|
|
||||||
|
|
||||||
class SharesTab(tabs.TableTab):
|
|
||||||
table_classes = (tables.SharesTable, )
|
|
||||||
name = _("Shares")
|
|
||||||
slug = "shares_tab"
|
|
||||||
template_name = "horizon/common/_detail_table.html"
|
|
||||||
|
|
||||||
def get_shares_data(self):
|
|
||||||
shares = []
|
|
||||||
try:
|
|
||||||
shares = manila.share_list(
|
|
||||||
self.request, search_opts={'all_tenants': True})
|
|
||||||
snapshots = manila.share_snapshot_list(
|
|
||||||
self.request, detailed=True, search_opts={'all_tenants': True})
|
|
||||||
share_ids_with_snapshots = []
|
|
||||||
for snapshot in snapshots:
|
|
||||||
share_ids_with_snapshots.append(snapshot.to_dict()['share_id'])
|
|
||||||
for share in shares:
|
|
||||||
if share.to_dict()['id'] in share_ids_with_snapshots:
|
|
||||||
setattr(share, 'has_snapshot', True)
|
|
||||||
else:
|
|
||||||
setattr(share, 'has_snapshot', False)
|
|
||||||
except Exception:
|
|
||||||
exceptions.handle(
|
|
||||||
self.request, _('Unable to retrieve share list.'))
|
|
||||||
|
|
||||||
# Gather our projects to correlate against IDs
|
|
||||||
utils.set_project_name_to_objects(self.request, shares)
|
|
||||||
|
|
||||||
return shares
|
|
||||||
|
|
||||||
|
|
||||||
class ShareTypesTab(tabs.TableTab):
|
|
||||||
table_classes = (tables.ShareTypesTable, )
|
|
||||||
name = _("Share Types")
|
|
||||||
slug = "share_types_tab"
|
|
||||||
template_name = "horizon/common/_detail_table.html"
|
|
||||||
|
|
||||||
def get_share_types_data(self):
|
|
||||||
try:
|
|
||||||
share_types = manila.share_type_list(self.request)
|
|
||||||
except Exception:
|
|
||||||
share_types = []
|
|
||||||
exceptions.handle(self.request,
|
|
||||||
_("Unable to retrieve share types"))
|
|
||||||
# Convert dict with extra specs to friendly view
|
|
||||||
for st in share_types:
|
|
||||||
st.extra_specs = common_utils.metadata_to_str(
|
|
||||||
st.extra_specs, 8, 45)
|
|
||||||
return share_types
|
|
||||||
|
|
||||||
|
|
||||||
class SecurityServiceTab(tabs.TableTab):
|
|
||||||
table_classes = (tables.SecurityServiceTable,)
|
|
||||||
name = _("Security Services")
|
|
||||||
slug = "security_services_tab"
|
|
||||||
template_name = "horizon/common/_detail_table.html"
|
|
||||||
|
|
||||||
def get_security_services_data(self):
|
|
||||||
try:
|
|
||||||
security_services = manila.security_service_list(
|
|
||||||
self.request, search_opts={'all_tenants': True})
|
|
||||||
except Exception:
|
|
||||||
security_services = []
|
|
||||||
exceptions.handle(self.request,
|
|
||||||
_("Unable to retrieve security services"))
|
|
||||||
|
|
||||||
utils.set_project_name_to_objects(self.request, security_services)
|
|
||||||
return security_services
|
|
||||||
|
|
||||||
|
|
||||||
class ShareNetworkTab(tabs.TableTab):
|
|
||||||
name = _("Share Networks")
|
|
||||||
slug = "share_networks_tab"
|
|
||||||
template_name = "horizon/common/_detail_table.html"
|
|
||||||
|
|
||||||
def __init__(self, tab_group, request):
|
|
||||||
if base.is_service_enabled(request, 'network'):
|
|
||||||
self.table_classes = (tables.NeutronShareNetworkTable,)
|
|
||||||
else:
|
|
||||||
self.table_classes = (tables.NovaShareNetworkTable,)
|
|
||||||
super(ShareNetworkTab, self).__init__(tab_group, request)
|
|
||||||
|
|
||||||
def get_share_networks_data(self):
|
|
||||||
try:
|
|
||||||
share_networks = manila.share_network_list(
|
|
||||||
self.request, detailed=True, search_opts={'all_tenants': True})
|
|
||||||
if base.is_service_enabled(self.request, 'network'):
|
|
||||||
neutron_net_names = dict((net.id, net.name) for net in
|
|
||||||
neutron.network_list(self.request))
|
|
||||||
neutron_subnet_names = dict((net.id, net.name) for net in
|
|
||||||
neutron.subnet_list(self.request))
|
|
||||||
for sn in share_networks:
|
|
||||||
sn.neutron_net = neutron_net_names.get(
|
|
||||||
sn.neutron_net_id) or sn.neutron_net_id or "-"
|
|
||||||
sn.neutron_subnet = neutron_subnet_names.get(
|
|
||||||
sn.neutron_subnet_id) or sn.neutron_subnet_id or "-"
|
|
||||||
else:
|
|
||||||
nova_net_names = dict(
|
|
||||||
[(net.id, net.label)
|
|
||||||
for net in network.network_list(self.request)])
|
|
||||||
for sn in share_networks:
|
|
||||||
sn.nova_net = nova_net_names.get(
|
|
||||||
sn.nova_net_id) or sn.nova_net_id or "-"
|
|
||||||
except Exception:
|
|
||||||
share_networks = []
|
|
||||||
exceptions.handle(self.request,
|
|
||||||
_("Unable to retrieve share networks"))
|
|
||||||
utils.set_project_name_to_objects(self.request, share_networks)
|
|
||||||
return share_networks
|
|
||||||
|
|
||||||
|
|
||||||
class ShareInstancesTab(tabs.TableTab):
|
|
||||||
table_classes = (tables.ShareInstancesTable,)
|
|
||||||
name = _("Share Instances")
|
|
||||||
slug = "share_instances_tab"
|
|
||||||
template_name = "horizon/common/_detail_table.html"
|
|
||||||
|
|
||||||
def get_share_instances_data(self):
|
|
||||||
try:
|
|
||||||
share_instances = manila.share_instance_list(self.request)
|
|
||||||
except Exception:
|
|
||||||
share_instances = []
|
|
||||||
exceptions.handle(
|
|
||||||
self.request, _("Unable to retrieve share instances."))
|
|
||||||
return share_instances
|
|
||||||
|
|
||||||
|
|
||||||
class ShareInstanceOverviewTab(tabs.Tab):
|
|
||||||
name = _("Overview")
|
|
||||||
slug = "overview"
|
|
||||||
template_name = ("admin/shares/_detail_share_instance.html")
|
|
||||||
|
|
||||||
def get_context_data(self, request):
|
def get_context_data(self, request):
|
||||||
return {"share_instance": self.tab_group.kwargs['share_instance']}
|
return {"share": self.tab_group.kwargs["share"]}
|
||||||
|
|
||||||
|
|
||||||
class ShareInstanceDetailTabs(tabs.TabGroup):
|
class ShareDetailTabs(tabs.TabGroup):
|
||||||
slug = "share_instance_details"
|
slug = "share_details"
|
||||||
tabs = (ShareInstanceOverviewTab,)
|
tabs = (
|
||||||
|
ShareOverviewTab,
|
||||||
|
)
|
||||||
class ShareServerTab(tabs.TableTab):
|
|
||||||
table_classes = (tables.ShareServerTable,)
|
|
||||||
name = _("Share Servers")
|
|
||||||
slug = "share_servers_tab"
|
|
||||||
template_name = "horizon/common/_detail_table.html"
|
|
||||||
|
|
||||||
def get_share_servers_data(self):
|
|
||||||
try:
|
|
||||||
share_servers = manila.share_server_list(
|
|
||||||
self.request)
|
|
||||||
except Exception:
|
|
||||||
share_servers = []
|
|
||||||
exceptions.handle(self.request,
|
|
||||||
_("Unable to retrieve share servers"))
|
|
||||||
utils.set_project_name_to_objects(self.request, share_servers)
|
|
||||||
return share_servers
|
|
||||||
|
|
||||||
|
|
||||||
class ShareServerOverviewTab(tabs.Tab):
|
|
||||||
name = _("Overview")
|
|
||||||
slug = "overview"
|
|
||||||
template_name = ("admin/shares/_detail_share_server.html")
|
|
||||||
|
|
||||||
def get_context_data(self, request):
|
|
||||||
return {"share_server": self.tab_group.kwargs['share_server']}
|
|
||||||
|
|
||||||
|
|
||||||
class ShareServerDetailTabs(tabs.TabGroup):
|
|
||||||
slug = "share_server_details"
|
|
||||||
tabs = (ShareServerOverviewTab,)
|
|
||||||
|
|
||||||
|
|
||||||
class ShareTabs(tabs.TabGroup):
|
|
||||||
slug = "share_tabs"
|
|
||||||
tabs = (SharesTab, SnapshotsTab, ShareNetworkTab, SecurityServiceTab,
|
|
||||||
ShareTypesTab, ShareServerTab, ShareInstancesTab)
|
|
||||||
sticky = True
|
|
||||||
|
|
||||||
|
|
||||||
class SnapshotOverviewTab(tabs.Tab):
|
|
||||||
name = _("Snapshot Overview")
|
|
||||||
slug = "snapshot_overview_tab"
|
|
||||||
template_name = ("admin/shares/"
|
|
||||||
"_snapshot_detail_overview.html")
|
|
||||||
|
|
||||||
def get_context_data(self, request):
|
|
||||||
return {"snapshot": self.tab_group.kwargs['snapshot']}
|
|
||||||
|
|
||||||
|
|
||||||
class SnapshotDetailTabs(tabs.TabGroup):
|
|
||||||
slug = "snapshot_details"
|
|
||||||
tabs = (SnapshotOverviewTab,)
|
|
||||||
|
100
manila_ui/dashboards/admin/shares/templates/shares/_detail.html
Normal file
100
manila_ui/dashboards/admin/shares/templates/shares/_detail.html
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
{% load i18n sizeformat parse_date %}
|
||||||
|
|
||||||
|
<h3>{% trans "Share Overview" %}</h3>
|
||||||
|
<div class="detail">
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd>{{ share.name }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ share.id }}</dd>
|
||||||
|
{% if share.description %}
|
||||||
|
<dt>{% trans "Description" %}</dt>
|
||||||
|
<dd>{{ share.description }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<dt>{% trans "Status" %}</dt>
|
||||||
|
<dd>{{ share.status|capfirst }}</dd>
|
||||||
|
<dt>{% trans "Export locations" %}</dt>
|
||||||
|
{% for el in share.export_locations %}
|
||||||
|
<dd><p>
|
||||||
|
<div><b>Path:</b>
|
||||||
|
<input type="text" readonly="true"
|
||||||
|
value="{{ el.path }}" size="{{ share.el_size }}"
|
||||||
|
onClick="this.setSelectionRange(0, this.value.length)">
|
||||||
|
</div>
|
||||||
|
<div><b>Preferred:</b> {{ el.preferred }}</div>
|
||||||
|
{% if el.is_admin_only == True or el.is_admin_only == False %}
|
||||||
|
<div><b>Is admin only:</b> {{ el.is_admin_only }}</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if el.share_instance_id %}
|
||||||
|
<div><b>Share Replica ID:</b> {{ el.share_instance_id }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</p></dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% if share.snapshot_id %}
|
||||||
|
<dt>{% trans "Snapshot ID" %}</dt>
|
||||||
|
{% url 'horizon:admin:share_snapshots:snapshot_detail' share.snapshot_id as snapshot_url%}
|
||||||
|
<dd><a href="{{ snapshot_url }}">{{ share.snapshot_id }}</a></dd>
|
||||||
|
{% endif %}
|
||||||
|
<dt>{% trans "Visibility" %}</dt>
|
||||||
|
{% if share.is_public == True %}
|
||||||
|
<dd>{{ 'public' }}</dd>
|
||||||
|
{% else %}
|
||||||
|
<dd>{{ 'private' }}</dd>
|
||||||
|
<dt>{% trans "Availability zone" %}</dt>
|
||||||
|
<dd>{{ share.availability_zone }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<dt>{% trans "Size" %}</dt>
|
||||||
|
<dd>{{ share.size }} {% trans "GiB" %}</dd>
|
||||||
|
<dt>{% trans "Protocol" %}</dt>
|
||||||
|
<dd>{{ share.share_proto }}</dd>
|
||||||
|
{% if share.share_type %}
|
||||||
|
<dt>{% trans "Share type" %}</dt>
|
||||||
|
<dd><p>
|
||||||
|
<div><b>Name: </b>{{ share.share_type_name }}</div>
|
||||||
|
<div><b>ID: </b>{{ share.share_type }}</div>
|
||||||
|
</p></dd>
|
||||||
|
{% endif %}
|
||||||
|
{% if share.share_network_id %}
|
||||||
|
<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 %}
|
||||||
|
<dt>{% trans "Mount snapshot support" %}</dt>
|
||||||
|
<dd>{{ share.mount_snapshot_support }}</dd>
|
||||||
|
<dt>{% trans "Created" %}</dt>
|
||||||
|
<dd>{{ share.created_at|parse_date }}</dd>
|
||||||
|
<dt>{% trans "Host" %}</dt>
|
||||||
|
<dd>{{ share.host }}</dd>
|
||||||
|
<dt>{% trans "Task state" %}</dt>
|
||||||
|
<dd>{{ share.task_state }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status row-fluid detail">
|
||||||
|
<h4>{% trans "Access Rules" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
{% for rule in share.rules %}
|
||||||
|
<dt>{{ rule.access_type }}</dt>
|
||||||
|
<dd><p>
|
||||||
|
<div><b>Access to: </b>{{ rule.access_to }}</div>
|
||||||
|
<div><b>Access Level: </b>{{ rule.access_level }}</div>
|
||||||
|
<div><b>Status: </b>{{ rule.state }}</div>
|
||||||
|
<div><b>Access Key: </b>{{ rule.access_key }}</div>
|
||||||
|
</p></dd>
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="status row-fluid detail">
|
||||||
|
<h4>{% trans "Metadata" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
{% for key, value in share.metadata.items %}
|
||||||
|
<dt>{{ key }}</dt>
|
||||||
|
<dd>{{ value }}</dd>
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -1,33 +0,0 @@
|
|||||||
{% load i18n sizeformat parse_date %}
|
|
||||||
|
|
||||||
<h3>{% trans "Snapshot Overview" %}</h3>
|
|
||||||
|
|
||||||
<div class="info row-fluid detail">
|
|
||||||
<h4>{% trans "Info" %}</h4>
|
|
||||||
<hr class="header_rule">
|
|
||||||
<dl>
|
|
||||||
<dt>{% trans "Name" %}</dt>
|
|
||||||
<dd>{{ snapshot.name }}</dd>
|
|
||||||
<dt>{% trans "ID" %}</dt>
|
|
||||||
<dd>{{ snapshot.id }}</dd>
|
|
||||||
<dt>{% trans "Source" %}</dt>
|
|
||||||
<dd>{{ snapshot.share_id }}</dd>
|
|
||||||
{% if snapshot.description %}
|
|
||||||
<dt>{% trans "Description" %}</dt>
|
|
||||||
<dd>{{ snapshot.description }}</dd>
|
|
||||||
{% endif %}
|
|
||||||
<dt>{% trans "Status" %}</dt>
|
|
||||||
<dd>{{ snapshot.status|capfirst }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="specs row-fluid detail">
|
|
||||||
<h4>{% trans "Specs" %}</h4>
|
|
||||||
<hr class="header_rule">
|
|
||||||
<dl>
|
|
||||||
<dt>{% trans "Size" %}</dt>
|
|
||||||
<dd>{{ snapshot.size }} {% trans "GiB" %}</dd>
|
|
||||||
<dt>{% trans "Created" %}</dt>
|
|
||||||
<dd>{{ snapshot.created_at|parse_date }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
@ -5,7 +5,7 @@
|
|||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
{{ tab_group.render }}
|
{{ shares_table.render }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -10,75 +10,72 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from django.conf.urls import url # noqa
|
from django.conf import urls
|
||||||
|
|
||||||
from manila_ui.api import manila
|
from manila_ui.api import manila
|
||||||
from manila_ui.dashboards.admin.shares.replicas import views as replica_views
|
from manila_ui.dashboards.admin.shares.replicas import views as replica_views
|
||||||
from manila_ui.dashboards.admin.shares import views
|
from manila_ui.dashboards.admin.shares import views
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
urls.url(
|
||||||
url(r'^(?P<share_id>[^/]+)/$', views.DetailView.as_view(), name='detail'),
|
r'^$',
|
||||||
url(r'^snapshots/(?P<snapshot_id>[^/]+)$',
|
views.SharesView.as_view(),
|
||||||
views.SnapshotDetailView.as_view(),
|
name='index'),
|
||||||
name='snapshot-detail'),
|
urls.url(
|
||||||
url(r'^share_networks/(?P<share_network_id>[^/]+)$',
|
r'^(?P<share_id>[^/]+)/$',
|
||||||
views.ShareNetworkDetailView.as_view(),
|
views.DetailView.as_view(),
|
||||||
name='share_network_detail'),
|
name='detail'),
|
||||||
url(r'^security_services/(?P<sec_service_id>[^/]+)$',
|
urls.url(
|
||||||
views.SecurityServiceDetailView.as_view(),
|
r'^manage$',
|
||||||
name='security_service_detail'),
|
views.ManageShareView.as_view(),
|
||||||
url(r'^create_type$', views.CreateShareTypeView.as_view(),
|
name='manage'),
|
||||||
name='create_type'),
|
urls.url(
|
||||||
url(r'^manage_share_type_access/(?P<share_type_id>[^/]+)$',
|
r'^unmanage/(?P<share_id>[^/]+)$',
|
||||||
views.ManageShareTypeAccessView.as_view(),
|
views.UnmanageShareView.as_view(),
|
||||||
name='manage_share_type_access'),
|
|
||||||
url(r'^update_type/(?P<share_type_id>[^/]+)/extra_specs$',
|
|
||||||
views.UpdateShareTypeView.as_view(),
|
|
||||||
name='update_type'),
|
|
||||||
url(r'^share_servers/(?P<share_server_id>[^/]+)$',
|
|
||||||
views.ShareServDetail.as_view(),
|
|
||||||
name='share_server_detail'),
|
|
||||||
url(r'^\?tab=share_tabs__share_servers_tab$', views.IndexView.as_view(),
|
|
||||||
name='share_servers_tab'),
|
|
||||||
url(r'^share_instances/(?P<share_instance_id>[^/]+)$',
|
|
||||||
views.ShareInstanceDetailView.as_view(),
|
|
||||||
name='share_instance_detail'),
|
|
||||||
url(r'^\?tab=share_tabs__share_instances_tab$', views.IndexView.as_view(),
|
|
||||||
name='share_instances_tab'),
|
|
||||||
url(r'^manage$', views.ManageShareView.as_view(), name='manage'),
|
|
||||||
url(r'^unmanage/(?P<share_id>[^/]+)$', views.UnmanageShareView.as_view(),
|
|
||||||
name='unmanage'),
|
name='unmanage'),
|
||||||
]
|
]
|
||||||
|
|
||||||
if manila.is_replication_enabled():
|
if manila.is_replication_enabled():
|
||||||
urlpatterns.extend([
|
urlpatterns.extend([
|
||||||
url(r'^(?P<share_id>[^/]+)/replicas/$',
|
urls.url(
|
||||||
|
r'^(?P<share_id>[^/]+)/replicas/$',
|
||||||
replica_views.ManageReplicasView.as_view(),
|
replica_views.ManageReplicasView.as_view(),
|
||||||
name='manage_replicas'),
|
name='manage_replicas'),
|
||||||
url(r'^replica/(?P<replica_id>[^/]+)$',
|
urls.url(
|
||||||
|
r'^replica/(?P<replica_id>[^/]+)$',
|
||||||
replica_views.DetailReplicaView.as_view(),
|
replica_views.DetailReplicaView.as_view(),
|
||||||
name='replica_detail'),
|
name='replica_detail'),
|
||||||
url(r'^replica/(?P<replica_id>[^/]+)/resync_replica$',
|
urls.url(
|
||||||
|
r'^replica/(?P<replica_id>[^/]+)/resync_replica$',
|
||||||
replica_views.ResyncReplicaView.as_view(),
|
replica_views.ResyncReplicaView.as_view(),
|
||||||
name='resync_replica'),
|
name='resync_replica'),
|
||||||
url(r'^replica/(?P<replica_id>[^/]+)/reset_replica_status$',
|
urls.url(
|
||||||
|
r'^replica/(?P<replica_id>[^/]+)/reset_replica_status$',
|
||||||
replica_views.ResetReplicaStatusView.as_view(),
|
replica_views.ResetReplicaStatusView.as_view(),
|
||||||
name='reset_replica_status'),
|
name='reset_replica_status'),
|
||||||
url(r'^replica/(?P<replica_id>[^/]+)/reset_replica_state$',
|
urls.url(
|
||||||
|
r'^replica/(?P<replica_id>[^/]+)/reset_replica_state$',
|
||||||
replica_views.ResetReplicaStateView.as_view(),
|
replica_views.ResetReplicaStateView.as_view(),
|
||||||
name='reset_replica_state'),
|
name='reset_replica_state'),
|
||||||
])
|
])
|
||||||
|
|
||||||
if manila.is_migration_enabled():
|
if manila.is_migration_enabled():
|
||||||
urlpatterns.extend([
|
urlpatterns.extend([
|
||||||
url(r'^migration_start/(?P<share_id>[^/]+)$',
|
urls.url(
|
||||||
views.MigrationStartView.as_view(), name='migration_start'),
|
r'^migration_start/(?P<share_id>[^/]+)$',
|
||||||
url(r'^migration_complete/(?P<share_id>[^/]+)$',
|
views.MigrationStartView.as_view(),
|
||||||
views.MigrationCompleteView.as_view(), name='migration_complete'),
|
name='migration_start'),
|
||||||
url(r'^migration_cancel/(?P<share_id>[^/]+)$',
|
urls.url(
|
||||||
views.MigrationCancelView.as_view(), name='migration_cancel'),
|
r'^migration_complete/(?P<share_id>[^/]+)$',
|
||||||
url(r'^migration_get_progress/(?P<share_id>[^/]+)$',
|
views.MigrationCompleteView.as_view(),
|
||||||
|
name='migration_complete'),
|
||||||
|
urls.url(
|
||||||
|
r'^migration_cancel/(?P<share_id>[^/]+)$',
|
||||||
|
views.MigrationCancelView.as_view(),
|
||||||
|
name='migration_cancel'),
|
||||||
|
urls.url(
|
||||||
|
r'^migration_get_progress/(?P<share_id>[^/]+)$',
|
||||||
views.MigrationGetProgressView.as_view(),
|
views.MigrationGetProgressView.as_view(),
|
||||||
name='migration_get_progress'),
|
name='migration_get_progress'),
|
||||||
])
|
])
|
||||||
|
@ -19,37 +19,54 @@ Admin views for managing shares.
|
|||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from horizon import forms
|
from horizon import forms
|
||||||
from horizon import tabs
|
from horizon import tables
|
||||||
from horizon.utils import memoized
|
from horizon.utils import memoized
|
||||||
from horizon import workflows
|
|
||||||
|
|
||||||
from manila_ui.api import manila
|
from manila_ui.api import manila
|
||||||
from manila_ui.dashboards.admin.shares import forms as project_forms
|
from manila_ui.dashboards.admin.shares import forms as project_forms
|
||||||
from manila_ui.dashboards.admin.shares import tabs as project_tabs
|
from manila_ui.dashboards.admin.shares import tables as s_tables
|
||||||
import manila_ui.dashboards.admin.shares.workflows as share_workflows
|
from manila_ui.dashboards.admin.shares import tabs as s_tabs
|
||||||
from manila_ui.dashboards.project.shares.security_services import \
|
from manila_ui.dashboards.admin import utils
|
||||||
views as ss_views
|
|
||||||
from manila_ui.dashboards.project.shares.share_networks import \
|
|
||||||
views as sn_views
|
|
||||||
from manila_ui.dashboards.project.shares.shares import views as share_views
|
from manila_ui.dashboards.project.shares.shares import views as share_views
|
||||||
from manila_ui.dashboards.project.shares.snapshots import \
|
|
||||||
views as snapshot_views
|
|
||||||
from manila_ui.dashboards import utils as ui_utils
|
|
||||||
from manila_ui.utils import filters
|
|
||||||
|
|
||||||
filters = (filters.get_item,)
|
|
||||||
|
|
||||||
|
|
||||||
class IndexView(tabs.TabbedTableView, share_views.ShareTableMixIn):
|
class SharesView(tables.MultiTableView, share_views.ShareTableMixIn):
|
||||||
tab_group_class = project_tabs.ShareTabs
|
table_classes = (
|
||||||
|
s_tables.SharesTable,
|
||||||
|
)
|
||||||
template_name = "admin/shares/index.html"
|
template_name = "admin/shares/index.html"
|
||||||
page_title = _("Shares")
|
page_title = _("Shares")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_shares_data(self):
|
||||||
|
shares = []
|
||||||
|
try:
|
||||||
|
shares = manila.share_list(
|
||||||
|
self.request, search_opts={'all_tenants': True})
|
||||||
|
snapshots = manila.share_snapshot_list(
|
||||||
|
self.request, detailed=True, search_opts={'all_tenants': True})
|
||||||
|
share_ids_with_snapshots = []
|
||||||
|
for snapshot in snapshots:
|
||||||
|
share_ids_with_snapshots.append(snapshot.to_dict()['share_id'])
|
||||||
|
for share in shares:
|
||||||
|
if share.to_dict()['id'] in share_ids_with_snapshots:
|
||||||
|
setattr(share, 'has_snapshot', True)
|
||||||
|
else:
|
||||||
|
setattr(share, 'has_snapshot', False)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(
|
||||||
|
self.request, _('Unable to retrieve share list.'))
|
||||||
|
|
||||||
|
# Gather our projects to correlate against IDs
|
||||||
|
utils.set_project_name_to_objects(self.request, shares)
|
||||||
|
|
||||||
|
return shares
|
||||||
|
|
||||||
|
|
||||||
class DetailView(share_views.DetailView):
|
class DetailView(share_views.DetailView):
|
||||||
|
tab_group_class = s_tabs.ShareDetailTabs
|
||||||
template_name = "admin/shares/detail.html"
|
template_name = "admin/shares/detail.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
@ -59,18 +76,6 @@ class DetailView(share_views.DetailView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class SecurityServiceDetailView(ss_views.Detail):
|
|
||||||
redirect_url = reverse_lazy('horizon:admin:shares:index')
|
|
||||||
|
|
||||||
|
|
||||||
class ShareNetworkDetailView(sn_views.Detail):
|
|
||||||
redirect_url = reverse_lazy('horizon:admin:shares:index')
|
|
||||||
|
|
||||||
|
|
||||||
class SnapshotDetailView(snapshot_views.SnapshotDetailView):
|
|
||||||
redirect_url = reverse_lazy('horizon:admin:shares:index')
|
|
||||||
|
|
||||||
|
|
||||||
class ManageShareView(forms.ModalFormView):
|
class ManageShareView(forms.ModalFormView):
|
||||||
form_class = project_forms.ManageShare
|
form_class = project_forms.ManageShare
|
||||||
template_name = 'admin/shares/manage_share.html'
|
template_name = 'admin/shares/manage_share.html'
|
||||||
@ -271,151 +276,3 @@ class UnmanageShareView(forms.ModalFormView):
|
|||||||
'name': share.name,
|
'name': share.name,
|
||||||
'host': getattr(share, "host"),
|
'host': getattr(share, "host"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class CreateShareTypeView(forms.ModalFormView):
|
|
||||||
form_class = project_forms.CreateShareType
|
|
||||||
form_id = "create_share_type"
|
|
||||||
template_name = 'admin/shares/create_share_type.html'
|
|
||||||
modal_header = _("Create Share Type")
|
|
||||||
submit_label = _("Create")
|
|
||||||
submit_url = reverse_lazy("horizon:admin:shares:create_type")
|
|
||||||
success_url = 'horizon:admin:shares:index'
|
|
||||||
page_title = _("Create Share Type")
|
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
return reverse(self.success_url)
|
|
||||||
|
|
||||||
|
|
||||||
class ManageShareTypeAccessView(workflows.WorkflowView):
|
|
||||||
workflow_class = share_workflows.ManageShareTypeAccessWorkflow
|
|
||||||
template_name = "admin/shares/manage_share_type_access.html"
|
|
||||||
success_url = 'horizon:project:shares:index'
|
|
||||||
page_title = _("Manage Share Type Access")
|
|
||||||
|
|
||||||
def get_initial(self):
|
|
||||||
return {'id': self.kwargs["share_type_id"]}
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(ManageShareTypeAccessView, self).get_context_data(
|
|
||||||
**kwargs)
|
|
||||||
context['id'] = self.kwargs['share_type_id']
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateShareTypeView(forms.ModalFormView):
|
|
||||||
form_class = project_forms.UpdateShareType
|
|
||||||
form_id = "update_share_type"
|
|
||||||
template_name = "admin/shares/update_share_type.html"
|
|
||||||
modal_header = _("Update Share Type")
|
|
||||||
modal_id = "update_share_type_modal"
|
|
||||||
submit_label = _("Update")
|
|
||||||
submit_url = "horizon:admin:shares:update_type"
|
|
||||||
success_url = reverse_lazy("horizon:admin:shares:index")
|
|
||||||
page_title = _("Update Share Type")
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
if not hasattr(self, "_object"):
|
|
||||||
st_id = self.kwargs["share_type_id"]
|
|
||||||
try:
|
|
||||||
self._object = manila.share_type_get(self.request, st_id)
|
|
||||||
except Exception:
|
|
||||||
msg = _("Unable to retrieve share_type.")
|
|
||||||
url = reverse("horizon:admin:shares:index")
|
|
||||||
exceptions.handle(self.request, msg, redirect=url)
|
|
||||||
return self._object
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(UpdateShareTypeView, 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_type = self.get_object()
|
|
||||||
return {
|
|
||||||
"id": self.kwargs["share_type_id"],
|
|
||||||
"name": share_type.name,
|
|
||||||
"extra_specs": share_type.extra_specs,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ShareServDetail(tabs.TabView):
|
|
||||||
tab_group_class = project_tabs.ShareServerDetailTabs
|
|
||||||
template_name = 'admin/shares/detail_share_server.html'
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(ShareServDetail, self).get_context_data(**kwargs)
|
|
||||||
share_server = self.get_data()
|
|
||||||
share_server_display_name = share_server.id
|
|
||||||
context["share_server"] = share_server
|
|
||||||
context["share_server_display_name"] = share_server_display_name
|
|
||||||
context["page_title"] = _("Share Server Details: %(server_name)s") % {
|
|
||||||
'server_name': share_server_display_name}
|
|
||||||
return context
|
|
||||||
|
|
||||||
@memoized.memoized_method
|
|
||||||
def get_data(self):
|
|
||||||
try:
|
|
||||||
share_serv_id = self.kwargs['share_server_id']
|
|
||||||
share_serv = manila.share_server_get(self.request, share_serv_id)
|
|
||||||
share_search_opts = {'share_server_id': share_serv.id}
|
|
||||||
shares_list = manila.share_list(self.request,
|
|
||||||
search_opts=share_search_opts)
|
|
||||||
for share in shares_list:
|
|
||||||
share.name_or_id = share.name or share.id
|
|
||||||
share_serv.shares_list = shares_list
|
|
||||||
if not hasattr(share_serv, 'share_network_id'):
|
|
||||||
share_serv.share_network_id = None
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
redirect = reverse('horizon:admin:shares:index')
|
|
||||||
exceptions.handle(self.request,
|
|
||||||
_('Unable to retrieve share server details.'),
|
|
||||||
redirect=redirect)
|
|
||||||
return share_serv
|
|
||||||
|
|
||||||
def get_tabs(self, request, *args, **kwargs):
|
|
||||||
share_server = self.get_data()
|
|
||||||
return self.tab_group_class(request, share_server=share_server,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ShareInstanceDetailView(tabs.TabView):
|
|
||||||
tab_group_class = project_tabs.ShareInstanceDetailTabs
|
|
||||||
template_name = 'admin/shares/share_instance_detail.html'
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(self.__class__, self).get_context_data(**kwargs)
|
|
||||||
share_instance = self.get_data()
|
|
||||||
context["share_instance"] = share_instance
|
|
||||||
context["page_title"] = (
|
|
||||||
_("Share Instance Details: %s") % share_instance.id)
|
|
||||||
return context
|
|
||||||
|
|
||||||
@memoized.memoized_method
|
|
||||||
def get_data(self):
|
|
||||||
try:
|
|
||||||
share_instance_id = self.kwargs['share_instance_id']
|
|
||||||
share_instance = manila.share_instance_get(
|
|
||||||
self.request, share_instance_id)
|
|
||||||
share_instance.export_locations = (
|
|
||||||
manila.share_instance_export_location_list(
|
|
||||||
self.request, share_instance_id))
|
|
||||||
export_locations = [
|
|
||||||
exp['path'] for exp in share_instance.export_locations
|
|
||||||
]
|
|
||||||
share_instance.el_size = ui_utils.calculate_longest_str_size(
|
|
||||||
export_locations)
|
|
||||||
return share_instance
|
|
||||||
except Exception:
|
|
||||||
redirect = reverse('horizon:admin:shares:index')
|
|
||||||
exceptions.handle(
|
|
||||||
self.request,
|
|
||||||
_('Unable to retrieve share instance details.'),
|
|
||||||
redirect=redirect)
|
|
||||||
|
|
||||||
def get_tabs(self, request, *args, **kwargs):
|
|
||||||
share_instance = self.get_data()
|
|
||||||
return self.tab_group_class(
|
|
||||||
request, share_instance=share_instance, **kwargs)
|
|
||||||
|
@ -13,16 +13,16 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
import horizon
|
import horizon
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.project import dashboard
|
from openstack_dashboard.dashboards.project import dashboard
|
||||||
|
|
||||||
|
|
||||||
class Shares(horizon.Panel):
|
class Shares(horizon.Panel):
|
||||||
name = _("Shares")
|
name = _("Shares")
|
||||||
slug = 'shares'
|
slug = 'shares'
|
||||||
permissions = ('openstack.services.share', )
|
permissions = (
|
||||||
|
'openstack.services.share',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
dashboard.Project.register(Shares)
|
dashboard.Project.register(Shares)
|
||||||
|
@ -132,7 +132,7 @@ class NovaShareNetworkTable(tables.DataTable):
|
|||||||
Delete)
|
Delete)
|
||||||
|
|
||||||
|
|
||||||
class NeutronShareNetworkTable(tables.DataTable):
|
class ShareNetworksTable(tables.DataTable):
|
||||||
STATUS_CHOICES = (
|
STATUS_CHOICES = (
|
||||||
("ACTIVE", True),
|
("ACTIVE", True),
|
||||||
("INACTIVE", True),
|
("INACTIVE", True),
|
||||||
|
@ -32,7 +32,7 @@ class ShareNetworkTab(tabs.TableTab):
|
|||||||
|
|
||||||
def __init__(self, tab_group, request):
|
def __init__(self, tab_group, request):
|
||||||
if base.is_service_enabled(request, 'network'):
|
if base.is_service_enabled(request, 'network'):
|
||||||
self.table_classes = (share_net_tables.NeutronShareNetworkTable,)
|
self.table_classes = (share_net_tables.ShareNetworksTable,)
|
||||||
else:
|
else:
|
||||||
self.table_classes = (share_net_tables.NovaShareNetworkTable,)
|
self.table_classes = (share_net_tables.NovaShareNetworkTable,)
|
||||||
super(ShareNetworkTab, self).__init__(tab_group, request)
|
super(ShareNetworkTab, self).__init__(tab_group, request)
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
# The slug of the panel group to be added to HORIZON_CONFIG. Required.
|
||||||
|
PANEL_GROUP = 'share'
|
||||||
|
# The display name of the PANEL_GROUP. Required.
|
||||||
|
PANEL_GROUP_NAME = 'Share'
|
||||||
|
# The slug of the dashboard the PANEL_GROUP associated with. Required.
|
||||||
|
PANEL_GROUP_DASHBOARD = 'admin'
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright 2016 Mirantis Inc.
|
# Copyright 2017 Mirantis Inc.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
@ -13,6 +13,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
PANEL_DASHBOARD = 'admin'
|
PANEL_DASHBOARD = 'admin'
|
||||||
PANEL_GROUP = 'admin'
|
PANEL_GROUP = 'share'
|
||||||
PANEL = 'shares'
|
PANEL = 'shares'
|
||||||
ADD_PANEL = 'manila_ui.dashboards.admin.shares.panel.Shares'
|
ADD_PANEL = 'manila_ui.dashboards.admin.shares.panel.Shares'
|
@ -0,0 +1,18 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
PANEL_DASHBOARD = 'admin'
|
||||||
|
PANEL_GROUP = 'share'
|
||||||
|
PANEL = 'share_snapshots'
|
||||||
|
ADD_PANEL = 'manila_ui.dashboards.admin.share_snapshots.panel.ShareSnapshots'
|
@ -0,0 +1,18 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
PANEL_DASHBOARD = 'admin'
|
||||||
|
PANEL_GROUP = 'share'
|
||||||
|
PANEL = 'share_types'
|
||||||
|
ADD_PANEL = 'manila_ui.dashboards.admin.share_types.panel.ShareTypes'
|
@ -0,0 +1,18 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
PANEL_DASHBOARD = 'admin'
|
||||||
|
PANEL_GROUP = 'share'
|
||||||
|
PANEL = 'share_networks'
|
||||||
|
ADD_PANEL = 'manila_ui.dashboards.admin.share_networks.panel.ShareNetworks'
|
@ -0,0 +1,19 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
PANEL_DASHBOARD = 'admin'
|
||||||
|
PANEL_GROUP = 'share'
|
||||||
|
PANEL = 'security_services'
|
||||||
|
ADD_PANEL = (
|
||||||
|
'manila_ui.dashboards.admin.security_services.panel.SecurityServices')
|
@ -0,0 +1,18 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
PANEL_DASHBOARD = 'admin'
|
||||||
|
PANEL_GROUP = 'share'
|
||||||
|
PANEL = 'share_servers'
|
||||||
|
ADD_PANEL = 'manila_ui.dashboards.admin.share_servers.panel.ShareServers'
|
@ -0,0 +1,18 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
PANEL_DASHBOARD = 'admin'
|
||||||
|
PANEL_GROUP = 'share'
|
||||||
|
PANEL = 'share_instances'
|
||||||
|
ADD_PANEL = 'manila_ui.dashboards.admin.share_instances.panel.ShareInstances'
|
95
manila_ui/tests/dashboards/admin/security_services/tests.py
Normal file
95
manila_ui/tests/dashboards/admin/security_services/tests.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# Copyright (c) 2014 NetApp, Inc.
|
||||||
|
# Copyright (c) 2015 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 django.core.urlresolvers import reverse
|
||||||
|
from horizon import exceptions as horizon_exceptions
|
||||||
|
import mock
|
||||||
|
from openstack_dashboard.api import keystone as api_keystone
|
||||||
|
|
||||||
|
from manila_ui.api import manila as api_manila
|
||||||
|
from manila_ui.dashboards.admin import utils
|
||||||
|
from manila_ui.tests.dashboards.project.shares import test_data
|
||||||
|
from manila_ui.tests import helpers as test
|
||||||
|
from manila_ui.tests.test_data import keystone_data
|
||||||
|
|
||||||
|
INDEX_URL = reverse('horizon:admin:security_services:index')
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityServicesTests(test.BaseAdminViewTests):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(self.__class__, self).setUp()
|
||||||
|
self.mock_object(
|
||||||
|
api_keystone, "tenant_list",
|
||||||
|
mock.Mock(return_value=(keystone_data.projects, None)))
|
||||||
|
# Reset taken list of projects to avoid test interference
|
||||||
|
utils.PROJECTS = {}
|
||||||
|
|
||||||
|
def test_detail_view(self):
|
||||||
|
sec_service = test_data.sec_service
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "security_service_get",
|
||||||
|
mock.Mock(return_value=sec_service))
|
||||||
|
url = reverse(
|
||||||
|
'horizon:admin:security_services:security_service_detail',
|
||||||
|
args=[sec_service.id])
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertContains(res, "<h1>Security Service Details: %s</h1>"
|
||||||
|
% sec_service.name,
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % sec_service.name, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % sec_service.id, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % sec_service.user, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % sec_service.server, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % sec_service.dns_ip, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % sec_service.domain, 1, 200)
|
||||||
|
self.assertNoMessages()
|
||||||
|
api_manila.security_service_get.assert_called_once_with(
|
||||||
|
mock.ANY, sec_service.id)
|
||||||
|
|
||||||
|
def test_detail_view_with_exception(self):
|
||||||
|
url = reverse(
|
||||||
|
'horizon:admin:security_services:security_service_detail',
|
||||||
|
args=[test_data.sec_service.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "security_service_get",
|
||||||
|
mock.Mock(side_effect=horizon_exceptions.NotFound(404)))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
api_manila.security_service_get.assert_called_once_with(
|
||||||
|
mock.ANY, test_data.sec_service.id)
|
||||||
|
|
||||||
|
def test_delete_security_service(self):
|
||||||
|
security_service = test_data.sec_service
|
||||||
|
formData = {
|
||||||
|
'action': 'security_services__delete__%s' % security_service.id,
|
||||||
|
}
|
||||||
|
self.mock_object(api_manila, "security_service_delete")
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "security_service_list",
|
||||||
|
mock.Mock(return_value=[test_data.sec_service]))
|
||||||
|
|
||||||
|
res = self.client.post(INDEX_URL, formData)
|
||||||
|
|
||||||
|
api_keystone.tenant_list.assert_called_once_with(mock.ANY)
|
||||||
|
api_manila.security_service_delete.assert_called_once_with(
|
||||||
|
mock.ANY, test_data.sec_service.id)
|
||||||
|
api_manila.security_service_list.assert_called_once_with(
|
||||||
|
mock.ANY, search_opts={'all_tenants': True})
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
127
manila_ui/tests/dashboards/admin/share_instances/tests.py
Normal file
127
manila_ui/tests/dashboards/admin/share_instances/tests.py
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
# Copyright (c) 2014 NetApp, Inc.
|
||||||
|
# Copyright (c) 2015 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 django.core.urlresolvers import reverse
|
||||||
|
from horizon import exceptions as horizon_exceptions
|
||||||
|
import mock
|
||||||
|
from openstack_dashboard.api import keystone as api_keystone
|
||||||
|
|
||||||
|
from manila_ui.api import manila as api_manila
|
||||||
|
from manila_ui.tests.dashboards.project.shares import test_data
|
||||||
|
from manila_ui.tests import helpers as test
|
||||||
|
|
||||||
|
INDEX_URL = reverse('horizon:admin:share_instances:index')
|
||||||
|
|
||||||
|
|
||||||
|
class ShareInstanceTests(test.BaseAdminViewTests):
|
||||||
|
|
||||||
|
def test_list_share_instances(self):
|
||||||
|
share_instances = [
|
||||||
|
test_data.share_instance,
|
||||||
|
test_data.share_instance_no_ss,
|
||||||
|
]
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_instance_list",
|
||||||
|
mock.Mock(return_value=share_instances))
|
||||||
|
self.mock_object(
|
||||||
|
api_keystone, "tenant_list", mock.Mock(return_value=([], None)))
|
||||||
|
|
||||||
|
res = self.client.get(INDEX_URL)
|
||||||
|
|
||||||
|
self.assertContains(res, "<h1>Share Instances</h1>")
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
'<a href="/admin/share_servers/%s" >%s</a>' % (
|
||||||
|
share_instances[0].share_server_id,
|
||||||
|
share_instances[0].share_server_id),
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
'<a href="/admin/share_networks/%s" >%s</a>' % (
|
||||||
|
share_instances[0].share_network_id,
|
||||||
|
share_instances[0].share_network_id),
|
||||||
|
1, 200)
|
||||||
|
for si in share_instances:
|
||||||
|
self.assertContains(
|
||||||
|
res, '<a href="/admin/share_instances/%s" >%s</a>' % (
|
||||||
|
si.id, si.id))
|
||||||
|
self.assertContains(res, si.host)
|
||||||
|
self.assertContains(res, si.availability_zone)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
'<a href="/admin/shares/%s/" >%s</a>' % (
|
||||||
|
si.share_id, si.share_id),
|
||||||
|
1, 200)
|
||||||
|
api_manila.share_instance_list.assert_called_once_with(mock.ANY)
|
||||||
|
self.assertEqual(0, api_keystone.tenant_list.call_count)
|
||||||
|
|
||||||
|
def test_detail_view_share_instance(self):
|
||||||
|
share_instance = test_data.share_instance
|
||||||
|
share_id = share_instance.share_id
|
||||||
|
ss_id = share_instance.share_server_id
|
||||||
|
url = reverse('horizon:admin:share_instances:share_instance_detail',
|
||||||
|
args=[share_instance.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_instance_get",
|
||||||
|
mock.Mock(return_value=share_instance))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_instance_export_location_list",
|
||||||
|
mock.Mock(return_value=test_data.export_locations))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertContains(
|
||||||
|
res, "<h1>Share Instance Details: %s</h1>" % share_instance.id,
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % share_instance.id, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>Available</dd>", 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % share_instance.host, 1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res, "<dd>%s</dd>" % share_instance.availability_zone, 1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
"<dd><a href=\"/admin/shares/%s/\">%s</a></dd>" % (
|
||||||
|
share_id, share_id),
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
"<dd><a href=\"/admin/share_networks/%s\">%s</a></dd>" % (
|
||||||
|
share_instance.share_network_id,
|
||||||
|
share_instance.share_network_id),
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
"<dd><a href=\"/admin/share_servers/%s\">%s</a></dd>" % (
|
||||||
|
ss_id, ss_id),
|
||||||
|
1, 200)
|
||||||
|
self.assertNoMessages()
|
||||||
|
api_manila.share_instance_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_instance.id)
|
||||||
|
api_manila.share_instance_export_location_list.assert_called_once_with(
|
||||||
|
mock.ANY, share_instance.id)
|
||||||
|
|
||||||
|
def test_detail_view_share_instance_with_exception(self):
|
||||||
|
share_instance = test_data.share_instance
|
||||||
|
url = reverse('horizon:admin:share_instances:share_instance_detail',
|
||||||
|
args=[share_instance.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_instance_get",
|
||||||
|
mock.Mock(side_effect=horizon_exceptions.NotFound(404)))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
api_manila.share_instance_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_instance.id)
|
166
manila_ui/tests/dashboards/admin/share_networks/tests.py
Normal file
166
manila_ui/tests/dashboards/admin/share_networks/tests.py
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
# Copyright (c) 2014 NetApp, Inc.
|
||||||
|
# Copyright (c) 2015 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 django.core.urlresolvers import reverse
|
||||||
|
from horizon import exceptions as horizon_exceptions
|
||||||
|
import mock
|
||||||
|
from neutronclient.client import exceptions
|
||||||
|
from openstack_dashboard.api import keystone as api_keystone
|
||||||
|
from openstack_dashboard.api import neutron as api_neutron
|
||||||
|
|
||||||
|
from manila_ui.api import manila as api_manila
|
||||||
|
from manila_ui.dashboards.admin import utils
|
||||||
|
from manila_ui.tests.dashboards.project.shares import test_data
|
||||||
|
from manila_ui.tests import helpers as test
|
||||||
|
from manila_ui.tests.test_data import keystone_data
|
||||||
|
|
||||||
|
INDEX_URL = reverse('horizon:admin:share_networks:index')
|
||||||
|
|
||||||
|
|
||||||
|
class ShareNetworksTests(test.BaseAdminViewTests):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(self.__class__, self).setUp()
|
||||||
|
self.mock_object(
|
||||||
|
api_keystone, "tenant_list",
|
||||||
|
mock.Mock(return_value=(keystone_data.projects, None)))
|
||||||
|
# Reset taken list of projects to avoid test interference
|
||||||
|
utils.PROJECTS = {}
|
||||||
|
|
||||||
|
def test_detail_view(self):
|
||||||
|
share_net = test_data.active_share_network
|
||||||
|
sec_service = test_data.sec_service
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_server_list", mock.Mock(return_value=[]))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_network_get", mock.Mock(return_value=share_net))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_network_security_service_list",
|
||||||
|
mock.Mock(return_value=[sec_service]))
|
||||||
|
network = self.networks.first()
|
||||||
|
subnet = self.subnets.first()
|
||||||
|
self.mock_object(
|
||||||
|
api_neutron, "network_get", mock.Mock(return_value=network))
|
||||||
|
self.mock_object(
|
||||||
|
api_neutron, "subnet_get", mock.Mock(return_value=subnet))
|
||||||
|
url = reverse('horizon:admin:share_networks:share_network_detail',
|
||||||
|
args=[share_net.id])
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertContains(res, "<h1>Share Network Details: %s</h1>"
|
||||||
|
% share_net.name,
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % share_net.name, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % share_net.id, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % network.name_or_id, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % subnet.name_or_id, 1, 200)
|
||||||
|
self.assertContains(res, "<a href=\"/admin/security_services"
|
||||||
|
"/%s\">%s</a>" % (sec_service.id,
|
||||||
|
sec_service.name), 1, 200)
|
||||||
|
self.assertNoMessages()
|
||||||
|
api_manila.share_network_security_service_list.assert_called_once_with(
|
||||||
|
mock.ANY, share_net.id)
|
||||||
|
api_manila.share_server_list.assert_called_once_with(
|
||||||
|
mock.ANY, search_opts={'share_network_id': share_net.id})
|
||||||
|
api_manila.share_network_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_net.id)
|
||||||
|
api_neutron.network_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_net.neutron_net_id)
|
||||||
|
api_neutron.subnet_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_net.neutron_subnet_id)
|
||||||
|
|
||||||
|
def test_detail_view_network_not_found(self):
|
||||||
|
share_net = test_data.active_share_network
|
||||||
|
sec_service = test_data.sec_service
|
||||||
|
url = reverse('horizon:admin:share_networks:share_network_detail',
|
||||||
|
args=[share_net.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_server_list", mock.Mock(return_value=[]))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_network_get", mock.Mock(return_value=share_net))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_network_security_service_list",
|
||||||
|
mock.Mock(return_value=[sec_service]))
|
||||||
|
self.mock_object(
|
||||||
|
api_neutron, "network_get", mock.Mock(
|
||||||
|
side_effect=exceptions.NeutronClientException('fake', 500)))
|
||||||
|
self.mock_object(
|
||||||
|
api_neutron, "subnet_get", mock.Mock(
|
||||||
|
side_effect=exceptions.NeutronClientException('fake', 500)))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertContains(res, "<h1>Share Network Details: %s</h1>"
|
||||||
|
% share_net.name,
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % share_net.name, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % share_net.id, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>Unknown</dd>", 2, 200)
|
||||||
|
self.assertNotContains(res, "<dd>%s</dd>" % share_net.neutron_net_id)
|
||||||
|
self.assertNotContains(res,
|
||||||
|
"<dd>%s</dd>" % share_net.neutron_subnet_id)
|
||||||
|
self.assertContains(res, "<a href=\"/admin/security_services"
|
||||||
|
"/%s\">%s</a>" % (sec_service.id,
|
||||||
|
sec_service.name), 1, 200)
|
||||||
|
self.assertNoMessages()
|
||||||
|
api_manila.share_network_security_service_list.assert_called_once_with(
|
||||||
|
mock.ANY, share_net.id)
|
||||||
|
api_manila.share_server_list.assert_called_once_with(
|
||||||
|
mock.ANY, search_opts={'share_network_id': share_net.id})
|
||||||
|
api_manila.share_network_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_net.id)
|
||||||
|
api_neutron.network_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_net.neutron_net_id)
|
||||||
|
api_neutron.subnet_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_net.neutron_subnet_id)
|
||||||
|
|
||||||
|
def test_detail_view_with_exception(self):
|
||||||
|
url = reverse('horizon:admin:share_networks:share_network_detail',
|
||||||
|
args=[test_data.active_share_network.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_network_get",
|
||||||
|
mock.Mock(side_effect=horizon_exceptions.NotFound(404)))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
api_manila.share_network_get.assert_called_once_with(
|
||||||
|
mock.ANY, test_data.active_share_network.id)
|
||||||
|
|
||||||
|
def test_delete_share_network(self):
|
||||||
|
share_network = test_data.inactive_share_network
|
||||||
|
formData = {'action': 'share_networks__delete__%s' % share_network.id}
|
||||||
|
self.mock_object(
|
||||||
|
api_neutron, "network_list", mock.Mock(return_value=[]))
|
||||||
|
self.mock_object(
|
||||||
|
api_neutron, "subnet_list", mock.Mock(return_value=[]))
|
||||||
|
self.mock_object(api_manila, "share_network_delete")
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_network_list",
|
||||||
|
mock.Mock(return_value=[
|
||||||
|
test_data.active_share_network,
|
||||||
|
test_data.inactive_share_network]))
|
||||||
|
|
||||||
|
res = self.client.post(INDEX_URL, formData)
|
||||||
|
|
||||||
|
api_keystone.tenant_list.assert_called_once_with(mock.ANY)
|
||||||
|
api_manila.share_network_delete.assert_called_once_with(
|
||||||
|
mock.ANY, test_data.inactive_share_network.id)
|
||||||
|
api_manila.share_network_list.assert_called_once_with(
|
||||||
|
mock.ANY, detailed=True, search_opts={'all_tenants': True})
|
||||||
|
api_neutron.network_list.assert_called_once_with(mock.ANY)
|
||||||
|
api_neutron.subnet_list.assert_called_once_with(mock.ANY)
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
135
manila_ui/tests/dashboards/admin/share_servers/tests.py
Normal file
135
manila_ui/tests/dashboards/admin/share_servers/tests.py
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
# Copyright (c) 2014 NetApp, Inc.
|
||||||
|
# Copyright (c) 2015 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 django.core.urlresolvers import reverse
|
||||||
|
from horizon import exceptions as horizon_exceptions
|
||||||
|
import mock
|
||||||
|
from openstack_dashboard.api import keystone as api_keystone
|
||||||
|
|
||||||
|
from manila_ui.api import manila as api_manila
|
||||||
|
from manila_ui.tests.dashboards.project.shares import test_data
|
||||||
|
from manila_ui.tests import helpers as test
|
||||||
|
|
||||||
|
INDEX_URL = reverse('horizon:admin:share_servers:index')
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerTests(test.BaseAdminViewTests):
|
||||||
|
|
||||||
|
def test_list_share_servers(self):
|
||||||
|
share_servers = [
|
||||||
|
test_data.share_server,
|
||||||
|
test_data.share_server_errored,
|
||||||
|
]
|
||||||
|
projects = [
|
||||||
|
type('FakeProject', (object, ),
|
||||||
|
{'id': s.project_id, 'name': '%s_name' % s.project_id})
|
||||||
|
for s in share_servers
|
||||||
|
]
|
||||||
|
projects_dict = {p.id: p for p in projects}
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_server_list",
|
||||||
|
mock.Mock(return_value=share_servers))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_list",
|
||||||
|
mock.Mock(side_effect=[
|
||||||
|
[], [test_data.share], [test_data.nameless_share]]))
|
||||||
|
self.mock_object(
|
||||||
|
api_keystone, "tenant_list",
|
||||||
|
mock.Mock(return_value=(projects, None)))
|
||||||
|
|
||||||
|
res = self.client.get(INDEX_URL)
|
||||||
|
|
||||||
|
self.assertContains(res, "<h1>Share Servers</h1>")
|
||||||
|
for share_server in share_servers:
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
'<a href="/admin/share_servers/%s" >%s</a>' % (
|
||||||
|
share_server.id, share_server.id),
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(res, share_server.host, 1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res, projects_dict[share_server.project_id].name, 1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
'<a href="/admin/share_networks/%s" >%s</a>' % (
|
||||||
|
share_server.share_network_id,
|
||||||
|
share_server.share_network),
|
||||||
|
1, 200)
|
||||||
|
api_manila.share_list.assert_has_calls([
|
||||||
|
mock.call(
|
||||||
|
mock.ANY, search_opts={'share_server_id': share_server.id})
|
||||||
|
for share_server in share_servers
|
||||||
|
])
|
||||||
|
api_manila.share_server_list.assert_called_once_with(mock.ANY)
|
||||||
|
self.assertEqual(1, api_keystone.tenant_list.call_count)
|
||||||
|
|
||||||
|
def test_detail_view_share_server(self):
|
||||||
|
share_server = test_data.share_server
|
||||||
|
shares = [test_data.share, test_data.nameless_share]
|
||||||
|
url = reverse(
|
||||||
|
'horizon:admin:share_servers:share_server_detail',
|
||||||
|
args=[share_server.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_server_get",
|
||||||
|
mock.Mock(return_value=share_server))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_list", mock.Mock(return_value=shares))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertContains(
|
||||||
|
res, "<h1>Share Server Details: %s</h1>" % share_server.id,
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % share_server.id, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>Active</dd>", 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % share_server.host, 1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
"<dd><a href=\"/admin/share_networks/%s\">%s</a></dd>" % (
|
||||||
|
share_server.share_network_id,
|
||||||
|
share_server.share_network_name),
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
"<dd><a href=\"/admin/shares/%s/\">%s</a></dd>" % (
|
||||||
|
shares[0].id, shares[0].name),
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res,
|
||||||
|
"<dd><a href=\"/admin/shares/%s/\">%s</a></dd>" % (
|
||||||
|
shares[1].id, shares[1].id),
|
||||||
|
1, 200)
|
||||||
|
for k, v in share_server.backend_details.items():
|
||||||
|
self.assertContains(res, "<dt>%s</dt>" % k)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % v)
|
||||||
|
self.assertNoMessages()
|
||||||
|
api_manila.share_server_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_server.id)
|
||||||
|
api_manila.share_list.assert_called_once_with(
|
||||||
|
mock.ANY, search_opts={"share_server_id": share_server.id})
|
||||||
|
|
||||||
|
def test_detail_view_share_server_with_exception(self):
|
||||||
|
share_server = test_data.share_server
|
||||||
|
url = reverse('horizon:admin:share_servers:share_server_detail',
|
||||||
|
args=[share_server.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_server_get",
|
||||||
|
mock.Mock(side_effect=horizon_exceptions.NotFound(404)))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
api_manila.share_server_get.assert_called_once_with(
|
||||||
|
mock.ANY, share_server.id)
|
151
manila_ui/tests/dashboards/admin/share_snapshots/tests.py
Normal file
151
manila_ui/tests/dashboards/admin/share_snapshots/tests.py
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
# Copyright (c) 2014 NetApp, Inc.
|
||||||
|
# Copyright (c) 2015 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 django.core.urlresolvers import reverse
|
||||||
|
from horizon import exceptions as horizon_exceptions
|
||||||
|
import mock
|
||||||
|
from openstack_dashboard.api import keystone as api_keystone
|
||||||
|
|
||||||
|
from manila_ui.api import manila as api_manila
|
||||||
|
from manila_ui.dashboards.admin import utils
|
||||||
|
from manila_ui.tests.dashboards.project.shares import test_data
|
||||||
|
from manila_ui.tests import helpers as test
|
||||||
|
from manila_ui.tests.test_data import keystone_data
|
||||||
|
|
||||||
|
INDEX_URL = reverse('horizon:admin:share_snapshots:index')
|
||||||
|
|
||||||
|
|
||||||
|
class SnapshotsTests(test.BaseAdminViewTests):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(self.__class__, self).setUp()
|
||||||
|
self.mock_object(
|
||||||
|
api_keystone, "tenant_list",
|
||||||
|
mock.Mock(return_value=(keystone_data.projects, None)))
|
||||||
|
# Reset taken list of projects to avoid test interference
|
||||||
|
utils.PROJECTS = {}
|
||||||
|
|
||||||
|
def test_detail_view(self):
|
||||||
|
snapshot = test_data.snapshot
|
||||||
|
share = test_data.share
|
||||||
|
url = reverse('horizon:admin:share_snapshots:share_snapshot_detail',
|
||||||
|
args=[snapshot.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_snapshot_get", mock.Mock(return_value=snapshot))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_get", mock.Mock(return_value=share))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertContains(res, "<h1>Snapshot Details: %s</h1>"
|
||||||
|
% snapshot.name,
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % snapshot.name, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % snapshot.id, 1, 200)
|
||||||
|
self.assertContains(res,
|
||||||
|
"<dd><a href=\"/admin/shares/%s/\">%s</a></dd>" %
|
||||||
|
(snapshot.share_id, share.name), 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s GiB</dd>" % snapshot.size, 1, 200)
|
||||||
|
self.assertNoMessages()
|
||||||
|
api_manila.share_get.assert_called_once_with(mock.ANY, share.id)
|
||||||
|
api_manila.share_snapshot_get.assert_called_once_with(
|
||||||
|
mock.ANY, snapshot.id)
|
||||||
|
|
||||||
|
def test_detail_view_with_mount_support(self):
|
||||||
|
snapshot = test_data.snapshot_mount_support
|
||||||
|
rules = [test_data.ip_rule, test_data.user_rule, test_data.cephx_rule]
|
||||||
|
export_locations = test_data.admin_snapshot_export_locations
|
||||||
|
share = test_data.share_mount_snapshot
|
||||||
|
url = reverse('horizon:admin:share_snapshots:share_snapshot_detail',
|
||||||
|
args=[snapshot.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_snapshot_get", mock.Mock(return_value=snapshot))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_snapshot_rules_list", mock.Mock(
|
||||||
|
return_value=rules))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_snap_export_location_list", mock.Mock(
|
||||||
|
return_value=export_locations))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_get", mock.Mock(return_value=share))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertContains(res, "<h1>Snapshot Details: %s</h1>"
|
||||||
|
% snapshot.name,
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % snapshot.name, 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s</dd>" % snapshot.id, 1, 200)
|
||||||
|
self.assertContains(res,
|
||||||
|
"<dd><a href=\"/admin/shares/%s/\">%s</a></dd>" %
|
||||||
|
(snapshot.share_id, share.name), 1, 200)
|
||||||
|
self.assertContains(res, "<dd>%s GiB</dd>" % snapshot.size, 1, 200)
|
||||||
|
for el in export_locations:
|
||||||
|
self.assertContains(res, "value=\"%s\"" % el.path, 1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res, "<div><b>Is admin only:</b> %s</div>" % el.is_admin_only,
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res, ("<div><b>Snapshot Replica ID:</b> %s</div>" %
|
||||||
|
el.share_snapshot_instance_id), 1, 200)
|
||||||
|
for rule in rules:
|
||||||
|
self.assertContains(res, "<dt>%s</dt>" % rule.access_type, 1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res, "<div><b>Access to: </b>%s</div>" % rule.access_to,
|
||||||
|
1, 200)
|
||||||
|
self.assertContains(
|
||||||
|
res, "<div><b>Status: </b>active</div>", len(rules), 200)
|
||||||
|
self.assertNoMessages()
|
||||||
|
api_manila.share_get.assert_called_once_with(mock.ANY, share.id)
|
||||||
|
api_manila.share_snapshot_get.assert_called_once_with(
|
||||||
|
mock.ANY, snapshot.id)
|
||||||
|
api_manila.share_snapshot_rules_list.assert_called_once_with(
|
||||||
|
mock.ANY, snapshot.id)
|
||||||
|
api_manila.share_snap_export_location_list.assert_called_once_with(
|
||||||
|
mock.ANY, snapshot)
|
||||||
|
|
||||||
|
def test_detail_view_with_exception(self):
|
||||||
|
url = reverse('horizon:admin:share_snapshots:share_snapshot_detail',
|
||||||
|
args=[test_data.snapshot.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_snapshot_get",
|
||||||
|
mock.Mock(side_effect=horizon_exceptions.NotFound(404)))
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
api_manila.share_snapshot_get.assert_called_once_with(
|
||||||
|
mock.ANY, test_data.snapshot.id)
|
||||||
|
|
||||||
|
def test_delete_snapshot(self):
|
||||||
|
share = test_data.share
|
||||||
|
snapshot = test_data.snapshot
|
||||||
|
formData = {'action': 'share_snapshots__delete__%s' % snapshot.id}
|
||||||
|
self.mock_object(api_manila, "share_snapshot_delete")
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_snapshot_list",
|
||||||
|
mock.Mock(return_value=[snapshot]))
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_list", mock.Mock(return_value=[share]))
|
||||||
|
|
||||||
|
res = self.client.post(INDEX_URL, formData)
|
||||||
|
|
||||||
|
api_keystone.tenant_list.assert_called_once_with(mock.ANY)
|
||||||
|
api_manila.share_snapshot_delete.assert_called_once_with(
|
||||||
|
mock.ANY, test_data.snapshot.id)
|
||||||
|
api_manila.share_snapshot_list.assert_called_once_with(
|
||||||
|
mock.ANY, search_opts={'all_tenants': True})
|
||||||
|
api_manila.share_list.assert_called_once_with(mock.ANY)
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
254
manila_ui/tests/dashboards/admin/share_types/test_forms.py
Normal file
254
manila_ui/tests/dashboards/admin/share_types/test_forms.py
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
# Copyright (c) 2015 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.handlers import wsgi
|
||||||
|
from django import forms as django_forms
|
||||||
|
from horizon import forms as horizon_forms
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from manila_ui.dashboards.admin.share_types import forms
|
||||||
|
from manila_ui.tests import helpers as base
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class ManilaDashboardsAdminSharesUpdateShareTypeFormTests(base.APITestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(self.__class__, self).setUp()
|
||||||
|
FAKE_ENVIRON = {'REQUEST_METHOD': 'GET', 'wsgi.input': 'fake_input'}
|
||||||
|
self.request = wsgi.WSGIRequest(FAKE_ENVIRON)
|
||||||
|
|
||||||
|
def _get_form(self, initial):
|
||||||
|
kwargs = {
|
||||||
|
'prefix': None,
|
||||||
|
'initial': initial,
|
||||||
|
}
|
||||||
|
return forms.UpdateShareType(self.request, **kwargs)
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
({}, []),
|
||||||
|
({'foo': 'bar', 'quuz': 'zaab'}, ["foo=bar\r\n", "quuz=zaab\r\n"]),
|
||||||
|
)
|
||||||
|
@ddt.unpack
|
||||||
|
def test___init__(self, extra_specs_dict_input, extra_specs_str_output):
|
||||||
|
form = self._get_form({'extra_specs': extra_specs_dict_input})
|
||||||
|
|
||||||
|
for expected_extra_spec in extra_specs_str_output:
|
||||||
|
self.assertIn(expected_extra_spec, form.initial['extra_specs'])
|
||||||
|
self.assertIn('extra_specs', list(form.fields.keys()))
|
||||||
|
self.assertTrue(
|
||||||
|
isinstance(form.fields['extra_specs'], horizon_forms.CharField))
|
||||||
|
|
||||||
|
@mock.patch('horizon.messages.success')
|
||||||
|
def test_handle_success_no_changes(self, mock_horizon_messages_success):
|
||||||
|
initial = {'id': 'fake_id', 'name': 'fake_name', 'extra_specs': {}}
|
||||||
|
form = self._get_form(initial)
|
||||||
|
data = {'extra_specs': ''}
|
||||||
|
|
||||||
|
result = form.handle(self.request, data)
|
||||||
|
|
||||||
|
self.assertTrue(result)
|
||||||
|
mock_horizon_messages_success.assert_called_once_with(
|
||||||
|
mock.ANY, mock.ANY)
|
||||||
|
|
||||||
|
@mock.patch('horizon.messages.success')
|
||||||
|
def test_handle_success_only_set(self, mock_horizon_messages_success):
|
||||||
|
initial = {
|
||||||
|
'id': 'fake_id',
|
||||||
|
'name': 'fake_name',
|
||||||
|
'extra_specs': {'foo': 'bar'}
|
||||||
|
}
|
||||||
|
form = self._get_form(initial)
|
||||||
|
data = {'extra_specs': 'foo=bar\r\n'}
|
||||||
|
|
||||||
|
result = form.handle(self.request, data)
|
||||||
|
|
||||||
|
self.assertTrue(result)
|
||||||
|
mock_horizon_messages_success.assert_called_once_with(
|
||||||
|
mock.ANY, mock.ANY)
|
||||||
|
self.manilaclient.share_types.get.assert_called_once_with(
|
||||||
|
initial['id'])
|
||||||
|
self.manilaclient.share_types.get.return_value.set_keys.\
|
||||||
|
assert_called_once_with({'foo': 'bar'})
|
||||||
|
self.assertFalse(
|
||||||
|
self.manilaclient.share_types.get.return_value.unset_keys.called)
|
||||||
|
|
||||||
|
@mock.patch('horizon.messages.success')
|
||||||
|
def test_handle_success_only_unset(self, mock_horizon_messages_success):
|
||||||
|
initial = {
|
||||||
|
'id': 'fake_id',
|
||||||
|
'name': 'fake_name',
|
||||||
|
'extra_specs': {'foo': 'bar'}
|
||||||
|
}
|
||||||
|
form = self._get_form(initial)
|
||||||
|
data = {'extra_specs': 'foo\r\n'}
|
||||||
|
share_types_get = self.manilaclient.share_types.get
|
||||||
|
share_types_get.return_value.get_keys.return_value = {
|
||||||
|
'foo': 'bar', 'quuz': 'zaab'}
|
||||||
|
|
||||||
|
result = form.handle(self.request, data)
|
||||||
|
|
||||||
|
self.assertTrue(result)
|
||||||
|
mock_horizon_messages_success.assert_called_once_with(
|
||||||
|
mock.ANY, mock.ANY)
|
||||||
|
self.manilaclient.share_types.get.assert_has_calls([
|
||||||
|
mock.call(initial['id'])])
|
||||||
|
share_types_get.return_value.get_keys.assert_called_once_with()
|
||||||
|
self.assertFalse(share_types_get.return_value.set_keys.called)
|
||||||
|
share_types_get.return_value.unset_keys.assert_called_once_with(
|
||||||
|
{'foo'})
|
||||||
|
|
||||||
|
@mock.patch('horizon.messages.success')
|
||||||
|
def test_handle_success_set_and_unset(self, mock_horizon_messages_success):
|
||||||
|
initial = {
|
||||||
|
'id': 'fake_id',
|
||||||
|
'name': 'fake_name',
|
||||||
|
'extra_specs': {'foo': 'bar'}
|
||||||
|
}
|
||||||
|
form = self._get_form(initial)
|
||||||
|
data = {'extra_specs': 'foo\r\nquuz=zaab'}
|
||||||
|
share_types_get = self.manilaclient.share_types.get
|
||||||
|
share_types_get.return_value.get_keys.return_value = {'foo': 'bar'}
|
||||||
|
|
||||||
|
result = form.handle(self.request, data)
|
||||||
|
|
||||||
|
self.assertTrue(result)
|
||||||
|
mock_horizon_messages_success.assert_called_once_with(
|
||||||
|
mock.ANY, mock.ANY)
|
||||||
|
self.manilaclient.share_types.get.assert_has_calls([
|
||||||
|
mock.call(initial['id'])])
|
||||||
|
share_types_get.return_value.get_keys.assert_called_once_with()
|
||||||
|
share_types_get.return_value.set_keys.assert_called_once_with(
|
||||||
|
{'quuz': 'zaab'})
|
||||||
|
share_types_get.return_value.unset_keys.assert_called_once_with(
|
||||||
|
{'foo'})
|
||||||
|
|
||||||
|
def test_handle_validation_error(self):
|
||||||
|
initial = {'id': 'fake_id', 'name': 'fake_name', 'extra_specs': {}}
|
||||||
|
form = self._get_form(initial)
|
||||||
|
form.api_error = mock.Mock()
|
||||||
|
data = {'extra_specs': 'a b'}
|
||||||
|
|
||||||
|
result = form.handle(self.request, data)
|
||||||
|
|
||||||
|
self.assertFalse(result)
|
||||||
|
form.api_error.assert_called_once_with(mock.ANY)
|
||||||
|
|
||||||
|
@mock.patch('horizon.exceptions.handle')
|
||||||
|
def test_handle_other_exception(self, mock_horizon_exceptions_handle):
|
||||||
|
django_forms.ValidationError
|
||||||
|
initial = {'id': 'fake_id', 'name': 'fake_name', 'extra_specs': {}}
|
||||||
|
form = self._get_form(initial)
|
||||||
|
data = {'extra_specs': None}
|
||||||
|
|
||||||
|
result = form.handle(self.request, data)
|
||||||
|
|
||||||
|
self.assertFalse(result)
|
||||||
|
mock_horizon_exceptions_handle.assert_called_once_with(
|
||||||
|
self.request, mock.ANY)
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class ManilaDashboardsAdminSharesCreateShareTypeFormTests(base.APITestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(self.__class__, self).setUp()
|
||||||
|
FAKE_ENVIRON = {'REQUEST_METHOD': 'GET', 'wsgi.input': 'fake_input'}
|
||||||
|
self.request = wsgi.WSGIRequest(FAKE_ENVIRON)
|
||||||
|
|
||||||
|
def _get_form(self, **kwargs):
|
||||||
|
return forms.CreateShareType(self.request, **kwargs)
|
||||||
|
|
||||||
|
@mock.patch('horizon.messages.success')
|
||||||
|
def test_create_share_type(self, mock_horizon_messages_success):
|
||||||
|
form = self._get_form()
|
||||||
|
data = {
|
||||||
|
'extra_specs': '',
|
||||||
|
'is_public': False,
|
||||||
|
'spec_driver_handles_share_servers': 'True',
|
||||||
|
'name': 'share',
|
||||||
|
}
|
||||||
|
|
||||||
|
result = form.handle(self.request, data)
|
||||||
|
|
||||||
|
self.assertTrue(result)
|
||||||
|
self.manilaclient.share_types.create.assert_called_once_with(
|
||||||
|
name=data['name'],
|
||||||
|
spec_driver_handles_share_servers='true',
|
||||||
|
spec_snapshot_support=True,
|
||||||
|
is_public=data["is_public"])
|
||||||
|
mock_horizon_messages_success.assert_called_once_with(
|
||||||
|
self.request, mock.ANY)
|
||||||
|
|
||||||
|
@mock.patch('horizon.messages.success')
|
||||||
|
def test_create_share_type_with_extra_specs(self,
|
||||||
|
mock_horizon_messages_success):
|
||||||
|
form = self._get_form()
|
||||||
|
data = {'extra_specs': 'a=b \n c=d',
|
||||||
|
'is_public': False,
|
||||||
|
'spec_driver_handles_share_servers': 'True',
|
||||||
|
'name': 'share'}
|
||||||
|
|
||||||
|
result = form.handle(self.request, data)
|
||||||
|
|
||||||
|
self.assertTrue(result)
|
||||||
|
|
||||||
|
set_keys = self.manilaclient.share_types.get.return_value.set_keys
|
||||||
|
set_keys.assert_called_once_with(
|
||||||
|
{'a': 'b', 'c': 'd'})
|
||||||
|
self.manilaclient.share_types.create.assert_called_once_with(
|
||||||
|
name=data['name'],
|
||||||
|
spec_driver_handles_share_servers='true',
|
||||||
|
spec_snapshot_support=True,
|
||||||
|
is_public=data["is_public"])
|
||||||
|
mock_horizon_messages_success.assert_called_once_with(
|
||||||
|
self.request, mock.ANY)
|
||||||
|
|
||||||
|
@ddt.data(True, False)
|
||||||
|
@mock.patch('horizon.messages.success')
|
||||||
|
def test_public_share_type_creation(self,
|
||||||
|
enable_public_share_type_creation,
|
||||||
|
mock_horizon_messages_success):
|
||||||
|
with self.settings(OPENSTACK_MANILA_FEATURES={
|
||||||
|
'enable_public_share_type_creation':
|
||||||
|
enable_public_share_type_creation}):
|
||||||
|
form = self._get_form()
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'extra_specs': '',
|
||||||
|
'is_public': enable_public_share_type_creation,
|
||||||
|
'spec_driver_handles_share_servers': 'True',
|
||||||
|
'name': 'share',
|
||||||
|
}
|
||||||
|
|
||||||
|
result = form.handle(self.request, data)
|
||||||
|
|
||||||
|
self.assertTrue(result)
|
||||||
|
self.assertEqual(
|
||||||
|
enable_public_share_type_creation,
|
||||||
|
form.enable_public_share_type_creation)
|
||||||
|
if enable_public_share_type_creation:
|
||||||
|
self.assertIn("is_public", form.fields)
|
||||||
|
self.assertTrue(form.fields["is_public"])
|
||||||
|
else:
|
||||||
|
self.assertNotIn("is_public", form.fields)
|
||||||
|
self.manilaclient.share_types.create.assert_called_once_with(
|
||||||
|
name=data['name'],
|
||||||
|
spec_driver_handles_share_servers='true',
|
||||||
|
spec_snapshot_support=True,
|
||||||
|
is_public=enable_public_share_type_creation)
|
||||||
|
mock_horizon_messages_success.assert_called_once_with(
|
||||||
|
self.request, mock.ANY)
|
88
manila_ui/tests/dashboards/admin/share_types/tests.py
Normal file
88
manila_ui/tests/dashboards/admin/share_types/tests.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# Copyright (c) 2014 NetApp, Inc.
|
||||||
|
# Copyright (c) 2015 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 django.core.urlresolvers import reverse
|
||||||
|
import mock
|
||||||
|
from openstack_dashboard.api import keystone as api_keystone
|
||||||
|
from openstack_dashboard.api import neutron as api_neutron
|
||||||
|
|
||||||
|
from manila_ui.api import manila as api_manila
|
||||||
|
from manila_ui.dashboards.admin import utils
|
||||||
|
from manila_ui.tests.dashboards.project.shares import test_data
|
||||||
|
from manila_ui.tests import helpers as test
|
||||||
|
from manila_ui.tests.test_data import keystone_data
|
||||||
|
|
||||||
|
INDEX_URL = reverse('horizon:admin:share_types:index')
|
||||||
|
|
||||||
|
|
||||||
|
class ShareTypeTests(test.BaseAdminViewTests):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(self.__class__, self).setUp()
|
||||||
|
self.share_type = test_data.share_type
|
||||||
|
self.url = reverse('horizon:admin:share_types:update_type',
|
||||||
|
args=[self.share_type.id])
|
||||||
|
self.mock_object(
|
||||||
|
api_manila, "share_type_get",
|
||||||
|
mock.Mock(return_value=self.share_type))
|
||||||
|
self.mock_object(
|
||||||
|
api_keystone, "tenant_list",
|
||||||
|
mock.Mock(return_value=(keystone_data.projects, None)))
|
||||||
|
self.mock_object(
|
||||||
|
api_neutron, "is_service_enabled", mock.Mock(return_value=[True]))
|
||||||
|
# Reset taken list of projects to avoid test interference
|
||||||
|
utils.PROJECTS = {}
|
||||||
|
|
||||||
|
def test_create_share_type(self):
|
||||||
|
url = reverse('horizon:admin:share_types:create_type')
|
||||||
|
data = {
|
||||||
|
'is_public': True,
|
||||||
|
'name': 'my_share_type',
|
||||||
|
'spec_driver_handles_share_servers': 'False'
|
||||||
|
}
|
||||||
|
form_data = data.copy()
|
||||||
|
form_data['spec_driver_handles_share_servers'] = 'false'
|
||||||
|
self.mock_object(api_manila, "share_type_create")
|
||||||
|
|
||||||
|
res = self.client.post(url, data)
|
||||||
|
|
||||||
|
api_manila.share_type_create.assert_called_once_with(
|
||||||
|
mock.ANY, form_data['name'],
|
||||||
|
form_data['spec_driver_handles_share_servers'],
|
||||||
|
is_public=form_data['is_public'])
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
def test_update_share_type_get(self):
|
||||||
|
res = self.client.get(self.url)
|
||||||
|
|
||||||
|
api_manila.share_type_get.assert_called_once_with(
|
||||||
|
mock.ANY, self.share_type.id)
|
||||||
|
self.assertNoMessages()
|
||||||
|
self.assertTemplateUsed(res, 'admin/share_types/update.html')
|
||||||
|
|
||||||
|
def test_update_share_type_post(self):
|
||||||
|
data = {
|
||||||
|
'extra_specs': 'driver_handles_share_servers=True'
|
||||||
|
}
|
||||||
|
form_data = {
|
||||||
|
'extra_specs': {'driver_handles_share_servers': 'True'},
|
||||||
|
}
|
||||||
|
self.mock_object(api_manila, "share_type_set_extra_specs")
|
||||||
|
|
||||||
|
res = self.client.post(self.url, data)
|
||||||
|
|
||||||
|
api_manila.share_type_set_extra_specs.assert_called_once_with(
|
||||||
|
mock.ANY, self.share_type.id, form_data['extra_specs'])
|
||||||
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
@ -13,10 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import ddt
|
|
||||||
from django.core.handlers import wsgi
|
from django.core.handlers import wsgi
|
||||||
from django import forms as django_forms
|
|
||||||
from horizon import forms as horizon_forms
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from manila_ui.api import manila as api
|
from manila_ui.api import manila as api
|
||||||
@ -24,237 +21,6 @@ from manila_ui.dashboards.admin.shares import forms
|
|||||||
from manila_ui.tests import helpers as base
|
from manila_ui.tests import helpers as base
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class ManilaDashboardsAdminSharesUpdateShareTypeFormTests(base.APITestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(self.__class__, self).setUp()
|
|
||||||
FAKE_ENVIRON = {'REQUEST_METHOD': 'GET', 'wsgi.input': 'fake_input'}
|
|
||||||
self.request = wsgi.WSGIRequest(FAKE_ENVIRON)
|
|
||||||
|
|
||||||
def _get_form(self, initial):
|
|
||||||
kwargs = {
|
|
||||||
'prefix': None,
|
|
||||||
'initial': initial,
|
|
||||||
}
|
|
||||||
return forms.UpdateShareType(self.request, **kwargs)
|
|
||||||
|
|
||||||
@ddt.data(
|
|
||||||
({}, []),
|
|
||||||
({'foo': 'bar', 'quuz': 'zaab'}, ["foo=bar\r\n", "quuz=zaab\r\n"]),
|
|
||||||
)
|
|
||||||
@ddt.unpack
|
|
||||||
def test___init__(self, extra_specs_dict_input, extra_specs_str_output):
|
|
||||||
form = self._get_form({'extra_specs': extra_specs_dict_input})
|
|
||||||
|
|
||||||
for expected_extra_spec in extra_specs_str_output:
|
|
||||||
self.assertIn(expected_extra_spec, form.initial['extra_specs'])
|
|
||||||
self.assertIn('extra_specs', list(form.fields.keys()))
|
|
||||||
self.assertTrue(
|
|
||||||
isinstance(form.fields['extra_specs'], horizon_forms.CharField))
|
|
||||||
|
|
||||||
@mock.patch('horizon.messages.success')
|
|
||||||
def test_handle_success_no_changes(self, mock_horizon_messages_success):
|
|
||||||
initial = {'id': 'fake_id', 'name': 'fake_name', 'extra_specs': {}}
|
|
||||||
form = self._get_form(initial)
|
|
||||||
data = {'extra_specs': ''}
|
|
||||||
|
|
||||||
result = form.handle(self.request, data)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
mock_horizon_messages_success.assert_called_once_with(
|
|
||||||
mock.ANY, mock.ANY)
|
|
||||||
|
|
||||||
@mock.patch('horizon.messages.success')
|
|
||||||
def test_handle_success_only_set(self, mock_horizon_messages_success):
|
|
||||||
initial = {
|
|
||||||
'id': 'fake_id',
|
|
||||||
'name': 'fake_name',
|
|
||||||
'extra_specs': {'foo': 'bar'}
|
|
||||||
}
|
|
||||||
form = self._get_form(initial)
|
|
||||||
data = {'extra_specs': 'foo=bar\r\n'}
|
|
||||||
|
|
||||||
result = form.handle(self.request, data)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
mock_horizon_messages_success.assert_called_once_with(
|
|
||||||
mock.ANY, mock.ANY)
|
|
||||||
self.manilaclient.share_types.get.assert_called_once_with(
|
|
||||||
initial['id'])
|
|
||||||
self.manilaclient.share_types.get.return_value.set_keys.\
|
|
||||||
assert_called_once_with({'foo': 'bar'})
|
|
||||||
self.assertFalse(
|
|
||||||
self.manilaclient.share_types.get.return_value.unset_keys.called)
|
|
||||||
|
|
||||||
@mock.patch('horizon.messages.success')
|
|
||||||
def test_handle_success_only_unset(self, mock_horizon_messages_success):
|
|
||||||
initial = {
|
|
||||||
'id': 'fake_id',
|
|
||||||
'name': 'fake_name',
|
|
||||||
'extra_specs': {'foo': 'bar'}
|
|
||||||
}
|
|
||||||
form = self._get_form(initial)
|
|
||||||
data = {'extra_specs': 'foo\r\n'}
|
|
||||||
share_types_get = self.manilaclient.share_types.get
|
|
||||||
share_types_get.return_value.get_keys.return_value = {
|
|
||||||
'foo': 'bar', 'quuz': 'zaab'}
|
|
||||||
|
|
||||||
result = form.handle(self.request, data)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
mock_horizon_messages_success.assert_called_once_with(
|
|
||||||
mock.ANY, mock.ANY)
|
|
||||||
self.manilaclient.share_types.get.assert_has_calls([
|
|
||||||
mock.call(initial['id'])])
|
|
||||||
share_types_get.return_value.get_keys.assert_called_once_with()
|
|
||||||
self.assertFalse(share_types_get.return_value.set_keys.called)
|
|
||||||
share_types_get.return_value.unset_keys.assert_called_once_with(
|
|
||||||
{'foo'})
|
|
||||||
|
|
||||||
@mock.patch('horizon.messages.success')
|
|
||||||
def test_handle_success_set_and_unset(self, mock_horizon_messages_success):
|
|
||||||
initial = {
|
|
||||||
'id': 'fake_id',
|
|
||||||
'name': 'fake_name',
|
|
||||||
'extra_specs': {'foo': 'bar'}
|
|
||||||
}
|
|
||||||
form = self._get_form(initial)
|
|
||||||
data = {'extra_specs': 'foo\r\nquuz=zaab'}
|
|
||||||
share_types_get = self.manilaclient.share_types.get
|
|
||||||
share_types_get.return_value.get_keys.return_value = {'foo': 'bar'}
|
|
||||||
|
|
||||||
result = form.handle(self.request, data)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
mock_horizon_messages_success.assert_called_once_with(
|
|
||||||
mock.ANY, mock.ANY)
|
|
||||||
self.manilaclient.share_types.get.assert_has_calls([
|
|
||||||
mock.call(initial['id'])])
|
|
||||||
share_types_get.return_value.get_keys.assert_called_once_with()
|
|
||||||
share_types_get.return_value.set_keys.assert_called_once_with(
|
|
||||||
{'quuz': 'zaab'})
|
|
||||||
share_types_get.return_value.unset_keys.assert_called_once_with(
|
|
||||||
{'foo'})
|
|
||||||
|
|
||||||
def test_handle_validation_error(self):
|
|
||||||
initial = {'id': 'fake_id', 'name': 'fake_name', 'extra_specs': {}}
|
|
||||||
form = self._get_form(initial)
|
|
||||||
form.api_error = mock.Mock()
|
|
||||||
data = {'extra_specs': 'a b'}
|
|
||||||
|
|
||||||
result = form.handle(self.request, data)
|
|
||||||
|
|
||||||
self.assertFalse(result)
|
|
||||||
form.api_error.assert_called_once_with(mock.ANY)
|
|
||||||
|
|
||||||
@mock.patch('horizon.exceptions.handle')
|
|
||||||
def test_handle_other_exception(self, mock_horizon_exceptions_handle):
|
|
||||||
django_forms.ValidationError
|
|
||||||
initial = {'id': 'fake_id', 'name': 'fake_name', 'extra_specs': {}}
|
|
||||||
form = self._get_form(initial)
|
|
||||||
data = {'extra_specs': None}
|
|
||||||
|
|
||||||
result = form.handle(self.request, data)
|
|
||||||
|
|
||||||
self.assertFalse(result)
|
|
||||||
mock_horizon_exceptions_handle.assert_called_once_with(
|
|
||||||
self.request, mock.ANY)
|
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
|
||||||
class ManilaDashboardsAdminSharesCreateShareTypeFormTests(base.APITestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(self.__class__, self).setUp()
|
|
||||||
FAKE_ENVIRON = {'REQUEST_METHOD': 'GET', 'wsgi.input': 'fake_input'}
|
|
||||||
self.request = wsgi.WSGIRequest(FAKE_ENVIRON)
|
|
||||||
|
|
||||||
def _get_form(self, **kwargs):
|
|
||||||
return forms.CreateShareType(self.request, **kwargs)
|
|
||||||
|
|
||||||
@mock.patch('horizon.messages.success')
|
|
||||||
def test_create_share_type(self, mock_horizon_messages_success):
|
|
||||||
form = self._get_form()
|
|
||||||
data = {
|
|
||||||
'extra_specs': '',
|
|
||||||
'is_public': False,
|
|
||||||
'spec_driver_handles_share_servers': 'True',
|
|
||||||
'name': 'share',
|
|
||||||
}
|
|
||||||
|
|
||||||
result = form.handle(self.request, data)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
self.manilaclient.share_types.create.assert_called_once_with(
|
|
||||||
name=data['name'],
|
|
||||||
spec_driver_handles_share_servers='true',
|
|
||||||
spec_snapshot_support=True,
|
|
||||||
is_public=data["is_public"])
|
|
||||||
mock_horizon_messages_success.assert_called_once_with(
|
|
||||||
self.request, mock.ANY)
|
|
||||||
|
|
||||||
@mock.patch('horizon.messages.success')
|
|
||||||
def test_create_share_type_with_extra_specs(self,
|
|
||||||
mock_horizon_messages_success):
|
|
||||||
form = self._get_form()
|
|
||||||
data = {'extra_specs': 'a=b \n c=d',
|
|
||||||
'is_public': False,
|
|
||||||
'spec_driver_handles_share_servers': 'True',
|
|
||||||
'name': 'share'}
|
|
||||||
|
|
||||||
result = form.handle(self.request, data)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
|
|
||||||
set_keys = self.manilaclient.share_types.get.return_value.set_keys
|
|
||||||
set_keys.assert_called_once_with(
|
|
||||||
{'a': 'b', 'c': 'd'})
|
|
||||||
self.manilaclient.share_types.create.assert_called_once_with(
|
|
||||||
name=data['name'],
|
|
||||||
spec_driver_handles_share_servers='true',
|
|
||||||
spec_snapshot_support=True,
|
|
||||||
is_public=data["is_public"])
|
|
||||||
mock_horizon_messages_success.assert_called_once_with(
|
|
||||||
self.request, mock.ANY)
|
|
||||||
|
|
||||||
@ddt.data(True, False)
|
|
||||||
@mock.patch('horizon.messages.success')
|
|
||||||
def test_public_share_type_creation(self,
|
|
||||||
enable_public_share_type_creation,
|
|
||||||
mock_horizon_messages_success):
|
|
||||||
with self.settings(OPENSTACK_MANILA_FEATURES={
|
|
||||||
'enable_public_share_type_creation':
|
|
||||||
enable_public_share_type_creation}):
|
|
||||||
form = self._get_form()
|
|
||||||
|
|
||||||
data = {
|
|
||||||
'extra_specs': '',
|
|
||||||
'is_public': enable_public_share_type_creation,
|
|
||||||
'spec_driver_handles_share_servers': 'True',
|
|
||||||
'name': 'share',
|
|
||||||
}
|
|
||||||
|
|
||||||
result = form.handle(self.request, data)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
self.assertEqual(
|
|
||||||
enable_public_share_type_creation,
|
|
||||||
form.enable_public_share_type_creation)
|
|
||||||
if enable_public_share_type_creation:
|
|
||||||
self.assertIn("is_public", form.fields)
|
|
||||||
self.assertTrue(form.fields["is_public"])
|
|
||||||
else:
|
|
||||||
self.assertNotIn("is_public", form.fields)
|
|
||||||
self.manilaclient.share_types.create.assert_called_once_with(
|
|
||||||
name=data['name'],
|
|
||||||
spec_driver_handles_share_servers='true',
|
|
||||||
spec_snapshot_support=True,
|
|
||||||
is_public=enable_public_share_type_creation)
|
|
||||||
mock_horizon_messages_success.assert_called_once_with(
|
|
||||||
self.request, mock.ANY)
|
|
||||||
|
|
||||||
|
|
||||||
class ManilaDashboardsAdminMigrationFormTests(base.APITestCase):
|
class ManilaDashboardsAdminMigrationFormTests(base.APITestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user