Merge "Adds initial SRIOV creation/config support"
This commit is contained in:
commit
a174b4294d
@ -678,6 +678,7 @@ Default::
|
|||||||
'enable_vpn': True,
|
'enable_vpn': True,
|
||||||
'profile_support': None,
|
'profile_support': None,
|
||||||
'supported_provider_types': ["*"],
|
'supported_provider_types': ["*"],
|
||||||
|
'supported_vnic_types': ["*"],
|
||||||
'segmentation_id_range': {}
|
'segmentation_id_range': {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,6 +804,19 @@ be available to choose from.
|
|||||||
|
|
||||||
Example: ``['local', 'flat', 'gre']``
|
Example: ``['local', 'flat', 'gre']``
|
||||||
|
|
||||||
|
``supported_vnic_types``:
|
||||||
|
|
||||||
|
.. versionadded:: 2015.1(Kilo)
|
||||||
|
|
||||||
|
Default ``['*']``
|
||||||
|
|
||||||
|
For use with the port binding extension. Use this to explicitly set which VNIC
|
||||||
|
types are supported; only those listed will be shown when creating or editing
|
||||||
|
a port. VNIC types include normal, direct and macvtap. By default all VNIC
|
||||||
|
types will be available to choose from.
|
||||||
|
|
||||||
|
Example ``['normal', 'direct']``
|
||||||
|
|
||||||
``segmentation_id_range``:
|
``segmentation_id_range``:
|
||||||
|
|
||||||
.. versionadded:: 2014.2(Juno)
|
.. versionadded:: 2014.2(Juno)
|
||||||
|
@ -88,9 +88,9 @@ class Network(NeutronAPIDictWrapper):
|
|||||||
def __init__(self, apiresource):
|
def __init__(self, apiresource):
|
||||||
apiresource['admin_state'] = \
|
apiresource['admin_state'] = \
|
||||||
'UP' if apiresource['admin_state_up'] else 'DOWN'
|
'UP' if apiresource['admin_state_up'] else 'DOWN'
|
||||||
# Django cannot handle a key name with a colon, so remap another key
|
# Django cannot handle a key name with ':', so use '__'
|
||||||
for key in apiresource.keys():
|
for key in apiresource.keys():
|
||||||
if key.find(':'):
|
if ':' in key:
|
||||||
apiresource['__'.join(key.split(':'))] = apiresource[key]
|
apiresource['__'.join(key.split(':'))] = apiresource[key]
|
||||||
super(Network, self).__init__(apiresource)
|
super(Network, self).__init__(apiresource)
|
||||||
|
|
||||||
@ -112,6 +112,10 @@ class Port(NeutronAPIDictWrapper):
|
|||||||
"""Wrapper for neutron ports."""
|
"""Wrapper for neutron ports."""
|
||||||
|
|
||||||
def __init__(self, apiresource):
|
def __init__(self, apiresource):
|
||||||
|
# Django cannot handle a key name with ':', so use '__'
|
||||||
|
for key in apiresource.keys():
|
||||||
|
if ':' in key:
|
||||||
|
apiresource['__'.join(key.split(':'))] = apiresource[key]
|
||||||
apiresource['admin_state'] = \
|
apiresource['admin_state'] = \
|
||||||
'UP' if apiresource['admin_state_up'] else 'DOWN'
|
'UP' if apiresource['admin_state_up'] else 'DOWN'
|
||||||
if 'mac_learning_enabled' in apiresource:
|
if 'mac_learning_enabled' in apiresource:
|
||||||
@ -729,6 +733,13 @@ def port_get(request, port_id, **params):
|
|||||||
return Port(port)
|
return Port(port)
|
||||||
|
|
||||||
|
|
||||||
|
def unescape_port_kwargs(**kwargs):
|
||||||
|
for key in kwargs:
|
||||||
|
if '__' in key:
|
||||||
|
kwargs[':'.join(key.split('__'))] = kwargs.pop(key)
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
def port_create(request, network_id, **kwargs):
|
def port_create(request, network_id, **kwargs):
|
||||||
"""Create a port on a specified network.
|
"""Create a port on a specified network.
|
||||||
|
|
||||||
@ -743,6 +754,7 @@ def port_create(request, network_id, **kwargs):
|
|||||||
# In the case policy profiles are being used, profile id is needed.
|
# In the case policy profiles are being used, profile id is needed.
|
||||||
if 'policy_profile_id' in kwargs:
|
if 'policy_profile_id' in kwargs:
|
||||||
kwargs['n1kv:profile_id'] = kwargs.pop('policy_profile_id')
|
kwargs['n1kv:profile_id'] = kwargs.pop('policy_profile_id')
|
||||||
|
kwargs = unescape_port_kwargs(**kwargs)
|
||||||
body = {'port': {'network_id': network_id}}
|
body = {'port': {'network_id': network_id}}
|
||||||
if 'tenant_id' not in kwargs:
|
if 'tenant_id' not in kwargs:
|
||||||
kwargs['tenant_id'] = request.user.project_id
|
kwargs['tenant_id'] = request.user.project_id
|
||||||
@ -758,6 +770,7 @@ def port_delete(request, port_id):
|
|||||||
|
|
||||||
def port_update(request, port_id, **kwargs):
|
def port_update(request, port_id, **kwargs):
|
||||||
LOG.debug("port_update(): portid=%s, kwargs=%s" % (port_id, kwargs))
|
LOG.debug("port_update(): portid=%s, kwargs=%s" % (port_id, kwargs))
|
||||||
|
kwargs = unescape_port_kwargs(**kwargs)
|
||||||
body = {'port': kwargs}
|
body = {'port': kwargs}
|
||||||
port = neutronclient(request).update_port(port_id, body=body).get('port')
|
port = neutronclient(request).update_port(port_id, body=body).get('port')
|
||||||
return Port(port)
|
return Port(port)
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
@ -27,6 +28,8 @@ from openstack_dashboard.dashboards.project.networks.ports \
|
|||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
VNIC_TYPES = [('normal', _('Normal')), ('direct', _('Direct')),
|
||||||
|
('macvtap', _('MacVTap'))]
|
||||||
|
|
||||||
|
|
||||||
class CreatePort(forms.SelfHandlingForm):
|
class CreatePort(forms.SelfHandlingForm):
|
||||||
@ -49,9 +52,36 @@ class CreatePort(forms.SelfHandlingForm):
|
|||||||
help_text=_("Device owner attached to the "
|
help_text=_("Device owner attached to the "
|
||||||
"port"),
|
"port"),
|
||||||
required=False)
|
required=False)
|
||||||
|
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 __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(CreatePort, self).__init__(request, *args, **kwargs)
|
super(CreatePort, self).__init__(request, *args, **kwargs)
|
||||||
|
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 == ['*']:
|
||||||
|
vnic_type_choices = VNIC_TYPES
|
||||||
|
else:
|
||||||
|
vnic_type_choices = [
|
||||||
|
vnic_type for vnic_type in VNIC_TYPES
|
||||||
|
if vnic_type[0] in supported_vnic_types
|
||||||
|
]
|
||||||
|
|
||||||
|
self.fields['binding__vnic_type'] = forms.ChoiceField(
|
||||||
|
choices=vnic_type_choices,
|
||||||
|
label=_("Binding: VNIC Type"),
|
||||||
|
help_text=_("The VNIC type that is bound to the neutron port"),
|
||||||
|
required=False)
|
||||||
|
|
||||||
if api.neutron.is_extension_supported(request, 'mac-learning'):
|
if api.neutron.is_extension_supported(request, 'mac-learning'):
|
||||||
self.fields['mac_state'] = forms.BooleanField(
|
self.fields['mac_state'] = forms.BooleanField(
|
||||||
label=_("MAC Learning State"), initial=False, required=False)
|
label=_("MAC Learning State"), initial=False, required=False)
|
||||||
@ -78,7 +108,7 @@ class CreatePort(forms.SelfHandlingForm):
|
|||||||
msg = _('Failed to create a port for network %s') \
|
msg = _('Failed to create a port for network %s') \
|
||||||
% data['network_id']
|
% data['network_id']
|
||||||
LOG.info(msg)
|
LOG.info(msg)
|
||||||
redirect = reverse('horizon:admin:networks:detail',
|
redirect = reverse(self.failure_url,
|
||||||
args=(data['network_id'],))
|
args=(data['network_id'],))
|
||||||
exceptions.handle(request, msg, redirect=redirect)
|
exceptions.handle(request, msg, redirect=redirect)
|
||||||
|
|
||||||
@ -92,6 +122,13 @@ class UpdatePort(project_forms.UpdatePort):
|
|||||||
help_text=_("Device owner attached to the "
|
help_text=_("Device owner attached to the "
|
||||||
"port"),
|
"port"),
|
||||||
required=False)
|
required=False)
|
||||||
|
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'
|
failure_url = 'horizon:admin:networks:detail'
|
||||||
|
|
||||||
def handle(self, request, data):
|
def handle(self, request, data):
|
||||||
@ -99,13 +136,21 @@ class UpdatePort(project_forms.UpdatePort):
|
|||||||
LOG.debug('params = %s' % data)
|
LOG.debug('params = %s' % data)
|
||||||
extension_kwargs = {}
|
extension_kwargs = {}
|
||||||
data['admin_state'] = (data['admin_state'] == 'True')
|
data['admin_state'] = (data['admin_state'] == 'True')
|
||||||
|
if 'binding__vnic_type' in data:
|
||||||
|
extension_kwargs['binding__vnic_type'] = \
|
||||||
|
data['binding__vnic_type']
|
||||||
|
|
||||||
if 'mac_state' in data:
|
if 'mac_state' in data:
|
||||||
extension_kwargs['mac_learning_enabled'] = data['mac_state']
|
extension_kwargs['mac_learning_enabled'] = data['mac_state']
|
||||||
port = api.neutron.port_update(request, data['port_id'],
|
|
||||||
|
port = api.neutron.port_update(request,
|
||||||
|
data['port_id'],
|
||||||
name=data['name'],
|
name=data['name'],
|
||||||
admin_state_up=data['admin_state'],
|
admin_state_up=data['admin_state'],
|
||||||
device_id=data['device_id'],
|
device_id=data['device_id'],
|
||||||
device_owner=data['device_owner'],
|
device_owner=data['device_owner'],
|
||||||
|
binding__host_id=data
|
||||||
|
['binding__host_id'],
|
||||||
**extension_kwargs)
|
**extension_kwargs)
|
||||||
msg = _('Port %s was successfully updated.') % data['port_id']
|
msg = _('Port %s was successfully updated.') % data['port_id']
|
||||||
LOG.debug(msg)
|
LOG.debug(msg)
|
||||||
|
@ -73,36 +73,14 @@ class CreatePort(tables.LinkAction):
|
|||||||
return reverse(self.url, args=(network_id,))
|
return reverse(self.url, args=(network_id,))
|
||||||
|
|
||||||
|
|
||||||
class UpdatePort(policy.PolicyTargetMixin, tables.LinkAction):
|
class UpdatePort(project_tables.UpdatePort):
|
||||||
name = "update"
|
|
||||||
verbose_name = _("Edit Port")
|
|
||||||
url = "horizon:admin:networks:editport"
|
url = "horizon:admin:networks:editport"
|
||||||
classes = ("ajax-modal",)
|
|
||||||
icon = "pencil"
|
|
||||||
policy_rules = (("network", "update_port"),)
|
|
||||||
|
|
||||||
def get_link_url(self, port):
|
|
||||||
network_id = self.table.kwargs['network_id']
|
|
||||||
return reverse(self.url, args=(network_id, port.id))
|
|
||||||
|
|
||||||
|
|
||||||
class PortsTable(tables.DataTable):
|
class PortsTable(project_tables.PortsTable):
|
||||||
name = tables.Column("name_or_id",
|
name = tables.Column("name_or_id",
|
||||||
verbose_name=_("Name"),
|
verbose_name=_("Name"),
|
||||||
link="horizon:admin:networks:ports:detail")
|
link="horizon:admin:networks:ports:detail")
|
||||||
fixed_ips = tables.Column(
|
|
||||||
project_tables.get_fixed_ips, verbose_name=_("Fixed IPs"))
|
|
||||||
device_id = tables.Column(
|
|
||||||
project_tables.get_attached, verbose_name=_("Device Attached"))
|
|
||||||
status = tables.Column(
|
|
||||||
"status",
|
|
||||||
verbose_name=_("Status"),
|
|
||||||
display_choices=project_tables.STATUS_DISPLAY_CHOICES)
|
|
||||||
admin_state = tables.Column("admin_state",
|
|
||||||
verbose_name=_("Admin State"),
|
|
||||||
display_choices=project_tables.DISPLAY_CHOICES)
|
|
||||||
mac_state = tables.Column("mac_state", empty_value=api.neutron.OFF_STATE,
|
|
||||||
verbose_name=_("Mac Learning State"))
|
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = "ports"
|
name = "ports"
|
||||||
@ -110,10 +88,3 @@ class PortsTable(tables.DataTable):
|
|||||||
table_actions = (CreatePort, DeletePort)
|
table_actions = (CreatePort, DeletePort)
|
||||||
row_actions = (UpdatePort, DeletePort,)
|
row_actions = (UpdatePort, DeletePort,)
|
||||||
hidden_title = False
|
hidden_title = False
|
||||||
|
|
||||||
def __init__(self, request, data=None, needs_form_wrapper=None, **kwargs):
|
|
||||||
super(PortsTable, self).__init__(request, data=data,
|
|
||||||
needs_form_wrapper=needs_form_wrapper,
|
|
||||||
**kwargs)
|
|
||||||
if not api.neutron.is_extension_supported(request, 'mac-learning'):
|
|
||||||
del self.columns['mac_state']
|
|
||||||
|
@ -12,31 +12,13 @@
|
|||||||
# 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.core.urlresolvers import reverse
|
from openstack_dashboard.dashboards.project.networks.ports \
|
||||||
from django.utils.translation import ugettext_lazy as _
|
import tabs as project_tabs
|
||||||
|
|
||||||
from horizon import exceptions
|
|
||||||
from horizon import tabs
|
|
||||||
|
|
||||||
from openstack_dashboard import api
|
|
||||||
|
|
||||||
|
|
||||||
class OverviewTab(tabs.Tab):
|
class OverviewTab(project_tabs.OverviewTab):
|
||||||
name = _("Overview")
|
template_name = "admin/networks/ports/_detail_overview.html"
|
||||||
slug = "overview"
|
|
||||||
template_name = "project/networks/ports/_detail_overview.html"
|
|
||||||
|
|
||||||
def get_context_data(self, request):
|
|
||||||
port_id = self.tab_group.kwargs['port_id']
|
|
||||||
try:
|
|
||||||
port = api.neutron.port_get(self.request, port_id)
|
|
||||||
except Exception:
|
|
||||||
redirect = reverse('horizon:admin:networks:index')
|
|
||||||
msg = _('Unable to retrieve port details.')
|
|
||||||
exceptions.handle(request, msg, redirect=redirect)
|
|
||||||
return {'port': port}
|
|
||||||
|
|
||||||
|
|
||||||
class PortDetailTabs(tabs.TabGroup):
|
class PortDetailTabs(project_tabs.PortDetailTabs):
|
||||||
slug = "port_details"
|
|
||||||
tabs = (OverviewTab,)
|
tabs = (OverviewTab,)
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
from django.conf.urls import patterns
|
from django.conf.urls import patterns
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.project.networks.ports import views
|
from openstack_dashboard.dashboards.admin.networks.ports import views
|
||||||
|
|
||||||
PORTS = r'^(?P<port_id>[^/]+)/%s$'
|
PORTS = r'^(?P<port_id>[^/]+)/%s$'
|
||||||
VIEW_MOD = 'openstack_dashboard.dashboards.admin.networks.ports.views'
|
VIEW_MOD = 'openstack_dashboard.dashboards.admin.networks.ports.views'
|
||||||
|
@ -20,26 +20,29 @@ from horizon import forms
|
|||||||
from horizon.utils import memoized
|
from horizon.utils import memoized
|
||||||
|
|
||||||
from openstack_dashboard import api
|
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 \
|
||||||
|
import tabs as ports_tabs
|
||||||
from openstack_dashboard.dashboards.project.networks.ports \
|
from openstack_dashboard.dashboards.project.networks.ports \
|
||||||
import views as project_views
|
import views as project_views
|
||||||
|
|
||||||
from openstack_dashboard.dashboards.admin.networks.ports \
|
|
||||||
import forms as project_forms
|
|
||||||
|
|
||||||
|
|
||||||
class CreateView(forms.ModalFormView):
|
class CreateView(forms.ModalFormView):
|
||||||
form_class = project_forms.CreatePort
|
form_class = ports_forms.CreatePort
|
||||||
form_id = "create_port_form"
|
form_id = "create_port_form"
|
||||||
modal_header = _("Create Port")
|
modal_header = _("Create Port")
|
||||||
template_name = 'admin/networks/ports/create.html'
|
|
||||||
submit_label = _("Create Port")
|
submit_label = _("Create Port")
|
||||||
submit_url = "horizon:admin:networks:addport"
|
submit_url = "horizon:admin:networks:addport"
|
||||||
success_url = 'horizon:admin:networks:detail'
|
|
||||||
failure_url = 'horizon:admin:networks:detail'
|
|
||||||
page_title = _("Create Port")
|
page_title = _("Create Port")
|
||||||
|
template_name = 'admin/networks/ports/create.html'
|
||||||
|
url = 'horizon:admin:networks:detail'
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse(self.success_url,
|
return reverse(self.url,
|
||||||
args=(self.kwargs['network_id'],))
|
args=(self.kwargs['network_id'],))
|
||||||
|
|
||||||
@memoized.memoized_method
|
@memoized.memoized_method
|
||||||
@ -48,7 +51,7 @@ class CreateView(forms.ModalFormView):
|
|||||||
network_id = self.kwargs["network_id"]
|
network_id = self.kwargs["network_id"]
|
||||||
return api.neutron.network_get(self.request, network_id)
|
return api.neutron.network_get(self.request, network_id)
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse(self.failure_url,
|
redirect = reverse(self.url,
|
||||||
args=(self.kwargs['network_id'],))
|
args=(self.kwargs['network_id'],))
|
||||||
msg = _("Unable to retrieve network.")
|
msg = _("Unable to retrieve network.")
|
||||||
exceptions.handle(self.request, msg, redirect=redirect)
|
exceptions.handle(self.request, msg, redirect=redirect)
|
||||||
@ -66,9 +69,32 @@ class CreateView(forms.ModalFormView):
|
|||||||
"network_name": network.name}
|
"network_name": network.name}
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(project_views.DetailView):
|
||||||
|
tab_group_class = ports_tabs.PortDetailTabs
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(DetailView, self).get_context_data(**kwargs)
|
||||||
|
port = context["port"]
|
||||||
|
table = ports_tables.PortsTable(self.request,
|
||||||
|
network_id=port.network_id)
|
||||||
|
context["url"] = reverse('horizon:admin:networks:index')
|
||||||
|
context["actions"] = table.render_row_actions(port)
|
||||||
|
return context
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_redirect_url():
|
||||||
|
return reverse('horizon:admin:networks:index')
|
||||||
|
|
||||||
|
|
||||||
class UpdateView(project_views.UpdateView):
|
class UpdateView(project_views.UpdateView):
|
||||||
form_class = project_forms.UpdatePort
|
form_class = ports_forms.UpdatePort
|
||||||
template_name = 'admin/networks/ports/update.html'
|
template_name = 'admin/networks/ports/update.html'
|
||||||
context_object_name = 'port'
|
context_object_name = 'port'
|
||||||
submit_url = "horizon:admin:networks:editport"
|
submit_url = "horizon:admin:networks:editport"
|
||||||
success_url = 'horizon:admin:networks:detail'
|
success_url = 'horizon:admin:networks:detail'
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
initial = super(UpdateView, self).get_initial()
|
||||||
|
port = self._get_object()
|
||||||
|
initial['binding__host_id'] = port['binding__host_id']
|
||||||
|
return initial
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
{% load i18n sizeformat %}
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd>{{ port.name|default:_("None") }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ port.id|default:_("None") }}</dd>
|
||||||
|
{% url 'horizon:project:networks:detail' port.network_id as network_url %}
|
||||||
|
<dt>{% trans "Network ID" %}</dt>
|
||||||
|
<dd><a href="{{ network_url }}">{{ port.network_id|default:_("None") }}</a></dd>
|
||||||
|
<dt>{% trans "Project ID" %}</dt>
|
||||||
|
<dd>{{ port.tenant_id|default:_("-") }}</dd>
|
||||||
|
<dt>{% trans "MAC Address" %}</dt>
|
||||||
|
<dd>{{ port.mac_address|default:_("None") }}</dd>
|
||||||
|
<dt>{% trans "Status" %}</dt>
|
||||||
|
<dd>{{ port.status_label|default:_("None") }}</dd>
|
||||||
|
<dt>{% trans "Admin State" %}</dt>
|
||||||
|
<dd>{{ port.admin_state_label|default:_("None") }}</dd>
|
||||||
|
{% if port.mac_state %}
|
||||||
|
<dt>{% trans "MAC Learning State" %}</dt>
|
||||||
|
<dd>{% trans "On" %}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<h4>{% trans "Fixed IP" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
{% if port.fixed_ips.items|length > 1 %}
|
||||||
|
{% for ip in port.fixed_ips %}
|
||||||
|
<dt>{% trans "IP Address" %}</dt>
|
||||||
|
<dd>{{ ip.ip_address }}</dd>
|
||||||
|
{% url 'horizon:project:networks:subnets:detail' ip.subnet_id as subnet_url %}
|
||||||
|
<dt>{% trans "Subnet ID" %}</dt>
|
||||||
|
<dd><a href="{{ subnet_url }}">{{ ip.subnet_id }}</a></dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<dd>{% trans "None" %}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<h4>{% trans "Attached Device" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
{% if port.device_id|length > 1 or port.device_owner %}
|
||||||
|
<dt>{% trans "Device Owner" %}</dt>
|
||||||
|
<dd>{{ port.device_owner|default:_("None") }}</dd>
|
||||||
|
<dt>{% trans "Device ID" %}</dt>
|
||||||
|
<dd>{{ port.device_id|default:_("None") }}</dd>
|
||||||
|
{% else %}
|
||||||
|
<dd>{% trans "No attached device" %}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<h4>{% trans "Binding" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dt>{% trans "Host" %}</dt>
|
||||||
|
<dd>{{ port.binding__host_id|default:_("None") }}</dd>
|
||||||
|
<dt>{% trans "Profile" %}</dt>
|
||||||
|
<dd>{{ port.binding__profile|default:_("None") }}</dd>
|
||||||
|
<dt>{% trans "VIF Type" %}</dt>
|
||||||
|
<dd>{{ port.binding__vif_type|replace_underscores }}</dd>
|
||||||
|
<dt>{% trans "VIF Details" %}</dt>
|
||||||
|
{% if port.binding__vif_details.items %}
|
||||||
|
<dd>
|
||||||
|
<ul>
|
||||||
|
{% for key,value in port.binding__vif_details.items %}
|
||||||
|
<li><b>{{ key }}</b> {{ value }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
{% else %}
|
||||||
|
<dd>{% trans "None" %}</dd>
|
||||||
|
{% endif %}
|
||||||
|
{% if port.binding__vnic_type %}
|
||||||
|
<dt>{% trans "VNIC Type" %}</dt>
|
||||||
|
<dd>{{ port.binding__vnic_type }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
@ -975,7 +975,9 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'mac-learning')\
|
||||||
|
.AndReturn(mac_learning)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
res = self.client.get(reverse('horizon:admin:networks:ports:detail',
|
res = self.client.get(reverse('horizon:admin:networks:ports:detail',
|
||||||
@ -997,7 +999,7 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
|
|
||||||
# admin DetailView is shared with userpanel one, so
|
# admin DetailView is shared with userpanel one, so
|
||||||
# redirection URL on error is userpanel index.
|
# redirection URL on error is userpanel index.
|
||||||
redir_url = reverse('horizon:project:networks:index')
|
redir_url = reverse('horizon:admin:networks:index')
|
||||||
self.assertRedirectsNoFollow(res, redir_url)
|
self.assertRedirectsNoFollow(res, redir_url)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',
|
@test.create_stubs({api.neutron: ('network_get',
|
||||||
@ -1010,11 +1012,14 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
def test_port_create_get_with_mac_learning(self):
|
def test_port_create_get_with_mac_learning(self):
|
||||||
self._test_port_create_get(mac_learning=True)
|
self._test_port_create_get(mac_learning=True)
|
||||||
|
|
||||||
def _test_port_create_get(self, mac_learning=False):
|
def _test_port_create_get(self, mac_learning=False, binding=False):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id)\
|
network.id)\
|
||||||
.AndReturn(self.networks.first())
|
.AndReturn(self.networks.first())
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'binding')\
|
||||||
|
.AndReturn(binding)
|
||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
@ -1036,9 +1041,9 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
'is_extension_supported',
|
'is_extension_supported',
|
||||||
'port_create',)})
|
'port_create',)})
|
||||||
def test_port_create_post_with_mac_learning(self):
|
def test_port_create_post_with_mac_learning(self):
|
||||||
self._test_port_create_post(mac_learning=True)
|
self._test_port_create_post(mac_learning=True, binding=False)
|
||||||
|
|
||||||
def _test_port_create_post(self, mac_learning=False):
|
def _test_port_create_post(self, mac_learning=False, binding=False):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
port = self.ports.first()
|
port = self.ports.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
@ -1047,10 +1052,16 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id)\
|
network.id)\
|
||||||
.AndReturn(self.networks.first())
|
.AndReturn(self.networks.first())
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'binding')\
|
||||||
|
.AndReturn(binding)
|
||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
extension_kwargs = {}
|
extension_kwargs = {}
|
||||||
|
if binding:
|
||||||
|
extension_kwargs['binding__vnic_type'] = \
|
||||||
|
port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
extension_kwargs['mac_learning_enabled'] = True
|
extension_kwargs['mac_learning_enabled'] = True
|
||||||
api.neutron.port_create(IsA(http.HttpRequest),
|
api.neutron.port_create(IsA(http.HttpRequest),
|
||||||
@ -1060,6 +1071,7 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
admin_state_up=port.admin_state_up,
|
admin_state_up=port.admin_state_up,
|
||||||
device_id=port.device_id,
|
device_id=port.device_id,
|
||||||
device_owner=port.device_owner,
|
device_owner=port.device_owner,
|
||||||
|
binding__host_id=port.binding__host_id,
|
||||||
**extension_kwargs)\
|
**extension_kwargs)\
|
||||||
.AndReturn(port)
|
.AndReturn(port)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
@ -1069,7 +1081,10 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
'name': port.name,
|
'name': port.name,
|
||||||
'admin_state': port.admin_state_up,
|
'admin_state': port.admin_state_up,
|
||||||
'device_id': port.device_id,
|
'device_id': port.device_id,
|
||||||
'device_owner': port.device_owner}
|
'device_owner': port.device_owner,
|
||||||
|
'binding__host_id': port.binding__host_id}
|
||||||
|
if binding:
|
||||||
|
form_data['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
form_data['mac_state'] = True
|
form_data['mac_state'] = True
|
||||||
url = reverse('horizon:admin:networks:addport',
|
url = reverse('horizon:admin:networks:addport',
|
||||||
@ -1093,7 +1108,8 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
def test_port_create_post_exception_with_mac_learning(self):
|
def test_port_create_post_exception_with_mac_learning(self):
|
||||||
self._test_port_create_post_exception(mac_learning=True)
|
self._test_port_create_post_exception(mac_learning=True)
|
||||||
|
|
||||||
def _test_port_create_post_exception(self, mac_learning=False):
|
def _test_port_create_post_exception(self, mac_learning=False,
|
||||||
|
binding=False):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
port = self.ports.first()
|
port = self.ports.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
@ -1102,10 +1118,15 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id)\
|
network.id)\
|
||||||
.AndReturn(self.networks.first())
|
.AndReturn(self.networks.first())
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'binding')\
|
||||||
|
.AndReturn(binding)
|
||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
extension_kwargs = {}
|
extension_kwargs = {}
|
||||||
|
if binding:
|
||||||
|
extension_kwargs['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
extension_kwargs['mac_learning_enabled'] = True
|
extension_kwargs['mac_learning_enabled'] = True
|
||||||
api.neutron.port_create(IsA(http.HttpRequest),
|
api.neutron.port_create(IsA(http.HttpRequest),
|
||||||
@ -1115,6 +1136,7 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
admin_state_up=port.admin_state_up,
|
admin_state_up=port.admin_state_up,
|
||||||
device_id=port.device_id,
|
device_id=port.device_id,
|
||||||
device_owner=port.device_owner,
|
device_owner=port.device_owner,
|
||||||
|
binding__host_id=port.binding__host_id,
|
||||||
**extension_kwargs)\
|
**extension_kwargs)\
|
||||||
.AndRaise(self.exceptions.neutron)
|
.AndRaise(self.exceptions.neutron)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
@ -1125,7 +1147,10 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
'admin_state': port.admin_state_up,
|
'admin_state': port.admin_state_up,
|
||||||
'mac_state': True,
|
'mac_state': True,
|
||||||
'device_id': port.device_id,
|
'device_id': port.device_id,
|
||||||
'device_owner': port.device_owner}
|
'device_owner': port.device_owner,
|
||||||
|
'binding__host_id': port.binding__host_id}
|
||||||
|
if binding:
|
||||||
|
form_data['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
form_data['mac_learning_enabled'] = True
|
form_data['mac_learning_enabled'] = True
|
||||||
url = reverse('horizon:admin:networks:addport',
|
url = reverse('horizon:admin:networks:addport',
|
||||||
@ -1147,11 +1172,14 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
def test_port_update_get_with_mac_learning(self):
|
def test_port_update_get_with_mac_learning(self):
|
||||||
self._test_port_update_get(mac_learning=True)
|
self._test_port_update_get(mac_learning=True)
|
||||||
|
|
||||||
def _test_port_update_get(self, mac_learning=False):
|
def _test_port_update_get(self, mac_learning=False, binding=False):
|
||||||
port = self.ports.first()
|
port = self.ports.first()
|
||||||
api.neutron.port_get(IsA(http.HttpRequest),
|
api.neutron.port_get(IsA(http.HttpRequest),
|
||||||
port.id)\
|
port.id)\
|
||||||
.AndReturn(port)
|
.AndReturn(port)
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'binding')\
|
||||||
|
.AndReturn(binding)
|
||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
@ -1175,14 +1203,19 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
def test_port_update_post_with_mac_learning(self):
|
def test_port_update_post_with_mac_learning(self):
|
||||||
self._test_port_update_post(mac_learning=True)
|
self._test_port_update_post(mac_learning=True)
|
||||||
|
|
||||||
def _test_port_update_post(self, mac_learning=False):
|
def _test_port_update_post(self, mac_learning=False, binding=False):
|
||||||
port = self.ports.first()
|
port = self.ports.first()
|
||||||
api.neutron.port_get(IsA(http.HttpRequest), port.id)\
|
api.neutron.port_get(IsA(http.HttpRequest), port.id)\
|
||||||
.AndReturn(port)
|
.AndReturn(port)
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'binding')\
|
||||||
|
.AndReturn(binding)
|
||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
extension_kwargs = {}
|
extension_kwargs = {}
|
||||||
|
if binding:
|
||||||
|
extension_kwargs['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
extension_kwargs['mac_learning_enabled'] = True
|
extension_kwargs['mac_learning_enabled'] = True
|
||||||
api.neutron.port_update(IsA(http.HttpRequest), port.id,
|
api.neutron.port_update(IsA(http.HttpRequest), port.id,
|
||||||
@ -1190,6 +1223,7 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
admin_state_up=port.admin_state_up,
|
admin_state_up=port.admin_state_up,
|
||||||
device_id=port.device_id,
|
device_id=port.device_id,
|
||||||
device_owner=port.device_owner,
|
device_owner=port.device_owner,
|
||||||
|
binding__host_id=port.binding__host_id,
|
||||||
**extension_kwargs)\
|
**extension_kwargs)\
|
||||||
.AndReturn(port)
|
.AndReturn(port)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
@ -1199,7 +1233,10 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
'name': port.name,
|
'name': port.name,
|
||||||
'admin_state': port.admin_state_up,
|
'admin_state': port.admin_state_up,
|
||||||
'device_id': port.device_id,
|
'device_id': port.device_id,
|
||||||
'device_owner': port.device_owner}
|
'device_owner': port.device_owner,
|
||||||
|
'binding__host_id': port.binding__host_id}
|
||||||
|
if binding:
|
||||||
|
form_data['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
form_data['mac_state'] = True
|
form_data['mac_state'] = True
|
||||||
url = reverse('horizon:admin:networks:editport',
|
url = reverse('horizon:admin:networks:editport',
|
||||||
@ -1220,16 +1257,22 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
'is_extension_supported',
|
'is_extension_supported',
|
||||||
'port_update')})
|
'port_update')})
|
||||||
def test_port_update_post_exception_with_mac_learning(self):
|
def test_port_update_post_exception_with_mac_learning(self):
|
||||||
self._test_port_update_post_exception(mac_learning=True)
|
self._test_port_update_post_exception(mac_learning=True, binding=False)
|
||||||
|
|
||||||
def _test_port_update_post_exception(self, mac_learning=False):
|
def _test_port_update_post_exception(self, mac_learning=False,
|
||||||
|
binding=False):
|
||||||
port = self.ports.first()
|
port = self.ports.first()
|
||||||
api.neutron.port_get(IsA(http.HttpRequest), port.id)\
|
api.neutron.port_get(IsA(http.HttpRequest), port.id)\
|
||||||
.AndReturn(port)
|
.AndReturn(port)
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'binding')\
|
||||||
|
.AndReturn(binding)
|
||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
extension_kwargs = {}
|
extension_kwargs = {}
|
||||||
|
if binding:
|
||||||
|
extension_kwargs['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
extension_kwargs['mac_learning_enabled'] = True
|
extension_kwargs['mac_learning_enabled'] = True
|
||||||
api.neutron.port_update(IsA(http.HttpRequest), port.id,
|
api.neutron.port_update(IsA(http.HttpRequest), port.id,
|
||||||
@ -1237,6 +1280,7 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
admin_state_up=port.admin_state_up,
|
admin_state_up=port.admin_state_up,
|
||||||
device_id=port.device_id,
|
device_id=port.device_id,
|
||||||
device_owner=port.device_owner,
|
device_owner=port.device_owner,
|
||||||
|
binding__host_id=port.binding__host_id,
|
||||||
**extension_kwargs)\
|
**extension_kwargs)\
|
||||||
.AndRaise(self.exceptions.neutron)
|
.AndRaise(self.exceptions.neutron)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
@ -1246,7 +1290,10 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
|||||||
'name': port.name,
|
'name': port.name,
|
||||||
'admin_state': port.admin_state_up,
|
'admin_state': port.admin_state_up,
|
||||||
'device_id': port.device_id,
|
'device_id': port.device_id,
|
||||||
'device_owner': port.device_owner}
|
'device_owner': port.device_owner,
|
||||||
|
'binding__host_id': port.binding__host_id}
|
||||||
|
if binding:
|
||||||
|
form_data['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
form_data['mac_state'] = True
|
form_data['mac_state'] = True
|
||||||
url = reverse('horizon:admin:networks:editport',
|
url = reverse('horizon:admin:networks:editport',
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
@ -25,6 +26,8 @@ from openstack_dashboard import api
|
|||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
VNIC_TYPES = [('normal', _('Normal')), ('direct', _('Direct')),
|
||||||
|
('macvtap', _('MacVTap'))]
|
||||||
|
|
||||||
|
|
||||||
class UpdatePort(forms.SelfHandlingForm):
|
class UpdatePort(forms.SelfHandlingForm):
|
||||||
@ -42,18 +45,42 @@ class UpdatePort(forms.SelfHandlingForm):
|
|||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(UpdatePort, self).__init__(request, *args, **kwargs)
|
super(UpdatePort, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
|
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 == ['*']:
|
||||||
|
vnic_type_choices = VNIC_TYPES
|
||||||
|
else:
|
||||||
|
vnic_type_choices = [
|
||||||
|
vnic_type for vnic_type in VNIC_TYPES
|
||||||
|
if vnic_type[0] in supported_vnic_types
|
||||||
|
]
|
||||||
|
|
||||||
|
self.fields['binding__vnic_type'] = forms.ChoiceField(
|
||||||
|
choices=vnic_type_choices,
|
||||||
|
label=_("Binding: VNIC Type"),
|
||||||
|
help_text=_("The VNIC type that is bound to the neutron port"),
|
||||||
|
required=False)
|
||||||
|
|
||||||
if api.neutron.is_extension_supported(request, 'mac-learning'):
|
if api.neutron.is_extension_supported(request, 'mac-learning'):
|
||||||
self.fields['mac_state'] = forms.BooleanField(
|
self.fields['mac_state'] = forms.BooleanField(
|
||||||
label=_("Mac Learning State"), required=False)
|
label=_("MAC Learning State"), initial=False, required=False)
|
||||||
|
|
||||||
def handle(self, request, data):
|
def handle(self, request, data):
|
||||||
data['admin_state'] = (data['admin_state'] == 'True')
|
data['admin_state'] = (data['admin_state'] == 'True')
|
||||||
try:
|
try:
|
||||||
LOG.debug('params = %s' % data)
|
LOG.debug('params = %s' % data)
|
||||||
extension_kwargs = {}
|
extension_kwargs = {}
|
||||||
|
if 'binding__vnic_type' in data:
|
||||||
|
extension_kwargs['binding__vnic_type'] = \
|
||||||
|
data['binding__vnic_type']
|
||||||
if 'mac_state' in data:
|
if 'mac_state' in data:
|
||||||
extension_kwargs['mac_learning_enabled'] = data['mac_state']
|
extension_kwargs['mac_learning_enabled'] = data['mac_state']
|
||||||
port = api.neutron.port_update(request, data['port_id'],
|
port = api.neutron.port_update(request,
|
||||||
|
data['port_id'],
|
||||||
name=data['name'],
|
name=data['name'],
|
||||||
admin_state_up=data['admin_state'],
|
admin_state_up=data['admin_state'],
|
||||||
**extension_kwargs)
|
**extension_kwargs)
|
||||||
|
@ -100,8 +100,7 @@ class UpdateView(forms.ModalFormView):
|
|||||||
try:
|
try:
|
||||||
return api.neutron.port_get(self.request, port_id)
|
return api.neutron.port_get(self.request, port_id)
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:project:networks:detail",
|
redirect = self.get_success_url()
|
||||||
args=(self.kwargs['network_id'],))
|
|
||||||
msg = _('Unable to retrieve port details')
|
msg = _('Unable to retrieve port details')
|
||||||
exceptions.handle(self.request, msg, redirect=redirect)
|
exceptions.handle(self.request, msg, redirect=redirect)
|
||||||
|
|
||||||
@ -120,9 +119,9 @@ class UpdateView(forms.ModalFormView):
|
|||||||
'network_id': port['network_id'],
|
'network_id': port['network_id'],
|
||||||
'tenant_id': port['tenant_id'],
|
'tenant_id': port['tenant_id'],
|
||||||
'name': port['name'],
|
'name': port['name'],
|
||||||
'admin_state': port['admin_state_up'],
|
'admin_state': port['admin_state_up']}
|
||||||
'device_id': port['device_id'],
|
if port['binding__vnic_type']:
|
||||||
'device_owner': port['device_owner']}
|
initial['binding__vnic_type'] = port['binding__vnic_type']
|
||||||
try:
|
try:
|
||||||
initial['mac_state'] = port['mac_learning_enabled']
|
initial['mac_state'] = port['mac_learning_enabled']
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
{% load i18n sizeformat %}
|
{% load i18n sizeformat %}
|
||||||
{% load url from future %}
|
{% load url from future %}
|
||||||
|
|
||||||
<h3>{% trans "Port Overview" %}</h3>
|
<div class="detail">
|
||||||
|
|
||||||
<div class="info row detail">
|
|
||||||
<h4>{% trans "Port" %}</h4>
|
|
||||||
<hr class="header_rule">
|
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>{% trans "Name" %}</dt>
|
<dt>{% trans "Name" %}</dt>
|
||||||
<dd>{{ port.name|default:_("None") }}</dd>
|
<dd>{{ port.name|default:_("None") }}</dd>
|
||||||
@ -16,18 +12,7 @@
|
|||||||
<dd><a href="{{ network_url }}">{{ port.network_id|default:_("None") }}</a></dd>
|
<dd><a href="{{ network_url }}">{{ port.network_id|default:_("None") }}</a></dd>
|
||||||
<dt>{% trans "Project ID" %}</dt>
|
<dt>{% trans "Project ID" %}</dt>
|
||||||
<dd>{{ port.tenant_id|default:_("-") }}</dd>
|
<dd>{{ port.tenant_id|default:_("-") }}</dd>
|
||||||
<dt>{% trans "Fixed IP" %}</dt>
|
<dt>{% trans "MAC Address" %}</dt>
|
||||||
<dd>
|
|
||||||
{% if port.fixed_ips.items|length > 1 %}
|
|
||||||
{% for ip in port.fixed_ips %}
|
|
||||||
<b>{% trans "IP address:" %}</b> {{ ip.ip_address }},
|
|
||||||
<b>{% trans "Subnet ID" %}</b> {{ ip.subnet_id }}<br>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
{% trans "None" %}
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
<dt>{% trans "Mac Address" %}</dt>
|
|
||||||
<dd>{{ port.mac_address|default:_("None") }}</dd>
|
<dd>{{ port.mac_address|default:_("None") }}</dd>
|
||||||
<dt>{% trans "Status" %}</dt>
|
<dt>{% trans "Status" %}</dt>
|
||||||
<dd>{{ port.status_label|default:_("None") }}</dd>
|
<dd>{{ port.status_label|default:_("None") }}</dd>
|
||||||
@ -37,12 +22,34 @@
|
|||||||
<dt>{% trans "MAC Learning State" %}</dt>
|
<dt>{% trans "MAC Learning State" %}</dt>
|
||||||
<dd>{{ port.mac_state }}</dd>
|
<dd>{{ port.mac_state }}</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<dt>{% trans "Attached Device" %}</dt>
|
<h4>{% trans "Fixed IP" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
{% if port.fixed_ips.items|length > 1 %}
|
||||||
|
{% for ip in port.fixed_ips %}
|
||||||
|
<dt>{% trans "IP Address" %}</dt>
|
||||||
|
<dd>{{ ip.ip_address }}</dd>
|
||||||
|
{% url 'horizon:project:networks:subnets:detail' ip.subnet_id as subnet_url %}
|
||||||
|
<dt>{% trans "Subnet ID" %}</dt>
|
||||||
|
<dd><a href="{{ subnet_url }}">{{ ip.subnet_id }}</a></dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<dd>{% trans "None" %}</dd>
|
||||||
|
{% endif %}
|
||||||
|
<h4>{% trans "Attached Device" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
{% if port.device_id|length > 1 or port.device_owner %}
|
{% if port.device_id|length > 1 or port.device_owner %}
|
||||||
<dd><b>{% trans "Device Owner" %}</b>: {{ port.device_owner|default:_("None") }}</dd>
|
<dt>{% trans "Device Owner" %}</dt>
|
||||||
<dd><b>{% trans "Device ID" %}</b>: {{ port.device_id|default:_("-") }}</dd>
|
<dd>{{ port.device_owner|default:_("None") }}</dd>
|
||||||
|
<dt>{% trans "Device ID" %}</dt>
|
||||||
|
<dd>{{ port.device_id|default:_("None") }}</dd>
|
||||||
{% else %}
|
{% else %}
|
||||||
<dd>{% trans "No attached device" %}</dd>
|
<dd>{% trans "No attached device" %}</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<h4>{% trans "Binding" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
{% if port.binding__vnic_type %}
|
||||||
|
<dt>{% trans "VNIC Type" %}</dt>
|
||||||
|
<dd>{{ port.binding__vnic_type }}</dd>
|
||||||
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1691,11 +1691,14 @@ class NetworkPortTests(test.TestCase):
|
|||||||
def test_port_update_get_with_mac_learning(self):
|
def test_port_update_get_with_mac_learning(self):
|
||||||
self._test_port_update_get(mac_learning=True)
|
self._test_port_update_get(mac_learning=True)
|
||||||
|
|
||||||
def _test_port_update_get(self, mac_learning=False):
|
def _test_port_update_get(self, mac_learning=False, binding=False):
|
||||||
port = self.ports.first()
|
port = self.ports.first()
|
||||||
api.neutron.port_get(IsA(http.HttpRequest),
|
api.neutron.port_get(IsA(http.HttpRequest),
|
||||||
port.id)\
|
port.id)\
|
||||||
.AndReturn(port)
|
.AndReturn(port)
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'binding')\
|
||||||
|
.AndReturn(binding)
|
||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
@ -1719,14 +1722,19 @@ class NetworkPortTests(test.TestCase):
|
|||||||
def test_port_update_post_with_mac_learning(self):
|
def test_port_update_post_with_mac_learning(self):
|
||||||
self._test_port_update_post(mac_learning=True)
|
self._test_port_update_post(mac_learning=True)
|
||||||
|
|
||||||
def _test_port_update_post(self, mac_learning=False):
|
def _test_port_update_post(self, mac_learning=False, binding=False):
|
||||||
port = self.ports.first()
|
port = self.ports.first()
|
||||||
api.neutron.port_get(IsA(http.HttpRequest), port.id)\
|
api.neutron.port_get(IsA(http.HttpRequest), port.id)\
|
||||||
.AndReturn(port)
|
.AndReturn(port)
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'binding')\
|
||||||
|
.AndReturn(binding)
|
||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
extension_kwargs = {}
|
extension_kwargs = {}
|
||||||
|
if binding:
|
||||||
|
extension_kwargs['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
extension_kwargs['mac_learning_enabled'] = True
|
extension_kwargs['mac_learning_enabled'] = True
|
||||||
api.neutron.port_update(IsA(http.HttpRequest), port.id,
|
api.neutron.port_update(IsA(http.HttpRequest), port.id,
|
||||||
@ -1740,6 +1748,8 @@ class NetworkPortTests(test.TestCase):
|
|||||||
'port_id': port.id,
|
'port_id': port.id,
|
||||||
'name': port.name,
|
'name': port.name,
|
||||||
'admin_state': port.admin_state_up}
|
'admin_state': port.admin_state_up}
|
||||||
|
if binding:
|
||||||
|
form_data['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
form_data['mac_state'] = True
|
form_data['mac_state'] = True
|
||||||
url = reverse('horizon:project:networks:editport',
|
url = reverse('horizon:project:networks:editport',
|
||||||
@ -1762,14 +1772,21 @@ class NetworkPortTests(test.TestCase):
|
|||||||
def test_port_update_post_exception_with_mac_learning(self):
|
def test_port_update_post_exception_with_mac_learning(self):
|
||||||
self._test_port_update_post_exception(mac_learning=True)
|
self._test_port_update_post_exception(mac_learning=True)
|
||||||
|
|
||||||
def _test_port_update_post_exception(self, mac_learning=False):
|
def _test_port_update_post_exception(self, mac_learning=False,
|
||||||
|
binding=False):
|
||||||
|
|
||||||
port = self.ports.first()
|
port = self.ports.first()
|
||||||
api.neutron.port_get(IsA(http.HttpRequest), port.id)\
|
api.neutron.port_get(IsA(http.HttpRequest), port.id)\
|
||||||
.AndReturn(port)
|
.AndReturn(port)
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'binding')\
|
||||||
|
.AndReturn(binding)
|
||||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
'mac-learning')\
|
'mac-learning')\
|
||||||
.AndReturn(mac_learning)
|
.AndReturn(mac_learning)
|
||||||
extension_kwargs = {}
|
extension_kwargs = {}
|
||||||
|
if binding:
|
||||||
|
extension_kwargs['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
extension_kwargs['mac_learning_enabled'] = True
|
extension_kwargs['mac_learning_enabled'] = True
|
||||||
api.neutron.port_update(IsA(http.HttpRequest), port.id,
|
api.neutron.port_update(IsA(http.HttpRequest), port.id,
|
||||||
@ -1783,6 +1800,8 @@ class NetworkPortTests(test.TestCase):
|
|||||||
'port_id': port.id,
|
'port_id': port.id,
|
||||||
'name': port.name,
|
'name': port.name,
|
||||||
'admin_state': port.admin_state_up}
|
'admin_state': port.admin_state_up}
|
||||||
|
if binding:
|
||||||
|
form_data['binding__vnic_type'] = port.binding__vnic_type
|
||||||
if mac_learning:
|
if mac_learning:
|
||||||
form_data['mac_state'] = True
|
form_data['mac_state'] = True
|
||||||
url = reverse('horizon:project:networks:editport',
|
url = reverse('horizon:project:networks:editport',
|
||||||
|
@ -216,6 +216,12 @@ OPENSTACK_NEUTRON_NETWORK = {
|
|||||||
# in this list will be available to choose from when creating a network.
|
# in this list will be available to choose from when creating a network.
|
||||||
# Network types include local, flat, vlan, gre, and vxlan.
|
# Network types include local, flat, vlan, gre, and vxlan.
|
||||||
'supported_provider_types': ['*'],
|
'supported_provider_types': ['*'],
|
||||||
|
|
||||||
|
# Set which VNIC types are supported for port binding. Only the VNIC
|
||||||
|
# types in this list will be available to choose from when creating a
|
||||||
|
# port.
|
||||||
|
# VNIC types include 'normal', 'macvtap' and 'direct'.
|
||||||
|
'supported_vnic_types': ['*']
|
||||||
}
|
}
|
||||||
|
|
||||||
# The OPENSTACK_IMAGE_BACKEND settings can be used to customize features
|
# The OPENSTACK_IMAGE_BACKEND settings can be used to customize features
|
||||||
|
@ -161,7 +161,10 @@ def data(TEST):
|
|||||||
'name': '',
|
'name': '',
|
||||||
'network_id': network_dict['id'],
|
'network_id': network_dict['id'],
|
||||||
'status': 'ACTIVE',
|
'status': 'ACTIVE',
|
||||||
'tenant_id': network_dict['tenant_id']}
|
'tenant_id': network_dict['tenant_id'],
|
||||||
|
'binding:vnic_type': 'normal',
|
||||||
|
'binding:host_id': 'host'}
|
||||||
|
|
||||||
TEST.api_ports.add(port_dict)
|
TEST.api_ports.add(port_dict)
|
||||||
TEST.ports.add(neutron.Port(port_dict))
|
TEST.ports.add(neutron.Port(port_dict))
|
||||||
|
|
||||||
@ -175,7 +178,9 @@ def data(TEST):
|
|||||||
'name': '',
|
'name': '',
|
||||||
'network_id': network_dict['id'],
|
'network_id': network_dict['id'],
|
||||||
'status': 'ACTIVE',
|
'status': 'ACTIVE',
|
||||||
'tenant_id': network_dict['tenant_id']}
|
'tenant_id': network_dict['tenant_id'],
|
||||||
|
'binding:vnic_type': 'normal',
|
||||||
|
'binding:host_id': 'host'}
|
||||||
TEST.api_ports.add(port_dict)
|
TEST.api_ports.add(port_dict)
|
||||||
TEST.ports.add(neutron.Port(port_dict))
|
TEST.ports.add(neutron.Port(port_dict))
|
||||||
assoc_port = port_dict
|
assoc_port = port_dict
|
||||||
@ -190,7 +195,9 @@ def data(TEST):
|
|||||||
'name': '',
|
'name': '',
|
||||||
'network_id': network_dict['id'],
|
'network_id': network_dict['id'],
|
||||||
'status': 'ACTIVE',
|
'status': 'ACTIVE',
|
||||||
'tenant_id': network_dict['tenant_id']}
|
'tenant_id': network_dict['tenant_id'],
|
||||||
|
'binding:vnic_type': 'normal',
|
||||||
|
'binding:host_id': 'host'}
|
||||||
TEST.api_ports.add(port_dict)
|
TEST.api_ports.add(port_dict)
|
||||||
TEST.ports.add(neutron.Port(port_dict))
|
TEST.ports.add(neutron.Port(port_dict))
|
||||||
|
|
||||||
@ -238,7 +245,9 @@ def data(TEST):
|
|||||||
'name': '',
|
'name': '',
|
||||||
'network_id': network_dict['id'],
|
'network_id': network_dict['id'],
|
||||||
'status': 'ACTIVE',
|
'status': 'ACTIVE',
|
||||||
'tenant_id': network_dict['tenant_id']}
|
'tenant_id': network_dict['tenant_id'],
|
||||||
|
'binding:vnic_type': 'normal',
|
||||||
|
'binding:host_id': 'host'}
|
||||||
|
|
||||||
TEST.api_ports.add(port_dict)
|
TEST.api_ports.add(port_dict)
|
||||||
TEST.ports.add(neutron.Port(port_dict))
|
TEST.ports.add(neutron.Port(port_dict))
|
||||||
@ -350,7 +359,9 @@ def data(TEST):
|
|||||||
'name': '',
|
'name': '',
|
||||||
'network_id': TEST.networks.get(name="ext_net")['id'],
|
'network_id': TEST.networks.get(name="ext_net")['id'],
|
||||||
'status': 'ACTIVE',
|
'status': 'ACTIVE',
|
||||||
'tenant_id': '1'}
|
'tenant_id': '1',
|
||||||
|
'binding:vnic_type': 'normal',
|
||||||
|
'binding:host_id': 'host'}
|
||||||
TEST.api_ports.add(port_dict)
|
TEST.api_ports.add(port_dict)
|
||||||
TEST.ports.add(neutron.Port(port_dict))
|
TEST.ports.add(neutron.Port(port_dict))
|
||||||
|
|
||||||
@ -1142,6 +1153,8 @@ def data(TEST):
|
|||||||
'name': 'port5',
|
'name': 'port5',
|
||||||
'network_id': TEST.networks.get(name="net4")['id'],
|
'network_id': TEST.networks.get(name="net4")['id'],
|
||||||
'status': 'ACTIVE',
|
'status': 'ACTIVE',
|
||||||
'tenant_id': TEST.networks.get(name="net4")['tenant_id']}
|
'tenant_id': TEST.networks.get(name="net4")['tenant_id'],
|
||||||
|
'binding:vnic_type': 'normal',
|
||||||
|
'binding:host_id': 'host'}
|
||||||
TEST.api_ports.add(port_dict)
|
TEST.api_ports.add(port_dict)
|
||||||
TEST.ports.add(neutron.Port(port_dict))
|
TEST.ports.add(neutron.Port(port_dict))
|
||||||
|
Loading…
Reference in New Issue
Block a user