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 os
33import xs_errors
34import vhdutil
35from lock import Lock
36from constants import EXT_PREFIX
38CAPABILITIES = ["SR_PROBE", "SR_UPDATE", "SR_SUPPORTS_LOCAL_CACHING", \
39 "VDI_CREATE", "VDI_DELETE", "VDI_ATTACH", "VDI_DETACH", \
40 "VDI_UPDATE", "VDI_CLONE", "VDI_SNAPSHOT", "VDI_RESIZE", "VDI_MIRROR", \
41 "VDI_GENERATE_CONFIG", \
42 "VDI_RESET_ON_BOOT/2", "ATOMIC_PAUSE", "VDI_CONFIG_CBT",
43 "VDI_ACTIVATE", "VDI_DEACTIVATE", "THIN_PROVISIONING", "VDI_READ_CACHING"]
45CONFIGURATION = [['device', 'local device path (required) (e.g. /dev/sda3)']]
47DRIVER_INFO = {
48 'name': 'Local XFS VHD',
49 'description': 'SR plugin which represents disks as VHD files stored on a local XFS filesystem, created inside an LVM volume',
50 'vendor': 'Vates SAS',
51 'copyright': '(C) 2019 Vates SAS',
52 'driver_version': '1.0',
53 'required_api_version': '1.0',
54 'capabilities': CAPABILITIES,
55 'configuration': CONFIGURATION
56 }
58DRIVER_CONFIG = {"ATTACH_FROM_CONFIG_WITH_TAPDISK": True}
61class XFSSR(FileSR.FileSR):
62 """XFS Local file storage repository"""
64 DRIVER_TYPE = 'xfs'
66 @override
67 @staticmethod
68 def handles(srtype) -> bool:
69 return srtype == XFSSR.DRIVER_TYPE
71 @override
72 def load(self, sr_uuid) -> None:
73 if not self._is_xfs_available():
74 raise xs_errors.XenError(
75 'SRUnavailable',
76 opterr='xfsprogs is not installed'
77 )
79 self.ops_exclusive = FileSR.OPS_EXCLUSIVE
80 self.lock = Lock(vhdutil.LOCK_TYPE_SR, self.uuid)
81 self.sr_vditype = SR.DEFAULT_TAP
83 self.path = os.path.join(SR.MOUNT_BASE, sr_uuid)
84 self.vgname = EXT_PREFIX + sr_uuid
85 self.remotepath = os.path.join("/dev", self.vgname, sr_uuid)
86 self.attached = self._checkmount()
87 self.driver_config = DRIVER_CONFIG
89 @override
90 def delete(self, sr_uuid) -> None:
91 super(XFSSR, self).delete(sr_uuid)
93 # Check PVs match VG
94 try:
95 for dev in self.dconf['device'].split(','):
96 cmd = ["pvs", dev]
97 txt = util.pread2(cmd)
98 if txt.find(self.vgname) == -1:
99 raise xs_errors.XenError('VolNotFound', \
100 opterr='volume is %s' % self.vgname)
101 except util.CommandException as inst:
102 raise xs_errors.XenError('PVSfailed', \
103 opterr='error is %d' % inst.code)
105 # Remove LV, VG and pv
106 try:
107 cmd = ["lvremove", "-f", self.remotepath]
108 util.pread2(cmd)
110 cmd = ["vgremove", self.vgname]
111 util.pread2(cmd)
113 for dev in self.dconf['device'].split(','):
114 cmd = ["pvremove", dev]
115 util.pread2(cmd)
116 except util.CommandException as inst:
117 raise xs_errors.XenError('LVMDelete', \
118 opterr='errno is %d' % inst.code)
120 @override
121 def attach(self, sr_uuid) -> None:
122 if not self._checkmount():
123 try:
124 #Activate LV
125 cmd = ['lvchange', '-ay', self.remotepath]
126 util.pread2(cmd)
128 # make a mountpoint:
129 if not os.path.isdir(self.path):
130 os.makedirs(self.path)
131 except util.CommandException as inst:
132 raise xs_errors.XenError('LVMMount', \
133 opterr='Unable to activate LV. Errno is %d' % inst.code)
135 try:
136 util.pread(["fsck", "-a", self.remotepath])
137 except util.CommandException as inst:
138 if inst.code == 1:
139 util.SMlog("FSCK detected and corrected FS errors. Not fatal.")
140 else:
141 raise xs_errors.XenError('LVMMount', \
142 opterr='FSCK failed on %s. Errno is %d' % (self.remotepath, inst.code))
144 try:
145 util.pread(["mount", self.remotepath, self.path])
146 except util.CommandException as inst:
147 raise xs_errors.XenError('LVMMount', \
148 opterr='Failed to mount FS. Errno is %d' % inst.code)
150 self.attached = True
152 #Update SCSIid string
153 scsiutil.add_serial_record(self.session, self.sr_ref, \
154 scsiutil.devlist_to_serialstring(self.dconf['device'].split(',')))
156 # Set the block scheduler
157 for dev in self.dconf['device'].split(','):
158 self.block_setscheduler(dev)
160 @override
161 def detach(self, sr_uuid) -> None:
162 super(XFSSR, self).detach(sr_uuid)
163 try:
164 # deactivate SR
165 cmd = ["lvchange", "-an", self.remotepath]
166 util.pread2(cmd)
167 except util.CommandException as inst:
168 raise xs_errors.XenError('LVMUnMount', \
169 opterr='lvm -an failed errno is %d' % inst.code)
171 @override
172 @deviceCheck
173 def probe(self) -> str:
174 return lvutil.srlist_toxml(lvutil.scan_srlist(EXT_PREFIX, self.dconf['device']),
175 EXT_PREFIX)
177 @override
178 @deviceCheck
179 def create(self, sr_uuid, size) -> None:
180 if self._checkmount():
181 raise xs_errors.XenError('SRExists')
183 # Check none of the devices already in use by other PBDs
184 if util.test_hostPBD_devs(self.session, sr_uuid, self.dconf['device']):
185 raise xs_errors.XenError('SRInUse')
187 # Check serial number entry in SR records
188 for dev in self.dconf['device'].split(','):
189 if util.test_scsiserial(self.session, dev):
190 raise xs_errors.XenError('SRInUse')
192 if not lvutil._checkVG(self.vgname):
193 lvutil.createVG(self.dconf['device'], self.vgname)
195 if lvutil._checkLV(self.remotepath):
196 raise xs_errors.XenError('SRExists')
198 try:
199 numdevs = len(self.dconf['device'].split(','))
200 cmd = ["lvcreate", "-n", sr_uuid]
201 if numdevs > 1:
202 lowest = -1
203 for dev in self.dconf['device'].split(','):
204 stats = lvutil._getPVstats(dev)
205 if lowest < 0 or stats['freespace'] < lowest:
206 lowest = stats['freespace']
207 size_mb = (lowest // (1024 * 1024)) * numdevs
209 # Add stripe parameter to command
210 cmd += ["-i", str(numdevs), "-I", "2048"]
211 else:
212 stats = lvutil._getVGstats(self.vgname)
213 size_mb = stats['freespace'] // (1024 * 1024)
214 assert(size_mb > 0)
215 cmd += ["-L", str(size_mb), self.vgname]
216 text = util.pread(cmd)
218 cmd = ["lvchange", "-ay", self.remotepath]
219 text = util.pread(cmd)
220 except util.CommandException as inst:
221 raise xs_errors.XenError('LVMCreate', \
222 opterr='lv operation, error %d' % inst.code)
223 except AssertionError:
224 raise xs_errors.XenError('SRNoSpace', \
225 opterr='Insufficient space in VG %s' % self.vgname)
227 try:
228 util.pread2(["mkfs.xfs", self.remotepath])
229 except util.CommandException as inst:
230 raise xs_errors.XenError('LVMFilesystem', \
231 opterr='mkfs failed error %d' % inst.code)
233 #Update serial number string
234 scsiutil.add_serial_record(self.session, self.sr_ref, \
235 scsiutil.devlist_to_serialstring(self.dconf['device'].split(',')))
237 @override
238 def vdi(self, uuid, loadLocked = False) -> VDI.VDI:
239 return XFSFileVDI(self, uuid)
241 @staticmethod
242 def _is_xfs_available():
243 return util.find_executable('mkfs.xfs')
246class XFSFileVDI(FileSR.FileVDI):
247 @override
248 def attach(self, sr_uuid, vdi_uuid) -> str:
249 if not hasattr(self, 'xenstore_data'):
250 self.xenstore_data = {}
252 self.xenstore_data['storage-type'] = XFSSR.DRIVER_TYPE
254 return super(XFSFileVDI, self).attach(sr_uuid, vdi_uuid)
257if __name__ == '__main__': 257 ↛ 258line 257 didn't jump to line 258, because the condition on line 257 was never true
258 SRCommand.run(XFSSR, DRIVER_INFO)
259else:
260 SR.registerSR(XFSSR)