Add a new type HostDomain.

HostDomain is like HostAddress with the support of
_ character - RFC1033

openstack services are failing to start when a hostname with underscore
_ is provided.

Example:

```
overcloud-novacompute_edge1-0.internalapi.localdomain
overcloud-novacompute_edge1-0.internalapi
```

Nova use `HostAddressOpt` to define `live_migration_inbound_addr`,
and if a hostname with underscore is present in the config file
then the service fail to start.

Example:

```
/etc/nova/nova.conf
live_migration_inbound_addr =
overcloud-novacompute_edge1-0.internalapi.localdomain
```

FQDN is a domain name that specifies its exact
location in the tree hierarchy of the Domain Name System (DNS).

Underscore are allowed by RFC1033 [1][2][3]. Indeed, while a hostname may not
contain other characters, such as the underscore character (_), other
DNS names may contain the underscore.[1][2].
Systems such as DomainKeys and service records use the underscore.

These changes allow us to use underscore with the `HostDomain`.

[1] https://www.ietf.org/rfc/rfc1912.txt
[2] https://www.ietf.org/rfc/rfc1033.txt
[3] http://domainkeys.sourceforge.net/underscore.html

Co-authored-by: Daniel Bengtsson <dbengt@redhat.com>
Change-Id: I0a0670207f96a987996d329e5efa9a5eb2ce000c
Closes-Bug: #1892044
This commit is contained in:
Hervé Beraud 2020-08-18 15:30:04 +02:00 committed by Daniel Bengtsson
parent fcb88941e3
commit 6480356928
3 changed files with 76 additions and 4 deletions

View File

@ -766,6 +766,27 @@ class HostAddressTypeTests(TypeTestHelper, unittest.TestCase):
self.assertConvertedValue('abc.0-0', 'abc.0-0')
class HostDomainTypeTests(TypeTestHelper, unittest.TestCase):
type = types.HostDomain()
def test_invalid_host_addresses(self):
self.assertInvalid('-1')
self.assertInvalid('3.14')
self.assertInvalid('10.0')
self.assertInvalid('host..name')
self.assertInvalid('org.10')
self.assertInvalid('0.0.00')
def test_valid_host_addresses(self):
self.assertConvertedValue('_foo', '_foo')
self.assertConvertedValue('host_name', 'host_name')
self.assertConvertedValue(
'overcloud-novacompute_edge1-0.internalapi.localdomain',
'overcloud-novacompute_edge1-0.internalapi.localdomain')
self.assertConvertedValue('host_01.co.uk', 'host_01.co.uk')
self.assertConvertedValue('_site01001', '_site01001')
class HostnameTypeTests(TypeTestHelper, unittest.TestCase):
type = types.Hostname()
@ -796,8 +817,8 @@ class HostnameTypeTests(TypeTestHelper, unittest.TestCase):
self.assertInvalid("h'ost'")
self.assertInvalid("h'ost")
self.assertInvalid("h$ost")
self.assertInvalid("h%ost")
self.assertInvalid("host_01.co.uk")
self.assertInvalid("h%ost")
self.assertInvalid("host;name=99")
self.assertInvalid('___site0.1001')
self.assertInvalid('_site01001')
@ -808,6 +829,7 @@ class HostnameTypeTests(TypeTestHelper, unittest.TestCase):
def test_invalid_hostnames_with_numeric_characters(self):
self.assertInvalid("10.0.0.0")
self.assertInvalid("3.14")
self.assertInvalid('___site0.1001')
self.assertInvalid("org.10")
self.assertInvalid('0.0.00')

View File

@ -761,11 +761,12 @@ class Hostname(ConfigType):
:param type_name: Type name to be used in the sample config file.
"""
HOSTNAME_REGEX = '(?!-)[A-Z0-9-]{1,63}(?<!-)$'
def __init__(self, type_name='hostname value'):
super(Hostname, self).__init__(type_name=type_name)
def __call__(self, value):
def __call__(self, value, regex=HOSTNAME_REGEX):
"""Check hostname is valid.
Ensures that each segment
@ -789,7 +790,7 @@ class Hostname(ConfigType):
% value)
if value.endswith("."):
value = value[:-1]
allowed = re.compile("(?!-)[A-Z0-9-]{1,63}(?<!-)$", re.IGNORECASE)
allowed = re.compile(regex, re.IGNORECASE)
if not re.search('[a-zA-Z-]', value.split(".")[-1]):
raise ValueError('%s contains no non-numeric characters in the '
'top-level domain part of the host name and is '
@ -844,7 +845,8 @@ class HostAddress(ConfigType):
try:
value = self.hostname(value)
except ValueError:
raise ValueError("%s is not a valid host address" % (value,))
raise ValueError(
"%s is not a valid host address" % (value,))
return value
def __repr__(self):
@ -857,6 +859,45 @@ class HostAddress(ConfigType):
return value
class HostDomain(HostAddress):
"""Host Domain type.
Like HostAddress with the support of _ character.
:param version: defines which version should be explicitly
checked (4 or 6) in case of an IP address
:param type_name: Type name to be used in the sample config file.
"""
# DOMAIN_REGEX is HOSTNAME_REGEX with the _ character added
DOMAIN_REGEX = '(?!-)[A-Z0-9-_]{1,63}(?<!-)$'
def __call__(self, value):
"""Checks if is a valid IP/hostname.
If not a valid IP, makes sure it is not a mistyped IP before
performing checks for it as a hostname.
"""
try:
value = super(HostDomain, self).__call__(value)
except ValueError:
# Check if domain is valid
# Add support of underscore
# https://www.ietf.org/rfc/rfc1912,
# http://domainkeys.sourceforge.net/underscore.html
# https://bugs.launchpad.net/oslo.config/+bug/1892044
try:
value = self.hostname(value, regex=self.DOMAIN_REGEX)
except ValueError:
raise ValueError(
"%s is not a valid host address" % (value,))
return value
def __repr__(self):
return 'HostDomain'
class URI(ConfigType):
"""URI type

View File

@ -0,0 +1,9 @@
---
features:
- |
Add ``HostDomain`` to handle address with underscore. Underscore are
allowed in domain by RFC1033 [1][2][3].
- [1] https://www.ietf.org/rfc/rfc1912.txt
- [2] https://www.ietf.org/rfc/rfc1033.txt
- [3] http://domainkeys.sourceforge.net/underscore.html