Merge "Refactor the create port form to workflow"

This commit is contained in:
Zuul 2018-02-09 14:11:34 +00:00 committed by Gerrit Code Review
commit d14439e0d8
13 changed files with 265 additions and 427 deletions

View File

@ -1,82 +0,0 @@
# Copyright 2012 NEC Corporation
#
# 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 logging
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import messages
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.networks.ports \
import forms as project_forms
LOG = logging.getLogger(__name__)
class CreatePort(project_forms.CreatePort):
binding__host_id = forms.CharField(
label=_("Binding: Host"),
help_text=_("The ID of the host where the port is allocated. In some "
"cases, different implementations can run on different "
"hosts."),
required=False)
failure_url = 'horizon:admin:networks:detail'
def handle(self, request, data):
network_id = self.initial['network_id']
try:
# We must specify tenant_id of the network which a subnet is
# created for if admin user does not belong to the tenant.
network = api.neutron.network_get(request, network_id)
params = {
'tenant_id': network.tenant_id,
'network_id': network_id,
'admin_state_up': data['admin_state'],
'name': data['name'],
'device_id': data['device_id'],
'device_owner': data['device_owner'],
'binding__host_id': data['binding__host_id']
}
if data.get('specify_ip') == 'subnet_id':
if data.get('subnet_id'):
params['fixed_ips'] = [{"subnet_id": data['subnet_id']}]
elif data.get('specify_ip') == 'fixed_ip':
if data.get('fixed_ip'):
params['fixed_ips'] = [{"ip_address": data['fixed_ip']}]
if data.get('binding__vnic_type'):
params['binding__vnic_type'] = data['binding__vnic_type']
if data.get('mac_state'):
params['mac_learning_enabled'] = data['mac_state']
if 'port_security_enabled' in data:
params['port_security_enabled'] = data['port_security_enabled']
port = api.neutron.port_create(request, **params)
msg = _('Port %s was successfully created.') % port['id']
messages.success(request, msg)
return port
except Exception as e:
LOG.info('Failed to create a port for network %(id)s: %(exc)s',
{'id': network_id, 'exc': e})
msg = _('Failed to create a port for network %s') % network_id
redirect = reverse(self.failure_url, args=(network_id,))
exceptions.handle(request, msg, redirect=redirect)

View File

@ -113,7 +113,7 @@ class NetworkPortTests(test.BaseAdminViewTests):
args=[network.id])
res = self.client.get(url)
self.assertTemplateUsed(res, 'admin/networks/ports/create.html')
self.assertTemplateUsed(res, views.WorkflowView.template_name)
@test.create_stubs({api.neutron: ('network_get',
'is_extension_supported',
@ -137,12 +137,6 @@ class NetworkPortTests(test.BaseAdminViewTests):
port_security=False):
network = self.networks.first()
port = self.ports.first()
api.neutron.network_get(IsA(http.HttpRequest),
network.id)\
.AndReturn(self.networks.first())
api.neutron.network_get(IsA(http.HttpRequest),
network.id)\
.AndReturn(self.networks.first())
api.neutron.network_get(IsA(http.HttpRequest),
network.id)\
.AndReturn(self.networks.first())
@ -205,14 +199,8 @@ class NetworkPortTests(test.BaseAdminViewTests):
network = self.networks.first()
port = self.ports.first()
api.neutron.network_get(IsA(http.HttpRequest),
network.id)\
.AndReturn(self.networks.first())
api.neutron.network_get(IsA(http.HttpRequest),
network.id)\
.AndReturn(self.networks.first())
api.neutron.network_get(IsA(http.HttpRequest),
network.id)\
.AndReturn(self.networks.first())
network.id) \
.MultipleTimes().AndReturn(self.networks.first())
api.neutron.is_extension_supported(IsA(http.HttpRequest),
'mac-learning')\
.AndReturn(True)
@ -280,12 +268,6 @@ class NetworkPortTests(test.BaseAdminViewTests):
port_security=False):
network = self.networks.first()
port = self.ports.first()
api.neutron.network_get(IsA(http.HttpRequest),
network.id)\
.AndReturn(self.networks.first())
api.neutron.network_get(IsA(http.HttpRequest),
network.id)\
.AndReturn(self.networks.first())
api.neutron.network_get(IsA(http.HttpRequest),
network.id)\
.AndReturn(self.networks.first())

