Coverage for drivers/EXTSR.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# EXTSR: Based on local-file storage repository, mounts ext3 partition
20from sm_typing import override
22import SR
23from SR import deviceCheck
24import VDI
25import SRCommand
26import FileSR
27import util
28import lvutil
29import scsiutil
31import os
32import xs_errors
33import vhdutil
34from lock import Lock
35from constants import EXT_PREFIX
37CAPABILITIES = ["SR_PROBE", "SR_UPDATE", "SR_SUPPORTS_LOCAL_CACHING",
38 "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH",
39 "VDI_UPDATE", "VDI_CLONE", "VDI_SNAPSHOT", "VDI_RESIZE", "VDI_MIRROR",
40 "VDI_GENERATE_CONFIG",
41 "VDI_RESET_ON_BOOT/2", "ATOMIC_PAUSE", "VDI_CONFIG_CBT",
42 "VDI_ACTIVATE", "VDI_DEACTIVATE", "THIN_PROVISIONING", "VDI_READ_CACHING"]
44CONFIGURATION = [['device', 'local device path (required) (e.g. /dev/sda3)']]
46DRIVER_INFO = {
47 'name': 'Local EXT3 VHD',
48 'description': 'SR plugin which represents disks as VHD files stored on a local EXT3 filesystem, created inside an LVM volume',
49 'vendor': 'Citrix Systems Inc',
50 'copyright': '(C) 2008 Citrix Systems Inc',
51 'driver_version': '1.0',
52 'required_api_version': '1.0',
53 'capabilities': CAPABILITIES,
54 'configuration': CONFIGURATION
55 }
57DRIVER_CONFIG = {"ATTACH_FROM_CONFIG_WITH_TAPDISK": True}
60class EXTSR(FileSR.FileSR):
61 """EXT3 Local file storage repository"""
63 @override
64 @staticmethod
65 def handles(srtype) -> bool:
66 return srtype == 'ext'
68 @override
69 def load(self, sr_uuid) -> None:
70 self.ops_exclusive = FileSR.OPS_EXCLUSIVE
71 self.lock = Lock(vhdutil.LOCK_TYPE_SR, self.uuid)
72 self.sr_vditype = SR.DEFAULT_TAP
74 self.path = os.path.join(SR.MOUNT_BASE, sr_uuid)
75 self.vgname = EXT_PREFIX + sr_uuid
76 self.remotepath = os.path.join("/dev", self.vgname, sr_uuid)
77 self.attached = self._checkmount()
78 self.driver_config = DRIVER_CONFIG
80 @override
81 def delete(self, sr_uuid) -> None:
82 super(EXTSR, self).delete(sr_uuid)
84 # Check PVs match VG
85 try:
86 for dev in self.dconf['device'].split(','):
87 cmd = ["pvs", dev]
88 txt = util.pread2(cmd)
89 if txt.find(self.vgname) == -1:
90 raise xs_errors.XenError('VolNotFound',
91 opterr='volume is %s' % self.vgname)
92 except util.CommandException as inst:
93 raise xs_errors.XenError('PVSfailed',
94 opterr='error is %d' % inst.code)
96 # Remove LV, VG and pv
97 try:
98 cmd = ["lvremove", "-f", self.remotepath]
99 util.pread2(cmd)
101 cmd = ["vgremove", self.vgname]
102 util.pread2(cmd)
104 for dev in self.dconf['device'].split(','):
105 cmd = ["pvremove", dev]
106 util.pread2(cmd)
107 except util.CommandException as inst:
108 raise xs_errors.XenError('LVMDelete',
109 opterr='errno is %d' % inst.code)
111 @override
112 def attach(self, sr_uuid) -> None:
113 if not self._checkmount():
114 try:
115 #Activate LV
116 cmd = ['lvchange', '-ay', self.remotepath]
117 util.pread2(cmd)
118 except util.CommandException as inst:
119 raise xs_errors.XenError(
120 'LVMMount',
121 opterr='Unable to activate LV. Errno is %d' % inst.code)
123 try:
124 util.pread(["fsck", "-a", self.remotepath])
125 except util.CommandException as inst:
126 if inst.code == 1:
127 util.SMlog("FSCK detected and corrected FS errors. Not fatal.")
128 else:
129 raise xs_errors.XenError(
130 'LVMMount',
131 opterr='FSCK failed on %s. Errno is %d' % (self.remotepath, inst.code))
133 self.attach_and_bind(sr_uuid, bind=False)
135 self.attached = True
137 #Update SCSIid string
138 scsiutil.add_serial_record(
139 self.session, self.sr_ref,
140 scsiutil.devlist_to_serialstring(self.dconf['device'].split(',')))
142 # Set the block scheduler
143 for dev in self.dconf['device'].split(','):
144 self.block_setscheduler(dev)
146 @override
147 def detach(self, sr_uuid) -> None:
148 super(EXTSR, self).detach(sr_uuid)
149 try:
150 # deactivate SR
151 cmd = ["lvchange", "-an", self.remotepath]
152 util.pread2(cmd)
153 except util.CommandException as inst:
154 raise xs_errors.XenError(
155 'LVMUnMount',
156 opterr='lvm -an failed errno is %d' % inst.code)
158 @override
159 @deviceCheck
160 def probe(self) -> str:
161 return lvutil.srlist_toxml(lvutil.scan_srlist(EXT_PREFIX, self.dconf['device']),
162 EXT_PREFIX)
164 @override
165 @deviceCheck
166 def create(self, sr_uuid, size) -> None:
167 if self._checkmount():
168 raise xs_errors.XenError('SRExists')
170 # Check none of the devices already in use by other PBDs
171 if util.test_hostPBD_devs(self.session, sr_uuid, self.dconf['device']):
172 raise xs_errors.XenError('SRInUse')
174 # Check serial number entry in SR records
175 for dev in self.dconf['device'].split(','):
176 if util.test_scsiserial(self.session, dev):
177 raise xs_errors.XenError('SRInUse')
179 if not lvutil._checkVG(self.vgname):
180 lvutil.createVG(self.dconf['device'], self.vgname)
182 if lvutil._checkLV(self.remotepath):
183 raise xs_errors.XenError('SRExists')
185 try:
186 numdevs = len(self.dconf['device'].split(','))
187 cmd = ["lvcreate", "-n", sr_uuid]
188 if numdevs > 1:
189 lowest = -1
190 for dev in self.dconf['device'].split(','):
191 stats = lvutil._getPVstats(dev)
192 if lowest < 0 or stats['freespace'] < lowest:
193 lowest = stats['freespace']
194 size_mb = (lowest // (1024 * 1024)) * numdevs
196 # Add stripe parameter to command
197 cmd += ["-i", str(numdevs), "-I", "2048"]
198 else:
199 stats = lvutil._getVGstats(self.vgname)
200 size_mb = stats['freespace'] // (1024 * 1024)
201 assert(size_mb > 0)
202 cmd += ["-L", str(size_mb), self.vgname]
203 text = util.pread(cmd)
205 cmd = ["lvchange", "-ay", self.remotepath]
206 text = util.pread(cmd)
207 except util.CommandException as inst:
208 raise xs_errors.XenError(
209 'LVMCreate',
210 opterr='lv operation, error %d' % inst.code)
211 except AssertionError:
212 raise xs_errors.XenError(
213 'SRNoSpace',
214 opterr='Insufficient space in VG %s' % self.vgname)
216 try:
217 util.pread2(["mkfs.ext4", "-F", self.remotepath])
218 except util.CommandException as inst:
219 raise xs_errors.XenError('LVMFilesystem',
220 opterr='mkfs failed error %d' % inst.code)
222 #Update serial number string
223 scsiutil.add_serial_record(
224 self.session, self.sr_ref,
225 scsiutil.devlist_to_serialstring(self.dconf['device'].split(',')))
227 @override
228 def vdi(self, uuid) -> VDI.VDI:
229 return EXTFileVDI(self, uuid)
232class EXTFileVDI(FileSR.FileVDI):
233 @override
234 def attach(self, sr_uuid, vdi_uuid) -> str:
235 if not hasattr(self, 'xenstore_data'):
236 self.xenstore_data = {}
238 self.xenstore_data["storage-type"] = "ext"
240 return super(EXTFileVDI, self).attach(sr_uuid, vdi_uuid)
243if __name__ == '__main__': 243 ↛ 244line 243 didn't jump to line 244, because the condition on line 243 was never true
244 SRCommand.run(EXTSR, DRIVER_INFO)
245else:
246 SR.registerSR(EXTSR)