Creating a LVM backed XFS SR: Difference between revisions
Outbackdingo (talk | contribs) No edit summary |
Outbackdingo (talk | contribs) No edit summary |
||
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