Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CP-5817: Productise removal of lvm2-environment-device.patch #28

Closed
wants to merge 11 commits into from
20 changes: 16 additions & 4 deletions Makefile
Expand Up @@ -56,6 +56,9 @@ SM_LIBS += lcache
SM_LIBS += resetvdis
SM_LIBS += B_util

UDEV_RULES = 40-multipath
MPATH_DAEMON = sm-multipath

CRON_JOBS += ringwatch

SM_XML := XE_SR_ERRORCODES
Expand All @@ -67,6 +70,8 @@ MASTER_SCRIPT_DEST := /etc/xensource/master.d/
PLUGIN_SCRIPT_DEST := /etc/xapi.d/plugins/
LIBEXEC := /opt/xensource/libexec/
CRON_DEST := /etc/cron.d/
UDEV_RULES_DIR := /etc/udev/rules.d/
INIT_DIR := /etc/rc.d/init.d/

SM_STAGING := $(DESTDIR)
SM_STAMP := $(MY_OBJ_DIR)/.staging_stamp
Expand All @@ -85,8 +90,8 @@ precommit: build
CHANGED=$$(git status --porcelain $(SM_PY_FILES) | awk '{print $$2}'); \
for i in $$CHANGED; do \
echo Checking $${i} ...; \
RESULT=$$(PYTHONPATH=./snapwatchd:./drivers:$$PAYTHONPATH pylint --rcfile=tests/pylintrc $${i} | tee /dev/tty); \
[ -z "$$RESULT" ] || QUIT=1; \
RESULT=$$(PYTHONPATH=./snapwatchd:./drivers:$$PAYTHONPATH pylint --rcfile=tests/pylintrc $${i}); \
[ -z "$$RESULT" ] || { echo "$$RESULT"; QUIT=1; }; \
done; \
if [ $$QUIT -ne 0 ]; then \
exit 1; \
Expand All @@ -99,8 +104,8 @@ precheck: build
@ QUIT=0; \
for i in $(SM_PY_FILES); do \
echo Checking $${i} ...; \
RESULT=$$(PYTHONPATH=./snapwatchd:./drivers:$$PAYTHONPATH pylint --rcfile=tests/pylintrc $${i} | tee /dev/tty); \
[ -z "$$RESULT" ] || QUIT=1; \
RESULT=$$(PYTHONPATH=./snapwatchd:./drivers:$$PAYTHONPATH pylint --rcfile=tests/pylintrc $${i}); \
[ -z "$$RESULT" ] || { echo "$$RESULT"; QUIT=1; }; \
done; \
if [ $$QUIT -ne 0 ]; then \
exit 1; \
Expand All @@ -112,6 +117,8 @@ install: precheck
mkdir -p $(SM_STAGING)
$(call mkdir_clean,$(SM_STAGING))
mkdir -p $(SM_STAGING)$(SM_DEST)
mkdir -p $(SM_STAGING)$(UDEV_RULES_DIR)
mkdir -p $(SM_STAGING)$(INIT_DIR)
mkdir -p $(SM_STAGING)$(DEBUG_DEST)
mkdir -p $(SM_STAGING)$(BIN_DEST)
mkdir -p $(SM_STAGING)$(MASTER_SCRIPT_DEST)
Expand All @@ -120,6 +127,11 @@ install: precheck
for i in $(SM_PY_FILES); do \
install -m 755 $$i $(SM_STAGING)$(SM_DEST); \
done
install -m 755 multipath/$(MPATH_DAEMON) \
$(SM_STAGING)/$(INIT_DIR)
for i in $(UDEV_RULES); do \
install -m 644 multipath/$$i.rules \
$(SM_STAGING)$(UDEV_RULES_DIR); done
for i in $(SM_XML); do \
install -m 755 drivers/$$i.xml \
$(SM_STAGING)$(SM_DEST); done
Expand Down
16 changes: 13 additions & 3 deletions drivers/FileSR.py
Expand Up @@ -425,7 +425,14 @@ def load(self, vdi_uuid):
return

try:
diskinfo = util.ioretry(lambda: self._query_info(self.path))
# If the VDI is activated in R/W mode, the VHD footer won't be
# valid, use the back-up one instead.
vdi_ref = self.sr.srcmd.params['vdi_ref']
sm_config = self.session.xenapi.VDI.get_sm_config(vdi_ref)
use_bkp_footer = util.attached_as(sm_config) == 'RW'
diskinfo = util.ioretry(lambda: self._query_info(self.path,
use_bkp_footer))

