Skip to content

Commit

Permalink
utils: Remove periods from instance hostnames
Browse files Browse the repository at this point in the history
When creating an instance, nova sanitizes the 'instance.name' attribute,
using the 'nova.utils.sanitize_hostname' function, and stores this as
the 'instance.hostname' attribute. If neutron has the DNS extension
enabled then this attribute will be reported as the 'dns_name' value
when attaching ports [1].

Nova does not currently remove or replace periods in the name as part of
this sanitization. This results in the hostname being identified as a
(FQDN) fully qualified domain name, with all the constraints placed on
FQDNs [2]. This can be problematic for instances with common names such
as 'ubuntu18.04' or 'test.a', which aren't valid since TLDs must start
with an alpha character and must be greater than 1 character long,
respectively. Attempting to boot instances with such names can result in
failures like the below when DNS integration is enabled in neutron:

  RescheduledException: Build of instance foo was re-scheduled:
  Invalid input for dns_name.
  Reason: 'test-ubuntu-20.04' not a valid PQDN or FQDN.
  Reason: TLD '04' must not be all numeric.

Start replacing these periods with hyphens. This is a change in behavior
and may affect users who are relying on this inadvertent support for
instance names as FQDNs when using cloud-init, however, a quick poll on
openstack-discuss [3] suggests the people that are using FQDN-like
instance names are setting hostnames in the guest explicitly and not
relying on the information provided via the nova metadata service,
meaning this will not affect them.

[1] https://docs.openstack.org/neutron/victoria/admin/config-dns-int.html
[2] https://stackoverflow.com/a/53875771/613428
[3] http://lists.openstack.org/pipermail/openstack-discuss/2020-November/019113.html

Change-Id: I2fac7f919e9ddd6b0925d3e5d04e61b2ba1b8c82
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
Closes-Bug: #1581977
  • Loading branch information
stephenfin committed Jan 14, 2021
1 parent e6f5e81 commit 9046f0f
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 18 deletions.
35 changes: 18 additions & 17 deletions nova/tests/unit/test_utils.py
Expand Up @@ -73,24 +73,25 @@ def test_parse_server_string(self):
self.assertEqual(('', ''), result)

def test_hostname_unicode_sanitization(self):
hostname = u"\u7684.test.example.com"
self.assertEqual("test.example.com",
utils.sanitize_hostname(hostname))
hostname = u'\u7684myamazinghostname'
self.assertEqual(
'myamazinghostname', utils.sanitize_hostname(hostname))

def test_hostname_sanitize_periods(self):
hostname = "....test.example.com..."
self.assertEqual("test.example.com",
utils.sanitize_hostname(hostname))
hostname = '....test.example.com...'
self.assertEqual(
'test-example-com', utils.sanitize_hostname(hostname))

def test_hostname_sanitize_dashes(self):
hostname = "----test.example.com---"
self.assertEqual("test.example.com",
utils.sanitize_hostname(hostname))
hostname = '----my-amazing-hostname---'
self.assertEqual(
"my-amazing-hostname", utils.sanitize_hostname(hostname))

def test_hostname_sanitize_characters(self):
hostname = "(#@&$!(@*--#&91)(__=+--test-host.example!!.com-0+"
self.assertEqual("91----test-host.example.com-0",
utils.sanitize_hostname(hostname))
self.assertEqual(
"91----test-host-example-com-0",
utils.sanitize_hostname(hostname))

def test_hostname_translate(self):
hostname = "<}\x1fh\x10e\x08l\x02l\x05o\x12!{>"
Expand All @@ -99,20 +100,20 @@ def test_hostname_translate(self):
def test_hostname_has_default(self):
hostname = u"\u7684hello"
defaultname = "Server-1"
self.assertEqual("hello", utils.sanitize_hostname(hostname,
defaultname))
self.assertEqual(
"hello", utils.sanitize_hostname(hostname, defaultname))

def test_hostname_empty_has_default(self):
hostname = u"\u7684"
defaultname = "Server-1"
self.assertEqual(defaultname, utils.sanitize_hostname(hostname,
defaultname))
self.assertEqual(
defaultname, utils.sanitize_hostname(hostname, defaultname))

def test_hostname_empty_has_default_too_long(self):
hostname = u"\u7684"
defaultname = "a" * 64
self.assertEqual("a" * 63, utils.sanitize_hostname(hostname,
defaultname))
self.assertEqual(
"a" * 63, utils.sanitize_hostname(hostname, defaultname))

def test_hostname_empty_no_default(self):
hostname = u"\u7684"
Expand Down
2 changes: 1 addition & 1 deletion nova/utils.py
Expand Up @@ -372,7 +372,7 @@ def truncate_hostname(name):
hostname = hostname.encode('latin-1', 'ignore').decode('latin-1')

hostname = truncate_hostname(hostname)
hostname = re.sub('[ _]', '-', hostname)
hostname = re.sub(r'[ _\.]', '-', hostname)
hostname = re.sub(r'[^\w.-]+', '', hostname)
hostname = hostname.lower()
hostname = hostname.strip('.-')
Expand Down
24 changes: 24 additions & 0 deletions releasenotes/notes/bug-1581977-310e5f218ccb1d16.yaml
@@ -0,0 +1,24 @@
---
fixes:
- |
Nova will now replace periods (``.``) with dashes (``-``) when santizing an
instance's display name for use as a hostname.
Nova publishes hostnames for instances via the metadata service and config
drives. This hostname is based on a sanitized version of the instance name
combined with the domain value specified in ``[api] dhcp_domain``. The
previous sanitization of the hostname included the replacement of whitespace
and underscores with dashes and the stripping of unicode characters along
with leading and trailing periods and dashes. It did not, however, include
the removal of periods in the name. Periods are not valid in the hostname
or, more specifically, in the host-specific or leaf label (the ``host`` in
``host.example.com``) and their presence can cause conflicts when ``[api]
dhcp_domain`` is configured, leading to instances being mistakenly
configured with hostnames like ``host.example.com.example.com``. More
pressingly, their use can result in a failure to boot instances if DNS
integration is enabled in neutron, likely via designate, as the hostname is
identified as a FQDN (fully-qualified domain name) by neutron and reasonable
instance names like ``test-ubuntu20.04`` will be rejected as invalid FQDNs,
in this case because the name would yield a TLD (top-level domain) of ``04``
and TLDs cannot be entire numerical. To avoid these issues, periods are now
replaced with dashes.

0 comments on commit 9046f0f

Please sign in to comment.