Hide keyboard shortcuts

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# udevSR: represents VDIs which are hotplugged into dom0 via udev e.g. 

19# USB CDROM/disk devices 

20 

21from sm_typing import override 

22 

23import SR 

24import VDI 

25import SRCommand 

26import util 

27import os 

28import time 

29import stat 

30import xs_errors 

31import sysdevice 

32 

33CAPABILITIES = ["VDI_INTRODUCE", "VDI_ATTACH", "VDI_DETACH", "VDI_UPDATE", "SR_UPDATE"] 

34 

35CONFIGURATION = \ 

36 [['location', 'path to mount (required) (e.g. server:/path)']] 

37 

38DRIVER_INFO = { 

39 'name': 'udev', 

40 'description': 'SR plugin which represents devices plugged in via udev as VDIs', 

41 'vendor': 'Citrix Systems Inc', 

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

43 'driver_version': '1.0', 

44 'required_api_version': '1.1', 

45 'capabilities': CAPABILITIES, 

46 'configuration': CONFIGURATION 

47 } 

48 

49TYPE = 'udev' 

50 

51 

52class udevSR(SR.SR): 

53 """udev-driven storage repository""" 

54 

55 @override 

56 @staticmethod 

57 def handles(type) -> bool: 

58 if type == TYPE: 

59 return True 

60 return False 

61 

62 @override 

63 def content_type(self, sr_uuid) -> str: 

64 return super(udevSR, self).content_type(sr_uuid) 

65 

66 @override 

67 def vdi(self, uuid) -> VDI.VDI: 

68 util.SMlog("params = %s" % (self.srcmd.params.keys())) 

69 

70 if 'vdi_location' in self.srcmd.params: 70 ↛ 71line 70 didn't jump to line 71, because the condition on line 70 was never true

71 vdi_location = self.srcmd.params['vdi_location'] 

72 else: 

73 vdi_location = self.get_vdi_location(uuid) 

74 

75 return udevVDI(self, vdi_location) 

76 

77 def get_vdi_location(self, uuid): 

78 vdi = self.session.xenapi.VDI 

79 vdi_ref = vdi.get_by_uuid(uuid) 

80 return vdi.get_location(vdi_ref) 

81 

82 @override 

83 def load(self, sr_uuid) -> None: 

84 # First of all, check we've got the correct keys in dconf 

85 if 'location' not in self.dconf: 

86 raise xs_errors.XenError('ConfigLocationMissing') 

87 self.sr_vditype = 'phy' 

88 # Cache the sm_config 

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

90 

91 @override 

92 def update(self, sr_uuid) -> None: 

93 # Return as much information as we have 

94 sr_root = self.dconf['location'] 

95 

96 if util.pathexists(sr_root): 

97 for filename in os.listdir(sr_root): 

98 path = os.path.join(sr_root, filename) 

99 x = udevVDI(self, path) 

100 self.vdis[path] = x 

101 

102 the_sum = 0 

103 for vdi in self.vdis.values(): 

104 the_sum = the_sum + vdi.size 

105 

106 self.physical_size = the_sum 

107 self.physical_utilisation = the_sum 

108 self.virtual_allocation = the_sum 

109 

110 self._db_update() 

111 

112 @override 

113 def scan(self, sr_uuid) -> None: 

114 self.update(sr_uuid) 

115 

116 # base class scan does all the work: 

117 super(udevSR, self).scan(sr_uuid) 

118 

119 @override 

120 def create(self, sr_uuid, size) -> None: 

121 pass 

122 

123 @override 

124 def delete(self, sr_uuid) -> None: 

125 pass 

126 

127 @override 

128 def attach(self, sr_uuid) -> None: 

129 pass 

130 

131 @override 

132 def detach(self, sr_uuid) -> None: 

133 pass 

134 

135 

136def read_whole_file(filename): 

137 f = open(filename, 'r') 

138 try: 

139 return f.readlines() 

140 finally: 

141 f.close() 

142 

143 

144class udevVDI(VDI.VDI): 

145 def __init__(self, sr, location): 

146 self.location = location 

147 VDI.VDI.__init__(self, sr, None) 

148 

149 @override 

150 def load(self, location) -> None: 

151 self.path = self.location 

152 self.size = 0 

153 self.utilisation = 0 

154 self.label = self.path 

155 self.sm_config = {} 

156 self.vdi_type = "raw" # We give raw but there is a special case in blktap2.py:VDI.tap_wanted() for udevSR 

157 self.image_format = "raw" 

158 self.sm_config["image-format"] = self.image_format 

159 

160 try: 

161 s = os.stat(self.path) 

162 self.deleted = False 

163 

164 # Use the CTIME of the symlink to mean "time it was hotplugged" 

165 iso8601 = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(s[stat.ST_CTIME])) 

166 self.sm_config['hotplugged_at'] = iso8601 

167 

168 self.path = os.path.realpath(self.path) 

169 

170 dev = os.path.basename(self.path) 

171 info = sysdevice.stat(dev) 

172 if "size" in info.keys(): 

173 self.size = info["size"] 

174 self.utilisation = self.size 

175 

176 self.label = "%s %s" % (info["bus"], info["bus_path"]) 

177 self.description = info["hwinfo"] 

178 

179 # XXX: what other information can we recover? 

180 if 'type' in self.sr.sm_config: 

181 self.read_only = self.sr.sm_config['type'] == "cd" 

182 

183 usb_path = info.get("usb_path") 

184 if usb_path: 

185 self.sm_config["usb_path"] = info["usb_path"] 

186 pusbs = self.session.xenapi.PUSB.get_all_records() 

187 for pusb in pusbs.values(): 

188 if usb_path == pusb.get("path"): 

189 if pusb.get("passthrough_enabled"): 

190 raise xs_errors.XenError('VDIUnavailable') 

191 break 

192 

193 except OSError as e: 

194 self.deleted = True 

195 

196 @override 

197 def introduce(self, sr_uuid, vdi_uuid) -> str: 

198 self.uuid = vdi_uuid 

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

200 self._db_introduce() 

201 # Update the physical_utilisation etc 

202 self.sr.update(sr_uuid) 

203 return super(udevVDI, self).get_params() 

204 

205 @override 

206 def update(self, sr_uuid, vdi_location) -> None: 

207 self.load(vdi_location) 

208 # _db_update requires self.uuid to be set 

209 self.uuid = self.sr.srcmd.params['vdi_uuid'] 

210 self._db_update() 

211 # also reset the name-label and description since we're a bit of 

212 # a special SR 

213 # this would lead to an infinite loop as VDI.set_name_label now 

214 # calls VDI.update 

215 # temporarily commenting this to pass quicktest 

216 #vdi = self.sr.session.xenapi.VDI.get_by_uuid(self.uuid) 

217 #self.sr.session.xenapi.VDI.set_name_label(vdi, self.label) 

218 #self.sr.session.xenapi.VDI.set_name_description(vdi, self.description) 

219 

220 @override 

221 def attach(self, sr_uuid, vdi_uuid) -> str: 

222 if self.deleted: 

223 raise xs_errors.XenError('VDIUnavailable') 

224 

225 return super(udevVDI, self).attach(sr_uuid, vdi_uuid) 

226 

227 @override 

228 def detach(self, sr_uuid, vdi_uuid) -> None: 

229 pass 

230 

231if __name__ == '__main__': 231 ↛ 232line 231 didn't jump to line 232, because the condition on line 231 was never true

232 SRCommand.run(udevSR, DRIVER_INFO) 

233else: 

234 SR.registerSR(udevSR)