Difference between revisions of "Creating a LVM backed XFS SR"

From Xen
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