Skip to content

Commit 94725ad

Browse files
committed
Install latest XenServer patches
1 parent b214496 commit 94725ad

7 files changed

Lines changed: 179 additions & 6 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
*.swp
33
config
44
*.iml
5-
.idea/
5+
.idea/
6+
xenserver_patches/

cloudstackops/xenserver.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import sys
2525
import time
2626
import os
27+
import requests
2728

2829
# Fabric
2930
from fabric.api import *
@@ -224,7 +225,7 @@ def host_reboot(self, host, halt_hypervisor=False):
224225

225226
# Execute script on hypervisor
226227
def exec_script_on_hypervisor(self, host, script):
227-
print "Note: Executing script %s on host %s.." % (script, host.name)
228+
print "Note: Executing script '%s' on host %s.." % (script, host.name)
228229
try:
229230
with settings(show('output'), host_string=self.ssh_user + "@" + host.ipaddress):
230231
return fab.run("bash /tmp/" + script)
@@ -336,3 +337,65 @@ def get_bond_status(self, host):
336337
return fab.run("python /tmp/xenserver_check_bonds.py | awk {'print $1'} | tr -d \":\"")
337338
except:
338339
return False
340+
341+
# Download XenServer patch
342+
def download_patch(self, url):
343+
filename = url.split("/")[-1]
344+
345+
directory = "xenserver_patches"
346+
if not os.path.exists(directory):
347+
os.makedirs(directory)
348+
349+
destination_file = os.getcwd() + '/' + directory + '/' + filename
350+
try:
351+
local_length = int(os.path.getsize(destination_file))
352+
except:
353+
local_length = 0
354+
355+
print "Note: Executing request.."
356+
try:
357+
response = requests.get(url, stream=True)
358+
remote_length = int(response.headers.get('Content-Length', 0))
359+
if not response.ok:
360+
return False
361+
except:
362+
return False
363+
364+
# Do we need to download?
365+
print "Note: The remote length is %s, local length is %s" % (remote_length, local_length)
366+
367+
if remote_length == local_length:
368+
print "Note: Skipping download because file is already downloaded."
369+
return True
370+
371+
with open(destination_file, 'wb') as handle:
372+
# Download file
373+
print "Note: Downloading file.."
374+
375+
for block in response.iter_content(1024):
376+
handle.write(block)
377+
return True
378+
379+
# Upload patches to poolmaster
380+
def put_patches_to_poolmaster(self, host):
381+
print "Note: Uploading patches to poolmaster.."
382+
try:
383+
with settings(host_string=self.ssh_user + "@" + host.ipaddress):
384+
run('rm -rf /root/xenserver_patches/')
385+
run('mkdir -p /root/xenserver_patches')
386+
put('xenserver_patches/*', '/root/xenserver_patches')
387+
put('xenserver_upload_patches_to_poolmaster.sh',
388+
'/root/xenserver_patches/xenserver_upload_patches_to_poolmaster.sh', mode=0755)
389+
return True
390+
except:
391+
print "Warning: Could not upload patches to host " + host.name + "."
392+
return False
393+
394+
# Upload patches to XenServer
395+
def upload_patches_to_xenserver(self, host):
396+
print "Note: We're uploading the patches to XenServer"
397+
try:
398+
with settings(show('output'), host_string=self.ssh_user + "@" + host.ipaddress):
399+
return fab.run("bash /root/xenserver_patches/xenserver_upload_patches_to_poolmaster.sh")
400+
except:
401+
return False

xenserver_patches_to_install.txt

Whitespace-only changes.

xenserver_post_empty_script.sh

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,56 @@
11
#!/usr/bin/env bash
22

