/
blk_device.rb
335 lines (291 loc) · 10.6 KB
/
blk_device.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# encoding: utf-8
# Copyright (c) [2017] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.
require "y2storage/storage_class_wrapper"
require "y2storage/device"
require "y2storage/hwinfo_reader"
require "y2storage/comparable_by_name"
module Y2Storage
# Base class for most devices having a device name, udev path and udev ids.
#
# This is a wrapper for Storage::BlkDevice
class BlkDevice < Device
wrap_class Storage::BlkDevice,
downcast_to: ["Partitionable", "Partition", "Encryption", "LvmLv"]
include ComparableByName
# @!method self.all(devicegraph)
# @param devicegraph [Devicegraph]
# @return [Array<BlkDevice>] all the block devices in the given devicegraph
storage_class_forward :all, as: "BlkDevice"
# @!method self.find_by_name(devicegraph, name)
# @param devicegraph [Devicegraph]
# @param name [String] kernel-style device name (e.g. "/dev/sda1")
# @return [BlkDevice] nil if there is no such block device
storage_class_forward :find_by_name, as: "BlkDevice"
# @!attribute name
# @return [String] kernel-style device name
# (e.g. "/dev/sda2" or "/dev/vg_name/lv_name")
storage_forward :name
storage_forward :name=
# @!attribute region
# @return [Region]
storage_forward :region, as: "Region"
storage_forward :region=
# @!attribute size
# @return [DiskSize]
storage_forward :size, as: "DiskSize"
storage_forward :size=
# @!method sysfs_name
# @return [String] e.g. "sda2" or "dm-1"
storage_forward :sysfs_name
# @!method sysfs_path
# e.g. "/devices/pci00:0/00:0:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda/sda2"
# or "/devices/virtual/block/dm-1"
# @return [String]
storage_forward :sysfs_path
# Full paths of all the udev by-* links. an empty array for devices
# not handled by udev.
# @see #udev_full_paths
# @see #udev_full_ids
# @see #udev_full_uuid
# @see #udev_full_label
# @return [Array<String>]
def udev_full_all
res = udev_full_paths.concat(udev_full_ids)
res << udev_full_uuid << udev_full_label
res.compact
end
# @!method udev_paths
# Names of all the udev by-path links. An empty array for devices
# not handled by udev.
# E.g. ["pci-0000:00:1f.2-ata-1-part2"]
# @see #udev_full_paths
# @return [Array<String>]
storage_forward :udev_paths
# Full paths of all the udev by-path links. An empty array for devices
# not handled by udev.
# E.g. ["/dev/disk/by-path/pci-0000:00:1f.2-ata-1-part2"]
# @see #udev_paths
# @return [Array<String>]
def udev_full_paths
udev_paths.map { |path| File.join("/dev", "disk", "by-path", path) }
end
# @!method udev_ids
# Names of all the udev by-id links. An empty array for devices
# not handled by udev.
# E.g. ["scsi-350014ee658db9ee6"]
# @see #udev_full_ids
# @return [Array<String]
storage_forward :udev_ids
# Full paths of all the udev by-id links. An empty array for devices
# not handled by udev.
# E.g. ["/dev/disk/by-id/scsi-350014ee658db9ee6"]
# @see #udev_ids
# @return [Array<String>]
def udev_full_ids
udev_ids.map { |id| File.join("/dev", "disk", "by-id", id) }
end
# @!attribute dm_table_name
# Device-mapper table name. Empty if this is not a device-mapper device.
# @return [String]
storage_forward :dm_table_name
storage_forward :dm_table_name=
# @!method create_blk_filesystem(fs_type)
# Creates a new filesystem object on top of the device in order to format it.
#
# @param fs_type [Filesystems::Type]
# @return [Filesystems::BlkFilesystem]
storage_forward :create_blk_filesystem, as: "Filesystems::BlkFilesystem", raise_errors: true
alias_method :create_filesystem, :create_blk_filesystem
# @!method create_encryption(dm_name)
# Creates a new encryption object on top of the device.
#
# If the blk device has children, the children will become children of
# the encryption device.
#
# @note: NEVER use this if any child of the block device already exists
# in the real system. It will fail during commit.
#
# @param dm_name [String] see #dm_table_name
# @return [Encryption]
storage_forward :create_encryption, as: "Encryption", raise_errors: true
# @!method remove_encryption
# Removes an encryption device on the block device.
#
# If the encryption device has children, the children will become direct
# children of the block device.
#
# @note: NEVER use this if any child of the encryption device already
# exists in the real system. It will fail during commit.
#
# @raise [Storage::WrongNumberOfChildren, Storage::DeviceHasWrongType] if
# the device is not encrypted.
storage_forward :remove_encryption, raise_errors: true
# @!method direct_blk_filesystem
# Filesystem directly placed in the device (no encryption or any other
# layer in between)
#
# This is a wrapper for Storage::BlkDevice#blk_filesystem
#
# @return [Filesystems::BlkFilesystem] nil if the raw device is not
# formatted
storage_forward :direct_blk_filesystem,
to: :blk_filesystem, as: "Filesystems::BlkFilesystem", check_with: :has_blk_filesystem
# @!method encryption
# Encryption device directly placed on top of the device
#
# @return [Encryption] nil if the device is not encrypted
storage_forward :encryption, as: "Encryption", check_with: :has_encryption
# Checks whether the device is encrypted
#
# @return [boolean]
def encrypted?
!encryption.nil?
end
# Filesystem placed in the device, either directly or through an encryption
# layer.
#
# @return [Filesystems::BlkFilesystem] nil if neither the raw device or its
# encrypted version are formatted
def blk_filesystem
encrypted? ? encryption.direct_blk_filesystem : direct_blk_filesystem
end
alias_method :filesystem, :blk_filesystem
# Checks whether the device is formatted
#
# @return [Boolean]
def formatted?
!filesystem.nil?
end
# Removes the filesystem when the device is formatted
def delete_filesystem
return if filesystem.nil?
remove_descendants
end
# LVM physical volume defined on top of the device, either directly or
# through an encryption layer.
#
# @return [LvmPv] nil if neither the raw device or its encrypted version
# are used as physical volume
def lvm_pv
descendants.detect { |dev| dev.is?(:lvm_pv) && dev.plain_blk_device == plain_device }
end
# LVM physical volume defined directly on top of the device (no encryption
# or any other layer in between)
#
# @return [LvmPv] nil if the raw device is not used as physical volume
def direct_lvm_pv
descendants.detect { |dev| dev.is?(:lvm_pv) && dev.blk_device == self }
end
# MD array defined on top of the device, either directly or through an
# encryption layer.
#
# @return [Md] nil if neither the raw device or its encrypted version
# are used by an MD RAID device
def md
descendants.detect { |dev| dev.is?(:md) && dev.plain_devices.include?(plain_device) }
end
# MD array defined directly on top of the device (no encryption or any
# other layer in between)
#
# @return [Md] nil if the raw device is not used by any MD RAID device
def direct_md
descendants.detect { |dev| dev.is?(:md) && dev.devices.include?(self) }
end
# Label of the filesystem, if any
# @return [String, nil]
def filesystem_label
return nil unless blk_filesystem
blk_filesystem.label
end
# full path of the udev by-label link or `nil` if it does not exist.
# e.g. "/dev/disk/by-label/DATA"
# @see #udev_paths
# @return [String]
def udev_full_label
label = filesystem_label
return nil if label.nil? || label.empty?
File.join("/dev", "disk", "by-label", label)
end
# UUID of the filesystem, if any
# @return [String, nil]
def filesystem_uuid
return nil unless blk_filesystem
blk_filesystem.uuid
end
# full path of the udev by-uuid link or `nil` if it does not exist.
# e.g. "/dev/disk/by-uuid/a1dc747af-6ef7-44b9-b4f8-d200a5f933ec"
# @see #udev_paths
# @return [String]
def udev_full_uuid
uuid = filesystem_uuid
return nil if uuid.nil? || uuid.empty?
File.join("/dev", "disk", "by-uuid", uuid)
end
# Type of the filesystem, if any
# @return [Filesystems::Type, nil]
def filesystem_type
return nil unless blk_filesystem
blk_filesystem.type
end
# Mount point of the filesystem, if any
# @return [String, nil]
def filesystem_mountpoint
return nil unless blk_filesystem
blk_filesystem.mountpoint
end
# Non encrypted version of this device
#
# For most subclasses, this will simply return the device itself. To be
# redefined by encryption-related subclasses.
#
# @return [BlkDevice]
def plain_device
self
end
# Checks whether a new filesystem (encrypted or not) should be created for
# this device
#
# @param initial_devicegraph [Devicegraph] devicegraph to use as starting
# point when calculating the actions to perform
# @return [Boolean]
def to_be_formatted?(initial_devicegraph)
return false unless blk_filesystem
!blk_filesystem.exists_in_devicegraph?(initial_devicegraph)
end
# Last part of {#name}
#
# @example Get the device basename
# device.name # => "/dev/sda"
# device.basename # => "sda"
#
# @return [String]
def basename
name.split("/").last
end
# Return hardware information for the device
#
# @return [OpenStruct,nil] Hardware information; nil if no information was found.
#
# @see Y2Storage::HWInfoReader
def hwinfo
Y2Storage::HWInfoReader.instance.for_device(name)
end
end
end