if diskinfo.has_key('parent'):
self.parent = diskinfo['parent']
self.sm_config_override = {'vhd-parent':self.parent}
Expand Down Expand Up @@ -841,9 +848,12 @@ def _query_p_uuid(self, path):
ls = parent.split('/')
return ls[len(ls) - 1].replace(vhdutil.FILE_EXTN_VHD, '')

def _query_info(self, path):
def _query_info(self, path, use_bkp_footer=False):
diskinfo = {}
cmd = [SR.TAPDISK_UTIL, "query", vhdutil.VDI_TYPE_VHD, "-vpf", path]
qopts = '-vpf'
if use_bkp_footer:
qopts += 'b'
cmd = [SR.TAPDISK_UTIL, "query", vhdutil.VDI_TYPE_VHD, qopts, path]
txt = util.pread(cmd).split('\n')
diskinfo['size'] = txt[0]
lst = [txt[1].split('/')[-1].replace(vhdutil.FILE_EXTN_VHD, "")]
Expand Down
9 changes: 6 additions & 3 deletions drivers/ISCSISR.py
Expand Up @@ -360,9 +360,12 @@ def attach(self, sr_uuid):
try:
pbdref = util.find_my_pbd(self.session, self.host_ref, self.sr_ref)
if pbdref <> None:
other_conf = self.session.xenapi.PBD.get_other_config(pbdref)
other_conf['iscsi_sessions'] = str(sessions)
self.session.xenapi.PBD.set_other_config(pbdref, other_conf)
# Just to be safe in case of garbage left during crashes
# we remove the key and add it
self.session.xenapi.PBD.remove_from_other_config(
pbdref, "iscsi_sessions")
self.session.xenapi.PBD.add_to_other_config(
pbdref, "iscsi_sessions", str(sessions))
except:
pass

Expand Down
2 changes: 1 addition & 1 deletion drivers/LVHDSR.py
Expand Up @@ -1277,7 +1277,7 @@ def create(self, sr_uuid, vdi_uuid, size):
IS_A_SNAPSHOT_TAG: 0,
SNAPSHOT_OF_TAG: '',
SNAPSHOT_TIME_TAG: '',
TYPE_TAG: self.type,
TYPE_TAG: self.ty,
VDI_TYPE_TAG: self.vdi_type,
READ_ONLY_TAG: int(self.read_only),
MANAGED_TAG: int(self.managed),
Expand Down
2 changes: 1 addition & 1 deletion drivers/SHMSR.py
Expand Up @@ -109,8 +109,8 @@ def load(self, vdi_uuid):

def __init__(self, mysr, uuid, filename):
self.uuid = uuid
self.path = os.path.join(mysr.dconf['location'], filename)
VDI.VDI.__init__(self, mysr, None)
self.path = os.path.join(mysr.dconf['location'], filename)
self.label = filename
self.location = filename
self.vdi_type = 'file'
Expand Down
6 changes: 0 additions & 6 deletions drivers/SR.py
Expand Up @@ -107,12 +107,6 @@ def __init__(self, srcmd, sr_uuid):
if 'sr_ref' in self.srcmd.params:
self.sr_ref = self.srcmd.params['sr_ref']

if 'device_config' in self.srcmd.params:
if self.srcmd.params['device_config'].has_key('SCSIid'):
dev_path = '/dev/disk/by-scsid/'+self.srcmd.params['device_config']['SCSIid']
os.environ['LVM_DEVICE'] = dev_path
util.SMlog('Setting LVM_DEVICE to %s' % dev_path)

except Exception, e:
raise e
raise xs_errors.XenError('SRBadXML')
Expand Down
10 changes: 7 additions & 3 deletions drivers/VDI.py
Expand Up @@ -103,7 +103,7 @@ def __init__(self, sr, uuid):
self.sm_config_override = {}
self.sm_config_keep = []
self.path = None
self.type = None
self.ty = "user"

self.load(uuid)

Expand Down Expand Up @@ -320,9 +320,11 @@ def _override_sm_config(self, sm_config):
del sm_config[key]

