@@ -10,6 +10,7 @@ import traceback
1010import subprocess
1111import os
1212import errno
13+ import re
1314import shutil
1415import StringIO
1516import ConfigParser
@@ -18,12 +19,35 @@ import xcp.logger
1819
1920
2021TMP_DIR = '/tmp/'
21- PATCH_PRECHECK_FAILED_UNKNOWN_ERROR = 'PATCH_PRECHECK_FAILED_UNKNOWN_ERROR'
22+ UPDATE_PRECHECK_FAILED_UNKNOWN_ERROR = 'UPDATE_PRECHECK_FAILED_UNKNOWN_ERROR'
23+ UPDATE_PRECHECK_FAILED_PREREQUISITE_MISSING = 'UPDATE_PRECHECK_FAILED_PREREQUISITE_MISSING'
24+ UPDATE_PRECHECK_FAILED_CONFLICT_PRESENT = 'UPDATE_PRECHECK_FAILED_CONFLICT_PRESENT'
25+ UPDATE_PRECHECK_FAILED_WRONG_SERVER_VERSION = 'UPDATE_PRECHECK_FAILED_WRONG_SERVER_VERSION'
26+ UPDATE_PRECHECK_FAILED_OUT_OF_SPACE = 'UPDATE_PRECHECK_FAILED_OUT_OF_SPACE'
27+ INVALID_UPDATE = 'INVALID_UPDATE'
2228CANNOT_FIND_UPDATE = 'CANNOT_FIND_UPDATE'
29+ ERROR_MESSAGE_START = 'Error: '
30+ ERROR_MESSAGE_END = 'You could try '
31+ ERROR_MESSAGE_CONFLICT = ' conflicts with '
32+ ERROR_MESSAGE_PREREQUISITE = 'Requires: '
33+ ERROR_MESSAGE_VERSION_REQUIRED = 'Requires: '
34+ ERROR_MESSAGE_VERSION_INSTALLED = 'Installed: '
35+ ERROR_MESSAGE_DOWNLOAD_PACKAGE = 'Error downloading packages:\n '
2336
2437class PrecheckFailure (Exception ):
2538 pass
2639
40+ class PrerequisiteMissing (Exception ):
41+ pass
42+
43+ class ConflictPresent (Exception ):
44+ pass
45+
46+ class WrongServerVersion (Exception ):
47+ pass
48+
49+ class InvalidUpdate (Exception ):
50+ pass
2751
2852def success_message (result ):
2953 rpcparams = {'Status' : 'Success' , 'Value' : result }
@@ -41,10 +65,10 @@ def parse_control_package(session, yum_url):
4165 update_xml = urllib2 .urlopen (yum_url + '/update.xml' ).read ()
4266 xmldoc = xml .dom .minidom .parse (StringIO .StringIO (update_xml ))
4367 else :
44- raise PrecheckFailure ('Incorrect yum repo (%r)' % yum_url )
68+ raise PrecheckFailure ('Incorrect yum repo' )
4569 items = xmldoc .getElementsByTagName ('update' )
4670 if not items :
47- raise PrecheckFailure ('Parse Control Package from yum (%r)' % yum_url )
71+ raise PrecheckFailure ('Missing <update> in update.xml' )
4872 return items [0 ].getAttribute ('control' )
4973
5074
@@ -54,19 +78,29 @@ def execute_precheck(session, control_package, yum_conf_file):
5478 livepatch_dic = {'PATCH_PRECHECK_LIVEPATCH_COMPLETE' : 'ok_livepatch_complete' , 'PATCH_PRECHECK_LIVEPATCH_INCOMPLETE' : 'ok_livepatch_incomplete' , 'PATCH_PRECHECK_LIVEPATCH_NOT_APPLICABLE' : 'ok' }
5579 cmd = ['yum' , 'install' , '-y' , '--noplugins' , '-c' , yum_conf_file , control_package ]
5680 p = subprocess .Popen (cmd , shell = False , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , close_fds = True )
57- p .wait ()
58- output = p .stdout .read ()
81+ output , _ = p .communicate ()
5982 xcp .logger .info ('pool_update.precheck %r returncode=%r output=%r' , cmd , p .returncode , output )
60- lines = output .splitlines ()
6183 if p .returncode != 0 :
62- errorlines = [l for l in lines if l .startswith ('Error: ' )]
63- if errorlines :
64- errmsg = errorlines [- 1 ].split (':' , 1 )[- 1 ].strip ()
84+ if ERROR_MESSAGE_DOWNLOAD_PACKAGE in output :
85+ raise InvalidUpdate ('Missing package(s) in the update' )
86+
87+ m = re .search ('(?<=' + ERROR_MESSAGE_START + ').+$' , output , flags = re .DOTALL )
88+ if m :
89+ errmsg = m .group ()
90+ errmsg = re .sub (ERROR_MESSAGE_END + '.+' , '' , errmsg , flags = re .DOTALL )
91+ errmsg = re .sub ('\n +' , ' ' , errmsg , flags = re .DOTALL )
92+ if ERROR_MESSAGE_CONFLICT in errmsg :
93+ raise ConflictPresent (errmsg )
94+ elif ERROR_MESSAGE_VERSION_REQUIRED in errmsg and ERROR_MESSAGE_VERSION_INSTALLED in errmsg :
95+ raise WrongServerVersion (errmsg )
96+ elif ERROR_MESSAGE_PREREQUISITE in errmsg :
97+ raise PrerequisiteMissing (errmsg )
98+ else :
99+ raise PrecheckFailure (errmsg )
65100 else :
66- errmsg = lines [- 1 ]
67- raise PrecheckFailure (
68- 'Install %s error: %s' % (control_package , errmsg ))
101+ raise PrecheckFailure ()
69102 else :
103+ lines = output .splitlines ()
70104 resultlines = [l for l in lines if l .startswith ('<livepatch ' )]
71105 if resultlines :
72106 result = resultlines [- 1 ].split ('\" ' )[1 ]
@@ -102,8 +136,20 @@ if __name__ == '__main__':
102136 update_vdi_uuid = session .xenapi .VDI .get_uuid (update_vdi )
103137 update_vdi_valid = True
104138 except Exception as e :
105- print (failure_message (CANNOT_FIND_UPDATE ,
106- ['Missing update package [uuid=%s]' % update_uuid ]))
139+ print (failure_message (CANNOT_FIND_UPDATE , []))
140+ sys .exit (0 )
141+
142+ # verify that dom0 has enough space to install the package
143+ statvfs = os .statvfs ('/' )
144+ available_dom0_disk_size = statvfs .f_frsize * statvfs .f_bavail
145+ try :
146+ required_size = int (int (session .xenapi .pool_update .get_installation_size (update )) * 1.5 )
147+ if required_size > available_dom0_disk_size :
148+ print (failure_message (UPDATE_PRECHECK_FAILED_OUT_OF_SPACE ,
149+ [update_package , str (available_dom0_disk_size ), str (required_size )]))
150+ sys .exit (0 )
151+ except :
152+ print (failure_message (INVALID_UPDATE , ["Issue with <installation-size> in update.xml" ]))
107153 sys .exit (0 )
108154
109155 # attach and get the yum configuration
@@ -126,9 +172,16 @@ if __name__ == '__main__':
126172
127173 control_package = parse_control_package (session , yum_url )
128174 print (success_message (execute_precheck (session , control_package , yum_conf_file )))
175+ except PrerequisiteMissing as e :
176+ print (failure_message (UPDATE_PRECHECK_FAILED_PREREQUISITE_MISSING , [update_package , str (e )]))
177+ except ConflictPresent as e :
178+ print (failure_message (UPDATE_PRECHECK_FAILED_CONFLICT_PRESENT , [update_package , str (e )]))
179+ except WrongServerVersion as e :
180+ print (failure_message (UPDATE_PRECHECK_FAILED_WRONG_SERVER_VERSION , [update_package , str (e )]))
181+ except InvalidUpdate as e :
182+ print (failure_message (INVALID_UPDATE , [update_package , str (e )]))
129183 except Exception as e :
130- print (failure_message (PATCH_PRECHECK_FAILED_UNKNOWN_ERROR ,
131- ['Precheck failed on host %s [uuid=%s]: %s' % (host_name_label ,host_uuid , e )]))
184+ print (failure_message (UPDATE_PRECHECK_FAILED_UNKNOWN_ERROR , [update_package , str (e )]))
132185 finally :
133186 if session is not None and update_vdi_valid is True :
134187 session .xenapi .pool_update .detach (update )
0 commit comments