Coverage for libs/sm/drivers/DummySR.py: 18%

193 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2026-07-10 07:59 +0000

1# Copyright (C) Citrix Systems Inc. 

2# 

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

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

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

6# 

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

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

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

10# GNU Lesser General Public License for more details. 

11# 

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

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

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

15# 

16# DummySR: an example dummy SR for the SDK 

17# matches with drivers/DummySR 

18 

19import time 

20 

21from sm import SR 

22from sm import VDI 

23from sm.core import util 

24from sm.core import xs_errors 

25 

26CAPABILITIES = ["SR_PROBE", "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH", 

27 "VDI_ACTIVATE", "VDI_DEACTIVATE", "VDI_CLONE", "VDI_SNAPSHOT", "VDI_RESIZE", 

28 "VDI_INTRODUCE", "VDI_MIRROR"] 

29 

30CONFIGURATION = [] 

31 

32DRIVER_INFO = { 

33 'name': 'dummy', 

34 'description': 'SR plugin which manages fake data', 

35 'vendor': 'Citrix Systems Inc', 

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

37 'driver_version': '1.0', 

38 'required_api_version': '1.1', 

39 'capabilities': CAPABILITIES, 

40 'configuration': CONFIGURATION 

41 } 

42 

43TYPE = 'dummy' 

44 

45 

46class DummySR(SR.SR): 

47 """dummy storage repository""" 

48 

49 def handles(type): 

50 if type == TYPE: 

51 return True 

52 return False 

53 handles = staticmethod(handles) 

54 

55 def load(self, sr_uuid): 

56 self.sr_vditype = 'phy' 

57 

58 def content_type(self, sr_uuid): 

59 return super(DummySR, self).content_type(sr_uuid) 

60 

61 def create(self, sr_uuid, size): 

62 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref']) 

63 assert(len(self.srcmd.params['args']) == 1) 

64 

65 def delete(self, sr_uuid): 

66 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref']) 

67 assert(len(self.srcmd.params['args']) == 0) 

68 

69 def attach(self, sr_uuid): 

70 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref']) 

71 assert(len(self.srcmd.params['args']) == 0) 

72 

73 def detach(self, sr_uuid): 

74 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref']) 

75 assert(len(self.srcmd.params['args']) == 0) 

76 

77 def probe(self): 

78 # N.B. There are no SR references 

79 self._assertValues(['args', 'host_ref', 'session_ref', 'device_config', 'command']) 

80 assert(len(self.srcmd.params['args']) == 0) 

81 

82 # Create some Dummy SR records 

83 entry = {} 

84 entry['size'] = 1024 

85 SRlist = {} 

86 SRlist[util.gen_uuid()] = entry 

87 

88 # Return the Probe XML 

89 return util.SRtoXML(SRlist) 

90 

91 def vdi(self, uuid): 

92 return DummyVDI(self, uuid) 

93 

94 def scan(self, sr_uuid): 

95 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref']) 

96 assert(len(self.srcmd.params['args']) == 0) 

97 

98 # The list of VDIs comes from the XenAPI - we have no state 

99 for v in self._getallVDIrecords(): 

100 x = DummyVDI(self, v['uuid']) 

101 x.size = v['virtual_size'] 

102 x.utilisation = v['physical_utilisation'] 

103 self.vdis[x.uuid] = x 

104 

105 self.physical_size = 2000000000000 

106 self.physical_utilisation = 0 

107 self.virtual_allocation = 0 

108 return super(DummySR, self).scan(sr_uuid) 

109 

110 def _assertValues(self, vals): 

111 for attr in vals: 

112 assert(attr in self.srcmd.params) 

113 util.SMlog("%s param %s: [%s]" % (self.cmd, attr, self.srcmd.params[attr])) 

114 

115 # Iterate through the device_config dictionary 

116 for key in self.dconf.keys(): 

117 util.SMlog("\tdevice_config: [%s:%s]" % (key, self.dconf[key])) 

