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 

22import SR 

23import LVHDSR 

24import SRCommand 

25import lvutil 

26import HBASR 

27import os 

28import re 

29import sys 

30import xs_errors 

31import xmlrpc.client 

32import util 

33import scsiutil 

34import mpath_cli 

35import glob 

36 

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

38 "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH", 

39 "VDI_GENERATE_CONFIG", "VDI_SNAPSHOT", "VDI_CLONE", "VDI_MIRROR", 

40 "VDI_RESIZE", "ATOMIC_PAUSE", "VDI_RESET_ON_BOOT/2", 

41 "VDI_UPDATE", "VDI_CONFIG_CBT", "VDI_ACTIVATE", "VDI_DEACTIVATE"] 

42 

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

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

45 

46DRIVER_INFO = { 

47 'name': 'LVHD over FC', 

48 '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', 

49 'vendor': 'Citrix Systems Inc', 

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

51 'driver_version': '1.0', 

52 'required_api_version': '1.0', 

53 'capabilities': CAPABILITIES, 

54 'configuration': CONFIGURATION 

55 } 

56 

57 

58class LVHDoHBASR(LVHDSR.LVHDSR): 

59 """LVHD over HBA storage repository""" 

60 

61 def handles(type): 

62 if __name__ == '__main__': 

63 name = sys.argv[0] 

64 else: 

65 name = __name__ 

66 if name.endswith("LVMoHBASR"): 

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

68 if type == "lvhdohba": 

69 return True 

70 return False 

71 handles = staticmethod(handles) 

72 

73 def load(self, sr_uuid): 

74 driver = SR.driver('hba') 

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

76 

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

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

79 pbd = None 

80 try: 

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

82 except: 

83 pass 

84 

85 try: 

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

87 # UPGRADE FROM MIAMI: add SCSIid key to device_config 

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

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

90 raise xs_errors.XenError('InvalidDev') 

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

92 self.dconf['SCSIid'] = SCSIid 

93 del self.dconf['device'] 

94 

95 if pbd is not None: 

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

97 device_config['SCSIid'] = SCSIid 

98 device_config['upgraded_from_miami'] = 'true' 

99 del device_config['device'] 

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

101 except: 

102 pass 

103 

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

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

106 raise xs_errors.XenError('ConfigSCSIid') 

107 

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

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

110 

111 def create(self, sr_uuid, size): 

112 self.hbasr.attach(sr_uuid) 

113 if self.mpath == "true": 

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

115 self._pathrefresh(LVHDoHBASR) 

116 try: 

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

118 finally: 

119 if self.mpath == "true": 

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

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

122 self.sr_ref, self.SCSIid) 

123 

124 def attach(self, sr_uuid): 

125 self.hbasr.attach(sr_uuid) 

126 if self.mpath == "true": 

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

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

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

130 for file in os.listdir(path): 

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

132 

133 self._pathrefresh(LVHDoHBASR) 

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

135 # Force a rescan on the bus 

136 self.hbasr._init_hbadict() 

137 # Must re-initialise the multipath node 

138 if self.mpath == "true": 

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

140 LVHDSR.LVHDSR.attach(self, sr_uuid) 

141 self._setMultipathableFlag(SCSIid=self.SCSIid) 

142 

143 def scan(self, sr_uuid): 

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

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

146 # take care of this scenario. 

147 if self.mpath == "true": 

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

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

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

151 self._pathrefresh(LVHDoHBASR) 

152 self._setMultipathableFlag(SCSIid=self.SCSIid) 

153 else: 

154 self._pathrefresh(LVHDoHBASR) 

155 LVHDSR.LVHDSR.scan(self, sr_uuid) 

156 

157 def probe(self): 

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

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

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

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

162 maps = [] 

163 try: 

164 maps = mpath_cli.list_maps() 

165 except: 

166 pass 

167 

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

169 raise xs_errors.XenError('SRInUse') 

170 

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

172 

173 try: 

174 self._pathrefresh(LVHDoHBASR) 

175 result = LVHDSR.LVHDSR.probe(self) 

176 if self.mpath == "true": 

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

178 return result 

179 except: 

180 if self.mpath == "true": 

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

182 raise 

183 

184 def detach(self, sr_uuid): 

185 LVHDSR.LVHDSR.detach(self, sr_uuid) 

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

187 try: 

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

189 except: 

190 pass 

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

192 try: 

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

194 except: 

195 pass 

196 

197 def _remove_device_nodes(self): 

198 """ 

199 Remove the kernel device nodes 

200 """ 

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

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

203 for node in nodes: 

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

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

206 f.write('1\n') 

207 

208 def delete(self, sr_uuid): 

209 self._pathrefresh(LVHDoHBASR) 

210 try: 

211 LVHDSR.LVHDSR.delete(self, sr_uuid) 

212 finally: 

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

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

215 self._remove_device_nodes() 

216 

217 def vdi(self, uuid): 

218 return LVHDoHBAVDI(self, uuid) 

219 

220 

221class LVHDoHBAVDI(LVHDSR.LVHDVDI): 

222 def generate_config(self, sr_uuid, vdi_uuid): 

223 util.SMlog("LVHDoHBAVDI.generate_config") 

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

225 raise xs_errors.XenError('VDIUnavailable') 

226 dict = {} 

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

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

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

230 dict['sr_uuid'] = sr_uuid 

231 dict['vdi_uuid'] = vdi_uuid 

232 dict['command'] = 'vdi_attach_from_config' 

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

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

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

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

237 

238 def attach_from_config(self, sr_uuid, vdi_uuid): 

239 util.SMlog("LVHDoHBAVDI.attach_from_config") 

240 self.sr.hbasr.attach(sr_uuid) 

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

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

243 try: 

244 return self.attach(sr_uuid, vdi_uuid) 

245 except: 

246 util.logException("LVHDoHBAVDI.attach_from_config") 

247 raise xs_errors.XenError('SRUnavailable', \ 

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

249 

250 

251def match_scsidev(s): 

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

253 return regex.search(s, 0) 

254 

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

256 SRCommand.run(LVHDoHBASR, DRIVER_INFO) 

257else: 

258 SR.registerSR(LVHDoHBASR)