Coverage for drivers/XFSSR.py : 24%
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# Original work copyright (C) Citrix Systems Inc.
4# Modified work copyright (C) Vates SAS and XCP-ng community
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU Lesser General Public License as published
8# by the Free Software Foundation; version 2.1 only.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU Lesser General Public License for more details.
14#
15# You should have received a copy of the GNU Lesser General Public License
16# along with this program; if not, write to the Free Software Foundation, Inc.,
17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18#
19# XFSSR: Based on local-file storage repository, mounts xfs partition
21from sm_typing import override
23import SR
24from SR import deviceCheck
25import SRCommand
26import VDI
27import FileSR
28import util
29import lvutil
30import scsiutil
32import lock
33import os
34import xs_errors
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 XFS VHD and QCOW2',
48 'description': 'SR plugin which represents disks as VHD and QCOW2 files stored on a local XFS filesystem, created inside an LVM volume',
49 'vendor': 'Vates SAS',
50 'copyright': '(C) 2019 Vates SAS',
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 XFSSR(FileSR.FileSR):
61 """XFS Local file storage repository"""
63 DRIVER_TYPE = 'xfs'
65 @override
66 @staticmethod
67 def handles(srtype) -> bool:
68 return srtype == XFSSR.DRIVER_TYPE
70 @override
71 def load(self, sr_uuid) -> None:
72 if not self._is_xfs_available():
73 raise xs_errors.XenError(
74 'SRUnavailable',
75 opterr='xfsprogs is not installed'
76 )
78 self.ops_exclusive = FileSR.OPS_EXCLUSIVE
79 self.lock = lock.Lock(lock.LOCK_TYPE_SR, self.uuid)
80 self.sr_vditype = SR.DEFAULT_TAP
82 self.path = os.path.join(SR.MOUNT_BASE, sr_uuid)
83 self.vgname = EXT_PREFIX + sr_uuid
84 self.remotepath = os.path.join("/dev", self.vgname, sr_uuid)
85 self.attached = self._checkmount()
86 self.driver_config = DRIVER_CONFIG
88 @override
89 def delete(self, sr_uuid) -> None:
90 super(XFSSR, self).delete(sr_uuid)
92 # Check PVs match VG
93 try:
94 for dev in self.dconf['device'].split(','):
95 cmd = ["pvs", dev]
96 txt = util.pread2(cmd)
97 if txt.find(self.vgname) == -1:
98 raise xs_errors.XenError('VolNotFound', \
99 opterr='volume is %s' % self.vgname)
100 except util.CommandException as inst:
101 raise xs_errors.XenError('PVSfailed', \
102 opterr='error is %d' % inst.code)
104 # Remove LV, VG and pv
105 try:
106 cmd = ["lvremove", "-f", self.remotepath]
107 util.pread2(cmd)
109 cmd = ["vgremove", self.vgname]
110 util.pread2(cmd)
112 for dev in self.dconf['device'].split(','):
113 cmd = ["pvremove", dev]
114 util.pread2(cmd)
115 except util.CommandException as inst:
116 raise xs_errors.XenError('LVMDelete', \
117 opterr='errno is %d' % inst.code)
119 @override
120 def attach(self, sr_uuid) -> None:
121 if not self._checkmount():
122 try:
123 #Activate LV
124 cmd = ['lvchange', '-ay', self.remotepath]
125 util.pread2(cmd)
127 # make a mountpoint:
128 if not os.path.isdir(self.path):
129 os.makedirs(self.path)
130 except util.CommandException as inst:
131 raise xs_errors.XenError('LVMMount', \
132 opterr='Unable to activate LV. Errno is %d' % inst.code)
134 try:
135 util.pread(["fsck", "-a", self.remotepath])
136 except util.CommandException as inst:
137 if inst.code == 1:
138 util.SMlog("FSCK detected and corrected FS errors. Not fatal.")
139 else:
140 raise xs_errors.XenError('LVMMount', \
141 opterr='FSCK failed on %s. Errno is %d' % (self.remotepath, inst.code))
143 try:
144 util.pread(["mount", self.remotepath, self.path])
145 except util.CommandException as inst:
146 raise xs_errors.XenError('LVMMount', \
147 opterr='Failed to mount FS. Errno is %d' % inst.code)
149 self.attached = True
151 #Update SCSIid string
152 scsiutil.add_serial_record(self.session, self.sr_ref, \
153 scsiutil.devlist_to_serialstring(self.dconf['device'].split(',')))
155 # Set the block scheduler
156 for dev in self.dconf['device'].split(','):
157 self.block_setscheduler(dev)
159 @override
160 def detach(self, sr_uuid) -> None:
161 super(XFSSR, self).detach(sr_uuid)
162 try:
163 # deactivate SR
164 cmd = ["lvchange", "-an", self.remotepath]
165 util.pread2(cmd)
166 except util.CommandException as inst:
167 raise xs_errors.XenError('LVMUnMount', \
168 opterr='lvm -an failed errno is %d' % inst.code)
170 @override
171 @deviceCheck
172 def probe(self) -> str:
173 return lvutil.srlist_toxml(lvutil.scan_srlist(EXT_PREFIX, self.dconf['device']),
174 EXT_PREFIX)
176 @override
177 @deviceCheck
178 def create(self, sr_uuid, size) -> None:
179 if self._checkmount():
180 raise xs_errors.XenError('SRExists')
182 # Check none of the devices already in use by other PBDs
183 if util.test_hostPBD_devs(self.session, sr_uuid, self.dconf['device']):
184 raise xs_errors.XenError('SRInUse')
186 # Check serial number entry in SR records
187 for dev in self.dconf['device'].split(','):
188 if util.test_scsiserial(self.session, dev):
189 raise xs_errors.XenError('SRInUse')
191 if not lvutil._checkVG(self.vgname):
192 lvutil.createVG(self.dconf['device'], self.vgname)
194 if lvutil._checkLV(self.remotepath):
195 raise xs_errors.XenError('SRExists')
197 try:
198 numdevs = len(self.dconf['device'].split(','))
199 cmd = ["lvcreate", "-n", sr_uuid]
200 if numdevs > 1:
201 lowest = -1
202 for dev in self.dconf['device'].split(','):
203 stats = lvutil._getPVstats(dev)
204 if lowest < 0 or stats['freespace'] < lowest:
205 lowest = stats['freespace']
206 size_mb = (lowest // (1024 * 1024)) * numdevs
208 # Add stripe parameter to command
209 cmd += ["-i", str(numdevs), "-I", "2048"]
210 else:
211 stats = lvutil._getVGstats(self.vgname)
212 size_mb = stats['freespace'] // (1024 * 1024)
213 assert(size_mb > 0)
214 cmd += ["-L", str(size_mb), self.vgname]
215 text = util.pread(cmd)
217 cmd = ["lvchange", "-ay", self.remotepath]
218 text = util.pread(cmd)
219 except util.CommandException as inst:
220 raise xs_errors.XenError('LVMCreate', \
221 opterr='lv operation, error %d' % inst.code)
222 except AssertionError:
223 raise xs_errors.XenError('SRNoSpace', \
224 opterr='Insufficient space in VG %s' % self.vgname)
226 try:
227 util.pread2(["mkfs.xfs", self.remotepath])
228 except util.CommandException as inst:
229 raise xs_errors.XenError('LVMFilesystem', \
230 opterr='mkfs failed error %d' % inst.code)
232 #Update serial number string
233 scsiutil.add_serial_record(self.session, self.sr_ref, \
234 scsiutil.devlist_to_serialstring(self.dconf['device'].split(',')))
236 @override
237 def vdi(self, uuid) -> VDI.VDI:
238 return XFSFileVDI(self, uuid)
240 @staticmethod
241 def _is_xfs_available():
242 return util.find_executable('mkfs.xfs')
245class XFSFileVDI(FileSR.FileVDI):
246 @override
247 def attach(self, sr_uuid, vdi_uuid) -> str:
248 if not hasattr(self, 'xenstore_data'):
249 self.xenstore_data = {}
251 self.xenstore_data['storage-type'] = XFSSR.DRIVER_TYPE
253 return super(XFSFileVDI, self).attach(sr_uuid, vdi_uuid)
256if __name__ == '__main__': 256 ↛ 257line 256 didn't jump to line 257, because the condition on line 256 was never true
257 SRCommand.run(XFSSR, DRIVER_INFO)
258else:
259 SR.registerSR(XFSSR)