Support provider network extension when creating network
This adds the ability for admins to set the provider network settings when creating a network. This includes the network type, physical network, and segmentation ID. These options will only be available if the provider network neutron extension is supported. Change-Id: I6108504a92a32f067cf151ec103171a7bbb601df Implements: blueprint quantum-network-provider-types Closes-Bug: 1223360
This commit is contained in:
parent
d24f00d24e
commit
b4fb18198c
|
@ -493,7 +493,54 @@ by cinder. Currently only the backup service is available.
|
||||||
Default: ``{'enable_lb': False}``
|
Default: ``{'enable_lb': False}``
|
||||||
|
|
||||||
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
|
||||||
by neutron. Currently only the load balancer service is available.
|
by neutron and configure neutron specific features. The following options are
|
||||||
|
available.
|
||||||
|
|
||||||
|
.. enable_lb:
|
||||||
|
|
||||||
|
``enable_lb``
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. versionadded:: 2013.2(Havana)
|
||||||
|
|
||||||
|
Default: ``False``
|
||||||
|
|
||||||
|
Enable or disable the load balancer service.
|
||||||
|
|
||||||
|
.. supported_provider_types:
|
||||||
|
|
||||||
|
``supported_provider_types``
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. versionadded:: 2014.2(Juno)
|
||||||
|
|
||||||
|
Default: ``["*"]``
|
||||||
|
|
||||||
|
For use with the provider network extension. Use this to explicitly set which
|
||||||
|
provider network types are supported. Only the network types in this list will
|
||||||
|
be available to choose from when creating a network. Network types include
|
||||||
|
local, flat, vlan, gre, and vxlan. By default all provider network types will
|
||||||
|
be available to choose from.
|
||||||
|
|
||||||
|
Example: ``['local', 'flat', 'gre']``
|
||||||
|
|
||||||
|
.. segmentation_id_range:
|
||||||
|
|
||||||
|
``segmentation_id_range``
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. versionadded:: 2014.2(Juno)
|
||||||
|
|
||||||
|
Default: ``None``
|
||||||
|
|
||||||
|
For use with the provider network extension. This is a dictionary where each
|
||||||
|
key is a provider network type and each value is a list containing two numbers.
|
||||||
|
The first number is the minimum segmentation ID that is valid. The second
|
||||||
|
number is the maximum segmentation ID. Pertains only to the vlan, gre, and
|
||||||
|
vxlan network types. By default this option is not provided and each minimum
|
||||||
|
and maximum value will be the default for the provider network type.
|
||||||
|
|
||||||
|
Example: ``{'vlan': [1024, 2048], 'gre': [4094, 65536]}``
|
||||||
|
|
||||||
|
|
||||||
``OPENSTACK_SSL_CACERT``
|
``OPENSTACK_SSL_CACERT``
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
@ -25,6 +26,10 @@ from openstack_dashboard import api
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
PROVIDER_TYPES = [('local', _('Local')), ('flat', _('Flat')),
|
||||||
|
('vlan', 'VLAN'), ('gre', 'GRE'), ('vxlan', 'VXLAN')]
|
||||||
|
SEGMENTATION_ID_RANGE = {'vlan': [1, 4094], 'gre': [0, (2 ** 32) - 1],
|
||||||
|
'vxlan': [0, (2 ** 24) - 1]}
|
||||||
|
|
||||||
|
|
||||||
class CreateNetwork(forms.SelfHandlingForm):
|
class CreateNetwork(forms.SelfHandlingForm):
|
||||||
|
@ -39,6 +44,35 @@ class CreateNetwork(forms.SelfHandlingForm):
|
||||||
net_profile_id = forms.ChoiceField(label=_("Network Profile"),
|
net_profile_id = forms.ChoiceField(label=_("Network Profile"),
|
||||||
required=False,
|
required=False,
|
||||||
widget=widget)
|
widget=widget)
|
||||||
|
network_type = forms.ChoiceField(
|
||||||
|
label=_("Provider Network Type"),
|
||||||
|
help_text=_("The physical mechanism by which the virtual "
|
||||||
|
"network is implemented."),
|
||||||
|
widget=forms.Select(attrs={
|
||||||
|
'class': 'switchable',
|
||||||
|
'data-slug': 'network_type'
|
||||||
|
}))
|
||||||
|
physical_network = forms.CharField(
|
||||||
|
max_length="255",
|
||||||
|
label=_("Physical Network"),
|
||||||
|
help_text=_("The name of the physical network over which the "
|
||||||
|
"virtual network is implemented."),
|
||||||
|
initial='default',
|
||||||
|
widget=forms.TextInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'network_type',
|
||||||
|
'data-network_type-flat': _('Physical Network'),
|
||||||
|
'data-network_type-vlan': _('Physical Network')
|
||||||
|
}))
|
||||||
|
segmentation_id = forms.IntegerField(
|
||||||
|
label=_("Segmentation ID"),
|
||||||
|
widget=forms.TextInput(attrs={
|
||||||
|
'class': 'switched',
|
||||||
|
'data-switch-on': 'network_type',
|
||||||
|
'data-network_type-vlan': _('Segmentation ID'),
|
||||||
|
'data-network_type-gre': _('Segmentation ID'),
|
||||||
|
'data-network_type-vxlan': _('Segmentation ID')
|
||||||
|
}))
|
||||||
admin_state = forms.BooleanField(label=_("Admin State"),
|
admin_state = forms.BooleanField(label=_("Admin State"),
|
||||||
initial=True, required=False)
|
initial=True, required=False)
|
||||||
shared = forms.BooleanField(label=_("Shared"),
|
shared = forms.BooleanField(label=_("Shared"),
|
||||||
|
@ -63,6 +97,46 @@ class CreateNetwork(forms.SelfHandlingForm):
|
||||||
self.fields['net_profile_id'].choices = (
|
self.fields['net_profile_id'].choices = (
|
||||||
self.get_network_profile_choices(request))
|
self.get_network_profile_choices(request))
|
||||||
|
|
||||||
|
if api.neutron.is_extension_supported(request, 'provider'):
|
||||||
|
neutron_settings = getattr(settings,
|
||||||
|
'OPENSTACK_NEUTRON_NETWORK', {})
|
||||||
|
seg_id_range = neutron_settings.get('segmentation_id_range', {})
|
||||||
|
self.seg_id_range = {
|
||||||
|
'vlan': seg_id_range.get('vlan',
|
||||||
|
SEGMENTATION_ID_RANGE.get('vlan')),
|
||||||
|
'gre': seg_id_range.get('gre',
|
||||||
|
SEGMENTATION_ID_RANGE.get('gre')),
|
||||||
|
'vxlan': seg_id_range.get('vxlan',
|
||||||
|
SEGMENTATION_ID_RANGE.get('vxlan'))
|
||||||
|
}
|
||||||
|
seg_id_help = (_("For VLAN networks, the VLAN VID on the physical "
|
||||||
|
"network that realizes the virtual network. Valid VLAN VIDs "
|
||||||
|
"are %(vlan_min)s through %(vlan_max)s. For GRE or VXLAN "
|
||||||
|
"networks, the tunnel ID. Valid tunnel IDs for GRE networks "
|
||||||
|
"are %(gre_min)s through %(gre_max)s. For VXLAN networks, "
|
||||||
|
"%(vxlan_min)s through %(vxlan_max)s.") % {
|
||||||
|
'vlan_min': self.seg_id_range['vlan'][0],
|
||||||
|
'vlan_max': self.seg_id_range['vlan'][1],
|
||||||
|
'gre_min': self.seg_id_range['gre'][0],
|
||||||
|
'gre_max': self.seg_id_range['gre'][1],
|
||||||
|
'vxlan_min': self.seg_id_range['vxlan'][0],
|
||||||
|
'vxlan_max': self.seg_id_range['vxlan'][1]})
|
||||||
|
self.fields['segmentation_id'].help_text = seg_id_help
|
||||||
|
|
||||||
|
supported_provider_types = neutron_settings.get(
|
||||||
|
'supported_provider_types', ['*'])
|
||||||
|
if supported_provider_types == ['*']:
|
||||||
|
network_type_choices = PROVIDER_TYPES
|
||||||
|
else:
|
||||||
|
network_type_choices = [net_type for net_type in
|
||||||
|
PROVIDER_TYPES if net_type[0] in supported_provider_types]
|
||||||
|
if len(network_type_choices) == 0:
|
||||||
|
self._hide_provider_network_type()
|
||||||
|
else:
|
||||||
|
self.fields['network_type'].choices = network_type_choices
|
||||||
|
else:
|
||||||
|
self._hide_provider_network_type()
|
||||||
|
|
||||||
def get_network_profile_choices(self, request):
|
def get_network_profile_choices(self, request):
|
||||||
profile_choices = [('', _("Select a profile"))]
|
profile_choices = [('', _("Select a profile"))]
|
||||||
for profile in self._get_profiles(request, 'network'):
|
for profile in self._get_profiles(request, 'network'):
|
||||||
|
@ -78,6 +152,14 @@ class CreateNetwork(forms.SelfHandlingForm):
|
||||||
exceptions.handle(request, msg)
|
exceptions.handle(request, msg)
|
||||||
return profiles
|
return profiles
|
||||||
|
|
||||||
|
def _hide_provider_network_type(self):
|
||||||
|
self.fields['network_type'].widget = forms.HiddenInput()
|
||||||
|
self.fields['physical_network'].widget = forms.HiddenInput()
|
||||||
|
self.fields['segmentation_id'].widget = forms.HiddenInput()
|
||||||
|
self.fields['network_type'].required = False
|
||||||
|
self.fields['physical_network'].required = False
|
||||||
|
self.fields['segmentation_id'].required = False
|
||||||
|
|
||||||
def handle(self, request, data):
|
def handle(self, request, data):
|
||||||
try:
|
try:
|
||||||
params = {'name': data['name'],
|
params = {'name': data['name'],
|
||||||
|
@ -87,6 +169,15 @@ class CreateNetwork(forms.SelfHandlingForm):
|
||||||
'router:external': data['external']}
|
'router:external': data['external']}
|
||||||
if api.neutron.is_port_profiles_supported():
|
if api.neutron.is_port_profiles_supported():
|
||||||
params['net_profile_id'] = data['net_profile_id']
|
params['net_profile_id'] = data['net_profile_id']
|
||||||
|
if api.neutron.is_extension_supported(request, 'provider'):
|
||||||
|
network_type = data['network_type']
|
||||||
|
params['provider:network_type'] = network_type
|
||||||
|
if network_type in ['flat', 'vlan']:
|
||||||
|
params['provider:physical_network'] = (
|
||||||
|
data['physical_network'])
|
||||||
|
if network_type in ['vlan', 'gre', 'vxlan']:
|
||||||
|
params['provider:segmentation_id'] = (
|
||||||
|
data['segmentation_id'])
|
||||||
network = api.neutron.network_create(request, **params)
|
network = api.neutron.network_create(request, **params)
|
||||||
msg = _('Network %s was successfully created.') % data['name']
|
msg = _('Network %s was successfully created.') % data['name']
|
||||||
LOG.debug(msg)
|
LOG.debug(msg)
|
||||||
|
@ -97,6 +188,43 @@ class CreateNetwork(forms.SelfHandlingForm):
|
||||||
msg = _('Failed to create network %s') % data['name']
|
msg = _('Failed to create network %s') % data['name']
|
||||||
exceptions.handle(request, msg, redirect=redirect)
|
exceptions.handle(request, msg, redirect=redirect)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
cleaned_data = super(CreateNetwork, self).clean()
|
||||||
|
self._clean_physical_network(cleaned_data)
|
||||||
|
self._clean_segmentation_id(cleaned_data)
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
def _clean_physical_network(self, data):
|
||||||
|
network_type = data.get('network_type')
|
||||||
|
if 'physical_network' in self._errors and (
|
||||||
|
network_type in ['local', 'gre']):
|
||||||
|
# In this case the physical network is not required, so we can
|
||||||
|
# ignore any errors.
|
||||||
|
del self._errors['physical_network']
|
||||||
|
|
||||||
|
def _clean_segmentation_id(self, data):
|
||||||
|
network_type = data.get('network_type')
|
||||||
|
if 'segmentation_id' in self._errors:
|
||||||
|
if network_type in ['local', 'flat']:
|
||||||
|
# In this case the segmentation ID is not required, so we can
|
||||||
|
# ignore any errors.
|
||||||
|
del self._errors['segmentation_id']
|
||||||
|
elif network_type in ['vlan', 'gre', 'vxlan']:
|
||||||
|
seg_id = data.get('segmentation_id')
|
||||||
|
seg_id_range = {'min': self.seg_id_range[network_type][0],
|
||||||
|
'max': self.seg_id_range[network_type][1]}
|
||||||
|
if seg_id < seg_id_range['min'] or seg_id > seg_id_range['max']:
|
||||||
|
if network_type == 'vlan':
|
||||||
|
msg = _('For VLAN networks, valid VLAN IDs are %(min)s '
|
||||||
|
'through %(max)s.') % seg_id_range
|
||||||
|
elif network_type == 'gre':
|
||||||
|
msg = _('For GRE networks, valid tunnel IDs are %(min)s '
|
||||||
|
'through %(max)s.') % seg_id_range
|
||||||
|
elif network_type == 'vxlan':
|
||||||
|
msg = _('For VXLAN networks, valid tunnel IDs are %(min)s '
|
||||||
|
'through %(max)s.') % seg_id_range
|
||||||
|
self._errors['segmentation_id'] = self.error_class([msg])
|
||||||
|
|
||||||
|
|
||||||
class UpdateNetwork(forms.SelfHandlingForm):
|
class UpdateNetwork(forms.SelfHandlingForm):
|
||||||
name = forms.CharField(label=_("Name"), required=False)
|
name = forms.CharField(label=_("Name"), required=False)
|
||||||
|
|
|
@ -241,17 +241,21 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||||
self.assertItemsEqual(subnets, [self.subnets.first()])
|
self.assertItemsEqual(subnets, [self.subnets.first()])
|
||||||
self.assertEqual(len(ports), 0)
|
self.assertEqual(len(ports), 0)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('profile_list',),
|
@test.create_stubs({api.neutron: ('profile_list',
|
||||||
|
'list_extensions',),
|
||||||
api.keystone: ('tenant_list',)})
|
api.keystone: ('tenant_list',)})
|
||||||
def test_network_create_get(self,
|
def test_network_create_get(self,
|
||||||
test_with_profile=False):
|
test_with_profile=False):
|
||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
|
extensions = self.api_extensions.list()
|
||||||
api.keystone.tenant_list(IsA(
|
api.keystone.tenant_list(IsA(
|
||||||
http.HttpRequest)).AndReturn([tenants, False])
|
http.HttpRequest)).AndReturn([tenants, False])
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
net_profiles = self.net_profiles.list()
|
net_profiles = self.net_profiles.list()
|
||||||
api.neutron.profile_list(IsA(http.HttpRequest),
|
api.neutron.profile_list(IsA(http.HttpRequest),
|
||||||
'network').AndReturn(net_profiles)
|
'network').AndReturn(net_profiles)
|
||||||
|
api.neutron.list_extensions(
|
||||||
|
IsA(http.HttpRequest)).AndReturn(extensions)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
url = reverse('horizon:admin:networks:create')
|
url = reverse('horizon:admin:networks:create')
|
||||||
|
@ -264,26 +268,31 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||||
self.test_network_create_get(test_with_profile=True)
|
self.test_network_create_get(test_with_profile=True)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_create',
|
@test.create_stubs({api.neutron: ('network_create',
|
||||||
'profile_list',),
|
'profile_list',
|
||||||
|
'list_extensions',),
|
||||||
api.keystone: ('tenant_list',)})
|
api.keystone: ('tenant_list',)})
|
||||||
def test_network_create_post(self,
|
def test_network_create_post(self,
|
||||||
test_with_profile=False):
|
test_with_profile=False):
|
||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
tenant_id = self.tenants.first().id
|
tenant_id = self.tenants.first().id
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
|
extensions = self.api_extensions.list()
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn([tenants, False])
|
.AndReturn([tenants, False])
|
||||||
params = {'name': network.name,
|
params = {'name': network.name,
|
||||||
'tenant_id': tenant_id,
|
'tenant_id': tenant_id,
|
||||||
'admin_state_up': network.admin_state_up,
|
'admin_state_up': network.admin_state_up,
|
||||||
'router:external': True,
|
'router:external': True,
|
||||||
'shared': True}
|
'shared': True,
|
||||||
|
'provider:network_type': 'local'}
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
net_profiles = self.net_profiles.list()
|
net_profiles = self.net_profiles.list()
|
||||||
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)
|
||||||
params['net_profile_id'] = net_profile_id
|
params['net_profile_id'] = net_profile_id
|
||||||
|
api.neutron.list_extensions(
|
||||||
|
IsA(http.HttpRequest)).AndReturn(extensions)
|
||||||
api.neutron.network_create(IsA(http.HttpRequest), **params)\
|
api.neutron.network_create(IsA(http.HttpRequest), **params)\
|
||||||
.AndReturn(network)
|
.AndReturn(network)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
@ -292,7 +301,8 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||||
'name': network.name,
|
'name': network.name,
|
||||||
'admin_state': network.admin_state_up,
|
'admin_state': network.admin_state_up,
|
||||||
'external': True,
|
'external': True,
|
||||||
'shared': True}
|
'shared': True,
|
||||||
|
'network_type': 'local'}
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
form_data['net_profile_id'] = net_profile_id
|
form_data['net_profile_id'] = net_profile_id
|
||||||
url = reverse('horizon:admin:networks:create')
|
url = reverse('horizon:admin:networks:create')
|
||||||
|
@ -306,35 +316,41 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||||
self.test_network_create_post(test_with_profile=True)
|
self.test_network_create_post(test_with_profile=True)
|
||||||
|
|
||||||
@test.create_stubs({api.neutron: ('network_create',
|
@test.create_stubs({api.neutron: ('network_create',
|
||||||
'profile_list',),
|
'profile_list',
|
||||||
|
'list_extensions',),
|
||||||
api.keystone: ('tenant_list',)})
|
api.keystone: ('tenant_list',)})
|
||||||
def test_network_create_post_network_exception(self,
|
def test_network_create_post_network_exception(self,
|
||||||
test_with_profile=False):
|
test_with_profile=False):
|
||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
tenant_id = self.tenants.first().id
|
tenant_id = self.tenants.first().id
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
extensions = self.api_extensions.list()
|
||||||
.AndReturn([tenants, False])
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([tenants,
|
||||||
|
False])
|
||||||
params = {'name': network.name,
|
params = {'name': network.name,
|
||||||
'tenant_id': tenant_id,
|
'tenant_id': tenant_id,
|
||||||
'admin_state_up': network.admin_state_up,
|
'admin_state_up': network.admin_state_up,
|
||||||
'router:external': True,
|
'router:external': True,
|
||||||
'shared': False}
|
'shared': False,
|
||||||
|
'provider:network_type': 'local'}
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
net_profiles = self.net_profiles.list()
|
net_profiles = self.net_profiles.list()
|
||||||
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)
|
||||||
params['net_profile_id'] = net_profile_id
|
params['net_profile_id'] = net_profile_id
|
||||||
api.neutron.network_create(IsA(http.HttpRequest), **params)\
|
api.neutron.list_extensions(
|
||||||
.AndRaise(self.exceptions.neutron)
|
IsA(http.HttpRequest)).AndReturn(extensions)
|
||||||
|
api.neutron.network_create(IsA(http.HttpRequest),
|
||||||
|
**params).AndRaise(self.exceptions.neutron)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
form_data = {'tenant_id': tenant_id,
|
form_data = {'tenant_id': tenant_id,
|
||||||
'name': network.name,
|
'name': network.name,
|
||||||
'admin_state': network.admin_state_up,
|
'admin_state': network.admin_state_up,
|
||||||
'external': True,
|
'external': True,
|
||||||
'shared': False}
|
'shared': False,
|
||||||
|
'network_type': 'local'}
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
form_data['net_profile_id'] = net_profile_id
|
form_data['net_profile_id'] = net_profile_id
|
||||||
url = reverse('horizon:admin:networks:create')
|
url = reverse('horizon:admin:networks:create')
|
||||||
|
@ -348,6 +364,131 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||||
self.test_network_create_post_network_exception(
|
self.test_network_create_post_network_exception(
|
||||||
test_with_profile=True)
|
test_with_profile=True)
|
||||||
|
|
||||||
|
@test.create_stubs({api.neutron: ('list_extensions',),
|
||||||
|
api.keystone: ('tenant_list',)})
|
||||||
|
def test_network_create_vlan_segmentation_id_invalid(self):
|
||||||
|
tenants = self.tenants.list()
|
||||||
|
tenant_id = self.tenants.first().id
|
||||||
|
network = self.networks.first()
|
||||||
|
extensions = self.api_extensions.list()
|
||||||
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([tenants,
|
||||||
|
False])
|
||||||
|
api.neutron.list_extensions(
|
||||||
|
IsA(http.HttpRequest)).AndReturn(extensions)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {'tenant_id': tenant_id,
|
||||||
|
'name': network.name,
|
||||||
|
'admin_state': network.admin_state_up,
|
||||||
|
'external': True,
|
||||||
|
'shared': False,
|
||||||
|
'network_type': 'vlan',
|
||||||
|
'physical_network': 'default',
|
||||||
|
'segmentation_id': 4095}
|
||||||
|
url = reverse('horizon:admin:networks:create')
|
||||||
|
res = self.client.post(url, form_data)
|
||||||
|
|
||||||
|
self.assertFormErrors(res, 1)
|
||||||
|
self.assertContains(res, "1 through 4094")
|
||||||
|
|
||||||
|
@test.create_stubs({api.neutron: ('list_extensions',),
|
||||||
|
api.keystone: ('tenant_list',)})
|
||||||
|
def test_network_create_gre_segmentation_id_invalid(self):
|
||||||
|
tenants = self.tenants.list()
|
||||||
|
tenant_id = self.tenants.first().id
|
||||||
|
network = self.networks.first()
|
||||||
|
extensions = self.api_extensions.list()
|
||||||
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([tenants,
|
||||||
|
False])
|
||||||
|
api.neutron.list_extensions(
|
||||||
|
IsA(http.HttpRequest)).AndReturn(extensions)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {'tenant_id': tenant_id,
|
||||||
|
'name': network.name,
|
||||||
|
'admin_state': network.admin_state_up,
|
||||||
|
'external': True,
|
||||||
|
'shared': False,
|
||||||
|
'network_type': 'gre',
|
||||||
|
'physical_network': 'default',
|
||||||
|
'segmentation_id': (2 ** 32) + 1}
|
||||||
|
url = reverse('horizon:admin:networks:create')
|
||||||
|
res = self.client.post(url, form_data)
|
||||||
|
|
||||||
|
self.assertFormErrors(res, 1)
|
||||||
|
self.assertContains(res, "0 through %s" % ((2 ** 32) - 1))
|
||||||
|
|
||||||
|
@test.create_stubs({api.neutron: ('list_extensions',),
|
||||||
|
api.keystone: ('tenant_list',)})
|
||||||
|
@override_settings(OPENSTACK_NEUTRON_NETWORK={
|
||||||
|
'segmentation_id_range': {'vxlan': [10, 20]}})
|
||||||
|
def test_network_create_vxlan_segmentation_id_custom(self):
|
||||||
|
tenants = self.tenants.list()
|
||||||
|
tenant_id = self.tenants.first().id
|
||||||
|
network = self.networks.first()
|
||||||
|
extensions = self.api_extensions.list()
|
||||||
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([tenants,
|
||||||
|
False])
|
||||||
|
api.neutron.list_extensions(
|
||||||
|
IsA(http.HttpRequest)).AndReturn(extensions)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
form_data = {'tenant_id': tenant_id,
|
||||||
|
'name': network.name,
|
||||||
|
'admin_state': network.admin_state_up,
|
||||||
|
'external': True,
|
||||||
|
'shared': False,
|
||||||
|
'network_type': 'vxlan',
|
||||||
|
'physical_network': 'default',
|
||||||
|
'segmentation_id': 9}
|
||||||
|
url = reverse('horizon:admin:networks:create')
|
||||||
|
res = self.client.post(url, form_data)
|
||||||
|
|
||||||
|
self.assertFormErrors(res, 1)
|
||||||
|
self.assertContains(res, "10 through 20")
|
||||||
|
|
||||||
|
@test.create_stubs({api.neutron: ('list_extensions',),
|
||||||
|
api.keystone: ('tenant_list',)})
|
||||||
|
@override_settings(OPENSTACK_NEUTRON_NETWORK={
|
||||||
|
'supported_provider_types': []})
|
||||||
|
def test_network_create_no_provider_types(self):
|
||||||
|
tenants = self.tenants.list()
|
||||||
|
extensions = self.api_extensions.list()
|
||||||
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([tenants,
|
||||||
|
False])
|
||||||
|
api.neutron.list_extensions(
|
||||||
|
IsA(http.HttpRequest)).AndReturn(extensions)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
url = reverse('horizon:admin:networks:create')
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertTemplateUsed(res, 'admin/networks/create.html')
|
||||||
|
self.assertContains(res, '<input type="hidden" name="network_type" '
|
||||||
|
'id="id_network_type" />', html=True)
|
||||||
|
|
||||||
|
@test.create_stubs({api.neutron: ('list_extensions',),
|
||||||
|
api.keystone: ('tenant_list',)})
|
||||||
|
@override_settings(OPENSTACK_NEUTRON_NETWORK={
|
||||||
|
'supported_provider_types': ['local', 'flat', 'gre']})
|
||||||
|
def test_network_create_unsupported_provider_types(self):
|
||||||
|
tenants = self.tenants.list()
|
||||||
|
extensions = self.api_extensions.list()
|
||||||
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn([tenants,
|
||||||
|
False])
|
||||||
|
api.neutron.list_extensions(
|
||||||
|
IsA(http.HttpRequest)).AndReturn(extensions)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
url = reverse('horizon:admin:networks:create')
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
self.assertTemplateUsed(res, 'admin/networks/create.html')
|
||||||
|
network_type = res.context['form'].fields['network_type']
|
||||||
|
self.assertListEqual(list(network_type.choices), [('local', 'Local'),
|
||||||
|
('flat', 'Flat'),
|
||||||
|
('gre', 'GRE')])
|
||||||
|
|
||||||
@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()
|
||||||
|
|
|
@ -187,6 +187,10 @@ OPENSTACK_NEUTRON_NETWORK = {
|
||||||
# profile_support can be turned on if needed.
|
# profile_support can be turned on if needed.
|
||||||
'profile_support': None,
|
'profile_support': None,
|
||||||
#'profile_support': 'cisco',
|
#'profile_support': 'cisco',
|
||||||
|
# Set which provider network types are supported. Only the network types
|
||||||
|
# in this list will be available to choose from when creating a network.
|
||||||
|
# Network types include local, flat, vlan, gre, and vxlan.
|
||||||
|
'supported_provider_types': ['*'],
|
||||||
}
|
}
|
||||||
|
|
||||||
# The OPENSTACK_IMAGE_BACKEND settings can be used to customize features
|
# The OPENSTACK_IMAGE_BACKEND settings can be used to customize features
|
||||||
|
|
|
@ -563,8 +563,12 @@ def data(TEST):
|
||||||
extension_2 = {"name": "Quota management support",
|
extension_2 = {"name": "Quota management support",
|
||||||
"alias": "quotas",
|
"alias": "quotas",
|
||||||
"description": "Expose functions for quotas management"}
|
"description": "Expose functions for quotas management"}
|
||||||
|
extension_3 = {"name": "Provider network",
|
||||||
|
"alias": "provider",
|
||||||
|
"description": "Provider network extension"}
|
||||||
TEST.api_extensions.add(extension_1)
|
TEST.api_extensions.add(extension_1)
|
||||||
TEST.api_extensions.add(extension_2)
|
TEST.api_extensions.add(extension_2)
|
||||||
|
TEST.api_extensions.add(extension_3)
|
||||||
|
|
||||||
# 1st agent.
|
# 1st agent.
|
||||||
agent_dict = {"binary": "neutron-openvswitch-agent",
|
agent_dict = {"binary": "neutron-openvswitch-agent",
|
||||||
|
|
Loading…
Reference in New Issue