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# EXTSR: Based on local-file storage repository, mounts ext3 partition 

19 

20import SR 

21from SR import deviceCheck 

22import SRCommand 

23import FileSR 

24import util 

25import lvutil 

26import scsiutil 

27 

28import os 

29import xs_errors 

30import vhdutil 

31from lock import Lock 

32from constants import EXT_PREFIX 

33 

34CAPABILITIES = ["SR_PROBE", "SR_UPDATE", "SR_SUPPORTS_LOCAL_CACHING", \ 

35 "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH", \ 

36 "VDI_UPDATE", "VDI_CLONE", "VDI_SNAPSHOT", "VDI_RESIZE", "VDI_MIRROR", \ 

37 "VDI_GENERATE_CONFIG", \ 

38 "VDI_RESET_ON_BOOT/2", "ATOMIC_PAUSE", "VDI_CONFIG_CBT", 

39 "VDI_ACTIVATE", "VDI_DEACTIVATE", "THIN_PROVISIONING", "VDI_READ_CACHING"] 

40 

41CONFIGURATION = [['device', 'local device path (required) (e.g. /dev/sda3)']] 

42 

43DRIVER_INFO = { 

44 'name': 'Local EXT3 VHD', 

45 'description': 'SR plugin which represents disks as VHD files stored on a local EXT3 filesystem, created inside an LVM volume', 

46 'vendor': 'Citrix Systems Inc', 

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

48 'driver_version': '1.0', 

49 'required_api_version': '1.0', 

50 'capabilities': CAPABILITIES, 

51 'configuration': CONFIGURATION 

52 } 

53 

54DRIVER_CONFIG = {"ATTACH_FROM_CONFIG_WITH_TAPDISK": True} 

55 

56 

57class EXTSR(FileSR.FileSR): 

58 """EXT3 Local file storage repository""" 

59 

60 def handles(srtype): 

61 return srtype == 'ext' 

62 handles = staticmethod(handles) 

63 

64 def load(self, sr_uuid): 

65 self.ops_exclusive = FileSR.OPS_EXCLUSIVE 

66 self.lock = Lock(vhdutil.LOCK_TYPE_SR, self.uuid) 

67 self.sr_vditype = SR.DEFAULT_TAP 

68 

69 self.path = os.path.join(SR.MOUNT_BASE, sr_uuid) 

70 self.vgname = EXT_PREFIX + sr_uuid 

71 self.remotepath = os.path.join("/dev", self.vgname, sr_uuid) 

72 self.attached = self._checkmount() 

73 self.driver_config = DRIVER_CONFIG 

74 

75 def delete(self, sr_uuid): 

76 super(EXTSR, self).delete(sr_uuid) 

77 

78 # Check PVs match VG 

79 try: 

80 for dev in self.dconf['device'].split(','): 

81 cmd = ["pvs", dev] 

82 txt = util.pread2(cmd) 

83 if txt.find(self.vgname) == -1: 

84 raise xs_errors.XenError('VolNotFound', \ 

85 opterr='volume is %s' % self.vgname) 

86 except util.CommandException as inst: 

87 raise xs_errors.XenError('PVSfailed', \ 

88 opterr='error is %d' % inst.code) 

89 

90 # Remove LV, VG and pv 

91 try: 

92 cmd = ["lvremove", "-f", self.remotepath] 

93 util.pread2(cmd) 

94 

95 cmd = ["vgremove", self.vgname] 

96 util.pread2(cmd) 

97 

98 for dev in self.dconf['device'].split(','): 

99 cmd = ["pvremove", dev] 

100 util.pread2(cmd) 

101 except util.CommandException as inst: 

102 raise xs_errors.XenError('LVMDelete', \ 

103 opterr='errno is %d' % inst.code) 

104 

105 def attach(self, sr_uuid): 

106 if not self._checkmount(): 

107 try: 

108 #Activate LV 

109 cmd = ['lvchange', '-ay', self.remotepath] 

110 util.pread2(cmd) 

111 

112 # make a mountpoint: 

113 if not os.path.isdir(self.path): 

114 os.makedirs(self.path) 

115 except util.CommandException as inst: 

116 raise xs_errors.XenError('LVMMount', \ 

117 opterr='Unable to activate LV. Errno is %d' % inst.code) 

118 

119 try: 

120 util.pread(["fsck", "-a", self.remotepath]) 

121 except util.CommandException as inst: 

122 if inst.code == 1: 

123 util.SMlog("FSCK detected and corrected FS errors. Not fatal.") 

124 else: 

125 raise xs_errors.XenError('LVMMount', \ 

126 opterr='FSCK failed on %s. Errno is %d' % (self.remotepath, inst.code)) 

