Source code for ironic.pxe_filter.service

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import os
import time

import eventlet
from eventlet import event
from ironic_lib import metrics_utils
from oslo_log import log

from ironic.common.i18n import _
from ironic.common import states
from ironic.conf import CONF
from ironic.db import api as dbapi
from ironic.pxe_filter import dnsmasq

LOG = log.getLogger(__name__)
METRICS = metrics_utils.get_metrics_logger(__name__)

_START_DELAY = 1.0


[docs] class PXEFilterManager: topic = 'ironic.pxe_filter' def __init__(self, host): self.host = host or CONF.host self._started = False
[docs] def prepare_host(self): if not CONF.pxe_filter.dhcp_hostsdir: raise RuntimeError(_('The [pxe_filter]dhcp_hostsdir option ' 'is required')) if not os.path.isdir(CONF.pxe_filter.dhcp_hostsdir): # FIXME(dtantsur): should we try to create it? The permissions will # most likely be wrong. raise RuntimeError(_('The path in [pxe_filter]dhcp_hostsdir ' 'does not exist'))
[docs] def init_host(self, admin_context): if self._started: raise RuntimeError(_('Attempt to start an already running ' 'PXE filter manager')) self._shutdown = event.Event() self._thread = eventlet.spawn_after(_START_DELAY, self._periodic_sync) self._started = True
[docs] def del_host(self): self._shutdown.send(True) eventlet.sleep(0) self._thread.wait() self._started = False
def _periodic_sync(self): db = dbapi.get_instance() self._try_sync(db) while not self._shutdown.wait(timeout=CONF.pxe_filter.sync_period): self._try_sync(db) def _try_sync(self, db): try: return self._sync(db) except Exception: LOG.exception('Sync failed, will retry') @METRICS.timer('PXEFilterManager._sync') def _sync(self, db): LOG.debug('Starting periodic sync of the filter') ts = time.time() nodeinfo_list = db.get_nodeinfo_list( columns=['id', 'inspect_interface'], filters={ 'provision_state_in': [states.INSPECTWAIT, states.INSPECTING], }) nodes_on_inspection = { node[0] for node in nodeinfo_list if node[1] in CONF.pxe_filter.supported_inspect_interfaces } all_ports = db.get_port_list() LOG.debug("Found %d nodes on inspection, handling %d ports", len(nodes_on_inspection), len(all_ports)) allow = [port.address for port in all_ports if port.node_id in nodes_on_inspection] deny = [port.address for port in all_ports if port.node_id not in nodes_on_inspection] allow_unknown = (CONF.auto_discovery.enabled or bool(nodes_on_inspection)) dnsmasq.sync(allow, deny, allow_unknown) LOG.info('Finished periodic sync of the filter, took %.2f seconds', time.time() - ts)