Coverage for libs/sm/drivers/udevSR.py: 35%
118 statements
« prev ^ index » next coverage.py v7.3.2, created at 2026-07-10 07:59 +0000
« 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# udevSR: represents VDIs which are hotplugged into dom0 via udev e.g.
17# USB CDROM/disk devices
18# matches with drivers/udevSR
20from sm import SR
21from sm import VDI
22from sm.core import util
23import os
24import time
25import stat
26from sm.core import xs_errors
27from sm import sysdevice
29CAPABILITIES = ["VDI_INTRODUCE", "VDI_ATTACH", "VDI_DETACH", "VDI_UPDATE", "SR_UPDATE"]
31CONFIGURATION = \
32 [['location', 'path to mount (required) (e.g. server:/path)']]
34DRIVER_INFO = {
35 'name': 'udev',
36 'description': 'SR plugin which represents devices plugged in via udev as VDIs',
37 'vendor': 'Citrix Systems Inc',
38 'copyright': '(C) 2008 Citrix Systems Inc',
39 'driver_version': '1.0',
40 'required_api_version': '1.1',
41 'capabilities': CAPABILITIES,
42 'configuration': CONFIGURATION
43 }
45TYPE = 'udev'
48class udevSR(SR.SR):
49 """udev-driven storage repository"""
51 def handles(type):
52 if type == TYPE:
53 return True
54 return False
55 handles = staticmethod(handles)
57 def content_type(self, sr_uuid):
58 return super(udevSR, self).content_type(sr_uuid)
60 def vdi(self, uuid):
61 util.SMlog("params = %s" % (self.srcmd.params.keys()))
63 if 'vdi_location' in self.srcmd.params: 63 ↛ 64line 63 didn't jump to line 64, because the condition on line 63 was never true
64 vdi_location = self.srcmd.params['vdi_location']
65 else:
66 vdi_location = self.get_vdi_location(uuid)
68 return udevVDI(self, vdi_location)
70 def get_vdi_location(self, uuid):
71 vdi = self.session.xenapi.VDI
72 vdi_ref = vdi.get_by_uuid(uuid)
73 return vdi.get_location(vdi_ref)
75 def load(self, sr_uuid):
76 # First of all, check we've got the correct keys in dconf
77 if 'location' not in self.dconf:
78 raise xs_errors.XenError('ConfigLocationMissing')
79 self.sr_vditype = 'phy'
80 # Cache the sm_config
81 self.sm_config = self.session.xenapi.SR.get_sm_config(self.sr_ref)
83 def update(self, sr_uuid):
84 # Return as much information as we have
85 sr_root = self.dconf['location']
87 if util.pathexists(sr_root):
88 for filename in os.listdir(sr_root):
89 path = os.path.join(sr_root, filename)
90 x = udevVDI(self, path)
91 self.vdis[path] = x
93 the_sum = 0
94 for vdi in self.vdis.values():
95 the_sum = the_sum + vdi.size
97 self.physical_size = the_sum
98 self.physical_utilisation = the_sum
99 self.virtual_allocation = the_sum
101 self._db_update()
103 def scan(self, sr_uuid):
104 self.update(sr_uuid)
106 # base class scan does all the work:
107 return super(udevSR, self).scan(sr_uuid)
109 def create(self, sr_uuid, size):
110 pass
112 def delete(self, sr_uuid):
113 pass
115 def attach(self, sr_uuid):
116 pass
118 def detach(self, sr_uuid):
119 pass
122def read_whole_file(filename):
123 f = open(filename, 'r')
124 try:
125 return f.readlines()
126 finally:
127 f.close()
130class udevVDI(VDI.VDI):
131 def __init__(self, sr, location):
132 self.location = location
133 VDI.VDI.__init__(self, sr, None)
135 def load(self, location):
136 self.path = self.location
137 self.size = 0
138 self.utilisation = 0
139 self.label = self.path
140 self.sm_config = {}
141 try:
142 s = os.stat(self.path)
143 self.deleted = False
145 # Use the CTIME of the symlink to mean "time it was hotplugged"
146 iso8601 = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(s[stat.ST_CTIME]))
147 self.sm_config['hotplugged_at'] = iso8601
149 self.path = os.path.realpath(self.path)
151 dev = os.path.basename(self.path)
152 info = sysdevice.stat(dev)
153 if "size" in info.keys():
154 self.size = info["size"]
155 self.utilisation = self.size
157 self.label = "%s %s" % (info["bus"], info["bus_path"])
158 self.description = info["hwinfo"]
160 # XXX: what other information can we recover?
161 if 'type' in self.sr.sm_config:
162 self.read_only = self.sr.sm_config['type'] == "cd"
164 usb_path = info.get("usb_path")
165 if usb_path:
166 self.sm_config["usb_path"] = info["usb_path"]
167 pusbs = self.session.xenapi.PUSB.get_all_records()
168 for pusb in pusbs.values():
169 if usb_path == pusb.get("path"):
170 if pusb.get("passthrough_enabled"):
171 raise xs_errors.XenError('VDIUnavailable')
172 break
174 except OSError as e:
175 self.deleted = True
177 def introduce(self, sr_uuid, vdi_uuid):
178 self.uuid = vdi_uuid
179 self.location = self.sr.srcmd.params['vdi_location']
180 self._db_introduce()
181 # Update the physical_utilisation etc
182 self.sr.update(sr_uuid)
183 return super(udevVDI, self).get_params()
185 def update(self, sr_uuid, vdi_location):
186 self.load(vdi_location)
187 # _db_update requires self.uuid to be set
188 self.uuid = self.sr.srcmd.params['vdi_uuid']
189 self._db_update()
190 # also reset the name-label and description since we're a bit of
191 # a special SR
192 # this would lead to an infinite loop as VDI.set_name_label now
193 # calls VDI.update
194 # temporarily commenting this to pass quicktest
195 #vdi = self.sr.session.xenapi.VDI.get_by_uuid(self.uuid)
196 #self.sr.session.xenapi.VDI.set_name_label(vdi, self.label)
197 #self.sr.session.xenapi.VDI.set_name_description(vdi, self.description)
199 def attach(self, sr_uuid, vdi_uuid):
200 if self.deleted:
201 raise xs_errors.XenError('VDIUnavailable')
203 return super(udevVDI, self).attach(sr_uuid, vdi_uuid)
205 def detach(self, sr_uuid, vdi_uuid):
206 pass
208# SR registration at import
209SR.registerSR(udevSR)