Merge "Support create subnet w/Neutron subnet allocation"
This commit is contained in:
commit
07d549c299
|
@ -797,6 +797,8 @@ Default::
|
|||
'supported_vnic_types': ["*"],
|
||||
'segmentation_id_range': {},
|
||||
'enable_fip_topology_check': True,
|
||||
'default_ipv4_subnet_pool_label': None,
|
||||
'default_ipv6_subnet_pool_label': None,
|
||||
}
|
||||
|
||||
A dictionary of settings which can be used to enable optional services provided
|
||||
|
@ -967,6 +969,28 @@ subnet with no router if your Neutron backend allows it.
|
|||
|
||||
.. versionadded:: 2015.2(Liberty)
|
||||
|
||||
``default_ipv4_subnet_pool_label``:
|
||||
|
||||
.. versionadded:: 2015.2(Liberty)
|
||||
|
||||
Default: ``None`` (Disabled)
|
||||
|
||||
Neutron can be configured with a default Subnet Pool to be used for IPv4
|
||||
subnet-allocation. Specify the label you wish to display in the Address pool
|
||||
selector on the create subnet step if you want to use this feature.
|
||||
|
||||
``default_ipv6_subnet_pool_label``:
|
||||
|
||||
.. versionadded:: 2015.2(Liberty)
|
||||
|
||||
Default: ``None`` (Disabled)
|
||||
|
||||
Neutron can be configured with a default Subnet Pool to be used for IPv6
|
||||
subnet-allocation. Specify the label you wish to display in the Address pool
|
||||
selector on the create subnet step if you want to use this feature.
|
||||
|
||||
You must set this to enable IPv6 Prefix Delegation in a PD-capable environment.
|
||||
|
||||
``OPENSTACK_SSL_CACERT``
|
||||
------------------------
|
||||
|
||||
|
|
|
@ -56,6 +56,68 @@ horizon.forms = {
|
|||
});
|
||||
},
|
||||
|
||||
handle_subnet_address_source: function() {
|
||||
$("div.table_wrapper, #modal_wrapper").on("change", "select#id_address_source", function(evt) {
|
||||
var $option = $(this).find("option:selected");
|
||||
var $form = $(this).closest("form");
|
||||
var $ipVersion = $form.find("select#id_ip_version");
|
||||
if ($option.val() == "subnetpool") {
|
||||
$ipVersion.attr("disabled", "disabled");
|
||||
// disabled fields do not post, store the value in a hidden input
|
||||
var el = document.createElement("input");
|
||||
el.type='hidden';
|
||||
el.id = "id_hidden_ip_version";
|
||||
el.name = $ipVersion.attr('name');
|
||||
el.value = $ipVersion.attr('value');
|
||||
$form.append(el);
|
||||
} else {
|
||||
var $hiddenIpVersion = $form.find("hidden#id_hidden_ip_version");
|
||||
$hiddenIpVersion.remove();
|
||||
$ipVersion.removeAttr("disabled");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handle_subnet_subnetpool: function() {
|
||||
$("div.table_wrapper, #modal_wrapper").on("change", "select#id_subnetpool", function(evt) {
|
||||
var $option = $(this).find("option:selected");
|
||||
var $form = $(this).closest("form");
|
||||
var $ipVersion = $form.find("select#id_ip_version");
|
||||
var $prefixLength = $form.find("select#id_prefixlen");
|
||||
var $ipv6Modes = $form.find("select#id_ipv6_modes");
|
||||
var subnetpoolIpVersion = parseInt($option.data("ip_version"), 10) || 4;
|
||||
var minPrefixLen = parseInt($option.data("min_prefixlen"), 10) || 1;
|
||||
var maxPrefixLen = parseInt($option.data("max_prefixlen"), 10);
|
||||
var defaultPrefixLen = parseInt($option.data("default_prefixlen"), 10) ||
|
||||
-1;
|
||||
var optionsAsString = "";
|
||||
|
||||
$ipVersion.val(subnetpoolIpVersion);
|
||||
|
||||
if (!maxPrefixLen) {
|
||||
if (subnetpoolIpVersion == 4) {
|
||||
maxPrefixLen = 32;
|
||||
} else {
|
||||
maxPrefixLen = 128;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = minPrefixLen; i <= maxPrefixLen; i++) {
|
||||
optionsAsString += "<option value='" + i + "'>" + i;
|
||||
if (i == defaultPrefixLen) {
|
||||
optionsAsString += " (" + gettext("pool default") + ")";
|
||||
}
|
||||
optionsAsString += "</option>";
|
||||
}
|
||||
$prefixLength.empty().append(optionsAsString);
|
||||
if (defaultPrefixLen >= 0) {
|
||||
$prefixLength.val(defaultPrefixLen);
|
||||
} else {
|
||||
$prefixLength.val("");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* In the container's upload object form, copy the selected file name in the
|
||||
* object name field if the field is empty. The filename string is stored in
|
||||
|
@ -196,6 +258,8 @@ horizon.addInitFunction(horizon.forms.init = function () {
|
|||
horizon.forms.handle_image_source();
|
||||
horizon.forms.handle_object_upload_source();
|
||||
horizon.forms.datepicker();
|
||||
horizon.forms.handle_subnet_address_source();
|
||||
horizon.forms.handle_subnet_subnetpool();
|
||||
|
||||
if (!horizon.conf.disable_password_reveal) {
|
||||
horizon.forms.add_password_fields_reveal_buttons($("body"));
|
||||
|
@ -260,24 +324,25 @@ horizon.addInitFunction(horizon.forms.init = function () {
|
|||
visible = $switchable.is(':visible'),
|
||||
slug = $switchable.data('slug'),
|
||||
checked = $switchable.prop('checked'),
|
||||
hide_tab = $switchable.data('hide-tab'),
|
||||
hide_tab = String($switchable.data('hide-tab')).split(','),
|
||||
hide_on = $switchable.data('hideOnChecked');
|
||||
|
||||
// If checkbox is hidden then do not apply any further logic
|
||||
if (!visible) return;
|
||||
|
||||
// If the checkbox has hide-tab attribute then hide/show the tab
|
||||
if (hide_tab) {
|
||||
var i, len;
|
||||
for (i = 0, len = hide_tab.length; i < len; i++) {
|
||||
var $btnfinal = $('.button-final');
|
||||
if(checked == hide_on) {
|
||||
// If the checkbox is not checked then hide the tab
|
||||
$('*[data-target="#'+ hide_tab +'"]').parent().hide();
|
||||
$('*[data-target="#'+ hide_tab[i] +'"]').parent().hide();
|
||||
$('.button-next').hide();
|
||||
$btnfinal.show();
|
||||
$btnfinal.data('show-on-tab', $fieldset.prop('id'));
|
||||
} else if (!$('*[data-target="#'+ hide_tab +'"]').parent().is(':visible')) {
|
||||
} else if (!$('*[data-target="#'+ hide_tab[i] +'"]').parent().is(':visible')) {
|
||||
// If the checkbox is checked and the tab is currently hidden then show the tab again
|
||||
$('*[data-target="#'+ hide_tab +'"]').parent().show();
|
||||
$('*[data-target="#'+ hide_tab[i] +'"]').parent().show();
|
||||
$btnfinal.hide();
|
||||
$('.button-next').show();
|
||||
$btnfinal.removeData('show-on-tab');
|
||||
|
|
|
@ -118,6 +118,14 @@ class DetailView(tabs.TabView):
|
|||
subnet.ipv6_ra_mode, subnet.ipv6_address_mode)
|
||||
subnet.ipv6_modes_desc = utils.IPV6_MODE_MAP.get(ipv6_modes)
|
||||
|
||||
if ('subnetpool_id' in subnet and
|
||||
subnet.subnetpool_id and
|
||||
api.neutron.is_extension_supported(self.request,
|
||||
'subnet_allocation')):
|
||||
subnetpool = api.neutron.subnetpool_get(self.request,
|
||||
subnet.subnetpool_id)
|
||||
subnet.subnetpool_name = subnetpool.name
|
||||
|
||||
return subnet
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
|
|
@ -36,7 +36,6 @@ class CreateSubnetInfoAction(network_workflows.CreateSubnetInfoAction):
|
|||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(CreateSubnetInfoAction, self).__init__(request, *args, **kwargs)
|
||||
self.fields['cidr'].required = True
|
||||
|
||||
class Meta(object):
|
||||
name = _("Subnet")
|
||||
|
@ -82,6 +81,12 @@ class CreateSubnet(network_workflows.CreateNetwork):
|
|||
|
||||
|
||||
class UpdateSubnetInfoAction(CreateSubnetInfoAction):
|
||||
address_source = forms.ChoiceField(widget=forms.HiddenInput(),
|
||||
required=False)
|
||||
subnetpool = forms.ChoiceField(widget=forms.HiddenInput(),
|
||||
required=False)
|
||||
prefixlen = forms.ChoiceField(widget=forms.HiddenInput(),
|
||||
required=False)
|
||||
cidr = forms.IPField(label=_("Network Address"),
|
||||
required=False,
|
||||
initial="",
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
{% url 'horizon:project:networks:detail' subnet.network_id as network_url %}
|
||||
<dt>{% trans "Network ID" %}</dt>
|
||||
<dd><a href="{{ network_url }}">{{ subnet.network_id|default:_("None") }}</a></dd>
|
||||
<dt>{% trans "Subnetpool" %}</dt>
|
||||
{% if subnet.subnetpool_id %}
|
||||
<dd>{{ subnet.subnetpool_name }} ({{ subnet.subnetpool_id }})</dd>
|
||||
{% else %}
|
||||
<dd>{% trans "None" %}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "IP version" %}</dt>
|
||||
<dd>{{ subnet.ipver_str|default:_("-") }}</dd>
|
||||
<dt>{% trans "CIDR" %}</dt>
|
||||
|
|
|
@ -463,6 +463,7 @@ class NetworkTests(test.TestCase):
|
|||
def test_network_create_post_with_subnet_network_exception(
|
||||
self,
|
||||
test_with_profile=False,
|
||||
test_with_subnetpool=False,
|
||||
):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
|
@ -499,7 +500,9 @@ class NetworkTests(test.TestCase):
|
|||
@test.create_stubs({api.neutron: ('network_create',
|
||||
'network_delete',
|
||||
'subnet_create',
|
||||
'profile_list')})
|
||||
'profile_list',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_network_create_post_with_subnet_subnet_exception(
|
||||
self,
|
||||
test_with_profile=False,
|
||||
|
@ -514,6 +517,11 @@ class NetworkTests(test.TestCase):
|
|||
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||
'network').AndReturn(net_profiles)
|
||||
params['net_profile_id'] = net_profile_id
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
api.neutron.network_create(IsA(http.HttpRequest),
|
||||
**params).AndReturn(network)
|
||||
api.neutron.subnet_create(IsA(http.HttpRequest),
|
||||
|
@ -546,9 +554,12 @@ class NetworkTests(test.TestCase):
|
|||
self.test_network_create_post_with_subnet_subnet_exception(
|
||||
test_with_profile=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('profile_list',)})
|
||||
@test.create_stubs({api.neutron: ('profile_list',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_network_create_post_with_subnet_nocidr(self,
|
||||
test_with_profile=False):
|
||||
test_with_profile=False,
|
||||
test_with_snpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
if test_with_profile:
|
||||
|
@ -556,6 +567,11 @@ class NetworkTests(test.TestCase):
|
|||
net_profile_id = self.net_profiles.first().id
|
||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||
'network').AndReturn(net_profiles)
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'net_name': network.name,
|
||||
|
@ -563,12 +579,16 @@ class NetworkTests(test.TestCase):
|
|||
'with_subnet': True}
|
||||
if test_with_profile:
|
||||
form_data['net_profile_id'] = net_profile_id
|
||||
if test_with_snpool:
|
||||
form_data['subnetpool_id'] = ''
|
||||
form_data['prefixlen'] = ''
|
||||
form_data.update(form_data_subnet(subnet, cidr='',
|
||||
allocation_pools=[]))
|
||||
url = reverse('horizon:project:networks:create')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertContains(res, escape('Specify "Network Address" or '
|
||||
self.assertContains(res, escape('Specify "Network Address", '
|
||||
'"Address pool" or '
|
||||
'clear "Create Subnet" checkbox.'))
|
||||
|
||||
@test.update_settings(
|
||||
|
@ -577,10 +597,17 @@ class NetworkTests(test.TestCase):
|
|||
self.test_network_create_post_with_subnet_nocidr(
|
||||
test_with_profile=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('profile_list',)})
|
||||
def test_network_create_post_with_subnet_nocidr_nosubnetpool(self):
|
||||
self.test_network_create_post_with_subnet_nocidr(
|
||||
test_with_snpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('profile_list',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_network_create_post_with_subnet_cidr_without_mask(
|
||||
self,
|
||||
test_with_profile=False,
|
||||
test_with_subnetpool=False,
|
||||
):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
|
@ -589,13 +616,22 @@ class NetworkTests(test.TestCase):
|
|||
net_profile_id = self.net_profiles.first().id
|
||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||
'network').AndReturn(net_profiles)
|
||||
self.mox.ReplayAll()
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'net_name': network.name,
|
||||
'admin_state': network.admin_state_up,
|
||||
'with_subnet': True}
|
||||
if test_with_profile:
|
||||
form_data['net_profile_id'] = net_profile_id
|
||||
if test_with_subnetpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
form_data['prefixlen'] = subnetpool.default_prefixlen
|
||||
form_data.update(form_data_subnet(subnet, cidr='10.0.0.0',
|
||||
allocation_pools=[]))
|
||||
url = reverse('horizon:project:networks:create')
|
||||
|
@ -610,10 +646,17 @@ class NetworkTests(test.TestCase):
|
|||
self.test_network_create_post_with_subnet_cidr_without_mask(
|
||||
test_with_profile=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('profile_list',)})
|
||||
def test_network_create_post_with_subnet_cidr_without_mask_w_snpool(self):
|
||||
self.test_network_create_post_with_subnet_cidr_without_mask(
|
||||
test_with_subnetpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('profile_list',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_network_create_post_with_subnet_cidr_inconsistent(
|
||||
self,
|
||||
test_with_profile=False,
|
||||
test_with_subnetpool=False
|
||||
):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
|
@ -622,6 +665,12 @@ class NetworkTests(test.TestCase):
|
|||
net_profile_id = self.net_profiles.first().id
|
||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||
'network').AndReturn(net_profiles)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
# dummy IPv6 address
|
||||
|
@ -631,6 +680,10 @@ class NetworkTests(test.TestCase):
|
|||
'with_subnet': True}
|
||||
if test_with_profile:
|
||||
form_data['net_profile_id'] = net_profile_id
|
||||
if test_with_subnetpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
form_data['prefixlen'] = subnetpool.default_prefixlen
|
||||
form_data.update(form_data_subnet(subnet, cidr=cidr,
|
||||
allocation_pools=[]))
|
||||
url = reverse('horizon:project:networks:create')
|
||||
|
@ -645,10 +698,17 @@ class NetworkTests(test.TestCase):
|
|||
self.test_network_create_post_with_subnet_cidr_inconsistent(
|
||||
test_with_profile=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('profile_list',)})
|
||||
def test_network_create_post_with_subnet_cidr_inconsistent_w_snpool(self):
|
||||
self.test_network_create_post_with_subnet_cidr_inconsistent(
|
||||
test_with_subnetpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('profile_list',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_network_create_post_with_subnet_gw_inconsistent(
|
||||
self,
|
||||
test_with_profile=False,
|
||||
test_with_subnetpool=False,
|
||||
):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
|
@ -657,6 +717,12 @@ class NetworkTests(test.TestCase):
|
|||
net_profile_id = self.net_profiles.first().id
|
||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||
'network').AndReturn(net_profiles)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
# dummy IPv6 address
|
||||
|
@ -666,6 +732,10 @@ class NetworkTests(test.TestCase):
|
|||
'with_subnet': True}
|
||||
if test_with_profile:
|
||||
form_data['net_profile_id'] = net_profile_id
|
||||
if test_with_subnetpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
form_data['prefixlen'] = subnetpool.default_prefixlen
|
||||
form_data.update(form_data_subnet(subnet, gateway_ip=gateway_ip,
|
||||
allocation_pools=[]))
|
||||
url = reverse('horizon:project:networks:create')
|
||||
|
@ -679,6 +749,10 @@ class NetworkTests(test.TestCase):
|
|||
self.test_network_create_post_with_subnet_gw_inconsistent(
|
||||
test_with_profile=True)
|
||||
|
||||
def test_network_create_post_with_subnet_gw_inconsistent_w_snpool(self):
|
||||
self.test_network_create_post_with_subnet_gw_inconsistent(
|
||||
test_with_subnetpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_network_update_get(self):
|
||||
network = self.networks.first()
|
||||
|
@ -834,7 +908,8 @@ class NetworkTests(test.TestCase):
|
|||
|
||||
class NetworkSubnetTests(test.TestCase):
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get', 'subnet_get',)})
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'subnet_get',)})
|
||||
def test_subnet_detail(self):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
|
@ -883,7 +958,7 @@ class NetworkSubnetTests(test.TestCase):
|
|||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'subnet_create',)})
|
||||
def test_subnet_create_post(self):
|
||||
def test_subnet_create_post(self, test_with_subnetpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
|
@ -972,7 +1047,8 @@ class NetworkSubnetTests(test.TestCase):
|
|||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'subnet_create',)})
|
||||
def test_subnet_create_post_network_exception(self):
|
||||
def test_subnet_create_post_network_exception(self,
|
||||
test_with_subnetpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
|
@ -980,8 +1056,12 @@ class NetworkSubnetTests(test.TestCase):
|
|||
.AndRaise(self.exceptions.neutron)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = form_data_subnet(subnet,
|
||||
allocation_pools=[])
|
||||
form_data = {}
|
||||
if test_with_subnetpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
form_data.update(form_data_subnet(subnet, allocation_pools=[]))
|
||||
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -989,9 +1069,14 @@ class NetworkSubnetTests(test.TestCase):
|
|||
self.assertNoFormErrors(res)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_subnet_create_post_network_exception_with_subnetpool(self):
|
||||
self.test_subnet_create_post_network_exception(
|
||||
test_with_subnetpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'subnet_create',)})
|
||||
def test_subnet_create_post_subnet_exception(self):
|
||||
def test_subnet_create_post_subnet_exception(self,
|
||||
test_with_subnetpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
|
@ -1007,8 +1092,7 @@ class NetworkSubnetTests(test.TestCase):
|
|||
.AndRaise(self.exceptions.neutron)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = form_data_subnet(subnet,
|
||||
allocation_pools=[])
|
||||
form_data = form_data_subnet(subnet, allocation_pools=[])
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1017,19 +1101,34 @@ class NetworkSubnetTests(test.TestCase):
|
|||
args=[subnet.network_id])
|
||||
self.assertRedirectsNoFollow(res, redir_url)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_cidr_inconsistent(self):
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_cidr_inconsistent(self,
|
||||
test_with_subnetpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id)\
|
||||
.AndReturn(self.networks.first())
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if test_with_subnetpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# dummy IPv6 address
|
||||
cidr = '2001:0DB8:0:CD30:123:4567:89AB:CDEF/60'
|
||||
form_data = form_data_subnet(subnet, cidr=cidr,
|
||||
allocation_pools=[])
|
||||
form_data.update(form_data_subnet(subnet, cidr=cidr,
|
||||
allocation_pools=[]))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1038,37 +1137,74 @@ class NetworkSubnetTests(test.TestCase):
|
|||
self.assertFormErrors(res, 1, expected_msg)
|
||||
self.assertTemplateUsed(res, views.WorkflowView.template_name)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_gw_inconsistent(self):
|
||||
def test_subnet_create_post_cidr_inconsistent_with_subnetpool(self):
|
||||
self.test_subnet_create_post_cidr_inconsistent(
|
||||
test_with_subnetpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_gw_inconsistent(self,
|
||||
test_with_subnetpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id)\
|
||||
.AndReturn(self.networks.first())
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if test_with_subnetpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# dummy IPv6 address
|
||||
gateway_ip = '2001:0DB8:0:CD30:123:4567:89AB:CDEF'
|
||||
form_data = form_data_subnet(subnet, gateway_ip=gateway_ip,
|
||||
allocation_pools=[])
|
||||
form_data.update(form_data_subnet(subnet, gateway_ip=gateway_ip,
|
||||
allocation_pools=[]))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertContains(res, 'Gateway IP and IP version are inconsistent.')
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_pools_start_only(self):
|
||||
def test_subnet_create_post_gw_inconsistent_with_subnetpool(self):
|
||||
self.test_subnet_create_post_gw_inconsistent(test_with_subnetpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_pools_start_only(self,
|
||||
test_w_snpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if test_w_snpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# Start only allocation_pools
|
||||
allocation_pools = '10.0.0.2'
|
||||
form_data = form_data_subnet(subnet,
|
||||
allocation_pools=allocation_pools)
|
||||
form_data.update(form_data_subnet(subnet,
|
||||
allocation_pools=allocation_pools))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1077,18 +1213,37 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'Start and end addresses must be specified '
|
||||
'(value=%s)' % allocation_pools)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_pools_three_entries(self):
|
||||
def test_subnet_create_post_invalid_pools_start_only_with_subnetpool(self):
|
||||
self.test_subnet_create_post_invalid_pools_start_only(
|
||||
test_w_snpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_pools_three_entries(self,
|
||||
t_w_snpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if t_w_snpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# pool with three entries
|
||||
allocation_pools = '10.0.0.2,10.0.0.3,10.0.0.4'
|
||||
form_data = form_data_subnet(subnet,
|
||||
allocation_pools=allocation_pools)
|
||||
form_data.update(form_data_subnet(subnet,
|
||||
allocation_pools=allocation_pools))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1097,18 +1252,37 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'Start and end addresses must be specified '
|
||||
'(value=%s)' % allocation_pools)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_pools_invalid_address(self):
|
||||
def test_subnet_create_post_invalid_pools_three_entries_w_subnetpool(self):
|
||||
self.test_subnet_create_post_invalid_pools_three_entries(
|
||||
t_w_snpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_pools_invalid_address(self,
|
||||
t_w_snpl=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if t_w_snpl:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# end address is not a valid IP address
|
||||
allocation_pools = '10.0.0.2,invalid_address'
|
||||
form_data = form_data_subnet(subnet,
|
||||
allocation_pools=allocation_pools)
|
||||
form_data.update(form_data_subnet(subnet,
|
||||
allocation_pools=allocation_pools))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1117,18 +1291,37 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'allocation_pools: Invalid IP address '
|
||||
'(value=%s)' % allocation_pools.split(',')[1])
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_pools_ip_network(self):
|
||||
def test_subnet_create_post_invalid_pools_invalid_address_w_snpool(self):
|
||||
self.test_subnet_create_post_invalid_pools_invalid_address(
|
||||
t_w_snpl=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_pools_ip_network(self,
|
||||
test_w_snpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if test_w_snpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# start address is CIDR
|
||||
allocation_pools = '10.0.0.2/24,10.0.0.5'
|
||||
form_data = form_data_subnet(subnet,
|
||||
allocation_pools=allocation_pools)
|
||||
form_data.update(form_data_subnet(subnet,
|
||||
allocation_pools=allocation_pools))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1137,14 +1330,33 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'allocation_pools: Invalid IP address '
|
||||
'(value=%s)' % allocation_pools.split(',')[0])
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_pools_start_larger_than_end(self):
|
||||
def test_subnet_create_post_invalid_pools_ip_network_with_subnetpool(self):
|
||||
self.test_subnet_create_post_invalid_pools_ip_network(
|
||||
test_w_snpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_pools_start_larger_than_end(self,
|
||||
tsn=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if tsn:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# start address is larger than end address
|
||||
allocation_pools = '10.0.0.254,10.0.0.2'
|
||||
form_data = form_data_subnet(subnet,
|
||||
|
@ -1157,18 +1369,38 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'Start address is larger than end address '
|
||||
'(value=%s)' % allocation_pools)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_nameservers(self):
|
||||
def test_subnet_create_post_invalid_pools_start_larger_than_end_tsn(self):
|
||||
self.test_subnet_create_post_invalid_pools_start_larger_than_end(
|
||||
tsn=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_nameservers(self,
|
||||
test_w_subnetpool=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if test_w_subnetpool:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# invalid DNS server address
|
||||
dns_nameservers = ['192.168.0.2', 'invalid_address']
|
||||
form_data = form_data_subnet(subnet, dns_nameservers=dns_nameservers,
|
||||
allocation_pools=[])
|
||||
form_data.update(form_data_subnet(subnet,
|
||||
dns_nameservers=dns_nameservers,
|
||||
allocation_pools=[]))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1177,19 +1409,39 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'dns_nameservers: Invalid IP address '
|
||||
'(value=%s)' % dns_nameservers[1])
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_routes_destination_only(self):
|
||||
def test_subnet_create_post_invalid_nameservers_with_subnetpool(self):
|
||||
self.test_subnet_create_post_invalid_nameservers(
|
||||
test_w_subnetpool=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_routes_destination_only(self,
|
||||
tsn=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if tsn:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# Start only host_route
|
||||
host_routes = '192.168.0.0/24'
|
||||
form_data = form_data_subnet(subnet,
|
||||
allocation_pools=[],
|
||||
host_routes=host_routes)
|
||||
form_data.update(form_data_subnet(subnet,
|
||||
allocation_pools=[],
|
||||
host_routes=host_routes))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1199,19 +1451,38 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'Destination CIDR and nexthop must be specified '
|
||||
'(value=%s)' % host_routes)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_routes_three_entries(self):
|
||||
def test_subnet_create_post_invalid_routes_destination_only_w_snpool(self):
|
||||
self.test_subnet_create_post_invalid_routes_destination_only(
|
||||
tsn=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_routes_three_entries(self,
|
||||
tsn=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if tsn:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# host_route with three entries
|
||||
host_routes = 'aaaa,bbbb,cccc'
|
||||
form_data = form_data_subnet(subnet,
|
||||
allocation_pools=[],
|
||||
host_routes=host_routes)
|
||||
form_data.update(form_data_subnet(subnet,
|
||||
allocation_pools=[],
|
||||
host_routes=host_routes))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1221,19 +1492,38 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'Destination CIDR and nexthop must be specified '
|
||||
'(value=%s)' % host_routes)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_routes_invalid_destination(self):
|
||||
def test_subnet_create_post_invalid_routes_three_entries_with_tsn(self):
|
||||
self.test_subnet_create_post_invalid_routes_three_entries(
|
||||
tsn=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_routes_invalid_destination(self,
|
||||
tsn=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if tsn:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# invalid destination network
|
||||
host_routes = '172.16.0.0/64,10.0.0.253'
|
||||
form_data = form_data_subnet(subnet,
|
||||
host_routes=host_routes,
|
||||
allocation_pools=[])
|
||||
form_data.update(form_data_subnet(subnet,
|
||||
host_routes=host_routes,
|
||||
allocation_pools=[]))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1242,19 +1532,38 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'host_routes: Invalid IP address '
|
||||
'(value=%s)' % host_routes.split(',')[0])
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',)})
|
||||
def test_subnet_create_post_invalid_routes_nexthop_ip_network(self):
|
||||
def test_subnet_create_post_invalid_routes_invalid_destination_tsn(self):
|
||||
self.test_subnet_create_post_invalid_routes_invalid_destination(
|
||||
tsn=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'subnetpool_list',)})
|
||||
def test_subnet_create_post_invalid_routes_nexthop_ip_network(self,
|
||||
tsn=False):
|
||||
network = self.networks.first()
|
||||
subnet = self.subnets.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id).AndReturn(network)
|
||||
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {}
|
||||
if tsn:
|
||||
subnetpool = self.subnetpools.first()
|
||||
form_data['subnetpool'] = subnetpool.id
|
||||
|
||||
# nexthop is not an IP address
|
||||
host_routes = '172.16.0.0/24,10.0.0.253/24'
|
||||
form_data = form_data_subnet(subnet,
|
||||
host_routes=host_routes,
|
||||
allocation_pools=[])
|
||||
form_data.update(form_data_subnet(subnet,
|
||||
host_routes=host_routes,
|
||||
allocation_pools=[]))
|
||||
url = reverse('horizon:project:networks:addsubnet',
|
||||
args=[subnet.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
@ -1263,9 +1572,20 @@ class NetworkSubnetTests(test.TestCase):
|
|||
'host_routes: Invalid IP address '
|
||||
'(value=%s)' % host_routes.split(',')[1])
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'subnet_create',)})
|
||||
def test_subnet_create_post_invalid_routes_nexthop_ip_network_tsn(self):
|
||||
self.test_subnet_create_post_invalid_routes_nexthop_ip_network(
|
||||
tsn=True)
|
||||
|
||||
@test.create_stubs({api.neutron: ('is_extension_supported',
|
||||
'network_get',
|
||||
'subnet_create',
|
||||
'subnetpool_list',)})
|
||||
def test_v6subnet_create_post(self):
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'subnet_allocation').\
|
||||
AndReturn(True)
|
||||
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.subnetpools.list())
|
||||
network = self.networks.get(name="v6_net1")
|
||||
subnet = self.subnets.get(name="v6_subnet1")
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
|
|
|
@ -50,6 +50,20 @@ class CreateNetworkInfoAction(workflows.Action):
|
|||
required=False,
|
||||
help_text=_("The state to start"
|
||||
" the network in."))
|
||||
with_subnet = forms.BooleanField(label=_("Create Subnet"),
|
||||
widget=forms.CheckboxInput(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'with_subnet',
|
||||
'data-hide-tab': 'create_network__'
|
||||
'createsubnetinfo'
|
||||
'action,'
|
||||
'create_network__'
|
||||
'createsubnetdetail'
|
||||
'action,',
|
||||
'data-hide-on-checked': 'false'
|
||||
}),
|
||||
initial=True,
|
||||
required=False)
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(CreateNetworkInfoAction, self).__init__(request,
|
||||
|
@ -84,35 +98,56 @@ class CreateNetworkInfoAction(workflows.Action):
|
|||
|
||||
class CreateNetworkInfo(workflows.Step):
|
||||
action_class = CreateNetworkInfoAction
|
||||
contributes = ("net_name", "admin_state", "net_profile_id")
|
||||
contributes = ("net_name", "admin_state", "net_profile_id", "with_subnet")
|
||||
|
||||
|
||||
class CreateSubnetInfoAction(workflows.Action):
|
||||
with_subnet = forms.BooleanField(label=_("Create Subnet"),
|
||||
widget=forms.CheckboxInput(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'with_subnet',
|
||||
'data-hide-tab': 'create_network__'
|
||||
'createsubnetdetail'
|
||||
'action',
|
||||
'data-hide-on-checked': 'false'
|
||||
}),
|
||||
initial=True,
|
||||
required=False)
|
||||
subnet_name = forms.CharField(max_length=255,
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'switched',
|
||||
'data-switch-on': 'with_subnet',
|
||||
}),
|
||||
label=_("Subnet Name"),
|
||||
required=False)
|
||||
|
||||
address_source = forms.ChoiceField(
|
||||
required=False,
|
||||
label=_('Network Address Source'),
|
||||
choices=[('manual', _('Enter Network Address manually')),
|
||||
('subnetpool', _('Allocate Network Address from a pool'))],
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'source',
|
||||
}))
|
||||
|
||||
subnetpool = forms.ChoiceField(
|
||||
label=_("Address pool"),
|
||||
widget=forms.SelectWidget(attrs={
|
||||
'class': 'switched switchable',
|
||||
'data-slug': 'subnetpool',
|
||||
'data-switch-on': 'source',
|
||||
'data-source-subnetpool': _('Address pool')},
|
||||
data_attrs=('name', 'prefixes',
|
||||
'ip_version',
|
||||
'min_prefixlen',
|
||||
'max_prefixlen',
|
||||
'default_prefixlen'),
|
||||
transform=lambda x: "%s (%s)" % (x.name, ", ".join(x.prefixes))
|
||||
if 'prefixes' in x else "%s" % (x.name)),
|
||||
required=False)
|
||||
|
||||
prefixlen = forms.ChoiceField(widget=forms.Select(attrs={
|
||||
'class': 'switched',
|
||||
'data-switch-on': 'subnetpool',
|
||||
}),
|
||||
label=_('Network Mask'),
|
||||
required=False)
|
||||
|
||||
cidr = forms.IPField(label=_("Network Address"),
|
||||
required=False,
|
||||
initial="",
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'switched',
|
||||
'data-switch-on': 'with_subnet',
|
||||
'data-is-required': 'true'
|
||||
'data-switch-on': 'source',
|
||||
'data-source-manual': _("Network Address"),
|
||||
}),
|
||||
help_text=_("Network address in CIDR format "
|
||||
"(e.g. 192.168.0.0/24, 2001:DB8::/48)"),
|
||||
|
@ -120,16 +155,17 @@ class CreateSubnetInfoAction(workflows.Action):
|
|||
mask=True)
|
||||
ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable switched',
|
||||
'class': 'switchable',
|
||||
'data-slug': 'ipversion',
|
||||
'data-switch-on': 'with_subnet'
|
||||
}),
|
||||
label=_("IP Version"))
|
||||
label=_("IP Version"),
|
||||
required=False)
|
||||
gateway_ip = forms.IPField(
|
||||
label=_("Gateway IP"),
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'switched',
|
||||
'data-switch-on': 'with_subnet gateway_ip'
|
||||
'data-switch-on': 'source gateway_ip',
|
||||
'data-source-manual': _("Gateway IP")
|
||||
}),
|
||||
required=False,
|
||||
initial="",
|
||||
|
@ -145,37 +181,109 @@ class CreateSubnetInfoAction(workflows.Action):
|
|||
mask=False)
|
||||
no_gateway = forms.BooleanField(label=_("Disable Gateway"),
|
||||
widget=forms.CheckboxInput(attrs={
|
||||
'class': 'switched switchable',
|
||||
'class': 'switchable',
|
||||
'data-slug': 'gateway_ip',
|
||||
'data-switch-on': 'with_subnet',
|
||||
'data-hide-on-checked': 'true'
|
||||
}),
|
||||
initial=False,
|
||||
required=False)
|
||||
msg = _('Specify "Network Address" or '
|
||||
msg = _('Specify "Network Address", "Address pool" or '
|
||||
'clear "Create Subnet" checkbox.')
|
||||
|
||||
class Meta(object):
|
||||
name = _("Subnet")
|
||||
help_text = _('Create a subnet associated with the new network, '
|
||||
'in which case "Network Address" must be specified. '
|
||||
'If you wish to create a network without a subnet, '
|
||||
'uncheck the "Create Subnet" checkbox.')
|
||||
help_text = _('Create a subnet associated with the network. '
|
||||
'Advanced configuration is available by clicking on the '
|
||||
'"Subnet Details" tab.')
|
||||
|
||||
def __init__(self, request, context, *args, **kwargs):
|
||||
super(CreateSubnetInfoAction, self).__init__(request, context, *args,
|
||||
**kwargs)
|
||||
if 'with_subnet' in context:
|
||||
self.fields['with_subnet'] = forms.BooleanField(
|
||||
initial=context['with_subnet'],
|
||||
required=False,
|
||||
widget=forms.HiddenInput()
|
||||
)
|
||||
|
||||
if not getattr(settings, 'OPENSTACK_NEUTRON_NETWORK',
|
||||
{}).get('enable_ipv6', True):
|
||||
self.fields['ip_version'].widget = forms.HiddenInput()
|
||||
self.fields['ip_version'].initial = 4
|
||||
|
||||
try:
|
||||
if api.neutron.is_extension_supported(request,
|
||||
'subnet_allocation'):
|
||||
self.fields['subnetpool'].choices = \
|
||||
self.get_subnetpool_choices(request)
|
||||
else:
|
||||
self.hide_subnetpool_choices()
|
||||
except Exception:
|
||||
self.hide_subnetpool_choices()
|
||||
msg = _('Unable to initialize subnetpools')
|
||||
exceptions.handle(request, msg)
|
||||
if len(self.fields['subnetpool'].choices):
|
||||
# Pre-populate prefixlen choices to satisfy Django
|
||||
# ChoiceField Validation. This is overridden w/data from
|
||||
# subnetpool on select.
|
||||
self.fields['prefixlen'].choices = \
|
||||
zip(list(range(0, 128 + 1)),
|
||||
list(range(0, 128 + 1)))
|
||||
# Populate data-fields for switching the prefixlen field
|
||||
# when user selects a subnetpool other than
|
||||
# "Provider default pool"
|
||||
for (id, name) in self.fields['subnetpool'].choices:
|
||||
if not len(id):
|
||||
continue
|
||||
key = 'data-subnetpool-' + id
|
||||
self.fields['prefixlen'].widget.attrs[key] = \
|
||||
_('Network Mask')
|
||||
else:
|
||||
self.hide_subnetpool_choices()
|
||||
|
||||
def get_subnetpool_choices(self, request):
|
||||
subnetpool_choices = [('', _('Select a pool'))]
|
||||
default_ipv6_subnet_pool_label = \
|
||||
getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {}).get(
|
||||
'default_ipv6_subnet_pool_label', None)
|
||||
default_ipv4_subnet_pool_label = \
|
||||
getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {}).get(
|
||||
'default_ipv4_subnet_pool_label', None)
|
||||
|
||||
if default_ipv6_subnet_pool_label:
|
||||
subnetpool_dict = {'ip_version': 6,
|
||||
'name': default_ipv6_subnet_pool_label}
|
||||
subnetpool = api.neutron.SubnetPool(subnetpool_dict)
|
||||
subnetpool_choices.append(('', subnetpool))
|
||||
|
||||
if default_ipv4_subnet_pool_label:
|
||||
subnetpool_dict = {'ip_version': 4,
|
||||
'name': default_ipv4_subnet_pool_label}
|
||||
subnetpool = api.neutron.SubnetPool(subnetpool_dict)
|
||||
subnetpool_choices.append(('', subnetpool))
|
||||
|
||||
for subnetpool in api.neutron.subnetpool_list(request):
|
||||
subnetpool_choices.append((subnetpool.id, subnetpool))
|
||||
return subnetpool_choices
|
||||
|
||||
def hide_subnetpool_choices(self):
|
||||
self.fields['address_source'].widget = forms.HiddenInput()
|
||||
self.fields['subnetpool'].choices = []
|
||||
self.fields['subnetpool'].widget = forms.HiddenInput()
|
||||
self.fields['prefixlen'].widget = forms.HiddenInput()
|
||||
|
||||
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')
|
||||
no_gateway = cleaned_data.get('no_gateway')
|
||||
if not cidr:
|
||||
address_source = cleaned_data.get('address_source')
|
||||
|
||||
# When creating network from a pool it is allowed to supply empty
|
||||
# subnetpool_id signalling that Neutron should choose the default
|
||||
# pool configured by the operator. This is also part of the IPv6
|
||||
# Prefix Delegation Workflow.
|
||||
if not cidr and address_source != 'subnetpool':
|
||||
raise forms.ValidationError(self.msg)
|
||||
if cidr:
|
||||
subnet = netaddr.IPNetwork(cidr)
|
||||
|
@ -207,8 +315,9 @@ class CreateSubnetInfoAction(workflows.Action):
|
|||
|
||||
class CreateSubnetInfo(workflows.Step):
|
||||
action_class = CreateSubnetInfoAction
|
||||
contributes = ("with_subnet", "subnet_name", "cidr",
|
||||
"ip_version", "gateway_ip", "no_gateway")
|
||||
contributes = ("subnet_name", "cidr", "ip_version",
|
||||
"gateway_ip", "no_gateway", "subnetpool",
|
||||
"prefixlen", "address_source")
|
||||
|
||||
|
||||
class CreateSubnetDetailAction(workflows.Action):
|
||||
|
@ -421,7 +530,7 @@ class CreateNetwork(workflows.Workflow):
|
|||
try:
|
||||
params = {'network_id': network_id,
|
||||
'name': data['subnet_name'],
|
||||
'cidr': data['cidr'],
|
||||
'cidr': data['cidr'] if len(data['cidr']) else None,
|
||||
'ip_version': int(data['ip_version'])}
|
||||
if tenant_id:
|
||||
params['tenant_id'] = tenant_id
|
||||
|
@ -429,6 +538,10 @@ class CreateNetwork(workflows.Workflow):
|
|||
params['gateway_ip'] = None
|
||||
elif data['gateway_ip']:
|
||||
params['gateway_ip'] = data['gateway_ip']
|
||||
if 'subnetpool' in data and len(data['subnetpool']):
|
||||
params['subnetpool_id'] = data['subnetpool']
|
||||
if 'prefixlen' in data and len(data['prefixlen']):
|
||||
params['prefixlen'] = data['prefixlen']
|
||||
|
||||
self._setup_subnet_parameters(params, data)
|
||||
|
||||
|
|
|
@ -225,6 +225,18 @@ OPENSTACK_NEUTRON_NETWORK = {
|
|||
'enable_vpn': True,
|
||||
'enable_fip_topology_check': True,
|
||||
|
||||
# Neutron can be configured with a default Subnet Pool to be used for IPv4
|
||||
# subnet-allocation. Specify the label you wish to display in the Address
|
||||
# pool selector on the create subnet step if you want to use this feature.
|
||||
'default_ipv4_subnet_pool_label': None,
|
||||
|
||||
# Neutron can be configured with a default Subnet Pool to be used for IPv6
|
||||
# subnet-allocation. Specify the label you wish to display in the Address
|
||||
# pool selector on the create subnet step if you want to use this feature.
|
||||
# You must set this to enable IPv6 Prefix Delegation in a PD-capable
|
||||
# environment.
|
||||
'default_ipv6_subnet_pool_label': None,
|
||||
|
||||
# The profile_support option is used to detect if an external router can be
|
||||
# configured via the dashboard. When using specific plugins the
|
||||
# profile_support can be turned on if needed.
|
||||
|
|
Loading…
Reference in New Issue