Difference between revisions of "Creating a LVM backed XFS SR"
Outbackdingo (talk | contribs) |
Outbackdingo (talk | contribs) |
||
Line 35: | Line 35: | ||
Enjoy |
Enjoy |
||
− | ---------------SNIP XFSSR.py------------------ |
||
− | #!/usr/bin/env python |
||
− | # Copyright (C) 2006-2007 XenSource Ltd. |
||
− | # Copyright (C) 2008-2009 Citrix Ltd. |
||
− | # |
||
− | # This program is free software; you can redistribute it and/or modify |
||
− | # it under the terms of the GNU Lesser General Public License as published |
||
− | # by the Free Software Foundation; version 2.1 only. |
||
− | # |
||
− | # This program is distributed in the hope that it will be useful, |
||
− | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
− | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
− | # GNU Lesser General Public License for more details. |
||
− | # |
||
− | # Modified for XFS by Scott V. Kamp (outbackdingo@gmail.com) |
||
− | # |
||
− | # XFSSR: Based on local-file storage repository, mounts xfs partition |
||
− | # EXTSR: Based on local-file storage repository, mounts ext partition |
||
− | |||
− | import SR, SRCommand, FileSR, util, lvutil, scsiutil |
||
− | |||
− | import os |
||
− | import tempfile |
||
− | import errno |
||
− | import xs_errors |
||
− | import vhdutil |
||
− | from lock import Lock |
||
− | import cleanup |
||
− | |||
− | CAPABILITIES = ["SR_PROBE","SR_UPDATE", "SR_SUPPORTS_LOCAL_CACHING", \ |
||
− | "VDI_CREATE","VDI_DELETE","VDI_ATTACH","VDI_DETACH", \ |
||
− | "VDI_UPDATE","VDI_CLONE","VDI_SNAPSHOT","VDI_RESIZE", \ |
||
− | "VDI_RESET_ON_BOOT","ATOMIC_PAUSE"] |
||
− | |||
− | CONFIGURATION = [ [ 'device', 'local device path (required) (e.g. /dev/sda3)' ] ] |
||
− | |||
− | DRIVER_INFO = { |
||
− | 'name': 'Local EXT3 VHD', |
||
− | 'description': 'SR plugin which represents disks as VHD files stored on a local EXT3 filesystem, created inside an LVM volume', |
||
− | 'vendor': 'Citrix Systems Inc', |
||
− | 'copyright': '(C) 2008 Citrix Systems Inc', |
||
− | 'driver_version': '1.0', |
||
− | 'required_api_version': '1.0', |
||
− | 'capabilities': CAPABILITIES, |
||
− | 'configuration': CONFIGURATION |
||
− | } |
||
− | |||
− | EXT_PREFIX = 'XSLocalEXT-' |
||
− | |||
− | class EXTSR(FileSR.FileSR): |
||
− | """EXT3 Local file storage repository""" |
||
− | def handles(srtype): |
||
− | return srtype == 'xfs' |
||
− | handles = staticmethod(handles) |
||
− | |||
− | def load(self, sr_uuid): |
||
− | self.ops_exclusive = FileSR.OPS_EXCLUSIVE |
||
− | self.lock = Lock(vhdutil.LOCK_TYPE_SR, self.uuid) |
||
− | self.sr_vditype = SR.DEFAULT_TAP |
||
− | if not self.dconf.has_key('device') or not self.dconf['device']: |
||
− | raise xs_errors.XenError('ConfigDeviceMissing') |
||
− | |||
− | self.root = self.dconf['device'] |
||
− | for dev in self.root.split(','): |
||
− | if not self._isvalidpathstring(dev): |
||
− | raise xs_errors.XenError('ConfigDeviceInvalid', \ |
||
− | opterr='path is %s' % dev) |
||
− | self.path = os.path.join(SR.MOUNT_BASE, sr_uuid) |
||
− | self.vgname = EXT_PREFIX + sr_uuid |
||
− | self.remotepath = os.path.join("/dev",self.vgname,sr_uuid) |
||
− | self.attached = self._checkmount() |
||
− | |||
− | def delete(self, sr_uuid): |
||
− | self.attach(sr_uuid) |
||
− | super(EXTSR, self).delete(sr_uuid) |
||
− | self.detach(sr_uuid) |
||
− | |||
− | # Check PVs match VG |
||
− | try: |
||
− | for dev in self.root.split(','): |
||
− | cmd = ["pvs", dev] |
||
− | txt = util.pread2(cmd) |
||
− | if txt.find(self.vgname) == -1: |
||
− | raise xs_errors.XenError('VolNotFound', \ |
||
− | opterr='volume is %s' % self.vgname) |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('PVSfailed', \ |
||
− | opterr='error is %d' % inst.code) |
||
− | |||
− | # Remove LV, VG and pv |
||
− | try: |
||
− | cmd = ["lvremove", "-f", self.remotepath] |
||
− | util.pread2(cmd) |
||
− | |||
− | cmd = ["vgremove", self.vgname] |
||
− | util.pread2(cmd) |
||
− | |||
− | for dev in self.root.split(','): |
||
− | cmd = ["pvremove", dev] |
||
− | util.pread2(cmd) |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('LVMDelete', \ |
||
− | opterr='errno is %d' % inst.code) |
||
− | |||
− | def attach(self, sr_uuid): |
||
− | if not self._checkmount(): |
||
− | try: |
||
− | #Activate LV |
||
− | cmd = ['lvchange','-ay',self.remotepath] |
||
− | util.pread2(cmd) |
||
− | |||
− | # make a mountpoint: |
||
− | if not os.path.isdir(self.path): |
||
− | os.makedirs(self.path) |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('LVMMount', \ |
||
− | opterr='Unable to activate LV. Errno is %d' % inst.code) |
||
− | |||
− | try: |
||
− | util.pread(["fsck", "-a", self.remotepath]) |
||
− | except util.CommandException, inst: |
||
− | if inst.code == 1: |
||
− | util.SMlog("FSCK detected and corrected FS errors. Not fatal.") |
||
− | else: |
||
− | raise xs_errors.XenError('LVMMount', \ |
||
− | opterr='FSCK failed on %s. Errno is %d' % (self.remotepath,inst.code)) |
||
− | |||
− | try: |
||
− | util.pread(["mount", self.remotepath, self.path]) |
||
− | |||
− | FileSR.FileSR.attach(self, sr_uuid) |
||
− | |||
− | self.attached = True |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('LVMMount', \ |
||
− | opterr='Failed to mount FS. Errno is %d' % inst.code) |
||
− | #Update SCSIid string |
||
− | scsiutil.add_serial_record(self.session, self.sr_ref, \ |
||
− | scsiutil.devlist_to_serialstring(self.root.split(','))) |
||
− | |||
− | # Set the block scheduler |
||
− | for dev in self.root.split(','): self.block_setscheduler(dev) |
||
− | |||
− | def detach(self, sr_uuid): |
||
− | if not self._checkmount(): |
||
− | return |
||
− | cleanup.abort(self.uuid) |
||
− | try: |
||
− | # Change directory to avoid unmount conflicts |
||
− | os.chdir(SR.MOUNT_BASE) |
||
− | |||
− | # unmount the device |
||
− | util.pread(["umount", self.path]) |
||
− | |||
− | # remove the mountpoint |
||
− | os.rmdir(self.path) |
||
− | self.path = None |
||
− | |||
− | # deactivate SR |
||
− | try: |
||
− | cmd = ["lvchange", "-an", self.remotepath] |
||
− | util.pread2(cmd) |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('LVMUnMount', \ |
||
− | opterr='lvm -an failed errno is %d' % inst.code) |
||
− | |||
− | self.attached = False |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('LVMUnMount', \ |
||
− | opterr='errno is %d' % inst.code) |
||
− | except: |
||
− | raise xs_errors.XenError('LVMUnMount') |
||
− | |||
− | def probe(self): |
||
− | return lvutil.srlist_toxml(lvutil.scan_srlist(EXT_PREFIX, self.root)) |
||
− | |||
− | def create(self, sr_uuid, size): |
||
− | if self._checkmount(): |
||
− | raise xs_errors.XenError('SRExists') |
||
− | |||
− | # Check none of the devices already in use by other PBDs |
||
− | if util.test_hostPBD_devs(self.session, self.root): |
||
− | raise xs_errors.XenError('SRInUse') |
||
− | |||
− | # Check serial number entry in SR records |
||
− | for dev in self.root.split(','): |
||
− | if util.test_scsiserial(self.session, dev): |
||
− | raise xs_errors.XenError('SRInUse') |
||
− | |||
− | if not lvutil._checkVG(self.vgname): |
||
− | systemroot = util.getrootdev() |
||
− | rootdev = self.root.split(',')[0] |
||
− | # Create PVs for each device |
||
− | for dev in self.root.split(','): |
||
− | if dev in [systemroot, '%s1'%systemroot, '%s2'%systemroot]: |
||
− | raise xs_errors.XenError('Rootdev', \ |
||
− | opterr=('Device %s contains core system files, ' \ |
||
− | + 'please use another device') % dev) |
||
− | |||
− | if not os.path.exists(dev): |
||
− | raise xs_errors.XenError('InvalidDev', \ |
||
− | opterr=('Device %s does not exist') % dev) |
||
− | |||
− | try: |
||
− | f = os.open("%s" % dev, os.O_RDWR | os.O_EXCL) |
||
− | except: |
||
− | raise xs_errors.XenError('SRInUse') |
||
− | os.close(f) |
||
− | try: |
||
− | # Overwrite the disk header, try direct IO first |
||
− | cmd = ["dd","if=/dev/zero","of=%s" % dev,"bs=1M", \ |
||
− | "count=100","oflag=direct"] |
||
− | util.pread2(cmd) |
||
− | except util.CommandException, inst: |
||
− | if inst.code == errno.EPERM: |
||
− | try: |
||
− | cmd = ["dd","if=/dev/zero","of=%s" % dev,"bs=1M", \ |
||
− | "count=100"] |
||
− | util.pread2(cmd) |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('LVMWrite', |
||
− | opterr='disk %s, error %d' % (dev, inst.code)) |
||
− | else: |
||
− | raise xs_errors.XenError('LVMWrite', |
||
− | opterr='disk %s, error %d' % (dev, inst.code)) |
||
− | if not lvutil._checkPV(dev): |
||
− | try: |
||
− | cmd = ["pvcreate", "--metadatasize", "10M", dev] |
||
− | util.pread2(cmd) |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('LVMPartCreate', |
||
− | opterr='disk %s, error %d' % (dev, inst.code)) |
||
− | else: |
||
− | raise xs_errors.XenError('LVMPartInUse', |
||
− | opterr='disk %s' % dev) |
||
− | |||
− | # Create VG on first device |
||
− | try: |
||
− | cmd = ["vgcreate", self.vgname, rootdev] |
||
− | util.pread2(cmd) |
||
− | except : |
||
− | raise xs_errors.XenError('LVMGroupCreate') |
||
− | |||
− | # Then add any additional devs into the VG |
||
− | for dev in self.root.split(',')[1:]: |
||
− | try: |
||
− | cmd = ["vgextend", self.vgname, dev] |
||
− | util.pread2(cmd) |
||
− | except util.CommandException, inst: |
||
− | # One of the PV args failed, delete SR |
||
− | try: |
||
− | cmd = ["vgremove", self.vgname] |
||
− | util.pread2(cmd) |
||
− | except: |
||
− | pass |
||
− | raise xs_errors.XenError('LVMGroupCreate') |
||
− | if lvutil._checkLV(self.remotepath): |
||
− | raise xs_errors.XenError('SRExists') |
||
− | try: |
||
− | numdevs = len(self.root.split(',')) |
||
− | cmd = ["lvcreate", "-n", sr_uuid] |
||
− | if numdevs > 1: |
||
− | lowest = -1 |
||
− | for dev in self.root.split(','): |
||
− | stats = lvutil._getPVstats(dev) |
||
− | if lowest < 0 or stats['freespace'] < lowest: |
||
− | lowest = stats['freespace'] |
||
− | size_mb = (lowest / (1024 * 1024)) * numdevs |
||
− | |||
− | # Add stripe parameter to command |
||
− | cmd += ["-i", str(numdevs), "-I", "2048"] |
||
− | else: |
||
− | stats = lvutil._getVGstats(self.vgname) |
||
− | size_mb = stats['freespace'] / (1024 * 1024) |
||
− | assert(size_mb > 0) |
||
− | cmd += ["-L", str(size_mb), self.vgname] |
||
− | text = util.pread(cmd) |
||
− | |||
− | cmd = ["lvchange", "-ay", self.remotepath] |
||
− | text = util.pread(cmd) |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('LVMCreate', \ |
||
− | opterr='lv operation, error %d' % inst.code) |
||
− | except AssertionError: |
||
− | raise xs_errors.XenError('SRNoSpace', \ |
||
− | opterr='Insufficient space in VG %s' % self.vgname) |
||
− | |||
− | try: |
||
− | util.pread2(["mkfs.xfs", self.remotepath]) |
||
− | except util.CommandException, inst: |
||
− | raise xs_errors.XenError('LVMFilesystem', \ |
||
− | opterr='mkfs failed error %d' % inst.code) |
||
− | |||
− | #Update serial number string |
||
− | scsiutil.add_serial_record(self.session, self.sr_ref, \ |
||
− | scsiutil.devlist_to_serialstring(self.root.split(','))) |
||
− | |||
− | def vdi(self, uuid, loadLocked = False): |
||
− | if not loadLocked: |
||
− | return EXTFileVDI(self, uuid) |
||
− | return EXTFileVDI(self, uuid) |
||
− | |||
− | def _checkmount(self): |
||
− | return self.path and os.path.ismount(self.path) |
||
− | |||
− | class EXTFileVDI(FileSR.FileVDI): |
||
− | def attach(self, sr_uuid, vdi_uuid): |
||
− | try: |
||
− | vdi_ref = self.sr.srcmd.params['vdi_ref'] |
||
− | self.session.xenapi.VDI.remove_from_xenstore_data(vdi_ref, \ |
||
− | "vdi-type") |
||
− | self.session.xenapi.VDI.remove_from_xenstore_data(vdi_ref, \ |
||
− | "storage-type") |
||
− | self.session.xenapi.VDI.add_to_xenstore_data(vdi_ref, \ |
||
− | "storage-type", "xfs") |
||
− | except: |
||
− | util.logException("EXTSR:attach") |
||
− | pass |
||
− | |||
− | return super(EXTFileVDI, self).attach(sr_uuid, vdi_uuid) |
||
− | |||
− | |||
− | if __name__ == '__main__': |
||
− | SRCommand.run(EXTSR, DRIVER_INFO) |
||
− | else: |
||
− | SR.registerSR(EXTSR) |
||
− | ------------SNIP----------------------- |
Revision as of 02:39, 21 December 2011
LVM backed XFS SR Ive created a Logical Volume under Kubuntu 11.10 with XFS and Kronos installed The following is what was required:
install lvm2 and xfstools
"apt-get install lvm2 xfstools"
create a logical volume
(If you need help in doing this, there are many tutorials for LVM on the net) ( see [1] )
Then you must copy the XFSSR.py
"cp XFSSR.py /usr/lib/xcp/sm/"
create a symlink to XFSSR
"cd /usr/lib/xcp/sm/"
"ln -s XFSSR.py XFSSR"
once the logical volume is created restart xapi
"service xcp-xapi restart"
to create the SR, run
"SR=`xe sr-create type=xfs device-config:device=/dev/mapper/test-builder name-label=xfs`"
change '/dev/mapper/test-builder' to your lvm device to match your system
after its done, youll be able to use the XFS LVM filesystem as the default SR
Enjoy