Merge "Support create subnet w/Neutron subnet allocation"
This commit is contained in:
commit
07d549c299
|
@ -797,6 +797,8 @@ Default::
|
||||||
'supported_vnic_types': ["*"],
|
'supported_vnic_types': ["*"],
|
||||||
'segmentation_id_range': {},
|
'segmentation_id_range': {},
|
||||||
'enable_fip_topology_check': True,
|
'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
|
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)
|
.. 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``
|
``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
|
* 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
|
* 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_image_source();
|
||||||
horizon.forms.handle_object_upload_source();
|
horizon.forms.handle_object_upload_source();
|
||||||
horizon.forms.datepicker();
|
horizon.forms.datepicker();
|
||||||
|
horizon.forms.handle_subnet_address_source();
|
||||||
|
horizon.forms.handle_subnet_subnetpool();
|
||||||
|
|
||||||
if (!horizon.conf.disable_password_reveal) {
|
if (!horizon.conf.disable_password_reveal) {
|
||||||
horizon.forms.add_password_fields_reveal_buttons($("body"));
|
horizon.forms.add_password_fields_reveal_buttons($("body"));
|
||||||
|
@ -260,24 +324,25 @@ horizon.addInitFunction(horizon.forms.init = function () {
|
||||||
visible = $switchable.is(':visible'),
|
visible = $switchable.is(':visible'),
|
||||||
slug = $switchable.data('slug'),
|
slug = $switchable.data('slug'),
|
||||||
checked = $switchable.prop('checked'),
|
checked = $switchable.prop('checked'),
|
||||||
hide_tab = $switchable.data('hide-tab'),
|
hide_tab = String($switchable.data('hide-tab')).split(','),
|
||||||
hide_on = $switchable.data('hideOnChecked');
|
hide_on = $switchable.data('hideOnChecked');
|
||||||
|
|
||||||
// If checkbox is hidden then do not apply any further logic
|
// If checkbox is hidden then do not apply any further logic
|
||||||
if (!visible) return;
|
if (!visible) return;
|
||||||
|
|
||||||
// If the checkbox has hide-tab attribute then hide/show the tab
|
// 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');
|
var $btnfinal = $('.button-final');
|
||||||
if(checked == hide_on) {
|
if(checked == hide_on) {
|
||||||
// If the checkbox is not checked then hide the tab
|
// 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();
|
$('.button-next').hide();
|
||||||
$btnfinal.show();
|
$btnfinal.show();
|
||||||
$btnfinal.data('show-on-tab', $fieldset.prop('id'));
|
$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
|
// 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();
|
$btnfinal.hide();
|
||||||
$('.button-next').show();
|
$('.button-next').show();
|
||||||
$btnfinal.removeData('show-on-tab');
|
$btnfinal.removeData('show-on-tab');
|
||||||
|
|
|
@ -118,6 +118,14 @@ class DetailView(tabs.TabView):
|
||||||
subnet.ipv6_ra_mode, subnet.ipv6_address_mode)
|
subnet.ipv6_ra_mode, subnet.ipv6_address_mode)
|
||||||
subnet.ipv6_modes_desc = utils.IPV6_MODE_MAP.get(ipv6_modes)
|
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
|
return subnet
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
|
|
@ -36,7 +36,6 @@ class CreateSubnetInfoAction(network_workflows.CreateSubnetInfoAction):
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(CreateSubnetInfoAction, self).__init__(request, *args, **kwargs)
|
super(CreateSubnetInfoAction, self).__init__(request, *args, **kwargs)
|
||||||
self.fields['cidr'].required = True
|
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = _("Subnet")
|
name = _("Subnet")
|
||||||
|
@ -82,6 +81,12 @@ class CreateSubnet(network_workflows.CreateNetwork):
|
||||||
|
|
||||||
|
|
||||||
class UpdateSubnetInfoAction(CreateSubnetInfoAction):
|
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"),
|
cidr = forms.IPField(label=_("Network Address"),
|
||||||
required=False,
|
required=False,
|
||||||
initial="",
|
initial="",
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
{% url 'horizon:project:networks:detail' subnet.network_id as network_url %}
|
{% url 'horizon:project:networks:detail' subnet.network_id as network_url %}
|
||||||
<dt>{% trans "Network ID" %}</dt>
|
<dt>{% trans "Network ID" %}</dt>
|
||||||
<dd><a href="{{ network_url }}">{{ subnet.network_id|default:_("None") }}</a></dd>
|
<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>
|
<dt>{% trans "IP version" %}</dt>
|
||||||
<dd>{{ subnet.ipver_str|default:_("-") }}</dd>
|
<dd>{{ subnet.ipver_str|default:_("-") }}</dd>
|
||||||
<dt>{% trans "CIDR" %}</dt>
|
<dt>{% trans "CIDR" %}</dt>
|
||||||
|
|
|
@ -463,6 +463,7 @@ class NetworkTests(test.TestCase):
|
||||||
def test_network_create_post_with_subnet_network_exception(
|
def test_network_create_post_with_subnet_network_exception(
|
||||||
self,
|
self,
|
||||||
test_with_profile=False,
|
test_with_profile=False,
|
||||||
|
test_with_subnetpool=False,
|
||||||
):
|
):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
|
@ -499,7 +500,9 @@ class NetworkTests(test.TestCase):
|
||||||
@test.create_stubs({api.neutron: ('network_create',
|
@test.create_stubs({api.neutron: ('network_create',
|
||||||
'network_delete',
|
'network_delete',
|
||||||
'subnet_create',
|
'subnet_create',
|
||||||
'profile_list')})
|
'profile_list',
|
||||||
|
'is_extension_supported',
|
||||||
|
'subnetpool_list',)})
|
||||||
def test_network_create_post_with_subnet_subnet_exception(
|
def test_network_create_post_with_subnet_subnet_exception(
|
||||||
self,
|
self,
|
||||||
test_with_profile=False,
|
test_with_profile=False,
|
||||||
|
@ -514,6 +517,11 @@ class NetworkTests(test.TestCase):
|
||||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||||
'network').AndReturn(net_profiles)
|
'network').AndReturn(net_profiles)
|
||||||
params['net_profile_id'] = net_profile_id
|
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),
|
api.neutron.network_create(IsA(http.HttpRequest),
|
||||||
**params).AndReturn(network)
|
**params).AndReturn(network)
|
||||||
api.neutron.subnet_create(IsA(http.HttpRequest),
|
api.neutron.subnet_create(IsA(http.HttpRequest),
|
||||||
|
@ -546,9 +554,12 @@ class NetworkTests(test.TestCase):
|
||||||
self.test_network_create_post_with_subnet_subnet_exception(
|
self.test_network_create_post_with_subnet_subnet_exception(
|
||||||
test_with_profile=True)
|
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,
|
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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
|
@ -556,6 +567,11 @@ class NetworkTests(test.TestCase):
|
||||||
net_profile_id = self.net_profiles.first().id
|
net_profile_id = self.net_profiles.first().id
|
||||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||||
'network').AndReturn(net_profiles)
|
'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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
form_data = {'net_name': network.name,
|
form_data = {'net_name': network.name,
|
||||||
|
@ -563,12 +579,16 @@ class NetworkTests(test.TestCase):
|
||||||
'with_subnet': True}
|
'with_subnet': True}
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
form_data['net_profile_id'] = net_profile_id
|
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='',
|
form_data.update(form_data_subnet(subnet, cidr='',
|
||||||
allocation_pools=[]))
|
allocation_pools=[]))
|
||||||
url = reverse('horizon:project:networks:create')
|
url = reverse('horizon:project:networks:create')
|
||||||
res = self.client.post(url, form_data)
|
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.'))
|
'clear "Create Subnet" checkbox.'))
|
||||||
|
|
||||||
@test.update_settings(
|
@test.update_settings(
|
||||||
|
@ -577,10 +597,17 @@ class NetworkTests(test.TestCase):
|
||||||
self.test_network_create_post_with_subnet_nocidr(
|
self.test_network_create_post_with_subnet_nocidr(
|
||||||
test_with_profile=True)
|
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(
|
def test_network_create_post_with_subnet_cidr_without_mask(
|
||||||
self,
|
self,
|
||||||
test_with_profile=False,
|
test_with_profile=False,
|
||||||
|
test_with_subnetpool=False,
|
||||||
):
|
):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
|
@ -589,13 +616,22 @@ class NetworkTests(test.TestCase):
|
||||||
net_profile_id = self.net_profiles.first().id
|
net_profile_id = self.net_profiles.first().id
|
||||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||||
'network').AndReturn(net_profiles)
|
'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,
|
form_data = {'net_name': network.name,
|
||||||
'admin_state': network.admin_state_up,
|
'admin_state': network.admin_state_up,
|
||||||
'with_subnet': True}
|
'with_subnet': True}
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
form_data['net_profile_id'] = net_profile_id
|
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',
|
form_data.update(form_data_subnet(subnet, cidr='10.0.0.0',
|
||||||
allocation_pools=[]))
|
allocation_pools=[]))
|
||||||
url = reverse('horizon:project:networks:create')
|
url = reverse('horizon:project:networks:create')
|
||||||
|
@ -610,10 +646,17 @@ class NetworkTests(test.TestCase):
|
||||||
self.test_network_create_post_with_subnet_cidr_without_mask(
|
self.test_network_create_post_with_subnet_cidr_without_mask(
|
||||||
test_with_profile=True)
|
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(
|
def test_network_create_post_with_subnet_cidr_inconsistent(
|
||||||
self,
|
self,
|
||||||
test_with_profile=False,
|
test_with_profile=False,
|
||||||
|
test_with_subnetpool=False
|
||||||
):
|
):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
|
@ -622,6 +665,12 @@ class NetworkTests(test.TestCase):
|
||||||
net_profile_id = self.net_profiles.first().id
|
net_profile_id = self.net_profiles.first().id
|
||||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||||
'network').AndReturn(net_profiles)
|
'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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
# dummy IPv6 address
|
# dummy IPv6 address
|
||||||
|
@ -631,6 +680,10 @@ class NetworkTests(test.TestCase):
|
||||||
'with_subnet': True}
|
'with_subnet': True}
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
form_data['net_profile_id'] = net_profile_id
|
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,
|
form_data.update(form_data_subnet(subnet, cidr=cidr,
|
||||||
allocation_pools=[]))
|
allocation_pools=[]))
|
||||||
url = reverse('horizon:project:networks:create')
|
url = reverse('horizon:project:networks:create')
|
||||||
|
@ -645,10 +698,17 @@ class NetworkTests(test.TestCase):
|
||||||
self.test_network_create_post_with_subnet_cidr_inconsistent(
|
self.test_network_create_post_with_subnet_cidr_inconsistent(
|
||||||
test_with_profile=True)
|
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(
|
def test_network_create_post_with_subnet_gw_inconsistent(
|
||||||
self,
|
self,
|
||||||
test_with_profile=False,
|
test_with_profile=False,
|
||||||
|
test_with_subnetpool=False,
|
||||||
):
|
):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
|
@ -657,6 +717,12 @@ class NetworkTests(test.TestCase):
|
||||||
net_profile_id = self.net_profiles.first().id
|
net_profile_id = self.net_profiles.first().id
|
||||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||||
'network').AndReturn(net_profiles)
|
'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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
# dummy IPv6 address
|
# dummy IPv6 address
|
||||||
|
@ -666,6 +732,10 @@ class NetworkTests(test.TestCase):
|
||||||
'with_subnet': True}
|
'with_subnet': True}
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
form_data['net_profile_id'] = net_profile_id
|
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,
|
form_data.update(form_data_subnet(subnet, gateway_ip=gateway_ip,
|
||||||
allocation_pools=[]))
|
allocation_pools=[]))
|
||||||
url = reverse('horizon:project:networks:create')
|
url = reverse('horizon:project:networks:create')
|
||||||
|
@ -679,6 +749,10 @@ class NetworkTests(test.TestCase):
|
||||||
self.test_network_create_post_with_subnet_gw_inconsistent(
|
self.test_network_create_post_with_subnet_gw_inconsistent(
|
||||||
test_with_profile=True)
|
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',)})
|
@test.create_stubs({api.neutron: ('network_get',)})
|
||||||
def test_network_update_get(self):
|
def test_network_update_get(self):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
|
@ -834,7 +908,8 @@ class NetworkTests(test.TestCase):
|
||||||
|
|
||||||
class NetworkSubnetTests(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):
|
def test_subnet_detail(self):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
|
@ -883,7 +958,7 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',
|
@test.create_stubs({api.neutron: ('network_get',
|
||||||
'subnet_create',)})
|
'subnet_create',)})
|
||||||
def test_subnet_create_post(self):
|
def test_subnet_create_post(self, test_with_subnetpool=False):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
|
@ -972,7 +1047,8 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',
|
@test.create_stubs({api.neutron: ('network_get',
|
||||||
'subnet_create',)})
|
'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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
|
@ -980,8 +1056,12 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
.AndRaise(self.exceptions.neutron)
|
.AndRaise(self.exceptions.neutron)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
form_data = form_data_subnet(subnet,
|
form_data = {}
|
||||||
allocation_pools=[])
|
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',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -989,9 +1069,14 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
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',
|
@test.create_stubs({api.neutron: ('network_get',
|
||||||
'subnet_create',)})
|
'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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
|
@ -1007,8 +1092,7 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
.AndRaise(self.exceptions.neutron)
|
.AndRaise(self.exceptions.neutron)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
form_data = form_data_subnet(subnet,
|
form_data = form_data_subnet(subnet, allocation_pools=[])
|
||||||
allocation_pools=[])
|
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1017,19 +1101,34 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
self.assertRedirectsNoFollow(res, redir_url)
|
self.assertRedirectsNoFollow(res, redir_url)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
@test.create_stubs({api.neutron: ('network_get',
|
||||||
def test_subnet_create_post_cidr_inconsistent(self):
|
'is_extension_supported',
|
||||||
|
'subnetpool_list',)})
|
||||||
|
def test_subnet_create_post_cidr_inconsistent(self,
|
||||||
|
test_with_subnetpool=False):
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id)\
|
network.id)\
|
||||||
.AndReturn(self.networks.first())
|
.AndReturn(self.networks.first())
|
||||||
|
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'subnet_allocation').\
|
||||||
|
AndReturn(True)
|
||||||
|
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||||
|
AndReturn(self.subnetpools.list())
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if test_with_subnetpool:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# dummy IPv6 address
|
# dummy IPv6 address
|
||||||
cidr = '2001:0DB8:0:CD30:123:4567:89AB:CDEF/60'
|
cidr = '2001:0DB8:0:CD30:123:4567:89AB:CDEF/60'
|
||||||
form_data = form_data_subnet(subnet, cidr=cidr,
|
form_data.update(form_data_subnet(subnet, cidr=cidr,
|
||||||
allocation_pools=[])
|
allocation_pools=[]))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1038,37 +1137,74 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
self.assertFormErrors(res, 1, expected_msg)
|
self.assertFormErrors(res, 1, expected_msg)
|
||||||
self.assertTemplateUsed(res, views.WorkflowView.template_name)
|
self.assertTemplateUsed(res, views.WorkflowView.template_name)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_cidr_inconsistent_with_subnetpool(self):
|
||||||
def test_subnet_create_post_gw_inconsistent(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id)\
|
network.id)\
|
||||||
.AndReturn(self.networks.first())
|
.AndReturn(self.networks.first())
|
||||||
|
|
||||||
|
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||||
|
'subnet_allocation').\
|
||||||
|
AndReturn(True)
|
||||||
|
api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
|
||||||
|
AndReturn(self.subnetpools.list())
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if test_with_subnetpool:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# dummy IPv6 address
|
# dummy IPv6 address
|
||||||
gateway_ip = '2001:0DB8:0:CD30:123:4567:89AB:CDEF'
|
gateway_ip = '2001:0DB8:0:CD30:123:4567:89AB:CDEF'
|
||||||
form_data = form_data_subnet(subnet, gateway_ip=gateway_ip,
|
form_data.update(form_data_subnet(subnet, gateway_ip=gateway_ip,
|
||||||
allocation_pools=[])
|
allocation_pools=[]))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
|
||||||
self.assertContains(res, 'Gateway IP and IP version are inconsistent.')
|
self.assertContains(res, 'Gateway IP and IP version are inconsistent.')
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_gw_inconsistent_with_subnetpool(self):
|
||||||
def test_subnet_create_post_invalid_pools_start_only(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if test_w_snpool:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# Start only allocation_pools
|
# Start only allocation_pools
|
||||||
allocation_pools = '10.0.0.2'
|
allocation_pools = '10.0.0.2'
|
||||||
form_data = form_data_subnet(subnet,
|
form_data.update(form_data_subnet(subnet,
|
||||||
allocation_pools=allocation_pools)
|
allocation_pools=allocation_pools))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1077,18 +1213,37 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'Start and end addresses must be specified '
|
'Start and end addresses must be specified '
|
||||||
'(value=%s)' % allocation_pools)
|
'(value=%s)' % allocation_pools)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_invalid_pools_start_only_with_subnetpool(self):
|
||||||
def test_subnet_create_post_invalid_pools_three_entries(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if t_w_snpool:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# pool with three entries
|
# pool with three entries
|
||||||
allocation_pools = '10.0.0.2,10.0.0.3,10.0.0.4'
|
allocation_pools = '10.0.0.2,10.0.0.3,10.0.0.4'
|
||||||
form_data = form_data_subnet(subnet,
|
form_data.update(form_data_subnet(subnet,
|
||||||
allocation_pools=allocation_pools)
|
allocation_pools=allocation_pools))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1097,18 +1252,37 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'Start and end addresses must be specified '
|
'Start and end addresses must be specified '
|
||||||
'(value=%s)' % allocation_pools)
|
'(value=%s)' % allocation_pools)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_invalid_pools_three_entries_w_subnetpool(self):
|
||||||
def test_subnet_create_post_invalid_pools_invalid_address(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
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
|
# end address is not a valid IP address
|
||||||
allocation_pools = '10.0.0.2,invalid_address'
|
allocation_pools = '10.0.0.2,invalid_address'
|
||||||
form_data = form_data_subnet(subnet,
|
form_data.update(form_data_subnet(subnet,
|
||||||
allocation_pools=allocation_pools)
|
allocation_pools=allocation_pools))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1117,18 +1291,37 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'allocation_pools: Invalid IP address '
|
'allocation_pools: Invalid IP address '
|
||||||
'(value=%s)' % allocation_pools.split(',')[1])
|
'(value=%s)' % allocation_pools.split(',')[1])
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_invalid_pools_invalid_address_w_snpool(self):
|
||||||
def test_subnet_create_post_invalid_pools_ip_network(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if test_w_snpool:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# start address is CIDR
|
# start address is CIDR
|
||||||
allocation_pools = '10.0.0.2/24,10.0.0.5'
|
allocation_pools = '10.0.0.2/24,10.0.0.5'
|
||||||
form_data = form_data_subnet(subnet,
|
form_data.update(form_data_subnet(subnet,
|
||||||
allocation_pools=allocation_pools)
|
allocation_pools=allocation_pools))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1137,14 +1330,33 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'allocation_pools: Invalid IP address '
|
'allocation_pools: Invalid IP address '
|
||||||
'(value=%s)' % allocation_pools.split(',')[0])
|
'(value=%s)' % allocation_pools.split(',')[0])
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_invalid_pools_ip_network_with_subnetpool(self):
|
||||||
def test_subnet_create_post_invalid_pools_start_larger_than_end(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if tsn:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# start address is larger than end address
|
# start address is larger than end address
|
||||||
allocation_pools = '10.0.0.254,10.0.0.2'
|
allocation_pools = '10.0.0.254,10.0.0.2'
|
||||||
form_data = form_data_subnet(subnet,
|
form_data = form_data_subnet(subnet,
|
||||||
|
@ -1157,18 +1369,38 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'Start address is larger than end address '
|
'Start address is larger than end address '
|
||||||
'(value=%s)' % allocation_pools)
|
'(value=%s)' % allocation_pools)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_invalid_pools_start_larger_than_end_tsn(self):
|
||||||
def test_subnet_create_post_invalid_nameservers(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if test_w_subnetpool:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# invalid DNS server address
|
# invalid DNS server address
|
||||||
dns_nameservers = ['192.168.0.2', 'invalid_address']
|
dns_nameservers = ['192.168.0.2', 'invalid_address']
|
||||||
form_data = form_data_subnet(subnet, dns_nameservers=dns_nameservers,
|
form_data.update(form_data_subnet(subnet,
|
||||||
allocation_pools=[])
|
dns_nameservers=dns_nameservers,
|
||||||
|
allocation_pools=[]))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1177,19 +1409,39 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'dns_nameservers: Invalid IP address '
|
'dns_nameservers: Invalid IP address '
|
||||||
'(value=%s)' % dns_nameservers[1])
|
'(value=%s)' % dns_nameservers[1])
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_invalid_nameservers_with_subnetpool(self):
|
||||||
def test_subnet_create_post_invalid_routes_destination_only(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if tsn:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# Start only host_route
|
# Start only host_route
|
||||||
host_routes = '192.168.0.0/24'
|
host_routes = '192.168.0.0/24'
|
||||||
form_data = form_data_subnet(subnet,
|
form_data.update(form_data_subnet(subnet,
|
||||||
allocation_pools=[],
|
allocation_pools=[],
|
||||||
host_routes=host_routes)
|
host_routes=host_routes))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1199,19 +1451,38 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'Destination CIDR and nexthop must be specified '
|
'Destination CIDR and nexthop must be specified '
|
||||||
'(value=%s)' % host_routes)
|
'(value=%s)' % host_routes)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_invalid_routes_destination_only_w_snpool(self):
|
||||||
def test_subnet_create_post_invalid_routes_three_entries(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if tsn:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# host_route with three entries
|
# host_route with three entries
|
||||||
host_routes = 'aaaa,bbbb,cccc'
|
host_routes = 'aaaa,bbbb,cccc'
|
||||||
form_data = form_data_subnet(subnet,
|
form_data.update(form_data_subnet(subnet,
|
||||||
allocation_pools=[],
|
allocation_pools=[],
|
||||||
host_routes=host_routes)
|
host_routes=host_routes))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1221,19 +1492,38 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'Destination CIDR and nexthop must be specified '
|
'Destination CIDR and nexthop must be specified '
|
||||||
'(value=%s)' % host_routes)
|
'(value=%s)' % host_routes)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_invalid_routes_three_entries_with_tsn(self):
|
||||||
def test_subnet_create_post_invalid_routes_invalid_destination(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if tsn:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# invalid destination network
|
# invalid destination network
|
||||||
host_routes = '172.16.0.0/64,10.0.0.253'
|
host_routes = '172.16.0.0/64,10.0.0.253'
|
||||||
form_data = form_data_subnet(subnet,
|
form_data.update(form_data_subnet(subnet,
|
||||||
host_routes=host_routes,
|
host_routes=host_routes,
|
||||||
allocation_pools=[])
|
allocation_pools=[]))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1242,19 +1532,38 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'host_routes: Invalid IP address '
|
'host_routes: Invalid IP address '
|
||||||
'(value=%s)' % host_routes.split(',')[0])
|
'(value=%s)' % host_routes.split(',')[0])
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',)})
|
def test_subnet_create_post_invalid_routes_invalid_destination_tsn(self):
|
||||||
def test_subnet_create_post_invalid_routes_nexthop_ip_network(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()
|
network = self.networks.first()
|
||||||
subnet = self.subnets.first()
|
subnet = self.subnets.first()
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
network.id).AndReturn(network)
|
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {}
|
||||||
|
if tsn:
|
||||||
|
subnetpool = self.subnetpools.first()
|
||||||
|
form_data['subnetpool'] = subnetpool.id
|
||||||
|
|
||||||
# nexthop is not an IP address
|
# nexthop is not an IP address
|
||||||
host_routes = '172.16.0.0/24,10.0.0.253/24'
|
host_routes = '172.16.0.0/24,10.0.0.253/24'
|
||||||
form_data = form_data_subnet(subnet,
|
form_data.update(form_data_subnet(subnet,
|
||||||
host_routes=host_routes,
|
host_routes=host_routes,
|
||||||
allocation_pools=[])
|
allocation_pools=[]))
|
||||||
url = reverse('horizon:project:networks:addsubnet',
|
url = reverse('horizon:project:networks:addsubnet',
|
||||||
args=[subnet.network_id])
|
args=[subnet.network_id])
|
||||||
res = self.client.post(url, form_data)
|
res = self.client.post(url, form_data)
|
||||||
|
@ -1263,9 +1572,20 @@ class NetworkSubnetTests(test.TestCase):
|
||||||
'host_routes: Invalid IP address '
|
'host_routes: Invalid IP address '
|
||||||
'(value=%s)' % host_routes.split(',')[1])
|
'(value=%s)' % host_routes.split(',')[1])
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_get',
|
def test_subnet_create_post_invalid_routes_nexthop_ip_network_tsn(self):
|
||||||
'subnet_create',)})
|
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):
|
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")
|
network = self.networks.get(name="v6_net1")
|
||||||
subnet = self.subnets.get(name="v6_subnet1")
|
subnet = self.subnets.get(name="v6_subnet1")
|
||||||
api.neutron.network_get(IsA(http.HttpRequest),
|
api.neutron.network_get(IsA(http.HttpRequest),
|
||||||
|
|
|
@ -50,6 +50,20 @@ class CreateNetworkInfoAction(workflows.Action):
|
||||||
required=False,
|
required=False,
|
||||||
help_text=_("The state to start"
|
help_text=_("The state to start"
|
||||||
" the network in."))
|
" 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):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(CreateNetworkInfoAction, self).__init__(request,
|
super(CreateNetworkInfoAction, self).__init__(request,
|
||||||
|
@ -84,35 +98,56 @@ class CreateNetworkInfoAction(workflows.Action):
|
||||||
|
|
||||||
class CreateNetworkInfo(workflows.Step):
|
class CreateNetworkInfo(workflows.Step):
|
||||||
action_class = CreateNetworkInfoAction
|
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):
|
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,
|
subnet_name = forms.CharField(max_length=255,
|
||||||
widget=forms.TextInput(attrs={
|
widget=forms.TextInput(attrs={
|
||||||
'class': 'switched',
|
|
||||||
'data-switch-on': 'with_subnet',
|
|
||||||
}),
|
}),
|
||||||
label=_("Subnet Name"),
|
label=_("Subnet Name"),
|
||||||
required=False)
|
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"),
|
cidr = forms.IPField(label=_("Network Address"),
|
||||||
required=False,
|
required=False,
|
||||||
initial="",
|
initial="",
|
||||||
widget=forms.TextInput(attrs={
|
widget=forms.TextInput(attrs={
|
||||||
'class': 'switched',
|
'class': 'switched',
|
||||||
'data-switch-on': 'with_subnet',
|
'data-switch-on': 'source',
|
||||||
'data-is-required': 'true'
|
'data-source-manual': _("Network Address"),
|
||||||
}),
|
}),
|
||||||
help_text=_("Network address in CIDR format "
|
help_text=_("Network address in CIDR format "
|
||||||
"(e.g. 192.168.0.0/24, 2001:DB8::/48)"),
|
"(e.g. 192.168.0.0/24, 2001:DB8::/48)"),
|
||||||
|
@ -120,16 +155,17 @@ class CreateSubnetInfoAction(workflows.Action):
|
||||||
mask=True)
|
mask=True)
|
||||||
ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
|
ip_version = forms.ChoiceField(choices=[(4, 'IPv4'), (6, 'IPv6')],
|
||||||
widget=forms.Select(attrs={
|
widget=forms.Select(attrs={
|
||||||
'class': 'switchable switched',
|
'class': 'switchable',
|
||||||
'data-slug': 'ipversion',
|
'data-slug': 'ipversion',
|
||||||
'data-switch-on': 'with_subnet'
|
|
||||||
}),
|
}),
|
||||||
label=_("IP Version"))
|
label=_("IP Version"),
|
||||||
|
required=False)
|
||||||
gateway_ip = forms.IPField(
|
gateway_ip = forms.IPField(
|
||||||
label=_("Gateway IP"),
|
label=_("Gateway IP"),
|
||||||
widget=forms.TextInput(attrs={
|
widget=forms.TextInput(attrs={
|
||||||
'class': 'switched',
|
'class': 'switched',
|
||||||
'data-switch-on': 'with_subnet gateway_ip'
|
'data-switch-on': 'source gateway_ip',
|
||||||
|
'data-source-manual': _("Gateway IP")
|
||||||
}),
|
}),
|
||||||
required=False,
|
required=False,
|
||||||
initial="",
|
initial="",
|
||||||
|
@ -145,37 +181,109 @@ class CreateSubnetInfoAction(workflows.Action):
|
||||||
mask=False)
|
mask=False)
|
||||||
no_gateway = forms.BooleanField(label=_("Disable Gateway"),
|
no_gateway = forms.BooleanField(label=_("Disable Gateway"),
|
||||||
widget=forms.CheckboxInput(attrs={
|
widget=forms.CheckboxInput(attrs={
|
||||||
'class': 'switched switchable',
|
'class': 'switchable',
|
||||||
'data-slug': 'gateway_ip',
|
'data-slug': 'gateway_ip',
|
||||||
'data-switch-on': 'with_subnet',
|
|
||||||
'data-hide-on-checked': 'true'
|
'data-hide-on-checked': 'true'
|
||||||
}),
|
}),
|
||||||
initial=False,
|
initial=False,
|
||||||
required=False)
|
required=False)
|
||||||
msg = _('Specify "Network Address" or '
|
msg = _('Specify "Network Address", "Address pool" or '
|
||||||
'clear "Create Subnet" checkbox.')
|
'clear "Create Subnet" checkbox.')
|
||||||
|
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = _("Subnet")
|
name = _("Subnet")
|
||||||
help_text = _('Create a subnet associated with the new network, '
|
help_text = _('Create a subnet associated with the network. '
|
||||||
'in which case "Network Address" must be specified. '
|
'Advanced configuration is available by clicking on the '
|
||||||
'If you wish to create a network without a subnet, '
|
'"Subnet Details" tab.')
|
||||||
'uncheck the "Create Subnet" checkbox.')
|
|
||||||
|
|
||||||
def __init__(self, request, context, *args, **kwargs):
|
def __init__(self, request, context, *args, **kwargs):
|
||||||
super(CreateSubnetInfoAction, self).__init__(request, context, *args,
|
super(CreateSubnetInfoAction, self).__init__(request, context, *args,
|
||||||
**kwargs)
|
**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',
|
if not getattr(settings, 'OPENSTACK_NEUTRON_NETWORK',
|
||||||
{}).get('enable_ipv6', True):
|
{}).get('enable_ipv6', True):
|
||||||
self.fields['ip_version'].widget = forms.HiddenInput()
|
self.fields['ip_version'].widget = forms.HiddenInput()
|
||||||
self.fields['ip_version'].initial = 4
|
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):
|
def _check_subnet_data(self, cleaned_data, is_create=True):
|
||||||
cidr = cleaned_data.get('cidr')
|
cidr = cleaned_data.get('cidr')
|
||||||
ip_version = int(cleaned_data.get('ip_version'))
|
ip_version = int(cleaned_data.get('ip_version'))
|
||||||
gateway_ip = cleaned_data.get('gateway_ip')
|
gateway_ip = cleaned_data.get('gateway_ip')
|
||||||
no_gateway = cleaned_data.get('no_gateway')
|
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)
|
raise forms.ValidationError(self.msg)
|
||||||
if cidr:
|
if cidr:
|
||||||
subnet = netaddr.IPNetwork(cidr)
|
subnet = netaddr.IPNetwork(cidr)
|
||||||
|
@ -207,8 +315,9 @@ class CreateSubnetInfoAction(workflows.Action):
|
||||||
|
|
||||||
class CreateSubnetInfo(workflows.Step):
|
class CreateSubnetInfo(workflows.Step):
|
||||||
action_class = CreateSubnetInfoAction
|
action_class = CreateSubnetInfoAction
|
||||||
contributes = ("with_subnet", "subnet_name", "cidr",
|
contributes = ("subnet_name", "cidr", "ip_version",
|
||||||
"ip_version", "gateway_ip", "no_gateway")
|
"gateway_ip", "no_gateway", "subnetpool",
|
||||||
|
"prefixlen", "address_source")
|
||||||
|
|
||||||
|
|
||||||
class CreateSubnetDetailAction(workflows.Action):
|
class CreateSubnetDetailAction(workflows.Action):
|
||||||
|
@ -421,7 +530,7 @@ class CreateNetwork(workflows.Workflow):
|
||||||
try:
|
try:
|
||||||
params = {'network_id': network_id,
|
params = {'network_id': network_id,
|
||||||
'name': data['subnet_name'],
|
'name': data['subnet_name'],
|
||||||
'cidr': data['cidr'],
|
'cidr': data['cidr'] if len(data['cidr']) else None,
|
||||||
'ip_version': int(data['ip_version'])}
|
'ip_version': int(data['ip_version'])}
|
||||||
if tenant_id:
|
if tenant_id:
|
||||||
params['tenant_id'] = tenant_id
|
params['tenant_id'] = tenant_id
|
||||||
|
@ -429,6 +538,10 @@ class CreateNetwork(workflows.Workflow):
|
||||||
params['gateway_ip'] = None
|
params['gateway_ip'] = None
|
||||||
elif data['gateway_ip']:
|
elif data['gateway_ip']:
|
||||||
params['gateway_ip'] = 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)
|
self._setup_subnet_parameters(params, data)
|
||||||
|
|
||||||
|
|
|
@ -225,6 +225,18 @@ OPENSTACK_NEUTRON_NETWORK = {
|
||||||
'enable_vpn': True,
|
'enable_vpn': True,
|
||||||
'enable_fip_topology_check': 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
|
# The profile_support option is used to detect if an external router can be
|
||||||
# configured via the dashboard. When using specific plugins the
|
# configured via the dashboard. When using specific plugins the
|
||||||
# profile_support can be turned on if needed.
|
# profile_support can be turned on if needed.
|
||||||
|
|
Loading…
Reference in New Issue