127 

128 try: 

129 util.pread(["mount", self.remotepath, self.path]) 

130 except util.CommandException as inst: 

131 raise xs_errors.XenError('LVMMount', \ 

132 opterr='Failed to mount FS. Errno is %d' % inst.code) 

133 

134 self.attached = True 

135 

136 #Update SCSIid string 

137 scsiutil.add_serial_record(self.session, self.sr_ref, \ 

138 scsiutil.devlist_to_serialstring(self.dconf['device'].split(','))) 

139 

140 # Set the block scheduler 

141 for dev in self.dconf['device'].split(','): 

142 self.block_setscheduler(dev) 

143 

144 def detach(self, sr_uuid): 

145 super(EXTSR, self).detach(sr_uuid) 

146 try: 

147 # deactivate SR 

148 cmd = ["lvchange", "-an", self.remotepath] 

149 util.pread2(cmd) 

150 except util.CommandException as inst: 

151 raise xs_errors.XenError('LVMUnMount', \ 

152 opterr='lvm -an failed errno is %d' % inst.code) 

153 

154 @deviceCheck 

155 def probe(self): 

156 return lvutil.srlist_toxml(lvutil.scan_srlist(EXT_PREFIX, self.dconf['device']), 

157 EXT_PREFIX) 

158 

159 @deviceCheck 

160 def create(self, sr_uuid, size): 

161 if self._checkmount(): 

162 raise xs_errors.XenError('SRExists') 

163 

164 # Check none of the devices already in use by other PBDs 

165 if util.test_hostPBD_devs(self.session, sr_uuid, self.dconf['device']): 

166 raise xs_errors.XenError('SRInUse') 

167 

168 # Check serial number entry in SR records 

169 for dev in self.dconf['device'].split(','): 

170 if util.test_scsiserial(self.session, dev): 

171 raise xs_errors.XenError('SRInUse') 

172 

173 if not lvutil._checkVG(self.vgname): 

174 lvutil.createVG(self.dconf['device'], self.vgname) 

175 

176 if lvutil._checkLV(self.remotepath): 

177 raise xs_errors.XenError('SRExists') 

178 

179 try: 

180 numdevs = len(self.dconf['device'].split(',')) 

181 cmd = ["lvcreate", "-n", sr_uuid] 

182 if numdevs > 1: 

183 lowest = -1 

184 for dev in self.dconf['device'].split(','): 

185 stats = lvutil._getPVstats(dev) 

186 if lowest < 0 or stats['freespace'] < lowest: 

187 lowest = stats['freespace'] 

188 size_mb = (lowest // (1024 * 1024)) * numdevs 

189 

190 # Add stripe parameter to command 

191 cmd += ["-i", str(numdevs), "-I", "2048"] 

192 else: 

193 stats = lvutil._getVGstats(self.vgname) 

194 size_mb = stats['freespace'] // (1024 * 1024) 

195 assert(size_mb > 0) 

196 cmd += ["-L", str(size_mb), self.vgname] 

197 text = util.pread(cmd) 

198 

199 cmd = ["lvchange", "-ay", self.remotepath] 

200 text = util.pread(cmd) 

201 except util.CommandException as inst: 

202 raise xs_errors.XenError('LVMCreate', \ 

203 opterr='lv operation, error %d' % inst.code) 

204 except AssertionError: 

205 raise xs_errors.XenError('SRNoSpace', \ 

206 opterr='Insufficient space in VG %s' % self.vgname) 

207 

208 try: 

209 util.pread2(["mkfs.ext4", "-F", self.remotepath]) 

210 except util.CommandException as inst: 

211 raise xs_errors.XenError('LVMFilesystem', \ 

212 opterr='mkfs failed error %d' % inst.code) 

213 

214 #Update serial number string 

215 scsiutil.add_serial_record(self.session, self.sr_ref, \ 

216 scsiutil.devlist_to_serialstring(self.dconf['device'].split(','))) 

217 

218 def vdi(self, uuid, loadLocked=False): 

219 if not loadLocked: 

220 return EXTFileVDI(self, uuid) 

221 return EXTFileVDI(self, uuid) 

222 

223 

224class EXTFileVDI(FileSR.FileVDI): 

225 def attach(self, sr_uuid, vdi_uuid): 

226 if not hasattr(self, 'xenstore_data'): 

227 self.xenstore_data = {} 

228 

229 self.xenstore_data["storage-type"] = "ext" 

230 

231 return super(EXTFileVDI, self).attach(sr_uuid, vdi_uuid) 

232 

233 

234if __name__ == '__main__': 

235 SRCommand.run(EXTSR, DRIVER_INFO) 

236else: 

237 SR.registerSR(EXTSR)