Support to return logs for hpsum firmware update
This commit adds supports to return the log files for the hpsum based firmware update as gzipped and base64 encoded string. Closes-Bug: #1673037 Change-Id: Ie9f165c75e6b47be29927864cbdf2d8b050ef887
This commit is contained in:
parent
93f6d17bd9
commit
c0ca2d7126
|
@ -14,23 +14,28 @@
|
|||
|
||||
|
||||
import fnmatch
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import tarfile
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_serialization import base64
|
||||
|
||||
from proliantutils import exception
|
||||
from proliantutils.ilo import client
|
||||
from proliantutils import utils
|
||||
|
||||
|
||||
OUTPUT_FILE = '/var/hp/log/localhost/hpsum_log.txt'
|
||||
|
||||
HPSUM_LOCATION = 'hp/swpackages/hpsum'
|
||||
|
||||
# List of log files created by hpsum based firmware update.
|
||||
OUTPUT_FILES = ['/var/hp/log/localhost/hpsum_log.txt',
|
||||
'/var/hp/log/localhost/hpsum_detail_log.txt']
|
||||
|
||||
EXIT_CODE_TO_STRING = {
|
||||
0: "The smart component was installed successfully.",
|
||||
1: ("The smart component was installed successfully, but the system "
|
||||
|
@ -70,6 +75,22 @@ def _execute_hpsum(hpsum_file_path, components=None):
|
|||
raise exception.HpsumOperationError(reason=msg)
|
||||
|
||||
|
||||
def _get_log_file_data_as_encoded_content():
|
||||
"""Gzip and base64 encode files and BytesIO buffers.
|
||||
|
||||
This method gets the log files created by hpsum based
|
||||
firmware update and tar zip the files.
|
||||
:returns: A gzipped and base64 encoded string as text.
|
||||
"""
|
||||
with io.BytesIO() as fp:
|
||||
with tarfile.open(fileobj=fp, mode='w:gz') as tar:
|
||||
for f in OUTPUT_FILES:
|
||||
tar.add(f)
|
||||
|
||||
fp.seek(0)
|
||||
return base64.encode_as_bytes(fp.getvalue())
|
||||
|
||||
|
||||
def _parse_hpsum_ouput(exit_code):
|
||||
"""Parse the hpsum output log file.
|
||||
|
||||
|
@ -88,8 +109,8 @@ def _parse_hpsum_ouput(exit_code):
|
|||
return "Summary: %s" % EXIT_CODE_TO_STRING.get(exit_code)
|
||||
|
||||
if exit_code in (0, 1, 253):
|
||||
if os.path.exists(OUTPUT_FILE):
|
||||
with open(OUTPUT_FILE, 'r') as f:
|
||||
if os.path.exists(OUTPUT_FILES[0]):
|
||||
with open(OUTPUT_FILES[0], 'r') as f:
|
||||
output_data = f.read()
|
||||
|
||||
ret_data = output_data[(output_data.find('Deployed Components:') +
|
||||
|
@ -105,12 +126,15 @@ def _parse_hpsum_ouput(exit_code):
|
|||
else:
|
||||
success += 1
|
||||
|
||||
return ("Summary: %(return_string)s Status of updated components:"
|
||||
" Total: %(total)s Success: %(success)s Failed: "
|
||||
"%(failed)s." %
|
||||
return {
|
||||
'Summary': (
|
||||
"%(return_string)s Status of updated components: Total: "
|
||||
"%(total)s Success: %(success)s Failed: %(failed)s." %
|
||||
{'return_string': EXIT_CODE_TO_STRING.get(exit_code),
|
||||
'total': (success + failed), 'success': success,
|
||||
'failed': failed})
|
||||
'failed': failed}),
|
||||
'Log Data': _get_log_file_data_as_encoded_content()
|
||||
}
|
||||
|
||||
return "UPDATE STATUS: UNKNOWN"
|
||||
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
|
||||
import os
|
||||
import shutil
|
||||
import tarfile
|
||||
import tempfile
|
||||
|
||||
import mock
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_serialization import base64
|
||||
import testtools
|
||||
|
||||
from proliantutils import exception
|
||||
|
@ -43,19 +45,25 @@ class HpsumFirmwareUpdateTest(testtools.TestCase):
|
|||
self.node = {'driver_info': self.info,
|
||||
'clean_step': clean_step}
|
||||
|
||||
@mock.patch.object(hpsum_controller,
|
||||
'_get_log_file_data_as_encoded_content')
|
||||
@mock.patch.object(hpsum_controller, 'open',
|
||||
mock.mock_open(read_data=constants.HPSUM_OUTPUT_DATA))
|
||||
@mock.patch.object(os.path, 'exists')
|
||||
@mock.patch.object(processutils, 'execute')
|
||||
def test_execute_hpsum(self, execute_mock, exists_mock):
|
||||
def test_execute_hpsum(self, execute_mock, exists_mock, log_mock):
|
||||
exists_mock.return_value = True
|
||||
log_mock.return_value = "aaabbbcccdddd"
|
||||
value = ("hpsum_service_x64 started successfully. Sending Shutdown "
|
||||
"request to engine. Successfully shutdown the service.")
|
||||
execute_mock.side_effect = processutils.ProcessExecutionError(
|
||||
stdout=value, stderr=None, exit_code=0)
|
||||
ret_value = ("Summary: The smart component was installed successfully."
|
||||
" Status of updated components: Total: 2 Success: 2 "
|
||||
"Failed: 0.")
|
||||
ret_value = {
|
||||
'Log Data': 'aaabbbcccdddd',
|
||||
'Summary': ("The smart component was installed successfully."
|
||||
" Status of updated components: Total: 2 Success: 2 "
|
||||
"Failed: 0.")
|
||||
}
|
||||
|
||||
stdout = hpsum_controller._execute_hpsum("hpsum", components=None)
|
||||
|
||||
|
@ -78,15 +86,23 @@ class HpsumFirmwareUpdateTest(testtools.TestCase):
|
|||
"hpsum", "--s", "--romonly", " --c foo --c bar")
|
||||
self.assertEqual(ret_value, stdout)
|
||||
|
||||
@mock.patch.object(hpsum_controller,
|
||||
'_get_log_file_data_as_encoded_content')
|
||||
@mock.patch.object(
|
||||
hpsum_controller, 'open',
|
||||
mock.mock_open(read_data=constants.HPSUM_OUTPUT_DATA_FAILURE))
|
||||
@mock.patch.object(os.path, 'exists')
|
||||
@mock.patch.object(processutils, 'execute')
|
||||
def test_execute_hpsum_update_fails(self, execute_mock, exists_mock):
|
||||
def test_execute_hpsum_update_fails(self, execute_mock, exists_mock,
|
||||
log_mock):
|
||||
exists_mock.return_value = True
|
||||
ret = ("Summary: The installation of the component failed. Status "
|
||||
"of updated components: Total: 2 Success: 1 Failed: 1.")
|
||||
log_mock.return_value = "aaabbbcccdddd"
|
||||
ret = {
|
||||
'Log Data': 'aaabbbcccdddd',
|
||||
'Summary': ("The installation of the component failed. Status "
|
||||
"of updated components: Total: 2 Success: 1 "
|
||||
"Failed: 1.")
|
||||
}
|
||||
value = ("hpsum_service_x64 started successfully. Sending Shutdown "
|
||||
"request to engine. Successfully shutdown the service.")
|
||||
execute_mock.side_effect = processutils.ProcessExecutionError(
|
||||
|
@ -111,6 +127,27 @@ class HpsumFirmwareUpdateTest(testtools.TestCase):
|
|||
None)
|
||||
self.assertIn(value, str(ex))
|
||||
|
||||
def test_get_log_file_data_as_encoded_content(self):
|
||||
log_file_content = b'Sample Data for testing hpsum log output'
|
||||
file_object = tempfile.NamedTemporaryFile(delete=False)
|
||||
file_object.write(log_file_content)
|
||||
file_object.close()
|
||||
hpsum_controller.OUTPUT_FILES = [file_object.name]
|
||||
|
||||
base64_encoded_text = (hpsum_controller.
|
||||
_get_log_file_data_as_encoded_content())
|
||||
|
||||
tar_gzipped_content = base64.decode_as_bytes(base64_encoded_text)
|
||||
tar_file = tempfile.NamedTemporaryFile(suffix='.tar.gz', delete=False)
|
||||
tar_file.write(tar_gzipped_content)
|
||||
tar_file.close()
|
||||
|
||||
with tarfile.open(name=tar_file.name) as tar:
|
||||
f = tar.extractfile(file_object.name.lstrip('/'))
|
||||
self.assertEqual(log_file_content, f.read())
|
||||
os.remove(file_object.name)
|
||||
os.remove(tar_file.name)
|
||||
|
||||
@mock.patch.object(utils, 'validate_href')
|
||||
@mock.patch.object(utils, 'verify_image_checksum')
|
||||
@mock.patch.object(hpsum_controller, '_execute_hpsum')
|
||||
|
@ -150,6 +187,19 @@ class HpsumFirmwareUpdateTest(testtools.TestCase):
|
|||
rmtree_mock.assert_called_once_with("/tempdir", ignore_errors=True)
|
||||
self.assertEqual('SUCCESS', ret_val)
|
||||
|
||||
@mock.patch.object(utils, 'validate_href')
|
||||
def test_update_firmware_throws_for_nonexistent_file(self,
|
||||
validate_href_mock):
|
||||
invalid_file_path = '/some/invalid/file/path'
|
||||
value = ("Got HTTP code 503 instead of 200 in response to "
|
||||
"HEAD request.")
|
||||
validate_href_mock.side_effect = exception.ImageRefValidationFailed(
|
||||
reason=value, image_href=invalid_file_path)
|
||||
|
||||
exc = self.assertRaises(exception.HpsumOperationError,
|
||||
hpsum_controller.update_firmware, self.node)
|
||||
self.assertIn(value, str(exc))
|
||||
|
||||
@mock.patch.object(utils, 'validate_href')
|
||||
@mock.patch.object(ilo_client, 'IloClient', spec_set=True, autospec=True)
|
||||
def test_update_firmware_vmedia_attach_fails(self, client_mock,
|
||||
|
@ -219,33 +269,41 @@ class HpsumFirmwareUpdateTest(testtools.TestCase):
|
|||
'CDROM')
|
||||
exists_mock.assert_called_once_with("/dev/disk/by-label/SPP_LABEL")
|
||||
|
||||
@mock.patch.object(hpsum_controller,
|
||||
'_get_log_file_data_as_encoded_content')
|
||||
@mock.patch.object(hpsum_controller, 'open',
|
||||
mock.mock_open(read_data=constants.HPSUM_OUTPUT_DATA))
|
||||
@mock.patch.object(os.path, 'exists')
|
||||
def test__parse_hpsum_ouput(self, exists_mock):
|
||||
def test__parse_hpsum_ouput(self, exists_mock, log_mock):
|
||||
exists_mock.return_value = True
|
||||
expt_ret = ("Summary: The smart component was installed successfully. "
|
||||
"Status of updated components: Total: 2 Success: 2 "
|
||||
"Failed: 0.")
|
||||
log_mock.return_value = "aaabbbcccdddd"
|
||||
expt_ret = {'Log Data': 'aaabbbcccdddd',
|
||||
'Summary': ("The smart component was installed "
|
||||
"successfully. Status of updated components: "
|
||||
"Total: 2 Success: 2 Failed: 0.")}
|
||||
|
||||
ret = hpsum_controller._parse_hpsum_ouput(0)
|
||||
|
||||
exists_mock.assert_called_once_with(hpsum_controller.OUTPUT_FILE)
|
||||
exists_mock.assert_called_once_with(hpsum_controller.OUTPUT_FILES[0])
|
||||
self.assertEqual(expt_ret, ret)
|
||||
|
||||
@mock.patch.object(hpsum_controller,
|
||||
'_get_log_file_data_as_encoded_content')
|
||||
@mock.patch.object(
|
||||
hpsum_controller, 'open',
|
||||
mock.mock_open(read_data=constants.HPSUM_OUTPUT_DATA_FAILURE))
|
||||
@mock.patch.object(os.path, 'exists')
|
||||
def test__parse_hpsum_ouput_some_failed(self, exists_mock):
|
||||
def test__parse_hpsum_ouput_some_failed(self, exists_mock, log_mock):
|
||||
exists_mock.return_value = True
|
||||
expt_ret = ("Summary: The installation of the component failed. "
|
||||
"Status of updated components: Total: 2 Success: 1 "
|
||||
"Failed: 1.")
|
||||
log_mock.return_value = "aaabbbcccdddd"
|
||||
expt_ret = {'Log Data': 'aaabbbcccdddd',
|
||||
'Summary': ("The installation of the component failed. "
|
||||
"Status of updated components: Total: 2 "
|
||||
"Success: 1 Failed: 1.")}
|
||||
|
||||
ret = hpsum_controller._parse_hpsum_ouput(253)
|
||||
|
||||
exists_mock.assert_called_once_with(hpsum_controller.OUTPUT_FILE)
|
||||
exists_mock.assert_called_once_with(hpsum_controller.OUTPUT_FILES[0])
|
||||
self.assertEqual(expt_ret, ret)
|
||||
|
||||
@mock.patch.object(os.path, 'exists')
|
||||
|
@ -255,5 +313,5 @@ class HpsumFirmwareUpdateTest(testtools.TestCase):
|
|||
|
||||
ret = hpsum_controller._parse_hpsum_ouput(1)
|
||||
|
||||
exists_mock.assert_called_once_with(hpsum_controller.OUTPUT_FILE)
|
||||
exists_mock.assert_called_once_with(hpsum_controller.OUTPUT_FILES[0])
|
||||
self.assertEqual(expt_ret, ret)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
pbr>=2.0.0 # Apache-2.0
|
||||
six>=1.9.0 # MIT
|
||||
oslo.concurrency>=3.8.0 # Apache-2.0
|
||||
oslo.serialization>=1.10.0 # Apache-2.0
|
||||
oslo.utils>=3.20.0 # Apache-2.0
|
||||
jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
|
||||
requests!=2.12.2,!=2.13.0,>=2.10.0 # Apache-2.0
|
||||
|
|
Loading…
Reference in New Issue