Hide keyboard shortcuts

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#!/usr/bin/python3 

2# 

3# Copyright (C) Citrix Systems Inc. 

4# 

5# This program is free software; you can redistribute it and/or modify 

6# it under the terms of the GNU Lesser General Public License as published 

7# by the Free Software Foundation; version 2.1 only. 

8# 

9# This program is distributed in the hope that it will be useful, 

10# but WITHOUT ANY WARRANTY; without even the implied warranty of 

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

12# GNU Lesser General Public License for more details. 

13# 

14# You should have received a copy of the GNU Lesser General Public License 

15# along with this program; if not, write to the Free Software Foundation, Inc., 

16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 

17# 

18# LVHDoISCSISR: LVHD over Hardware HBA LUN driver, e.g. Fibre Channel or 

19# hardware based iSCSI 

20# 

21 

22from sm_typing import override 

23 

24import SR 

25import LVHDSR 

26import SRCommand 

27import VDI 

28import lvutil 

29import HBASR 

30import os 

31import re 

32import sys 

33import xs_errors 

34import xmlrpc.client 

35import util 

36import scsiutil 

37import mpath_cli 

38import glob 

39 

40CAPABILITIES = ["SR_PROBE", "SR_UPDATE", "SR_METADATA", "SR_TRIM", 

41 "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH", 

42 "VDI_GENERATE_CONFIG", "VDI_SNAPSHOT", "VDI_CLONE", "VDI_MIRROR", 

43 "VDI_RESIZE", "ATOMIC_PAUSE", "VDI_RESET_ON_BOOT/2", 

44 "VDI_UPDATE", "VDI_CONFIG_CBT", "VDI_ACTIVATE", "VDI_DEACTIVATE"] 

45 

46CONFIGURATION = [['SCSIid', 'The scsi_id of the destination LUN'], \ 

47 ['allocation', 'Valid values are thick or thin (optional, defaults to thick)']] 

48 

49DRIVER_INFO = { 

50 'name': 'LVHD over FC', 

51 'description': 'SR plugin which represents disks as VHDs on Logical Volumes within a Volume Group created on an HBA LUN, e.g. hardware-based iSCSI or FC support', 

52 'vendor': 'Citrix Systems Inc', 

53 'copyright': '(C) 2008 Citrix Systems Inc', 

54 'driver_version': '1.0', 

55 'required_api_version': '1.0', 

56 'capabilities': CAPABILITIES, 

57 'configuration': CONFIGURATION 

58 } 

59 

60 

61class LVHDoHBASR(LVHDSR.LVHDSR): 

62 """LVHD over HBA storage repository""" 

63 

64 @override 

65 @staticmethod 

66 def handles(type) -> bool: 

67 if __name__ == '__main__': 

68 name = sys.argv[0] 

69 else: 

70 name = __name__ 

71 if name.endswith("LVMoHBASR"): 

72 return type == "lvmohba" # for the initial switch from LVM 

73 if type == "lvhdohba": 

74 return True 

75 return False 

76 

77 @override 

78 def load(self, sr_uuid) -> None: 

79 driver = SR.driver('hba') 

80 self.hbasr = driver(self.original_srcmd, sr_uuid) 

81 

82 # If this is a vdi command, don't initialise SR 

83 if not (util.isVDICommand(self.original_srcmd.cmd)): 83 ↛ 84line 83 didn't jump to line 84, because the condition on line 83 was never true

84 pbd = None 

85 try: 

86 pbd = util.find_my_pbd(self.session, self.host_ref, self.sr_ref) 

87 except: 

88 pass 

89 

90 try: 

91 if 'SCSIid' not in self.dconf and 'device' in self.dconf: 

92 # UPGRADE FROM MIAMI: add SCSIid key to device_config 

93 util.SMlog("Performing upgrade from Miami") 

94 if not os.path.exists(self.dconf['device']): 

95 raise xs_errors.XenError('InvalidDev') 

96 SCSIid = scsiutil.getSCSIid(self.dconf['device']) 

97 self.dconf['SCSIid'] = SCSIid 

