Create share network panel workflows

Implements: bp share-network-subnets
Co-Authored-By: Cameron Kolodjski <cdkolod@gmail.com>
Co-Authored-By: Shkoh Hamasoor <shkoh.hamasoor@ndsu.edu>
Co-Authored-By: melakualehegn <melakualehegn34@gmail.com>
Change-Id: I4c539b151cbbf69e4a2a3580906b2a8bd5f3a452
Signed-off-by: Goutham Pacha Ravi <gouthampravi@gmail.com>
This commit is contained in:
Cameron Kolodjski
2022-04-22 15:28:13 +00:00
committed by melakualehegn
parent 99138f186a
commit d1428c5fc5
16 changed files with 492 additions and 236 deletions

1
.gitignore vendored
View File

@@ -22,6 +22,7 @@ lib64
pip-log.txt pip-log.txt
# Unit test / coverage reports # Unit test / coverage reports
coverage.xml
.coverage .coverage
.tox .tox
nosetests.xml nosetests.xml

View File

@@ -28,7 +28,7 @@ from manilaclient import client as manila_client
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
MANILA_UI_USER_AGENT_REPR = "manila_ui_plugin_for_horizon" MANILA_UI_USER_AGENT_REPR = "manila_ui_plugin_for_horizon"
MANILA_VERSION = "2.50" MANILA_VERSION = "2.51"
MANILA_SERVICE_TYPE = "sharev2" MANILA_SERVICE_TYPE = "sharev2"
# API static values # API static values
@@ -302,10 +302,11 @@ def share_network_list(request, detailed=False, search_opts=None):
def share_network_create(request, neutron_net_id=None, neutron_subnet_id=None, def share_network_create(request, neutron_net_id=None, neutron_subnet_id=None,
name=None, description=None): name=None, description=None, availability_zone=None):
return manilaclient(request).share_networks.create( return manilaclient(request).share_networks.create(
neutron_net_id=neutron_net_id, neutron_subnet_id=neutron_subnet_id, neutron_net_id=neutron_net_id, neutron_subnet_id=neutron_subnet_id,
name=name, description=description) name=name, description=description,
availability_zone=availability_zone)
def share_network_get(request, share_net_id): def share_network_get(request, share_net_id):

View File

@@ -1,24 +0,0 @@
# 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.
from openstack_dashboard.api import neutron
def network_list(request):
return neutron.network_list(request)
def network_get(request, net_id):
return neutron.network_get(request, net_id)

View File

@@ -21,14 +21,6 @@ class ShareNetworksTable(tables.DataTable):
"name", verbose_name=_("Name"), "name", verbose_name=_("Name"),
link="horizon:admin:share_networks:share_network_detail") link="horizon:admin:share_networks:share_network_detail")
project = tables.Column("project_name", verbose_name=_("Project")) 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): def get_object_display(self, share_network):
return share_network.name or str(share_network.id) return share_network.name or str(share_network.id)

View File

@@ -1,53 +1,90 @@
{% load i18n sizeformat parse_date %} {% load i18n sizeformat parse_date %}
<h3>{% trans "Share Network Overview" %}</h3> <div class="row">
<div class="detail">
<hr class="header_rule">
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt>{% trans "Name" %}</dt> <dt>{% trans "Name" %}</dt>
<dd>{{ share_network.name }}</dd> <dd>{{ share_network.name }}</dd>
<dt>{% trans "ID" %}</dt>
<dd>{{ share_network.id }}</dd>
{% if share_network.description %} {% if share_network.description %}
<dt>{% trans "Description" %}</dt> <dt>{% trans "Description" %}</dt>
<dd>{{ share_network.description }}</dd> <dd>{{ share_network.description }}</dd>
{% endif %} {% endif %}
{% if share_network.share_servers %} {% if share_network.created_at %}
<dt>{% trans "Share Servers" %}</dt> <dt>{% trans "Created At" %}</dt>
{% for server in share_network.share_servers %} <dd>{{ share_network.created_at }}</dd>
{% url 'horizon:admin:share_servers:share_server_detail' server.id as server_url %}
<dd><a href="{{ server_url }}">{{ server.id }}</a></dd>
{% endfor %}
{% endif %} {% endif %}
{% if share_network.updated_at %}
<dt>{% trans "Updated At" %} </dt>
<dd>{{ share_network.updated_at }}</dd>
{% endif %}
<dt>{% trans "Share Network ID" %}</dt>
<dd>{{ share_network.id }}</dd>
<dt>{% trans "Project ID" %}</dt>
<dd>{{ share_network.project_id }}</dd>
</dl> </dl>
</div> </div>
<div class="detail"> <div class="detail">
<h4>{% trans "Net Details" %}</h4> <h4>{% trans "Subnets" %}</h4>
<hr class="header_rule"> <hr class="header_rule">
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt>{% trans "Network" %}</dt> <dl class="dl-horizontal">
{% if share_network.neutron_net %} {% for subnet in share_network.share_network_subnets %}
<dd>{{ share_network.neutron_net }}</dd> <dl class="dl-horizontal">
<dt>{% trans "Subnet" %}</dt> <dt>{% trans "Id" %}</dt>
<dd>{{ share_network.neutron_subnet}}</dd> <dd>
{% endif %} {{subnet.id}}
</dd>
{% if subnet.neutron_net != "Unknown" %}
{% url 'horizon:admin:networks:detail' subnet.neutron_net_id as network_detail_url %}
<dt>{% trans "Neutron Network" %}</dt>
<dd>
<a href="{{ network_detail_url }}">{{subnet.neutron_net}}</a>
</dd>
{% endif %}
{% if subnet.neutron_subnet != "Unknown" %}
{% url 'horizon:admin:networks:subnets:detail' subnet.neutron_subnet_id as subnet_detail_url %}
<dt>{% trans "Neutron Subnet" %}</dt>
<dd>
<a href="{{ subnet_detail_url }}">{{subnet.neutron_subnet}}</a>
</dd>
{% endif %}
<dt>{% trans "Availability Zone" %}</dt>
<dd>
{{subnet.availability_zone}}
</dd>
</dl>
{% endfor %}
</dl>
</dl> </dl>
</div> </div>
{% if share_network.share_servers %}
<div class="detail"> <div class="detail">
<h4>{% trans "Security Services" %}</h4> <h4>{% trans "Share Servers" %}</h4>
<hr class="header_rule"> <hr class="header_rule">
{% for sec_service in share_network.sec_services %} <dl class="dl-horizontal">
{% url 'horizon:admin:security_services:security_service_detail' sec_service.id as sec_service_url%} {% for server in share_network.share_servers %}
<dl class="dl-horizontal"> <ul>
{% url 'horizon:admin:share_servers:share_server_detail' server.id as server_url %}
<li><a href="{{ server_url }}">{{server.id }}</a></li>
</ul>
{% endfor %}
</dl>
</div>
{% endif %}
{% if share_network.sec_services %}
<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> <dt>{% trans "Id" %}</dt>
<dd><a href="{{ sec_service_url }}">{{ sec_service.id }}</a></dd> <dd><a href="{{ sec_service_url }}">{{ sec_service.id }}</a></dd>
<dt>{% trans "Name" %}</dt> <dt>{% trans "Name" %}</dt>
<dd><a href="{{ sec_service_url }}">{{ sec_service.name }}</a></dd> <dd><a href="{{ sec_service_url }}">{{ sec_service.name }}</a></dd>
<dt>{% trans "Type" %}</dt> <dt>{% trans "Type" %}</dt>
<dd>{{ sec_service.type }}</dd> <dd>{{ sec_service.type }}</dd>
</dl> </dl>
<br /> <br />
{% endfor %} {% endfor %}
</div> </div>
{% endif %}

