Coverage for drivers/LVHDoHBASR.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#!/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#
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
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"]
43CONFIGURATION = [['SCSIid', 'The scsi_id of the destination LUN'], \
44 ['allocation', 'Valid values are thick or thin (optional, defaults to thick)']]
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 }
58class LVHDoHBASR(LVHDSR.LVHDSR):
59 """LVHD over HBA storage repository"""
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)
73 def load(self, sr_uuid):
74 driver = SR.driver('hba')
75 self.hbasr = driver(self.original_srcmd, sr_uuid)
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
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']
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
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')
108 self.SCSIid = self.dconf['SCSIid']
109 super(LVHDoHBASR, self).load(sr_uuid)
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)
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))
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)
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)
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
168 if self.dconf['SCSIid'] in maps:
169 raise xs_errors.XenError('SRInUse')
171 self.mpathmodule.refresh(self.SCSIid, 0)
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
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
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')
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()
217 def vdi(self, uuid):
218 return LVHDoHBAVDI(self, uuid)
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)
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')
251def match_scsidev(s):
252 regex = re.compile("^/dev/disk/by-id|^/dev/mapper")
253 return regex.search(s, 0)
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)