Merge "Use instance hostname for Neutron DNS"
This commit is contained in:
commit
12d224e7df
@ -843,6 +843,12 @@ class PortNotUsable(Invalid):
|
|||||||
msg_fmt = _("Port %(port_id)s not usable for instance %(instance)s.")
|
msg_fmt = _("Port %(port_id)s not usable for instance %(instance)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class PortNotUsableDNS(Invalid):
|
||||||
|
msg_fmt = _("Port %(port_id)s not usable for instance %(instance)s. "
|
||||||
|
"Value %(value)s assigned to dns_name attribute does not "
|
||||||
|
"match instance's hostname %(hostname)s")
|
||||||
|
|
||||||
|
|
||||||
class PortNotFree(Invalid):
|
class PortNotFree(Invalid):
|
||||||
msg_fmt = _("No free port available for instance %(instance)s.")
|
msg_fmt = _("No free port available for instance %(instance)s.")
|
||||||
|
|
||||||
|
@ -378,6 +378,8 @@ class API(base_api.NetworkAPI):
|
|||||||
port's MAC address is not in that set.
|
port's MAC address is not in that set.
|
||||||
:raises nova.exception.PortInUse: If a requested port is already
|
:raises nova.exception.PortInUse: If a requested port is already
|
||||||
attached to another instance.
|
attached to another instance.
|
||||||
|
:raises nova.exception.PortNotUsableDNS: If a requested port has a
|
||||||
|
value assigned to its dns_name attribute.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
available_macs = None
|
available_macs = None
|
||||||
@ -408,6 +410,15 @@ class API(base_api.NetworkAPI):
|
|||||||
if port.get('device_id'):
|
if port.get('device_id'):
|
||||||
raise exception.PortInUse(port_id=request.port_id)
|
raise exception.PortInUse(port_id=request.port_id)
|
||||||
|
|
||||||
|
# Make sure the user didn't assign a value to the port's
|
||||||
|
# dns_name attribute.
|
||||||
|
if port.get('dns_name'):
|
||||||
|
if port['dns_name'] != instance.hostname:
|
||||||
|
raise exception.PortNotUsableDNS(
|
||||||
|
port_id=request.port_id,
|
||||||
|
instance=instance.uuid, value=port['dns_name'],
|
||||||
|
hostname=instance.hostname)
|
||||||
|
|
||||||
# Make sure the port is usable
|
# Make sure the port is usable
|
||||||
if (port.get('binding:vif_type') ==
|
if (port.get('binding:vif_type') ==
|
||||||
network_model.VIF_TYPE_BINDING_FAILED):
|
network_model.VIF_TYPE_BINDING_FAILED):
|
||||||
@ -626,7 +637,8 @@ class API(base_api.NetworkAPI):
|
|||||||
try:
|
try:
|
||||||
self._populate_neutron_extension_values(
|
self._populate_neutron_extension_values(
|
||||||
context, instance, request.pci_request_id, port_req_body,
|
context, instance, request.pci_request_id, port_req_body,
|
||||||
neutron=neutron, bind_host_id=bind_host_id)
|
network=network, neutron=neutron,
|
||||||
|
bind_host_id=bind_host_id)
|
||||||
if request.port_id:
|
if request.port_id:
|
||||||
port = ports[request.port_id]
|
port = ports[request.port_id]
|
||||||
port_client.update_port(port['id'], port_req_body)
|
port_client.update_port(port['id'], port_req_body)
|
||||||
@ -639,6 +651,9 @@ class API(base_api.NetworkAPI):
|
|||||||
security_group_ids, available_macs, dhcp_opts)
|
security_group_ids, available_macs, dhcp_opts)
|
||||||
created_port_ids.append(created_port)
|
created_port_ids.append(created_port)
|
||||||
ports_in_requested_order.append(created_port)
|
ports_in_requested_order.append(created_port)
|
||||||
|
self._update_port_dns_name(context, instance, network,
|
||||||
|
ports_in_requested_order[-1],
|
||||||
|
neutron)
|
||||||
except Exception:
|
except Exception:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self._unbind_ports(context,
|
self._unbind_ports(context,
|
||||||
@ -699,7 +714,8 @@ class API(base_api.NetworkAPI):
|
|||||||
|
|
||||||
def _populate_neutron_extension_values(self, context, instance,
|
def _populate_neutron_extension_values(self, context, instance,
|
||||||
pci_request_id, port_req_body,
|
pci_request_id, port_req_body,
|
||||||
neutron=None, bind_host_id=None):
|
network=None, neutron=None,
|
||||||
|
bind_host_id=None):
|
||||||
"""Populate neutron extension values for the instance.
|
"""Populate neutron extension values for the instance.
|
||||||
|
|
||||||
If the extensions loaded contain QOS_QUEUE then pass the rxtx_factor.
|
If the extensions loaded contain QOS_QUEUE then pass the rxtx_factor.
|
||||||
@ -709,11 +725,53 @@ class API(base_api.NetworkAPI):
|
|||||||
flavor = instance.get_flavor()
|
flavor = instance.get_flavor()
|
||||||
rxtx_factor = flavor.get('rxtx_factor')
|
rxtx_factor = flavor.get('rxtx_factor')
|
||||||
port_req_body['port']['rxtx_factor'] = rxtx_factor
|
port_req_body['port']['rxtx_factor'] = rxtx_factor
|
||||||
if self._has_port_binding_extension(context, neutron=neutron):
|
has_port_binding_extension = (
|
||||||
|
self._has_port_binding_extension(context, neutron=neutron))
|
||||||
|
if has_port_binding_extension:
|
||||||
port_req_body['port']['binding:host_id'] = bind_host_id
|
port_req_body['port']['binding:host_id'] = bind_host_id
|
||||||
self._populate_neutron_binding_profile(instance,
|
self._populate_neutron_binding_profile(instance,
|
||||||
pci_request_id,
|
pci_request_id,
|
||||||
port_req_body)
|
port_req_body)
|
||||||
|
if constants.DNS_INTEGRATION in self.extensions:
|
||||||
|
# If the DNS integration extension is enabled in Neutron, most
|
||||||
|
# ports will get their dns_name attribute set in the port create or
|
||||||
|
# update requests in allocate_for_instance. So we just add the
|
||||||
|
# dns_name attribute to the payload of those requests. The
|
||||||
|
# exception is when the port binding extension is enabled in
|
||||||
|
# Neutron and the port is on a network that has a non-blank
|
||||||
|
# dns_domain attribute. This case requires to be processed by
|
||||||
|
# method _update_port_dns_name
|
||||||
|
if (not has_port_binding_extension
|
||||||
|
or not network.get('dns_domain')):
|
||||||
|
port_req_body['port']['dns_name'] = instance.hostname
|
||||||
|
|
||||||
|
def _update_port_dns_name(self, context, instance, network, port_id,
|
||||||
|
neutron):
|
||||||
|
"""Update an instance port dns_name attribute with instance.hostname.
|
||||||
|
|
||||||
|
The dns_name attribute of a port on a network with a non-blank
|
||||||
|
dns_domain attribute will be sent to the external DNS service
|
||||||
|
(Designate) if DNS integration is enabled in Neutron. This requires the
|
||||||
|
assignment of the dns_name to the port to be done with a Neutron client
|
||||||
|
using the user's context. allocate_for_instance uses a port with admin
|
||||||
|
context if the port binding extensions is enabled in Neutron. In this
|
||||||
|
case, we assign in this method the dns_name attribute to the port with
|
||||||
|
an additional update request. Only a very small fraction of ports will
|
||||||
|
require this additional update request.
|
||||||
|
"""
|
||||||
|
if (constants.DNS_INTEGRATION in self.extensions and
|
||||||
|
self._has_port_binding_extension(context) and
|
||||||
|
network.get('dns_domain')):
|
||||||
|
try:
|
||||||
|
port_req_body = {'port': {'dns_name': instance.hostname}}
|
||||||
|
neutron.update_port(port_id, port_req_body)
|
||||||
|
except neutron_client_exc.BadRequest:
|
||||||
|
LOG.warning(_LW('Neutron error: Instance hostname '
|
||||||
|
'%(hostname)s is not a valid DNS name'),
|
||||||
|
{'hostname': instance.hostname}, instance=instance)
|
||||||
|
msg = (_('Instance hostname %(hostname)s is not a valid DNS '
|
||||||
|
'name') % {'hostname': instance.hostname})
|
||||||
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
|
||||||
def _delete_ports(self, neutron, instance, ports, raise_if_fail=False):
|
def _delete_ports(self, neutron, instance, ports, raise_if_fail=False):
|
||||||
exceptions = []
|
exceptions = []
|
||||||
|
@ -17,3 +17,4 @@ QOS_QUEUE = 'QoS Queue'
|
|||||||
NET_EXTERNAL = 'router:external'
|
NET_EXTERNAL = 'router:external'
|
||||||
PORTBINDING_EXT = 'Port Binding'
|
PORTBINDING_EXT = 'Port Binding'
|
||||||
VNIC_INDEX_EXT = 'VNIC Index'
|
VNIC_INDEX_EXT = 'VNIC Index'
|
||||||
|
DNS_INTEGRATION = 'DNS Integration'
|
||||||
|
@ -511,7 +511,8 @@ class TestNeutronv2Base(test.TestCase):
|
|||||||
if not has_portbinding:
|
if not has_portbinding:
|
||||||
api._populate_neutron_extension_values(mox.IgnoreArg(),
|
api._populate_neutron_extension_values(mox.IgnoreArg(),
|
||||||
self.instance, mox.IgnoreArg(),
|
self.instance, mox.IgnoreArg(),
|
||||||
mox.IgnoreArg(), neutron=self.moxed_client,
|
mox.IgnoreArg(), network=network,
|
||||||
|
neutron=self.moxed_client,
|
||||||
bind_host_id=None).AndReturn(None)
|
bind_host_id=None).AndReturn(None)
|
||||||
else:
|
else:
|
||||||
# since _populate_neutron_extension_values() will call
|
# since _populate_neutron_extension_values() will call
|
||||||
@ -1140,7 +1141,7 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||||||
port = {'id': 'portid_' + network['id']}
|
port = {'id': 'portid_' + network['id']}
|
||||||
|
|
||||||
api._populate_neutron_extension_values(self.context,
|
api._populate_neutron_extension_values(self.context,
|
||||||
self.instance, None, binding_port_req_body,
|
self.instance, None, binding_port_req_body, network=network,
|
||||||
neutron=self.moxed_client, bind_host_id=None).AndReturn(None)
|
neutron=self.moxed_client, bind_host_id=None).AndReturn(None)
|
||||||
if index == 0:
|
if index == 0:
|
||||||
self.moxed_client.create_port(
|
self.moxed_client.create_port(
|
||||||
@ -1195,7 +1196,8 @@ class TestNeutronv2(TestNeutronv2Base):
|
|||||||
}
|
}
|
||||||
api._populate_neutron_extension_values(self.context,
|
api._populate_neutron_extension_values(self.context,
|
||||||
self.instance, None, binding_port_req_body,
|
self.instance, None, binding_port_req_body,
|
||||||
neutron=self.moxed_client, bind_host_id=None).AndReturn(None)
|
network=self.nets2[0], neutron=self.moxed_client,
|
||||||
|
bind_host_id=None).AndReturn(None)
|
||||||
self.moxed_client.create_port(
|
self.moxed_client.create_port(
|
||||||
MyComparator(port_req_body)).AndRaise(
|
MyComparator(port_req_body)).AndRaise(
|
||||||
Exception("fail to create port"))
|
Exception("fail to create port"))
|
||||||
|
Loading…
Reference in New Issue
Block a user