3-
echo "This is the post_empty script you could customise."
3+
echo "This is the post_empty script you could customise."
4+
5+
#echo "Downgrading openvswitch RPM to the XenServer default"
6+
#rpm -Uvh http://10.200.10.10/software/xenserver/openvswitch-1.4.6-143.9926.i386.rpm --force --nodeps
7+
8+
echo "Applying patches"
9+
HOST_UUID=$(xe host-list name-label=${HOSTNAME} --minimal)
10+
11+
# Check for 6.5
12+
cat /etc/redhat-release | grep "6.5"
13+
if [ $? -eq 0 ]; then
14+
SERVICE_PACK_PATCH=XS65ESP1
15+
fi
16+
# Check for 6.2
17+
cat /etc/redhat-release | grep "6.2"
18+
if [ $? -eq 0 ]; then
19+
SERVICE_PACK_PATCH=XS62ESP1
20+
fi
21+
22+
# First apply SP1
23+
xe patch-list name-label=${SERVICE_PACK_PATCH} params=hosts --minimal | tr ',' '\n' | grep ${HOST_UUID}
24+
if [ $? -eq 0 ]; then
25+
echo Service Pack ${SERVICE_PACK_PATCH} is already installed, skipping.
26+
else
27+
echo Installing ${SERVICE_PACK_PATCH}...
28+
PATCH_UUID=$(xe patch-list name-label=${SERVICE_PACK_PATCH} | grep uuid | sed -e 's/^.*: //g')
29+
if [ ${PATCH_UUID} ]; then
30+
xe patch-apply uuid=${PATCH_UUID} host-uuid=${HOST_UUID}
31+
fi
32+
fi
33+
34+
# Apply any other available patch
35+
XEN_ALL_PATCHES=$(xe patch-list params=name-label --minimal | tr ',' '\n' )
36+
XEN_INSTALLED_PATCHES=$(xe patch-list hosts:contains=${HOST_UUID} params=name-label --minimal | tr ',' '\n' )
37+
38+
for patch in ${XEN_ALL_PATCHES}; do
39+
echo "Checking patch " ${patch}
40+
41+
# Check if already included
42+
echo ${XEN_INSTALLED_PATCHES} | grep ${patch} 2>&1 >/dev/null
43+
if [ $? -eq 0 ]; then
44+
echo Patch ${patch} is already installed, skipping.
45+
else
46+
echo Installing $patch...
47+
PATCH_UUID=$(xe patch-list name-label=${patch}| grep uuid | sed -e 's/^.*: //g')
48+
if [ ${PATCH_UUID} ]; then
49+
xe patch-apply uuid=${PATCH_UUID} host-uuid=${HOST_UUID}
50+
fi
51+
fi
52+
done
53+
54+
echo "Upgrading drivers"
55+
yum -y install bnx2x-* fnic* qla2* glnic* qlge* tg3* hpsa* openvswitch-modules-xen*
56+
yum -y upgrade nicira-ovs-hypervisor-node

xenserver_pre_empty_script.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/usr/bin/env bash
22

3-
echo "This is the pre_empty script you could customise."
3+
echo "This is the pre_empty script you could customise."

xenserver_rolling_reboot.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ def handleArguments(argv):
6161
pre_empty_script = 'xenserver_pre_empty_script.sh'
6262
global post_empty_script
6363
post_empty_script = 'xenserver_post_empty_script.sh'
64+
global patch_list_file
65+
patch_list_file = 'xenserver_patches_to_install.txt'
6466
# Usage message
6567
help = "Usage: ./" + os.path.basename(__file__) + ' [options]' + \
6668
'\n --config-profile -c <profilename>\t\tSpecify the CloudMonkey profile name to ' \
@@ -74,6 +76,7 @@ def handleArguments(argv):
7476
'\n --pre-empty-script\t\t\t\tBash script to run on hypervisor before starting the live migrations to empty ' \
7577
'hypervisor (expected in same folder as this script)' + \
7678
'\n --post-empty-script\t\t\t\tBash script to run on hypervisor after a hypervisor has no more VMs running' \
79+
'\n --patch-list-file\t\t\t\tText file with URLs of patches to download and install. One per line. ' \
7780
'(expected in same folder as this script)' + \
7881
'\n --debug\t\t\t\t\tEnable debug mode' + \
7982
'\n --exec\t\t\t\t\tExecute for real' + \
@@ -83,7 +86,7 @@ def handleArguments(argv):
8386
opts, args = getopt.getopt(
8487
argv, "hc:n:t:p", [
8588
"credentials-file=", "clustername=", "ignore-hosts=", "threads=", "pre-empty-script=",
86-
"post-empty-script=", "halt", "debug", "exec", "prepare"])
89+
"post-empty-script=", "patch-list-file=", "halt", "debug", "exec", "prepare"])
8790
except getopt.GetoptError as e:
8891
print "Error: " + str(e)
8992
print help
@@ -107,6 +110,8 @@ def handleArguments(argv):
107110
pre_empty_script = arg
108111
elif opt in ("--post-empty-script"):
109112
post_empty_script = arg
113+
elif opt in ("--patch-list-file"):
114+
patch_list_file = arg
110115
elif opt in ("--debug"):
111116
DEBUG = 1
112117
elif opt in ("--exec"):
@@ -137,7 +142,7 @@ def handleArguments(argv):
137142
c = cloudstackops.CloudStackOps(DEBUG, DRYRUN)
138143

