root / lib / storage / base.py @ ba174485
History | View | Annotate | Download (13 kB)
1 | 89ff748d | Thomas Thrainer | #
|
---|---|---|---|
2 | 89ff748d | Thomas Thrainer | #
|
3 | 89ff748d | Thomas Thrainer | |
4 | 89ff748d | Thomas Thrainer | # Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 Google Inc.
|
5 | 89ff748d | Thomas Thrainer | #
|
6 | 89ff748d | Thomas Thrainer | # This program is free software; you can redistribute it and/or modify
|
7 | 89ff748d | Thomas Thrainer | # it under the terms of the GNU General Public License as published by
|
8 | 89ff748d | Thomas Thrainer | # the Free Software Foundation; either version 2 of the License, or
|
9 | 89ff748d | Thomas Thrainer | # (at your option) any later version.
|
10 | 89ff748d | Thomas Thrainer | #
|
11 | 89ff748d | Thomas Thrainer | # This program is distributed in the hope that it will be useful, but
|
12 | 89ff748d | Thomas Thrainer | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 89ff748d | Thomas Thrainer | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 89ff748d | Thomas Thrainer | # General Public License for more details.
|
15 | 89ff748d | Thomas Thrainer | #
|
16 | 89ff748d | Thomas Thrainer | # You should have received a copy of the GNU General Public License
|
17 | 89ff748d | Thomas Thrainer | # along with this program; if not, write to the Free Software
|
18 | 89ff748d | Thomas Thrainer | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | 89ff748d | Thomas Thrainer | # 02110-1301, USA.
|
20 | 89ff748d | Thomas Thrainer | |
21 | 89ff748d | Thomas Thrainer | |
22 | 89ff748d | Thomas Thrainer | """Block device abstraction - base class and utility functions"""
|
23 | 89ff748d | Thomas Thrainer | |
24 | 89ff748d | Thomas Thrainer | import logging |
25 | 89ff748d | Thomas Thrainer | |
26 | 89ff748d | Thomas Thrainer | from ganeti import objects |
27 | 89ff748d | Thomas Thrainer | from ganeti import constants |
28 | 89ff748d | Thomas Thrainer | from ganeti import utils |
29 | 89ff748d | Thomas Thrainer | from ganeti import errors |
30 | 89ff748d | Thomas Thrainer | |
31 | 89ff748d | Thomas Thrainer | |
32 | 89ff748d | Thomas Thrainer | class BlockDev(object): |
33 | 89ff748d | Thomas Thrainer | """Block device abstract class.
|
34 | 89ff748d | Thomas Thrainer |
|
35 | 89ff748d | Thomas Thrainer | A block device can be in the following states:
|
36 | 89ff748d | Thomas Thrainer | - not existing on the system, and by `Create()` it goes into:
|
37 | 89ff748d | Thomas Thrainer | - existing but not setup/not active, and by `Assemble()` goes into:
|
38 | 89ff748d | Thomas Thrainer | - active read-write and by `Open()` it goes into
|
39 | 89ff748d | Thomas Thrainer | - online (=used, or ready for use)
|
40 | 89ff748d | Thomas Thrainer |
|
41 | 89ff748d | Thomas Thrainer | A device can also be online but read-only, however we are not using
|
42 | 89ff748d | Thomas Thrainer | the readonly state (LV has it, if needed in the future) and we are
|
43 | 89ff748d | Thomas Thrainer | usually looking at this like at a stack, so it's easier to
|
44 | 89ff748d | Thomas Thrainer | conceptualise the transition from not-existing to online and back
|
45 | 89ff748d | Thomas Thrainer | like a linear one.
|
46 | 89ff748d | Thomas Thrainer |
|
47 | 89ff748d | Thomas Thrainer | The many different states of the device are due to the fact that we
|
48 | 89ff748d | Thomas Thrainer | need to cover many device types:
|
49 | 89ff748d | Thomas Thrainer | - logical volumes are created, lvchange -a y $lv, and used
|
50 | 89ff748d | Thomas Thrainer | - drbd devices are attached to a local disk/remote peer and made primary
|
51 | 89ff748d | Thomas Thrainer |
|
52 | 89ff748d | Thomas Thrainer | A block device is identified by three items:
|
53 | 89ff748d | Thomas Thrainer | - the /dev path of the device (dynamic)
|
54 | 89ff748d | Thomas Thrainer | - a unique ID of the device (static)
|
55 | 89ff748d | Thomas Thrainer | - it's major/minor pair (dynamic)
|
56 | 89ff748d | Thomas Thrainer |
|
57 | 89ff748d | Thomas Thrainer | Not all devices implement both the first two as distinct items. LVM
|
58 | 89ff748d | Thomas Thrainer | logical volumes have their unique ID (the pair volume group, logical
|
59 | 89ff748d | Thomas Thrainer | volume name) in a 1-to-1 relation to the dev path. For DRBD devices,
|
60 | 89ff748d | Thomas Thrainer | the /dev path is again dynamic and the unique id is the pair (host1,
|
61 | 89ff748d | Thomas Thrainer | dev1), (host2, dev2).
|
62 | 89ff748d | Thomas Thrainer |
|
63 | 89ff748d | Thomas Thrainer | You can get to a device in two ways:
|
64 | 89ff748d | Thomas Thrainer | - creating the (real) device, which returns you
|
65 | 89ff748d | Thomas Thrainer | an attached instance (lvcreate)
|
66 | 89ff748d | Thomas Thrainer | - attaching of a python instance to an existing (real) device
|
67 | 89ff748d | Thomas Thrainer |
|
68 | 89ff748d | Thomas Thrainer | The second point, the attachment to a device, is different
|
69 | 89ff748d | Thomas Thrainer | depending on whether the device is assembled or not. At init() time,
|
70 | 89ff748d | Thomas Thrainer | we search for a device with the same unique_id as us. If found,
|
71 | 89ff748d | Thomas Thrainer | good. It also means that the device is already assembled. If not,
|
72 | 89ff748d | Thomas Thrainer | after assembly we'll have our correct major/minor.
|
73 | 89ff748d | Thomas Thrainer |
|
74 | 89ff748d | Thomas Thrainer | """
|
75 | 0c3d9c7c | Thomas Thrainer | def __init__(self, unique_id, children, size, params, dyn_params): |
76 | 89ff748d | Thomas Thrainer | self._children = children
|
77 | 89ff748d | Thomas Thrainer | self.dev_path = None |
78 | 89ff748d | Thomas Thrainer | self.unique_id = unique_id
|
79 | 89ff748d | Thomas Thrainer | self.major = None |
80 | 89ff748d | Thomas Thrainer | self.minor = None |
81 | 89ff748d | Thomas Thrainer | self.attached = False |
82 | 89ff748d | Thomas Thrainer | self.size = size
|
83 | 89ff748d | Thomas Thrainer | self.params = params
|
84 | 0c3d9c7c | Thomas Thrainer | self.dyn_params = dyn_params
|
85 | 89ff748d | Thomas Thrainer | |
86 | 89ff748d | Thomas Thrainer | def Assemble(self): |
87 | 89ff748d | Thomas Thrainer | """Assemble the device from its components.
|
88 | 89ff748d | Thomas Thrainer |
|
89 | 89ff748d | Thomas Thrainer | Implementations of this method by child classes must ensure that:
|
90 | 89ff748d | Thomas Thrainer | - after the device has been assembled, it knows its major/minor
|
91 | 89ff748d | Thomas Thrainer | numbers; this allows other devices (usually parents) to probe
|
92 | 89ff748d | Thomas Thrainer | correctly for their children
|
93 | 89ff748d | Thomas Thrainer | - calling this method on an existing, in-use device is safe
|
94 | 89ff748d | Thomas Thrainer | - if the device is already configured (and in an OK state),
|
95 | 89ff748d | Thomas Thrainer | this method is idempotent
|
96 | 89ff748d | Thomas Thrainer |
|
97 | 89ff748d | Thomas Thrainer | """
|
98 | 89ff748d | Thomas Thrainer | pass
|
99 | 89ff748d | Thomas Thrainer | |
100 | 89ff748d | Thomas Thrainer | def Attach(self): |
101 | 89ff748d | Thomas Thrainer | """Find a device which matches our config and attach to it.
|
102 | 89ff748d | Thomas Thrainer |
|
103 | 89ff748d | Thomas Thrainer | """
|
104 | 89ff748d | Thomas Thrainer | raise NotImplementedError |
105 | 89ff748d | Thomas Thrainer | |
106 | 89ff748d | Thomas Thrainer | def Close(self): |
107 | 89ff748d | Thomas Thrainer | """Notifies that the device will no longer be used for I/O.
|
108 | 89ff748d | Thomas Thrainer |
|
109 | 89ff748d | Thomas Thrainer | """
|
110 | 89ff748d | Thomas Thrainer | raise NotImplementedError |
111 | 89ff748d | Thomas Thrainer | |
112 | 89ff748d | Thomas Thrainer | @classmethod
|
113 | 0c3d9c7c | Thomas Thrainer | def Create(cls, unique_id, children, size, spindles, params, excl_stor, |
114 | 0c3d9c7c | Thomas Thrainer | dyn_params): |
115 | 89ff748d | Thomas Thrainer | """Create the device.
|
116 | 89ff748d | Thomas Thrainer |
|
117 | 89ff748d | Thomas Thrainer | If the device cannot be created, it will return None
|
118 | 89ff748d | Thomas Thrainer | instead. Error messages go to the logging system.
|
119 | 89ff748d | Thomas Thrainer |
|
120 | 89ff748d | Thomas Thrainer | Note that for some devices, the unique_id is used, and for other,
|
121 | 89ff748d | Thomas Thrainer | the children. The idea is that these two, taken together, are
|
122 | 89ff748d | Thomas Thrainer | enough for both creation and assembly (later).
|
123 | 89ff748d | Thomas Thrainer |
|
124 | 5073fa0c | Bernardo Dal Seno | @type unique_id: 2-element tuple or list
|
125 | 5073fa0c | Bernardo Dal Seno | @param unique_id: unique identifier; the details depend on the actual device
|
126 | 5073fa0c | Bernardo Dal Seno | type
|
127 | 5073fa0c | Bernardo Dal Seno | @type children: list of L{BlockDev}
|
128 | 5073fa0c | Bernardo Dal Seno | @param children: for hierarchical devices, the child devices
|
129 | 5073fa0c | Bernardo Dal Seno | @type size: float
|
130 | 5073fa0c | Bernardo Dal Seno | @param size: size in MiB
|
131 | 24c06acb | Bernardo Dal Seno | @type spindles: int
|
132 | 24c06acb | Bernardo Dal Seno | @param spindles: number of physical disk to dedicate to the device
|
133 | 5073fa0c | Bernardo Dal Seno | @type params: dict
|
134 | 5073fa0c | Bernardo Dal Seno | @param params: device-specific options/parameters
|
135 | 5073fa0c | Bernardo Dal Seno | @type excl_stor: bool
|
136 | 5073fa0c | Bernardo Dal Seno | @param excl_stor: whether exclusive_storage is active
|
137 | 0c3d9c7c | Thomas Thrainer | @type dyn_params: dict
|
138 | 0c3d9c7c | Thomas Thrainer | @param dyn_params: dynamic parameters of the disk only valid for this node.
|
139 | 0c3d9c7c | Thomas Thrainer | As set by L{objects.Disk.UpdateDynamicDiskParams}.
|
140 | 5073fa0c | Bernardo Dal Seno | @rtype: L{BlockDev}
|
141 | 5073fa0c | Bernardo Dal Seno | @return: the created device, or C{None} in case of an error
|
142 | 5073fa0c | Bernardo Dal Seno |
|
143 | 89ff748d | Thomas Thrainer | """
|
144 | 89ff748d | Thomas Thrainer | raise NotImplementedError |
145 | 89ff748d | Thomas Thrainer | |
146 | 89ff748d | Thomas Thrainer | def Remove(self): |
147 | 89ff748d | Thomas Thrainer | """Remove this device.
|
148 | 89ff748d | Thomas Thrainer |
|
149 | 89ff748d | Thomas Thrainer | This makes sense only for some of the device types: LV and file
|
150 | 89ff748d | Thomas Thrainer | storage. Also note that if the device can't attach, the removal
|
151 | 89ff748d | Thomas Thrainer | can't be completed.
|
152 | 89ff748d | Thomas Thrainer |
|
153 | 89ff748d | Thomas Thrainer | """
|
154 | 89ff748d | Thomas Thrainer | raise NotImplementedError |
155 | 89ff748d | Thomas Thrainer | |
156 | 89ff748d | Thomas Thrainer | def Rename(self, new_id): |
157 | 89ff748d | Thomas Thrainer | """Rename this device.
|
158 | 89ff748d | Thomas Thrainer |
|
159 | 89ff748d | Thomas Thrainer | This may or may not make sense for a given device type.
|
160 | 89ff748d | Thomas Thrainer |
|
161 | 89ff748d | Thomas Thrainer | """
|
162 | 89ff748d | Thomas Thrainer | raise NotImplementedError |
163 | 89ff748d | Thomas Thrainer | |
164 | 89ff748d | Thomas Thrainer | def Open(self, force=False): |
165 | 89ff748d | Thomas Thrainer | """Make the device ready for use.
|
166 | 89ff748d | Thomas Thrainer |
|
167 | 89ff748d | Thomas Thrainer | This makes the device ready for I/O. For now, just the DRBD
|
168 | 89ff748d | Thomas Thrainer | devices need this.
|
169 | 89ff748d | Thomas Thrainer |
|
170 | 89ff748d | Thomas Thrainer | The force parameter signifies that if the device has any kind of
|
171 | 89ff748d | Thomas Thrainer | --force thing, it should be used, we know what we are doing.
|
172 | 89ff748d | Thomas Thrainer |
|
173 | 47e0abee | Thomas Thrainer | @type force: boolean
|
174 | 47e0abee | Thomas Thrainer |
|
175 | 89ff748d | Thomas Thrainer | """
|
176 | 89ff748d | Thomas Thrainer | raise NotImplementedError |
177 | 89ff748d | Thomas Thrainer | |
178 | 89ff748d | Thomas Thrainer | def Shutdown(self): |
179 | 89ff748d | Thomas Thrainer | """Shut down the device, freeing its children.
|
180 | 89ff748d | Thomas Thrainer |
|
181 | 89ff748d | Thomas Thrainer | This undoes the `Assemble()` work, except for the child
|
182 | 89ff748d | Thomas Thrainer | assembling; as such, the children on the device are still
|
183 | 89ff748d | Thomas Thrainer | assembled after this call.
|
184 | 89ff748d | Thomas Thrainer |
|
185 | 89ff748d | Thomas Thrainer | """
|
186 | 89ff748d | Thomas Thrainer | raise NotImplementedError |
187 | 89ff748d | Thomas Thrainer | |
188 | 89ff748d | Thomas Thrainer | def SetSyncParams(self, params): |
189 | 89ff748d | Thomas Thrainer | """Adjust the synchronization parameters of the mirror.
|
190 | 89ff748d | Thomas Thrainer |
|
191 | 89ff748d | Thomas Thrainer | In case this is not a mirroring device, this is no-op.
|
192 | 89ff748d | Thomas Thrainer |
|
193 | 89ff748d | Thomas Thrainer | @param params: dictionary of LD level disk parameters related to the
|
194 | 89ff748d | Thomas Thrainer | synchronization.
|
195 | 89ff748d | Thomas Thrainer | @rtype: list
|
196 | 89ff748d | Thomas Thrainer | @return: a list of error messages, emitted both by the current node and by
|
197 | 89ff748d | Thomas Thrainer | children. An empty list means no errors.
|
198 | 89ff748d | Thomas Thrainer |
|
199 | 89ff748d | Thomas Thrainer | """
|
200 | 89ff748d | Thomas Thrainer | result = [] |
201 | 89ff748d | Thomas Thrainer | if self._children: |
202 | 89ff748d | Thomas Thrainer | for child in self._children: |
203 | 89ff748d | Thomas Thrainer | result.extend(child.SetSyncParams(params)) |
204 | 89ff748d | Thomas Thrainer | return result
|
205 | 89ff748d | Thomas Thrainer | |
206 | 89ff748d | Thomas Thrainer | def PauseResumeSync(self, pause): |
207 | 89ff748d | Thomas Thrainer | """Pause/Resume the sync of the mirror.
|
208 | 89ff748d | Thomas Thrainer |
|
209 | 89ff748d | Thomas Thrainer | In case this is not a mirroring device, this is no-op.
|
210 | 89ff748d | Thomas Thrainer |
|
211 | 47e0abee | Thomas Thrainer | @type pause: boolean
|
212 | 89ff748d | Thomas Thrainer | @param pause: Whether to pause or resume
|
213 | 89ff748d | Thomas Thrainer |
|
214 | 89ff748d | Thomas Thrainer | """
|
215 | 89ff748d | Thomas Thrainer | result = True
|
216 | 89ff748d | Thomas Thrainer | if self._children: |
217 | 89ff748d | Thomas Thrainer | for child in self._children: |
218 | 89ff748d | Thomas Thrainer | result = result and child.PauseResumeSync(pause)
|
219 | 89ff748d | Thomas Thrainer | return result
|
220 | 89ff748d | Thomas Thrainer | |
221 | 89ff748d | Thomas Thrainer | def GetSyncStatus(self): |
222 | 89ff748d | Thomas Thrainer | """Returns the sync status of the device.
|
223 | 89ff748d | Thomas Thrainer |
|
224 | 89ff748d | Thomas Thrainer | If this device is a mirroring device, this function returns the
|
225 | 89ff748d | Thomas Thrainer | status of the mirror.
|
226 | 89ff748d | Thomas Thrainer |
|
227 | 89ff748d | Thomas Thrainer | If sync_percent is None, it means the device is not syncing.
|
228 | 89ff748d | Thomas Thrainer |
|
229 | 89ff748d | Thomas Thrainer | If estimated_time is None, it means we can't estimate
|
230 | 89ff748d | Thomas Thrainer | the time needed, otherwise it's the time left in seconds.
|
231 | 89ff748d | Thomas Thrainer |
|
232 | 89ff748d | Thomas Thrainer | If is_degraded is True, it means the device is missing
|
233 | 89ff748d | Thomas Thrainer | redundancy. This is usually a sign that something went wrong in
|
234 | 89ff748d | Thomas Thrainer | the device setup, if sync_percent is None.
|
235 | 89ff748d | Thomas Thrainer |
|
236 | 89ff748d | Thomas Thrainer | The ldisk parameter represents the degradation of the local
|
237 | 89ff748d | Thomas Thrainer | data. This is only valid for some devices, the rest will always
|
238 | 89ff748d | Thomas Thrainer | return False (not degraded).
|
239 | 89ff748d | Thomas Thrainer |
|
240 | 89ff748d | Thomas Thrainer | @rtype: objects.BlockDevStatus
|
241 | 89ff748d | Thomas Thrainer |
|
242 | 89ff748d | Thomas Thrainer | """
|
243 | 89ff748d | Thomas Thrainer | return objects.BlockDevStatus(dev_path=self.dev_path, |
244 | 89ff748d | Thomas Thrainer | major=self.major,
|
245 | 89ff748d | Thomas Thrainer | minor=self.minor,
|
246 | 89ff748d | Thomas Thrainer | sync_percent=None,
|
247 | 89ff748d | Thomas Thrainer | estimated_time=None,
|
248 | 89ff748d | Thomas Thrainer | is_degraded=False,
|
249 | 89ff748d | Thomas Thrainer | ldisk_status=constants.LDS_OKAY) |
250 | 89ff748d | Thomas Thrainer | |
251 | 89ff748d | Thomas Thrainer | def CombinedSyncStatus(self): |
252 | 89ff748d | Thomas Thrainer | """Calculate the mirror status recursively for our children.
|
253 | 89ff748d | Thomas Thrainer |
|
254 | 89ff748d | Thomas Thrainer | The return value is the same as for `GetSyncStatus()` except the
|
255 | 89ff748d | Thomas Thrainer | minimum percent and maximum time are calculated across our
|
256 | 89ff748d | Thomas Thrainer | children.
|
257 | 89ff748d | Thomas Thrainer |
|
258 | 89ff748d | Thomas Thrainer | @rtype: objects.BlockDevStatus
|
259 | 89ff748d | Thomas Thrainer |
|
260 | 89ff748d | Thomas Thrainer | """
|
261 | 89ff748d | Thomas Thrainer | status = self.GetSyncStatus()
|
262 | 89ff748d | Thomas Thrainer | |
263 | 89ff748d | Thomas Thrainer | min_percent = status.sync_percent |
264 | 89ff748d | Thomas Thrainer | max_time = status.estimated_time |
265 | 89ff748d | Thomas Thrainer | is_degraded = status.is_degraded |
266 | 89ff748d | Thomas Thrainer | ldisk_status = status.ldisk_status |
267 | 89ff748d | Thomas Thrainer | |
268 | 89ff748d | Thomas Thrainer | if self._children: |
269 | 89ff748d | Thomas Thrainer | for child in self._children: |
270 | 89ff748d | Thomas Thrainer | child_status = child.GetSyncStatus() |
271 | 89ff748d | Thomas Thrainer | |
272 | 89ff748d | Thomas Thrainer | if min_percent is None: |
273 | 89ff748d | Thomas Thrainer | min_percent = child_status.sync_percent |
274 | 89ff748d | Thomas Thrainer | elif child_status.sync_percent is not None: |
275 | 89ff748d | Thomas Thrainer | min_percent = min(min_percent, child_status.sync_percent)
|
276 | 89ff748d | Thomas Thrainer | |
277 | 89ff748d | Thomas Thrainer | if max_time is None: |
278 | 89ff748d | Thomas Thrainer | max_time = child_status.estimated_time |
279 | 89ff748d | Thomas Thrainer | elif child_status.estimated_time is not None: |
280 | 89ff748d | Thomas Thrainer | max_time = max(max_time, child_status.estimated_time)
|
281 | 89ff748d | Thomas Thrainer | |
282 | 89ff748d | Thomas Thrainer | is_degraded = is_degraded or child_status.is_degraded
|
283 | 89ff748d | Thomas Thrainer | |
284 | 89ff748d | Thomas Thrainer | if ldisk_status is None: |
285 | 89ff748d | Thomas Thrainer | ldisk_status = child_status.ldisk_status |
286 | 89ff748d | Thomas Thrainer | elif child_status.ldisk_status is not None: |
287 | 89ff748d | Thomas Thrainer | ldisk_status = max(ldisk_status, child_status.ldisk_status)
|
288 | 89ff748d | Thomas Thrainer | |
289 | 89ff748d | Thomas Thrainer | return objects.BlockDevStatus(dev_path=self.dev_path, |
290 | 89ff748d | Thomas Thrainer | major=self.major,
|
291 | 89ff748d | Thomas Thrainer | minor=self.minor,
|
292 | 89ff748d | Thomas Thrainer | sync_percent=min_percent, |
293 | 89ff748d | Thomas Thrainer | estimated_time=max_time, |
294 | 89ff748d | Thomas Thrainer | is_degraded=is_degraded, |
295 | 89ff748d | Thomas Thrainer | ldisk_status=ldisk_status) |
296 | 89ff748d | Thomas Thrainer | |
297 | 89ff748d | Thomas Thrainer | def SetInfo(self, text): |
298 | 89ff748d | Thomas Thrainer | """Update metadata with info text.
|
299 | 89ff748d | Thomas Thrainer |
|
300 | 89ff748d | Thomas Thrainer | Only supported for some device types.
|
301 | 89ff748d | Thomas Thrainer |
|
302 | 89ff748d | Thomas Thrainer | """
|
303 | 89ff748d | Thomas Thrainer | for child in self._children: |
304 | 89ff748d | Thomas Thrainer | child.SetInfo(text) |
305 | 89ff748d | Thomas Thrainer | |
306 | be9150ea | Bernardo Dal Seno | def Grow(self, amount, dryrun, backingstore, excl_stor): |
307 | 89ff748d | Thomas Thrainer | """Grow the block device.
|
308 | 89ff748d | Thomas Thrainer |
|
309 | 89ff748d | Thomas Thrainer | @type amount: integer
|
310 | 89ff748d | Thomas Thrainer | @param amount: the amount (in mebibytes) to grow with
|
311 | 89ff748d | Thomas Thrainer | @type dryrun: boolean
|
312 | 89ff748d | Thomas Thrainer | @param dryrun: whether to execute the operation in simulation mode
|
313 | 89ff748d | Thomas Thrainer | only, without actually increasing the size
|
314 | 89ff748d | Thomas Thrainer | @param backingstore: whether to execute the operation on backing storage
|
315 | 89ff748d | Thomas Thrainer | only, or on "logical" storage only; e.g. DRBD is logical storage,
|
316 | 89ff748d | Thomas Thrainer | whereas LVM, file, RBD are backing storage
|
317 | be9150ea | Bernardo Dal Seno | @type excl_stor: boolean
|
318 | be9150ea | Bernardo Dal Seno | @param excl_stor: Whether exclusive_storage is active
|
319 | 89ff748d | Thomas Thrainer |
|
320 | 89ff748d | Thomas Thrainer | """
|
321 | 89ff748d | Thomas Thrainer | raise NotImplementedError |
322 | 89ff748d | Thomas Thrainer | |
323 | 89ff748d | Thomas Thrainer | def GetActualSize(self): |
324 | 89ff748d | Thomas Thrainer | """Return the actual disk size.
|
325 | 89ff748d | Thomas Thrainer |
|
326 | 89ff748d | Thomas Thrainer | @note: the device needs to be active when this is called
|
327 | 89ff748d | Thomas Thrainer |
|
328 | 89ff748d | Thomas Thrainer | """
|
329 | 89ff748d | Thomas Thrainer | assert self.attached, "BlockDevice not attached in GetActualSize()" |
330 | 89ff748d | Thomas Thrainer | result = utils.RunCmd(["blockdev", "--getsize64", self.dev_path]) |
331 | 89ff748d | Thomas Thrainer | if result.failed:
|
332 | 89ff748d | Thomas Thrainer | ThrowError("blockdev failed (%s): %s",
|
333 | 89ff748d | Thomas Thrainer | result.fail_reason, result.output) |
334 | 89ff748d | Thomas Thrainer | try:
|
335 | 89ff748d | Thomas Thrainer | sz = int(result.output.strip())
|
336 | 89ff748d | Thomas Thrainer | except (ValueError, TypeError), err: |
337 | 89ff748d | Thomas Thrainer | ThrowError("Failed to parse blockdev output: %s", str(err)) |
338 | 89ff748d | Thomas Thrainer | return sz
|
339 | 89ff748d | Thomas Thrainer | |
340 | baa7f1d6 | Bernardo Dal Seno | def GetActualSpindles(self): |
341 | baa7f1d6 | Bernardo Dal Seno | """Return the actual number of spindles used.
|
342 | baa7f1d6 | Bernardo Dal Seno |
|
343 | baa7f1d6 | Bernardo Dal Seno | This is not supported by all devices; if not supported, C{None} is returned.
|
344 | baa7f1d6 | Bernardo Dal Seno |
|
345 | baa7f1d6 | Bernardo Dal Seno | @note: the device needs to be active when this is called
|
346 | baa7f1d6 | Bernardo Dal Seno |
|
347 | baa7f1d6 | Bernardo Dal Seno | """
|
348 | baa7f1d6 | Bernardo Dal Seno | assert self.attached, "BlockDevice not attached in GetActualSpindles()" |
349 | baa7f1d6 | Bernardo Dal Seno | return None |
350 | baa7f1d6 | Bernardo Dal Seno | |
351 | baa7f1d6 | Bernardo Dal Seno | def GetActualDimensions(self): |
352 | baa7f1d6 | Bernardo Dal Seno | """Return the actual disk size and number of spindles used.
|
353 | baa7f1d6 | Bernardo Dal Seno |
|
354 | baa7f1d6 | Bernardo Dal Seno | @rtype: tuple
|
355 | baa7f1d6 | Bernardo Dal Seno | @return: (size, spindles); spindles is C{None} when they are not supported
|
356 | baa7f1d6 | Bernardo Dal Seno |
|
357 | baa7f1d6 | Bernardo Dal Seno | @note: the device needs to be active when this is called
|
358 | baa7f1d6 | Bernardo Dal Seno |
|
359 | baa7f1d6 | Bernardo Dal Seno | """
|
360 | baa7f1d6 | Bernardo Dal Seno | return (self.GetActualSize(), self.GetActualSpindles()) |
361 | baa7f1d6 | Bernardo Dal Seno | |
362 | f83057ad | Raffa Santi | def GetUserspaceAccessUri(self, hypervisor): |
363 | f83057ad | Raffa Santi | """Return URIs hypervisors can use to access disks in userspace mode.
|
364 | f83057ad | Raffa Santi |
|
365 | f83057ad | Raffa Santi | @rtype: string
|
366 | f83057ad | Raffa Santi | @return: userspace device URI
|
367 | f505e3ee | Raffa Santi | @raise errors.BlockDeviceError: if userspace access is not supported
|
368 | f83057ad | Raffa Santi |
|
369 | f83057ad | Raffa Santi | """
|
370 | f83057ad | Raffa Santi | ThrowError("Userspace access with %s block device and %s hypervisor is not "
|
371 | f83057ad | Raffa Santi | "supported." % (self.__class__.__name__, |
372 | f83057ad | Raffa Santi | hypervisor)) |
373 | f83057ad | Raffa Santi | |
374 | 89ff748d | Thomas Thrainer | def __repr__(self): |
375 | 89ff748d | Thomas Thrainer | return ("<%s: unique_id: %s, children: %s, %s:%s, %s>" % |
376 | 89ff748d | Thomas Thrainer | (self.__class__, self.unique_id, self._children, |
377 | 89ff748d | Thomas Thrainer | self.major, self.minor, self.dev_path)) |
378 | 89ff748d | Thomas Thrainer | |
379 | 89ff748d | Thomas Thrainer | |
380 | 89ff748d | Thomas Thrainer | def ThrowError(msg, *args): |
381 | 89ff748d | Thomas Thrainer | """Log an error to the node daemon and the raise an exception.
|
382 | 89ff748d | Thomas Thrainer |
|
383 | 89ff748d | Thomas Thrainer | @type msg: string
|
384 | 89ff748d | Thomas Thrainer | @param msg: the text of the exception
|
385 | 89ff748d | Thomas Thrainer | @raise errors.BlockDeviceError
|
386 | 89ff748d | Thomas Thrainer |
|
387 | 89ff748d | Thomas Thrainer | """
|
388 | 89ff748d | Thomas Thrainer | if args:
|
389 | 89ff748d | Thomas Thrainer | msg = msg % args |
390 | 89ff748d | Thomas Thrainer | logging.error(msg) |
391 | 89ff748d | Thomas Thrainer | raise errors.BlockDeviceError(msg)
|
392 | 89ff748d | Thomas Thrainer | |
393 | 89ff748d | Thomas Thrainer | |
394 | 89ff748d | Thomas Thrainer | def IgnoreError(fn, *args, **kwargs): |
395 | 89ff748d | Thomas Thrainer | """Executes the given function, ignoring BlockDeviceErrors.
|
396 | 89ff748d | Thomas Thrainer |
|
397 | 89ff748d | Thomas Thrainer | This is used in order to simplify the execution of cleanup or
|
398 | 89ff748d | Thomas Thrainer | rollback functions.
|
399 | 89ff748d | Thomas Thrainer |
|
400 | 89ff748d | Thomas Thrainer | @rtype: boolean
|
401 | 89ff748d | Thomas Thrainer | @return: True when fn didn't raise an exception, False otherwise
|
402 | 89ff748d | Thomas Thrainer |
|
403 | 89ff748d | Thomas Thrainer | """
|
404 | 89ff748d | Thomas Thrainer | try:
|
405 | 89ff748d | Thomas Thrainer | fn(*args, **kwargs) |
406 | 89ff748d | Thomas Thrainer | return True |
407 | 89ff748d | Thomas Thrainer | except errors.BlockDeviceError, err:
|
408 | 89ff748d | Thomas Thrainer | logging.warning("Caught BlockDeviceError but ignoring: %s", str(err)) |
409 | 89ff748d | Thomas Thrainer | return False |