Merge "Allow users to create a rich network topology"
This commit is contained in:
@@ -412,7 +412,8 @@ def router_add_interface(request, router_id, subnet_id=None, port_id=None):
|
||||
body['subnet_id'] = subnet_id
|
||||
if port_id:
|
||||
body['port_id'] = port_id
|
||||
quantumclient(request).add_interface_router(router_id, body)
|
||||
client = quantumclient(request)
|
||||
return client.add_interface_router(router_id, body)
|
||||
|
||||
|
||||
def router_remove_interface(request, router_id, subnet_id=None, port_id=None):
|
||||
|
@@ -22,13 +22,19 @@ 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 AddInterface(forms.SelfHandlingForm):
|
||||
subnet_id = forms.ChoiceField(label=_("Subnet"), required=False)
|
||||
subnet_id = forms.ChoiceField(label=_("Subnet"))
|
||||
ip_address = fields.IPField(
|
||||
label=_("IP Address (optional)"), required=False, initial="",
|
||||
help_text=_("You can specify an IP address of the interface "
|
||||
"created if you want (e.g. 192.168.0.254)."),
|
||||
version=fields.IPv4 | fields.IPv6, mask=False)
|
||||
router_name = forms.CharField(label=_("Router Name"),
|
||||
widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}))
|
||||
@@ -70,24 +76,73 @@ class AddInterface(forms.SelfHandlingForm):
|
||||
return choices
|
||||
|
||||
def handle(self, request, data):
|
||||
if data['ip_address']:
|
||||
port = self._add_interface_by_port(request, data)
|
||||
else:
|
||||
port = self._add_interface_by_subnet(request, data)
|
||||
msg = _('Interface added')
|
||||
if port:
|
||||
msg += ' ' + port.fixed_ips[0]['ip_address']
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
return True
|
||||
|
||||
def _add_interface_by_subnet(self, request, data):
|
||||
router_id = data['router_id']
|
||||
try:
|
||||
api.quantum.router_add_interface(request,
|
||||
data['router_id'],
|
||||
subnet_id=data['subnet_id'])
|
||||
msg = _('Interface added')
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
return True
|
||||
router_inf = api.quantum.router_add_interface(
|
||||
request, router_id, subnet_id=data['subnet_id'])
|
||||
except Exception as e:
|
||||
msg = _('Failed to add_interface %s') % e.message
|
||||
self._handle_error(request, router_id, e)
|
||||
try:
|
||||
port = api.quantum.port_get(request, router_inf['port_id'])
|
||||
except:
|
||||
# Ignore an error when port_get() since it is just
|
||||
# to get an IP address for the interface.
|
||||
port = None
|
||||
return port
|
||||
|
||||
def _add_interface_by_port(self, request, data):
|
||||
router_id = data['router_id']
|
||||
subnet_id = data['subnet_id']
|
||||
try:
|
||||
subnet = api.quantum.subnet_get(request, subnet_id)
|
||||
except:
|
||||
msg = _('Unable to get subnet "%s"') % subnet_id
|
||||
self._handle_error(request, router_id, msg)
|
||||
try:
|
||||
ip_address = data['ip_address']
|
||||
body = {'network_id': subnet.network_id,
|
||||
'fixed_ips': [{'subnet_id': subnet.id,
|
||||
'ip_address': ip_address}]}
|
||||
port = api.quantum.port_create(request, **body)
|
||||
except Exception as e:
|
||||
self._handle_error(request, router_id, e)
|
||||
try:
|
||||
api.quantum.router_add_interface(request, router_id,
|
||||
port_id=port.id)
|
||||
except Exception as e:
|
||||
self._delete_port(request, port)
|
||||
self._handle_error(request, router_id, e)
|
||||
return port
|
||||
|
||||
def _handle_error(self, request, router_id, reason):
|
||||
msg = _('Failed to add_interface: %s') % reason
|
||||
LOG.info(msg)
|
||||
redirect = reverse(self.failure_url, args=[router_id])
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
|
||||
def _delete_port(self, request, port):
|
||||
try:
|
||||
api.quantum.port_delete(request, port.id)
|
||||
except:
|
||||
msg = _('Failed to delete port %s') % port.id
|
||||
LOG.info(msg)
|
||||
messages.error(request, msg)
|
||||
redirect = reverse(self.failure_url, args=[data['router_id']])
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
exceptions.handle(request, msg)
|
||||
|
||||
|
||||
class SetGatewayForm(forms.SelfHandlingForm):
|
||||
network_id = forms.ChoiceField(label=_("External Network"), required=False)
|
||||
network_id = forms.ChoiceField(label=_("External Network"))
|
||||
router_name = forms.CharField(label=_("Router Name"),
|
||||
widget=forms.TextInput(
|
||||
attrs={'readonly': 'readonly'}))
|
||||
@@ -132,6 +187,5 @@ class SetGatewayForm(forms.SelfHandlingForm):
|
||||
except Exception as e:
|
||||
msg = _('Failed to set gateway %s') % e.message
|
||||
LOG.info(msg)
|
||||
messages.error(request, msg)
|
||||
redirect = reverse(self.failure_url)
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
|
@@ -71,6 +71,11 @@ class RemoveInterface(tables.DeleteAction):
|
||||
args=[router_id])
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
|
||||
def allowed(self, request, datum=None):
|
||||
if datum and datum['device_owner'] == 'network:router_gateway':
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class PortsTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
|
@@ -15,7 +15,12 @@
|
||||
</div>
|
||||
<div class="right">
|
||||
<h3>{% trans "Description" %}:</h3>
|
||||
<p>{% trans "You can connect a specified subnet to the router." %}</p>
|
||||
<p>
|
||||
{% trans "You can connect a specified subnet to the router." %}
|
||||
</p>
|
||||
<p>
|
||||
{% trans "The default IP address of the interface created is a gateway of the selected subnet. You can specify another IP address of the interface here. You must select a subnet to which the specified IP address belongs to from the above list." %}
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@@ -150,12 +150,21 @@ class RouterActionTests(test.TestCase):
|
||||
def _test_router_addinterface(self, raise_error=False):
|
||||
router = self.routers.first()
|
||||
subnet = self.subnets.first()
|
||||
port = self.ports.first()
|
||||
|
||||
add_interface = api.quantum.router_add_interface(
|
||||
IsA(http.HttpRequest), router.id, subnet_id=subnet.id)
|
||||
if raise_error:
|
||||
add_interface.AndRaise(self.exceptions.quantum)
|
||||
else:
|
||||
add_interface.AndReturn(None)
|
||||
add_interface.AndReturn({'subnet_id': subnet.id,
|
||||
'port_id': port.id})
|
||||
api.quantum.port_get(IsA(http.HttpRequest), port.id)\
|
||||
.AndReturn(port)
|
||||
self._check_router_addinterface(router, subnet)
|
||||
|
||||
def _check_router_addinterface(self, router, subnet, ip_address=''):
|
||||
# mock APIs used to show router detail
|
||||
api.quantum.router_get(IsA(http.HttpRequest), router.id)\
|
||||
.AndReturn(router)
|
||||
self._mock_network_list(router['tenant_id'])
|
||||
@@ -163,7 +172,8 @@ class RouterActionTests(test.TestCase):
|
||||
|
||||
form_data = {'router_id': router.id,
|
||||
'router_name': router.name,
|
||||
'subnet_id': subnet.id}
|
||||
'subnet_id': subnet.id,
|
||||
'ip_address': ip_address}
|
||||
|
||||
url = reverse('horizon:%s:routers:addinterface' % self.DASHBOARD,
|
||||
args=[router.id])
|
||||
@@ -174,6 +184,7 @@ class RouterActionTests(test.TestCase):
|
||||
|
||||
@test.create_stubs({api.quantum: ('router_get',
|
||||
'router_add_interface',
|
||||
'port_get',
|
||||
'network_list')})
|
||||
def test_router_addinterface(self):
|
||||
self._test_router_addinterface()
|
||||
@@ -184,6 +195,71 @@ class RouterActionTests(test.TestCase):
|
||||
def test_router_addinterface_exception(self):
|
||||
self._test_router_addinterface(raise_error=True)
|
||||
|
||||
def _test_router_addinterface_ip_addr(self, errors=[]):
|
||||
router = self.routers.first()
|
||||
subnet = self.subnets.first()
|
||||
port = self.ports.first()
|
||||
ip_addr = port['fixed_ips'][0]['ip_address']
|
||||
self._setup_mock_addinterface_ip_addr(router, subnet, port,
|
||||
ip_addr, errors)
|
||||
self._check_router_addinterface(router, subnet, ip_addr)
|
||||
|
||||
def _setup_mock_addinterface_ip_addr(self, router, subnet, port,
|
||||
ip_addr, errors=[]):
|
||||
subnet_get = api.quantum.subnet_get(IsA(http.HttpRequest), subnet.id)
|
||||
if 'subnet_get' in errors:
|
||||
subnet_get.AndRaise(self.exceptions.quantum)
|
||||
return
|
||||
subnet_get.AndReturn(subnet)
|
||||
|
||||
params = {'network_id': subnet.network_id,
|
||||
'fixed_ips': [{'subnet_id': subnet.id,
|
||||
'ip_address': ip_addr}]}
|
||||
port_create = api.quantum.port_create(IsA(http.HttpRequest), **params)
|
||||
if 'port_create' in errors:
|
||||
port_create.AndRaise(self.exceptions.quantum)
|
||||
return
|
||||
port_create.AndReturn(port)
|
||||
|
||||
add_inf = api.quantum.router_add_interface(
|
||||
IsA(http.HttpRequest), router.id, port_id=port.id)
|
||||
if 'add_interface' not in errors:
|
||||
return
|
||||
|
||||
add_inf.AndRaise(self.exceptions.quantum)
|
||||
port_delete = api.quantum.port_delete(IsA(http.HttpRequest), port.id)
|
||||
if 'port_delete' in errors:
|
||||
port_delete.AndRaise(self.exceptions.quantum)
|
||||
|
||||
@test.create_stubs({api.quantum: ('router_add_interface', 'subnet_get',
|
||||
'port_create',
|
||||
'router_get', 'network_list')})
|
||||
def test_router_addinterface_ip_addr(self):
|
||||
self._test_router_addinterface_ip_addr()
|
||||
|
||||
@test.create_stubs({api.quantum: ('subnet_get',
|
||||
'router_get', 'network_list')})
|
||||
def test_router_addinterface_ip_addr_exception_subnet_get(self):
|
||||
self._test_router_addinterface_ip_addr(errors=['subnet_get'])
|
||||
|
||||
@test.create_stubs({api.quantum: ('subnet_get', 'port_create',
|
||||
'router_get', 'network_list')})
|
||||
def test_router_addinterface_ip_addr_exception_port_create(self):
|
||||
self._test_router_addinterface_ip_addr(errors=['port_create'])
|
||||
|
||||
@test.create_stubs({api.quantum: ('router_add_interface', 'subnet_get',
|
||||
'port_create', 'port_delete',
|
||||
'router_get', 'network_list')})
|
||||
def test_router_addinterface_ip_addr_exception_add_interface(self):
|
||||
self._test_router_addinterface_ip_addr(errors=['add_interface'])
|
||||
|
||||
@test.create_stubs({api.quantum: ('router_add_interface', 'subnet_get',
|
||||
'port_create', 'port_delete',
|
||||
'router_get', 'network_list')})
|
||||
def test_router_addinterface_ip_addr_exception_port_delete(self):
|
||||
self._test_router_addinterface_ip_addr(errors=['add_interface',
|
||||
'port_delete'])
|
||||
|
||||
@test.create_stubs({api.quantum: ('router_get',
|
||||
'router_add_gateway',
|
||||
'network_list')})
|
||||
|
Reference in New Issue
Block a user