def _db_update_sm_config(self, ref, sm_config):
import cleanup
current_sm_config = self.sr.session.xenapi.VDI.get_sm_config(ref)
for key, val in sm_config.iteritems():
if key.startswith("host_") or key == "paused":
if key.startswith("host_") or \
key in ["paused", cleanup.VDI.DB_VHD_BLOCKS]:
continue
if sm_config.get(key) != current_sm_config.get(key):
util.SMlog("_db_update_sm_config: %s sm-config:%s %s->%s" % \
Expand All @@ -331,7 +333,9 @@ def _db_update_sm_config(self, ref, sm_config):
self.sr.session.xenapi.VDI.add_to_sm_config(ref, key, val)

for key in current_sm_config.keys():
if key.startswith("host_") or key == "paused" or key in self.sm_config_keep:
if key.startswith("host_") or \
key in ["paused", cleanup.VDI.DB_VHD_BLOCKS] or \
key in self.sm_config_keep:
continue
if not sm_config.get(key):
util.SMlog("_db_update_sm_config: %s del sm-config:%s" % \
Expand Down
79 changes: 78 additions & 1 deletion drivers/cleanup.py
Expand Up @@ -29,6 +29,7 @@
import traceback
import base64
import zlib
import errno

import XenAPI
import util
Expand Down Expand Up @@ -61,6 +62,12 @@
LOCK_TYPE_RUNNING = "running"
lockRunning = None

# Default coalesce error rate limit, in messages per minute. A zero value
# disables throttling, and a negative value disables error reporting.
DEFAULT_COALESCE_ERR_RATE = 1.0/60

COALESCE_LAST_ERR_TAG = 'last-coalesce-error'
COALESCE_ERR_RATE_TAG = 'coalesce-error-rate'

class AbortException(util.SMException):
pass
Expand Down Expand Up @@ -687,10 +694,80 @@ def _runTapdiskDiff(self):
Util.doexec(cmd, 0)
return True

def _reportCoalesceError(vdi, ce):
"""Reports a coalesce error to XenCenter.

vdi: the VDI object on which the coalesce error occured
ce: the CommandException that was raised"""

msg_name = os.strerror(ce.code)
if ce.code == errno.ENOSPC:
# TODO We could add more information here, e.g. exactly how much
# space is required for the particular coalesce, as well as actions
# to be taken by the user and consequences of not taking these
# actions.
msg_body = 'Run out of space while coalescing.'
elif ce.code == errno.EIO:
msg_body = 'I/O error while coalescing.'
else:
msg_body = ''
util.SMlog('Coalesce failed on SR %s: %s (%s)'
% (vdi.sr.uuid, msg_name, msg_body))

# Create a XenCenter message, but don't spam.
xapi = vdi.sr.xapi.session.xenapi
sr_ref = xapi.SR.get_by_uuid(vdi.sr.uuid)
oth_cfg = xapi.SR.get_other_config(sr_ref)
if COALESCE_ERR_RATE_TAG in oth_cfg:
coalesce_err_rate = float(oth_cfg[COALESCE_ERR_RATE_TAG])
else:
coalesce_err_rate = DEFAULT_COALESCE_ERR_RATE

xcmsg = False
if coalesce_err_rate == 0:
xcmsg = True
elif coalesce_err_rate > 0:
now = datetime.datetime.now()
sm_cfg = xapi.SR.get_sm_config(sr_ref)
if COALESCE_LAST_ERR_TAG in sm_cfg:
# seconds per message (minimum distance in time between two
# messages in seconds)
spm = datetime.timedelta(seconds=(1.0/coalesce_err_rate)*60)
last = datetime.datetime.fromtimestamp(
float(sm_cfg[COALESCE_LAST_ERR_TAG]))
if now - last >= spm:
xapi.SR.remove_from_sm_config(sr_ref,
COALESCE_LAST_ERR_TAG)
xcmsg = True
else:
xcmsg = True
if xcmsg:
xapi.SR.add_to_sm_config(sr_ref, COALESCE_LAST_ERR_TAG,
str(now.strftime('%s')))
if xcmsg:
xapi.message.create(msg_name, "3", "SR", vdi.sr.uuid, msg_body)
_reportCoalesceError = staticmethod(_reportCoalesceError)

def _doCoalesceVHD(vdi):
try:
vhdutil.coalesce(vdi.path)
except util.CommandException, ce:
# We use try/except for the following piece of code because it runs
# in a separate process context and errors will not be caught and
# reported by anyone.
try:
VDI._reportCoalesceError(vdi, ce)
except Exception, e:
util.SMlog('failed to create XenCenter message: %s' % e)
raise ce
except:
raise
_doCoalesceVHD = staticmethod(_doCoalesceVHD)

def _coalesceVHD(self, timeOut):
Util.log(" Running VHD coalesce on %s" % self)
abortTest = lambda:IPCFlag(self.sr.uuid).test(FLAG_TYPE_ABORT)
Util.runAbortable(lambda: vhdutil.coalesce(self.path), None,
Util.runAbortable(lambda: VDI._doCoalesceVHD(self), None,
self.sr.uuid, abortTest, VDI.POLL_INTERVAL, timeOut)
util.fistpoint.activate("LVHDRT_coalescing_VHD_data",self.sr.uuid)

Expand Down
9 changes: 6 additions & 3 deletions drivers/mpathcount.py
Expand Up @@ -104,9 +104,12 @@ def match_dmpLUN(s):

def match_pathup(s):
s = re.sub('\]',' ',re.sub('\[','',s)).split()
dm_status = s[-1]
path_status = s[-2]
for val in [dm_status, path_status]:
# The new multipath has a different output. Fixed it
dm_status = s[-2]
path_status = s[-3]
# path_status is more reliable, at least for failures initiated or spotted by multipath
# To be tested for failures during high I/O when dm should spot errors first
for val in [path_status]:
if val in ['faulty','shaky','failed']:
return False
return True
Expand Down
2 changes: 1 addition & 1 deletion drivers/udevSR.py
Expand Up @@ -114,8 +114,8 @@ def read_whole_file(filename):

class udevVDI(VDI.VDI):
def __init__(self, sr, location):
self.location = location
VDI.VDI.__init__(self, sr, None)
self.location = location

def load(self, location):
self.path = self.location
Expand Down
6 changes: 6 additions & 0 deletions mk/sm.spec.in
Expand Up @@ -28,6 +28,10 @@ rm -rf $RPM_BUILD_ROOT

%post
[ ! -x /sbin/chkconfig ] || chkconfig --add mpathroot
[ ! -x /sbin/chkconfig ] || chkconfig --add sm-multipath

%preun
[ ! -x /sbin/chkconfig ] || chkconfig --del sm-multipath

%files
%defattr(-,root,root,-)
Expand Down Expand Up @@ -229,6 +233,8 @@ rm -rf $RPM_BUILD_ROOT
/opt/xensource/sm/xs_errors.pyc
/opt/xensource/sm/xs_errors.pyo
/sbin/mpathutil
/etc/rc.d/init.d/sm-multipath
%config /etc/udev/rules.d/40-multipath.rules


%changelog
Expand Down
12 changes: 12 additions & 0 deletions multipath/40-multipath.rules
@@ -0,0 +1,12 @@
SUBSYSTEM!="block", GOTO="end_mpath"
RUN+="socket:/org/kernel/dm/multipath_event"
KERNEL!="dm-*", GOTO="end_mpath"
ACTION=="add", PROGRAM=="/bin/bash -c '/sbin/dmsetup info -c -o name --noheadings -j %M -m %m | /bin/grep VG_XenStorage'", OPTIONS+="ignore_device"
ACTION=="add", PROGRAM=="/bin/bash -c '/sbin/dmsetup info -c -o name --noheadings -j %M -m %m | /bin/grep XSLocalEXT'", OPTIONS+="ignore_device"
KERNEL=="dm-*", ACTION=="add", PROGRAM=="/sbin/dmsetup info -c -o name --noheadings -j %M -m %m", RESULT=="?*", SYMLINK+="disk/by-scsid/%c/mapper"
ACTION=="change", PROGRAM!="/sbin/dmsetup info -c --noheadings -j %M -m %m", GOTO="end_mpath"
PROGRAM!="/sbin/dmsetup info -c -o uuid,name --separator ' ' --noheadings -j %M -m %m", GOTO="end_mpath"
RESULT!="mpath-*", GOTO="end_mpath"
# ENV is necessary otherwise the child process of mpathcount cannot find multipathd executable
ACTION=="change", ENV{PATH}="/sbin:/bin:/usr/sbin:/usr/bin", RUN+="/opt/xensource/sm/mpathcount.py %c{2}"
LABEL="end_mpath"