Revision 2fe690f1
b/lib/backend.py | ||
---|---|---|
832 | 832 |
|
833 | 833 |
if constants.NV_DRBDLIST in what and vm_capable: |
834 | 834 |
try: |
835 |
used_minors = drbd.DRBD8.GetUsedDevs().keys()
|
|
835 |
used_minors = drbd.DRBD8.GetUsedDevs() |
|
836 | 836 |
except errors.BlockDeviceError, err: |
837 | 837 |
logging.warning("Can't get used minors list", exc_info=True) |
838 | 838 |
used_minors = str(err) |
b/lib/block/drbd.py | ||
---|---|---|
42 | 42 |
_DEVICE_READ_SIZE = 128 * 1024 |
43 | 43 |
|
44 | 44 |
|
45 |
class DRBD8Status(object): |
|
45 |
class DRBD8Status(object): # pylint: disable=R0902
|
|
46 | 46 |
"""A DRBD status representation class. |
47 | 47 |
|
48 | 48 |
Note that this class is meant to be used to parse one of the entries returned |
49 |
from L{DRBD8._JoinProcDataPerMinor}. |
|
49 |
from L{DRBD8Info._JoinProcDataPerMinor}.
|
|
50 | 50 |
|
51 | 51 |
""" |
52 | 52 |
UNCONF_RE = re.compile(r"\s*[0-9]+:\s*cs:Unconfigured$") |
... | ... | |
119 | 119 |
self.is_standalone = self.cstatus == self.CS_STANDALONE |
120 | 120 |
self.is_wfconn = self.cstatus == self.CS_WFCONNECTION |
121 | 121 |
self.is_connected = self.cstatus == self.CS_CONNECTED |
122 |
self.is_unconfigured = self.cstatus == self.CS_UNCONFIGURED |
|
122 | 123 |
self.is_primary = self.lrole == self.RO_PRIMARY |
123 | 124 |
self.is_secondary = self.lrole == self.RO_SECONDARY |
124 | 125 |
self.peer_primary = self.rrole == self.RO_PRIMARY |
... | ... | |
151 | 152 |
self.est_time = None |
152 | 153 |
|
153 | 154 |
|
155 |
class DRBD8Info(object): |
|
156 |
"""Represents information DRBD exports (usually via /proc/drbd). |
|
157 |
|
|
158 |
An instance of this class is created by one of the CreateFrom... methods. |
|
159 |
|
|
160 |
""" |
|
161 |
|
|
162 |
_VERSION_RE = re.compile(r"^version: (\d+)\.(\d+)\.(\d+)(?:\.\d+)?" |
|
163 |
r" \(api:(\d+)/proto:(\d+)(?:-(\d+))?\)") |
|
164 |
_VALID_LINE_RE = re.compile("^ *([0-9]+): cs:([^ ]+).*$") |
|
165 |
|
|
166 |
def __init__(self, lines): |
|
167 |
self._version = self._ParseVersion(lines) |
|
168 |
self._minors, self._line_per_minor = self._JoinProcDataPerMinor(lines) |
|
169 |
|
|
170 |
def GetVersion(self): |
|
171 |
"""Return the DRBD version. |
|
172 |
|
|
173 |
This will return a dict with keys: |
|
174 |
- k_major |
|
175 |
- k_minor |
|
176 |
- k_point |
|
177 |
- api |
|
178 |
- proto |
|
179 |
- proto2 (only on drbd > 8.2.X) |
|
180 |
|
|
181 |
""" |
|
182 |
return self._version |
|
183 |
|
|
184 |
def GetMinors(self): |
|
185 |
"""Return a list of minor for which information is available. |
|
186 |
|
|
187 |
This list is ordered in exactly the order which was found in the underlying |
|
188 |
data. |
|
189 |
|
|
190 |
""" |
|
191 |
return self._minors |
|
192 |
|
|
193 |
def HasMinorStatus(self, minor): |
|
194 |
return minor in self._line_per_minor |
|
195 |
|
|
196 |
def GetMinorStatus(self, minor): |
|
197 |
return DRBD8Status(self._line_per_minor[minor]) |
|
198 |
|
|
199 |
def _ParseVersion(self, lines): |
|
200 |
first_line = lines[0].strip() |
|
201 |
version = self._VERSION_RE.match(first_line) |
|
202 |
if not version: |
|
203 |
raise errors.BlockDeviceError("Can't parse DRBD version from '%s'" % |
|
204 |
first_line) |
|
205 |
|
|
206 |
values = version.groups() |
|
207 |
retval = { |
|
208 |
"k_major": int(values[0]), |
|
209 |
"k_minor": int(values[1]), |
|
210 |
"k_point": int(values[2]), |
|
211 |
"api": int(values[3]), |
|
212 |
"proto": int(values[4]), |
|
213 |
} |
|
214 |
if values[5] is not None: |
|
215 |
retval["proto2"] = values[5] |
|
216 |
|
|
217 |
return retval |
|
218 |
|
|
219 |
def _JoinProcDataPerMinor(self, lines): |
|
220 |
"""Transform the raw lines into a dictionary based on the minor. |
|
221 |
|
|
222 |
@return: a dictionary of minor: joined lines from /proc/drbd |
|
223 |
for that minor |
|
224 |
|
|
225 |
""" |
|
226 |
minors = [] |
|
227 |
results = {} |
|
228 |
old_minor = old_line = None |
|
229 |
for line in lines: |
|
230 |
if not line: # completely empty lines, as can be returned by drbd8.0+ |
|
231 |
continue |
|
232 |
lresult = self._VALID_LINE_RE.match(line) |
|
233 |
if lresult is not None: |
|
234 |
if old_minor is not None: |
|
235 |
minors.append(old_minor) |
|
236 |
results[old_minor] = old_line |
|
237 |
old_minor = int(lresult.group(1)) |
|
238 |
old_line = line |
|
239 |
else: |
|
240 |
if old_minor is not None: |
|
241 |
old_line += " " + line.strip() |
|
242 |
# add last line |
|
243 |
if old_minor is not None: |
|
244 |
minors.append(old_minor) |
|
245 |
results[old_minor] = old_line |
|
246 |
return minors, results |
|
247 |
|
|
248 |
@staticmethod |
|
249 |
def CreateFromLines(lines): |
|
250 |
return DRBD8Info(lines) |
|
251 |
|
|
252 |
@staticmethod |
|
253 |
def CreateFromFile(filename=constants.DRBD_STATUS_FILE): |
|
254 |
try: |
|
255 |
lines = utils.ReadFile(filename).splitlines() |
|
256 |
except EnvironmentError, err: |
|
257 |
if err.errno == errno.ENOENT: |
|
258 |
base.ThrowError("The file %s cannot be opened, check if the module" |
|
259 |
" is loaded (%s)", filename, str(err)) |
|
260 |
else: |
|
261 |
base.ThrowError("Can't read the DRBD proc file %s: %s", |
|
262 |
filename, str(err)) |
|
263 |
if not lines: |
|
264 |
base.ThrowError("Can't read any data from %s", filename) |
|
265 |
return DRBD8Info.CreateFromLines(lines) |
|
266 |
|
|
267 |
|
|
154 | 268 |
class DRBD8(base.BlockDev): |
155 | 269 |
"""DRBD v8.x block device. |
156 | 270 |
|
... | ... | |
164 | 278 |
is checked for valid size and is zeroed on create. |
165 | 279 |
|
166 | 280 |
""" |
167 |
_VERSION_RE = re.compile(r"^version: (\d+)\.(\d+)\.(\d+)(?:\.\d+)?" |
|
168 |
r" \(api:(\d+)/proto:(\d+)(?:-(\d+))?\)") |
|
169 |
_VALID_LINE_RE = re.compile("^ *([0-9]+): cs:([^ ]+).*$") |
|
170 |
_UNUSED_LINE_RE = re.compile("^ *([0-9]+): cs:Unconfigured$") |
|
171 |
|
|
172 | 281 |
_DRBD_MAJOR = 147 |
173 |
_ST_UNCONFIGURED = DRBD8Status.CS_UNCONFIGURED |
|
174 |
_ST_WFCONNECTION = DRBD8Status.CS_WFCONNECTION |
|
175 |
_ST_CONNECTED = DRBD8Status.CS_CONNECTED |
|
176 | 282 |
|
177 |
_STATUS_FILE = constants.DRBD_STATUS_FILE |
|
178 | 283 |
_USERMODE_HELPER_FILE = "/sys/module/drbd/parameters/usermode_helper" |
179 | 284 |
|
180 | 285 |
_MAX_MINORS = 255 |
... | ... | |
205 | 310 |
children = [] |
206 | 311 |
super(DRBD8, self).__init__(unique_id, children, size, params) |
207 | 312 |
self.major = self._DRBD_MAJOR |
208 |
version = self._GetVersion(self._GetProcData()) |
|
313 |
|
|
314 |
drbd_info = DRBD8Info.CreateFromFile() |
|
315 |
version = drbd_info.GetVersion() |
|
209 | 316 |
if version["k_major"] != 8: |
210 | 317 |
base.ThrowError("Mismatch in DRBD kernel version and requested ganeti" |
211 | 318 |
" usage: kernel is %s.%s, ganeti wants 8.x", |
... | ... | |
218 | 325 |
self.Attach() |
219 | 326 |
|
220 | 327 |
@staticmethod |
221 |
def _GetProcData(filename=_STATUS_FILE): |
|
222 |
"""Return data from /proc/drbd. |
|
223 |
|
|
224 |
""" |
|
225 |
try: |
|
226 |
data = utils.ReadFile(filename).splitlines() |
|
227 |
except EnvironmentError, err: |
|
228 |
if err.errno == errno.ENOENT: |
|
229 |
base.ThrowError("The file %s cannot be opened, check if the module" |
|
230 |
" is loaded (%s)", filename, str(err)) |
|
231 |
else: |
|
232 |
base.ThrowError("Can't read the DRBD proc file %s: %s", |
|
233 |
filename, str(err)) |
|
234 |
if not data: |
|
235 |
base.ThrowError("Can't read any data from %s", filename) |
|
236 |
return data |
|
237 |
|
|
238 |
@classmethod |
|
239 |
def _JoinProcDataPerMinor(cls, data): |
|
240 |
"""Transform the output of _GetProdData into a nicer form. |
|
241 |
|
|
242 |
@return: a dictionary of minor: joined lines from /proc/drbd |
|
243 |
for that minor |
|
244 |
|
|
245 |
""" |
|
246 |
results = {} |
|
247 |
old_minor = old_line = None |
|
248 |
for line in data: |
|
249 |
if not line: # completely empty lines, as can be returned by drbd8.0+ |
|
250 |
continue |
|
251 |
lresult = cls._VALID_LINE_RE.match(line) |
|
252 |
if lresult is not None: |
|
253 |
if old_minor is not None: |
|
254 |
results[old_minor] = old_line |
|
255 |
old_minor = int(lresult.group(1)) |
|
256 |
old_line = line |
|
257 |
else: |
|
258 |
if old_minor is not None: |
|
259 |
old_line += " " + line.strip() |
|
260 |
# add last line |
|
261 |
if old_minor is not None: |
|
262 |
results[old_minor] = old_line |
|
263 |
return results |
|
264 |
|
|
265 |
@classmethod |
|
266 |
def _GetVersion(cls, proc_data): |
|
267 |
"""Return the DRBD version. |
|
268 |
|
|
269 |
This will return a dict with keys: |
|
270 |
- k_major |
|
271 |
- k_minor |
|
272 |
- k_point |
|
273 |
- api |
|
274 |
- proto |
|
275 |
- proto2 (only on drbd > 8.2.X) |
|
276 |
|
|
277 |
""" |
|
278 |
first_line = proc_data[0].strip() |
|
279 |
version = cls._VERSION_RE.match(first_line) |
|
280 |
if not version: |
|
281 |
raise errors.BlockDeviceError("Can't parse DRBD version from '%s'" % |
|
282 |
first_line) |
|
283 |
|
|
284 |
values = version.groups() |
|
285 |
retval = { |
|
286 |
"k_major": int(values[0]), |
|
287 |
"k_minor": int(values[1]), |
|
288 |
"k_point": int(values[2]), |
|
289 |
"api": int(values[3]), |
|
290 |
"proto": int(values[4]), |
|
291 |
} |
|
292 |
if values[5] is not None: |
|
293 |
retval["proto2"] = values[5] |
|
294 |
|
|
295 |
return retval |
|
296 |
|
|
297 |
@staticmethod |
|
298 | 328 |
def GetUsermodeHelper(filename=_USERMODE_HELPER_FILE): |
299 | 329 |
"""Returns DRBD usermode_helper currently set. |
300 | 330 |
|
... | ... | |
324 | 354 |
"""Compute the list of used DRBD devices. |
325 | 355 |
|
326 | 356 |
""" |
327 |
data = cls._GetProcData() |
|
328 |
|
|
329 |
used_devs = {} |
|
330 |
for line in data: |
|
331 |
match = cls._VALID_LINE_RE.match(line) |
|
332 |
if not match: |
|
333 |
continue |
|
334 |
minor = int(match.group(1)) |
|
335 |
state = match.group(2) |
|
336 |
if state == cls._ST_UNCONFIGURED: |
|
337 |
continue |
|
338 |
used_devs[minor] = state, line |
|
339 |
|
|
340 |
return used_devs |
|
357 |
drbd_info = DRBD8Info.CreateFromFile() |
|
358 |
return filter(lambda m: not drbd_info.GetMinorStatus(m).is_unconfigured, |
|
359 |
drbd_info.GetMinors()) |
|
341 | 360 |
|
342 | 361 |
def _SetFromMinor(self, minor): |
343 | 362 |
"""Set our parameters based on the given minor. |
... | ... | |
406 | 425 |
if result.failed: |
407 | 426 |
base.ThrowError("Can't initialize meta device: %s", result.output) |
408 | 427 |
|
409 |
@classmethod |
|
410 |
def _FindUnusedMinor(cls): |
|
428 |
def _FindUnusedMinor(self): |
|
411 | 429 |
"""Find an unused DRBD device. |
412 | 430 |
|
413 | 431 |
This is specific to 8.x as the minors are allocated dynamically, |
414 | 432 |
so non-existing numbers up to a max minor count are actually free. |
415 | 433 |
|
416 | 434 |
""" |
417 |
data = cls._GetProcData() |
|
418 | 435 |
|
419 | 436 |
highest = None |
420 |
for line in data: |
|
421 |
match = cls._UNUSED_LINE_RE.match(line) |
|
422 |
if match: |
|
423 |
return int(match.group(1)) |
|
424 |
match = cls._VALID_LINE_RE.match(line) |
|
425 |
if match: |
|
426 |
minor = int(match.group(1)) |
|
427 |
highest = max(highest, minor) |
|
437 |
drbd_info = DRBD8Info.CreateFromFile() |
|
438 |
for minor in drbd_info.GetMinors(): |
|
439 |
status = drbd_info.GetMinorStatus(minor) |
|
440 |
if not status.is_in_use: |
|
441 |
return minor |
|
442 |
highest = max(highest, minor) |
|
443 |
|
|
428 | 444 |
if highest is None: # there are no minors in use at all |
429 | 445 |
return 0 |
430 |
if highest >= cls._MAX_MINORS:
|
|
446 |
if highest >= self._MAX_MINORS:
|
|
431 | 447 |
logging.error("Error: no free drbd minors!") |
432 | 448 |
raise errors.BlockDeviceError("Can't find a free DRBD minor") |
449 |
|
|
433 | 450 |
return highest + 1 |
434 | 451 |
|
435 | 452 |
@classmethod |
... | ... | |
607 | 624 |
if size: |
608 | 625 |
args.extend(["-d", "%sm" % size]) |
609 | 626 |
|
610 |
version = self._GetVersion(self._GetProcData()) |
|
627 |
drbd_info = DRBD8Info.CreateFromFile() |
|
628 |
version = drbd_info.GetVersion() |
|
611 | 629 |
vmaj = version["k_major"] |
612 | 630 |
vmin = version["k_minor"] |
613 | 631 |
vrel = version["k_point"] |
... | ... | |
822 | 840 |
self._ShutdownLocal(self.minor) |
823 | 841 |
self._children = [] |
824 | 842 |
|
825 |
@classmethod |
|
826 |
def _SetMinorSyncParams(cls, minor, params): |
|
843 |
def _SetMinorSyncParams(self, minor, params): |
|
827 | 844 |
"""Set the parameters of the DRBD syncer. |
828 | 845 |
|
829 | 846 |
This is the low-level implementation. |
... | ... | |
837 | 854 |
|
838 | 855 |
""" |
839 | 856 |
|
840 |
args = ["drbdsetup", cls._DevPath(minor), "syncer"]
|
|
857 |
args = ["drbdsetup", self._DevPath(minor), "syncer"]
|
|
841 | 858 |
if params[constants.LDP_DYNAMIC_RESYNC]: |
842 |
version = cls._GetVersion(cls._GetProcData()) |
|
859 |
drbd_info = DRBD8Info.CreateFromFile() |
|
860 |
version = drbd_info.GetVersion() |
|
843 | 861 |
vmin = version["k_minor"] |
844 | 862 |
vrel = version["k_point"] |
845 | 863 |
|
... | ... | |
929 | 947 |
if self.minor is None: |
930 | 948 |
base.ThrowError("drbd%d: GetStats() called while not attached", |
931 | 949 |
self._aminor) |
932 |
proc_info = self._JoinProcDataPerMinor(self._GetProcData())
|
|
933 |
if self.minor not in proc_info:
|
|
950 |
drbd_info = DRBD8Info.CreateFromFile()
|
|
951 |
if not drbd_info.HasMinorStatus(self.minor):
|
|
934 | 952 |
base.ThrowError("drbd%d: can't find myself in /proc", self.minor) |
935 |
return DRBD8Status(proc_info[self.minor])
|
|
953 |
return drbd_info.GetMinorStatus(self.minor)
|
|
936 | 954 |
|
937 | 955 |
def GetSyncStatus(self): |
938 | 956 |
"""Returns the sync status of the device. |
... | ... | |
1312 | 1330 |
" exclusive_storage") |
1313 | 1331 |
# check that the minor is unused |
1314 | 1332 |
aminor = unique_id[4] |
1315 |
proc_info = cls._JoinProcDataPerMinor(cls._GetProcData()) |
|
1316 |
if aminor in proc_info: |
|
1317 |
status = DRBD8Status(proc_info[aminor]) |
|
1333 |
|
|
1334 |
drbd_info = DRBD8Info.CreateFromFile() |
|
1335 |
if drbd_info.HasMinorStatus(aminor): |
|
1336 |
status = drbd_info.GetMinorStatus(aminor) |
|
1318 | 1337 |
in_use = status.is_in_use |
1319 | 1338 |
else: |
1320 | 1339 |
in_use = False |
b/lib/watcher/nodemaint.py | ||
---|---|---|
80 | 80 |
"""Get list of used DRBD minors. |
81 | 81 |
|
82 | 82 |
""" |
83 |
return drbd.DRBD8.GetUsedDevs().keys()
|
|
83 |
return drbd.DRBD8.GetUsedDevs() |
|
84 | 84 |
|
85 | 85 |
@classmethod |
86 | 86 |
def DoMaintenance(cls, role): |
b/test/data/proc_drbd80-emptyline.txt | ||
---|---|---|
1 |
version: 8.0.12 (api:86/proto:86) |
|
1 | 2 |
GIT-hash: 5c9f89594553e32adb87d9638dce591782f947e3 build by root@node1.example.com, 2009-05-22 12:47:52 |
2 | 3 |
0: cs:Connected st:Primary/Secondary ds:UpToDate/UpToDate C r--- |
3 | 4 |
ns:78728316 nr:0 dw:77675644 dr:1277039 al:254 bm:270 lo:0 pe:0 ua:0 ap:0 |
b/test/hs/Test/Ganeti/Block/Drbd/Parser.hs | ||
---|---|---|
52 | 52 |
case_drbd80_emptyline :: Assertion |
53 | 53 |
case_drbd80_emptyline = testFile "proc_drbd80-emptyline.txt" $ |
54 | 54 |
DRBDStatus |
55 |
( VersionInfo Nothing Nothing Nothing Nothing
|
|
55 |
( VersionInfo (Just "8.0.12") (Just "86") (Just "86") Nothing
|
|
56 | 56 |
(Just "5c9f89594553e32adb87d9638dce591782f947e3") |
57 | 57 |
(Just "root@node1.example.com, 2009-05-22 12:47:52") |
58 | 58 |
) |
b/test/py/ganeti.block.bdev_unittest.py | ||
---|---|---|
71 | 71 |
} |
72 | 72 |
] |
73 | 73 |
for d,r in zip(data, result): |
74 |
self.assertEqual(drbd.DRBD8._GetVersion(d), r) |
|
74 |
info = drbd.DRBD8Info.CreateFromLines(d) |
|
75 |
self.assertEqual(info.GetVersion(), r) |
|
75 | 76 |
|
76 | 77 |
|
77 | 78 |
class TestDRBD8Runner(testutils.GanetiTestCase): |
... | ... | |
244 | 245 |
proc83_sync_data = testutils.TestDataFilename("proc_drbd83_sync.txt") |
245 | 246 |
proc83_sync_krnl_data = \ |
246 | 247 |
testutils.TestDataFilename("proc_drbd83_sync_krnl2.6.39.txt") |
247 |
self.proc_data = drbd.DRBD8._GetProcData(filename=proc_data) |
|
248 |
self.proc80e_data = drbd.DRBD8._GetProcData(filename=proc80e_data) |
|
249 |
self.proc83_data = drbd.DRBD8._GetProcData(filename=proc83_data) |
|
250 |
self.proc83_sync_data = drbd.DRBD8._GetProcData(filename=proc83_sync_data) |
|
251 |
self.proc83_sync_krnl_data = \ |
|
252 |
drbd.DRBD8._GetProcData(filename=proc83_sync_krnl_data) |
|
253 |
self.mass_data = drbd.DRBD8._JoinProcDataPerMinor(self.proc_data) |
|
254 |
self.mass80e_data = drbd.DRBD8._JoinProcDataPerMinor(self.proc80e_data) |
|
255 |
self.mass83_data = drbd.DRBD8._JoinProcDataPerMinor(self.proc83_data) |
|
256 |
self.mass83_sync_data = \ |
|
257 |
drbd.DRBD8._JoinProcDataPerMinor(self.proc83_sync_data) |
|
258 |
self.mass83_sync_krnl_data = \ |
|
259 |
drbd.DRBD8._JoinProcDataPerMinor(self.proc83_sync_krnl_data) |
|
248 |
|
|
249 |
self.drbd_info = drbd.DRBD8Info.CreateFromFile(filename=proc_data) |
|
250 |
self.drbd_info80e = drbd.DRBD8Info.CreateFromFile(filename=proc80e_data) |
|
251 |
self.drbd_info83 = drbd.DRBD8Info.CreateFromFile(filename=proc83_data) |
|
252 |
self.drbd_info83_sync = \ |
|
253 |
drbd.DRBD8Info.CreateFromFile(filename=proc83_sync_data) |
|
254 |
self.drbd_info83_sync_krnl = \ |
|
255 |
drbd.DRBD8Info.CreateFromFile(filename=proc83_sync_krnl_data) |
|
260 | 256 |
|
261 | 257 |
def testIOErrors(self): |
262 | 258 |
"""Test handling of errors while reading the proc file.""" |
263 | 259 |
temp_file = self._CreateTempFile() |
264 | 260 |
os.unlink(temp_file) |
265 | 261 |
self.failUnlessRaises(errors.BlockDeviceError, |
266 |
drbd.DRBD8._GetProcData, filename=temp_file)
|
|
262 |
drbd.DRBD8Info.CreateFromFile, filename=temp_file)
|
|
267 | 263 |
|
268 | 264 |
def testHelper(self): |
269 | 265 |
"""Test reading usermode_helper in /sys.""" |
... | ... | |
280 | 276 |
|
281 | 277 |
def testMinorNotFound(self): |
282 | 278 |
"""Test not-found-minor in /proc""" |
283 |
self.failUnless(9 not in self.mass_data)
|
|
284 |
self.failUnless(9 not in self.mass83_data)
|
|
285 |
self.failUnless(3 not in self.mass80e_data)
|
|
279 |
self.failUnless(not self.drbd_info.HasMinorStatus(9))
|
|
280 |
self.failUnless(not self.drbd_info83.HasMinorStatus(9))
|
|
281 |
self.failUnless(not self.drbd_info80e.HasMinorStatus(3))
|
|
286 | 282 |
|
287 | 283 |
def testLineNotMatch(self): |
288 | 284 |
"""Test wrong line passed to drbd.DRBD8Status""" |
... | ... | |
290 | 286 |
|
291 | 287 |
def testMinor0(self): |
292 | 288 |
"""Test connected, primary device""" |
293 |
for data in [self.mass_data, self.mass83_data]:
|
|
294 |
stats = drbd.DRBD8Status(data[0])
|
|
289 |
for info in [self.drbd_info, self.drbd_info83]:
|
|
290 |
stats = info.GetMinorStatus(0)
|
|
295 | 291 |
self.failUnless(stats.is_in_use) |
296 | 292 |
self.failUnless(stats.is_connected and stats.is_primary and |
297 | 293 |
stats.peer_secondary and stats.is_disk_uptodate) |
298 | 294 |
|
299 | 295 |
def testMinor1(self): |
300 | 296 |
"""Test connected, secondary device""" |
301 |
for data in [self.mass_data, self.mass83_data]:
|
|
302 |
stats = drbd.DRBD8Status(data[1])
|
|
297 |
for info in [self.drbd_info, self.drbd_info83]:
|
|
298 |
stats = info.GetMinorStatus(1)
|
|
303 | 299 |
self.failUnless(stats.is_in_use) |
304 | 300 |
self.failUnless(stats.is_connected and stats.is_secondary and |
305 | 301 |
stats.peer_primary and stats.is_disk_uptodate) |
306 | 302 |
|
307 | 303 |
def testMinor2(self): |
308 | 304 |
"""Test unconfigured device""" |
309 |
for data in [self.mass_data, self.mass83_data, self.mass80e_data]:
|
|
310 |
stats = drbd.DRBD8Status(data[2])
|
|
305 |
for info in [self.drbd_info, self.drbd_info83, self.drbd_info80e]:
|
|
306 |
stats = info.GetMinorStatus(2)
|
|
311 | 307 |
self.failIf(stats.is_in_use) |
312 | 308 |
|
313 | 309 |
def testMinor4(self): |
314 | 310 |
"""Test WFconn device""" |
315 |
for data in [self.mass_data, self.mass83_data]:
|
|
316 |
stats = drbd.DRBD8Status(data[4])
|
|
311 |
for info in [self.drbd_info, self.drbd_info83]:
|
|
312 |
stats = info.GetMinorStatus(4)
|
|
317 | 313 |
self.failUnless(stats.is_in_use) |
318 | 314 |
self.failUnless(stats.is_wfconn and stats.is_primary and |
319 | 315 |
stats.rrole == "Unknown" and |
... | ... | |
321 | 317 |
|
322 | 318 |
def testMinor6(self): |
323 | 319 |
"""Test diskless device""" |
324 |
for data in [self.mass_data, self.mass83_data]:
|
|
325 |
stats = drbd.DRBD8Status(data[6])
|
|
320 |
for info in [self.drbd_info, self.drbd_info83]:
|
|
321 |
stats = info.GetMinorStatus(6)
|
|
326 | 322 |
self.failUnless(stats.is_in_use) |
327 | 323 |
self.failUnless(stats.is_connected and stats.is_secondary and |
328 | 324 |
stats.peer_primary and stats.is_diskless) |
329 | 325 |
|
330 | 326 |
def testMinor8(self): |
331 | 327 |
"""Test standalone device""" |
332 |
for data in [self.mass_data, self.mass83_data]:
|
|
333 |
stats = drbd.DRBD8Status(data[8])
|
|
328 |
for info in [self.drbd_info, self.drbd_info83]:
|
|
329 |
stats = info.GetMinorStatus(8)
|
|
334 | 330 |
self.failUnless(stats.is_in_use) |
335 | 331 |
self.failUnless(stats.is_standalone and |
336 | 332 |
stats.rrole == "Unknown" and |
337 | 333 |
stats.is_disk_uptodate) |
338 | 334 |
|
339 | 335 |
def testDRBD83SyncFine(self): |
340 |
stats = drbd.DRBD8Status(self.mass83_sync_data[3])
|
|
336 |
stats = self.drbd_info83_sync.GetMinorStatus(3)
|
|
341 | 337 |
self.failUnless(stats.is_in_resync) |
342 | 338 |
self.failUnless(stats.sync_percent is not None) |
343 | 339 |
|
344 | 340 |
def testDRBD83SyncBroken(self): |
345 |
stats = drbd.DRBD8Status(self.mass83_sync_krnl_data[3])
|
|
341 |
stats = self.drbd_info83_sync_krnl.GetMinorStatus(3)
|
|
346 | 342 |
self.failUnless(stats.is_in_resync) |
347 | 343 |
self.failUnless(stats.sync_percent is not None) |
348 | 344 |
|
Also available in: Unified diff