Revision 82463074 lib/bdev.py
b/lib/bdev.py | ||
---|---|---|
33 | 33 |
from ganeti import constants |
34 | 34 |
|
35 | 35 |
|
36 |
def _IgnoreError(fn, *args, **kwargs): |
|
37 |
"""Executes the given function, ignoring BlockDeviceErrors. |
|
38 |
|
|
39 |
This is used in order to simplify the execution of cleanup or |
|
40 |
rollback functions. |
|
41 |
|
|
42 |
@rtype: boolean |
|
43 |
@return: True when fn didn't raise an exception, False otherwise |
|
44 |
|
|
45 |
""" |
|
46 |
try: |
|
47 |
fn(*args, **kwargs) |
|
48 |
return True |
|
49 |
except errors.BlockDeviceError, err: |
|
50 |
logging.warning("Caught BlockDeviceError but ignoring: %s" % str(err)) |
|
51 |
return False |
|
52 |
|
|
53 |
|
|
54 |
def _ThrowError(msg, *args): |
|
55 |
"""Log an error to the node daemon and the raise an exception. |
|
56 |
|
|
57 |
@type msg: string |
|
58 |
@param msg: the text of the exception |
|
59 |
@raise errors.BlockDeviceError |
|
60 |
|
|
61 |
""" |
|
62 |
if args: |
|
63 |
msg = msg % args |
|
64 |
logging.error(msg) |
|
65 |
raise errors.BlockDeviceError(msg) |
|
66 |
|
|
67 |
|
|
36 | 68 |
class BlockDev(object): |
37 | 69 |
"""Block device abstract class. |
38 | 70 |
|
... | ... | |
280 | 312 |
vg_name, lv_name = unique_id |
281 | 313 |
pvs_info = cls.GetPVInfo(vg_name) |
282 | 314 |
if not pvs_info: |
283 |
raise errors.BlockDeviceError("Can't compute PV info for vg %s" % |
|
284 |
vg_name) |
|
315 |
_ThrowError("Can't compute PV info for vg %s", vg_name) |
|
285 | 316 |
pvs_info.sort() |
286 | 317 |
pvs_info.reverse() |
287 | 318 |
|
... | ... | |
291 | 322 |
# The size constraint should have been checked from the master before |
292 | 323 |
# calling the create function. |
293 | 324 |
if free_size < size: |
294 |
raise errors.BlockDeviceError("Not enough free space: required %s,"
|
|
295 |
" available %s" % (size, free_size))
|
|
325 |
_ThrowError("Not enough free space: required %s,"
|
|
326 |
" available %s", size, free_size)
|
|
296 | 327 |
result = utils.RunCmd(["lvcreate", "-L%dm" % size, "-n%s" % lv_name, |
297 | 328 |
vg_name] + pvlist) |
298 | 329 |
if result.failed: |
299 |
raise errors.BlockDeviceError("LV create failed (%s): %s" %
|
|
300 |
(result.fail_reason, result.output))
|
|
330 |
_ThrowError("LV create failed (%s): %s",
|
|
331 |
result.fail_reason, result.output)
|
|
301 | 332 |
return LogicalVolume(unique_id, children) |
302 | 333 |
|
303 | 334 |
@staticmethod |
... | ... | |
359 | 390 |
(self._vg_name, new_vg)) |
360 | 391 |
result = utils.RunCmd(["lvrename", new_vg, self._lv_name, new_name]) |
361 | 392 |
if result.failed: |
362 |
raise errors.BlockDeviceError("Failed to rename the logical volume: %s" % |
|
363 |
result.output) |
|
393 |
_ThrowError("Failed to rename the logical volume: %s", result.output) |
|
364 | 394 |
self._lv_name = new_name |
365 | 395 |
self.dev_path = "/dev/%s/%s" % (self._vg_name, self._lv_name) |
366 | 396 |
|
... | ... | |
480 | 510 |
|
481 | 511 |
pvs_info = self.GetPVInfo(self._vg_name) |
482 | 512 |
if not pvs_info: |
483 |
raise errors.BlockDeviceError("Can't compute PV info for vg %s" % |
|
484 |
self._vg_name) |
|
513 |
_ThrowError("Can't compute PV info for vg %s", self._vg_name) |
|
485 | 514 |
pvs_info.sort() |
486 | 515 |
pvs_info.reverse() |
487 | 516 |
free_size, pv_name = pvs_info[0] |
488 | 517 |
if free_size < size: |
489 |
raise errors.BlockDeviceError("Not enough free space: required %s,"
|
|
490 |
" available %s" % (size, free_size))
|
|
518 |
_ThrowError("Not enough free space: required %s,"
|
|
519 |
" available %s", size, free_size)
|
|
491 | 520 |
|
492 | 521 |
result = utils.RunCmd(["lvcreate", "-L%dm" % size, "-s", |
493 | 522 |
"-n%s" % snap_name, self.dev_path]) |
494 | 523 |
if result.failed: |
495 |
raise errors.BlockDeviceError("command: %s error: %s - %s" % |
|
496 |
(result.cmd, result.fail_reason, |
|
497 |
result.output)) |
|
524 |
_ThrowError("command: %s error: %s - %s", |
|
525 |
result.cmd, result.fail_reason, result.output) |
|
498 | 526 |
|
499 | 527 |
return snap_name |
500 | 528 |
|
... | ... | |
514 | 542 |
result = utils.RunCmd(["lvchange", "--addtag", text, |
515 | 543 |
self.dev_path]) |
516 | 544 |
if result.failed: |
517 |
raise errors.BlockDeviceError("Command: %s error: %s - %s" %
|
|
518 |
(result.cmd, result.fail_reason,
|
|
519 |
result.output)) |
|
545 |
_ThrowError("Command: %s error: %s - %s", result.cmd, result.fail_reason,
|
|
546 |
result.output)
|
|
547 |
|
|
520 | 548 |
def Grow(self, amount): |
521 | 549 |
"""Grow the logical volume. |
522 | 550 |
|
... | ... | |
530 | 558 |
"-L", "+%dm" % amount, self.dev_path]) |
531 | 559 |
if not result.failed: |
532 | 560 |
return |
533 |
raise errors.BlockDeviceError("Can't grow LV %s: %s" % |
|
534 |
(self.dev_path, result.output)) |
|
561 |
_ThrowError("Can't grow LV %s: %s", self.dev_path, result.output) |
|
535 | 562 |
|
536 | 563 |
|
537 | 564 |
class DRBD8Status(object): |
... | ... | |
623 | 650 |
finally: |
624 | 651 |
stat.close() |
625 | 652 |
if not data: |
626 |
raise errors.BlockDeviceError("Can't read any data from %s" % filename)
|
|
653 |
_ThrowError("Can't read any data from %s", filename)
|
|
627 | 654 |
return data |
628 | 655 |
|
629 | 656 |
@staticmethod |
... | ... | |
788 | 815 |
self.major = self._DRBD_MAJOR |
789 | 816 |
version = self._GetVersion() |
790 | 817 |
if version['k_major'] != 8 : |
791 |
raise errors.BlockDeviceError("Mismatch in DRBD kernel version and" |
|
792 |
" requested ganeti usage: kernel is" |
|
793 |
" %s.%s, ganeti wants 8.x" % |
|
794 |
(version['k_major'], version['k_minor'])) |
|
818 |
_ThrowError("Mismatch in DRBD kernel version and requested ganeti" |
|
819 |
" usage: kernel is %s.%s, ganeti wants 8.x", |
|
820 |
version['k_major'], version['k_minor']) |
|
795 | 821 |
|
796 | 822 |
if len(children) not in (0, 2): |
797 | 823 |
raise ValueError("Invalid configuration data %s" % str(children)) |
... | ... | |
816 | 842 |
result = utils.RunCmd(["drbdmeta", "--force", cls._DevPath(minor), |
817 | 843 |
"v08", dev_path, "0", "create-md"]) |
818 | 844 |
if result.failed: |
819 |
raise errors.BlockDeviceError("Can't initialize meta device: %s" % |
|
820 |
result.output) |
|
845 |
_ThrowError("Can't initialize meta device: %s", result.output) |
|
821 | 846 |
|
822 | 847 |
@classmethod |
823 | 848 |
def _FindUnusedMinor(cls): |
... | ... | |
929 | 954 |
try: |
930 | 955 |
results = bnf.parseString(out) |
931 | 956 |
except pyp.ParseException, err: |
932 |
raise errors.BlockDeviceError("Can't parse drbdsetup show output: %s" % |
|
933 |
str(err)) |
|
957 |
_ThrowError("Can't parse drbdsetup show output: %s", str(err)) |
|
934 | 958 |
|
935 | 959 |
# and massage the results into our desired format |
936 | 960 |
for section in results: |
... | ... | |
1075 | 1099 |
|
1076 | 1100 |
""" |
1077 | 1101 |
if self.minor is None: |
1078 |
raise errors.BlockDeviceError("Can't attach to dbrd8 during AddChildren") |
|
1102 |
_ThrowError("drbd%d: can't attach to dbrd8 during AddChildren", |
|
1103 |
self._aminor) |
|
1079 | 1104 |
if len(devices) != 2: |
1080 |
raise errors.BlockDeviceError("Need two devices for AddChildren")
|
|
1105 |
_ThrowError("drbd%d: need two devices for AddChildren", self.minor)
|
|
1081 | 1106 |
info = self._GetDevInfo(self._GetShowData(self.minor)) |
1082 | 1107 |
if "local_dev" in info: |
1083 |
raise errors.BlockDeviceError("DRBD8 already attached to a local disk")
|
|
1108 |
_ThrowError("drbd%d: already attached to a local disk", self.minor)
|
|
1084 | 1109 |
backend, meta = devices |
1085 | 1110 |
if backend.dev_path is None or meta.dev_path is None: |
1086 |
raise errors.BlockDeviceError("Children not ready during AddChildren")
|
|
1111 |
_ThrowError("drbd%d: children not ready during AddChildren", self.minor)
|
|
1087 | 1112 |
backend.Open() |
1088 | 1113 |
meta.Open() |
1089 | 1114 |
if not self._CheckMetaSize(meta.dev_path): |
... | ... | |
1099 | 1124 |
|
1100 | 1125 |
""" |
1101 | 1126 |
if self.minor is None: |
1102 |
raise errors.BlockDeviceError("Can't attach to drbd8 during"
|
|
1103 |
" RemoveChildren")
|
|
1127 |
_ThrowError("drbd%d: can't attach to drbd8 during RemoveChildren",
|
|
1128 |
self._aminor)
|
|
1104 | 1129 |
# early return if we don't actually have backing storage |
1105 | 1130 |
info = self._GetDevInfo(self._GetShowData(self.minor)) |
1106 | 1131 |
if "local_dev" not in info: |
1107 | 1132 |
return |
1108 | 1133 |
if len(self._children) != 2: |
1109 |
raise errors.BlockDeviceError("We don't have two children: %s" %
|
|
1110 |
self._children)
|
|
1134 |
_ThrowError("drbd%d: we don't have two children: %s", self.minor,
|
|
1135 |
self._children) |
|
1111 | 1136 |
if self._children.count(None) == 2: # we don't actually have children :) |
1112 |
logging.error("Requested detach while detached")
|
|
1137 |
logging.warning("drbd%d: requested detach while detached", self.minor)
|
|
1113 | 1138 |
return |
1114 | 1139 |
if len(devices) != 2: |
1115 |
raise errors.BlockDeviceError("We need two children in RemoveChildren")
|
|
1140 |
_ThrowError("drbd%d: we need two children in RemoveChildren", self.minor)
|
|
1116 | 1141 |
for child, dev in zip(self._children, devices): |
1117 | 1142 |
if dev != child.dev_path: |
1118 |
raise errors.BlockDeviceError("Mismatch in local storage" |
|
1119 |
" (%s != %s) in RemoveChildren" % |
|
1120 |
(dev, child.dev_path)) |
|
1143 |
_ThrowError("drbd%d: mismatch in local storage (%s != %s) in" |
|
1144 |
" RemoveChildren", self.minor, dev, child.dev_path) |
|
1121 | 1145 |
|
1122 | 1146 |
if not self._ShutdownLocal(self.minor): |
1123 | 1147 |
raise errors.BlockDeviceError("Can't detach from local storage") |
... | ... | |
1164 | 1188 |
|
1165 | 1189 |
""" |
1166 | 1190 |
if self.minor is None: |
1167 |
raise errors.BlockDeviceError("GetStats() called while not attached")
|
|
1191 |
_ThrowError("drbd%d: GetStats() called while not attached", self._aminor)
|
|
1168 | 1192 |
proc_info = self._MassageProcData(self._GetProcData()) |
1169 | 1193 |
if self.minor not in proc_info: |
1170 |
raise errors.BlockDeviceError("Can't find myself in /proc (minor %d)" % |
|
1171 |
self.minor) |
|
1194 |
_ThrowError("drbd%d: can't find myself in /proc", self.minor) |
|
1172 | 1195 |
return DRBD8Status(proc_info[self.minor]) |
1173 | 1196 |
|
1174 | 1197 |
def GetSyncStatus(self): |
... | ... | |
1191 | 1214 |
|
1192 | 1215 |
""" |
1193 | 1216 |
if self.minor is None and not self.Attach(): |
1194 |
raise errors.BlockDeviceError("Can't attach to device in GetSyncStatus")
|
|
1217 |
_ThrowError("drbd%d: can't Attach() in GetSyncStatus", self._aminor)
|
|
1195 | 1218 |
stats = self.GetProcStatus() |
1196 | 1219 |
ldisk = not stats.is_disk_uptodate |
1197 | 1220 |
is_degraded = not stats.is_connected |
... | ... | |
1214 | 1237 |
cmd.append("-o") |
1215 | 1238 |
result = utils.RunCmd(cmd) |
1216 | 1239 |
if result.failed: |
1217 |
msg = ("Can't make drbd device primary: %s" % result.output) |
|
1218 |
logging.error(msg) |
|
1219 |
raise errors.BlockDeviceError(msg) |
|
1240 |
_ThrowError("drbd%d: can't make drbd device primary: %s", self.minor, |
|
1241 |
result.output) |
|
1220 | 1242 |
|
1221 | 1243 |
def Close(self): |
1222 | 1244 |
"""Make the local state secondary. |
... | ... | |
1225 | 1247 |
|
1226 | 1248 |
""" |
1227 | 1249 |
if self.minor is None and not self.Attach(): |
1228 |
logging.info("Instance not attached to a device") |
|
1229 |
raise errors.BlockDeviceError("Can't find device") |
|
1250 |
_ThrowError("drbd%d: can't Attach() in Close()", self._aminor) |
|
1230 | 1251 |
result = utils.RunCmd(["drbdsetup", self.dev_path, "secondary"]) |
1231 | 1252 |
if result.failed: |
1232 |
msg = ("Can't switch drbd device to" |
|
1233 |
" secondary: %s" % result.output) |
|
1234 |
logging.error(msg) |
|
1235 |
raise errors.BlockDeviceError(msg) |
|
1253 |
_ThrowError("drbd%d: can't switch drbd device to secondary: %s", |
|
1254 |
self.minor, result.output) |
|
1236 | 1255 |
|
1237 | 1256 |
def DisconnectNet(self): |
1238 | 1257 |
"""Removes network configuration. |
... | ... | |
1249 | 1268 |
|
1250 | 1269 |
""" |
1251 | 1270 |
if self.minor is None: |
1252 |
raise errors.BlockDeviceError("DRBD disk not attached in re-attach net")
|
|
1271 |
_ThrowError("drbd%d: disk not attached in re-attach net", self._aminor)
|
|
1253 | 1272 |
|
1254 | 1273 |
if None in (self._lhost, self._lport, self._rhost, self._rport): |
1255 |
raise errors.BlockDeviceError("DRBD disk missing network info in"
|
|
1256 |
" DisconnectNet()")
|
|
1274 |
_ThrowError("drbd%d: DRBD disk missing network info in"
|
|
1275 |
" DisconnectNet()", self.minor)
|
|
1257 | 1276 |
|
1258 | 1277 |
ever_disconnected = self._ShutdownNet(self.minor) |
1259 | 1278 |
timeout_limit = time.time() + self._NET_RECONFIG_TIMEOUT |
... | ... | |
1271 | 1290 |
|
1272 | 1291 |
if not status.is_standalone: |
1273 | 1292 |
if ever_disconnected: |
1274 |
msg = ("Device did not react to the"
|
|
1293 |
msg = ("drbd%d: device did not react to the"
|
|
1275 | 1294 |
" 'disconnect' command in a timely manner") |
1276 | 1295 |
else: |
1277 |
msg = ("Can't shutdown network, even after multiple retries")
|
|
1278 |
raise errors.BlockDeviceError(msg)
|
|
1296 |
msg = "drbd%d: can't shutdown network, even after multiple retries"
|
|
1297 |
_ThrowError(msg, self.minor)
|
|
1279 | 1298 |
|
1280 | 1299 |
reconfig_time = time.time() - timeout_limit + self._NET_RECONFIG_TIMEOUT |
1281 | 1300 |
if reconfig_time > 15: # hardcoded alert limit |
1282 |
logging.debug("DRBD8.DisconnectNet: detach took %.3f seconds",
|
|
1283 |
reconfig_time) |
|
1301 |
logging.info("drbd%d: DisconnectNet: detach took %.3f seconds",
|
|
1302 |
self.minor, reconfig_time)
|
|
1284 | 1303 |
|
1285 | 1304 |
def AttachNet(self, multimaster): |
1286 | 1305 |
"""Reconnects the network. |
... | ... | |
1294 | 1313 |
|
1295 | 1314 |
""" |
1296 | 1315 |
if self.minor is None: |
1297 |
raise errors.BlockDeviceError("DRBD disk not attached in AttachNet")
|
|
1316 |
_ThrowError("drbd%d: device not attached in AttachNet", self._aminor)
|
|
1298 | 1317 |
|
1299 | 1318 |
if None in (self._lhost, self._lport, self._rhost, self._rport): |
1300 |
raise errors.BlockDeviceError("DRBD disk missing network info in" |
|
1301 |
" AttachNet()") |
|
1319 |
_ThrowError("drbd%d: missing network info in AttachNet()", self.minor) |
|
1302 | 1320 |
|
1303 | 1321 |
status = self.GetProcStatus() |
1304 | 1322 |
|
1305 | 1323 |
if not status.is_standalone: |
1306 |
raise errors.BlockDeviceError("Device is not standalone in AttachNet")
|
|
1324 |
_ThrowError("drbd%d: device is not standalone in AttachNet", self.minor)
|
|
1307 | 1325 |
|
1308 | 1326 |
return self._AssembleNet(self.minor, |
1309 | 1327 |
(self._lhost, self._lport, |
... | ... | |
1521 | 1539 |
else: |
1522 | 1540 |
in_use = False |
1523 | 1541 |
if in_use: |
1524 |
raise errors.BlockDeviceError("DRBD minor %d already in use at" |
|
1525 |
" Create() time" % aminor) |
|
1542 |
_ThrowError("DRBD minor %d already in use at Create() time", aminor) |
|
1526 | 1543 |
meta = children[1] |
1527 | 1544 |
meta.Assemble() |
1528 | 1545 |
if not meta.Attach(): |
... | ... | |
1537 | 1554 |
|
1538 | 1555 |
""" |
1539 | 1556 |
if self.minor is None: |
1540 |
raise errors.ProgrammerError("drbd8: Grow called while not attached")
|
|
1557 |
_ThrowError("drbd%d: Grow called while not attached", self._aminor)
|
|
1541 | 1558 |
if len(self._children) != 2 or None in self._children: |
1542 |
raise errors.BlockDeviceError("Cannot grow diskless DRBD8 device")
|
|
1559 |
_ThrowError("drbd%d: cannot grow diskless device", self.minor)
|
|
1543 | 1560 |
self._children[0].Grow(amount) |
1544 | 1561 |
result = utils.RunCmd(["drbdsetup", self.dev_path, "resize"]) |
1545 | 1562 |
if result.failed: |
1546 |
raise errors.BlockDeviceError("resize failed for %s: %s" % |
|
1547 |
(self.dev_path, result.output)) |
|
1548 |
return |
|
1563 |
_ThrowError("drbd%d: resize failed: %s", self.minor, result.output) |
|
1549 | 1564 |
|
1550 | 1565 |
|
1551 | 1566 |
class FileStorage(BlockDev): |
... | ... | |
1653 | 1668 |
f.truncate(size * 1024 * 1024) |
1654 | 1669 |
f.close() |
1655 | 1670 |
except IOError, err: |
1656 |
raise errors.BlockDeviceError("Error in file creation: %" % str(err))
|
|
1671 |
_ThrowError("Error in file creation: %", str(err))
|
|
1657 | 1672 |
|
1658 | 1673 |
return FileStorage(unique_id, children) |
1659 | 1674 |
|
Also available in: Unified diff