Add a parameter fixed ip when creating a port
When we create a port, we can specify fixed ip in CLI. However, we cannot do it in Horizon. This patch will support this param. Change-Id: I3b2fa8609ec27edcb8d3ecc400b93ea7870a48a1 Closes-Bug: #1588663
This commit is contained in:
parent
09b745a4bb
commit
5894e159cf
@ -59,11 +59,51 @@ class CreatePort(forms.SelfHandlingForm):
|
||||
"cases, different implementations can run on different "
|
||||
"hosts."),
|
||||
required=False)
|
||||
|
||||
specify_ip = forms.ThemableChoiceField(
|
||||
label=_("Specify IP address or subnet"),
|
||||
help_text=_("To specify a subnet or a fixed IP, select any options."),
|
||||
initial=False,
|
||||
required=False,
|
||||
choices=[('', _("Unspecified")),
|
||||
('subnet_id', _("Subnet")),
|
||||
('fixed_ip', _("Fixed IP Address"))],
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switchable',
|
||||
'data-slug': 'specify_ip',
|
||||
}))
|
||||
subnet_id = forms.ThemableChoiceField(
|
||||
label=_("Subnet"),
|
||||
required=False,
|
||||
widget=forms.Select(attrs={
|
||||
'class': 'switched',
|
||||
'data-switch-on': 'specify_ip',
|
||||
'data-specify_ip-subnet_id': _('Subnet'),
|
||||
}))
|
||||
fixed_ip = forms.IPField(
|
||||
label=_("Fixed IP Address"),
|
||||
required=False,
|
||||
help_text=_("Specify the subnet IP address for the new port"),
|
||||
version=forms.IPv4 | forms.IPv6,
|
||||
widget=forms.TextInput(attrs={
|
||||
'class': 'switched',
|
||||
'data-switch-on': 'specify_ip',
|
||||
'data-specify_ip-fixed_ip': _('Fixed IP Address'),
|
||||
}))
|
||||
failure_url = 'horizon:admin:networks:detail'
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(CreatePort, self).__init__(request, *args, **kwargs)
|
||||
|
||||
# prepare subnet choices and input area for each subnet
|
||||
subnet_choices = self._get_subnet_choices(kwargs['initial'])
|
||||
if subnet_choices:
|
||||
subnet_choices.insert(0, ('', _("Select a subnet")))
|
||||
self.fields['subnet_id'].choices = subnet_choices
|
||||
else:
|
||||
self.fields['specify_ip'].widget = forms.HiddenInput()
|
||||
self.fields['subnet_id'].widget = forms.HiddenInput()
|
||||
self.fields['fixed_ip'].widget = forms.HiddenInput()
|
||||
|
||||
try:
|
||||
if api.neutron.is_extension_supported(request, 'binding'):
|
||||
neutron_settings = getattr(settings,
|
||||
@ -100,20 +140,45 @@ class CreatePort(forms.SelfHandlingForm):
|
||||
msg = _("Unable to retrieve MAC learning state")
|
||||
exceptions.handle(self.request, msg)
|
||||
|
||||
def _get_subnet_choices(self, kwargs):
|
||||
try:
|
||||
network_id = kwargs['network_id']
|
||||
network = api.neutron.network_get(self.request, network_id)
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
return [(subnet.id, '%s %s' % (subnet.name_or_id, subnet.cidr))
|
||||
for subnet in network.subnets]
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
# We must specify tenant_id of the network which a subnet is
|
||||
# created for if admin user does not belong to the tenant.
|
||||
network = api.neutron.network_get(request, data['network_id'])
|
||||
data['tenant_id'] = network.tenant_id
|
||||
data['admin_state_up'] = (data['admin_state'] == 'True')
|
||||
del data['network_name']
|
||||
del data['admin_state']
|
||||
if 'mac_state' in data:
|
||||
data['mac_learning_enabled'] = data['mac_state']
|
||||
del data['mac_state']
|
||||
params = {
|
||||
'tenant_id': network.tenant_id,
|
||||
'network_id': data['network_id'],
|
||||
'admin_state_up': data['admin_state'] == 'True',
|
||||
'name': data['name'],
|
||||
'device_id': data['device_id'],
|
||||
'device_owner': data['device_owner'],
|
||||
'binding__host_id': data['binding__host_id']
|
||||
}
|
||||
|
||||
port = api.neutron.port_create(request, **data)
|
||||
if data.get('specify_ip') == 'subnet_id':
|
||||
if data.get('subnet_id'):
|
||||
params['fixed_ips'] = [{"subnet_id": data['subnet_id']}]
|
||||
elif data.get('specify_ip') == 'fixed_ip':
|
||||
if data.get('fixed_ip'):
|
||||
params['fixed_ips'] = [{"ip_address": data['fixed_ip']}]
|
||||
|
||||
if data.get('binding__vnic_type'):
|
||||
params['binding__vnic_type'] = data['binding__vnic_type']
|
||||
|
||||
if data.get('mac_state'):
|
||||
params['mac_learning_enabled'] = data['mac_state']
|
||||
|
||||
port = api.neutron.port_create(request, **params)
|
||||
msg = _('Port %s was successfully created.') % port['id']
|
||||
LOG.debug(msg)
|
||||
messages.success(request, msg)
|
||||
|
@ -124,6 +124,9 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id)\
|
||||
.AndReturn(self.networks.first())
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id)\
|
||||
.AndReturn(self.networks.first())
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'binding')\
|
||||
.AndReturn(binding)
|
||||
@ -167,6 +170,63 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
||||
redir_url = reverse(NETWORKS_DETAIL_URL, args=[port.network_id])
|
||||
self.assertRedirectsNoFollow(res, redir_url)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'is_extension_supported',
|
||||
'port_create',)})
|
||||
def test_port_create_post_with_fixed_ip(self):
|
||||
network = self.networks.first()
|
||||
port = self.ports.first()
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id)\
|
||||
.AndReturn(self.networks.first())
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id)\
|
||||
.AndReturn(self.networks.first())
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id)\
|
||||
.AndReturn(self.networks.first())
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'binding')\
|
||||
.AndReturn(True)
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'mac-learning')\
|
||||
.AndReturn(True)
|
||||
extension_kwargs = {}
|
||||
extension_kwargs['binding__vnic_type'] = \
|
||||
port.binding__vnic_type
|
||||
api.neutron.port_create(IsA(http.HttpRequest),
|
||||
tenant_id=network.tenant_id,
|
||||
network_id=network.id,
|
||||
name=port.name,
|
||||
admin_state_up=port.admin_state_up,
|
||||
device_id=port.device_id,
|
||||
device_owner=port.device_owner,
|
||||
binding__host_id=port.binding__host_id,
|
||||
fixed_ips=port.fixed_ips,
|
||||
**extension_kwargs)\
|
||||
.AndReturn(port)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {'network_id': port.network_id,
|
||||
'network_name': network.name,
|
||||
'name': port.name,
|
||||
'admin_state': port.admin_state_up,
|
||||
'device_id': port.device_id,
|
||||
'device_owner': port.device_owner,
|
||||
'binding__host_id': port.binding__host_id,
|
||||
'specify_ip': 'fixed_ip',
|
||||
'fixed_ip': port.fixed_ips[0]['ip_address'],
|
||||
'subnet_id': port.fixed_ips[0]['subnet_id']}
|
||||
form_data['binding__vnic_type'] = port.binding__vnic_type
|
||||
form_data['mac_state'] = True
|
||||
url = reverse('horizon:admin:networks:addport',
|
||||
args=[port.network_id])
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
redir_url = reverse(NETWORKS_DETAIL_URL, args=[port.network_id])
|
||||
self.assertRedirectsNoFollow(res, redir_url)
|
||||
|
||||
@test.create_stubs({api.neutron: ('network_get',
|
||||
'port_create',
|
||||
'is_extension_supported',)})
|
||||
@ -189,6 +249,9 @@ class NetworkPortTests(test.BaseAdminViewTests):
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id)\
|
||||
.AndReturn(self.networks.first())
|
||||
api.neutron.network_get(IsA(http.HttpRequest),
|
||||
network.id)\
|
||||
.AndReturn(self.networks.first())
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
'binding')\
|
||||
.AndReturn(binding)
|
||||
|
4
releasenotes/notes/bug-1588663-6fab83e9d89b20d2.yaml
Normal file
4
releasenotes/notes/bug-1588663-6fab83e9d89b20d2.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Support a parameter to specify subnet or fixed IP address
|
||||
when creating port.
|
Loading…
Reference in New Issue
Block a user