]> git.proxmox.com Git - ceph.git/blame - ceph/src/ceph-volume/ceph_volume/util/disk.py
update sources to 12.2.2
[ceph.git] / ceph / src / ceph-volume / ceph_volume / util / disk.py
CommitLineData
3efd9988
FG
1import os
2import stat
181888fb
FG
3from ceph_volume import process
4
5
6def get_partuuid(device):
7 """
8 If a device is a partition, it will probably have a PARTUUID on it that
9 will persist and can be queried against `blkid` later to detect the actual
10 device
11 """
12 out, err, rc = process.call(
13 ['sudo', 'blkid', '-s', 'PARTUUID', '-o', 'value', device]
14 )
15 return ' '.join(out).strip()
16
17
18def get_device_from_partuuid(partuuid):
19 """
20 If a device has a partuuid, query blkid so that it can tell us what that
21 device is
22 """
23 out, err, rc = process.call(
24 ['sudo', 'blkid', '-t', 'PARTUUID="%s"' % partuuid, '-o', 'device']
25 )
26 return ' '.join(out).strip()
3efd9988
FG
27
28
29def _stat_is_device(stat_obj):
30 """
31 Helper function that will interpret ``os.stat`` output directly, so that other
32 functions can call ``os.stat`` once and interpret that result several times
33 """
34 return stat.S_ISBLK(stat_obj)
35
36
37def lsblk(device, columns=None):
38 """
39 Create a dictionary of identifying values for a device using ``lsblk``.
40 Each supported column is a key, in its *raw* format (all uppercase
41 usually). ``lsblk`` has support for certain "columns" (in blkid these
42 would be labels), and these columns vary between distributions and
43 ``lsblk`` versions. The newer versions support a richer set of columns,
44 while older ones were a bit limited.
45
46 These are the default lsblk columns reported which are safe to use for
47 Ubuntu 14.04.5 LTS:
48
49 NAME device name
50 KNAME internal kernel device name
51 MAJ:MIN major:minor device number
52 FSTYPE filesystem type
53 MOUNTPOINT where the device is mounted
54 LABEL filesystem LABEL
55 UUID filesystem UUID
56 RO read-only device
57 RM removable device
58 MODEL device identifier
59 SIZE size of the device
60 STATE state of the device
61 OWNER user name
62 GROUP group name
63 MODE device node permissions
64 ALIGNMENT alignment offset
65 MIN-IO minimum I/O size
66 OPT-IO optimal I/O size
67 PHY-SEC physical sector size
68 LOG-SEC logical sector size
69 ROTA rotational device
70 SCHED I/O scheduler name
71 RQ-SIZE request queue size
72 TYPE device type
73 DISC-ALN discard alignment offset
74 DISC-GRAN discard granularity
75 DISC-MAX discard max bytes
76 DISC-ZERO discard zeroes data
77
78 There is a bug in ``lsblk`` where using all the available (supported)
79 columns will result in no output (!), in order to workaround this the
80 following columns have been removed from the default reporting columns:
81
82 * RQ-SIZE (request queue size)
83 * MIN-IO minimum I/O size
84 * OPT-IO optimal I/O size
85
86 These should be available however when using `columns`. For example::
87
88 >>> lsblk('/dev/sda1', columns=['OPT-IO'])
89 {'OPT-IO': '0'}
90
91 Normal CLI output, as filtered by the flags in this function will look like ::
92
93 $ sudo lsblk --nodeps -P -o NAME,KNAME,MAJ:MIN,FSTYPE,MOUNTPOINT
94 NAME="sda1" KNAME="sda1" MAJ:MIN="8:1" FSTYPE="ext4" MOUNTPOINT="/"
95
96 :param columns: A list of columns to report as keys in its original form.
97 """
98 default_columns = [
99 'NAME', 'KNAME', 'MAJ:MIN', 'FSTYPE', 'MOUNTPOINT', 'LABEL', 'UUID',
100 'RO', 'RM', 'MODEL', 'SIZE', 'STATE', 'OWNER', 'GROUP', 'MODE',
101 'ALIGNMENT', 'PHY-SEC', 'LOG-SEC', 'ROTA', 'SCHED', 'TYPE', 'DISC-ALN',
102 'DISC-GRAN', 'DISC-MAX', 'DISC-ZERO'
103 ]
104 device = device.rstrip('/')
105 columns = columns or default_columns
106 # --nodeps -> Avoid adding children/parents to the device, only give information
107 # on the actual device we are querying for
108 # -P -> Produce pairs of COLUMN="value"
109 # -o -> Use the columns specified or default ones provided by this function
110 command = ['sudo', 'lsblk', '--nodeps', '-P', '-o']
111 command.append(','.join(columns))
112 command.append(device)
113 out, err, rc = process.call(command)
114
115 if rc != 0:
116 return {}
117
118 # parse the COLUMN="value" output to construct the dictionary
119 pairs = ' '.join(out).split()
120 parsed = {}
121 for pair in pairs:
122 try:
123 column, value = pair.split('=')
124 except ValueError:
125 continue
126 parsed[column] = value.strip().strip().strip('"')
127 return parsed
128
129
130def _lsblk_type(device):
131 """
132 Helper function that will use the ``TYPE`` label output of ``lsblk`` to determine
133 if a device is a partition or disk.
134 It does not process the output to return a boolean, but it does process it to return the
135 """
136 out, err, rc = process.call(
137 ['sudo', 'blkid', '-s', 'PARTUUID', '-o', 'value', device]
138 )
139 return ' '.join(out).strip()
140
141
142def is_device(dev):
143 """
144 Boolean to determine if a given device is a block device (**not**
145 a partition!)
146
147 For example: /dev/sda would return True, but not /dev/sdc1
148 """
149 if not os.path.exists(dev):
150 return False
151 # use lsblk first, fall back to using stat
152 TYPE = lsblk(dev).get('TYPE')
153 if TYPE:
154 return TYPE == 'disk'
155
156 # fallback to stat
157 return _stat_is_device(os.lstat(dev).st_mode)
158 if stat.S_ISBLK(os.lstat(dev)):
159 return True
160 return False
161
162
163def is_partition(dev):
164 """
165 Boolean to determine if a given device is a partition, like /dev/sda1
166 """
167 if not os.path.exists(dev):
168 return False
169 # use lsblk first, fall back to using stat
170 TYPE = lsblk(dev).get('TYPE')
171 if TYPE:
172 return TYPE == 'part'
173
174 # fallback to stat
175 stat_obj = os.stat(dev)
176 if _stat_is_device(stat_obj.st_mode):
177 return False
178
179 major = os.major(stat_obj.st_rdev)
180 minor = os.minor(stat_obj.st_rdev)
181 if os.path.exists('/sys/dev/block/%d:%d/partition' % (major, minor)):
182 return True
183 return False