Publish baremetal endpoint via mdns

This change adds an option to publish the endpoint via mDNS on start
up and clean it up on tear down.

Story: #2005393
Task: #30383
Change-Id: I55d2e7718a23cde111eaac4e431588184cb16bda
This commit is contained in:
Dmitry Tantsur 2019-04-11 17:02:58 +02:00
parent 82c853530f
commit c36a01a439
7 changed files with 68 additions and 2 deletions

View File

@ -19,6 +19,7 @@ import eventlet
import futurist
from futurist import periodics
from futurist import rejection
from ironic_lib import mdns
from oslo_db import exception as db_exception
from oslo_log import log
from oslo_utils import excutils
@ -39,6 +40,7 @@ from ironic.conductor import task_manager
from ironic.conf import CONF
from ironic.db import api as dbapi
from ironic.drivers import base as driver_base
from ironic.drivers.modules import deploy_utils
from ironic import objects
from ironic.objects import fields as obj_fields
@ -78,6 +80,7 @@ class BaseConductorManager(object):
self.sensors_notifier = rpc.get_sensors_notifier()
self._started = False
self._shutdown = None
self._zeroconf = None
def init_host(self, admin_context=None):
"""Initialize the conductor host.
@ -212,6 +215,9 @@ class BaseConductorManager(object):
except exception.NoFreeConductorWorker:
LOG.warning('Failed to start worker for resuming allocations.')
if CONF.conductor.enable_mdns:
self._publish_endpoint()
self._started = True
def _use_groups(self):
@ -316,6 +322,11 @@ class BaseConductorManager(object):
self._periodic_tasks.stop()
self._periodic_tasks.wait()
self._executor.shutdown(wait=True)
if self._zeroconf is not None:
self._zeroconf.close()
self._zeroconf = None
self._started = False
def _register_and_validate_hardware_interfaces(self, hardware_types):
@ -564,3 +575,12 @@ class BaseConductorManager(object):
for allocation in objects.Allocation.list(context, filters=filters):
LOG.debug('Resuming unfinished allocation %s', allocation.uuid)
allocations.do_allocate(context, allocation)
def _publish_endpoint(self):
params = {}
if CONF.debug:
params['ipa_debug'] = True
self._zeroconf = mdns.Zeroconf()
self._zeroconf.register_service('baremetal',
deploy_utils.get_ironic_api_url(),
params=params)

View File

@ -221,6 +221,9 @@ opts = [
mutable=True,
help=_('Allow deleting nodes which are in state '
'\'available\'. Defaults to True.')),
cfg.BoolOpt('enable_mdns', default=False,
help=_('Whether to enable publishing the ironic-inspector API '
'endpoint via multicast DNS.')),
]

View File

@ -18,6 +18,7 @@ import uuid
import eventlet
import futurist
from futurist import periodics
from ironic_lib import mdns
import mock
from oslo_config import cfg
from oslo_db import exception as db_exception
@ -32,6 +33,7 @@ from ironic.conductor import notification_utils
from ironic.conductor import task_manager
from ironic.drivers import fake_hardware
from ironic.drivers import generic
from ironic.drivers.modules import deploy_utils
from ironic.drivers.modules import fake
from ironic import objects
from ironic.objects import fields
@ -247,6 +249,40 @@ class StartStopTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
self.service.del_host()
self.assertTrue(self.service._shutdown)
@mock.patch.object(deploy_utils, 'get_ironic_api_url', autospec=True)
@mock.patch.object(mdns, 'Zeroconf', autospec=True)
def test_start_with_mdns(self, mock_zc, mock_api_url):
CONF.set_override('debug', False)
CONF.set_override('enable_mdns', True, 'conductor')
self._start_service()
res = objects.Conductor.get_by_hostname(self.context, self.hostname)
self.assertEqual(self.hostname, res['hostname'])
mock_zc.return_value.register_service.assert_called_once_with(
'baremetal',
mock_api_url.return_value,
params={})
@mock.patch.object(deploy_utils, 'get_ironic_api_url', autospec=True)
@mock.patch.object(mdns, 'Zeroconf', autospec=True)
def test_start_with_mdns_and_debug(self, mock_zc, mock_api_url):
CONF.set_override('debug', True)
CONF.set_override('enable_mdns', True, 'conductor')
self._start_service()
res = objects.Conductor.get_by_hostname(self.context, self.hostname)
self.assertEqual(self.hostname, res['hostname'])
mock_zc.return_value.register_service.assert_called_once_with(
'baremetal',
mock_api_url.return_value,
params={'ipa_debug': True})
def test_del_host_with_mdns(self):
mock_zc = mock.Mock(spec=mdns.Zeroconf)
self.service._zeroconf = mock_zc
self._start_service()
self.service.del_host()
mock_zc.close.assert_called_once_with()
self.assertIsNone(self.service._zeroconf)
class CheckInterfacesTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
def test__check_enabled_interfaces_success(self):

View File

@ -38,7 +38,7 @@ greenlet==0.4.13
hacking==1.0.0
idna==2.6
imagesize==1.0.0
ironic-lib==2.15.0
ironic-lib==2.17.0
iso8601==0.1.11
Jinja2==2.10
jmespath==0.9.3

View File

@ -0,0 +1,6 @@
---
features:
- |
A new option ``enable_mdns`` allows to enable publishing the baremetal
API endpoint via mDNS as specified in the `API SIG guideline
<http://specs.openstack.org/openstack/api-sig/guidelines/dns-sd.html>`_.

View File

@ -11,7 +11,7 @@ python-cinderclient>=3.3.0 # Apache-2.0
python-neutronclient>=6.7.0 # Apache-2.0
python-glanceclient>=2.8.0 # Apache-2.0
keystoneauth1>=3.4.0 # Apache-2.0
ironic-lib>=2.15.0 # Apache-2.0
ironic-lib>=2.17.0 # Apache-2.0
python-swiftclient>=3.2.0 # Apache-2.0
pytz>=2013.6 # MIT
stevedore>=1.20.0 # Apache-2.0

View File

@ -4,6 +4,7 @@ wrap_width = 62
namespace = ironic
namespace = ironic_lib.disk_utils
namespace = ironic_lib.disk_partitioner
namespace = ironic_lib.mdns
namespace = ironic_lib.metrics
namespace = ironic_lib.metrics_statsd
namespace = ironic_lib.utils