View File

@@ -21,8 +21,6 @@ from django.utils.translation import gettext_lazy as _
from horizon import exceptions from horizon import exceptions
from horizon import tables from horizon import tables
from horizon.utils import memoized 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.api import manila
from manila_ui.dashboards.admin.share_networks import tables as sn_tables from manila_ui.dashboards.admin.share_networks import tables as sn_tables
@@ -42,19 +40,7 @@ class ShareNetworksView(tables.MultiTableView):
def get_share_networks_data(self): def get_share_networks_data(self):
try: try:
share_networks = manila.share_network_list( share_networks = manila.share_network_list(
self.request, detailed=True, search_opts={'all_tenants': True}) 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: except Exception:
share_networks = [] share_networks = []
exceptions.handle( exceptions.handle(

View File

@@ -22,7 +22,6 @@ from openstack_dashboard.api import base
from openstack_dashboard.api import neutron from openstack_dashboard.api import neutron
from manila_ui.api import manila from manila_ui.api import manila
from manila_ui.api import network
from manila_ui.dashboards import utils from manila_ui.dashboards import utils
@@ -34,8 +33,8 @@ class Create(forms.SelfHandlingForm):
def __init__(self, request, *args, **kwargs): def __init__(self, request, *args, **kwargs):
super(Create, self).__init__(request, *args, **kwargs) super(Create, self).__init__(request, *args, **kwargs)
self.neutron_enabled = base.is_service_enabled(request, 'network') self.neutron_enabled = base.is_service_enabled(request, 'network')
net_choices = network.network_list(request)
if self.neutron_enabled: if self.neutron_enabled:
net_choices = neutron.network_list(request)
self.fields['neutron_net_id'] = forms.ChoiceField( self.fields['neutron_net_id'] = forms.ChoiceField(
choices=[(' ', ' ')] + choices=[(' ', ' ')] +
[(utils.transform_dashed_name(choice.id), [(utils.transform_dashed_name(choice.id),

View File

@@ -109,14 +109,8 @@ class ShareNetworksTable(tables.DataTable):
name = tables.WrappingColumn( name = tables.WrappingColumn(
"name", verbose_name=_("Name"), "name", verbose_name=_("Name"),
link="horizon:project:share_networks:share_network_detail") link="horizon:project:share_networks:share_network_detail")
neutron_net = tables.Column("neutron_net", verbose_name=_("Neutron Net")) description = tables.WrappingColumn(
neutron_subnet = tables.Column( "description", verbose_name=_("Description"))
"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): def get_object_display(self, share_network):
return share_network.name or str(share_network.id) return share_network.name or str(share_network.id)

View File

@@ -1,65 +1,90 @@
{% load i18n sizeformat parse_date %} {% load i18n sizeformat parse_date %}
<h3>{% trans "Share Network Overview" %}</h3> <div class="row">
<div class="detail">
<hr class="header_rule">
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt>{% trans "Name" %}</dt> <dt>{% trans "Name" %}</dt>
<dd>{{ share_network.name }}</dd> <dd>{{ share_network.name }}</dd>
<dt>{% trans "ID" %}</dt>
<dd>{{ share_network.id }}</dd>
{% if share_network.description %} {% if share_network.description %}
<dt>{% trans "Description" %}</dt> <dt>{% trans "Description" %}</dt>
<dd>{{ share_network.description }}</dd> <dd>{{ share_network.description }}</dd>
{% endif %} {% endif %}
{% if share_network.created_at %}
<dt>{% trans "Created At" %}</dt>
<dd>{{ share_network.created_at }}</dd>
{% endif %}
{% if share_network.updated_at %}
<dt>{% trans "Updated At" %} </dt>
<dd>{{ share_network.updated_at }}</dd>
{% endif %}
<dt>{% trans "Share Network ID" %}</dt>
<dd>{{ share_network.id }}</dd>
<dt>{% trans "Project ID" %}</dt>
<dd>{{ share_network.project_id }}</dd>
</dl> </dl>
</div> </div>
<div class="detail"> <div class="detail">
<h4>{% trans "Network Details" %}</h4> <h4>{% trans "Subnets" %}</h4>
<hr class="header_rule"> <hr class="header_rule">
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt>{% trans "Network" %}</dt> <dl class="dl-horizontal">
{% if share_network.neutron_net %} {% for subnet in share_network.share_network_subnets %}
<dd>{{ share_network.neutron_net }}</dd> <dl class="dl-horizontal">
<dt>{% trans "Subnet" %}</dt> <dt>{% trans "Id" %}</dt>
<dd>{{ share_network.neutron_subnet}}</dd> <dd>
{% endif %} {{subnet.id}}
</dd>
{% if subnet.neutron_net != "Unknown" %}
{% url 'horizon:project:networks:detail' subnet.neutron_net_id as network_detail_url %}
<dt>{% trans "Neutron Network" %}</dt>
<dd>
<a href="{{ network_detail_url }}">{{subnet.neutron_net}}</a>
</dd>
{% endif %}
{% if subnet.neutron_subnet != "Unknown" %}
{% url 'horizon:project:networks:subnets:detail' subnet.neutron_subnet_id as subnet_detail_url %}
<dt>{% trans "Neutron Subnet" %}</dt>
<dd>
<a href="{{ subnet_detail_url }}">{{subnet.neutron_subnet}}</a>
</dd>
{% endif %}
<dt>{% trans "Availability Zone" %}</dt>
<dd>
{{subnet.availability_zone}}
</dd>
</dl>
{% endfor %}
</dl>
</dl> </dl>
</div> </div>
{% if share_network.share_servers %} {% if share_network.share_servers %}
<div class="detail"> <div class="detail">
<h4>{% trans "Share Servers" %}</h4> <h4>{% trans "Share Servers" %}</h4>
<hr class="header_rule"> <hr class="header_rule">
<dl class="dl-horizontal"> <dl class="dl-horizontal">
{% for server in share_network.share_servers %} {% for server in share_network.share_servers %}
<ul> <ul>
{% url 'horizon:admin:share_servers:share_server_detail' server.id as server_url %} {% url 'horizon:admin:share_servers:share_server_detail' server.id as server_url %}
<li><a href="{{ server_url }}">{{ server.id }}</a></li> <li><a href="{{ server_url }}">{{server.id }}</a></li>
</ul> </ul>
{% endfor %} {% endfor %}
</dl> </dl>
</div> </div>
{% endif %} {% endif %}
{% if share_network.sec_services %} {% if share_network.sec_services %}
<div class="detail"> <div class="detail">
<h4>{% trans "Security Services" %}</h4> <h4>{% trans "Security Services" %}</h4>
<hr class="header_rule"> <hr class="header_rule">
{% for sec_service in share_network.sec_services %} {% for sec_service in share_network.sec_services %}
{% url 'horizon:project:security_services:security_service_detail' sec_service.id as sec_service_url%} {% url 'horizon:project:security_services:security_service_detail' sec_service.id as sec_service_url%}
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt>{% trans "Id" %}</dt> <dt>{% trans "Id" %}</dt>
<dd><a href="{{ sec_service_url }}">{{ sec_service.id }}</a></dd> <dd><a href="{{ sec_service_url }}">{{ sec_service.id }}</a></dd>
<dt>{% trans "Name" %}</dt> <dt>{% trans "Name" %}</dt>
<dd><a href="{{ sec_service_url }}">{{ sec_service.name }}</a></dd> <dd><a href="{{ sec_service_url }}">{{ sec_service.name }}</a></dd>
<dt>{% trans "Type" %}</dt> <dt>{% trans "Type" %}</dt>
<dd>{{ sec_service.type }}</dd> <dd>{{ sec_service.type }}</dd>
</dl> </dl>
<br /> <br />
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}

View File

@@ -15,7 +15,6 @@
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from horizon import exceptions from horizon import exceptions
from horizon import forms
from horizon import tables from horizon import tables
from horizon import tabs from horizon import tabs
from horizon.utils import memoized from horizon.utils import memoized
@@ -24,7 +23,6 @@ from openstack_dashboard.api import base
from openstack_dashboard.api import neutron from openstack_dashboard.api import neutron
from manila_ui.api import manila from manila_ui.api import manila
from manila_ui.dashboards.project.share_networks import forms as sn_forms
from manila_ui.dashboards.project.share_networks import tables as sn_tables from manila_ui.dashboards.project.share_networks import tables as sn_tables
from manila_ui.dashboards.project.share_networks import tabs as sn_tabs from manila_ui.dashboards.project.share_networks import tabs as sn_tabs
import manila_ui.dashboards.project.share_networks.workflows as sn_workflows import manila_ui.dashboards.project.share_networks.workflows as sn_workflows
@@ -43,16 +41,6 @@ class ShareNetworksView(tables.MultiTableView):
try: try:
share_networks = manila.share_network_list( share_networks = manila.share_network_list(
self.request, detailed=True) self.request, detailed=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: except Exception:
share_networks = [] share_networks = []
exceptions.handle( exceptions.handle(
@@ -75,13 +63,9 @@ class Update(workflows.WorkflowView):
return context return context
class Create(forms.ModalFormView): class Create(workflows.WorkflowView):
form_class = sn_forms.Create workflow_class = sn_workflows.CreateShareNetworkWorkflow
form_id = "create_share_network" form_id = "create_share_network"
template_name = 'project/share_networks/create.html'
modal_header = _("Create Share Network")
modal_id = "create_share_network_modal"
submit_label = _("Create")
submit_url = reverse_lazy( submit_url = reverse_lazy(
"horizon:project:share_networks:share_network_create") "horizon:project:share_networks:share_network_create")
success_url = reverse_lazy("horizon:project:share_networks:index") success_url = reverse_lazy("horizon:project:share_networks:index")
@@ -110,19 +94,32 @@ class Detail(tabs.TabView):
share_net_id = self.kwargs['share_network_id'] share_net_id = self.kwargs['share_network_id']
share_net = manila.share_network_get(self.request, share_net_id) share_net = manila.share_network_get(self.request, share_net_id)
if base.is_service_enabled(self.request, 'network'): if base.is_service_enabled(self.request, 'network'):
try: for subnet in share_net.share_network_subnets:
share_net.neutron_net = neutron.network_get( # Neutron Net ID
self.request, share_net.neutron_net_id).name_or_id try:
except ( subnet["neutron_net"] = neutron.network_get(
neutron.neutron_client.exceptions.NeutronClientException): self.request, subnet["neutron_net_id"]).name_or_id
share_net.neutron_net = _("Unknown") except (
try: neutron.neutron_client.exceptions
share_net.neutron_subnet = neutron.subnet_get( .NeutronClientException
self.request, share_net.neutron_subnet_id).name_or_id ):
except ( subnet["neutron_net"] = _("Unknown")
neutron.neutron_client.exceptions.NeutronClientException): # Neutron Subnet ID
share_net.neutron_subnet = _("Unknown") try:
subnet["neutron_subnet"] = neutron.subnet_get(
self.request,
subnet["neutron_subnet_id"]).name_or_id
except (
neutron.neutron_client.exceptions
.NeutronClientException
):
subnet["neutron_subnet"] = _("Unknown")
# List all azs if availability_zone is None
availability_zones = manila.availability_zone_list(self.request)
az_list = ", ".join([az.name for az in availability_zones])
for subnet in share_net.share_network_subnets:
if subnet["availability_zone"] is None:
subnet["availability_zone"] = az_list
share_net.sec_services = ( share_net.sec_services = (
manila.share_network_security_service_list( manila.share_network_security_service_list(
self.request, share_net_id)) self.request, share_net_id))

View File

@@ -12,12 +12,160 @@
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from horizon import exceptions from horizon import exceptions
from horizon import forms from horizon import forms
from horizon import messages
from horizon import workflows from horizon import workflows
from openstack_dashboard import api
from openstack_dashboard.api import base
from manila_ui.api import manila from manila_ui.api import manila
from manila_ui.dashboards import utils
class CreateShareNetworkInfoAction(workflows.Action):
share_network_name = forms.CharField(
max_length=255, label=_("Name"), required=True)
share_network_description = forms.CharField(
widget=forms.Textarea, label=_("Description"), required=False)
class Meta(object):
name = ("Share Network")
class CreateShareNetworkInfoStep(workflows.Step):
action_class = CreateShareNetworkInfoAction
contributes = ("share_network_description",
"share_network_name")
class AddShareNetworkSubnetAction(workflows.MembershipAction):
availability_zone = forms.ChoiceField(
required=False,
label=_('Availability Zone'),
widget=forms.ThemableSelectWidget(attrs={
'data-availability_zone': _('Availability Zone')}))
neutron_net_id = forms.ChoiceField(
required=False,
label=_('Neutron Net'),
widget=forms.ThemableSelectWidget(attrs={
'class': 'switchable',
'data-slug': 'neutron_net_id',
'data-neutron_net_id': _('Neutron Net')}))
class Meta(object):
name = _("Subnet")
help_text = _("Specify an Availability Zone or an existing subnet. "
"If no details are specified, "
"then a default subnet with a null Availability "
"Zone will be created automatically.")
def __init__(self, request, context, *args, **kwargs):
super().__init__(request, context, *args, **kwargs)
self.fields['availability_zone'].choices = (
self.get_availability_zone_choices(request)
)
self.neutron_enabled = base.is_service_enabled(request, 'network')
if self.neutron_enabled:
try:
self.fields['neutron_net_id'].choices, networks = (
self.get_neutron_net_id_choices(request)
)
except Exception:
msg = _('Unable to initialize neutron networks.')
exceptions.handle(request, msg)
try:
self.get_neutron_subnet_id_choices(request, networks)
except Exception:
msg = _('Unable to initialize neutron subnets.')
exceptions.handle(request, msg)
def get_availability_zone_choices(self, request):
availability_zone_choices = [('', _('None'))]
for availability_zone in manila.availability_zone_list(request):
availability_zone_choices.append(
(availability_zone.id, availability_zone.name)
)
return availability_zone_choices
def get_neutron_net_id_choices(self, request):
net_choices = [('', _('None'))]
networks = api.neutron.network_list(request)
for network in networks:
net_choices.append((utils.transform_dashed_name(network.id),
network.name_or_id))
return net_choices, networks
def get_neutron_subnet_id_choices(self, request, networks):
for net in networks:
subnet_field_name = (
'subnet-choices-%s' % utils.transform_dashed_name(net.id))
data_net_id = (
'data-neutron_net_id-%s' % utils.transform_dashed_name(net.id))
subnet_field = forms.ChoiceField(
required=False,
choices=(),
label=_('Neutron Subnet'),
widget=forms.ThemableSelectWidget(attrs={
'class': 'switched',
'data-switch-on': 'neutron_net_id',
data_net_id: _('Neutron Subnet')}))
self.fields[subnet_field_name] = subnet_field
subnet_choices = api.neutron.subnet_list(request,
network_id=net.id)
self.fields[subnet_field_name].choices = [
(choice.id, choice.name_or_id)
for choice in subnet_choices]
def hide_neutron_subnet_id_choices(self):
self.fields['neutron_subnet_id'].choices = []
self.fields['neutron_subnet_id'].widget = forms.HiddenInput()
class AddShareNetworkSubnetStep(workflows.Step):
action_class = AddShareNetworkSubnetAction
contributes = ("neutron_net_id", "neutron_subnet_id", "availability_zone")
class CreateShareNetworkWorkflow(workflows.Workflow):
slug = "create_share_network"
name = _("Create Share Network")
finalize_button_name = _("Create Share Network")
success_message = _('Created share network "%s".')
failure_message = _('Unable to create share network "%s".')
success_url = 'horizon:project:share_networks:index'
default_steps = (CreateShareNetworkInfoStep, AddShareNetworkSubnetStep)
wizard = True
def handle(self, request, context):
try:
data = request.POST
send_data = {'name': context['share_network_name']}
if context['share_network_description']:
send_data['description'] = context['share_network_description']
neutron_net_id = context.get('neutron_net_id')
if neutron_net_id:
send_data['neutron_net_id'] = utils.transform_dashed_name(
neutron_net_id.strip())
subnet_key = (
'subnet-choices-%s' % neutron_net_id.strip()
)
if data.get(subnet_key) is not None:
send_data['neutron_subnet_id'] = data.get(subnet_key)
if context['availability_zone']:
send_data['availability_zone'] = context['availability_zone']
share_network = manila.share_network_create(request, **send_data)
messages.success(request, _('Successfully created share'
' network: %s') % send_data['name'])
return share_network
except Exception:
exceptions.handle(request, _('Unable to create share network.'))
return False
class UpdateShareNetworkInfoAction(workflows.Action): class UpdateShareNetworkInfoAction(workflows.Action):

View File

@@ -412,6 +412,7 @@ class ManilaApiTests(base.APITestCase):
"description": None, "description": None,
"neutron_net_id": None, "neutron_net_id": None,
"neutron_subnet_id": None, "neutron_subnet_id": None,
"availability_zone": None
} }
expected_kwargs.update(**kwargs) expected_kwargs.update(**kwargs)

View File

@@ -18,6 +18,7 @@ from horizon import exceptions as horizon_exceptions
from neutronclient.client import exceptions from neutronclient.client import exceptions
from openstack_dashboard.api import keystone as api_keystone from openstack_dashboard.api import keystone as api_keystone
from openstack_dashboard.api import neutron as api_neutron from openstack_dashboard.api import neutron as api_neutron
from oslo_utils import timeutils
from unittest import mock from unittest import mock
from manila_ui.api import manila as api_manila from manila_ui.api import manila as api_manila
@@ -39,8 +40,15 @@ class ShareNetworksTests(test.BaseAdminViewTests):
# Reset taken list of projects to avoid test interference # Reset taken list of projects to avoid test interference
utils.PROJECTS = {} utils.PROJECTS = {}
class FakeAZ(object):
def __init__(self, name, id):
self.name = name
self.id = id
self.created_at = timeutils.utcnow()
def test_detail_view(self): def test_detail_view(self):
share_net = test_data.active_share_network share_net = test_data.active_share_network
share_network_subnets = share_net.share_network_subnets
sec_service = test_data.sec_service sec_service = test_data.sec_service
self.mock_object( self.mock_object(
api_manila, "share_server_list", mock.Mock(return_value=[])) api_manila, "share_server_list", mock.Mock(return_value=[]))
@@ -55,6 +63,10 @@ class ShareNetworksTests(test.BaseAdminViewTests):
api_neutron, "network_get", mock.Mock(return_value=network)) api_neutron, "network_get", mock.Mock(return_value=network))
self.mock_object( self.mock_object(
api_neutron, "subnet_get", mock.Mock(return_value=subnet)) api_neutron, "subnet_get", mock.Mock(return_value=subnet))
self.mock_object(
api_manila, "availability_zone_list",
mock.Mock(return_value=[self.FakeAZ('fake_az', 'fake_az')])
)
url = reverse('horizon:admin:share_networks:share_network_detail', url = reverse('horizon:admin:share_networks:share_network_detail',
args=[share_net.id]) args=[share_net.id])
@@ -65,11 +77,23 @@ class ShareNetworksTests(test.BaseAdminViewTests):
1, 200) 1, 200)
self.assertContains(res, "<dd>%s</dd>" % 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>" % share_net.id, 1, 200)
self.assertContains(res, "<dd>%s</dd>" % network.name_or_id, 1, 200) for sub in share_network_subnets:
self.assertContains(res, "<dd>%s</dd>" % subnet.name_or_id, 1, 200) self.assertContains(res, "<a href=\"/admin/networks"
"/%s/detail\">%s</a>" % (
sub['neutron_net_id'],
network.name), 1, 200)
self.assertContains(res, "<a href=\"/admin/security_services" self.assertContains(res, "<a href=\"/admin/security_services"
"/%s\">%s</a>" % (sec_service.id, "/%s\">%s</a>" % (sec_service.id,
sec_service.name), 1, 200) sec_service.name), 1, 200)
network_get_calls = [mock.call(mock.ANY, sub['neutron_net_id']
) for sub in share_network_subnets]
subnet_get_calls = [mock.call(mock.ANY, sub['neutron_subnet_id']
) for sub in share_network_subnets]
api_neutron.network_get.assert_has_calls(network_get_calls,
any_order=True)
api_neutron.subnet_get.assert_has_calls(subnet_get_calls,
any_order=True)
self.assertNoMessages() self.assertNoMessages()
api_manila.share_network_security_service_list.assert_called_once_with( api_manila.share_network_security_service_list.assert_called_once_with(
mock.ANY, share_net.id) mock.ANY, share_net.id)
@@ -77,14 +101,11 @@ class ShareNetworksTests(test.BaseAdminViewTests):
mock.ANY, search_opts={'share_network_id': share_net.id}) mock.ANY, search_opts={'share_network_id': share_net.id})
api_manila.share_network_get.assert_called_once_with( api_manila.share_network_get.assert_called_once_with(
mock.ANY, share_net.id) 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): def test_detail_view_network_not_found(self):
share_net = test_data.active_share_network share_net = test_data.active_share_network
sec_service = test_data.sec_service sec_service = test_data.sec_service
share_network_subnets = share_net.share_network_subnets
url = reverse('horizon:admin:share_networks:share_network_detail', url = reverse('horizon:admin:share_networks:share_network_detail',
args=[share_net.id]) args=[share_net.id])
self.mock_object( self.mock_object(
@@ -100,7 +121,10 @@ class ShareNetworksTests(test.BaseAdminViewTests):
self.mock_object( self.mock_object(
api_neutron, "subnet_get", mock.Mock( api_neutron, "subnet_get", mock.Mock(
side_effect=exceptions.NeutronClientException('fake', 500))) side_effect=exceptions.NeutronClientException('fake', 500)))
self.mock_object(
api_manila, "availability_zone_list",
mock.Mock(return_value=[])
)
res = self.client.get(url) res = self.client.get(url)
self.assertContains(res, "<h1>Share Network Details: %s</h1>" self.assertContains(res, "<h1>Share Network Details: %s</h1>"
@@ -108,10 +132,19 @@ class ShareNetworksTests(test.BaseAdminViewTests):
1, 200) 1, 200)
self.assertContains(res, "<dd>%s</dd>" % 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>" % share_net.id, 1, 200)
self.assertContains(res, "<dd>Unknown</dd>", 2, 200) for sub in share_network_subnets:
self.assertNotContains(res, "<dd>%s</dd>" % share_net.neutron_net_id) self.assertNotContains(res, "<dd>%s</dd>" % sub['neutron_net_id'])
self.assertNotContains(res, self.assertNotContains(res,
"<dd>%s</dd>" % share_net.neutron_subnet_id) "<dd>%s</dd>" % sub['neutron_subnet_id'])
network_get_calls = [mock.call(mock.ANY, sub['neutron_net_id']
) for sub in share_network_subnets]
subnet_get_calls = [mock.call(mock.ANY, sub['neutron_subnet_id']
) for sub in share_network_subnets]
api_neutron.network_get.assert_has_calls(network_get_calls,
any_order=True)
api_neutron.subnet_get.assert_has_calls(subnet_get_calls,
any_order=True)
self.assertContains(res, "<a href=\"/admin/security_services" self.assertContains(res, "<a href=\"/admin/security_services"
"/%s\">%s</a>" % (sec_service.id, "/%s\">%s</a>" % (sec_service.id,
sec_service.name), 1, 200) sec_service.name), 1, 200)
@@ -122,10 +155,6 @@ class ShareNetworksTests(test.BaseAdminViewTests):
mock.ANY, search_opts={'share_network_id': share_net.id}) mock.ANY, search_opts={'share_network_id': share_net.id})
api_manila.share_network_get.assert_called_once_with( api_manila.share_network_get.assert_called_once_with(
mock.ANY, share_net.id) 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): def test_detail_view_with_exception(self):
url = reverse('horizon:admin:share_networks:share_network_detail', url = reverse('horizon:admin:share_networks:share_network_detail',
@@ -143,10 +172,6 @@ class ShareNetworksTests(test.BaseAdminViewTests):
def test_delete_share_network(self): def test_delete_share_network(self):
share_network = test_data.inactive_share_network share_network = test_data.inactive_share_network
formData = {'action': 'share_networks__delete__%s' % share_network.id} 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_delete")
self.mock_object( self.mock_object(
api_manila, "share_network_list", api_manila, "share_network_list",
@@ -156,11 +181,9 @@ class ShareNetworksTests(test.BaseAdminViewTests):
res = self.client.post(INDEX_URL, formData) res = self.client.post(INDEX_URL, formData)
self.assertRedirectsNoFollow(res, INDEX_URL)
api_keystone.tenant_list.assert_called_once_with(mock.ANY) api_keystone.tenant_list.assert_called_once_with(mock.ANY)
api_manila.share_network_delete.assert_called_once_with( api_manila.share_network_delete.assert_called_once_with(
mock.ANY, test_data.inactive_share_network.id) mock.ANY, share_network.id)
api_manila.share_network_list.assert_called_once_with( api_manila.share_network_list.assert_called_once_with(
mock.ANY, detailed=True, search_opts={'all_tenants': True}) 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)

View File

@@ -16,10 +16,10 @@ from django.urls import reverse
from neutronclient.client import exceptions from neutronclient.client import exceptions
from openstack_auth import policy from openstack_auth import policy
from openstack_dashboard import api from openstack_dashboard import api
from oslo_utils import timeutils
from unittest import mock from unittest import mock
from manila_ui.api import manila as api_manila from manila_ui.api import manila as api_manila
from manila_ui.api import network as api_manila_network
from manila_ui.dashboards import utils from manila_ui.dashboards import utils
from manila_ui.tests.dashboards.project import test_data from manila_ui.tests.dashboards.project import test_data
from manila_ui.tests import helpers as test from manila_ui.tests import helpers as test
@@ -28,40 +28,55 @@ INDEX_URL = reverse('horizon:project:share_networks:index')
class ShareNetworksViewTests(test.TestCase): class ShareNetworksViewTests(test.TestCase):
class FakeAZ(object):
def __init__(self, name, id):
self.name = name
self.id = id
self.created_at = timeutils.utcnow()
def test_create_share_network(self): def test_create_share_network(self):
share_net = test_data.active_share_network share_net = test_data.active_share_network
url = reverse('horizon:project:share_networks:share_network_create') url = reverse('horizon:project:share_networks:share_network_create')
neutron_net_id = self.networks.first().id neutron_net_id = self.networks.first().id
sanitized_net_id = utils.transform_dashed_name(neutron_net_id)
formData = { formData = {
'name': 'new_share_network', 'share_network_name': 'new_share_network',
'description': 'This is test share network', 'share_network_description': 'This is test share network',
'method': 'CreateForm', 'method': 'CreateForm',
'neutron_net_id': utils.transform_dashed_name(neutron_net_id), 'neutron_net_id': utils.transform_dashed_name(neutron_net_id),
'availability_zone': 'fake_az',
f'subnet-choices-{sanitized_net_id}':
self.networks.first().subnets[0].id,
} }
for net in self.networks.list():
sanitized_net_id = utils.transform_dashed_name(net.id)
subnet_choices_field = 'subnet-choices-%s' % sanitized_net_id
formData[subnet_choices_field] = net.subnets[0].id
self.mock_object( self.mock_object(
api.neutron, "subnet_list", api.neutron, "subnet_list",
mock.Mock(return_value=self.subnets.list())) mock.Mock(return_value=self.subnets.list()))
self.mock_object( self.mock_object(
api_manila_network, "network_list", api.neutron, "network_list",
mock.Mock(return_value=self.networks.list())) mock.Mock(return_value=self.networks.list()))
self.mock_object( self.mock_object(
api_manila, "share_network_create", api_manila, "share_network_create",
mock.Mock(return_value=share_net)) mock.Mock(return_value=share_net))
self.mock_object(
api_manila, "availability_zone_list",
mock.Mock(return_value=[self.FakeAZ('fake_az', 'fake_az')])
)
self.client.post(url, formData) res = self.client.post(url, formData)
sanitized_neutron_net_field = formData[ self.assertNoFormErrors(res)
'subnet-choices-%s' % utils.transform_dashed_name(neutron_net_id)] self.assertMessageCount(error=0, warning=0)
self.assertRedirectsNoFollow(res, INDEX_URL)
api_manila.share_network_create.assert_called_once_with( api_manila.share_network_create.assert_called_once_with(
mock.ANY, name=formData['name'], neutron_net_id=neutron_net_id, mock.ANY, name=formData['share_network_name'],
neutron_subnet_id=sanitized_neutron_net_field, neutron_net_id=neutron_net_id,
description=formData['description']) neutron_subnet_id=self.networks.first().subnets[0].id,
api_manila_network.network_list.assert_called_once_with(mock.ANY) description=formData['share_network_description'],
availability_zone='fake_az')
api_manila.availability_zone_list.assert_called_once_with(mock.ANY)
api.neutron.network_list.assert_called_once_with(mock.ANY)
api.neutron.subnet_list.assert_has_calls([ api.neutron.subnet_list.assert_has_calls([
mock.call(mock.ANY, network_id=network.id) mock.call(mock.ANY, network_id=network.id)
for network in self.networks.list() for network in self.networks.list()
@@ -75,12 +90,6 @@ class ShareNetworksViewTests(test.TestCase):
api_manila, "share_network_list", api_manila, "share_network_list",
mock.Mock(return_value=[ mock.Mock(return_value=[
test_data.active_share_network, share_network])) test_data.active_share_network, share_network]))
self.mock_object(
api.neutron, "network_list",
mock.Mock(return_value=self.networks.list()))
self.mock_object(
api.neutron, "subnet_list",
mock.Mock(return_value=self.subnets.list()))
res = self.client.post(INDEX_URL, formData) res = self.client.post(INDEX_URL, formData)
@@ -89,12 +98,11 @@ class ShareNetworksViewTests(test.TestCase):
mock.ANY, detailed=True) mock.ANY, detailed=True)
api_manila.share_network_delete.assert_called_once_with( api_manila.share_network_delete.assert_called_once_with(
mock.ANY, share_network.id) mock.ANY, share_network.id)
api.neutron.network_list.assert_called_once_with(mock.ANY)
api.neutron.subnet_list.assert_called_once_with(mock.ANY)
def test_detail_view(self): def test_detail_view(self):
share_net = test_data.active_share_network share_net = test_data.active_share_network
sec_service = test_data.sec_service sec_service = test_data.sec_service
share_network_subnets = share_net.share_network_subnets
self.mock_object( self.mock_object(
api_manila, "share_server_list", mock.Mock(return_value=[])) api_manila, "share_server_list", mock.Mock(return_value=[]))
self.mock_object( self.mock_object(
@@ -104,40 +112,58 @@ class ShareNetworksViewTests(test.TestCase):
mock.Mock(return_value=[sec_service])) mock.Mock(return_value=[sec_service]))
network = self.networks.first() network = self.networks.first()
subnet = self.subnets.first() subnet = self.subnets.first()
self.mock_object( self.mock_object(
api.neutron, "network_get", mock.Mock(return_value=network)) api.neutron, "network_get", mock.Mock(return_value=network))
self.mock_object( self.mock_object(
api.neutron, "subnet_get", mock.Mock(return_value=subnet)) api.neutron, "subnet_get", mock.Mock(return_value=subnet))
self.mock_object(
api_manila, "availability_zone_list",
mock.Mock(return_value=[self.FakeAZ('fake_az', 'fake_az')])
)
url = reverse('horizon:project:share_networks:share_network_detail', url = reverse('horizon:project:share_networks:share_network_detail',
args=[share_net.id]) args=[share_net.id])
res = self.client.get(url) res = self.client.get(url)
self.assertNoMessages()
self.assertContains(res, "<h1>Share Network Details: %s</h1>" self.assertContains(res, "<h1>Share Network Details: %s</h1>"
% share_net.name, % share_net.name,
1, 200) 1, 200)
self.assertContains(res, "<dd>%s</dd>" % 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>" % share_net.id, 1, 200)
self.assertContains(res, "<dd>%s</dd>" % network.name_or_id, 1, 200) for sub in share_network_subnets:
self.assertContains(res, "<dd>%s</dd>" % subnet.name_or_id, 1, 200) self.assertContains(res, "<a href=\"/project/networks"
"/%s/detail\">%s</a>" % (
sub['neutron_net_id'],
network.name), 1, 200)
self.assertContains(res, "<a href=\"/project/networks/subnets"
"/%s/detail\">%s</a>" % (
sub['neutron_subnet_id'],
subnet['name']), 1, 200)
network_get_calls = [mock.call(mock.ANY, sub['neutron_net_id'])
for sub in share_network_subnets]
subnet_get_calls = [mock.call(mock.ANY, sub['neutron_subnet_id'])
for sub in share_network_subnets]
api.neutron.network_get.assert_has_calls(network_get_calls,
any_order=True)
api.neutron.subnet_get.assert_has_calls(subnet_get_calls,
any_order=True)
self.assertContains(res, "<a href=\"/project/security_services" self.assertContains(res, "<a href=\"/project/security_services"
"/%s\">%s</a>" % (sec_service.id, "/%s\">%s</a>" % (sec_service.id,
sec_service.name), 1, 200) sec_service.name), 1, 200)
self.assertNoMessages()
api_manila.share_network_security_service_list.assert_called_once_with( api_manila.share_network_security_service_list.assert_called_once_with(
mock.ANY, share_net.id) mock.ANY, share_net.id)
api_manila.share_server_list.assert_called_once_with( api_manila.share_server_list.assert_called_once_with(
mock.ANY, search_opts={'share_network_id': share_net.id}) mock.ANY, search_opts={'share_network_id': share_net.id})
api_manila.share_network_get.assert_called_once_with( api_manila.share_network_get.assert_called_once_with(
mock.ANY, share_net.id) 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): def test_detail_view_network_not_found(self):
share_net = test_data.active_share_network share_net = test_data.active_share_network
sec_service = test_data.sec_service sec_service = test_data.sec_service
share_network_subnets = share_net.share_network_subnets
url = reverse('horizon:project:share_networks:share_network_detail', url = reverse('horizon:project:share_networks:share_network_detail',
args=[share_net.id]) args=[share_net.id])
self.mock_object( self.mock_object(
@@ -153,7 +179,10 @@ class ShareNetworksViewTests(test.TestCase):
self.mock_object( self.mock_object(
api.neutron, "subnet_get", mock.Mock( api.neutron, "subnet_get", mock.Mock(
side_effect=exceptions.NeutronClientException('fake', 500))) side_effect=exceptions.NeutronClientException('fake', 500)))
self.mock_object(
api_manila, "availability_zone_list",
mock.Mock(return_value=[])
)
res = self.client.get(url) res = self.client.get(url)
self.assertContains(res, "<h1>Share Network Details: %s</h1>" self.assertContains(res, "<h1>Share Network Details: %s</h1>"
@@ -161,10 +190,19 @@ class ShareNetworksViewTests(test.TestCase):
1, 200) 1, 200)
self.assertContains(res, "<dd>%s</dd>" % 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>" % share_net.id, 1, 200)
self.assertContains(res, "<dd>Unknown</dd>", 2, 200) for sub in share_network_subnets:
self.assertNotContains(res, "<dd>%s</dd>" % share_net.neutron_net_id) self.assertNotContains(res, "<dd>%s</dd>" % sub['neutron_net_id'])
self.assertNotContains(res, self.assertNotContains(res,
"<dd>%s</dd>" % share_net.neutron_subnet_id) "<dd>%s</dd>" % sub['neutron_subnet_id'])
network_get_calls = [mock.call(mock.ANY, sub['neutron_net_id']
) for sub in share_network_subnets]
subnet_get_calls = [mock.call(mock.ANY, sub['neutron_subnet_id']
) for sub in share_network_subnets]
api.neutron.network_get.assert_has_calls(network_get_calls,
any_order=True)
api.neutron.subnet_get.assert_has_calls(subnet_get_calls,
any_order=True)
self.assertContains(res, "<a href=\"/project/security_services" self.assertContains(res, "<a href=\"/project/security_services"
"/%s\">%s</a>" % (sec_service.id, "/%s\">%s</a>" % (sec_service.id,
sec_service.name), 1, 200) sec_service.name), 1, 200)
@@ -175,10 +213,6 @@ class ShareNetworksViewTests(test.TestCase):
mock.ANY, search_opts={'share_network_id': share_net.id}) mock.ANY, search_opts={'share_network_id': share_net.id})
api_manila.share_network_get.assert_called_once_with( api_manila.share_network_get.assert_called_once_with(
mock.ANY, share_net.id) 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_update_share_network(self): def test_update_share_network(self):
share_net = test_data.inactive_share_network share_net = test_data.inactive_share_network

View File

@@ -279,12 +279,46 @@ inactive_share_network = share_networks.ShareNetwork(
active_share_network = share_networks.ShareNetwork( active_share_network = share_networks.ShareNetwork(
share_networks.ShareNetworkManager(FakeAPIClient), share_networks.ShareNetworkManager(FakeAPIClient),
{'id': '7f3d1c33-8d00-4511-29df-a2def31f3b5d', {
'name': 'test_share_net', "id": "1324e7d3-fba8-45e4-bb37-b59c12eb06dc",
'description': 'test share network', "name": "net_my1",
'status': 'ACTIVE', "project_id": "16e1ab15c35a457e9c2b2aa189f544e1",
'neutron_net_id': 'fake_neutron_net_id', "created_at": "2019-10-02T17:49:43.000000",
'neutron_subnet_id': 'fake_neutron_subnet_id'}) "description": "This is test share network",
"security_service_update_support": True,
"status": "active",
"share_network_subnets": [
{
"id": "e4db03dc-6041-4c6a-a8f9-80bb4141a1eb",
"availability_zone": None,
"created_at": "2019-10-02T17:49:43.000000",
"updated_at": "2019-10-03T12:17:39.000000",
"segmentation_id": None,
"neutron_net_id": "62187648-6617-4509-a780-ffc973a7fe43",
"neutron_subnet_id": "2276888a-27c1-47c2-82a0-ea33050128b5",
"ip_version": 4,
"cidr": "172.24.5.0/24",
"network_type": "flat",
"mtu": 1500,
"gateway": "172.24.5.1",
},
{
"id": "e4db03dc-6041-4c6a-a8f9-80bb4141a1en",
"availability_zone": "manila-zone-0",
"created_at": "2019-10-02T17:49:43.000000",
"updated_at": "2019-10-03T12:17:39.000000",
"segmentation_id": None,
"neutron_net_id": "62187648-6617-4509-a780-ffc973a7f333",
"neutron_subnet_id": "2276888a-27c1-47c2-82a0-ea3305012905",
"ip_version": 4,
"cidr": "172.24.5.0/24",
"network_type": "flat",
"mtu": 1500,
"gateway": "172.24.5.1",
},
],
}
)
sec_service = security_services.SecurityService( sec_service = security_services.SecurityService(
security_services.SecurityServiceManager(FakeAPIClient), security_services.SecurityServiceManager(FakeAPIClient),

View File

@@ -0,0 +1,8 @@
---
features:
- |
Switched share network creation to a two-step
workflow. We now allow configuring an availability
zone with the initial network subnet associated with
the share network. Share network detail panels have
been updated accordingly as well