mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
* Add NFS version to mount command * Remove extra line * Extend NFS version to mount secondary storage * Unused import * Refactor NFS version to be granular * Make use of the ConfigKey on the NFS version setting value
306 lines
9.8 KiB
Python
306 lines
9.8 KiB
Python
#!/usr/bin/python
|
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
# Version @VERSION@
|
|
#
|
|
# A plugin for executing script needed by vmops cloud
|
|
|
|
import os, sys, time
|
|
import XenAPIPlugin
|
|
if os.path.exists("/opt/xensource/sm"):
|
|
sys.path.extend(["/opt/xensource/sm/", "/usr/local/sbin/", "/sbin/"])
|
|
if os.path.exists("/usr/lib/xcp/sm"):
|
|
sys.path.extend(["/usr/lib/xcp/sm/", "/usr/local/sbin/", "/sbin/"])
|
|
|
|
import SR, VDI, SRCommand, util, lvutil
|
|
from util import CommandException
|
|
import vhdutil
|
|
import shutil
|
|
import lvhdutil
|
|
import errno
|
|
import subprocess
|
|
import xs_errors
|
|
import cleanup
|
|
import stat
|
|
import random
|
|
import cloudstack_pluginlib as lib
|
|
import logging
|
|
|
|
lib.setup_logging("/var/log/cloud/cloud.log")
|
|
|
|
VHDUTIL = "vhd-util"
|
|
VHD_PREFIX = 'VHD-'
|
|
CLOUD_DIR = '/var/run/cloud_mount'
|
|
|
|
def echo(fn):
|
|
def wrapped(*v, **k):
|
|
name = fn.__name__
|
|
logging.debug("#### CLOUD enter %s ####" % name )
|
|
res = fn(*v, **k)
|
|
logging.debug("#### CLOUD exit %s ####" % name )
|
|
return res
|
|
return wrapped
|
|
|
|
def getPrimarySRPath(primaryStorageSRUuid, isISCSI):
|
|
if isISCSI:
|
|
primarySRDir = lvhdutil.VG_PREFIX + primaryStorageSRUuid
|
|
return os.path.join(lvhdutil.VG_LOCATION, primarySRDir)
|
|
else:
|
|
return os.path.join(SR.MOUNT_BASE, primaryStorageSRUuid)
|
|
|
|
def getBackupVHD(UUID):
|
|
return UUID + '.' + SR.DEFAULT_TAP
|
|
|
|
def getVHD(UUID, isISCSI):
|
|
if isISCSI:
|
|
return VHD_PREFIX + UUID
|
|
else:
|
|
return UUID + '.' + SR.DEFAULT_TAP
|
|
|
|
def getIsTrueString(stringValue):
|
|
booleanValue = False
|
|
if (stringValue and stringValue == 'true'):
|
|
booleanValue = True
|
|
return booleanValue
|
|
|
|
def makeUnavailable(uuid, primarySRPath, isISCSI):
|
|
if not isISCSI:
|
|
return
|
|
VHD = getVHD(uuid, isISCSI)
|
|
path = os.path.join(primarySRPath, VHD)
|
|
manageAvailability(path, '-an')
|
|
return
|
|
|
|
def manageAvailability(path, value):
|
|
if path.__contains__("/var/run/sr-mount"):
|
|
return
|
|
logging.debug("Setting availability of " + path + " to " + value)
|
|
try:
|
|
cmd = ['/usr/sbin/lvchange', value, path]
|
|
util.pread2(cmd)
|
|
except: #CommandException, (rc, cmdListStr, stderr):
|
|
#errMsg = "CommandException thrown while executing: " + cmdListStr + " with return code: " + str(rc) + " and stderr: " + stderr
|
|
errMsg = "Unexpected exception thrown by lvchange"
|
|
logging.debug(errMsg)
|
|
if value == "-ay":
|
|
# Raise an error only if we are trying to make it available.
|
|
# Just warn if we are trying to make it unavailable after the
|
|
# snapshot operation is done.
|
|
raise xs_errors.XenError(errMsg)
|
|
return
|
|
|
|
|
|
def checkVolumeAvailablility(path):
|
|
try:
|
|
if not isVolumeAvailable(path):
|
|
# The VHD file is not available on XenSever. The volume is probably
|
|
# inactive or detached.
|
|
# Do lvchange -ay to make it available on XenServer
|
|
manageAvailability(path, '-ay')
|
|
except:
|
|
errMsg = "Could not determine status of ISCSI path: " + path
|
|
logging.debug(errMsg)
|
|
raise xs_errors.XenError(errMsg)
|
|
|
|
success = False
|
|
i = 0
|
|
while i < 6:
|
|
i = i + 1
|
|
# Check if the vhd is actually visible by checking for the link
|
|
# set isISCSI to true
|
|
success = isVolumeAvailable(path)
|
|
if success:
|
|
logging.debug("Made vhd: " + path + " available and confirmed that it is visible")
|
|
break
|
|
|
|
# Sleep for 10 seconds before checking again.
|
|
time.sleep(10)
|
|
|
|
# If not visible within 1 min fail
|
|
if not success:
|
|
logging.debug("Could not make vhd: " + path + " available despite waiting for 1 minute. Does it exist?")
|
|
|
|
return success
|
|
|
|
def isVolumeAvailable(path):
|
|
# Check if iscsi volume is available on this XenServer.
|
|
status = "0"
|
|
try:
|
|
p = subprocess.Popen(["/bin/bash", "-c", "if [ -L " + path + " ]; then echo 1; else echo 0;fi"], stdout=subprocess.PIPE)
|
|
status = p.communicate()[0].strip("\n")
|
|
except:
|
|
errMsg = "Could not determine status of ISCSI path: " + path
|
|
logging.debug(errMsg)
|
|
raise xs_errors.XenError(errMsg)
|
|
|
|
return (status == "1")
|
|
|
|
def scanParent(path):
|
|
# Do a scan for the parent for ISCSI volumes
|
|
# Note that the parent need not be visible on the XenServer
|
|
parentUUID = ''
|
|
try:
|
|
lvName = os.path.basename(path)
|
|
dirname = os.path.dirname(path)
|
|
vgName = os.path.basename(dirname)
|
|
vhdInfo = vhdutil.getVHDInfoLVM(lvName, lvhdutil.extractUuid, vgName)
|
|
parentUUID = vhdInfo.parentUuid
|
|
except:
|
|
errMsg = "Could not get vhd parent of " + path
|
|
logging.debug(errMsg)
|
|
raise xs_errors.XenError(errMsg)
|
|
return parentUUID
|
|
|
|
def getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI):
|
|
snapshotVHD = getVHD(snapshotUuid, isISCSI)
|
|
snapshotPath = os.path.join(primarySRPath, snapshotVHD)
|
|
|
|
baseCopyUuid = ''
|
|
if isISCSI:
|
|
checkVolumeAvailablility(snapshotPath)
|
|
baseCopyUuid = scanParent(snapshotPath)
|
|
else:
|
|
baseCopyUuid = getParent(snapshotPath, isISCSI)
|
|
|
|
logging.debug("Base copy of snapshotUuid: " + snapshotUuid + " is " + baseCopyUuid)
|
|
return baseCopyUuid
|
|
|
|
def getParent(path, isISCSI):
|
|
parentUUID = ''
|
|
try :
|
|
if isISCSI:
|
|
parentUUID = vhdutil.getParent(path, lvhdutil.extractUuid)
|
|
else:
|
|
parentUUID = vhdutil.getParent(path, cleanup.FileVDI.extractUuid)
|
|
except:
|
|
errMsg = "Could not get vhd parent of " + path
|
|
logging.debug(errMsg)
|
|
raise xs_errors.XenError(errMsg)
|
|
return parentUUID
|
|
|
|
def getVhdParent(session, args):
|
|
logging.debug("getParent with " + str(args))
|
|
try:
|
|
primaryStorageSRUuid = args['primaryStorageSRUuid']
|
|
snapshotUuid = args['snapshotUuid']
|
|
isISCSI = getIsTrueString(args['isISCSI'])
|
|
|
|
primarySRPath = getPrimarySRPath(primaryStorageSRUuid, isISCSI)
|
|
logging.debug("primarySRPath: " + primarySRPath)
|
|
|
|
baseCopyUuid = getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI)
|
|
|
|
return baseCopyUuid
|
|
except:
|
|
logging.debug('getVhdParent', exc_info=True)
|
|
raise xs_errors.XenError("Failed to getVhdParent")
|
|
def makedirs(path):
|
|
if not os.path.isdir(path):
|
|
try:
|
|
os.makedirs(path)
|
|
except OSError, (errno, strerror):
|
|
umount(path)
|
|
if os.path.isdir(path):
|
|
return
|
|
errMsg = "OSError while creating " + path + " with errno: " + str(errno) + " and strerr: " + strerror
|
|
logging.debug(errMsg)
|
|
raise xs_errors.XenError(errMsg)
|
|
return
|
|
|
|
def umount(localDir):
|
|
try:
|
|
cmd = ['umount', localDir]
|
|
util.pread2(cmd)
|
|
except CommandException:
|
|
errMsg = "CommandException raised while trying to umount " + localDir
|
|
logging.debug(errMsg)
|
|
raise xs_errors.XenError(errMsg)
|
|
|
|
logging.debug("Successfully unmounted " + localDir)
|
|
return
|
|
|
|
@echo
|
|
def mountNfsSecondaryStorage(session, args):
|
|
remoteDir = args['remoteDir']
|
|
localDir = args['localDir']
|
|
nfsVersion = args['nfsVersion']
|
|
logging.debug("mountNfsSecondaryStorage with params: " + str(args))
|
|
mounted = False
|
|
f = open("/proc/mounts", 'r')
|
|
for line in f:
|
|
tokens = line.split(" ")
|
|
if len(tokens) > 2 and tokens[0] == remoteDir and tokens[1] == localDir:
|
|
mounted = True
|
|
|
|
if mounted:
|
|
return "true"
|
|
|
|
makedirs(localDir)
|
|
options = "soft,tcp,timeo=133,retrans=1"
|
|
if nfsVersion:
|
|
options += ",vers=" + nfsVersion
|
|
try:
|
|
cmd = ['mount', '-o', options, remoteDir, localDir]
|
|
txt = util.pread2(cmd)
|
|
except:
|
|
txt = ''
|
|
errMsg = "Unexpected error while trying to mount " + remoteDir + " to " + localDir
|
|
logging.debug(errMsg)
|
|
raise xs_errors.XenError(errMsg)
|
|
logging.debug("Successfully mounted " + remoteDir + " to " + localDir)
|
|
|
|
return "true"
|
|
|
|
@echo
|
|
def umountNfsSecondaryStorage(session, args):
|
|
localDir = args['localDir']
|
|
try:
|
|
cmd = ['umount', localDir]
|
|
util.pread2(cmd)
|
|
except CommandException:
|
|
errMsg = "CommandException raised while trying to umount " + localDir
|
|
logging.debug(errMsg)
|
|
raise xs_errors.XenError(errMsg)
|
|
try:
|
|
os.system("rmdir " + localDir)
|
|
except:
|
|
pass
|
|
logging.debug("Successfully unmounted " + localDir)
|
|
return "true"
|
|
|
|
@echo
|
|
def makeDirectory(session, args):
|
|
path = args['path']
|
|
if not os.path.isdir(path):
|
|
try:
|
|
os.makedirs(path)
|
|
except OSError, (errno, strerror):
|
|
if os.path.isdir(path):
|
|
return "true"
|
|
errMsg = "OSError while creating " + path + " with errno: " + str(errno) + " and strerr: " + strerror
|
|
logging.debug(errMsg)
|
|
raise xs_errors.XenError(errMsg)
|
|
return "true"
|
|
|
|
if __name__ == "__main__":
|
|
XenAPIPlugin.dispatch({"getVhdParent":getVhdParent, "mountNfsSecondaryStorage":mountNfsSecondaryStorage,
|
|
"umountNfsSecondaryStorage":umountNfsSecondaryStorage,
|
|
"makeDirectory":makeDirectory})
|
|
|
|
|