@@ -48,7 +48,12 @@ def solve(config)
4848 # @return [Storage::System]
4949 attr_reader :storage_system
5050
51- # Finds a device for booting and sets its alias, if needed.
51+ # Finds a device for booting.
52+ #
53+ # It there is already an entry pointing to that device, it may set an alias for that config
54+ # entry if needed.
55+ #
56+ # If there is no Drive or MdRaid entry, it may add it to the config.
5257 #
5358 # A boot device cannot be automatically inferred in the following scenarios:
5459 # * The root partition or logical volume is missing.
@@ -69,12 +74,15 @@ def solve_device_alias
6974
7075 # Config of the device used for allocating root, directly or indirectly.
7176 #
72- # The boot device has to be a partitioned drive. If root is not directly created as a
73- # partition of a drive (e.g., as logical volume, as partition of a MD RAID, etc), then the
74- # first partitioned drive used for allocating the device (physical volume or MD member
75- # device) is considered as boot device.
77+ # The boot device has to be a partitioned drive or hardware RAID. If root is not directly
78+ # created as a partition of a drive (e.g., as logical volume, as partition of a MD RAID,
79+ # etc), then the first partitioned drive used for allocating the device (physical volume
80+ # or MD member device) is considered as boot device.
81+ #
82+ # The boot device is recursively searched until reaching a drive or a hardware RAID.
7683 #
77- # The boot device is recursively searched until reaching a drive.
84+ # For reused LVMs or RAIDs, the result may be a new config entry created to point to the
85+ # appropriate boot device.
7886 #
7987 # @return [Configs::Drive, Configs::MdRaid, nil] nil if the boot device cannot be inferred
8088 # from the config.
@@ -130,14 +138,14 @@ def partitionable_from_md_raid(md_raid)
130138
131139 # Recursively looks for the first partitioned config from the given MD RAID.
132140 #
141+ # If no config is found, it may create and return a new Drive or MdRaid config.
142+ #
133143 # @param md_raid [Configs::MdRaid]
134144 # @return [Configs::Drive, Configs::MdRaid, nil]
135145 def partitionable_from_found_md_raid ( md_raid )
136146 return md_raid if storage_system . candidate? ( md_raid . found_device )
137147
138- # TODO: find the correct underlying disk devices for the MD RAID (note they may lack
139- # a corresponding drive entry at the configuration)
140- nil
148+ partitionable_from_found ( md_raid . found_device )
141149 end
142150
143151 # Recursively looks for the first partitioned drive from the given MD RAID.
@@ -151,9 +159,20 @@ def partitioned_drive_from_new_md_raid(md_raid)
151159
152160 # Recursively looks for the first partitioned config from the given volume group.
153161 #
162+ # If no config is found, it may create and return a new Drive or MdRaid config.
163+ #
154164 # @param volume_group [Configs::VolumeGroup]
155165 # @return [Configs::Drive, Configs::MdRaid, nil]
156166 def partitionable_from_volume_group ( volume_group )
167+ partitionable_from_volume_group_pvs ( volume_group ) ||
168+ ( volume_group . found_device && partitionable_from_found ( volume_group . found_device ) )
169+ end
170+
171+ # Recursively looks for the first partitioned config from the given volume group.
172+ #
173+ # @param volume_group [Configs::VolumeGroup]
174+ # @return [Configs::Drive, Configs::MdRaid, nil]
175+ def partitionable_from_volume_group_pvs ( volume_group )
157176 pv_devices = find_devices ( volume_group . physical_volumes_devices , is_target : true )
158177 pvs = find_devices ( volume_group . physical_volumes )
159178
@@ -212,6 +231,94 @@ def find_md_raid(device_alias)
212231 def find_volume_group ( device_alias )
213232 config . volume_groups . find { |v | v . logical_volume? ( device_alias ) }
214233 end
234+
235+ # Finds or creates a config pointing to the bootable device corresponding to the given
236+ # RAID or volume group.
237+ #
238+ # @param device [Y2Storage::Md, Y2Storage::LvmVg]
239+ # @return [Configs::Drive, Configs::MdRaid, nil]
240+ def partitionable_from_found ( device )
241+ disks = bootable_devices ( device )
242+ return if disks . empty?
243+
244+ config_entry ( disks )
245+ end
246+
247+ # Finds all devices that could be used to boot into the given RAID or volume group
248+ #
249+ # @see #partitionable_from_found
250+ #
251+ # @param device [Y2Storage::Md, Y2Storage::LvmVg]
252+ # @return [Array<Y2Storage::Partitionable>]
253+ def bootable_devices ( device )
254+ device . ancestors . select do |dev |
255+ dev . is? ( :disk_device ) && dev . partition_table? && storage_system . candidate? ( dev )
256+ end
257+ end
258+
259+ # @see #partitionable_from_found
260+ #
261+ # @param devices [Array<Y2Storage::Partitionable>] list of candidate RAIDs or disk devices
262+ # @return [Configs::Drive, Configs::MdRaid]
263+ def config_entry ( devices )
264+ find_config_entry ( devices ) || create_config_entry ( devices )
265+ end
266+
267+ # Find the first entry in the current configuration that corresponds to any of the given
268+ # devices
269+ #
270+ # @param devices [Array<Y2Storage::Partitionable>] list of candidate RAIDs or disk devices
271+ # @return [Configs::Drive, Configs::MdRaid, nil]
272+ def find_config_entry ( devices )
273+ sids = devices . map ( &:sid )
274+ raid = config . md_raids . find { |d | sids . include? ( d . found_device &.sid ) }
275+ return raid if raid
276+
277+ config . drives . find { |d | sids . include? ( d . found_device . sid ) }
278+ end
279+
280+ # Creates a new entry in the config to point to one of the given devices
281+ #
282+ # @param devices [Array<Y2Storage::Partitionable>] list of candidate RAIDs or disk devices
283+ # @return [Configs::Drive, Configs::MdRaid]
284+ def create_config_entry ( devices )
285+ device = preferred_device_to_create_entry ( devices )
286+ device . is? ( :raid ) ? create_raid_entry ( device ) : create_drive_entry ( device )
287+ end
288+
289+ # @see #create_config_entry
290+ #
291+ # @param devices [Array<Y2Storage::Partitionable>]
292+ # @return [Y2Storage::Partitionable]
293+ def preferred_device_to_create_entry ( devices )
294+ devices = devices . select { |d | d . is? ( :raid ) } if devices . any? { |d | d . is? ( :raid ) }
295+ devices . min_by ( &:name )
296+ end
297+
298+ # @see #create_config_entry
299+ #
300+ # @param device [<Y2Storage::Partitionable>] disk device
301+ # @return [Configs::Drive]
302+ def create_drive_entry ( device )
303+ config . drives << Configs ::Drive . new . tap do |drive |
304+ drive . search . name = device . name
305+ drive . search . solve ( device )
306+ end
307+ config . drives . last
308+ end
309+
310+ # @see #create_config_entry
311+ #
312+ # @param device [<Y2Storage::Md>] RAID device
313+ # @return [Configs::MdRaid]
314+ def create_raid_entry ( device )
315+ config . md_raids << Configs ::MdRaid . new . tap do |md |
316+ md . search = Configs ::Search . new
317+ md . search . name = device . name
318+ md . search . solve ( device )
319+ end
320+ config . md_raids . last
321+ end
215322 end
216323 end
217324 end
0 commit comments