118 

119 # Query the sm_config; parameters can be set at Create time. Iterate through keys 

120 self.sm_config = self.session.xenapi.SR.get_sm_config(self.sr_ref) 

121 for key in self.sm_config.keys(): 

122 util.SMlog("\tsm_config: [%s:%s]" % (key, self.sm_config[key])) 

123 

124 def _getallVDIrecords(self): 

125 """Helper function which returns a list of all VDI records for this SR 

126 stored in the XenAPI server""" 

127 # Returns a list of (reference, record) pairs: we only need the records 

128 vdis = list(self.session.VDI.get_all_records(self.session_ref)['Value'].values()) 

129 # We only need the VDIs corresponding to this SR 

130 return [v for v in vdis if v['SR'] == self.sr_ref] 

131 

132 

133class DummyVDI(VDI.VDI): 

134 def load(self, vdi_uuid): 

135 self.path = "/dev/null" # returned on attach 

136 self.uuid = vdi_uuid 

137 self.size = 0 

138 self.utilisation = 0 

139 self.location = vdi_uuid 

140 self.sm_config = {} 

141 

142 def create(self, sr_uuid, vdi_uuid, size): 

143 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_sm_config']) 

144 assert(len(self.sr.srcmd.params['args']) == 8) 

145 

146 self.vdi_sm_config = self.sr.srcmd.params['vdi_sm_config'] 

147 for key in self.vdi_sm_config.keys(): 

148 util.SMlog("\tvdi_sm_config: [%s:%s]" % (key, self.vdi_sm_config[key])) 

149 

150 for v in self.sr._getallVDIrecords(): 

151 if v['uuid'] == vdi_uuid: 

152 raise xs_errors.XenError('VDIExists') 

153 

154 self.size = size 

155 self.utilisation = size 

156 self.sm_config['samplekey'] = "This is a dummy SR VDI" 

157 self._db_introduce() 

158 self.run_corner_cases_tests() 

159 return self.get_params() 

160 

161 def delete(self, sr_uuid, vdi_uuid): 

162 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid']) 

163 assert(len(self.sr.srcmd.params['args']) == 0) 

164 

165 # Assert that the VDI record exists 

166 self.session.VDI.get_record(self.sr.session_ref) 

167 self.run_corner_cases_tests() 

168 self._db_forget() 

169 

170 def introduce(self, sr_uuid, vdi_uuid): 

171 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_sm_config', 'new_uuid']) 

172 assert(len(self.sr.srcmd.params['args']) == 0) 

173 self.vdi_sm_config = self.sr.srcmd.params['vdi_sm_config'] 

174 for key in self.vdi_sm_config.keys(): 

175 util.SMlog("\tvdi_sm_config: [%s:%s]" % (key, self.vdi_sm_config[key])) 

176 

177 for v in self.sr._getallVDIrecords(): 

178 if v['uuid'] == vdi_uuid: 

179 raise xs_errors.XenError('VDIExists') 

180 self.uuid = vdi_uuid 

181 self.location = self.sr.srcmd.params['vdi_location'] 

182 self._db_introduce() 

183 self.run_corner_cases_tests() 

184 return super(DummyVDI, self).get_params() 

185 

186 def attach(self, sr_uuid, vdi_uuid): 

187 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid']) 

188 assert(len(self.sr.srcmd.params['args']) == 1) 

189 vdi = super(DummyVDI, self).attach(sr_uuid, vdi_uuid) 

190 self.run_corner_cases_tests() 

191 return vdi 

192 

193 def detach(self, sr_uuid, vdi_uuid): 

194 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid']) 

195 self.run_corner_cases_tests() 

196 assert(len(self.sr.srcmd.params['args']) == 0) 

197 

198 def activate(self, sr_uuid, vdi_uuid): 

199 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid']) 

200 assert(len(self.sr.srcmd.params['args']) == 1) 

201 self.vdi_ref = self.sr.srcmd.params['vdi_ref'] 

