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