Coverage for drivers/LVHDoHBASR.py : 35%

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#
22from sm_typing import override
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
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"]
46CONFIGURATION = [['SCSIid', 'The scsi_id of the destination LUN'], \
47 ['allocation', 'Valid values are thick or thin (optional, defaults to thick)']]
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 }
61class LVHDoHBASR(LVHDSR.LVHDSR):
62 """LVHD over HBA storage repository"""
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
77 @override
78 def load(self, sr_uuid) -> None:
79 driver = SR.driver('hba')
80 self.hbasr = driver(self.original_srcmd, sr_uuid)
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
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']
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
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')
113 self.SCSIid = self.dconf['SCSIid']
114 super(LVHDoHBASR, self).load(sr_uuid)
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)
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))
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)
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)
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
177 if self.dconf['SCSIid'] in maps:
178 raise xs_errors.XenError('SRInUse')
180 self.mpathmodule.refresh(self.SCSIid, 0)
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
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
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')
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()
228 @override
229 def vdi(self, uuid) -> VDI.VDI:
230 return LVHDoHBAVDI(self, uuid)
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)
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')
265def match_scsidev(s):
266 regex = re.compile("^/dev/disk/by-id|^/dev/mapper")
267 return regex.search(s, 0)
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)