139144
# Init XenServer class
140-
x = xenserver.xenserver('root', threads)
145+
x = xenserver.xenserver('root', threads, pre_empty_script, post_empty_script)
141146
c.xenserver = x
142147

143148
# make credentials file known to our class
@@ -212,7 +217,10 @@ def handleArguments(argv):
212217
print " - Turn OFF XenServer poolHA for " + clustername
213218
print " - For any hypervisor it will do this (poolmaster " + poolmaster.name + " first):"
214219
print " - put it to Disabled aka Maintenance in XenServer"
220+
print " - download the patches in file --patch-list-file '" + patch_list_file + "'"
221+
print " - execute the --pre-empty-script script '" + pre_empty_script + "' on the hypervisor"
215222
print " - live migrate all VMs off of it using XenServer evacuate command"
223+
print " - execute the --post-empty-script script '" + post_empty_script + "' on the hypervisor"
216224
print " - when empty, it will reboot the hypervisor (halting is " + str(halt_hypervisor) + ")"
217225
print " - will wait for it to come back online (checks SSH connection)"
218226
print " - set the hypervisor to Enabled in XenServer"
@@ -261,6 +269,19 @@ def handleArguments(argv):
261269
disconnect_all()
262270
sys.exit(1)
263271

272+
# Download all XenServer patches
273+
print "Note: Reading patches list '%s'" % patch_list_file
274+
with open(patch_list_file) as file_pointer:
275+
patches = file_pointer.read().splitlines()
276+
277+
for patch_url in patches:
278+
print "Note: Processing patch '%s'" % patch_url
279+
x.download_patch(patch_url)
280+
281+
# Upload the patches to poolmaster, then to XenServer
282+
x.put_patches_to_poolmaster(poolmaster)
283+
x.upload_patches_to_xenserver(poolmaster)
284+
264285
# Migrate all VMs off of pool master
265286
vm_count = x.host_get_vms(poolmaster)
266287
if vm_count:
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env bash
2+
3+
if [ "$(xe host-list name-label=$HOSTNAME --minimal)" == "$(xe pool-list params=master --minimal)" ]
4+
then
5+
echo "We are the poolmaster, so let's process the patches."
6+
7+
echo "Unzipping patches"
8+
cd /root/xenserver_patches
9+
for file in $(ls /root/xenserver_patches/*.zip); do unzip ${file}; done
10+
11+
echo "Deleting what we don't need"
12+
rm -f /root/xenserver_patches/*.zip /root/xenserver_patches/*.bz2
13+
14+
# Check if already included
15+
XEN_ALL_PATCHES=$(xe patch-list params=name-label --minimal | tr ',' '\n' )
16+
for patch in $(ls *.xsupdate)
17+
do
18+
echo "Processing patch file ${patch}"
19+
20+
patchname=${patch%.*}
21+
echo "Checking if ${patchname} from file ${patch} is already uploaded"
22+
echo ${XEN_ALL_PATCHES} | tr ' ' '\n' | grep ^${patchname}$ 2>&1 >/dev/null
23+
if [ $? -eq 0 ]; then
24+
echo Patch ${patch} is already installed, skipping.
25+
else
26+
echo "Uploading patch ${patchname}"
27+
xe patch-upload file-name=${patch}
28+
if [ $? -gt 0 ]; then
29+
echo "Uploading failed, continuing with other patches"
30+
fi
31+
fi
32+
done
33+
else
34+
echo "We are NOT poolmaster, so skipping uploading patches"
35+
fi

0 commit comments

Comments
 (0)