View File

@ -15,14 +15,6 @@
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon.utils import memoized
from openstack_dashboard import api
from openstack_dashboard.dashboards.admin.networks.ports \
import forms as ports_forms
from openstack_dashboard.dashboards.admin.networks.ports \
import tables as ports_tables
from openstack_dashboard.dashboards.admin.networks.ports \
@ -33,42 +25,9 @@ from openstack_dashboard.dashboards.project.networks.ports \
import views as project_views
class CreateView(forms.ModalFormView):
form_class = ports_forms.CreatePort
form_id = "create_port_form"
submit_label = _("Create Port")
submit_url = "horizon:admin:networks:addport"
page_title = _("Create Port")
template_name = 'admin/networks/ports/create.html'
url = 'horizon:admin:networks:detail'
def get_success_url(self):
return reverse(self.url,
args=(self.kwargs['network_id'],))
@memoized.memoized_method
def get_object(self):
try:
network_id = self.kwargs["network_id"]
return api.neutron.network_get(self.request, network_id)
except Exception:
redirect = reverse(self.url,
args=(self.kwargs['network_id'],))
msg = _("Unable to retrieve network.")
exceptions.handle(self.request, msg, redirect=redirect)
def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs)
context['network'] = self.get_object()
args = (self.kwargs['network_id'],)
context['submit_url'] = reverse(self.submit_url, args=args)
context['cancel_url'] = reverse(self.url, args=args)
return context
def get_initial(self):
network = self.get_object()
return {"network_id": self.kwargs['network_id'],
"network_name": network.name}
class CreateView(project_views.CreateView):
workflow_class = admin_workflows.CreatePort
failure_url = 'horizon:admin:networks:detail'
class DetailView(project_views.DetailView):

View File

@ -27,6 +27,41 @@ from openstack_dashboard.dashboards.project.networks.ports \
LOG = logging.getLogger(__name__)
class CreatePortInfoAction(project_workflow.CreatePortInfoAction):
binding__host_id = forms.CharField(
label=_("Binding: Host"),
help_text=_("The ID of the host where the port is allocated. In some "
"cases, different implementations can run on different "
"hosts."),
required=False)
class Meta(object):
name = _("Info")
slug = 'create_info'
help_text_template = 'project/networks/ports/_create_port_help.html'
class CreatePortInfo(project_workflow.CreatePortInfo):
action_class = CreatePortInfoAction
depends_on = ("network_id", "target_tenant_id")
contributes = (project_workflow.CreatePortInfo.contributes
+ ['binding__host_id'])
class CreatePort(project_workflow.CreatePort):
default_steps = (CreatePortInfo,)
def get_success_url(self):
return reverse("horizon:admin:networks:detail",
args=(self.context['network_id'],))
def _construct_parameters(self, context):
params = super(CreatePort, self)._construct_parameters(context)
params.update({'tenant_id': context['target_tenant_id'],
'binding__host_id': context['binding__host_id']})
return params
class UpdatePortInfoAction(project_workflow.UpdatePortInfoAction):
device_id = forms.CharField(
max_length=100, label=_("Device ID"),

View File

@ -1,7 +0,0 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% block modal-body-right %}
<h3>{% trans "Description:" %}</h3>
<p>{% trans "You can create a port for the network. If you specify device ID to be attached, the device specified will be attached to the port created."%}</p>
{% endblock %}

View File

@ -1,7 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Create Port" %}{% endblock %}
{% block main %}
{% include "admin/networks/ports/_create.html" %}
{% endblock %}

View File