202 self.other_config = self.session.xenapi.VDI.get_other_config(self.vdi_ref) 

203 self.run_corner_cases_tests() 

204 for key in self.other_config.keys(): 

205 util.SMlog("\tvdi_other_config: [%s:%s]" % (key, self.other_config[key])) 

206 

207 def deactivate(self, sr_uuid, vdi_uuid): 

208 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid']) 

209 self.run_corner_cases_tests() 

210 assert(len(self.sr.srcmd.params['args']) == 0) 

211 

212 def resize(self, sr_uuid, vdi_uuid, size): 

213 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid']) 

214 assert(len(self.sr.srcmd.params['args']) == 1) 

215 

216 self.size = size 

217 self.utilisation = size 

218 self._db_update() 

219 self.run_corner_cases_tests() 

220 return super(DummyVDI, self).get_params() 

221 

222 def snapshot(self, sr_uuid, vdi_uuid): 

223 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref']) 

224 assert(len(self.sr.srcmd.params['args']) == 0) 

225 

226 dest = util.gen_uuid() 

227 vdi = VDI.VDI(self.sr, dest) 

228 vdi.read_only = True 

229 vdi.location = dest 

230 vdi.size = 0 

231 vdi.utilisation = 0 

232 vdi._db_introduce() 

233 self.run_corner_cases_tests() 

234 return vdi.get_params() 

235 

236 def clone(self, sr_uuid, vdi_uuid): 

237 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref']) 

238 assert(len(self.sr.srcmd.params['args']) == 0) 

239 

240 dest = util.gen_uuid() 

241 vdi = VDI.VDI(self.sr, dest) 

242 vdi.read_only = False 

243 vdi.location = dest 

244 vdi.size = 0 

245 vdi.utilisation = 0 

246 vdi._db_introduce() 

247 self.run_corner_cases_tests() 

248 return vdi.get_params() 

249 

250 def check_no_other_vdi_operation_in_progress(self): 

251 vdis = util.list_VDI_records_in_sr(self.sr) 

252 vdi_ref = self.session.xenapi.VDI.get_by_uuid(self.uuid) 

253 del vdis[vdi_ref] 

254 active_vdis = [v for v in list(vdis.values()) if v['current_operations'] != {}] 

255 if len(active_vdis) != 0: 

256 msg = "LVHDRT: found other operations in progress for VDI: %s" % active_vdis[0]['uuid'] 

257 util.SMlog(msg) 

258 raise xs_errors.XenError('VDIInUse') 

259 

260 def get_attached_vbds(self): 

261 vdi_ref = self.session.xenapi.VDI.get_by_uuid(self.uuid) 

262 vbds = self.session.xenapi.VBD.get_all_records_where("field \"VDI\" = \"%s\"" % vdi_ref) 

263 return [v for v in list(vbds.values()) if v['currently_attached'] == "true"] 

264 

265 def check_vbd_list_is_stable(self, attached_vbds): 

266 newly_attached_vbds = self.get_attached_vbds() 

267 old_set = set(attached_vbds) 

268 new_set = set(newly_attached_vbds) 

269 diff_set = old_set.difference(new_set) | new_set.difference(old_set) 

270 if len(diff_set) != 0: 

271 msg = "LVHDRT: found a non-stable VBD: %s" % (diff_set.pop()) 

272 util.SMlog(msg) 

273 raise xs_errors.XenError('VBDListNotStable') 

274 

275 def run_corner_cases_tests(self): 

276 

277 def fn(): 

278 attached_vbds = self.get_attached_vbds() 

279 for i in range(0, 10): 

280 time.sleep(2) 

281 self.check_no_other_vdi_operation_in_progress() 

282 self.check_vbd_list_is_stable(attached_vbds) 

283 

284 util.fistpoint.activate_custom_fn("LVHDRT_xapiSM_serialization_tests", fn) 

285 

286# SR registration at import 

287SR.registerSR(DummySR)