]>
git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/util/disk.py
3 from ceph_volume
import process
6 # The blkid CLI tool has some oddities which prevents having one common call
7 # to extract the information instead of having separate utilities. The `udev`
8 # type of output is needed in older versions of blkid (v 2.23) that will not
9 # work correctly with just the ``-p`` flag to bypass the cache for example.
10 # Xenial doesn't have this problem as it uses a newer blkid version.
13 def get_partuuid(device
):
15 If a device is a partition, it will probably have a PARTUUID on it that
16 will persist and can be queried against `blkid` later to detect the actual
19 out
, err
, rc
= process
.call(
20 ['blkid', '-s', 'PARTUUID', '-o', 'value', device
]
22 return ' '.join(out
).strip()
25 def get_part_entry_type(device
):
27 Parses the ``ID_PART_ENTRY_TYPE`` from the "low level" (bypasses the cache)
28 output that uses the ``udev`` type of output. This output is intended to be
29 used for udev rules, but it is useful in this case as it is the only
30 consistent way to retrieve the GUID used by ceph-disk to identify devices.
32 out
, err
, rc
= process
.call(['blkid', '-p', '-o', 'udev', device
])
34 if 'ID_PART_ENTRY_TYPE=' in line
:
35 return line
.split('=')[-1].strip()
39 def get_device_from_partuuid(partuuid
):
41 If a device has a partuuid, query blkid so that it can tell us what that
44 out
, err
, rc
= process
.call(
45 ['blkid', '-t', 'PARTUUID="%s"' % partuuid
, '-o', 'device']
47 return ' '.join(out
).strip()
50 def _stat_is_device(stat_obj
):
52 Helper function that will interpret ``os.stat`` output directly, so that other
53 functions can call ``os.stat`` once and interpret that result several times
55 return stat
.S_ISBLK(stat_obj
)
58 def _lsblk_parser(line
):
60 Parses lines in lsblk output. Requires output to be in pair mode (``-P`` flag). Lines
61 need to be whole strings, the line gets split when processed.
63 :param line: A string, with the full line from lsblk output
65 # parse the COLUMN="value" output to construct the dictionary
66 pairs
= line
.split('" ')
70 column
, value
= pair
.split('=')
73 parsed
[column
] = value
.strip().strip().strip('"')
77 def device_family(device
):
79 Returns a list of associated devices. It assumes that ``device`` is
80 a parent device. It is up to the caller to ensure that the device being
81 used is a parent, not a partition.
83 labels
= ['NAME', 'PARTLABEL', 'TYPE']
84 command
= ['lsblk', '-P', '-p', '-o', ','.join(labels
), device
]
85 out
, err
, rc
= process
.call(command
)
88 devices
.append(_lsblk_parser(line
))
93 def lsblk(device
, columns
=None, abspath
=False):
95 Create a dictionary of identifying values for a device using ``lsblk``.
96 Each supported column is a key, in its *raw* format (all uppercase
97 usually). ``lsblk`` has support for certain "columns" (in blkid these
98 would be labels), and these columns vary between distributions and
99 ``lsblk`` versions. The newer versions support a richer set of columns,
100 while older ones were a bit limited.
102 These are a subset of lsblk columns which are known to work on both CentOS 7 and Xenial:
105 KNAME internal kernel device name
106 MAJ:MIN major:minor device number
107 FSTYPE filesystem type
108 MOUNTPOINT where the device is mounted
109 LABEL filesystem LABEL
113 MODEL device identifier
114 SIZE size of the device
115 STATE state of the device
118 MODE device node permissions
119 ALIGNMENT alignment offset
120 MIN-IO minimum I/O size
121 OPT-IO optimal I/O size
122 PHY-SEC physical sector size
123 LOG-SEC logical sector size
124 ROTA rotational device
125 SCHED I/O scheduler name
126 RQ-SIZE request queue size
128 PKNAME internal parent kernel device name
129 DISC-ALN discard alignment offset
130 DISC-GRAN discard granularity
131 DISC-MAX discard max bytes
132 DISC-ZERO discard zeroes data
134 There is a bug in ``lsblk`` where using all the available (supported)
135 columns will result in no output (!), in order to workaround this the
136 following columns have been removed from the default reporting columns:
138 * RQ-SIZE (request queue size)
139 * MIN-IO minimum I/O size
140 * OPT-IO optimal I/O size
142 These should be available however when using `columns`. For example::
144 >>> lsblk('/dev/sda1', columns=['OPT-IO'])
147 Normal CLI output, as filtered by the flags in this function will look like ::
149 $ lsblk --nodeps -P -o NAME,KNAME,MAJ:MIN,FSTYPE,MOUNTPOINT
150 NAME="sda1" KNAME="sda1" MAJ:MIN="8:1" FSTYPE="ext4" MOUNTPOINT="/"
152 :param columns: A list of columns to report as keys in its original form.
153 :param abspath: Set the flag for absolute paths on the report
156 'NAME', 'KNAME', 'MAJ:MIN', 'FSTYPE', 'MOUNTPOINT', 'LABEL', 'UUID',
157 'RO', 'RM', 'MODEL', 'SIZE', 'STATE', 'OWNER', 'GROUP', 'MODE',
158 'ALIGNMENT', 'PHY-SEC', 'LOG-SEC', 'ROTA', 'SCHED', 'TYPE', 'DISC-ALN',
159 'DISC-GRAN', 'DISC-MAX', 'DISC-ZERO', 'PKNAME', 'PARTLABEL'
161 device
= device
.rstrip('/')
162 columns
= columns
or default_columns
163 # --nodeps -> Avoid adding children/parents to the device, only give information
164 # on the actual device we are querying for
165 # -P -> Produce pairs of COLUMN="value"
166 # -p -> Return full paths to devices, not just the names, when ``abspath`` is set
167 # -o -> Use the columns specified or default ones provided by this function
168 base_command
= ['lsblk', '--nodeps', '-P']
170 base_command
.append('-p')
171 base_command
.append('-o')
172 base_command
.append(','.join(columns
))
173 base_command
.append(device
)
174 out
, err
, rc
= process
.call(base_command
)
179 return _lsblk_parser(' '.join(out
))
184 Boolean to determine if a given device is a block device (**not**
187 For example: /dev/sda would return True, but not /dev/sdc1
189 if not os
.path
.exists(dev
):
191 # use lsblk first, fall back to using stat
192 TYPE
= lsblk(dev
).get('TYPE')
194 return TYPE
== 'disk'
197 return _stat_is_device(os
.lstat(dev
).st_mode
)
198 if stat
.S_ISBLK(os
.lstat(dev
)):
203 def is_partition(dev
):
205 Boolean to determine if a given device is a partition, like /dev/sda1
207 if not os
.path
.exists(dev
):
209 # use lsblk first, fall back to using stat
210 TYPE
= lsblk(dev
).get('TYPE')
212 return TYPE
== 'part'
215 stat_obj
= os
.stat(dev
)
216 if _stat_is_device(stat_obj
.st_mode
):
219 major
= os
.major(stat_obj
.st_rdev
)
220 minor
= os
.minor(stat_obj
.st_rdev
)
221 if os
.path
.exists('/sys/dev/block/%d:%d/partition' % (major
, minor
)):