@ -1,220 +0,0 @@
# Copyright 2012 NEC Corporation
#
# 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 logging
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from neutronclient.common import exceptions as neutron_exc
from horizon import exceptions
from horizon import forms
from horizon import messages
from openstack_dashboard import api
LOG = logging.getLogger(__name__)
class CreatePort(forms.SelfHandlingForm):
name = forms.CharField(max_length=255,
label=_("Name"),
required=False)
admin_state = forms.BooleanField(label=_("Enable Admin State"),
initial=True,
required=False)
device_id = forms.CharField(max_length=100, label=_("Device ID"),
help_text=_("Device ID attached to the port"),
required=False)
device_owner = forms.CharField(
max_length=100, label=_("Device Owner"),
help_text=_("Owner of the device attached to the port"),
required=False)
specify_ip = forms.ThemableChoiceField(
label=_("Specify IP address or subnet"),
help_text=_("To specify a subnet or a fixed IP, select any options."),
required=False,
choices=[('', _("Unspecified")),
('subnet_id', _("Subnet")),
('fixed_ip', _("Fixed IP Address"))],
widget=forms.ThemableSelectWidget(attrs={
'class': 'switchable',
'data-slug': 'specify_ip',
}))
subnet_id = forms.ThemableChoiceField(
label=_("Subnet"),
required=False,
widget=forms.ThemableSelectWidget(attrs={
'class': 'switched',
'data-switch-on': 'specify_ip',
'data-specify_ip-subnet_id': _('Subnet'),
}))
fixed_ip = forms.IPField(
label=_("Fixed IP Address"),
required=False,
help_text=_("Specify the subnet IP address for the new port"),
version=forms.IPv4 | forms.IPv6,
widget=forms.TextInput(attrs={
'class': 'switched',
'data-switch-on': 'specify_ip',
'data-specify_ip-fixed_ip': _('Fixed IP Address'),
}))
mac_address = forms.MACAddressField(
label=_("MAC Address"),
required=False,
help_text=_("Specify the MAC address for the new port"))
mac_state = forms.BooleanField(
label=_("MAC Learning State"), initial=False,
required=False)
port_security_enabled = forms.BooleanField(
label=_("Port Security"),
help_text=_("Enable anti-spoofing rules for the port"),
initial=True,
required=False)
binding__vnic_type = forms.ThemableChoiceField(
label=_("VNIC Type"),
help_text=_("The VNIC type that is bound to the network port"),
required=False)
failure_url = 'horizon:project:networks:detail'
def __init__(self, request, *args, **kwargs):
super(CreatePort, self).__init__(request, *args, **kwargs)
# prepare subnet choices and input area for each subnet
subnet_choices = self._get_subnet_choices(kwargs['initial'])
if subnet_choices:
subnet_choices.insert(0, ('', _("Select a subnet")))
self.fields['subnet_id'].choices = subnet_choices
else:
self.fields['specify_ip'].widget = forms.HiddenInput()
self.fields['subnet_id'].widget = forms.HiddenInput()
self.fields['fixed_ip'].widget = forms.HiddenInput()
self._hide_field_if_not_supported(
request, 'mac_state', 'mac-learning',
_("Unable to retrieve MAC learning state"))
self._hide_field_if_not_supported(
request, 'port_security_enabled', 'port-security',
_("Unable to retrieve port security state"))
self._populate_vnic_type_choices(request)
def _hide_field_if_not_supported(self, request, field, extension_alias,
failure_message):
is_supproted = False
try:
is_supproted = api.neutron.is_extension_supported(
request, extension_alias)
except Exception:
exceptions.handle(self.request, failure_message)
if not is_supproted:
del self.fields[field]
return is_supproted
def _populate_vnic_type_choices(self, request):
neutron_settings = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {})
supported_vnic_types = neutron_settings.get('supported_vnic_types',
['*'])
# When a list of VNIC types is empty, hide the corresponding field.
if not supported_vnic_types:
del self.fields['binding__vnic_type']
return
binding_supported = self._hide_field_if_not_supported(
request, 'binding__vnic_type', 'binding',
_("Unable to verify the VNIC types extension in Neutron"))
if not binding_supported:
# binding__vnic_type field is already deleted, so return here
return
if supported_vnic_types == ['*']:
vnic_type_choices = api.neutron.VNIC_TYPES
else:
vnic_type_choices = [
vnic_type for vnic_type in api.neutron.VNIC_TYPES
if vnic_type[0] in supported_vnic_types
]
self.fields['binding__vnic_type'].choices = vnic_type_choices
def _get_subnet_choices(self, kwargs):
try:
network_id = kwargs['network_id']
network = api.neutron.network_get(self.request, network_id)
except Exception:
return []
# NOTE(amotoki): When a user cannot retrieve a subnet info,
# subnet ID is stored in network.subnets field.
# If so, we skip such subnet as subnet choices.
# This happens usually for external networks.
# TODO(amotoki): Ideally it is better to disable/hide
# Create Port button in the port table, but as of Pike
# the default neutron policy.json for "create_port" is empty
# and there seems no appropriate policy. This is a dirty hack.
return [(subnet.id, '%s %s' % (subnet.name_or_id, subnet.cidr))
for subnet in network.subnets
if isinstance(subnet, api.neutron.Subnet)]
def handle(self, request, data):
try:
params = {
'network_id': self.initial['network_id'],
'admin_state_up': data['admin_state'],
'name': data['name'],
'device_id': data['device_id'],
'device_owner': data['device_owner']
}
if data.get('specify_ip') == 'subnet_id':
if data.get('subnet_id'):
params['fixed_ips'] = [{"subnet_id": data['subnet_id']}]
elif data.get('specify_ip') == 'fixed_ip':
if data.get('fixed_ip'):
params['fixed_ips'] = [{"ip_address": data['fixed_ip']}]
if data.get('binding__vnic_type'):
params['binding__vnic_type'] = data['binding__vnic_type']
if data.get('mac_state'):
params['mac_learning_enabled'] = data['mac_state']
if 'port_security_enabled' in data:
params['port_security_enabled'] = data['port_security_enabled']
# Send mac_address only when it is specified.
if data['mac_address']:
params['mac_address'] = data['mac_address']
port = api.neutron.port_create(request, **params)
if port['name']:
msg = _('Port %s was successfully created.') % port['name']
else:
msg = _('Port %s was successfully created.') % port['id']
messages.success(request, msg)
return port
except Exception as e:
LOG.info('Failed to create a port for network %(id)s: %(exc)s',
{'id': self.initial['network_id'], 'exc': e})
if isinstance(e, neutron_exc.Forbidden):
msg = (_('You are not allowed to create a port '
'for network %s.')
% self.initial['network_id'])
else:
msg = (_('Failed to create a port for network %s')
% self.initial['network_id'])
redirect = reverse(self.failure_url,
args=(self.initial['network_id'],))
exceptions.handle(request, msg, redirect=redirect)

