Skip to content

Commit b40798d

Browse files
committed
CA-223030: Return corresponding error message for update precheck and apply extension.
Signed-off-by: Hui Zhang <[email protected]>
1 parent 8d7afa6 commit b40798d

File tree

2 files changed

+95
-33
lines changed

2 files changed

+95
-33
lines changed

scripts/extensions/pool_update.apply

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import json
77
import traceback
88
import subprocess
99
import os
10+
import re
1011
import fasteners
1112
import errno
1213
import shutil
@@ -17,13 +18,19 @@ TMP_DIR = '/tmp/'
1718
UPDATE_ALREADY_APPLIED = 'UPDATE_ALREADY_APPLIED'
1819
UPDATE_APPLY_FAILED = 'UPDATE_APPLY_FAILED'
1920
OTHER_OPERATION_IN_PROGRESS = 'OTHER_OPERATION_IN_PROGRESS'
20-
PATCH_PRECHECK_FAILED_UNKNOWN_ERROR = 'PATCH_PRECHECK_FAILED_UNKNOWN_ERROR'
21+
UPDATE_PRECHECK_FAILED_UNKNOWN_ERROR = 'UPDATE_PRECHECK_FAILED_UNKNOWN_ERROR'
2122
CANNOT_FIND_UPDATE = 'CANNOT_FIND_UPDATE'
23+
INVALID_UPDATE = 'INVALID_UPDATE'
24+
ERROR_MESSAGE_DOWNLOAD_PACKAGE = 'Error downloading packages:\n'
25+
ERROR_MESSAGE_START = 'Error: '
26+
ERROR_MESSAGE_END = 'You could try '
2227

2328

2429
class ApplyFailure(Exception):
2530
pass
2631

32+
class InvalidUpdate(Exception):
33+
pass
2734

2835
def success_message():
2936
rpcparams = {'Status': 'Success', 'Value': ''}
@@ -42,14 +49,17 @@ def execute_apply(session, update_package, yum_conf_file):
4249
output, _ = p.communicate()
4350
xcp.logger.info('pool_update.apply %r returncode=%r output=%r', cmd, p.returncode, output)
4451
if p.returncode != 0:
45-
lines = output.splitlines()
46-
errorlines = [l for l in lines if l.startswith('Error: ')]
47-
if errorlines:
48-
errmsg = errorlines[-1].split(':', 1)[-1].strip()
52+
if ERROR_MESSAGE_DOWNLOAD_PACKAGE in output:
53+
raise InvalidUpdate('Missing package(s) in the update.')
54+
55+
m = re.search('(?<=' + ERROR_MESSAGE_START + ').+$', output, flags=re.DOTALL)
56+
if m:
57+
errmsg = m.group()
58+
errmsg = re.sub(ERROR_MESSAGE_END + '.+', '', errmsg, flags=re.DOTALL)
59+
errmsg = re.sub('\n +', ' ', errmsg, flags=re.DOTALL)
60+
raise ApplyFailure(errmsg)
4961
else:
50-
errmsg = lines[-1]
51-
raise ApplyFailure(
52-
'Install %s error: %s' % (update_package, errmsg))
62+
raise ApplyFailure()
5363

5464

5565
if __name__ == '__main__':
@@ -68,7 +78,7 @@ if __name__ == '__main__':
6878
# Check if the update has been applied.
6979
if update in session.xenapi.host.get_updates(host):
7080
print(failure_message(
71-
UPDATE_ALREADY_APPLIED, ['This update has already been applied.']))
81+
UPDATE_ALREADY_APPLIED, [update]))
7282
sys.exit(0)
7383

7484
update_uuid = session.xenapi.pool_update.get_uuid(update)
@@ -82,26 +92,24 @@ if __name__ == '__main__':
8292

8393
if not lock_acquired:
8494
print(failure_message(
85-
OTHER_OPERATION_IN_PROGRESS, ['Another apply operation is in progress.']))
95+
OTHER_OPERATION_IN_PROGRESS, ['Applying the update', update]))
8696
sys.exit(0)
8797

8898
# Run precheck
8999
try:
90100
session.xenapi.pool_update.precheck(update, host)
91101
except Exception as e:
92102
try:
93-
errors = json.loads(str(e))
94-
print(failure_message(errors[0], errors[1:]))
103+
print(failure_message(e.details[0], e.details[1:]))
95104
except:
96-
print(failure_message(PATCH_PRECHECK_FAILED_UNKNOWN_ERROR, [str(e)]))
105+
print(failure_message(UPDATE_PRECHECK_FAILED_UNKNOWN_ERROR, [str(e)]))
97106
sys.exit(0)
98107

99108
update_vdi = session.xenapi.pool_update.get_vdi(update)
100109
try:
101110
update_vdi_uuid = session.xenapi.VDI.get_uuid(update_vdi)
102111
except Exception as e:
103-
print(failure_message(CANNOT_FIND_UPDATE,
104-
['Missing update package [uuid=%s]' % update_uuid]))
112+
print(failure_message(CANNOT_FIND_UPDATE, []))
105113
sys.exit(0)
106114

107115
# Apply the update.
@@ -121,9 +129,10 @@ if __name__ == '__main__':
121129

122130
session.xenapi.pool_update.resync_host(host)
123131
print(success_message())
132+
except InvalidUpdate as e:
133+
print(failure_message(INVALID_UPDATE, [str(e)]))
124134
except Exception as e:
125-
print(failure_message(UPDATE_APPLY_FAILED,
126-
['Failed to apply the update: %s' % e]))
135+
print(failure_message(UPDATE_APPLY_FAILED, [str(e)]))
127136
finally:
128137
session.xenapi.pool_update.detach(update)
129138
try:

scripts/extensions/pool_update.precheck

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import traceback
1010
import subprocess
1111
import os
1212
import errno
13+
import re
1314
import shutil
1415
import StringIO
1516
import ConfigParser
@@ -18,12 +19,35 @@ import xcp.logger
1819

1920

2021
TMP_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'
2228
CANNOT_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

2437
class 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

2852
def 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

Comments
 (0)