Use hosts official name for FQDN
The current implementations use of a specific interface to build
FQDN from has the undesired side effect of the ``nova-compute`` and
``neutron-openvswitch`` charms ending up with using different
hostnames in some situations. It may also lead to use of a
identifier that is mutable throughout the lifetime of a deployment.
Use of a specific interface was chosen due to ``socket.getfqdn()``
not giving reliable results (https://bugs.python.org/issue5004).
This patch gets the FQDN by mimicking the behaviour of a call to
``hostname -f`` with fallback to shortname on failure.
Add relevant update from c-h.
Change-Id: I82db81937e5a46dc6bd222b7160ca1fa5b190c10
Closes-Bug: #1839300
(cherry-picked from 1869bfbc97
)
This commit is contained in:
parent
1530383a79
commit
66405e2092
@ -2177,9 +2177,66 @@ class LogrotateContext(OSContextGenerator):
|
||||
class HostInfoContext(OSContextGenerator):
|
||||
"""Context to provide host information."""
|
||||
|
||||
def __init__(self, use_fqdn_hint_cb=None):
|
||||
"""Initialize HostInfoContext
|
||||
|
||||
:param use_fqdn_hint_cb: Callback whose return value used to populate
|
||||
`use_fqdn_hint`
|
||||
:type use_fqdn_hint_cb: Callable[[], bool]
|
||||
"""
|
||||
# Store callback used to get hint for whether FQDN should be used
|
||||
|
||||
# Depending on the workload a charm manages, the use of FQDN vs.
|
||||
# shortname may be a deploy-time decision, i.e. behaviour can not
|
||||
# change on charm upgrade or post-deployment configuration change.
|
||||
|
||||
# The hint is passed on as a flag in the context to allow the decision
|
||||
# to be made in the Jinja2 configuration template.
|
||||
self.use_fqdn_hint_cb = use_fqdn_hint_cb
|
||||
|
||||
def _get_canonical_name(self, name=None):
|
||||
"""Get the official FQDN of the host
|
||||
|
||||
The implementation of ``socket.getfqdn()`` in the standard Python
|
||||
library does not exhaust all methods of getting the official name
|
||||
of a host ref Python issue https://bugs.python.org/issue5004
|
||||
|
||||
This function mimics the behaviour of a call to ``hostname -f`` to
|
||||
get the official FQDN but returns an empty string if it is
|
||||
unsuccessful.
|
||||
|
||||
:param name: Shortname to get FQDN on
|
||||
:type name: Optional[str]
|
||||
:returns: The official FQDN for host or empty string ('')
|
||||
:rtype: str
|
||||
"""
|
||||
name = name or socket.gethostname()
|
||||
fqdn = ''
|
||||
|
||||
if six.PY2:
|
||||
exc = socket.error
|
||||
else:
|
||||
exc = OSError
|
||||
|
||||
try:
|
||||
addrs = socket.getaddrinfo(
|
||||
name, None, 0, socket.SOCK_DGRAM, 0, socket.AI_CANONNAME)
|
||||
except exc:
|
||||
pass
|
||||
else:
|
||||
for addr in addrs:
|
||||
if addr[3]:
|
||||
if '.' in addr[3]:
|
||||
fqdn = addr[3]
|
||||
break
|
||||
return fqdn
|
||||
|
||||
def __call__(self):
|
||||
name = socket.gethostname()
|
||||
ctxt = {
|
||||
'host_fqdn': socket.getfqdn(),
|
||||
'host': socket.gethostname(),
|
||||
'host_fqdn': self._get_canonical_name(name) or name,
|
||||
'host': name,
|
||||
'use_fqdn_hint': (
|
||||
self.use_fqdn_hint_cb() if self.use_fqdn_hint_cb else False)
|
||||
}
|
||||
return ctxt
|
||||
|
@ -16,7 +16,6 @@ import json
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import socket
|
||||
import uuid
|
||||
|
||||
from charmhelpers.core.unitdata import kv
|
||||
@ -784,23 +783,6 @@ class HostIPContext(context.OSContextGenerator):
|
||||
# NOTE: do not format this even for ipv6 (see bug 1499656)
|
||||
ctxt['host_ip'] = host_ip
|
||||
|
||||
# the contents of the Nova ``host`` configuration option is
|
||||
# referenced throughout a OpenStack deployment, an example being
|
||||
# Neutron port bindings. It's value should not change after a
|
||||
# individual units initial deployment.
|
||||
#
|
||||
# We do want to migrate to using FQDNs so we enable this for new
|
||||
# installations.
|
||||
db = kv()
|
||||
if db.get('nova-compute-charm-use-fqdn', False):
|
||||
fqdn = socket.getfqdn(host_ip)
|
||||
if '.' in fqdn:
|
||||
# only populate the value if getfqdn() is able to find an
|
||||
# actual FQDN for this host. If not, we revert back to
|
||||
# not setting the configuration option and use Nova's
|
||||
# default behaviour.
|
||||
ctxt['host'] = fqdn
|
||||
|
||||
return ctxt
|
||||
|
||||
|
||||
|
@ -117,6 +117,7 @@ from nova_compute_utils import (
|
||||
get_availability_zone,
|
||||
remove_old_packages,
|
||||
MULTIPATH_PACKAGES,
|
||||
USE_FQDN_KEY,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.network.ip import (
|
||||
@ -163,7 +164,7 @@ def install():
|
||||
release = os_release('nova-common')
|
||||
if CompareOpenStackReleases(release) >= 'stein':
|
||||
db = kv()
|
||||
db.set('nova-compute-charm-use-fqdn', True)
|
||||
db.set(USE_FQDN_KEY, True)
|
||||
db.flush()
|
||||
|
||||
|
||||
|
@ -179,6 +179,19 @@ NOVA_NETWORK_AA_PROFILE_PATH = ('/etc/apparmor.d/{}'
|
||||
|
||||
LIBVIRT_TYPES = ['kvm', 'qemu', 'lxc']
|
||||
|
||||
USE_FQDN_KEY = 'nova-compute-charm-use-fqdn'
|
||||
|
||||
|
||||
def use_fqdn_hint():
|
||||
"""Hint for whether FQDN should be used for agent registration
|
||||
|
||||
:returns: True or False
|
||||
:rtype: bool
|
||||
"""
|
||||
db = kv()
|
||||
return db.get(USE_FQDN_KEY, False)
|
||||
|
||||
|
||||
BASE_RESOURCE_MAP = {
|
||||
NOVA_CONF: {
|
||||
'services': ['nova-compute'],
|
||||
@ -212,7 +225,9 @@ BASE_RESOURCE_MAP = {
|
||||
vaultlocker.VaultKVContext(
|
||||
vaultlocker.VAULTLOCKER_BACKEND),
|
||||
context.IdentityCredentialsContext(
|
||||
rel_name='cloud-credentials')],
|
||||
rel_name='cloud-credentials'),
|
||||
context.HostInfoContext(use_fqdn_hint_cb=use_fqdn_hint),
|
||||
],
|
||||
},
|
||||
VENDORDATA_FILE: {
|
||||
'services': [],
|
||||
|
@ -20,8 +20,8 @@ enabled_apis=osapi_compute,metadata
|
||||
my_ip = {{ host_ip }}
|
||||
force_raw_images = {{ force_raw_images }}
|
||||
|
||||
{% if host -%}
|
||||
host = {{ host }}
|
||||
{% if use_fqdn_hint and host_fqdn -%}
|
||||
host = {{ host_fqdn }}
|
||||
{% endif -%}
|
||||
|
||||
{% if debug -%}
|
||||
|
@ -19,6 +19,7 @@ os.environ['JUJU_UNIT_NAME'] = 'nova_compute'
|
||||
|
||||
with patch('charmhelpers.core.hookenv.config') as config:
|
||||
config.return_value = 'nova'
|
||||
with patch('charmhelpers.contrib.openstack.context.HostInfoContext'):
|
||||
import nova_compute_utils as utils # noqa
|
||||
|
||||
with patch('nova_compute_utils.restart_map'):
|
||||
|
@ -635,25 +635,14 @@ class NovaComputeContextTests(CharmTestCase):
|
||||
libvirt = context.NovaComputeLibvirtContext()
|
||||
self.assertFalse('cpu-mode' in libvirt())
|
||||
|
||||
@patch.object(context.socket, 'getfqdn')
|
||||
@patch('subprocess.call')
|
||||
def test_host_IP_context(self, _call, _getfqdn):
|
||||
def test_host_IP_context(self, _call):
|
||||
self.log = fake_log
|
||||
self.get_relation_ip.return_value = '172.24.0.79'
|
||||
self.kv.return_value = FakeUnitdata()
|
||||
host_ip = context.HostIPContext()
|
||||
self.assertEqual({'host_ip': '172.24.0.79'}, host_ip())
|
||||
self.get_relation_ip.assert_called_with('cloud-compute',
|
||||
cidr_network=None)
|
||||
self.kv.return_value = FakeUnitdata(
|
||||
**{'nova-compute-charm-use-fqdn': True})
|
||||
_getfqdn.return_value = 'some'
|
||||
host_ip = context.HostIPContext()
|
||||
self.assertEqual({'host_ip': '172.24.0.79'}, host_ip())
|
||||
_getfqdn.return_value = 'some.hostname'
|
||||
host_ip = context.HostIPContext()
|
||||
self.assertDictEqual({'host': 'some.hostname',
|
||||
'host_ip': '172.24.0.79'}, host_ip())
|
||||
|
||||
@patch('subprocess.call')
|
||||
def test_host_IP_context_ipv6(self, _call):
|
||||
|
@ -129,7 +129,7 @@ class NovaComputeRelationsTests(CharmTestCase):
|
||||
kv = MagicMock()
|
||||
_kv.return_value = kv
|
||||
hooks.install()
|
||||
kv.set.assert_called_once_with('nova-compute-charm-use-fqdn', True)
|
||||
kv.set.assert_called_once_with(hooks.USE_FQDN_KEY, True)
|
||||
kv.flush.assert_called_once_with()
|
||||
|
||||
@patch.object(hooks, 'ceph_changed')
|
||||
|
@ -1128,3 +1128,10 @@ class NovaComputeUtilsTests(CharmTestCase):
|
||||
_hook_name.return_value = "post-series-upgrade"
|
||||
self.assertEqual(_full,
|
||||
utils.services_to_pause_or_resume())
|
||||
|
||||
@patch.object(utils, 'kv')
|
||||
def test_use_fqdn_hint(self, _kv):
|
||||
_kv().get.return_value = False
|
||||
self.assertEquals(utils.use_fqdn_hint(), False)
|
||||
_kv().get.return_value = True
|
||||
self.assertEquals(utils.use_fqdn_hint(), True)
|
||||
|
Loading…
Reference in New Issue
Block a user