Skip to content

Commit 260ece7

Browse files
Tim SmithTimSmithCtx
Tim Smith
authored andcommitted
CP-54096 Move most of mpathcount.py into libs
What used to be /opt/xensource/sm/mpathcount.py is now /usr/libexec/sm/mpathcount. The non-cli part has been moved to the python install path for sm.pathcount Signed-off-by: Tim Smith <[email protected]>
1 parent e74bd48 commit 260ece7

File tree

5 files changed

+267
-240
lines changed

5 files changed

+267
-240
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ SM_CORE_LIBS += f_exceptions
3333
SM_CORE_LIBS += libiscsi
3434

3535
SM_LIBS := cleanup
36+
SM_LIBS += mpathcount
3637

3738
# Things used as commands which install in libexec
3839
# which are in python and need compatibility symlinks from

drivers/mpathcount

+19-221
Original file line numberDiff line numberDiff line change
@@ -15,218 +15,16 @@
1515
# along with this program; if not, write to the Free Software Foundation, Inc.,
1616
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1717

18-
from sm.core import util
1918
import os
2019
import sys
2120
import re
22-
from sm.core import xs_errors
23-
from sm.core import mpath_cli
2421
import json
2522
import subprocess
2623

27-
supported = ['iscsi', 'lvmoiscsi', 'rawhba', 'lvmohba', 'ocfsohba', 'ocfsoiscsi', 'netapp', 'gfs2']
28-
29-
LOCK_TYPE_HOST = "host"
30-
LOCK_NS1 = "mpathcount1"
31-
LOCK_NS2 = "mpathcount2"
32-
33-
MAPPER_DIR = "/dev/mapper"
34-
MPATHS_DIR = "/dev/shm"
35-
MPATH_FILE_NAME = "/dev/shm/mpath_status"
36-
match_bySCSIid = False
37-
mpath_enabled = True
38-
SCSIid = 'NOTSUPPLIED'
39-
XAPI_HEALTH_CHECK = '/opt/xensource/libexec/xapi-health-check'
40-
41-
cached_DM_maj = None
42-
43-
def get_dm_major():
44-
global cached_DM_maj
45-
if not cached_DM_maj:
46-
try:
47-
line = [x for x in open('/proc/devices').readlines() if x.endswith('device-mapper\n')]
48-
cached_DM_maj = int(line[0].split()[0])
49-
except:
50-
pass
51-
return cached_DM_maj
52-
53-
54-
def mpc_exit(session, code):
55-
if session is not None:
56-
try:
57-
session.xenapi.session.logout()
58-
except:
59-
pass
60-
sys.exit(code)
61-
62-
63-
def match_host_id(s):
64-
regex = re.compile("^INSTALLATION_UUID")
65-
return regex.search(s, 0)
66-
67-
68-
def get_localhost_uuid():
69-
filename = '/etc/xensource-inventory'
70-
try:
71-
f = open(filename, 'r')
72-
except:
73-
raise xs_errors.XenError('EIO', \
74-
opterr="Unable to open inventory file [%s]" % filename)
75-
domid = ''
76-
for line in filter(match_host_id, f.readlines()):
77-
domid = line.split("'")[1]
78-
return domid
79-
80-
81-
def match_dmpLUN(s):
82-
regex = re.compile("[0-9]*:[0-9]*:[0-9]*:[0-9]*")
83-
return regex.search(s, 0)
84-
85-
86-
def match_pathup(s):
87-
path_status = None
88-
match = re.match(r'.*\d+:\d+:\d+:\d+\s+\S+\s+\S+\s+\S+\s+(\S+)', s)
89-
if match:
90-
path_status = match.group(1)
91-
if path_status in ['faulty', 'shaky', 'failed']:
92-
return False
93-
return True
94-
95-
96-
def _tostring(l):
97-
return str(l)
98-
99-
100-
def get_path_count(SCSIid):
101-
count = 0
102-
total = 0
103-
lines = mpath_cli.get_topology(SCSIid)
104-
for line in filter(match_dmpLUN, lines):
105-
total += 1
106-
if match_pathup(line):
107-
count += 1
108-
return (count, total)
109-
110-
111-
def get_root_dev_major():
112-
buf = os.stat('/')
113-
devno = buf.st_dev
114-
return os.major(devno)
115-
116-
117-
# @key: key to update
118-
# @SCSIid: SCSI id of multipath map
119-
# @entry: string representing previous value
120-
# @remove: callback to remove key
121-
# @add: callback to add key/value pair
122-
# @mpath_status: map to record multipath status
123-
def update_config(key, SCSIid, entry, remove, add, mpath_status=None):
124-
path = os.path.join(MAPPER_DIR, SCSIid)
125-
util.SMlog("MPATH: Updating entry for [%s], current: %s" % (SCSIid, entry))
126-
if os.path.exists(path):
127-
count, total = get_path_count(SCSIid)
128-
max = 0
129-
if len(entry) != 0:
130-
try:
131-
p = entry.strip('[')
132-
p = p.strip(']')
133-
q = p.split(',')
134-
max = int(q[1])
135-
except:
136-
pass
137-
if total > max:
138-
max = total
139-
newentry = [count, max]
140-
if str(newentry) != entry:
141-
remove('multipathed')
142-
remove(key)
143-
add('multipathed', 'true')
144-
add(key, str(newentry))
145-
util.SMlog("MPATH: Set val: %s" % str(newentry))
146-
if mpath_status != None:
147-
mpath_status.update({str(key): f"{count}/{max}"})
148-
else:
149-
util.SMlog('MPATH: device %s gone' % (SCSIid))
150-
remove('multipathed')
151-
remove(key)
152-
153-
154-
def get_SCSIidlist(devconfig, sm_config):
155-
SCSIidlist = []
156-
if 'SCSIid' in sm_config:
157-
SCSIidlist = sm_config['SCSIid'].split(',')
158-
elif 'SCSIid' in devconfig:
159-
SCSIidlist.append(devconfig['SCSIid'])
160-
elif 'provider' in devconfig:
161-
SCSIidlist.append(devconfig['ScsiId'])
162-
else:
163-
for key in sm_config:
164-
if util._isSCSIid(key):
165-
SCSIidlist.append(re.sub("^scsi-", "", key))
166-
return SCSIidlist
167-
168-
169-
def check_root_disk(config, maps, remove, add):
170-
if get_root_dev_major() == get_dm_major():
171-
# Ensure output headers are not in the list
172-
if 'name' in maps:
173-
maps.remove('name')
174-
# first map will always correspond to the root dev, dm-0
175-
assert(len(maps) > 0)
176-
i = maps[0]
177-
if (not match_bySCSIid) or i == SCSIid:
178-
util.SMlog("Matched SCSIid %s, updating " \
179-
" Host.other-config:mpath-boot " % i)
180-
key = "mpath-boot"
181-
if key not in config:
182-
update_config(key, i, "", remove, add)
183-
else:
184-
update_config(key, i, config[key], remove, add)
185-
186-
187-
def check_devconfig(devconfig, sm_config, config, remove, add, mpath_status=None):
188-
SCSIidlist = get_SCSIidlist(devconfig, sm_config)
189-
if not len(SCSIidlist):
190-
return
191-
for i in SCSIidlist:
192-
if match_bySCSIid and i != SCSIid:
193-
continue
194-
util.SMlog("Matched SCSIid, updating %s" % i)
195-
key = "mpath-" + i
196-
if not mpath_enabled:
197-
remove(key)
198-
remove('multipathed')
199-
else:
200-
if key not in config:
201-
update_config(key, i, "", remove, add, mpath_status)
202-
else:
203-
update_config(key, i, config[key], remove, add, mpath_status)
204-
205-
def check_xapi_is_enabled():
206-
"""Check XAPI health status"""
207-
def _run_command(command, timeout):
208-
try:
209-
process = subprocess.Popen(
210-
command,
211-
stdout=subprocess.PIPE,
212-
stderr=subprocess.PIPE,
213-
universal_newlines=True
214-
)
215-
try:
216-
stdout, stderr = process.communicate(timeout=timeout)
217-
return process.returncode, stdout, stderr
218-
except subprocess.TimeoutExpired:
219-
process.kill()
220-
util.SMlog(f"Command execution timeout after {timeout}s: {' '.join(command)}")
221-
return -1, "", "Timeout"
222-
except Exception as e:
223-
util.SMlog(f"Error executing command: {e}")
224-
return -1, "", str(e)
225-
226-
returncode, _, stderr = _run_command([XAPI_HEALTH_CHECK], timeout=120)
227-
if returncode != 0:
228-
util.SMlog(f"XAPI health check failed: {stderr}")
229-
return returncode == 0
24+
from sm.core import util
25+
from sm.core import xs_errors
26+
from sm.core import mpath_cli
27+
from sm import mpathcount
23028

