128 |
128 |
this method is idempotent
|
129 |
129 |
|
130 |
130 |
"""
|
131 |
|
return True
|
|
131 |
pass
|
132 |
132 |
|
133 |
133 |
def Attach(self):
|
134 |
134 |
"""Find a device which matches our config and attach to it.
|
... | ... | |
441 |
441 |
"""
|
442 |
442 |
result = utils.RunCmd(["lvchange", "-ay", self.dev_path])
|
443 |
443 |
if result.failed:
|
444 |
|
logging.error("Can't activate lv %s: %s", self.dev_path, result.output)
|
445 |
|
return False
|
446 |
|
return self.Attach()
|
|
444 |
_ThrowError("Can't activate lv %s: %s", self.dev_path, result.output)
|
447 |
445 |
|
448 |
446 |
def Shutdown(self):
|
449 |
447 |
"""Shutdown the device.
|
... | ... | |
1034 |
1032 |
backend, meta, "0", "-e", "detach", "--create-device"]
|
1035 |
1033 |
result = utils.RunCmd(args)
|
1036 |
1034 |
if result.failed:
|
1037 |
|
logging.error("Can't attach local disk: %s", result.output)
|
1038 |
|
return not result.failed
|
|
1035 |
_ThrowError("drbd%d: can't attach local disk: %s", minor, result.output)
|
1039 |
1036 |
|
1040 |
1037 |
@classmethod
|
1041 |
1038 |
def _AssembleNet(cls, minor, net_info, protocol,
|
... | ... | |
1047 |
1044 |
if None in net_info:
|
1048 |
1045 |
# we don't want network connection and actually want to make
|
1049 |
1046 |
# sure its shutdown
|
1050 |
|
return cls._ShutdownNet(minor)
|
|
1047 |
cls._ShutdownNet(minor)
|
|
1048 |
return
|
1051 |
1049 |
|
1052 |
1050 |
# Workaround for a race condition. When DRBD is doing its dance to
|
1053 |
1051 |
# establish a connection with its peer, it also sends the
|
... | ... | |
1069 |
1067 |
args.extend(["-a", hmac, "-x", secret])
|
1070 |
1068 |
result = utils.RunCmd(args)
|
1071 |
1069 |
if result.failed:
|
1072 |
|
logging.error("Can't setup network for dbrd device: %s - %s",
|
1073 |
|
result.fail_reason, result.output)
|
1074 |
|
return False
|
|
1070 |
_ThrowError("drbd%d: can't setup network: %s - %s",
|
|
1071 |
minor, result.fail_reason, result.output)
|
1075 |
1072 |
|
1076 |
1073 |
timeout = time.time() + 10
|
1077 |
1074 |
ok = False
|
... | ... | |
1087 |
1084 |
ok = True
|
1088 |
1085 |
break
|
1089 |
1086 |
if not ok:
|
1090 |
|
logging.error("Timeout while configuring network")
|
1091 |
|
return False
|
1092 |
|
return True
|
|
1087 |
_ThrowError("drbd%d: timeout while configuring network", minor)
|
1093 |
1088 |
|
1094 |
1089 |
def AddChildren(self, devices):
|
1095 |
1090 |
"""Add a disk to the DRBD device.
|
... | ... | |
1112 |
1107 |
raise errors.BlockDeviceError("Invalid meta device size")
|
1113 |
1108 |
self._InitMeta(self._FindUnusedMinor(), meta.dev_path)
|
1114 |
1109 |
|
1115 |
|
if not self._AssembleLocal(self.minor, backend.dev_path, meta.dev_path):
|
1116 |
|
raise errors.BlockDeviceError("Can't attach to local storage")
|
|
1110 |
self._AssembleLocal(self.minor, backend.dev_path, meta.dev_path)
|
1117 |
1111 |
self._children = devices
|
1118 |
1112 |
|
1119 |
1113 |
def RemoveChildren(self, devices):
|
... | ... | |
1140 |
1134 |
_ThrowError("drbd%d: mismatch in local storage (%s != %s) in"
|
1141 |
1135 |
" RemoveChildren", self.minor, dev, child.dev_path)
|
1142 |
1136 |
|
1143 |
|
if not self._ShutdownLocal(self.minor):
|
1144 |
|
raise errors.BlockDeviceError("Can't detach from local storage")
|
|
1137 |
self._ShutdownLocal(self.minor)
|
1145 |
1138 |
self._children = []
|
1146 |
1139 |
|
1147 |
1140 |
@classmethod
|
... | ... | |
1271 |
1264 |
_ThrowError("drbd%d: DRBD disk missing network info in"
|
1272 |
1265 |
" DisconnectNet()", self.minor)
|
1273 |
1266 |
|
1274 |
|
ever_disconnected = self._ShutdownNet(self.minor)
|
|
1267 |
ever_disconnected = _IgnoreError(self._ShutdownNet, self.minor)
|
1275 |
1268 |
timeout_limit = time.time() + self._NET_RECONFIG_TIMEOUT
|
1276 |
1269 |
sleep_time = 0.100 # we start the retry time at 100 miliseconds
|
1277 |
1270 |
while time.time() < timeout_limit:
|
... | ... | |
1281 |
1274 |
# retry the disconnect, it seems possible that due to a
|
1282 |
1275 |
# well-time disconnect on the peer, my disconnect command might
|
1283 |
1276 |
# be ingored and forgotten
|
1284 |
|
ever_disconnected = self._ShutdownNet(self.minor) or ever_disconnected
|
|
1277 |
ever_disconnected = _IgnoreError(self._ShutdownNet, self.minor) or \
|
|
1278 |
ever_disconnected
|
1285 |
1279 |
time.sleep(sleep_time)
|
1286 |
1280 |
sleep_time = min(2, sleep_time * 1.5)
|
1287 |
1281 |
|
... | ... | |
1320 |
1314 |
if not status.is_standalone:
|
1321 |
1315 |
_ThrowError("drbd%d: device is not standalone in AttachNet", self.minor)
|
1322 |
1316 |
|
1323 |
|
return self._AssembleNet(self.minor,
|
1324 |
|
(self._lhost, self._lport,
|
1325 |
|
self._rhost, self._rport),
|
1326 |
|
"C", dual_pri=multimaster)
|
|
1317 |
self._AssembleNet(self.minor,
|
|
1318 |
(self._lhost, self._lport, self._rhost, self._rport),
|
|
1319 |
constants.DRBD_NET_PROTOCOL, dual_pri=multimaster,
|
|
1320 |
hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
|
1327 |
1321 |
|
1328 |
1322 |
def Attach(self):
|
1329 |
1323 |
"""Check if our minor is configured.
|
... | ... | |
1354 |
1348 |
- if not, we create it from zero
|
1355 |
1349 |
|
1356 |
1350 |
"""
|
1357 |
|
result = super(DRBD8, self).Assemble()
|
1358 |
|
if not result:
|
1359 |
|
return result
|
|
1351 |
super(DRBD8, self).Assemble()
|
1360 |
1352 |
|
1361 |
1353 |
self.Attach()
|
1362 |
1354 |
if self.minor is None:
|
1363 |
1355 |
# local device completely unconfigured
|
1364 |
|
return self._FastAssemble()
|
|
1356 |
self._FastAssemble()
|
1365 |
1357 |
else:
|
1366 |
1358 |
# we have to recheck the local and network status and try to fix
|
1367 |
1359 |
# the device
|
1368 |
|
return self._SlowAssemble()
|
|
1360 |
self._SlowAssemble()
|
1369 |
1361 |
|
1370 |
1362 |
def _SlowAssemble(self):
|
1371 |
1363 |
"""Assembles the DRBD device from a (partially) configured device.
|
... | ... | |
1375 |
1367 |
the attach if can return success.
|
1376 |
1368 |
|
1377 |
1369 |
"""
|
|
1370 |
net_data = (self._lhost, self._lport, self._rhost, self._rport)
|
1378 |
1371 |
for minor in (self._aminor,):
|
1379 |
1372 |
info = self._GetDevInfo(self._GetShowData(minor))
|
1380 |
1373 |
match_l = self._MatchesLocal(info)
|
1381 |
1374 |
match_r = self._MatchesNet(info)
|
|
1375 |
|
1382 |
1376 |
if match_l and match_r:
|
|
1377 |
# everything matches
|
1383 |
1378 |
break
|
|
1379 |
|
1384 |
1380 |
if match_l and not match_r and "local_addr" not in info:
|
1385 |
|
res_r = self._AssembleNet(minor,
|
1386 |
|
(self._lhost, self._lport,
|
1387 |
|
self._rhost, self._rport),
|
1388 |
|
constants.DRBD_NET_PROTOCOL,
|
1389 |
|
hmac=constants.DRBD_HMAC_ALG,
|
1390 |
|
secret=self._secret
|
1391 |
|
)
|
1392 |
|
if res_r:
|
1393 |
|
if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
|
1394 |
|
break
|
1395 |
|
# the weakest case: we find something that is only net attached
|
1396 |
|
# even though we were passed some children at init time
|
|
1381 |
# disk matches, but not attached to network, attach and recheck
|
|
1382 |
self._AssembleNet(minor, net_data, constants.DRBD_NET_PROTOCOL,
|
|
1383 |
hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
|
|
1384 |
if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
|
|
1385 |
break
|
|
1386 |
else:
|
|
1387 |
_ThrowError("drbd%d: network attach successful, but 'drbdsetup"
|
|
1388 |
" show' disagrees", minor)
|
|
1389 |
|
1397 |
1390 |
if match_r and "local_dev" not in info:
|
1398 |
|
break
|
|
1391 |
# no local disk, but network attached and it matches
|
|
1392 |
self._AssembleLocal(minor, self._children[0].dev_path,
|
|
1393 |
self._children[1].dev_path)
|
|
1394 |
if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
|
|
1395 |
break
|
|
1396 |
else:
|
|
1397 |
_ThrowError("drbd%d: disk attach successful, but 'drbdsetup"
|
|
1398 |
" show' disagrees", minor)
|
1399 |
1399 |
|
1400 |
1400 |
# this case must be considered only if we actually have local
|
1401 |
1401 |
# storage, i.e. not in diskless mode, because all diskless
|
... | ... | |
1407 |
1407 |
# else, even though its local storage is ours; as we own the
|
1408 |
1408 |
# drbd space, we try to disconnect from the remote peer and
|
1409 |
1409 |
# reconnect to our correct one
|
1410 |
|
if not self._ShutdownNet(minor):
|
1411 |
|
raise errors.BlockDeviceError("Device has correct local storage,"
|
1412 |
|
" wrong remote peer and is unable to"
|
1413 |
|
" disconnect in order to attach to"
|
1414 |
|
" the correct peer")
|
|
1410 |
try:
|
|
1411 |
self._ShutdownNet(minor)
|
|
1412 |
except errors.BlockDeviceError, err:
|
|
1413 |
_ThrowError("Device has correct local storage, wrong remote peer"
|
|
1414 |
" and is unable to disconnect in order to attach to"
|
|
1415 |
" the correct peer: %s", str(err))
|
1415 |
1416 |
# note: _AssembleNet also handles the case when we don't want
|
1416 |
1417 |
# local storage (i.e. one or more of the _[lr](host|port) is
|
1417 |
1418 |
# None)
|
1418 |
|
if (self._AssembleNet(minor, (self._lhost, self._lport,
|
1419 |
|
self._rhost, self._rport),
|
1420 |
|
constants.DRBD_NET_PROTOCOL,
|
1421 |
|
hmac=constants.DRBD_HMAC_ALG,
|
1422 |
|
secret=self._secret) and
|
1423 |
|
self._MatchesNet(self._GetDevInfo(self._GetShowData(minor)))):
|
|
1419 |
self._AssembleNet(minor, net_data, constants.DRBD_NET_PROTOCOL,
|
|
1420 |
hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
|
|
1421 |
if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
|
1424 |
1422 |
break
|
|
1423 |
else:
|
|
1424 |
_ThrowError("drbd%d: network attach successful, but 'drbdsetup"
|
|
1425 |
" show' disagrees", minor)
|
1425 |
1426 |
|
1426 |
1427 |
else:
|
1427 |
1428 |
minor = None
|
1428 |
1429 |
|
1429 |
1430 |
self._SetFromMinor(minor)
|
1430 |
|
return minor is not None
|
|
1431 |
if minor is None:
|
|
1432 |
_ThrowError("drbd%d: cannot activate, unknown or unhandled reason",
|
|
1433 |
self._aminor)
|
1431 |
1434 |
|
1432 |
1435 |
def _FastAssemble(self):
|
1433 |
1436 |
"""Assemble the drbd device from zero.
|
... | ... | |
1435 |
1438 |
This is run when in Assemble we detect our minor is unused.
|
1436 |
1439 |
|
1437 |
1440 |
"""
|
1438 |
|
# TODO: maybe completely tear-down the minor (drbdsetup ... down)
|
1439 |
|
# before attaching our own?
|
1440 |
1441 |
minor = self._aminor
|
1441 |
|
need_localdev_teardown = False
|
1442 |
1442 |
if self._children and self._children[0] and self._children[1]:
|
1443 |
|
result = self._AssembleLocal(minor, self._children[0].dev_path,
|
1444 |
|
self._children[1].dev_path)
|
1445 |
|
if not result:
|
1446 |
|
return False
|
|
1443 |
self._AssembleLocal(minor, self._children[0].dev_path,
|
|
1444 |
self._children[1].dev_path)
|
1447 |
1445 |
if self._lhost and self._lport and self._rhost and self._rport:
|
1448 |
|
result = self._AssembleNet(minor,
|
1449 |
|
(self._lhost, self._lport,
|
1450 |
|
self._rhost, self._rport),
|
1451 |
|
constants.DRBD_NET_PROTOCOL,
|
1452 |
|
hmac=constants.DRBD_HMAC_ALG,
|
1453 |
|
secret=self._secret)
|
1454 |
|
if not result:
|
1455 |
|
return False
|
|
1446 |
self._AssembleNet(minor,
|
|
1447 |
(self._lhost, self._lport, self._rhost, self._rport),
|
|
1448 |
constants.DRBD_NET_PROTOCOL,
|
|
1449 |
hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
|
1456 |
1450 |
self._SetFromMinor(minor)
|
1457 |
|
return True
|
1458 |
1451 |
|
1459 |
1452 |
@classmethod
|
1460 |
1453 |
def _ShutdownLocal(cls, minor):
|
... | ... | |
1466 |
1459 |
"""
|
1467 |
1460 |
result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "detach"])
|
1468 |
1461 |
if result.failed:
|
1469 |
|
logging.error("Can't detach local device: %s", result.output)
|
1470 |
|
return not result.failed
|
|
1462 |
_ThrowError("drbd%d: can't detach local disk: %s", minor, result.output)
|
1471 |
1463 |
|
1472 |
1464 |
@classmethod
|
1473 |
1465 |
def _ShutdownNet(cls, minor):
|
... | ... | |
1478 |
1470 |
"""
|
1479 |
1471 |
result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "disconnect"])
|
1480 |
1472 |
if result.failed:
|
1481 |
|
logging.error("Can't shutdown network: %s", result.output)
|
1482 |
|
return not result.failed
|
|
1473 |
_ThrowError("drbd%d: can't shutdown network: %s", minor, result.output)
|
1483 |
1474 |
|
1484 |
1475 |
@classmethod
|
1485 |
1476 |
def _ShutdownAll(cls, minor):
|
... | ... | |
1581 |
1572 |
|
1582 |
1573 |
"""
|
1583 |
1574 |
if not os.path.exists(self.dev_path):
|
1584 |
|
raise errors.BlockDeviceError("File device '%s' does not exist." %
|
1585 |
|
self.dev_path)
|
1586 |
|
return True
|
|
1575 |
_ThrowError("File device '%s' does not exist" % self.dev_path)
|
1587 |
1576 |
|
1588 |
1577 |
def Shutdown(self):
|
1589 |
1578 |
"""Shutdown the device.
|
... | ... | |
1692 |
1681 |
if dev_type not in DEV_MAP:
|
1693 |
1682 |
raise errors.ProgrammerError("Invalid block device type '%s'" % dev_type)
|
1694 |
1683 |
device = DEV_MAP[dev_type](unique_id, children)
|
1695 |
|
if not device.Assemble():
|
1696 |
|
raise errors.BlockDeviceError("Can't find a valid block device for"
|
1697 |
|
" %s/%s/%s" %
|
1698 |
|
(dev_type, unique_id, children))
|
|
1684 |
device.Assemble()
|
1699 |
1685 |
return device
|
1700 |
1686 |
|
1701 |
1687 |
|