Skip to content

Commit 9a99c43

Browse files
committed
Use Python3 for Xenserver 8.4
1 parent 31123e3 commit 9a99c43

File tree

8 files changed

+4913
-0
lines changed

8 files changed

+4913
-0
lines changed

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/discoverer/XcpServerDiscoverer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import javax.naming.ConfigurationException;
3131
import javax.persistence.EntityExistsException;
3232

33+
import com.cloud.hypervisor.xenserver.resource.Xenserver84Resource;
3334
import org.apache.cloudstack.hypervisor.xenserver.XenserverConfigs;
3435
import org.apache.commons.collections.CollectionUtils;
3536
import org.apache.commons.lang3.StringUtils;
@@ -435,6 +436,8 @@ else if (prodBrand.equals("XenServer") && prodVersion.equals("5.6.0")) {
435436
}
436437
} else if (prodBrand.equals("XCP_Kronos")) {
437438
return new XcpOssResource();
439+
} else if (prodBrand.equals("XenServer") && prodVersion.equals("8.4.0")) {
440+
return new Xenserver84Resource();
438441
} else if (prodBrand.equals("XenServer") || prodBrand.equals("XCP-ng") || prodBrand.equals("Citrix Hypervisor")) {
439442
final String[] items = prodVersion.split("\\.");
440443
if ((Integer.parseInt(items[0]) > 6) ||
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.cloud.hypervisor.xenserver.resource;
2+
3+
public class Xenserver84Resource extends CitrixResourceBase {
4+
@Override
5+
protected String getPatchFilePath() {
6+
return "scripts/vm/hypervisor/xenserver/xenserver84/patch";
7+
}
8+
}
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
#!/usr/bin/python
2+
# Licensed to the Apache Software Foundation (ASF) under one
3+
# or more contributor license agreements. See the NOTICE file
4+
# distributed with this work for additional information
5+
# regarding copyright ownership. The ASF licenses this file
6+
# to you under the Apache License, Version 2.0 (the
7+
# "License"); you may not use this file except in compliance
8+
# with the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
19+
# Version @VERSION@
20+
#
21+
# A plugin for executing script needed by vmops cloud
22+
23+
import os, sys, time
24+
import XenAPIPlugin
25+
if os.path.exists("/opt/xensource/sm"):
26+
sys.path.extend(["/opt/xensource/sm/", "/usr/local/sbin/", "/sbin/"])
27+
if os.path.exists("/usr/lib/xcp/sm"):
28+
sys.path.extend(["/usr/lib/xcp/sm/", "/usr/local/sbin/", "/sbin/"])
29+
30+
import SR, VDI, SRCommand, util, lvutil
31+
from util import CommandException
32+
import vhdutil
33+
import shutil
34+
import lvhdutil
35+
import errno
36+
import subprocess
37+
import xs_errors
38+
import cleanup
39+
import stat
40+
import random
41+
import cloudstack_pluginlib as lib
42+
import logging
43+
44+
lib.setup_logging("/var/log/cloud/cloud.log")
45+
46+
VHDUTIL = "vhd-util"
47+
VHD_PREFIX = 'VHD-'
48+
CLOUD_DIR = '/var/run/cloud_mount'
49+
50+
def echo(fn):
51+
def wrapped(*v, **k):
52+
name = fn.__name__
53+
logging.debug("#### CLOUD enter %s ####" % name )
54+
res = fn(*v, **k)
55+
logging.debug("#### CLOUD exit %s ####" % name )
56+
return res
57+
return wrapped
58+
59+
def getPrimarySRPath(primaryStorageSRUuid, isISCSI):
60+
if isISCSI:
61+
primarySRDir = lvhdutil.VG_PREFIX + primaryStorageSRUuid
62+
return os.path.join(lvhdutil.VG_LOCATION, primarySRDir)
63+
else:
64+
return os.path.join(SR.MOUNT_BASE, primaryStorageSRUuid)
65+
66+
def getBackupVHD(UUID):
67+
return UUID + '.' + SR.DEFAULT_TAP
68+
69+
def getVHD(UUID, isISCSI):
70+
if isISCSI:
71+
return VHD_PREFIX + UUID
72+
else:
73+
return UUID + '.' + SR.DEFAULT_TAP
74+
75+
def getIsTrueString(stringValue):
76+
booleanValue = False
77+
if (stringValue and stringValue == 'true'):
78+
booleanValue = True
79+
return booleanValue
80+
81+
def makeUnavailable(uuid, primarySRPath, isISCSI):
82+
if not isISCSI:
83+
return
84+
VHD = getVHD(uuid, isISCSI)
85+
path = os.path.join(primarySRPath, VHD)
86+
manageAvailability(path, '-an')
87+
return
88+
89+
def manageAvailability(path, value):
90+
if path.__contains__("/var/run/sr-mount"):
91+
return
92+
logging.debug("Setting availability of " + path + " to " + value)
93+
try:
94+
cmd = ['/usr/sbin/lvchange', value, path]
95+
util.pread2(cmd)
96+
except: #CommandException, (rc, cmdListStr, stderr):
97+
#errMsg = "CommandException thrown while executing: " + cmdListStr + " with return code: " + str(rc) + " and stderr: " + stderr
98+
errMsg = "Unexpected exception thrown by lvchange"
99+
logging.debug(errMsg)
100+
if value == "-ay":
101+
# Raise an error only if we are trying to make it available.
102+
# Just warn if we are trying to make it unavailable after the
103+
# snapshot operation is done.
104+
raise xs_errors.XenError(errMsg)
105+
return
106+
107+
108+
def checkVolumeAvailability(path):
109+
try:
110+
if not isVolumeAvailable(path):
111+
# The VHD file is not available on XenSever. The volume is probably
112+
# inactive or detached.
113+
# Do lvchange -ay to make it available on XenServer
114+
manageAvailability(path, '-ay')
115+
except:
116+
errMsg = "Could not determine status of ISCSI path: " + path
117+
logging.debug(errMsg)
118+
raise xs_errors.XenError(errMsg)
119+
120+
success = False
121+
i = 0
122+
while i < 6:
123+
i = i + 1
124+
# Check if the vhd is actually visible by checking for the link
125+
# set isISCSI to true
126+
success = isVolumeAvailable(path)
127+
if success:
128+
logging.debug("Made vhd: " + path + " available and confirmed that it is visible")
129+
break
130+
131+
# Sleep for 10 seconds before checking again.
132+
time.sleep(10)
133+
134+
# If not visible within 1 min fail
135+
if not success:
136+
logging.debug("Could not make vhd: " + path + " available despite waiting for 1 minute. Does it exist?")
137+
138+
return success
139+
140+
def isVolumeAvailable(path):
141+
# Check if iscsi volume is available on this XenServer.
142+
status = "0"
143+
try:
144+
p = subprocess.Popen(["/bin/bash", "-c", "if [ -L " + path + " ]; then echo 1; else echo 0;fi"], stdout=subprocess.PIPE)
145+
status = p.communicate()[0].strip("\n")
146+
except:
147+
errMsg = "Could not determine status of ISCSI path: " + path
148+
logging.debug(errMsg)
149+
raise xs_errors.XenError(errMsg)
150+
151+
return (status == "1")
152+
153+
def scanParent(path):
154+
# Do a scan for the parent for ISCSI volumes
155+
# Note that the parent need not be visible on the XenServer
156+
parentUUID = ''
157+
try:
158+
lvName = os.path.basename(path)
159+
dirname = os.path.dirname(path)
160+
vgName = os.path.basename(dirname)
161+
vhdInfo = vhdutil.getVHDInfoLVM(lvName, lvhdutil.extractUuid, vgName)
162+
parentUUID = vhdInfo.parentUuid
163+
except:
164+
errMsg = "Could not get vhd parent of " + path
165+
logging.debug(errMsg)
166+
raise xs_errors.XenError(errMsg)
167+
return parentUUID
168+
169+
def getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI):
170+
snapshotVHD = getVHD(snapshotUuid, isISCSI)
171+
snapshotPath = os.path.join(primarySRPath, snapshotVHD)
172+
173+
baseCopyUuid = ''
174+
if isISCSI:
175+
checkVolumeAvailability(snapshotPath)
176+
baseCopyUuid = scanParent(snapshotPath)
177+
else:
178+
baseCopyUuid = getParent(snapshotPath, isISCSI)
179+
180+
logging.debug("Base copy of snapshotUuid: " + snapshotUuid + " is " + baseCopyUuid)
181+
return baseCopyUuid
182+
183+
def getParent(path, isISCSI):
184+
parentUUID = ''
185+
try :
186+
if isISCSI:
187+
parentUUID = vhdutil.getParent(path, lvhdutil.extractUuid)
188+
else:
189+
parentUUID = vhdutil.getParent(path, cleanup.FileVDI.extractUuid)
190+
except:
191+
errMsg = "Could not get vhd parent of " + path
192+
logging.debug(errMsg)
193+
raise xs_errors.XenError(errMsg)
194+
return parentUUID
195+
196+
def getVhdParent(session, args):
197+
logging.debug("getParent with " + str(args))
198+
try:
199+
primaryStorageSRUuid = args['primaryStorageSRUuid']
200+
snapshotUuid = args['snapshotUuid']
201+
isISCSI = getIsTrueString(args['isISCSI'])
202+
203+
primarySRPath = getPrimarySRPath(primaryStorageSRUuid, isISCSI)
204+
logging.debug("primarySRPath: " + primarySRPath)
205+
206+
baseCopyUuid = getParentOfSnapshot(snapshotUuid, primarySRPath, isISCSI)
207+
208+
return baseCopyUuid
209+
except:
210+
logging.debug('getVhdParent', exc_info=True)
211+
raise xs_errors.XenError("Failed to getVhdParent")
212+
def makedirs(path):
213+
if not os.path.isdir(path):
214+
try:
215+
os.makedirs(path)
216+
except OSError as e:
217+
umount(path)
218+
if os.path.isdir(path):
219+
return
220+
errMsg = "OSError while creating " + path + " with errno: " + str(e.errno) + " and strerr: " + e.strerror
221+
logging.debug(errMsg)
222+
raise xs_errors.XenError(errMsg)
223+
return
224+
225+
def umount(localDir):
226+
try:
227+
cmd = ['umount', localDir]
228+
util.pread2(cmd)
229+
except CommandException:
230+
errMsg = "CommandException raised while trying to umount " + localDir
231+
logging.debug(errMsg)
232+
raise xs_errors.XenError(errMsg)
233+
234+
logging.debug("Successfully unmounted " + localDir)
235+
return
236+
237+
@echo
238+
def mountNfsSecondaryStorage(session, args):
239+
remoteDir = args['remoteDir']
240+
localDir = args['localDir']
241+
nfsVersion = args['nfsVersion']
242+
logging.debug("mountNfsSecondaryStorage with params: " + str(args))
243+
mounted = False
244+
f = open("/proc/mounts", 'r')
245+
for line in f:
246+
tokens = line.split(" ")
247+
if len(tokens) > 2 and tokens[0] == remoteDir and tokens[1] == localDir:
248+
mounted = True
249+
250+
if mounted:
251+
return "true"
252+
253+
makedirs(localDir)
254+
options = "soft,tcp,timeo=133,retrans=1"
255+
if nfsVersion:
256+
options += ",vers=" + nfsVersion
257+
try:
258+
cmd = ['mount', '-o', options, remoteDir, localDir]
259+
txt = util.pread2(cmd)
260+
except:
261+
txt = ''
262+
errMsg = "Unexpected error while trying to mount " + remoteDir + " to " + localDir
263+
logging.debug(errMsg)
264+
raise xs_errors.XenError(errMsg)
265+
logging.debug("Successfully mounted " + remoteDir + " to " + localDir)
266+
267+
return "true"
268+
269+
@echo
270+
def umountNfsSecondaryStorage(session, args):
271+
localDir = args['localDir']
272+
try:
273+
cmd = ['umount', localDir]
274+
util.pread2(cmd)
275+
except CommandException:
276+
errMsg = "CommandException raised while trying to umount " + localDir
277+
logging.debug(errMsg)
278+
raise xs_errors.XenError(errMsg)
279+
try:
280+
os.system("rmdir " + localDir)
281+
except:
282+
pass
283+
logging.debug("Successfully unmounted " + localDir)
284+
return "true"
285+
286+
@echo
287+
def makeDirectory(session, args):
288+
path = args['path']
289+
if not os.path.isdir(path):
290+
try:
291+
os.makedirs(path)
292+
except OSError as e:
293+
if os.path.isdir(path):
294+
return "true"
295+
errMsg = "OSError while creating " + path + " with errno: " + str(e.errno) + " and strerr: " + e.strerror
296+
logging.debug(errMsg)
297+
raise xs_errors.XenError(errMsg)
298+
return "true"
299+
300+
if __name__ == "__main__":
301+
XenAPIPlugin.dispatch({"getVhdParent":getVhdParent, "mountNfsSecondaryStorage":mountNfsSecondaryStorage,
302+
"umountNfsSecondaryStorage":umountNfsSecondaryStorage,
303+
"makeDirectory":makeDirectory})
304+

0 commit comments

Comments
 (0)