23129
if __name__ == '__main__':
23230
try:
@@ -235,16 +33,16 @@ if __name__ == '__main__':
23533
print("Unable to open local XAPI session")
23634
sys.exit(-1)
23735

238-
localhost = session.xenapi.host.get_by_uuid(get_localhost_uuid())
239-
check_xapi_is_enabled()
36+
localhost = session.xenapi.host.get_by_uuid(mpathcount.get_localhost_uuid())
37+
mpathcount.check_xapi_is_enabled()
24038
# Check whether multipathing is enabled (either for root dev or SRs)
24139
try:
242-
if get_root_dev_major() != get_dm_major():
40+
if mpathcount.get_root_dev_major() != mpathcount.get_dm_major():
24341
hconf = session.xenapi.host.get_other_config(localhost)
24442
assert(hconf['multipathing'] == 'true')
245-
mpath_enabled = True
43+
mpathcount.mpath_enabled = True
24644
except:
247-
mpath_enabled = False
45+
mpathcount.mpath_enabled = False
24846

24947
# Check root disk if multipathed
25048
try:
@@ -256,16 +54,16 @@ if __name__ == '__main__':
25654
session.xenapi.host.add_to_other_config(localhost, key, val)
25755
config = session.xenapi.host.get_other_config(localhost)
25856
maps = mpath_cli.list_maps()
259-
check_root_disk(config, maps, _remove, _add)
57+
mpathcount.check_root_disk(config, maps, _remove, _add)
26058

