Coverage for sm/core/scsiutil.py : 31%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Fake scsiutil module"""
3import glob
4import os
5import re
6import traceback
8from . import f_exceptions
9from . import util
10from . import mpath_cli
12SECTOR_SHIFT = 9
14def match_dm(s):
15 regex = re.compile("mapper/")
16 return regex.search(s, 0)
19def getdev(path):
20 realpath = os.path.realpath(path)
21 if match_dm(realpath):
22 newpath = realpath.replace("/dev/mapper/","/dev/disk/by-id/scsi-")
23 else:
24 newpath = path
25 return os.path.realpath(newpath).split('/')[-1]
28def getsize(path):
29 dev = getdev(path)
30 sysfs = os.path.join('/sys/block',dev,'size')
31 size = 0
32 if os.path.exists(sysfs):
33 try:
34 f=open(sysfs, 'r')
35 size = (int(f.readline()) << SECTOR_SHIFT)
36 f.close()
37 except:
38 pass
39 return size
42def get_vendor(device_path):
43 vendor_command = ['sginfo', '-M', device_path]
44 (rc, stdout, _) = util.doexec(vendor_command)
45 if rc != 0:
46 raise f_exceptions.XenError(
47 'SCSIRead', 'sginfo failed {}, {}'.format(device_path, rc))
49 match = re.search(r'(^|.*\n)Vendor:\s+(.*)[$|\n]', stdout)
50 if not match:
51 raise f_exceptions.XenError(
52 'SCSIRead', 'sginfo no vendor match {}'.format(device_path))
53 return match.group(2).strip()
56def get_serial(device_path):
57 serial_command = ['sginfo', '-s', device_path]
58 (rc, stdout, _) = util.doexec(serial_command)
59 if rc != 0:
60 raise f_exceptions.XenError(
61 'SCSIRead', 'sginfo failed {}, {}'.format(device_path, rc))
63 match = re.search(r'(^|.*\n)Serial Number\s+\'([^\']*)\'[$|\n]', stdout)
64 if not match:
65 raise f_exceptions.XenError(
66 'SCSIRead', 'sginfo no serial match {}'.format(device_path))
67 return match.group(2).strip()
70def get_devices_by_SCSIid(SCSIid):
71 devices = os.listdir(os.path.join('/dev/disk/by-scsid', SCSIid))
72 if 'mapper' in devices:
73 devices.remove('mapper')
74 return devices
77def get_device_provisioning_mode(SCSIid):
78 device = get_devices_by_SCSIid(SCSIid)[0]
79 glob_pattern = os.path.join('/sys', 'block', device, 'device', 'scsi_disk', '*', 'provisioning_mode')
80 for file in glob.glob(glob_pattern): 80 ↛ exitline 80 didn't return from function 'get_device_provisioning_mode', because the loop on line 80 didn't complete
81 with open(file, 'r') as device_mode:
82 mode = device_mode.readline().strip()
83 return mode
86def device_is_thin_provisioned(SCSIid):
87 mode = get_device_provisioning_mode(SCSIid)
88 # Kernel modes are
89 # [SD_LBP_FULL] = "full",
90 # [SD_LBP_UNMAP] = "unmap",
91 # [SD_LBP_WS16] = "writesame_16",
92 # [SD_LBP_WS10] = "writesame_10",
93 # [SD_LBP_ZERO] = "writesame_zero",
94 # [SD_LBP_DISABLE] = "disabled"
95 return mode in ['unmap', 'writesame_16', 'writesame_10', 'writesame_zero']
98def sg_readcap(device):
99 device = os.path.join('/dev', getdev(device))
100 readcapcommand = ['/usr/bin/sg_readcap', '-b', device]
101 (rc,stdout,stderr) = util.doexec(readcapcommand)
102 if rc == 6:
103 # retry one time for "Capacity data has changed"
104 (rc,stdout,stderr) = util.doexec(readcapcommand)
105 if rc != 0:
106 raise f_exceptions.XenError("SCSIRead",
107 "scsiutil.sg_readcap(%s) failed" % (device))
108 match = re.search('(^|.*\n)(0x[0-9a-fA-F]+) (0x[0-9a-fA-F]+)\n$', stdout)
109 if not match:
110 raise f_exceptions.XenError("SCSIRead",
111 "scsiutil.sg_readcap(%s) failed to parse: %s"
112 % (device, stdout))
113 (blockcount, blocksize) = match.group(2, 3)
114 return (int(blockcount, 0) * int(blocksize, 0))
117def refreshdev(pathlist):
118 """
119 Refresh block devices given a path list
120 """
121 for path in pathlist:
122 dev = getdev(path)
123 util.SMlog("Refreshing size for device %s (%s)" % (path, dev))
124 sysfs = os.path.join('/sys/block',dev,'device/rescan')
125 if os.path.exists(sysfs):
126 try:
127 f = os.open(sysfs, os.O_WRONLY)
128 os.write(f, b'1')
129 os.close(f)
130 except:
131 pass
134def refresh_lun_size_by_SCSIid(SCSIid):
135 """
136 Refresh all devices for the SCSIid.
137 Returns True if all known devices and the mapper device are up to date.
138 """
139 def get_primary_device(SCSIid):
140 mapperdevice = os.path.join('/dev/mapper', SCSIid)
141 if os.path.exists(mapperdevice):
142 return mapperdevice
143 else:
144 devices = get_devices_by_SCSIid(SCSIid)
145 if devices:
146 return devices[0]
147 else:
148 return None
150 def get_outdated_size_devices(currentcapacity, devices):
151 devicesthatneedrefresh = []
152 for device in devices:
153 if getsize(device) != currentcapacity:
154 devicesthatneedrefresh.append(device)
155 return devicesthatneedrefresh
157 def refresh_devices_if_needed(primarydevice, SCSIid, currentcapacity):
158 devices = get_devices_by_SCSIid(SCSIid)
159 if "/dev/mapper/" in primarydevice:
160 devices = set(devices + mpath_cli.list_paths(SCSIid))
161 devicesthatneedrefresh = get_outdated_size_devices(currentcapacity,
162 devices)
163 if devicesthatneedrefresh:
164 # timing out avoids waiting for min(dev_loss_tmo, fast_io_fail_tmo)
165 # if one or multiple devices don't answer
166 util.timeout_call(10, refreshdev, devicesthatneedrefresh)
167 if get_outdated_size_devices(currentcapacity,
168 devicesthatneedrefresh):
169 # in this state we shouldn't force resizing the mapper dev
170 raise f_exceptions.XenError("DeviceResize",
171 "Failed to get %s to agree on the "
172 "current capacity."
173 % devicesthatneedrefresh)
175 def refresh_mapper_if_needed(primarydevice, SCSIid, currentcapacity):
176 if ("/dev/mapper/" in primarydevice
177 and get_outdated_size_devices(currentcapacity, [primarydevice])):
178 util.SMlog("Resizing multpath map for device %s" % SCSIid)
179 mpath_cli.resize_map(SCSIid)
180 if get_outdated_size_devices(currentcapacity, [primarydevice]):
181 raise f_exceptions.XenError("DeviceResize",
182 "Failed to get the mapper dev to "
183 "agree on the current capacity.")
185 try:
186 primarydevice = get_primary_device(SCSIid)
187 if primarydevice:
188 currentcapacity = sg_readcap(primarydevice)
189 refresh_devices_if_needed(primarydevice, SCSIid, currentcapacity)
190 refresh_mapper_if_needed(primarydevice, SCSIid, currentcapacity)
191 else:
192 util.SMlog("scsiutil.refresh_lun_size_by_SCSIid(%s) could not "
193 "find any devices for the SCSIid." % SCSIid)
194 return True
195 except:
196 util.SMlog("Error in scsiutil.refresh_lun_size_by_SCSIid(%s: %s)" % (SCSIid, traceback.format_exc()))
197 return False