Source code for ironic_inspector.plugins.raid_device

# 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.

"""Gather root device hint from recognized block devices."""

from ironic_inspector.common.i18n import _LI, _LW
from ironic_inspector.plugins import base
from ironic_inspector import utils


LOG = utils.getProcessingLogger(__name__)


[docs]class RaidDeviceDetection(base.ProcessingHook): """Processing hook for learning the root device after RAID creation. The plugin can figure out the root device in 2 runs. First, it saves the discovered block device serials in node.extra. The second run will check the difference between the recently discovered block devices and the previously saved ones. After saving the root device in node.properties, it will delete the temporarily saved block device serials in node.extra. This way, it helps to figure out the root device hint in cases when otherwise Ironic doesn't have enough information to do so. Such a usecase is DRAC RAID configuration where the BMC doesn't provide any useful information about the created RAID disks. Using this plugin immediately before and after creating the root RAID device will solve the issue of root device hints. In cases where there's no RAID volume on the node, the standard plugin will fail due to the missing local_gb value. This plugin fakes the missing value, until it's corrected during later runs. Note, that for this to work the plugin needs to take precedence over the standard plugin. """ def _get_serials(self, data): if 'inventory' in data: return [x['serial'] for x in data['inventory'].get('disks', ()) if x.get('serial')] elif 'block_devices' in data: return data['block_devices'].get('serials', ())
[docs] def before_processing(self, introspection_data, **kwargs): """Adds fake local_gb value if it's missing from introspection_data.""" if not introspection_data.get('local_gb'): LOG.info(_LI('No volume is found on the node. Adding a fake ' 'value for "local_gb"'), data=introspection_data) introspection_data['local_gb'] = 1
[docs] def before_update(self, introspection_data, node_info, **kwargs): current_devices = self._get_serials(introspection_data) if not current_devices: LOG.warning(_LW('No block device was received from ramdisk'), node_info=node_info, data=introspection_data) return node = node_info.node() if 'root_device' in node.properties: LOG.info(_LI('Root device is already known for the node'), node_info=node_info, data=introspection_data) return if 'block_devices' in node.extra: # Compare previously discovered devices with the current ones previous_devices = node.extra['block_devices']['serials'] new_devices = [device for device in current_devices if device not in previous_devices] if len(new_devices) > 1: LOG.warning(_LW('Root device cannot be identified because ' 'multiple new devices were found'), node_info=node_info, data=introspection_data) return elif len(new_devices) == 0: LOG.warning(_LW('No new devices were found'), node_info=node_info, data=introspection_data) return node_info.patch([ {'op': 'remove', 'path': '/extra/block_devices'}, {'op': 'add', 'path': '/properties/root_device', 'value': {'serial': new_devices[0]}} ]) else: # No previously discovered devices - save the inspector block # devices in node.extra node_info.patch([{'op': 'add', 'path': '/extra/block_devices', 'value': {'serials': current_devices}}])