26159
except:
26260
util.SMlog("MPATH: Failure updating Host.other-config:mpath-boot db")
263-
mpc_exit(session, -1)
61+
mpathcount.mpc_exit(session, -1)
26462

26563
try:
26664
pbds = session.xenapi.PBD.get_all_records_where("field \"host\" = \"%s\"" % localhost)
26765
except:
268-
mpc_exit(session, -1)
66+
mpathcount.mpc_exit(session, -1)
26967

27068
try:
27169
mpath_status = {}
@@ -280,17 +78,17 @@ if __name__ == '__main__':
28078
config = record['other_config']
28179
SR = record['SR']
28280
srtype = session.xenapi.SR.get_type(SR)
283-
if srtype in supported:
81+
if srtype in mpathcount.supported:
28482
devconfig = record["device_config"]
28583
sm_config = session.xenapi.SR.get_sm_config(SR)
286-
check_devconfig(devconfig, sm_config, config, remove, add, mpath_status)
287-
mpath_status = mpath_status if mpath_enabled else {}
288-
util.atomicFileWrite(MPATH_FILE_NAME, MPATHS_DIR, json.dumps(mpath_status))
289-
os.chmod(MPATH_FILE_NAME, 0o0644)
84+
mpathcount.check_devconfig(devconfig, sm_config, config, remove, add, mpath_status)
85+
mpath_status = mpath_status if mpathcount.mpath_enabled else {}
86+
util.atomicFileWrite(mpathcount.MPATH_FILE_NAME, mpathcount.MPATHS_DIR, json.dumps(mpath_status))
87+
os.chmod(mpathcount.MPATH_FILE_NAME, 0o0644)
29088
except:
29189
util.SMlog("MPATH: Failure updating db. %s" % sys.exc_info())
292-
mpc_exit(session, -1)
90+
mpathcount.mpc_exit(session, -1)
29391

29492
util.SMlog("MPATH: Update done")
29593

296-
mpc_exit(session, 0)
94+
mpathcount.mpc_exit(session, 0)

0 commit comments

Comments
 (0)