-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfakemtx.py
134 lines (111 loc) · 4.68 KB
/
fakemtx.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python3
"""Pretends to be mtx.py, but just executes shell commands and parses the output"""
import sh
import re
# import json
import logging
logger = logging.getLogger(__name__)
class Changer(object):
"""Changer
Represents a media changer device, and uses pyscsi to control it
"""
def __init__(self, changer, do_status_update=False):
self.status = {}
self.ioslot = None
self.changer = changer
if do_status_update:
self.update_status()
def update_status(self):
rawstatus = sh.mtx('-f', self.changer, "altres", "status").split("\n")
mtxregexstring = "Storage Element (?P<number>[0-9]*)(?P<io> IMPORT/EXPORT|):"
mtxregexstring += "(?P<state>Empty|Full).*"
mtxregex = re.compile(mtxregexstring)
for line in rawstatus:
parseresult = mtxregex.match(line.strip())
if parseresult is not None:
status = parseresult.groupdict()
# If this is our import/export slot, make note of it
if status['io'] != "":
self.ioslot = status['number']
# If this is our first run and we're just learning about the different elements
elif status['number'] not in self.status:
self.status[status['number']] = {}
self.status[status['number']]['full'] = status['state'] == "Full"
# If we previously believed this to be in a different state than it is, then our
# information about what's in there is probably wrong
elif 'state' in self.status[status['number']]:
if status['state'] != self.status[status['number']]['state']:
self.status[status['number']] = {}
self.status[status['number']]['full'] = status['state'] == "Full"
return self.status
def load(self, slot=None):
"""
Causes the changer to accept a disk and load it into the specified slot. If no slot is
specified, it selects an empty slot (update_status() must have been run already). Returns
the slot the disk was inserted into
"""
if self.ioslot is None:
raise NeverScannedError()
if slot is None:
for possible in self.status:
if self.status[possible]['full'] is False:
slot = possible
if slot is None:
# No slots available to load stuff into
raise NoSlotsAvailableError()
try:
sh.mtx('-f', self.changer, 'altres', 'eepos', '0', 'transfer', self.ioslot, slot)
self.status[slot]['full'] = True
return slot
except sh.ErrorReturnCode_1:
return False
def eject(self, slot):
"""
Causes the changer to unload the disk from the specified slot and eject it from the changer
"""
ejected = False
try:
sh.mtx('-f', self.changer, 'altres', 'eepos', '0', 'transfer', slot, self.ioslot)
ejected = True
self.status[slot]['full'] = False
except sh.ErrorReturnCode_1:
pass
return ejected
def load_drive(self, slot, drive=0):
"""
Loads the disk from the specified slot into the specified drive (default drive is 0)
"""
try:
sh.mtx('-f', self.changer, 'altres', 'load', slot, drive)
except sh.ErrorReturnCode_1:
raise DriveAlreadyLoaded()
def unload_drive(self, slot=None, drive=0):
"""
Unloads the disc from the specified drive (default 0) into the specified slot, or the slot
slot that the disc originally came from if unspecified
"""
try:
if slot is None:
sh.mtx('-f', self.changer, 'altres', 'unload')
else:
sh.mtx('-f', self.changer, 'altres', 'unload', slot)
except sh.ErrorReturnCode_1:
raise FailedToUnloadDrive()
def get_status(self):
return self.status
class IncorrectDeviceTypeError(Exception):
def __str__(self):
return "The device you selected is not a media changer"
class NeverScannedError(Exception):
def __str__(self):
err = "That operation can't be completed until you've run updateStatus() at least once"
return err
class NoSlotsAvailableError(Exception):
def __str__(self):
return "No slots are available to load the disk into!"
class DriveAlreadyLoaded(Exception):
def __str__(self):
return "There is already a disk in the drive!"
class FailedToUnloadDrive(Exception):
def __str__(self):
return "Failed to unload the drive"