Coverage for drivers/DummySR.py : 25%

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# DummySR: an example dummy SR for the SDK
20from sm_typing import Dict, Optional, List, Tuple, override
22import SR
23import VDI
24import SRCommand
25import util
26import time
27import xs_errors
29CAPABILITIES = ["SR_PROBE", "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH",
30 "VDI_ACTIVATE", "VDI_DEACTIVATE", "VDI_CLONE", "VDI_SNAPSHOT", "VDI_RESIZE",
31 "VDI_INTRODUCE", "VDI_MIRROR"]
33CONFIGURATION: List[Tuple[str, str]] = []
35DRIVER_INFO = {
36 'name': 'dummy',
37 'description': 'SR plugin which manages fake data',
38 'vendor': 'Citrix Systems Inc',
39 'copyright': '(C) 2008 Citrix Systems Inc',
40 'driver_version': '1.0',
41 'required_api_version': '1.1',
42 'capabilities': CAPABILITIES,
43 'configuration': CONFIGURATION
44 }
46TYPE = 'dummy'
49class DummySR(SR.SR):
50 """dummy storage repository"""
52 @override
53 @staticmethod
54 def handles(type) -> bool:
55 if type == TYPE:
56 return True
57 return False
59 @override
60 def load(self, sr_uuid) -> None:
61 self.sr_vditype = 'phy'
63 @override
64 def content_type(self, sr_uuid) -> str:
65 return super(DummySR, self).content_type(sr_uuid)
67 @override
68 def create(self, sr_uuid, size) -> None:
69 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref'])
70 assert(len(self.srcmd.params['args']) == 1)
72 @override
73 def delete(self, sr_uuid) -> None:
74 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref'])
75 assert(len(self.srcmd.params['args']) == 0)
77 @override
78 def attach(self, sr_uuid) -> None:
79 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref'])
80 assert(len(self.srcmd.params['args']) == 0)
82 @override
83 def detach(self, sr_uuid) -> None:
84 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref'])
85 assert(len(self.srcmd.params['args']) == 0)
87 @override
88 def probe(self) -> str:
89 # N.B. There are no SR references
90 self._assertValues(['args', 'host_ref', 'session_ref', 'device_config', 'command'])
91 assert(len(self.srcmd.params['args']) == 0)
93 # Create some Dummy SR records
94 entry = {}
95 entry['size'] = 1024
96 SRlist = {}
97 SRlist[util.gen_uuid()] = entry
99 # Return the Probe XML
100 return util.SRtoXML(SRlist)
102 @override
103 def vdi(self, uuid) -> VDI.VDI:
104 return DummyVDI(self, uuid)
106 @override
107 def scan(self, sr_uuid) -> None:
108 self._assertValues(['sr_uuid', 'args', 'host_ref', 'session_ref', 'device_config', 'command', 'sr_ref'])
109 assert(len(self.srcmd.params['args']) == 0)
111 # The list of VDIs comes from the XenAPI - we have no state
112 for v in self._getallVDIrecords():
113 x = DummyVDI(self, v['uuid'])
114 x.size = v['virtual_size']
115 x.utilisation = v['physical_utilisation']
116 self.vdis[x.uuid] = x
118 self.physical_size = 2000000000000
119 self.physical_utilisation = 0
120 self.virtual_allocation = 0
121 super(DummySR, self).scan(sr_uuid)
123 def _assertValues(self, vals):
124 for attr in vals:
125 assert(attr in self.srcmd.params)
126 util.SMlog("%s param %s: [%s]" % (self.cmd, attr, self.srcmd.params[attr]))
128 # Iterate through the device_config dictionary
129 for key in self.dconf.keys():
130 util.SMlog("\tdevice_config: [%s:%s]" % (key, self.dconf[key]))
132 # Query the sm_config; parameters can be set at Create time. Iterate through keys
133 self.sm_config = self.session.xenapi.SR.get_sm_config(self.sr_ref)
134 for key in self.sm_config.keys():
135 util.SMlog("\tsm_config: [%s:%s]" % (key, self.sm_config[key]))
137 def _getallVDIrecords(self):
138 """Helper function which returns a list of all VDI records for this SR
139 stored in the XenAPI server"""
140 # Returns a list of (reference, record) pairs: we only need the records
141 vdis = list(self.session.VDI.get_all_records(self.session_ref)['Value'].values())
142 # We only need the VDIs corresponding to this SR
143 return [v for v in vdis if v['SR'] == self.sr_ref]
146class DummyVDI(VDI.VDI):
147 @override
148 def load(self, vdi_uuid) -> None:
149 self.path = "/dev/null" # returned on attach
150 self.uuid = vdi_uuid
151 self.size = 0
152 self.utilisation = 0
153 self.location = vdi_uuid
154 self.sm_config: Dict[str, str] = {}
156 @override
157 def create(self, sr_uuid, vdi_uuid, size) -> str:
158 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_sm_config'])
159 assert(len(self.sr.srcmd.params['args']) == 8)
161 self.vdi_sm_config = self.sr.srcmd.params['vdi_sm_config']
162 for key in self.vdi_sm_config.keys():
163 util.SMlog("\tvdi_sm_config: [%s:%s]" % (key, self.vdi_sm_config[key]))
165 for v in self.sr._getallVDIrecords():
166 if v['uuid'] == vdi_uuid:
167 raise xs_errors.XenError('VDIExists')
169 self.size = size
170 self.utilisation = size
171 self.sm_config['samplekey'] = "This is a dummy SR VDI"
172 self._db_introduce()
173 self.run_corner_cases_tests()
174 return self.get_params()
176 @override
177 def delete(self, sr_uuid, vdi_uuid, data_only=False) -> None:
178 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid'])
179 assert(len(self.sr.srcmd.params['args']) == 0)
181 # Assert that the VDI record exists
182 self.session.VDI.get_record(self.sr.session_ref)
183 self.run_corner_cases_tests()
184 self._db_forget()
186 @override
187 def introduce(self, sr_uuid, vdi_uuid) -> str:
188 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_sm_config', 'new_uuid'])
189 assert(len(self.sr.srcmd.params['args']) == 0)
190 self.vdi_sm_config = self.sr.srcmd.params['vdi_sm_config']
191 for key in self.vdi_sm_config.keys():
192 util.SMlog("\tvdi_sm_config: [%s:%s]" % (key, self.vdi_sm_config[key]))
194 for v in self.sr._getallVDIrecords():
195 if v['uuid'] == vdi_uuid:
196 raise xs_errors.XenError('VDIExists')
197 self.uuid = vdi_uuid
198 self.location = self.sr.srcmd.params['vdi_location']
199 self._db_introduce()
200 self.run_corner_cases_tests()
201 return super(DummyVDI, self).get_params()
203 @override
204 def attach(self, sr_uuid, vdi_uuid) -> str:
205 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid'])
206 assert(len(self.sr.srcmd.params['args']) == 1)
207 vdi = super(DummyVDI, self).attach(sr_uuid, vdi_uuid)
208 self.run_corner_cases_tests()
209 return vdi
211 @override
212 def detach(self, sr_uuid, vdi_uuid) -> None:
213 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid'])
214 self.run_corner_cases_tests()
215 assert(len(self.sr.srcmd.params['args']) == 0)
217 @override
218 def activate(self, sr_uuid, vdi_uuid) -> Optional[Dict[str, str]]:
219 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid'])
220 assert(len(self.sr.srcmd.params['args']) == 1)
221 self.vdi_ref = self.sr.srcmd.params['vdi_ref']
222 self.other_config = self.session.xenapi.VDI.get_other_config(self.vdi_ref)
223 self.run_corner_cases_tests()
224 for key in self.other_config.keys():
225 util.SMlog("\tvdi_other_config: [%s:%s]" % (key, self.other_config[key]))
226 return None
228 @override
229 def deactivate(self, sr_uuid, vdi_uuid) -> None:
230 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid'])
231 self.run_corner_cases_tests()
232 assert(len(self.sr.srcmd.params['args']) == 0)
234 @override
235 def resize(self, sr_uuid, vdi_uuid, size) -> str:
236 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref', 'vdi_ref', 'vdi_location', 'vdi_uuid'])
237 assert(len(self.sr.srcmd.params['args']) == 1)
239 self.size = size
240 self.utilisation = size
241 self._db_update()
242 self.run_corner_cases_tests()
243 return super(DummyVDI, self).get_params()
245 @override
246 def snapshot(self, sr_uuid, vdi_uuid) -> str:
247 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref'])
248 assert(len(self.sr.srcmd.params['args']) == 0)
250 dest = util.gen_uuid()
251 vdi = VDI.VDI(self.sr, dest)
252 vdi.read_only = True
253 vdi.location = dest
254 vdi.size = 0
255 vdi.utilisation = 0
256 vdi._db_introduce()
257 self.run_corner_cases_tests()
258 return vdi.get_params()
260 @override
261 def clone(self, sr_uuid, vdi_uuid) -> str:
262 self.sr._assertValues(['sr_uuid', 'args', 'host_ref', 'device_config', 'command', 'sr_ref'])
263 assert(len(self.sr.srcmd.params['args']) == 0)
265 dest = util.gen_uuid()
266 vdi = VDI.VDI(self.sr, dest)
267 vdi.read_only = False
268 vdi.location = dest
269 vdi.size = 0
270 vdi.utilisation = 0
271 vdi._db_introduce()
272 self.run_corner_cases_tests()
273 return vdi.get_params()
275 def check_no_other_vdi_operation_in_progress(self):
276 vdis = util.list_VDI_records_in_sr(self.sr)
277 vdi_ref = self.session.xenapi.VDI.get_by_uuid(self.uuid)
278 del vdis[vdi_ref]
279 active_vdis = [v for v in list(vdis.values()) if v['current_operations'] != {}]
280 if len(active_vdis) != 0:
281 msg = "LVHDRT: found other operations in progress for VDI: %s" % active_vdis[0]['uuid']
282 util.SMlog(msg)
283 raise xs_errors.XenError('VDIInUse')
285 def get_attached_vbds(self):
286 vdi_ref = self.session.xenapi.VDI.get_by_uuid(self.uuid)
287 vbds = self.session.xenapi.VBD.get_all_records_where("field \"VDI\" = \"%s\"" % vdi_ref)
288 return [v for v in list(vbds.values()) if v['currently_attached'] == "true"]
290 def check_vbd_list_is_stable(self, attached_vbds):
291 newly_attached_vbds = self.get_attached_vbds()
292 old_set = set(attached_vbds)
293 new_set = set(newly_attached_vbds)
294 diff_set = old_set.difference(new_set) | new_set.difference(old_set)
295 if len(diff_set) != 0:
296 msg = "LVHDRT: found a non-stable VBD: %s" % (diff_set.pop())
297 util.SMlog(msg)
298 raise xs_errors.XenError('VBDListNotStable')
300 def run_corner_cases_tests(self):
302 def fn():
303 attached_vbds = self.get_attached_vbds()
304 for i in range(0, 10):
305 time.sleep(2)
306 self.check_no_other_vdi_operation_in_progress()
307 self.check_vbd_list_is_stable(attached_vbds)
309 util.fistpoint.activate_custom_fn("LVHDRT_xapiSM_serialization_tests", fn)
311if __name__ == '__main__': 311 ↛ 312line 311 didn't jump to line 312, because the condition on line 311 was never true
312 SRCommand.run(DummySR, DRIVER_INFO)
313else:
314 SR.registerSR(DummySR)