98 del self.dconf['device'] 

99 

100 if pbd is not None: 

101 device_config = self.session.xenapi.PBD.get_device_config(pbd) 

102 device_config['SCSIid'] = SCSIid 

103 device_config['upgraded_from_miami'] = 'true' 

104 del device_config['device'] 

105 self.session.xenapi.PBD.set_device_config(pbd, device_config) 

106 except: 

107 pass 

108 

109 if 'SCSIid' not in self.dconf or not self.dconf['SCSIid']: 

110 print(self.hbasr.print_devs(), file=sys.stderr) 

111 raise xs_errors.XenError('ConfigSCSIid') 

112 

113 self.SCSIid = self.dconf['SCSIid'] 

114 super(LVHDoHBASR, self).load(sr_uuid) 

115 

116 @override 

117 def create(self, sr_uuid, size) -> None: 

118 self.hbasr.attach(sr_uuid) 

119 if self.mpath == "true": 

120 self.mpathmodule.refresh(self.SCSIid, 0) 

121 self._pathrefresh(LVHDoHBASR) 

122 try: 

123 LVHDSR.LVHDSR.create(self, sr_uuid, size) 

124 finally: 

125 if self.mpath == "true": 

126 self.mpathmodule.reset(self.SCSIid, explicit_unmap=True) 

127 util.remove_mpathcount_field(self.session, self.host_ref, \ 

128 self.sr_ref, self.SCSIid) 

129 

130 @override 

131 def attach(self, sr_uuid) -> None: 

132 self.hbasr.attach(sr_uuid) 

133 if self.mpath == "true": 

134 self.mpathmodule.refresh(self.SCSIid, 0) 

135 # set the device mapper's I/O scheduler 

136 path = '/dev/disk/by-scsid/%s' % self.dconf['SCSIid'] 

137 for file in os.listdir(path): 

138 self.block_setscheduler('%s/%s' % (path, file)) 

139 

140 self._pathrefresh(LVHDoHBASR) 

141 if not os.path.exists(self.dconf['device']): 

142 # Force a rescan on the bus 

143 self.hbasr._init_hbadict() 

144 # Must re-initialise the multipath node 

145 if self.mpath == "true": 

146 self.mpathmodule.refresh(self.SCSIid, 0) 

147 LVHDSR.LVHDSR.attach(self, sr_uuid) 

148 self._setMultipathableFlag(SCSIid=self.SCSIid) 

149 

150 @override 

151 def scan(self, sr_uuid) -> None: 

152 # During a reboot, scan is called ahead of attach, which causes the MGT 

153 # to point of the wrong device instead of dm-x. Running multipathing will 

154 # take care of this scenario. 

155 if self.mpath == "true": 

156 if 'device' not in self.dconf or not os.path.exists(self.dconf['device']): 

157 util.SMlog("@@@@@ path does not exists") 

158 self.mpathmodule.refresh(self.SCSIid, 0) 

159 self._pathrefresh(LVHDoHBASR) 

160 self._setMultipathableFlag(SCSIid=self.SCSIid) 

161 else: 

162 self._pathrefresh(LVHDoHBASR) 

163 LVHDSR.LVHDSR.scan(self, sr_uuid) 

164 

165 @override 

166 def probe(self) -> str: 

167 if self.mpath == "true" and 'SCSIid' in self.dconf: 

168 # When multipathing is enabled, since we don't refcount the multipath maps, 

169 # we should not attempt to do the iscsi.attach/detach when the map is already present, 

170 # as this will remove it (which may well be in use). 

171 maps = [] 

172 try: 

173 maps = mpath_cli.list_maps() 

174 except: 

175 pass 

176 

177 if self.dconf['SCSIid'] in maps: 

178 raise xs_errors.XenError('SRInUse') 

179 

180 self.mpathmodule.refresh(self.SCSIid, 0) 

181 

182 try: 

183 self._pathrefresh(LVHDoHBASR) 

184 result = LVHDSR.LVHDSR.probe(self) 

185 if self.mpath == "true": 