View File

@ -392,7 +392,7 @@ class NetworkPortTests(test.TestCase):
args=[network.id])
res = self.client.get(url)
self.assertTemplateUsed(res, 'project/networks/ports/create.html')
self.assertTemplateUsed(res, views.WorkflowView.template_name)
@test.create_stubs({api.neutron: ('network_get',
'is_extension_supported',
@ -446,7 +446,6 @@ class NetworkPortTests(test.TestCase):
**extension_kwargs) \
.AndReturn(port)
self.mox.ReplayAll()
form_data = {'network_id': port.network_id,
'network_name': network.name,
'name': port.name,

View File

@ -16,15 +16,12 @@ from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import forms
from horizon import tabs
from horizon.utils import memoized
from horizon import workflows
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.networks.ports \
import forms as project_forms
from openstack_dashboard.dashboards.project.networks.ports \
import tables as project_tables
from openstack_dashboard.dashboards.project.networks.ports \
@ -38,19 +35,9 @@ STATUS_DICT = dict(project_tables.STATUS_DISPLAY_CHOICES)
VNIC_TYPE_DICT = dict(api.neutron.VNIC_TYPES)
class CreateView(forms.ModalFormView):
form_class = project_forms.CreatePort
form_id = "create_port_form"
modal_header = _("Create Port")
submit_label = _("Create Port")
submit_url = "horizon:project:networks:addport"
page_title = _("Create Port")
template_name = 'project/networks/ports/create.html'
url = 'horizon:project:networks:detail'
def get_success_url(self):
return reverse(self.url,
args=(self.kwargs['network_id'],))
class CreateView(workflows.WorkflowView):
workflow_class = project_workflows.CreatePort
failure_url = 'horizon:project:networks:detail'
@memoized.memoized_method
def get_network(self):
@ -58,23 +45,16 @@ class CreateView(forms.ModalFormView):
network_id = self.kwargs["network_id"]
return api.neutron.network_get(self.request, network_id)
except Exception:
redirect = reverse(self.url,
redirect = reverse(self.failure_url,
args=(self.kwargs['network_id'],))
msg = _("Unable to retrieve network.")
exceptions.handle(self.request, msg, redirect=redirect)
def get_context_data(self, **kwargs):
context = super(CreateView, self).get_context_data(**kwargs)
context['network'] = self.get_network()
args = (self.kwargs['network_id'],)
context['submit_url'] = reverse(self.submit_url, args=args)
context['cancel_url'] = reverse(self.url, args=args)
return context
def get_initial(self):
network = self.get_network()
return {"network_id": self.kwargs['network_id'],
"network_name": network.name}
"network_name": network.name,
"target_tenant_id": network.tenant_id}
class DetailView(tabs.TabbedTableView):

View File

@ -32,6 +32,215 @@ from openstack_dashboard.utils import filters
LOG = logging.getLogger(__name__)
class CreatePortInfoAction(workflows.Action):
name = forms.CharField(max_length=255,
label=_("Name"),
required=False)
admin_state = forms.BooleanField(label=_("Enable Admin State"),
initial=True,
required=False)
device_id = forms.CharField(max_length=100, label=_("Device ID"),
help_text=_("Device ID attached to the port"),
required=False)
device_owner = forms.CharField(
max_length=100, label=_("Device Owner"),
help_text=_("Owner of the device attached to the port"),
required=False)
specify_ip = forms.ThemableChoiceField(
label=_("Specify IP address or subnet"),
help_text=_("To specify a subnet or a fixed IP, select any options."),
required=False,
choices=[('', _("Unspecified")),
('subnet_id', _("Subnet")),
('fixed_ip', _("Fixed IP Address"))],
widget=forms.ThemableSelectWidget(attrs={
'class': 'switchable',
'data-slug': 'specify_ip',
}))
subnet_id = forms.ThemableChoiceField(
label=_("Subnet"),
required=False,
widget=forms.ThemableSelectWidget(attrs={
'class': 'switched',
'data-switch-on': 'specify_ip',
'data-specify_ip-subnet_id': _('Subnet'),
}))
fixed_ip = forms.IPField(
label=_("Fixed IP Address"),
required=False,
help_text=_("Specify the subnet IP address for the new port"),
version=forms.IPv4 | forms.IPv6,
widget=forms.TextInput(attrs={
'class': 'switched',
'data-switch-on': 'specify_ip',
'data-specify_ip-fixed_ip': _('Fixed IP Address'),
}))
mac_address = forms.MACAddressField(
label=_("MAC Address"),
required=False,
help_text=_("Specify the MAC address for the new port"))
mac_state = forms.BooleanField(
label=_("MAC Learning State"), initial=False,
required=False)
port_security_enabled = forms.BooleanField(
label=_("Port Security"),
help_text=_("Enable anti-spoofing rules for the port"),
initial=True,
required=False)
binding__vnic_type = forms.ThemableChoiceField(
label=_("VNIC Type"),
help_text=_("The VNIC type that is bound to the network port"),
required=False)
def __init__(self, request, context, *args, **kwargs):
super(CreatePortInfoAction, self).__init__(
request, context, *args, **kwargs)
# prepare subnet choices and input area for each subnet
subnet_choices = self._get_subnet_choices(context)
if subnet_choices:
subnet_choices.insert(0, ('', _("Select a subnet")))
self.fields['subnet_id'].choices = subnet_choices
else:
self.fields['specify_ip'].widget = forms.HiddenInput()
self.fields['subnet_id'].widget = forms.HiddenInput()
self.fields['fixed_ip'].widget = forms.HiddenInput()
self._hide_field_if_not_supported(
request, 'mac_state', 'mac-learning',
_("Unable to retrieve MAC learning state"))
self._hide_field_if_not_supported(
request, 'port_security_enabled', 'port-security',
_("Unable to retrieve port security state"))
self._populate_vnic_type_choices(request)
def _hide_field_if_not_supported(self, request, field, extension_alias,
failure_message):
is_supproted = False
try:
is_supproted = api.neutron.is_extension_supported(
request, extension_alias)
except Exception:
exceptions.handle(self.request, failure_message)
if not is_supproted:
del self.fields[field]
return is_supproted
def _populate_vnic_type_choices(self, request):
neutron_settings = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {})
supported_vnic_types = neutron_settings.get('supported_vnic_types',
['*'])
# When a list of VNIC types is empty, hide the corresponding field.
if not supported_vnic_types:
del self.fields['binding__vnic_type']
return
binding_supported = self._hide_field_if_not_supported(
request, 'binding__vnic_type', 'binding',
_("Unable to verify the VNIC types extension in Neutron"))
if not binding_supported:
# binding__vnic_type field is already deleted, so return here
return
if supported_vnic_types == ['*']:
vnic_type_choices = api.neutron.VNIC_TYPES
else:
vnic_type_choices = [
vnic_type for vnic_type in api.neutron.VNIC_TYPES
if vnic_type[0] in supported_vnic_types
]
self.fields['binding__vnic_type'].choices = vnic_type_choices
def _get_subnet_choices(self, context):
try:
network_id = context['network_id']
network = api.neutron.network_get(self.request, network_id)
except Exception:
return []
# NOTE(amotoki): When a user cannot retrieve a subnet info,
# subnet ID is stored in network.subnets field.
# If so, we skip such subnet as subnet choices.
# This happens usually for external networks.
# TODO(amotoki): Ideally it is better to disable/hide
# Create Port button in the port table, but as of Pike
# the default neutron policy.json for "create_port" is empty
# and there seems no appropriate policy. This is a dirty hack.
return [(subnet.id, '%s %s' % (subnet.name_or_id, subnet.cidr))
for subnet in network.subnets
if isinstance(subnet, api.neutron.Subnet)]
class Meta(object):
name = _("Info")
slug = 'create_info'
help_text_template = 'project/networks/ports/_create_port_help.html'
class CreatePortInfo(workflows.Step):
action_class = CreatePortInfoAction
depends_on = ("network_id",)
contributes = ["name", "admin_state", "device_id", "device_owner",
"specify_ip", "subnet_id", "fixed_ip", "mac_address",
"mac_state", "port_security_enabled", "binding__vnic_type"]
class CreatePort(workflows.Workflow):
slug = "create_port"
name = _("Create Port")
finalize_button_name = _("Create")
success_message = _('Port %s was successfully created.')
failure_message = _('Failed to create port "%s".')
default_steps = (CreatePortInfo,)
def get_success_url(self):
return reverse("horizon:project:networks:detail",
args=(self.context['network_id'],))
def format_status_message(self, message):
name = self.context['name'] or self.context.get('port_id', '')
return message % name
def handle(self, request, context):
try:
params = self._construct_parameters(context)
port = api.neutron.port_create(request, **params)
self.context['port_id'] = port.id
return True
except Exception as e:
LOG.info('Failed to create a port for network %(id)s: %(exc)s',
{'id': context['network_id'], 'exc': e})
def _construct_parameters(self, context):
params = {
'network_id': context['network_id'],
'admin_state_up': context['admin_state'],
'name': context['name'],
'device_id': context['device_id'],
'device_owner': context['device_owner']
}
if context.get('specify_ip') == 'subnet_id':
if context.get('subnet_id'):
params['fixed_ips'] = [{"subnet_id": context['subnet_id']}]
elif context.get('specify_ip') == 'fixed_ip':
if context.get('fixed_ip'):
params['fixed_ips'] = [{"ip_address": context['fixed_ip']}]
if context.get('binding__vnic_type'):
params['binding__vnic_type'] = context['binding__vnic_type']
if context.get('mac_state'):
params['mac_learning_enabled'] = context['mac_state']
if 'port_security_enabled' in context:
params['port_security_enabled'] = context['port_security_enabled']
# Send mac_address only when it is specified.
if context['mac_address']:
params['mac_address'] = context['mac_address']
return params
class UpdatePortInfoAction(workflows.Action):
name = forms.CharField(max_length=255,
label=_("Name"),

View File

@ -1,11 +0,0 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% block modal-body-right %}
<h3>{% trans "Description:" %}</h3>
<p>{% blocktrans trimmed %} You can create a port for the network.
If you specify device ID to be attached, the device specified will
be attached to the port created.
{% endblocktrans %}
</p>
{% endblock %}

View File

@ -0,0 +1,8 @@
{% load i18n %}
<h3>{% trans "Description:" %}</h3>
<p>{% blocktrans trimmed %} You can create a port for the network.
If you specify device ID to be attached, the device specified will
be attached to the port created.
{% endblocktrans %}
</p>

View File

@ -1,7 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Create Port" %}{% endblock %}
{% block main %}
{% include "project/networks/ports/_create.html" %}
{% endblock %}