def test_parse_root_device_size(self, mock_get_params): mock_get_params.return_value = { 'root_device': 'size=12345', 'ipa-api-url': 'http://1.2.3.4:1234' } result = utils.parse_root_device_hints() self.assertEqual(12345, result['size'])
def test_parse_root_device_hints(self, mock_get_params): mock_get_params.return_value = { 'root_device': 'vendor=SpongeBob,model=Square%20Pants', 'ipa-api-url': 'http://1.2.3.4:1234' } expected = {'vendor': 'spongebob', 'model': 'square pants'} result = utils.parse_root_device_hints() self.assertEqual(expected, result)
def get_os_install_device(self): block_devices = self.list_block_devices() root_device_hints = utils.parse_root_device_hints() if not root_device_hints: return utils.guess_root_disk(block_devices).name else: def match(hint, current_value, device): hint_value = root_device_hints[hint] if hint_value != current_value: LOG.debug( "Root device hint %(hint)s=%(value)s does not " "match the device %(device)s value of " "%(current)s", { 'hint': hint, 'value': hint_value, 'device': device, 'current': current_value }) return False return True def check_device_attrs(device): for key in ('model', 'wwn', 'serial', 'vendor', 'wwn_with_extension', 'wwn_vendor_extension', 'name'): if key not in root_device_hints: continue value = getattr(device, key) if not value: return False value = utils.normalize(value) if not match(key, value, device.name): return False return True for dev in block_devices: # TODO(lucasagomes): Add support for operators <, >, =, etc... # to better deal with sizes. if 'size' in root_device_hints: # Since we don't support units yet we expect the size # in GiB for now size = dev.size / units.Gi if not match('size', size, dev.name): continue if check_device_attrs(dev): return dev.name else: raise errors.DeviceNotFound("No suitable device was found for " "deployment using these hints %s" % root_device_hints)
def get_os_install_device(self): block_devices = self.list_block_devices() root_device_hints = utils.parse_root_device_hints() if not root_device_hints: return utils.guess_root_disk(block_devices).name else: def match(hint, current_value, device): hint_value = root_device_hints[hint] if hint_value != current_value: LOG.debug("Root device hint %(hint)s=%(value)s does not " "match the device %(device)s value of " "%(current)s", { 'hint': hint, 'value': hint_value, 'device': device, 'current': current_value}) return False return True def check_device_attrs(device): for key in ('model', 'wwn', 'serial', 'vendor', 'wwn_with_extension', 'wwn_vendor_extension', 'name'): if key not in root_device_hints: continue value = getattr(device, key) if not value: return False value = utils.normalize(value) if not match(key, value, device.name): return False return True for dev in block_devices: # TODO(lucasagomes): Add support for operators <, >, =, etc... # to better deal with sizes. if 'size' in root_device_hints: # Since we don't support units yet we expect the size # in GiB for now size = dev.size / units.Gi if not match('size', size, dev.name): continue if check_device_attrs(dev): return dev.name else: raise errors.DeviceNotFound( "No suitable device was found for " "deployment using these hints %s" % root_device_hints)
def test_parse_root_device_hints_wwn(self, mock_get_params): mock_get_params.return_value = { 'root_device': 'wwn=abcd,wwn_vendor_extension=ext,' 'wwn_with_extension=abcd_ext', 'ipa-api-url': 'http://1.2.3.4:1234' } expected = { 'wwn': 'abcd', 'wwn_vendor_extension': 'ext', 'wwn_with_extension': 'abcd_ext' } result = utils.parse_root_device_hints() self.assertEqual(expected, result)
def test_parse_root_device_hints_no_hints(self, mock_get_params): mock_get_params.return_value = {'ipa-api-url': 'http://1.2.3.4:1234'} result = utils.parse_root_device_hints() self.assertEqual({}, result)
def get_os_install_device(self): block_devices = self.list_block_devices() root_device_hints = utils.parse_root_device_hints() if not root_device_hints: # If no hints are passed find the first device larger than # 4GB, assume it is the OS disk # TODO(russellhaering): This isn't a valid assumption in # all cases, is there a more reasonable default behavior? block_devices.sort(key=lambda device: device.size) for device in block_devices: if device.size >= (4 * pow(1024, 3)): return device.name else: def match(hint, current_value, device): hint_value = root_device_hints[hint] if hint_value != current_value: LOG.debug("Root device hint %(hint)s=%(value)s does not " "match the device %(device)s value of " "%(current)s", {'hint': hint, 'value': hint_value, 'device': device, 'current': current_value}) return False return True context = pyudev.Context() for dev in block_devices: try: udev = pyudev.Device.from_device_file(context, dev.name) except (ValueError, EnvironmentError) as e: LOG.warning("Device %(dev)s is inaccessible, skipping... " "Error: %(error)s", {'dev': dev, 'error': e}) continue # TODO(lucasagomes): Add support for operators <, >, =, etc... # to better deal with sizes. if 'size' in root_device_hints: # Since we don't support units yet we expect the size # in GiB for now size = dev.size / units.Gi if not match('size', size, dev.name): continue if 'model' in root_device_hints: model = udev.get('ID_MODEL', None) if not model: continue model = utils.normalize(model) if not match('model', model, dev.name): continue if 'wwn' in root_device_hints: wwn = udev.get('ID_WWN', None) if not wwn: continue wwn = utils.normalize(wwn) if not match('wwn', wwn, dev.name): continue if 'serial' in root_device_hints: # TODO(lucasagomes): Since lsblk only supports # returning the short serial we are using # ID_SERIAL_SHORT here to keep compatibility with the # bash deploy ramdisk serial = udev.get('ID_SERIAL_SHORT', None) if not serial: continue serial = utils.normalize(serial) if not match('serial', serial, dev.name): continue if 'vendor' in root_device_hints: vendor = self._get_device_vendor(dev.name) if not vendor: continue vendor = utils.normalize(vendor) if not match('vendor', vendor, dev.name): continue return dev.name else: raise errors.DeviceNotFound("No suitable device was found for " "deployment using these hints %s" % root_device_hints)
def test_parse_root_device_hints_no_hints(self, mock_get_params): mock_get_params.return_value = { 'ipa-api-url': 'http://1.2.3.4:1234' } result = utils.parse_root_device_hints() self.assertEqual({}, result)
def get_os_install_device(self): block_devices = self.list_block_devices() root_device_hints = utils.parse_root_device_hints() if not root_device_hints: # If no hints are passed find the first device larger than # 4GB, assume it is the OS disk # TODO(russellhaering): This isn't a valid assumption in # all cases, is there a more reasonable default behavior? block_devices.sort(key=lambda device: device.size) for device in block_devices: if device.size >= (4 * pow(1024, 3)): return device.name else: def match(hint, current_value, device): hint_value = root_device_hints[hint] if hint_value != current_value: LOG.debug( "Root device hint %(hint)s=%(value)s does not " "match the device %(device)s value of " "%(current)s", { 'hint': hint, 'value': hint_value, 'device': device, 'current': current_value }) return False return True context = pyudev.Context() for dev in block_devices: try: udev = pyudev.Device.from_device_file(context, dev.name) except (ValueError, EnvironmentError) as e: LOG.warning( "Device %(dev)s is inaccessible, skipping... " "Error: %(error)s", { 'dev': dev, 'error': e }) continue # TODO(lucasagomes): Add support for operators <, >, =, etc... # to better deal with sizes. if 'size' in root_device_hints: # Since we don't support units yet we expect the size # in GiB for now size = dev.size / units.Gi if not match('size', size, dev.name): continue if 'model' in root_device_hints: model = udev.get('ID_MODEL', None) if not model: continue model = utils.normalize(model) if not match('model', model, dev.name): continue if 'wwn' in root_device_hints: wwn = udev.get('ID_WWN', None) if not wwn: continue wwn = utils.normalize(wwn) if not match('wwn', wwn, dev.name): continue if 'serial' in root_device_hints: # TODO(lucasagomes): Since lsblk only supports # returning the short serial we are using # ID_SERIAL_SHORT here to keep compatibility with the # bash deploy ramdisk serial = udev.get('ID_SERIAL_SHORT', None) if not serial: continue serial = utils.normalize(serial) if not match('serial', serial, dev.name): continue if 'vendor' in root_device_hints: vendor = self._get_device_vendor(dev.name) if not vendor: continue vendor = utils.normalize(vendor) if not match('vendor', vendor, dev.name): continue return dev.name else: raise errors.DeviceNotFound("No suitable device was found for " "deployment using these hints %s" % root_device_hints)