Improve Quantum panels to Folsom advanced features
Implements blueprint improve-quantum-summary-table * Improve displayed columns in network related tables * Use workflows in subnet create/update panels * Operations * admin_state control for network and port * router:external support in network creation and update * No gateway support in subnet creation and update * enable_dhcp, allocation_pools, dns_nameservers and host_routes support in subnet creattion and update * Setting device_owner is supported in admin port panel * Detail panels * router:external and provider network information in admin network detail * enable_dhcp, host_routes and dns_nameservers in subnet detail * device_owner in port detail * Behavior changes * Remove created network when subnet creation failed in "Create Network". Before this commit a created network remains even when an associated subnet failed to be created, but it is a little confusing since an unintended network without subnet is created. This commit deletes such networks and display a message indicating it. Change-Id: I1325c415acc6afc664879540c66957874d1c95c3
This commit is contained in:
parent
4d2199d8fe
commit
31d55e503d
@ -50,19 +50,19 @@ class QuantumAPIDictWrapper(APIDictWrapper):
|
||||
|
||||
class Network(QuantumAPIDictWrapper):
|
||||
"""Wrapper for quantum Networks"""
|
||||
_attrs = ['name', 'id', 'subnets', 'tenant_id', 'status',
|
||||
'admin_state_up', 'shared']
|
||||
|
||||
def __init__(self, apiresource):
|
||||
apiresource['admin_state'] = \
|
||||
'UP' if apiresource['admin_state_up'] else 'DOWN'
|
||||
# Django cannot handle a key name with a colon, so remap another key
|
||||
for key in apiresource.keys():
|
||||
if key.find(':'):
|
||||
apiresource['__'.join(key.split(':'))] = apiresource[key]
|
||||
super(Network, self).__init__(apiresource)
|
||||
|
||||
|
||||
class Subnet(QuantumAPIDictWrapper):
|
||||
"""Wrapper for quantum subnets"""
|
||||
_attrs = ['name', 'id', 'cidr', 'network_id', 'tenant_id',
|
||||
'ip_version', 'ipver_str']
|
||||
|
||||
def __init__(self, apiresource):
|
||||
apiresource['ipver_str'] = get_ipver_str(apiresource['ip_version'])
|
||||
@ -71,9 +71,6 @@ class Subnet(QuantumAPIDictWrapper):
|
||||
|
||||
class Port(QuantumAPIDictWrapper):
|
||||
"""Wrapper for quantum ports"""
|
||||
_attrs = ['name', 'id', 'network_id', 'tenant_id',
|
||||
'admin_state_up', 'status', 'mac_address',
|
||||
'fixed_ips', 'host_routes', 'device_id']
|
||||
|
||||
def __init__(self, apiresource):
|
||||
apiresource['admin_state'] = \
|
||||
|
@ -34,8 +34,12 @@ class CreateNetwork(forms.SelfHandlingForm):
|
||||
label=_("Name"),
|
||||
required=False)
|
||||
tenant_id = forms.ChoiceField(label=_("Project"))
|
||||
admin_state = forms.BooleanField(label=_("Admin State"),
|
||||
initial=True, required=False)
|
||||
shared = forms.BooleanField(label=_("Shared"),
|
||||
initial=False, required=False)
|
||||
external = forms.BooleanField(label=_("External Network"),
|
||||
initial=False, required=False)
|
||||
|
||||
@classmethod
|
||||
def _instantiate(cls, request, *args, **kwargs):
|
||||
@ -51,10 +55,12 @@ class CreateNetwork(forms.SelfHandlingForm):
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
network = api.quantum.network_create(request,
|
||||
name=data['name'],
|
||||
tenant_id=data['tenant_id'],
|
||||
shared=data['shared'])
|
||||
params = {'name': data['name'],
|
||||
'tenant_id': data['tenant_id'],
|
||||
'admin_state_up': data['admin_state'],
|
||||
'shared': data['shared'],
|
||||
'router:external': data['external']}
|
||||
network = api.quantum.network_create(request, **params)
|
||||
msg = _('Network %s was successfully created.') % data['name']
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
@ -71,14 +77,19 @@ class UpdateNetwork(forms.SelfHandlingForm):
|
||||
network_id = forms.CharField(label=_("ID"),
|
||||
widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}))
|
||||
admin_state = forms.BooleanField(label=_("Admin State"), required=False)
|
||||
shared = forms.BooleanField(label=_("Shared"), required=False)
|
||||
external = forms.BooleanField(label=_("External Network"), required=False)
|
||||
failure_url = 'horizon:admin:networks:index'
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
params = {'name': data['name'],
|
||||
'admin_state_up': data['admin_state'],
|
||||
'shared': data['shared'],
|
||||
'router:external': data['external']}
|
||||
network = api.quantum.network_modify(request, data['network_id'],
|
||||
name=data['name'],
|
||||
shared=data['shared'])
|
||||
**params)
|
||||
msg = _('Network %s was successfully updated.') % data['name']
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
|
@ -24,6 +24,8 @@ 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__)
|
||||
@ -39,9 +41,14 @@ class CreatePort(forms.SelfHandlingForm):
|
||||
name = forms.CharField(max_length=255,
|
||||
label=_("Name"),
|
||||
required=False)
|
||||
admin_state = forms.BooleanField(label=_("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='Device owner attached to the port',
|
||||
required=False)
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
@ -49,6 +56,8 @@ class CreatePort(forms.SelfHandlingForm):
|
||||
# created for if admin user does not belong to the tenant.
|
||||
network = api.quantum.network_get(request, data['network_id'])
|
||||
data['tenant_id'] = network.tenant_id
|
||||
data['admin_state_up'] = data['admin_state']
|
||||
del data['admin_state']
|
||||
|
||||
port = api.quantum.port_create(request, **data)
|
||||
msg = _('Port %s was successfully created.') % port['id']
|
||||
@ -64,23 +73,24 @@ class CreatePort(forms.SelfHandlingForm):
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
|
||||
|
||||
class UpdatePort(forms.SelfHandlingForm):
|
||||
network_id = forms.CharField(widget=forms.HiddenInput())
|
||||
tenant_id = forms.CharField(widget=forms.HiddenInput())
|
||||
port_id = forms.CharField(widget=forms.HiddenInput())
|
||||
name = forms.CharField(max_length=255,
|
||||
label=_("Name"),
|
||||
required=False)
|
||||
class UpdatePort(project_forms.UpdatePort):
|
||||
#tenant_id = forms.CharField(widget=forms.HiddenInput())
|
||||
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='Device owner attached to the port',
|
||||
required=False)
|
||||
failure_url = 'horizon:admin:networks:detail'
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.debug('params = %s' % data)
|
||||
port = api.quantum.port_modify(request, data['port_id'],
|
||||
name=data['name'],
|
||||
device_id=data['device_id'])
|
||||
admin_state_up=data['admin_state'],
|
||||
device_id=data['device_id'],
|
||||
device_owner=data['device_owner'])
|
||||
msg = _('Port %s was successfully updated.') % data['port_id']
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
@ -88,6 +98,6 @@ class UpdatePort(forms.SelfHandlingForm):
|
||||
except Exception:
|
||||
msg = _('Failed to update port %s') % data['port_id']
|
||||
LOG.info(msg)
|
||||
redirect = reverse('horizon:admin:networks:detail',
|
||||
redirect = reverse(self.failure_url,
|
||||
args=[data['network_id']])
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
|
@ -23,6 +23,9 @@ from horizon import exceptions
|
||||
from horizon import forms
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.dashboards.project.networks.ports \
|
||||
import views as project_views
|
||||
|
||||
from .forms import CreatePort, UpdatePort
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -32,6 +35,7 @@ class CreateView(forms.ModalFormView):
|
||||
form_class = CreatePort
|
||||
template_name = 'admin/networks/ports/create.html'
|
||||
success_url = 'horizon:admin:networks:detail'
|
||||
failure_url = 'horizon:admin:networks:detail'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse(self.success_url,
|
||||
@ -44,7 +48,7 @@ class CreateView(forms.ModalFormView):
|
||||
self._object = api.quantum.network_get(self.request,
|
||||
network_id)
|
||||
except:
|
||||
redirect = reverse("horizon:admin:networks:detail",
|
||||
redirect = reverse(self.failure_url,
|
||||
args=(self.kwargs['network_id'],))
|
||||
msg = _("Unable to retrieve network.")
|
||||
exceptions.handle(self.request, msg, redirect=redirect)
|
||||
@ -61,39 +65,8 @@ class CreateView(forms.ModalFormView):
|
||||
"network_name": network.name}
|
||||
|
||||
|
||||
class UpdateView(forms.ModalFormView):
|
||||
class UpdateView(project_views.UpdateView):
|
||||
form_class = UpdatePort
|
||||
template_name = 'admin/networks/ports/update.html'
|
||||
context_object_name = 'port'
|
||||
success_url = 'horizon:admin:networks:detail'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse(self.success_url,
|
||||
args=(self.kwargs['network_id'],))
|
||||
|
||||
def _get_object(self, *args, **kwargs):
|
||||
if not hasattr(self, "_object"):
|
||||
port_id = self.kwargs['port_id']
|
||||
try:
|
||||
self._object = api.quantum.port_get(self.request, port_id)
|
||||
except:
|
||||
redirect = reverse("horizon:admin:networks:detail",
|
||||
args=(self.kwargs['network_id'],))
|
||||
msg = _('Unable to retrieve port details')
|
||||
exceptions.handle(self.request, msg, redirect=redirect)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||
port = self._get_object()
|
||||
context['port_id'] = port['id']
|
||||
context['network_id'] = port['network_id']
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
port = self._get_object()
|
||||
return {'port_id': port['id'],
|
||||
'network_id': port['network_id'],
|
||||
'tenant_id': port['tenant_id'],
|
||||
'name': port['name'],
|
||||
'device_id': port['device_id']}
|
||||
|
@ -1,53 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# 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 forms
|
||||
from horizon import exceptions
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.dashboards.project.networks.subnets import \
|
||||
forms as user_forms
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateSubnet(user_forms.CreateSubnet):
|
||||
failure_url = 'horizon:admin:networks:detail'
|
||||
|
||||
def handle(self, request, data):
|
||||
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.quantum.network_get(request, data['network_id'])
|
||||
data['tenant_id'] = network.tenant_id
|
||||
except:
|
||||
msg = _('Failed to retrieve network %s for a subnet') \
|
||||
% data['network_id']
|
||||
LOG.info(msg)
|
||||
redirect = reverse(self.failure_url, args=[data['network_id']])
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
return super(CreateSubnet, self).handle(request, data)
|
||||
|
||||
|
||||
class UpdateSubnet(user_forms.UpdateSubnet):
|
||||
tenant_id = forms.CharField(widget=forms.HiddenInput())
|
||||
failure_url = 'horizon:admin:networks:detail'
|
@ -23,81 +23,20 @@ from horizon import exceptions
|
||||
from horizon import forms
|
||||
|
||||
from openstack_dashboard import api
|
||||
from .forms import CreateSubnet, UpdateSubnet
|
||||
from openstack_dashboard.dashboards.project.networks.subnets \
|
||||
import views as project_views
|
||||
|
||||
from .workflows import CreateSubnet, UpdateSubnet
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateView(forms.ModalFormView):
|
||||
form_class = CreateSubnet
|
||||
class CreateView(project_views.CreateView):
|
||||
workflow_class = CreateSubnet
|
||||
template_name = 'admin/networks/subnets/create.html'
|
||||
success_url = 'horizon:admin:networks:detail'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse(self.success_url,
|
||||
args=(self.kwargs['network_id'],))
|
||||
|
||||
def get_object(self):
|
||||
if not hasattr(self, "_object"):
|
||||
try:
|
||||
network_id = self.kwargs["network_id"]
|
||||
self._object = api.quantum.network_get(self.request,
|
||||
network_id)
|
||||
except:
|
||||
redirect = reverse('horizon:project:networks:index')
|
||||
msg = _("Unable to retrieve network.")
|
||||
exceptions.handle(self.request, msg, redirect=redirect)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(CreateView, self).get_context_data(**kwargs)
|
||||
context['network'] = self.get_object()
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
network = self.get_object()
|
||||
return {"network_id": self.kwargs['network_id'],
|
||||
"network_name": network.name}
|
||||
|
||||
|
||||
class UpdateView(forms.ModalFormView):
|
||||
form_class = UpdateSubnet
|
||||
class UpdateView(project_views.UpdateView):
|
||||
workflow_class = UpdateSubnet
|
||||
template_name = 'admin/networks/subnets/update.html'
|
||||
context_object_name = 'subnet'
|
||||
success_url = 'horizon:admin:networks:detail'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse(self.success_url,
|
||||
args=(self.kwargs['network_id'],))
|
||||
|
||||
def _get_object(self, *args, **kwargs):
|
||||
if not hasattr(self, "_object"):
|
||||
subnet_id = self.kwargs['subnet_id']
|
||||
try:
|
||||
self._object = api.quantum.subnet_get(self.request, subnet_id)
|
||||
except:
|
||||
redirect = reverse("horizon:admin:networks:detail",
|
||||
args=(self.kwargs['network_id'],))
|
||||
msg = _('Unable to retrieve subnet details')
|
||||
exceptions.handle(self.request, msg, redirect=redirect)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||
subnet = self._get_object()
|
||||
context['subnet_id'] = subnet['id']
|
||||
context['network_id'] = subnet['network_id']
|
||||
context['cidr'] = subnet['cidr']
|
||||
context['ip_version'] = {4: 'IPv4', 6: 'IPv6'}[subnet['ip_version']]
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
subnet = self._get_object()
|
||||
return {'network_id': self.kwargs['network_id'],
|
||||
'subnet_id': subnet['id'],
|
||||
'tenant_id': subnet['tenant_id'],
|
||||
'cidr': subnet['cidr'],
|
||||
'ip_version': subnet['ip_version'],
|
||||
'name': subnet['name'],
|
||||
'gateway_ip': subnet['gateway_ip']}
|
||||
|
@ -0,0 +1,60 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 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 as _
|
||||
|
||||
from horizon import exceptions
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.dashboards.project.networks.subnets \
|
||||
import workflows as project_workflows
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateSubnet(project_workflows.CreateSubnet):
|
||||
def get_success_url(self):
|
||||
return reverse("horizon:admin:networks:detail",
|
||||
args=(self.context.get('network_id'),))
|
||||
|
||||
def get_failure_url(self):
|
||||
return reverse("horizon:admin:networks:detail",
|
||||
args=(self.context.get('network_id'),))
|
||||
|
||||
def handle(self, request, data):
|
||||
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.quantum.network_get(request,
|
||||
self.context['network_id'])
|
||||
except:
|
||||
msg = (_('Failed to retrieve network %s for a subnet') %
|
||||
data['network_id'])
|
||||
LOG.info(msg)
|
||||
redirect = self.get_failure_url()
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
subnet = self._create_subnet(request, data,
|
||||
tenant_id=network.tenant_id)
|
||||
return True if subnet else False
|
||||
|
||||
|
||||
class UpdateSubnet(project_workflows.UpdateSubnet):
|
||||
success_url = "horizon:admin:networks:detail"
|
||||
failure_url = "horizon:admin:networks:detail"
|
@ -1,25 +0,0 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block form_id %}create_subnet_form{% endblock %}
|
||||
{% block form_action %}{% url horizon:admin:networks:addsubnet network.id %}
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Create Subnet" %}{% endblock %}
|
||||
|
||||
{% block modal-body %}
|
||||
<div class="left">
|
||||
<fieldset>
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="right">
|
||||
<h3>{% trans "Description" %}:</h3>
|
||||
<p>{% trans "You can create a subnet for the network. Any network address can be specified unless the network address does not overlap other subnets in the network." %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Create Subnet" %}" />
|
||||
<a href="{% url horizon:admin:networks:detail network.id %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
@ -1,33 +0,0 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block form_id %}update_subnet_form{% endblock %}
|
||||
{% block form_action %}{% url horizon:admin:networks:editsubnet network_id subnet_id %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Edit Subnet" %}{% endblock %}
|
||||
|
||||
{% block modal-body %}
|
||||
<div class="left">
|
||||
<dl>
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ subnet_id }}</dd>
|
||||
<dt>{% trans "Network Address" %}</dt>
|
||||
<dd>{{ cidr }}</dd>
|
||||
<dt>{% trans "IP version" %}</dt>
|
||||
<dd>{{ ip_version }}</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
<fieldset>
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="right">
|
||||
<h3>{% trans "Description:" %}</h3>
|
||||
<p>{% trans "You may update the editable properties of your subnet here." %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Save Changes" %}" />
|
||||
<a href="{% url horizon:admin:networks:detail network_id %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
@ -7,5 +7,5 @@
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include "admin/networks/subnets/_create.html" %}
|
||||
{% include "horizon/common/_workflow.html" %}
|
||||
{% endblock %}
|
||||
|
@ -7,5 +7,5 @@
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/networks/subnets/_update.html' %}
|
||||
{% include "horizon/common/_workflow.html" %}
|
||||
{% endblock %}
|
||||
|
@ -21,6 +21,8 @@ from mox import IsA
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.test import helpers as test
|
||||
from openstack_dashboard.dashboards.project.networks.tests \
|
||||
import form_data_subnet
|
||||
|
||||
|
||||
INDEX_URL = reverse('horizon:admin:networks:index')
|
||||
@ -166,13 +168,19 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
network = self.networks.first()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
||||
.AndReturn(tenants)
|
||||
api.quantum.network_create(IsA(http.HttpRequest), name=network.name,
|
||||
tenant_id=tenant_id, shared=True)\
|
||||
params = {'name': network.name,
|
||||
'tenant_id': tenant_id,
|
||||
'admin_state_up': network.admin_state_up,
|
||||
'router:external': True,
|
||||
'shared': True}
|
||||
api.quantum.network_create(IsA(http.HttpRequest), **params)\
|
||||
.AndReturn(network)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'tenant_id': tenant_id,
|
||||
'name': network.name,
|
||||
'admin_state': network.admin_state_up,
|
||||
'external': True,
|
||||
'shared': True}
|
||||
url = reverse('horizon:admin:networks:create')
|
||||
res = self.client.post(url, form_data)
|
||||
@ -188,13 +196,19 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
network = self.networks.first()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
||||
.AndReturn(tenants)
|
||||
api.quantum.network_create(IsA(http.HttpRequest), name=network.name,
|
||||
tenant_id=tenant_id, shared=False)\
|
||||
params = {'name': network.name,
|
||||
'tenant_id': tenant_id,
|
||||
'admin_state_up': network.admin_state_up,
|
||||
'router:external': True,
|
||||
'shared': False}
|
||||
api.quantum.network_create(IsA(http.HttpRequest), **params)\
|
||||
.AndRaise(self.exceptions.quantum)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'tenant_id': tenant_id,
|
||||
'name': network.name,
|
||||
'admin_state': network.admin_state_up,
|
||||
'external': True,
|
||||
'shared': False}
|
||||
url = reverse('horizon:admin:networks:create')
|
||||
res = self.client.post(url, form_data)
|
||||
@ -233,19 +247,25 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
'network_get',)})
|
||||
def test_network_update_post(self):
|
||||
network = self.networks.first()
|
||||
params = {'name': network.name,
|
||||
'shared': True,
|
||||
'admin_state_up': network.admin_state_up,
|
||||
'router:external': True}
|
||||
api.quantum.network_modify(IsA(http.HttpRequest), network.id,
|
||||
name=network.name, shared=True)\
|
||||
**params)\
|
||||
.AndReturn(network)
|
||||
api.quantum.network_get(IsA(http.HttpRequest), network.id)\
|
||||
.AndReturn(network)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'network_id': network.id,
|
||||
'name': network.name,
|
||||
'tenant_id': network.tenant_id,
|
||||
'shared': True}
|
||||
form_data = {'network_id': network.id,
|
||||
'name': network.name,
|
||||
'tenant_id': network.tenant_id,
|
||||
'admin_state': network.admin_state_up,
|
||||
'shared': True,
|
||||
'external': True}
|
||||
url = reverse('horizon:admin:networks:update', args=[network.id])
|
||||
res = self.client.post(url, formData)
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@ -253,8 +273,12 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
'network_get',)})
|
||||
def test_network_update_post_exception(self):
|
||||
network = self.networks.first()
|
||||
params = {'name': network.name,
|
||||
'shared': False,
|
||||
'admin_state_up': network.admin_state_up,
|
||||
'router:external': False}
|
||||
api.quantum.network_modify(IsA(http.HttpRequest), network.id,
|
||||
name=network.name, shared=False)\
|
||||
**params)\
|
||||
.AndRaise(self.exceptions.quantum)
|
||||
api.quantum.network_get(IsA(http.HttpRequest), network.id)\
|
||||
.AndReturn(network)
|
||||
@ -263,7 +287,9 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
form_data = {'network_id': network.id,
|
||||
'name': network.name,
|
||||
'tenant_id': network.tenant_id,
|
||||
'shared': False}
|
||||
'admin_state': network.admin_state_up,
|
||||
'shared': False,
|
||||
'external': False}
|
||||
url = reverse('horizon:admin:networks:update', args=[network.id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
@ -308,6 +334,9 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
|
||||
class NetworkSubnetTests(test.BaseAdminViewTests):
|
||||
|
||||
@test.create_stubs({api.quantum: ('subnet_get',)})
|
||||
def test_subnet_detail(self):
|
||||
subnet = self.subnets.first()
|
||||
@ -367,21 +396,17 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
.AndReturn(self.networks.first())
|
||||
api.quantum.subnet_create(IsA(http.HttpRequest),
|
||||
network_id=network.id,
|
||||
network_name=network.name,
|
||||
name=subnet.name,
|
||||
cidr=subnet.cidr,
|
||||
ip_version=subnet.ip_version,
|
||||
gateway_ip=subnet.gateway_ip,
|
||||
enable_dhcp=subnet.enable_dhcp,
|
||||
allocation_pools=subnet.allocation_pools,
|
||||
tenant_id=subnet.tenant_id)\
|
||||
.AndReturn(subnet)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'network_id': subnet.network_id,
|
||||
'network_name': network.name,
|
||||
'name': subnet.name,
|
||||
'cidr': subnet.cidr,
|
||||
'ip_version': subnet.ip_version,
|
||||
'gateway_ip': subnet.gateway_ip}
|
||||
form_data = form_data_subnet(subnet)
|
||||
url = reverse('horizon:admin:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
@ -401,12 +426,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
.AndRaise(self.exceptions.quantum)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'network_id': subnet.network_id,
|
||||
'network_name': network.name,
|
||||
'name': subnet.name,
|
||||
'cidr': subnet.cidr,
|
||||
'ip_version': subnet.ip_version,
|
||||
'gateway_ip': subnet.gateway_ip}
|
||||
form_data = form_data_subnet(subnet, allocation_pools=[])
|
||||
url = reverse('horizon:admin:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
@ -430,21 +450,16 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
.AndReturn(self.networks.first())
|
||||
api.quantum.subnet_create(IsA(http.HttpRequest),
|
||||
network_id=network.id,
|
||||
network_name=network.name,
|
||||
name=subnet.name,
|
||||
cidr=subnet.cidr,
|
||||
ip_version=subnet.ip_version,
|
||||
gateway_ip=subnet.gateway_ip,
|
||||
enable_dhcp=subnet.enable_dhcp,
|
||||
tenant_id=subnet.tenant_id)\
|
||||
.AndRaise(self.exceptions.quantum)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'network_id': subnet.network_id,
|
||||
'network_name': network.name,
|
||||
'name': subnet.name,
|
||||
'cidr': subnet.cidr,
|
||||
'ip_version': subnet.ip_version,
|
||||
'gateway_ip': subnet.gateway_ip}
|
||||
form_data = form_data_subnet(subnet, allocation_pools=[])
|
||||
url = reverse('horizon:admin:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
@ -464,12 +479,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
|
||||
# dummy IPv6 address
|
||||
cidr = '2001:0DB8:0:CD30:123:4567:89AB:CDEF/60'
|
||||
form_data = {'network_id': subnet.network_id,
|
||||
'network_name': network.name,
|
||||
'name': subnet.name,
|
||||
'cidr': cidr,
|
||||
'ip_version': subnet.ip_version,
|
||||
'gateway_ip': subnet.gateway_ip}
|
||||
form_data = form_data_subnet(subnet, cidr=cidr, allocation_pools=[])
|
||||
url = reverse('horizon:admin:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
@ -488,12 +498,8 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
|
||||
# dummy IPv6 address
|
||||
gateway_ip = '2001:0DB8:0:CD30:123:4567:89AB:CDEF'
|
||||
form_data = {'network_id': subnet.network_id,
|
||||
'network_name': network.name,
|
||||
'name': subnet.name,
|
||||
'cidr': subnet.cidr,
|
||||
'ip_version': subnet.ip_version,
|
||||
'gateway_ip': gateway_ip}
|
||||
form_data = form_data_subnet(subnet, gateway_ip=gateway_ip,
|
||||
allocation_pools=[])
|
||||
url = reverse('horizon:admin:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
@ -508,20 +514,17 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
.AndReturn(subnet)
|
||||
api.quantum.subnet_modify(IsA(http.HttpRequest), subnet.id,
|
||||
name=subnet.name,
|
||||
gateway_ip=subnet.gateway_ip)\
|
||||
gateway_ip=subnet.gateway_ip,
|
||||
enable_dhcp=subnet.enable_dhcp,
|
||||
dns_nameservers=[],
|
||||
host_routes=[])\
|
||||
.AndReturn(subnet)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'network_id': subnet.network_id,
|
||||
'tenant_id': subnet.tenant_id,
|
||||
'subnet_id': subnet.id,
|
||||
'name': subnet.name,
|
||||
'cidr': subnet.cidr,
|
||||
'ip_version': subnet.ip_version,
|
||||
'gateway_ip': subnet.gateway_ip}
|
||||
form_data = form_data_subnet(subnet, allocation_pools=[])
|
||||
url = reverse('horizon:admin:networks:editsubnet',
|
||||
args=[subnet.network_id, subnet.id])
|
||||
res = self.client.post(url, formData)
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
redir_url = reverse('horizon:admin:networks:detail',
|
||||
args=[subnet.network_id])
|
||||
@ -537,16 +540,11 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
|
||||
# dummy IPv6 address
|
||||
gateway_ip = '2001:0DB8:0:CD30:123:4567:89AB:CDEF'
|
||||
formData = {'network_id': subnet.network_id,
|
||||
'tenant_id': subnet.tenant_id,
|
||||
'subnet_id': subnet.id,
|
||||
'name': subnet.name,
|
||||
'cidr': subnet.cidr,
|
||||
'ip_version': subnet.ip_version,
|
||||
'gateway_ip': gateway_ip}
|
||||
form_data = form_data_subnet(subnet, gateway_ip=gateway_ip,
|
||||
allocation_pools=[])
|
||||
url = reverse('horizon:admin:networks:editsubnet',
|
||||
args=[subnet.network_id, subnet.id])
|
||||
res = self.client.post(url, formData)
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertContains(res, 'Gateway IP and IP version are inconsistent.')
|
||||
|
||||
@ -563,10 +561,10 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
.AndReturn([self.ports.first()])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'subnets__delete__%s' % subnet.id}
|
||||
form_data = {'action': 'subnets__delete__%s' % subnet.id}
|
||||
url = reverse('horizon:admin:networks:detail',
|
||||
args=[network_id])
|
||||
res = self.client.post(url, formData)
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertRedirectsNoFollow(res, url)
|
||||
|
||||
@ -584,13 +582,16 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
.AndReturn([self.ports.first()])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'subnets__delete__%s' % subnet.id}
|
||||
form_data = {'action': 'subnets__delete__%s' % subnet.id}
|
||||
url = reverse('horizon:admin:networks:detail',
|
||||
args=[network_id])
|
||||
res = self.client.post(url, formData)
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertRedirectsNoFollow(res, url)
|
||||
|
||||
|
||||
class NetworkPortTests(test.BaseAdminViewTests):
|
||||
|
||||
@test.create_stubs({api.quantum: ('port_get',)})
|
||||
def test_port_detail(self):
|
||||
port = self.ports.first()
|
||||
@ -651,14 +652,18 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
network_id=network.id,
|
||||
network_name=network.name,
|
||||
name=port.name,
|
||||
device_id=port.device_id)\
|
||||
admin_state_up=port.admin_state_up,
|
||||
device_id=port.device_id,
|
||||
device_owner=port.device_owner)\
|
||||
.AndReturn(port)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'network_id': port.network_id,
|
||||
'network_name': network.name,
|
||||
'name': port.name,
|
||||
'device_id': port.device_id}
|
||||
'admin_state': port.admin_state_up,
|
||||
'device_id': port.device_id,
|
||||
'device_owner': port.device_owner}
|
||||
url = reverse('horizon:admin:networks:addport',
|
||||
args=[port.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
@ -684,14 +689,18 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
network_id=network.id,
|
||||
network_name=network.name,
|
||||
name=port.name,
|
||||
device_id=port.device_id)\
|
||||
admin_state_up=port.admin_state_up,
|
||||
device_id=port.device_id,
|
||||
device_owner=port.device_owner)\
|
||||
.AndRaise(self.exceptions.quantum)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'network_id': port.network_id,
|
||||
'network_name': network.name,
|
||||
'name': port.name,
|
||||
'device_id': port.device_id}
|
||||
'admin_state': port.admin_state_up,
|
||||
'device_id': port.device_id,
|
||||
'device_owner': port.device_owner}
|
||||
url = reverse('horizon:admin:networks:addport',
|
||||
args=[port.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
@ -722,18 +731,22 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
api.quantum.port_get(IsA(http.HttpRequest), port.id)\
|
||||
.AndReturn(port)
|
||||
api.quantum.port_modify(IsA(http.HttpRequest), port.id,
|
||||
name=port.name, device_id=port.device_id)\
|
||||
name=port.name,
|
||||
admin_state_up=port.admin_state_up,
|
||||
device_id=port.device_id,
|
||||
device_owner=port.device_owner)\
|
||||
.AndReturn(port)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'tenant_id': port.tenant_id,
|
||||
'network_id': port.network_id,
|
||||
'port_id': port.id,
|
||||
'name': port.name,
|
||||
'device_id': port.device_id}
|
||||
form_data = {'network_id': port.network_id,
|
||||
'port_id': port.id,
|
||||
'name': port.name,
|
||||
'admin_state': port.admin_state_up,
|
||||
'device_id': port.device_id,
|
||||
'device_owner': port.device_owner}
|
||||
url = reverse('horizon:admin:networks:editport',
|
||||
args=[port.network_id, port.id])
|
||||
res = self.client.post(url, formData)
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
redir_url = reverse('horizon:admin:networks:detail',
|
||||
args=[port.network_id])
|
||||
@ -746,18 +759,22 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
api.quantum.port_get(IsA(http.HttpRequest), port.id)\
|
||||
.AndReturn(port)
|
||||
api.quantum.port_modify(IsA(http.HttpRequest), port.id,
|
||||
name=port.name, device_id=port.device_id)\
|
||||
name=port.name,
|
||||
admin_state_up=port.admin_state_up,
|
||||
device_id=port.device_id,
|
||||
device_owner=port.device_owner)\
|
||||
.AndRaise(self.exceptions.quantum)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'tenant_id': port.tenant_id,
|
||||
'network_id': port.network_id,
|
||||
'port_id': port.id,
|
||||
'name': port.name,
|
||||
'device_id': port.device_id}
|
||||
form_data = {'network_id': port.network_id,
|
||||
'port_id': port.id,
|
||||
'name': port.name,
|
||||
'admin_state': port.admin_state_up,
|
||||
'device_id': port.device_id,
|
||||
'device_owner': port.device_owner}
|
||||
url = reverse('horizon:admin:networks:editport',
|
||||
args=[port.network_id, port.id])
|
||||
res = self.client.post(url, formData)
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
redir_url = reverse('horizon:admin:networks:detail',
|
||||
args=[port.network_id])
|
||||
@ -776,10 +793,10 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
.AndReturn([self.ports.first()])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'ports__delete__%s' % port.id}
|
||||
form_data = {'action': 'ports__delete__%s' % port.id}
|
||||
url = reverse('horizon:admin:networks:detail',
|
||||
args=[network_id])
|
||||
res = self.client.post(url, formData)
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertRedirectsNoFollow(res, url)
|
||||
|
||||
@ -797,9 +814,9 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
.AndReturn([self.ports.first()])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'action': 'ports__delete__%s' % port.id}
|
||||
form_data = {'action': 'ports__delete__%s' % port.id}
|
||||
url = reverse('horizon:admin:networks:detail',
|
||||
args=[network_id])
|
||||
res = self.client.post(url, formData)
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertRedirectsNoFollow(res, url)
|
||||
|
@ -137,4 +137,6 @@ class UpdateView(user_views.UpdateView):
|
||||
return {'network_id': network['id'],
|
||||
'tenant_id': network['tenant_id'],
|
||||
'name': network['name'],
|
||||
'shared': network['shared']}
|
||||
'admin_state': network['admin_state_up'],
|
||||
'shared': network['shared'],
|
||||
'external': network['router__external']}
|
||||
|
@ -39,12 +39,15 @@ class UpdateNetwork(forms.SelfHandlingForm):
|
||||
network_id = forms.CharField(label=_("ID"),
|
||||
widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}))
|
||||
admin_state = forms.BooleanField(label=_("Admin State"), required=False)
|
||||
failure_url = 'horizon:project:networks:index'
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
params = {'admin_state_up': data['admin_state'],
|
||||
'name': data['name']}
|
||||
network = api.quantum.network_modify(request, data['network_id'],
|
||||
name=data['name'])
|
||||
**params)
|
||||
msg = _('Network %s was successfully updated.') % data['name']
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
|
@ -0,0 +1,56 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UpdatePort(forms.SelfHandlingForm):
|
||||
network_id = forms.CharField(widget=forms.HiddenInput())
|
||||
port_id = forms.CharField(widget=forms.HiddenInput())
|
||||
name = forms.CharField(max_length=255,
|
||||
label=_("Name"),
|
||||
required=False)
|
||||
admin_state = forms.BooleanField(label=_("Admin State"), required=False)
|
||||
failure_url = 'horizon:project:networks:detail'
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.debug('params = %s' % data)
|
||||
port = api.quantum.port_modify(request, data['port_id'],
|
||||
name=data['name'],
|
||||
admin_state_up=data['admin_state'])
|
||||
msg = _('Port %s was successfully updated.') % data['port_id']
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
return port
|
||||
except Exception:
|
||||
msg = _('Failed to update port %s') % data['port_id']
|
||||
LOG.info(msg)
|
||||
redirect = reverse(self.failure_url,
|
||||
args=[data['network_id']])
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
@ -16,6 +16,7 @@
|
||||
|
||||
import logging
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django import template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
@ -32,7 +33,23 @@ def get_fixed_ips(port):
|
||||
|
||||
|
||||
def get_attached(port):
|
||||
return _('Attached') if port['device_id'] else _('Detached')
|
||||
if port['device_owner']:
|
||||
return port['device_owner']
|
||||
elif port['device_id']:
|
||||
return _('Attached')
|
||||
else:
|
||||
return _('Detached')
|
||||
|
||||
|
||||
class UpdatePort(tables.LinkAction):
|
||||
name = "update"
|
||||
verbose_name = _("Edit Port")
|
||||
url = "horizon:project:networks:editport"
|
||||
classes = ("ajax-modal", "btn-edit")
|
||||
|
||||
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):
|
||||
@ -40,7 +57,7 @@ class PortsTable(tables.DataTable):
|
||||
verbose_name=_("Name"),
|
||||
link="horizon:project:networks:ports:detail")
|
||||
fixed_ips = tables.Column(get_fixed_ips, verbose_name=_("Fixed IPs"))
|
||||
attached = tables.Column(get_attached, verbose_name=_("Device Attached"))
|
||||
attached = tables.Column(get_attached, verbose_name=_("Attached Device"))
|
||||
status = tables.Column("status", verbose_name=_("Status"))
|
||||
admin_state = tables.Column("admin_state",
|
||||
verbose_name=_("Admin State"))
|
||||
@ -51,3 +68,4 @@ class PortsTable(tables.DataTable):
|
||||
class Meta:
|
||||
name = "ports"
|
||||
verbose_name = _("Ports")
|
||||
row_actions = (UpdatePort,)
|
||||
|
@ -14,11 +14,59 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import tabs
|
||||
|
||||
from openstack_dashboard import api
|
||||
|
||||
from .forms import UpdatePort
|
||||
from .tabs import PortDetailTabs
|
||||
|
||||
|
||||
class DetailView(tabs.TabView):
|
||||
tab_group_class = PortDetailTabs
|
||||
template_name = 'project/networks/ports/detail.html'
|
||||
|
||||
|
||||
class UpdateView(forms.ModalFormView):
|
||||
form_class = UpdatePort
|
||||
template_name = 'project/networks/ports/update.html'
|
||||
context_object_name = 'port'
|
||||
success_url = 'horizon:project:networks:detail'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse(self.success_url,
|
||||
args=(self.kwargs['network_id'],))
|
||||
|
||||
def _get_object(self, *args, **kwargs):
|
||||
if not hasattr(self, "_object"):
|
||||
port_id = self.kwargs['port_id']
|
||||
try:
|
||||
self._object = api.quantum.port_get(self.request, port_id)
|
||||
except:
|
||||
redirect = reverse("horizon:project:networks:detail",
|
||||
args=(self.kwargs['network_id'],))
|
||||
msg = _('Unable to retrieve port details')
|
||||
exceptions.handle(self.request, msg, redirect=redirect)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||
port = self._get_object()
|
||||
context['port_id'] = port['id']
|
||||
context['network_id'] = port['network_id']
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
port = self._get_object()
|
||||
return {'port_id': port['id'],
|
||||
'network_id': port['network_id'],
|
||||
'tenant_id': port['tenant_id'],
|
||||
'name': port['name'],
|
||||
'admin_state': port['admin_state_up'],
|
||||
'device_id': port['device_id'],
|
||||
'device_owner': port['device_owner']}
|
||||
|
@ -1,139 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# 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
|
||||
import netaddr
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from horizon import exceptions
|
||||
from horizon.utils import fields
|
||||
|
||||
from openstack_dashboard import api
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateSubnet(forms.SelfHandlingForm):
|
||||
network_name = forms.CharField(label=_("Network Name"),
|
||||
required=False,
|
||||
widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}))
|
||||
network_id = forms.CharField(label=_("Network ID"),
|
||||
widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}))
|
||||
name = forms.CharField(max_length=255,
|
||||
label=_("Name"),
|
||||
required=False)
|
||||
cidr = fields.IPField(label=_("Network Address"),
|
||||
required=True,
|
||||
initial="",
|
||||
help_text=_("Network address in CIDR format "
|
||||
"(e.g. 192.168.0.0/24)"),
|
||||
version=fields.IPv4 | fields.IPv6,
|
||||
mask=True)
|
||||
ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
|
||||
label=_("IP Version"))
|
||||
gateway_ip = fields.IPField(label=_("Gateway IP"),
|
||||
required=False,
|
||||
initial="",
|
||||
help_text=_("IP address of Gateway "
|
||||
"(e.g. 192.168.0.1)"),
|
||||
version=fields.IPv4 | fields.IPv6,
|
||||
mask=False)
|
||||
failure_url = 'horizon:project:networks:detail'
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(CreateSubnet, self).clean()
|
||||
cidr = cleaned_data.get('cidr')
|
||||
ip_version = int(cleaned_data.get('ip_version'))
|
||||
gateway_ip = cleaned_data.get('gateway_ip')
|
||||
if cidr:
|
||||
if netaddr.IPNetwork(cidr).version is not ip_version:
|
||||
msg = _('Network Address and IP version are inconsistent.')
|
||||
raise forms.ValidationError(msg)
|
||||
if gateway_ip:
|
||||
if netaddr.IPAddress(gateway_ip).version is not ip_version:
|
||||
msg = _('Gateway IP and IP version are inconsistent.')
|
||||
raise forms.ValidationError(msg)
|
||||
return cleaned_data
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.debug('params = %s' % data)
|
||||
data['ip_version'] = int(data['ip_version'])
|
||||
if not data['gateway_ip']:
|
||||
del data['gateway_ip']
|
||||
subnet = api.quantum.subnet_create(request, **data)
|
||||
msg = _('Subnet %s was successfully created.') % data['cidr']
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
return subnet
|
||||
except Exception:
|
||||
msg = _('Failed to create subnet %s') % data['cidr']
|
||||
LOG.info(msg)
|
||||
redirect = reverse(self.failure_url, args=[data['network_id']])
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
|
||||
|
||||
class UpdateSubnet(forms.SelfHandlingForm):
|
||||
network_id = forms.CharField(widget=forms.HiddenInput())
|
||||
subnet_id = forms.CharField(widget=forms.HiddenInput())
|
||||
cidr = forms.CharField(widget=forms.HiddenInput())
|
||||
ip_version = forms.CharField(widget=forms.HiddenInput())
|
||||
name = forms.CharField(max_length=255,
|
||||
label=_("Name"),
|
||||
required=False)
|
||||
gateway_ip = fields.IPField(label=_("Gateway IP"),
|
||||
required=True,
|
||||
initial="",
|
||||
help_text=_("IP address of Gateway "
|
||||
"(e.g. 192.168.0.1)"),
|
||||
version=fields.IPv4 | fields.IPv6,
|
||||
mask=False)
|
||||
failure_url = 'horizon:project:networks:detail'
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(UpdateSubnet, self).clean()
|
||||
ip_version = int(cleaned_data.get('ip_version'))
|
||||
gateway_ip = cleaned_data.get('gateway_ip')
|
||||
if gateway_ip:
|
||||
if netaddr.IPAddress(gateway_ip).version is not ip_version:
|
||||
msg = _('Gateway IP and IP version are inconsistent.')
|
||||
raise forms.ValidationError(msg)
|
||||
return cleaned_data
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.debug('params = %s' % data)
|
||||
params = {'name': data['name']}
|
||||
params['gateway_ip'] = data['gateway_ip']
|
||||
subnet = api.quantum.subnet_modify(request, data['subnet_id'],
|
||||
name=data['name'],
|
||||
gateway_ip=data['gateway_ip'])
|
||||
msg = _('Subnet %s was successfully updated.') % data['cidr']
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
return subnet
|
||||
except Exception:
|
||||
msg = _('Failed to update subnet %s') % data['cidr']
|
||||
LOG.info(msg)
|
||||
redirect = reverse(self.failure_url, args=[data['network_id']])
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
@ -22,26 +22,21 @@ import logging
|
||||
from django.core.urlresolvers import reverse_lazy, reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import forms
|
||||
from horizon import exceptions
|
||||
from horizon import tabs
|
||||
from horizon import workflows
|
||||
|
||||
from openstack_dashboard import api
|
||||
from .forms import CreateSubnet, UpdateSubnet
|
||||
from .tabs import SubnetDetailTabs
|
||||
from .workflows import CreateSubnet, UpdateSubnet
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateView(forms.ModalFormView):
|
||||
form_class = CreateSubnet
|
||||
class CreateView(workflows.WorkflowView):
|
||||
workflow_class = CreateSubnet
|
||||
template_name = 'project/networks/subnets/create.html'
|
||||
success_url = 'horizon:project:networks:detail'
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse(self.success_url,
|
||||
args=(self.kwargs['network_id'],))
|
||||
|
||||
def get_object(self):
|
||||
if not hasattr(self, "_object"):
|
||||
@ -49,32 +44,22 @@ class CreateView(forms.ModalFormView):
|
||||
network_id = self.kwargs["network_id"]
|
||||
self._object = api.quantum.network_get(self.request,
|
||||
network_id)
|
||||
self._object.set_id_as_name_if_empty()
|
||||
except:
|
||||
redirect = reverse('horizon:project:networks:index')
|
||||
msg = _("Unable to retrieve network.")
|
||||
exceptions.handle(self.request, msg, redirect=redirect)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(CreateView, self).get_context_data(**kwargs)
|
||||
context['network'] = self.get_object()
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
network = self.get_object()
|
||||
return {"network_id": self.kwargs['network_id'],
|
||||
"network_name": network.name}
|
||||
|
||||
|
||||
class UpdateView(forms.ModalFormView):
|
||||
form_class = UpdateSubnet
|
||||
class UpdateView(workflows.WorkflowView):
|
||||
workflow_class = UpdateSubnet
|
||||
template_name = 'project/networks/subnets/update.html'
|
||||
context_object_name = 'subnet'
|
||||
success_url = reverse_lazy('horizon:project:networks:detail')
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('horizon:project:networks:detail',
|
||||
args=(self.kwargs['network_id'],))
|
||||
|
||||
def _get_object(self, *args, **kwargs):
|
||||
if not hasattr(self, "_object"):
|
||||
@ -87,23 +72,30 @@ class UpdateView(forms.ModalFormView):
|
||||
exceptions.handle(self.request, msg, redirect=redirect)
|
||||
return self._object
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||
subnet = self._get_object()
|
||||
context['subnet_id'] = subnet.id
|
||||
context['network_id'] = subnet.network_id
|
||||
context['cidr'] = subnet.cidr
|
||||
context['ip_version'] = subnet.ipver_str
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
initial = super(UpdateView, self).get_initial()
|
||||
|
||||
subnet = self._get_object()
|
||||
return {'network_id': self.kwargs['network_id'],
|
||||
'subnet_id': subnet['id'],
|
||||
'cidr': subnet['cidr'],
|
||||
'ip_version': subnet['ip_version'],
|
||||
'name': subnet['name'],
|
||||
'gateway_ip': subnet['gateway_ip']}
|
||||
|
||||
initial['network_id'] = self.kwargs['network_id']
|
||||
initial['subnet_id'] = subnet['id']
|
||||
initial['subnet_name'] = subnet['name']
|
||||
|
||||
for key in ('cidr', 'ip_version', 'enable_dhcp'):
|
||||
initial[key] = subnet[key]
|
||||
|
||||
initial['gateway_ip'] = subnet['gateway_ip'] or ''
|
||||
initial['no_gateway'] = (subnet['gateway_ip'] is None)
|
||||
|
||||
initial['dns_nameservers'] = '\n'.join(subnet['dns_nameservers'])
|
||||
pools = ['%s,%s' % (p['start'], p['end'])
|
||||
for p in subnet['allocation_pools']]
|
||||
initial['allocation_pools'] = '\n'.join(pools)
|
||||
routes = ['%s,%s' % (r['destination'], r['nexthop'])
|
||||
for r in subnet['host_routes']]
|
||||
initial['host_routes'] = '\n'.join(routes)
|
||||
|
||||
return initial
|
||||
|
||||
|
||||
class DetailView(tabs.TabView):
|
||||
|
@ -0,0 +1,198 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 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
|
||||
|
||||
import netaddr
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon.utils import fields
|
||||
from horizon import workflows
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.dashboards.project.networks import workflows \
|
||||
as network_workflows
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateSubnetInfoAction(network_workflows.CreateSubnetInfoAction):
|
||||
with_subnet = forms.BooleanField(initial=True, required=False,
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
class Meta:
|
||||
name = ("Subnet")
|
||||
help_text = _('You can create a subnet associated with the '
|
||||
'network. Advanced configuration are available '
|
||||
'at "Subnet Detail" tab.')
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = workflows.Action.clean(self)
|
||||
self._check_subnet_data(cleaned_data)
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class CreateSubnetInfo(network_workflows.CreateSubnetInfo):
|
||||
action_class = CreateSubnetInfoAction
|
||||
depends_on = ("network_id",)
|
||||
|
||||
|
||||
class CreateSubnet(network_workflows.CreateNetwork):
|
||||
slug = "create_subnet"
|
||||
name = _("Create Subnet")
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _('Created subnet "%s".')
|
||||
failure_message = _('Unable to create subnet "%s".')
|
||||
default_steps = (CreateSubnetInfo,
|
||||
network_workflows.CreateSubnetDetail)
|
||||
|
||||
def format_status_message(self, message):
|
||||
name = self.context.get('subnet_name') or self.context.get('subnet_id')
|
||||
return message % name
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("horizon:project:networks:detail",
|
||||
args=(self.context.get('network_id'),))
|
||||
|
||||
def get_failure_url(self):
|
||||
return reverse("horizon:project:networks:detail",
|
||||
args=(self.context.get('network_id'),))
|
||||
|
||||
def handle(self, request, data):
|
||||
subnet = self._create_subnet(request, data)
|
||||
return True if subnet else False
|
||||
|
||||
|
||||
class UpdateSubnetInfoAction(CreateSubnetInfoAction):
|
||||
cidr = fields.IPField(label=_("Network Address"),
|
||||
required=False,
|
||||
initial="",
|
||||
widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}),
|
||||
help_text=_("Network address in CIDR format "
|
||||
"(e.g. 192.168.0.0/24)"),
|
||||
version=fields.IPv4 | fields.IPv6,
|
||||
mask=True)
|
||||
# NOTE(amotoki): When 'disabled' attribute is set for the ChoiceField
|
||||
# and ValidationError is raised for POST request, the initial value of
|
||||
# the ip_version ChoiceField is not set in the re-displayed form
|
||||
# As a result, 'IPv4' is displayed even when IPv6 is used if
|
||||
# ValidationError is detected. In addition 'required=True' check complains
|
||||
# when re-POST since the value of the ChoiceField is not set.
|
||||
# Thus now I use HiddenInput for the ip_version ChoiceField as a work
|
||||
# around.
|
||||
ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
|
||||
#widget=forms.Select(
|
||||
# attrs={'disabled': 'disabled'}),
|
||||
widget=forms.HiddenInput(),
|
||||
label=_("IP Version"))
|
||||
|
||||
gateway_ip = fields.IPField(
|
||||
label=_("Gateway IP (optional)"),
|
||||
required=False,
|
||||
initial="",
|
||||
help_text=_("IP address of Gateway (e.g. 192.168.0.254). "
|
||||
"You need to specify an explicit address "
|
||||
"to set the gateway. "
|
||||
"If you want to use no gateway, "
|
||||
"check 'Disable Gateway' below."),
|
||||
version=fields.IPv4 | fields.IPv6,
|
||||
mask=False)
|
||||
no_gateway = forms.BooleanField(label=_("Disable Gateway"),
|
||||
initial=False, required=False)
|
||||
|
||||
class Meta:
|
||||
name = ("Subnet")
|
||||
help_text = _('You can update a subnet associated with the '
|
||||
'network. Advanced configuration are available '
|
||||
'at "Subnet Detail" tab.')
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = workflows.Action.clean(self)
|
||||
self._check_subnet_data(cleaned_data, is_create=False)
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class UpdateSubnetInfo(CreateSubnetInfo):
|
||||
action_class = UpdateSubnetInfoAction
|
||||
depends_on = ("network_id", "subnet_id")
|
||||
|
||||
|
||||
class UpdateSubnetDetailAction(network_workflows.CreateSubnetDetailAction):
|
||||
allocation_pools = forms.CharField(widget=forms.HiddenInput(),
|
||||
required=False)
|
||||
|
||||
class Meta:
|
||||
name = ("Subnet Detail")
|
||||
help_text = _('You can specify additional attributes for the subnet.')
|
||||
|
||||
|
||||
class UpdateSubnetDetail(network_workflows.CreateSubnetDetail):
|
||||
action_class = UpdateSubnetDetailAction
|
||||
|
||||
|
||||
class UpdateSubnet(network_workflows.CreateNetwork):
|
||||
slug = "update_subnet"
|
||||
name = _("Update Subnet")
|
||||
finalize_button_name = _("Update")
|
||||
success_message = _('Updated subnet "%s".')
|
||||
failure_message = _('Unable to update subnet "%s".')
|
||||
success_url = "horizon:project:networks:detail"
|
||||
failure_url = "horizon:project:networks:detail"
|
||||
default_steps = (UpdateSubnetInfo,
|
||||
UpdateSubnetDetail)
|
||||
|
||||
def format_status_message(self, message):
|
||||
name = self.context.get('subnet_name') or self.context.get('subnet_id')
|
||||
return message % name
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse(self.success_url,
|
||||
args=(self.context.get('network_id'),))
|
||||
|
||||
def _update_subnet(self, request, data):
|
||||
network_id = self.context.get('network_id')
|
||||
try:
|
||||
subnet_id = self.context.get('subnet_id')
|
||||
params = {}
|
||||
params['name'] = data['subnet_name']
|
||||
if data['no_gateway']:
|
||||
params['gateway_ip'] = None
|
||||
elif data['gateway_ip']:
|
||||
params['gateway_ip'] = data['gateway_ip']
|
||||
|
||||
self._setup_subnet_parameters(params, data, is_create=False)
|
||||
|
||||
subnet = api.quantum.subnet_modify(request, subnet_id, **params)
|
||||
msg = _('Subnet "%s" was successfully updated.') % data['cidr']
|
||||
LOG.debug(msg)
|
||||
return subnet
|
||||
except Exception as e:
|
||||
msg = (_('Failed to update subnet "%(sub)s": '
|
||||
' %(reason)s') %
|
||||
{"sub": data['cidr'], "reason": e})
|
||||
redirect = reverse(self.failure_url, args=(network_id,))
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
return False
|
||||
|
||||
def handle(self, request, data):
|
||||
subnet = self._update_subnet(request, data)
|
||||
return True if subnet else False
|
@ -16,5 +16,13 @@
|
||||
<dd>{{ network.admin_state|default:"Unknown" }}</dd>
|
||||
<dt>{% trans "Shared" %}</dt>
|
||||
<dd>{{ network.shared|yesno|capfirst }}</dd>
|
||||
<dt>{% trans "External Network" %}</dt>
|
||||
<dd>{{ network.router__external|yesno|capfirst }}</dd>
|
||||
{% if network.provider__network_type %}
|
||||
<dt>{% trans "Provider Network" %}</dt>
|
||||
<dd>{% trans "Network Type" %}: {{ network.provider__network_type|default:"Unknown" }}</dd>
|
||||
<dd>{% trans "Physical Network" %}: {{ network.provider__physical_network|default:"-" }}</dd>
|
||||
<dd>{% trans "Segmentation ID" %}: {{ network.provider__segmentation_id|default:"-" }}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
|
@ -10,8 +10,9 @@
|
||||
<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>{{ port.network_id|default:"None" }}</dd>
|
||||
<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 "Fixed IP" %}</dt>
|
||||
@ -31,9 +32,10 @@
|
||||
<dd>{{ port.status|default:"None" }}</dd>
|
||||
<dt>{% trans "Admin State" %}</dt>
|
||||
<dd>{{ port.admin_state|default:"None" }}</dd>
|
||||
<dt>{% trans "Device ID" %}</dt>
|
||||
{% if port.device_id|length > 1 %}
|
||||
<dd>{{ port.device_id }}</dd>
|
||||
<dt>{% trans "Attached Device" %}</dt>
|
||||
{% if port.device_id|length > 1 or port.device_owner %}
|
||||
<dd><b>{% trans "Device Owner" %}</b>: {{ port.device_owner|default:"None" }}</dd>
|
||||
<dd><b>{% trans "Device ID" %}</b>: {{ port.device_id|default:"-" }}</dd>
|
||||
{% else %}
|
||||
<dd>No attached device</dd>
|
||||
{% endif %}
|
||||
|
@ -1,20 +1,16 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block form_id %}update_subnet_form{% endblock %}
|
||||
{% block form_action %}{% url horizon:project:networks:editsubnet network_id subnet_id %}{% endblock %}
|
||||
{% block form_id %}update_port_form{% endblock %}
|
||||
{% block form_action %}{% url horizon:project:networks:editport network_id port_id %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Edit Subnet" %}{% endblock %}
|
||||
{% block modal-header %}{% trans "Edit Port" %}{% endblock %}
|
||||
|
||||
{% block modal-body %}
|
||||
<div class="left">
|
||||
<dl>
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ subnet_id }}</dd>
|
||||
<dt>{% trans "Network Address" %}</dt>
|
||||
<dd>{{ cidr }}</dd>
|
||||
<dt>{% trans "IP version" %}</dt>
|
||||
<dd>{{ ip_version }}</dd>
|
||||
<dd>{{ port_id }}</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
<fieldset>
|
||||
@ -23,7 +19,7 @@
|
||||
</div>
|
||||
<div class="right">
|
||||
<h3>{% trans "Description:" %}</h3>
|
||||
<p>{% trans "You may update the editable properties of your subnet here." %}</p>
|
||||
<p>{% trans "You may update the editable properties of your port here." %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Update Port" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Update Port") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'project/networks/ports/_update.html' %}
|
||||
{% endblock %}
|
@ -1,25 +0,0 @@
|
||||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block form_id %}create_subnet_form{% endblock %}
|
||||
{% block form_action %}{% url horizon:project:networks:addsubnet network.id %}
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Create Subnet" %}{% endblock %}
|
||||
|
||||
{% block modal-body %}
|
||||
<div class="left">
|
||||
<fieldset>
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="right">
|
||||
<h3>{% trans "Description" %}:</h3>
|
||||
<p>{% trans "You can create a subnet for the network. Any network address can be specified unless the network address does not overlap other subnets in the network." %}</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Create Subnet" %}" />
|
||||
<a href="{% url horizon:project:networks:index %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
@ -10,14 +10,13 @@
|
||||
<dd>{{ subnet.name|default:"None" }}</dd>
|
||||
<dt>{% trans "ID" %}</dt>
|
||||
<dd>{{ subnet.id|default:"None" }}</dd>
|
||||
{% url horizon:project:networks:detail subnet.network_id as network_url %}
|
||||
<dt>{% trans "Network ID" %}</dt>
|
||||
<dd>{{ subnet.network_id|default:"None" }}</dd>
|
||||
<dt>{% trans "CIDR" %}</dt>
|
||||
<dd>{{ subnet.cidr|default:"None" }}</dd>
|
||||
<dd><a href="{{ network_url }}">{{ subnet.network_id|default:"None" }}</a></dd>
|
||||
<dt>{% trans "IP version" %}</dt>
|
||||
<dd>{{ subnet.ipver_str|default:"-" }}</dd>
|
||||
<dt>{% trans "Gateway IP" %}</dt>
|
||||
<dd>{{ subnet.gateway_ip|default:"-" }}</dd>
|
||||
<dt>{% trans "CIDR" %}</dt>
|
||||
<dd>{{ subnet.cidr|default:"None" }}</dd>
|
||||
<dt>{% trans "IP allocation pool" %}</dt>
|
||||
<dd>
|
||||
{% for pool in subnet.allocation_pools %}
|
||||
@ -25,5 +24,26 @@
|
||||
{% trans " - End" %} {{ pool.end }}<br>
|
||||
{% endfor %}
|
||||
</dd>
|
||||
<dt>{% trans "DHCP Enable" %}<dt>
|
||||
<dd>{{ subnet.enable_dhcp|yesno|capfirst }}</dd>
|
||||
<dt>{% trans "Gateway IP" %}</dt>
|
||||
<dd>{{ subnet.gateway_ip|default:"-" }}</dd>
|
||||
<dt>{% trans "Additional routes" %}</dt>
|
||||
<dd>
|
||||
{% for route in subnet.host_routes %}
|
||||
{% trans "Destination" %} {{ route.destination }}
|
||||
{% trans " : Next hop" %} {{ route.nexthop }}<br>
|
||||
{% empty %}
|
||||
{% trans "None" %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
<dt>{% trans "DNS name server" %}</dt>
|
||||
<dd>
|
||||
{% for dns in subnet.dns_nameservers %}
|
||||
{{ dns }}
|
||||
{% empty %}
|
||||
{% trans "None" %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
@ -7,5 +7,5 @@
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include "project/networks/subnets/_create.html" %}
|
||||
{% include "horizon/common/_workflow.html" %}
|
||||
{% endblock %}
|
||||
|
@ -7,5 +7,5 @@
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'project/networks/subnets/_update.html' %}
|
||||
{% include "horizon/common/_workflow.html" %}
|
||||
{% endblock %}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@ from .views import IndexView, CreateView, DetailView, UpdateView
|
||||
from .subnets.views import CreateView as AddSubnetView
|
||||
from .subnets.views import UpdateView as EditSubnetView
|
||||
from .subnets import urls as subnet_urls
|
||||
from .ports.views import UpdateView as EditPortView
|
||||
from .ports import urls as port_urls
|
||||
|
||||
|
||||
@ -35,5 +36,7 @@ urlpatterns = patterns('',
|
||||
name='addsubnet'),
|
||||
url(r'^(?P<network_id>[^/]+)/subnets/(?P<subnet_id>[^/]+)/update$',
|
||||
EditSubnetView.as_view(), name='editsubnet'),
|
||||
url(r'^(?P<network_id>[^/]+)/ports/(?P<port_id>[^/]+)/update$',
|
||||
EditPortView.as_view(), name='editport'),
|
||||
url(r'^subnets/', include(subnet_urls, namespace='subnets')),
|
||||
url(r'^ports/', include(port_urls, namespace='ports')))
|
||||
|
@ -91,7 +91,8 @@ class UpdateView(forms.ModalFormView):
|
||||
network = self._get_object()
|
||||
return {'network_id': network['id'],
|
||||
'tenant_id': network['tenant_id'],
|
||||
'name': network['name']}
|
||||
'name': network['name'],
|
||||
'admin_state': network['admin_state_up']}
|
||||
|
||||
|
||||
class DetailView(tables.MultiTableView):
|
||||
|
@ -23,6 +23,7 @@ from django.utils.translation import ugettext as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from horizon import workflows
|
||||
from horizon.utils import fields
|
||||
|
||||
@ -34,8 +35,12 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
class CreateNetworkInfoAction(workflows.Action):
|
||||
net_name = forms.CharField(max_length=255,
|
||||
label=_("Network Name (optional)"),
|
||||
label=_("Network Name"),
|
||||
help_text=_("Network Name. This field is "
|
||||
"optional."),
|
||||
required=False)
|
||||
admin_state = forms.BooleanField(label=_("Admin State"),
|
||||
initial=True, required=False)
|
||||
|
||||
class Meta:
|
||||
name = ("Network")
|
||||
@ -46,14 +51,16 @@ class CreateNetworkInfoAction(workflows.Action):
|
||||
|
||||
class CreateNetworkInfo(workflows.Step):
|
||||
action_class = CreateNetworkInfoAction
|
||||
contributes = ("net_name",)
|
||||
contributes = ("net_name", "admin_state")
|
||||
|
||||
|
||||
class CreateSubnetInfoAction(workflows.Action):
|
||||
with_subnet = forms.BooleanField(label=_("Create Subnet"),
|
||||
initial=True, required=False)
|
||||
subnet_name = forms.CharField(max_length=255,
|
||||
label=_("Subnet Name (optional)"),
|
||||
label=_("Subnet Name"),
|
||||
help_text=_("Subnet Name. This field is "
|
||||
"optional."),
|
||||
required=False)
|
||||
cidr = fields.IPField(label=_("Network Address"),
|
||||
required=False,
|
||||
@ -64,13 +71,21 @@ class CreateSubnetInfoAction(workflows.Action):
|
||||
mask=True)
|
||||
ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
|
||||
label=_("IP Version"))
|
||||
gateway_ip = fields.IPField(label=_("Gateway IP (optional)"),
|
||||
required=False,
|
||||
initial="",
|
||||
help_text=_("IP address of Gateway "
|
||||
"(e.g. 192.168.0.1)"),
|
||||
version=fields.IPv4 | fields.IPv6,
|
||||
mask=False)
|
||||
gateway_ip = fields.IPField(
|
||||
label=_("Gateway IP (optional)"),
|
||||
required=False,
|
||||
initial="",
|
||||
help_text=_("IP address of Gateway (e.g. 192.168.0.254) "
|
||||
"The default value is the first IP of the "
|
||||
"network address (e.g. 192.168.0.1 for "
|
||||
"192.168.0.0/24). "
|
||||
"If you use the default, leave blank. "
|
||||
"If you want to use no gateway, "
|
||||
"check 'Disable Gateway' below."),
|
||||
version=fields.IPv4 | fields.IPv6,
|
||||
mask=False)
|
||||
no_gateway = forms.BooleanField(label=_("Disable Gateway"),
|
||||
initial=False, required=False)
|
||||
|
||||
class Meta:
|
||||
name = ("Subnet")
|
||||
@ -79,13 +94,12 @@ class CreateSubnetInfoAction(workflows.Action):
|
||||
'specified. If you wish to create a network WITHOUT a '
|
||||
'subnet, uncheck the "Create Subnet" checkbox.')
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(CreateSubnetInfoAction, self).clean()
|
||||
with_subnet = cleaned_data.get('with_subnet')
|
||||
def _check_subnet_data(self, cleaned_data, is_create=True):
|
||||
cidr = cleaned_data.get('cidr')
|
||||
ip_version = int(cleaned_data.get('ip_version'))
|
||||
gateway_ip = cleaned_data.get('gateway_ip')
|
||||
if with_subnet and not cidr:
|
||||
no_gateway = cleaned_data.get('no_gateway')
|
||||
if not cidr:
|
||||
msg = _('Specify "Network Address" or '
|
||||
'clear "Create Subnet" checkbox.')
|
||||
raise forms.ValidationError(msg)
|
||||
@ -93,17 +107,126 @@ class CreateSubnetInfoAction(workflows.Action):
|
||||
if netaddr.IPNetwork(cidr).version is not ip_version:
|
||||
msg = _('Network Address and IP version are inconsistent.')
|
||||
raise forms.ValidationError(msg)
|
||||
if gateway_ip:
|
||||
if not no_gateway and gateway_ip:
|
||||
if netaddr.IPAddress(gateway_ip).version is not ip_version:
|
||||
msg = _('Gateway IP and IP version are inconsistent.')
|
||||
raise forms.ValidationError(msg)
|
||||
if not is_create and not no_gateway and not gateway_ip:
|
||||
msg = _('Specify IP address of gateway or '
|
||||
'check "Disable Gateway".')
|
||||
raise forms.ValidationError(msg)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(CreateSubnetInfoAction, self).clean()
|
||||
with_subnet = cleaned_data.get('with_subnet')
|
||||
if not with_subnet:
|
||||
return cleaned_data
|
||||
self._check_subnet_data(cleaned_data)
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class CreateSubnetInfo(workflows.Step):
|
||||
action_class = CreateSubnetInfoAction
|
||||
contributes = ("with_subnet", "subnet_name", "cidr",
|
||||
"ip_version", "gateway_ip")
|
||||
"ip_version", "gateway_ip", "no_gateway")
|
||||
|
||||
|
||||
class CreateSubnetDetailAction(workflows.Action):
|
||||
enable_dhcp = forms.BooleanField(label=_("Enable DHCP"),
|
||||
initial=True, required=False)
|
||||
allocation_pools = forms.CharField(
|
||||
widget=forms.Textarea(),
|
||||
label=_("Allocation Pools"),
|
||||
help_text=_("IP address allocation pools. Each entry is "
|
||||
"<start_ip_address>,<end_ip_address> "
|
||||
"(e.g., 192.168.1.100,192.168.1.120) "
|
||||
"and one entry per line."),
|
||||
required=False)
|
||||
dns_nameservers = forms.CharField(
|
||||
widget=forms.widgets.Textarea(),
|
||||
label=_("DNS Name Servers"),
|
||||
help_text=_("IP address list of DNS name servers for this subnet. "
|
||||
"One entry per line."),
|
||||
required=False)
|
||||
host_routes = forms.CharField(
|
||||
widget=forms.widgets.Textarea(),
|
||||
label=_("Host Routes"),
|
||||
help_text=_("Additional routes announced to the hosts. "
|
||||
"Each entry is <destination_cidr>,<nexthop> "
|
||||
"(e.g., 192.168.200.0/24,10.56.1.254)"
|
||||
"and one entry per line."),
|
||||
required=False)
|
||||
|
||||
class Meta:
|
||||
name = ("Subnet Detail")
|
||||
help_text = _('You can specify additional attributes for the subnet.')
|
||||
|
||||
def _convert_ip_address(self, ip, field_name):
|
||||
try:
|
||||
return netaddr.IPAddress(ip)
|
||||
except (netaddr.AddrFormatError, ValueError):
|
||||
msg = _('%(field_name)s: Invalid IP address '
|
||||
'(value=%(ip)s)') % locals()
|
||||
raise forms.ValidationError(msg)
|
||||
|
||||
def _convert_ip_network(self, network, field_name):
|
||||
try:
|
||||
return netaddr.IPNetwork(network)
|
||||
except (netaddr.AddrFormatError, ValueError):
|
||||
msg = _('%(field_name)s: Invalid IP address '
|
||||
'(value=%(network)s)') % locals()
|
||||
raise forms.ValidationError(msg)
|
||||
|
||||
def _check_allocation_pools(self, allocation_pools):
|
||||
for p in allocation_pools.split('\n'):
|
||||
p = p.strip()
|
||||
if not p:
|
||||
continue
|
||||
pool = p.split(',')
|
||||
if len(pool) != 2:
|
||||
msg = _('Start and end addresses must be specified '
|
||||
'(value=%s)') % p
|
||||
raise forms.ValidationError(msg)
|
||||
start, end = [self._convert_ip_address(ip, "allocation_pools")
|
||||
for ip in pool]
|
||||
if start > end:
|
||||
msg = _('Start address is larger than end address '
|
||||
'(value=%s)') % p
|
||||
raise forms.ValidationError(msg)
|
||||
|
||||
def _check_dns_nameservers(self, dns_nameservers):
|
||||
for ns in dns_nameservers.split('\n'):
|
||||
ns = ns.strip()
|
||||
if not ns:
|
||||
continue
|
||||
self._convert_ip_address(ns, "dns_nameservers")
|
||||
|
||||
def _check_host_routes(self, host_routes):
|
||||
for r in host_routes.split('\n'):
|
||||
r = r.strip()
|
||||
if not r:
|
||||
continue
|
||||
route = r.split(',')
|
||||
if len(route) != 2:
|
||||
msg = _('Host Routes format error: '
|
||||
'Destination CIDR and nexthop must be specified '
|
||||
'(value=%s)') % r
|
||||
raise forms.ValidationError(msg)
|
||||
dest = self._convert_ip_network(route[0], "host_routes")
|
||||
nexthop = self._convert_ip_address(route[1], "host_routes")
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(CreateSubnetDetailAction, self).clean()
|
||||
self._check_allocation_pools(cleaned_data.get('allocation_pools'))
|
||||
self._check_host_routes(cleaned_data.get('host_routes'))
|
||||
self._check_dns_nameservers(cleaned_data.get('dns_nameservers'))
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class CreateSubnetDetail(workflows.Step):
|
||||
action_class = CreateSubnetDetailAction
|
||||
contributes = ("enable_dhcp", "allocation_pools",
|
||||
"dns_nameservers", "host_routes")
|
||||
|
||||
|
||||
class CreateNetwork(workflows.Workflow):
|
||||
@ -112,51 +235,130 @@ class CreateNetwork(workflows.Workflow):
|
||||
finalize_button_name = _("Create")
|
||||
success_message = _('Created network "%s".')
|
||||
failure_message = _('Unable to create network "%s".')
|
||||
success_url = "horizon:project:networks:index"
|
||||
default_steps = (CreateNetworkInfo,
|
||||
CreateSubnetInfo)
|
||||
CreateSubnetInfo,
|
||||
CreateSubnetDetail)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("horizon:project:networks:index")
|
||||
|
||||
def get_failure_url(self):
|
||||
return reverse("horizon:project:networks:index")
|
||||
|
||||
def format_status_message(self, message):
|
||||
name = self.context.get('net_name') or self.context.get('net_id', '')
|
||||
return message % name
|
||||
|
||||
def handle(self, request, data):
|
||||
# create the network
|
||||
def _create_network(self, request, data):
|
||||
try:
|
||||
network = api.quantum.network_create(request,
|
||||
name=data['net_name'])
|
||||
params = {'name': data['net_name'],
|
||||
'admin_state_up': data['admin_state']}
|
||||
network = api.quantum.network_create(request, **params)
|
||||
network.set_id_as_name_if_empty()
|
||||
self.context['net_id'] = network.id
|
||||
msg = _('Network "%s" was successfully created.') % network.name
|
||||
LOG.debug(msg)
|
||||
except:
|
||||
msg = _('Failed to create network "%s".') % data['net_name']
|
||||
return network
|
||||
except Exception as e:
|
||||
msg = (_('Failed to create network "%(network)s": %(reason)s') %
|
||||
{"network": data['net_name'], "reason": e})
|
||||
LOG.info(msg)
|
||||
redirect = reverse('horizon:project:networks:index')
|
||||
redirect = self.get_failure_url()
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
return False
|
||||
|
||||
# If we do not need to create a subnet, return here.
|
||||
if not data['with_subnet']:
|
||||
return True
|
||||
def _setup_subnet_parameters(self, params, data, is_create=True):
|
||||
"""Setup subnet parameters
|
||||
|
||||
# Create the subnet.
|
||||
This methods setups subnet parameters which are available
|
||||
in both create and update.
|
||||
"""
|
||||
is_update = not is_create
|
||||
params['enable_dhcp'] = data['enable_dhcp']
|
||||
if is_create and data['allocation_pools']:
|
||||
pools = [dict(zip(['start', 'end'], pool.strip().split(',')))
|
||||
for pool in data['allocation_pools'].split('\n')
|
||||
if pool.strip()]
|
||||
params['allocation_pools'] = pools
|
||||
if data['host_routes'] or is_update:
|
||||
routes = [dict(zip(['destination', 'nexthop'],
|
||||
route.strip().split(',')))
|
||||
for route in data['host_routes'].split('\n')
|
||||
if route.strip()]
|
||||
params['host_routes'] = routes
|
||||
if data['dns_nameservers'] or is_update:
|
||||
nameservers = [ns.strip()
|
||||
for ns in data['dns_nameservers'].split('\n')
|
||||
if ns.strip()]
|
||||
params['dns_nameservers'] = nameservers
|
||||
|
||||
def _create_subnet(self, request, data, network=None, tenant_id=None,
|
||||
no_redirect=False):
|
||||
if network:
|
||||
network_id = network.id
|
||||
network_name = network.name
|
||||
else:
|
||||
network_id = self.context.get('network_id')
|
||||
network_name = self.context.get('network_name')
|
||||
try:
|
||||
params = {'network_id': network.id,
|
||||
params = {'network_id': network_id,
|
||||
'name': data['subnet_name'],
|
||||
'cidr': data['cidr'],
|
||||
'ip_version': int(data['ip_version'])}
|
||||
if data['gateway_ip']:
|
||||
if tenant_id:
|
||||
params['tenant_id'] = tenant_id
|
||||
if data['no_gateway']:
|
||||
params['gateway_ip'] = None
|
||||
elif data['gateway_ip']:
|
||||
params['gateway_ip'] = data['gateway_ip']
|
||||
api.quantum.subnet_create(request, **params)
|
||||
|
||||
self._setup_subnet_parameters(params, data)
|
||||
|
||||
subnet = api.quantum.subnet_create(request, **params)
|
||||
self.context['subnet_id'] = subnet.id
|
||||
msg = _('Subnet "%s" was successfully created.') % data['cidr']
|
||||
LOG.debug(msg)
|
||||
except Exception:
|
||||
msg = _('Failed to create subnet "%(sub)s" for network "%(net)s".')
|
||||
redirect = reverse('horizon:project:networks:index')
|
||||
return subnet
|
||||
except Exception as e:
|
||||
msg = _('Failed to create subnet "%(sub)s" for network "%(net)s": '
|
||||
' %(reason)s')
|
||||
if no_redirect:
|
||||
redirect = None
|
||||
else:
|
||||
redirect = self.get_failure_url()
|
||||
exceptions.handle(request,
|
||||
msg % {"sub": data['cidr'], "net": network.id},
|
||||
msg % {"sub": data['cidr'], "net": network_name,
|
||||
"reason": e},
|
||||
redirect=redirect)
|
||||
return False
|
||||
|
||||
return True
|
||||
def _delete_network(self, request, network):
|
||||
"""Delete the created network when subnet creation failed"""
|
||||
try:
|
||||
api.quantum.network_delete(request, network.id)
|
||||
msg = _('Delete the created network "%s" '
|
||||
'due to subnet creation failure.') % network.name
|
||||
LOG.debug(msg)
|
||||
redirect = self.get_failure_url()
|
||||
messages.info(request, msg)
|
||||
raise exceptions.Http302(redirect)
|
||||
#return exceptions.RecoverableError
|
||||
except:
|
||||
msg = _('Failed to delete network "%s"') % network.name
|
||||
LOG.info(msg)
|
||||
redirect = self.get_failure_url()
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
|
||||
def handle(self, request, data):
|
||||
network = self._create_network(request, data)
|
||||
if not network:
|
||||
return False
|
||||
# If we do not need to create a subnet, return here.
|
||||
if not data['with_subnet']:
|
||||
return True
|
||||
subnet = self._create_subnet(request, data, network, no_redirect=True)
|
||||
if subnet:
|
||||
return True
|
||||
else:
|
||||
self._delete_network(request, network)
|
||||
return False
|
||||
|
@ -37,9 +37,12 @@ def data(TEST):
|
||||
'status': 'ACTIVE',
|
||||
'subnets': ['e8abc972-eb0c-41f1-9edd-4bc6e3bcd8c9'],
|
||||
'tenant_id': '1',
|
||||
'router:external': False,
|
||||
'shared': False}
|
||||
subnet_dict = {'allocation_pools': [{'end': '10.0.0.254',
|
||||
'start': '10.0.0.2'}],
|
||||
'dns_nameservers': [],
|
||||
'host_routes': [],
|
||||
'cidr': '10.0.0.0/24',
|
||||
'enable_dhcp': True,
|
||||
'gateway_ip': '10.0.0.1',
|
||||
@ -50,6 +53,7 @@ def data(TEST):
|
||||
'tenant_id': network_dict['tenant_id']}
|
||||
port_dict = {'admin_state_up': True,
|
||||
'device_id': 'af75c8e5-a1cc-4567-8d04-44fcd6922890',
|
||||
'device_owner': 'network:dhcp',
|
||||
'fixed_ips': [{'ip_address': '10.0.0.3',
|
||||
'subnet_id': subnet_dict['id']}],
|
||||
'id': '3ec7f3db-cb2f-4a34-ab6b-69a64d3f008c',
|
||||
@ -77,9 +81,15 @@ def data(TEST):
|
||||
'status': 'ACTIVE',
|
||||
'subnets': ['3f7c5d79-ee55-47b0-9213-8e669fb03009'],
|
||||
'tenant_id': '2',
|
||||
'router:external': True,
|
||||
'shared': True}
|
||||
subnet_dict = {'allocation_pools': [{'end': '172.16.88.254',
|
||||
'start': '172.16.88.2'}],
|
||||
'start': '172.16.88.2'}],
|
||||
'dns_nameservers': ['10.56.1.20', '10.56.1.21'],
|
||||
'host_routes': [{'destination': '192.168.20.0/24',
|
||||
'nexthop': '172.16.88.253'},
|
||||
{'destination': '192.168.21.0/24',
|
||||
'nexthop': '172.16.88.252'}],
|
||||
'cidr': '172.16.88.0/24',
|
||||
'enable_dhcp': True,
|
||||
'gateway_ip': '172.16.88.1',
|
||||
@ -90,6 +100,7 @@ def data(TEST):
|
||||
'tenant_id': network_dict['tenant_id']}
|
||||
port_dict = {'admin_state_up': True,
|
||||
'device_id': '40e536b1-b9fd-4eb7-82d6-84db5d65a2ac',
|
||||
'device_owner': 'compute:nova',
|
||||
'fixed_ips': [{'ip_address': '172.16.88.3',
|
||||
'subnet_id': subnet_dict['id']}],
|
||||
'id': '7e6ce62c-7ea2-44f8-b6b4-769af90a8406',
|
||||
|
Loading…
Reference in New Issue
Block a user