2424import sys
2525import time
2626import os
27+ import requests
2728
2829# Fabric
2930from fabric .api import *
4950# Class to handle XenServer patching
5051class xenserver ():
5152
52- def __init__ (self , ssh_user = 'root' , threads = 5 ):
53+ def __init__ (self , ssh_user = 'root' , threads = 5 , pre_empty_script = 'xenserver_pre_empty_script.sh' ,
54+ post_empty_script = 'xenserver_post_empty_script.sh' ):
5355 self .ssh_user = ssh_user
5456 self .threads = threads
57+ self .pre_empty_script = pre_empty_script
58+ self .post_empty_script = post_empty_script
5559
5660 # Wait for hypervisor to become alive again
5761 def check_connect (self , host ):
@@ -74,16 +78,15 @@ def check_connect(self, host):
7478 # Remove progress indication
7579 sys .stdout .write ("\033 [F" )
7680 print "Note: Host " + host .name + " is able to do XE stuff again! "
77- print "Note: Waiting 30s to allow the hypervisor to connect.."
78- time .sleep (30 )
81+ print "Note: Waiting 60s to allow the hypervisor to connect.."
82+ time .sleep (60 )
7983 return True
8084
8185 # Check if we can use xapi
8286 def check_xapi (self , host ):
8387 try :
84- with settings (host_string = self .ssh_user + "@" + host .ipaddress ):
85- with warn_only ():
86- result = fab .run ("xe host-enable host=" + host .name )
88+ with settings (warn_only = True , host_string = self .ssh_user + "@" + host .ipaddress ):
89+ result = fab .run ("xe host-enable host=" + host .name )
8790 if result .return_code == 0 :
8891 return True
8992 else :
@@ -169,11 +172,16 @@ def host_evacuate(self, host):
169172
170173 # Reboot a host when all conditions are met
171174 def host_reboot (self , host , halt_hypervisor = False ):
172- # Disbale host
175+ # Disable host
173176 if self .host_disable (host ) is False :
174177 print "Error: Disabling host " + host .name + " failed."
175178 return False
176179
180+ # Execute pre-empty-script
181+ if self .exec_script_on_hypervisor (host , self .pre_empty_script ) is False :
182+ print "Error: Executing script '" + self .pre_empty_script + "' on host " + host .name + " failed."
183+ return False
184+
177185 # Then evacuate it
178186 if self .host_evacuate (host ) is False :
179187 print "Error: Evacuating host " + host .name + " failed."
@@ -185,6 +193,11 @@ def host_reboot(self, host, halt_hypervisor=False):
185193 return False
186194 print "Note: Host " + host .name + " has no VMs running, continuing"
187195
196+ # Execute post-empty-script
197+ if self .exec_script_on_hypervisor (host , self .post_empty_script ) is False :
198+ print "Error: Executing script '" + self .post_empty_script + "' on host " + host .name + " failed."
199+ return False
200+
188201 # Finally reboot it
189202 try :
190203 with settings (host_string = self .ssh_user + "@" + host .ipaddress ):
@@ -209,6 +222,16 @@ def host_reboot(self, host, halt_hypervisor=False):
209222 print "Error: Enabling host " + host .name + " failed."
210223 return False
211224
225+ # Execute script on hypervisor
226+ def exec_script_on_hypervisor (self , host , script ):
227+ script = script .split ('/' )[- 1 ]
228+ print "Note: Executing script '%s' on host %s.." % (script , host .name )
229+ try :
230+ with settings (show ('output' ), host_string = self .ssh_user + "@" + host .ipaddress ):
231+ return fab .run ("bash /tmp/" + script )
232+ except :
233+ return False
234+
212235 # Get VM count of a hypervisor
213236 def host_get_vms (self , host ):
214237 try :
@@ -275,6 +298,12 @@ def put_scripts(self, host):
275298 '/tmp/xenserver_fake_pvtools.sh' , mode = 0755 )
276299 put ('xenserver_parallel_evacuate.py' ,
277300 '/tmp/xenserver_parallel_evacuate.py' , mode = 0755 )
301+ if len (self .pre_empty_script ) > 0 :
302+ put (self .pre_empty_script ,
303+ '/tmp/' + self .pre_empty_script .split ('/' )[- 1 ], mode = 0755 )
304+ if len (self .post_empty_script ) > 0 :
305+ put (self .post_empty_script ,
306+ '/tmp/' + self .post_empty_script .split ('/' )[- 1 ], mode = 0755 )
278307 return True
279308 except :
280309 print "Warning: Could not upload check scripts to host " + host .name + ". Continuing anyway."
@@ -308,3 +337,65 @@ def get_bond_status(self, host):
308337 return fab .run ("python /tmp/xenserver_check_bonds.py | awk {'print $1'} | tr -d \" :\" " )
309338 except :
310339 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
0 commit comments