186 self.mpathmodule.reset(self.SCSIid, explicit_unmap=True) 

187 return result 

188 except: 

189 if self.mpath == "true": 

190 self.mpathmodule.reset(self.SCSIid, explicit_unmap=True) 

191 raise 

192 

193 @override 

194 def detach(self, sr_uuid) -> None: 

195 LVHDSR.LVHDSR.detach(self, sr_uuid) 

196 self.mpathmodule.reset(self.SCSIid, explicit_unmap=True) 

197 try: 

198 pbdref = util.find_my_pbd(self.session, self.host_ref, self.sr_ref) 

199 except: 

200 pass 

201 for key in ["mpath-" + self.SCSIid, "multipathed"]: 

202 try: 

203 self.session.xenapi.PBD.remove_from_other_config(pbdref, key) 

204 except: 

205 pass 

206 

207 def _remove_device_nodes(self): 

208 """ 

209 Remove the kernel device nodes 

210 """ 

211 nodes = glob.glob('/dev/disk/by-scsid/%s/*' % self.SCSIid) 

212 util.SMlog('Remove_nodes, nodes are %s' % nodes) 

213 for node in nodes: 

214 with open('/sys/block/%s/device/delete' % 

215 (os.path.basename(node)), 'w') as f: 

216 f.write('1\n') 

217 

218 @override 

219 def delete(self, sr_uuid) -> None: 

220 self._pathrefresh(LVHDoHBASR) 

221 try: 

222 LVHDSR.LVHDSR.delete(self, sr_uuid) 

223 finally: 

224 if self.mpath == "true": 224 ↛ 225line 224 didn't jump to line 225, because the condition on line 224 was never true

225 self.mpathmodule.reset(self.SCSIid, explicit_unmap=True) 

226 self._remove_device_nodes() 

227 

228 @override 

229 def vdi(self, uuid) -> VDI.VDI: 

230 return LVHDoHBAVDI(self, uuid) 

231 

232 

233class LVHDoHBAVDI(LVHDSR.LVHDVDI): 

234 @override 

235 def generate_config(self, sr_uuid, vdi_uuid) -> str: 

236 util.SMlog("LVHDoHBAVDI.generate_config") 

237 if not lvutil._checkLV(self.path): 

238 raise xs_errors.XenError('VDIUnavailable') 

239 dict = {} 

240 self.sr.dconf['multipathing'] = self.sr.mpath 

241 self.sr.dconf['multipathhandle'] = self.sr.mpathhandle 

242 dict['device_config'] = self.sr.dconf 

243 dict['sr_uuid'] = sr_uuid 

244 dict['vdi_uuid'] = vdi_uuid 

245 dict['command'] = 'vdi_attach_from_config' 

246 # Return the 'config' encoded within a normal XMLRPC response so that 

247 # we can use the regular response/error parsing code. 

248 config = xmlrpc.client.dumps(tuple([dict]), "vdi_attach_from_config") 

249 return xmlrpc.client.dumps((config, ), "", True) 

250 

251 @override 

252 def attach_from_config(self, sr_uuid, vdi_uuid) -> str: 

253 util.SMlog("LVHDoHBAVDI.attach_from_config") 

254 self.sr.hbasr.attach(sr_uuid) 

255 if self.sr.mpath == "true": 

256 self.sr.mpathmodule.refresh(self.sr.SCSIid, 0) 

257 try: 

258 return self.attach(sr_uuid, vdi_uuid) 

259 except: 

260 util.logException("LVHDoHBAVDI.attach_from_config") 

261 raise xs_errors.XenError('SRUnavailable', \ 

262 opterr='Unable to attach the heartbeat disk') 

263 

264 

265def match_scsidev(s): 

266 regex = re.compile("^/dev/disk/by-id|^/dev/mapper") 

267 return regex.search(s, 0) 

268 

269if __name__ == '__main__': 269 ↛ 270line 269 didn't jump to line 270, because the condition on line 269 was never true

270 SRCommand.run(LVHDoHBASR, DRIVER_INFO) 

271else: 

272 SR.registerSR(LVHDoHBASR)