Allow regular users to specify VNIC type for port

VNIC type needs to be specified when creating a server with an SR-IOV
port. In this case, a user first creates a port with vnic_type=direct
and creates a server with the created port. To allow this scenario,
horizon needs to allow users to specify VNIC type for port.

This commit also clean up the code duplication on the port security and
mac state fields in the port create form. The code in the admin form for
them are completely duplicated with that in the project form.

Change-Id: Ib6e91ed7f720e2720994025429da0dcef2fa4e25
Closes-Bug: #1402959
This commit is contained in:
Akihiro Motoki 2017-10-21 00:48:42 +00:00
parent 98d0714939
commit 09efe2d432
2 changed files with 56 additions and 62 deletions

View File

@ -14,7 +14,6 @@
import logging
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
@ -39,56 +38,6 @@ class CreatePort(project_forms.CreatePort):
required=False)
failure_url = 'horizon:admin:networks:detail'
def __init__(self, request, *args, **kwargs):
super(CreatePort, self).__init__(request, *args, **kwargs)
try:
if api.neutron.is_extension_supported(request, 'binding'):
neutron_settings = getattr(settings,
'OPENSTACK_NEUTRON_NETWORK', {})
supported_vnic_types = neutron_settings.get(
'supported_vnic_types', ['*'])
if supported_vnic_types:
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'] = \
forms.ThemableChoiceField(
choices=vnic_type_choices,
label=_("Binding: VNIC Type"),
help_text=_(
"The VNIC type that is bound to the neutron "
"port"),
required=False)
except Exception:
msg = _("Unable to verify the VNIC types extension in Neutron")
exceptions.handle(self.request, msg)
try:
if api.neutron.is_extension_supported(request, 'mac-learning'):
self.fields['mac_state'] = forms.BooleanField(
label=_("MAC Learning State"), initial=False,
required=False)
except Exception:
msg = _("Unable to retrieve MAC learning state")
exceptions.handle(self.request, msg)
try:
if api.neutron.is_extension_supported(request, 'port-security'):
self.fields['port_security_enabled'] = forms.BooleanField(
label=_("Port Security"),
help_text=_("Enable anti-spoofing rules for the port"),
initial=True,
required=False)
except Exception:
msg = _("Unable to retrieve port security state")
exceptions.handle(self.request, msg)
def handle(self, request, data):
network_id = self.initial['network_id']
try:

View File

@ -14,6 +14,7 @@
import logging
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
@ -76,6 +77,19 @@ class CreatePort(forms.SelfHandlingForm):
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):
@ -91,20 +105,51 @@ class CreatePort(forms.SelfHandlingForm):
self.fields['subnet_id'].widget = forms.HiddenInput()
self.fields['fixed_ip'].widget = forms.HiddenInput()
if api.neutron.is_extension_supported(request, 'mac-learning'):
self.fields['mac_state'] = forms.BooleanField(
label=_("MAC Learning State"), initial=False, required=False)
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:
if api.neutron.is_extension_supported(request, 'port-security'):
self.fields['port_security_enabled'] = forms.BooleanField(
label=_("Port Security"),
help_text=_("Enable anti-spoofing rules for the port"),
initial=True,
required=False)
is_supproted = api.neutron.is_extension_supported(
request, extension_alias)
except Exception:
msg = _("Unable to retrieve port security state")
exceptions.handle(self.request, msg)
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: