blob: e8ee562537a8a8f4aa47b06a84ca7175817e04e0 [file] [log] [blame]
George Keishinge7e91712021-09-03 11:28:44 -05001#!/usr/bin/env python3
Saqib Khanfb1f6ae2017-04-26 13:24:41 -05002
3r"""
Charles Paul Hoferde7d4082017-08-08 14:41:01 -05004This module provides utilities for code updates.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -05005"""
6
7import os
Saqib Khanfb1f6ae2017-04-26 13:24:41 -05008import re
Charles Paul Hoferde7d4082017-08-08 14:41:01 -05009import sys
Saqib Khanfb1f6ae2017-04-26 13:24:41 -050010import tarfile
11import time
George Keishinge635ddc2022-12-08 07:38:02 -060012import collections
George Keishing37c58c82022-12-08 07:42:54 -060013from robot.libraries.BuiltIn import BuiltIn
Saqib Khanfb1f6ae2017-04-26 13:24:41 -050014
15robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
George Keishinge635ddc2022-12-08 07:38:02 -060016repo_data_path = re.sub('/lib', '/data', robot_pgm_dir_path)
Saqib Khanfb1f6ae2017-04-26 13:24:41 -050017sys.path.append(repo_data_path)
18
George Keishing37c58c82022-12-08 07:42:54 -060019import bmc_ssh_utils as bsu
20import gen_robot_keyword as keyword
21import gen_print as gp
22import variables as var
23from robot.libraries.BuiltIn import BuiltIn
24
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050025
Sushil Singh8469a482020-07-30 04:19:10 -050026def get_bmc_firmware(image_type, sw_dict):
27 r"""
28 Get the dictionary of image based on image type like either BMC or Host.
29
30 Description of argument(s):
31 image_type This value is either BMC update or Host update type.
George Keishing16b3c7b2021-01-28 09:23:37 -060032 sw_dict This contain dictionary of firmware inventory properties.
Sushil Singh8469a482020-07-30 04:19:10 -050033 """
34
35 temp_dict = collections.OrderedDict()
36 for key, value in sw_dict.items():
George Keishinge635ddc2022-12-08 07:38:02 -060037 if value['image_type'] == image_type:
Sushil Singh8469a482020-07-30 04:19:10 -050038 temp_dict[key] = value
39 else:
40 pass
41 return temp_dict
42
43
Gunnar Mills096cd562018-03-26 10:19:12 -050044def verify_no_duplicate_image_priorities(image_purpose):
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050045 r"""
46 Check that there are no active images with the same purpose and priority.
47
48 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050049 image_purpose The purpose that images must have to be
50 checked for priority duplicates.
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050051 """
52
53 taken_priorities = {}
George Keishinge635ddc2022-12-08 07:38:02 -060054 _, image_names = keyword.run_key("Get Software Objects "
55 + "version_type=" + image_purpose)
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050056
57 for image_name in image_names:
58 _, image = keyword.run_key("Get Host Software Property " + image_name)
59 if image["Activation"] != var.ACTIVE:
60 continue
61 image_priority = image["Priority"]
62 if image_priority in taken_priorities:
George Keishinge635ddc2022-12-08 07:38:02 -060063 BuiltIn().fail("Found active images with the same priority.\n"
64 + gp.sprint_vars(image,
65 taken_priorities[image_priority]))
Charles Paul Hofera5673162017-08-30 09:49:16 -050066 taken_priorities[image_priority] = image
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050067
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050068
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050069def get_non_running_bmc_software_object():
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050070 r"""
71 Get the URI to a BMC image from software that is not running on the BMC.
72 """
73
74 # Get the version of the image currently running on the BMC.
75 _, cur_img_version = keyword.run_key("Get BMC Version")
76 # Remove the surrounding double quotes from the version.
George Keishinge635ddc2022-12-08 07:38:02 -060077 cur_img_version = cur_img_version.replace('"', '')
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050078
George Keishinge635ddc2022-12-08 07:38:02 -060079 _, images = keyword.run_key("Read Properties "
80 + var.SOFTWARE_VERSION_URI + "enumerate")
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050081
82 for image_name in images:
83 _, image_properties = keyword.run_key(
George Keishinge635ddc2022-12-08 07:38:02 -060084 "Get Host Software Property " + image_name)
85 if 'Purpose' in image_properties and 'Version' in image_properties \
86 and image_properties['Purpose'] != var.VERSION_PURPOSE_HOST \
87 and image_properties['Version'] != cur_img_version:
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050088 return image_name
89 BuiltIn().fail("Did not find any non-running BMC images.")
90
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050091
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050092def delete_all_pnor_images():
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050093 r"""
94 Delete all PNOR images from the BMC.
95 """
96
Adriana Kobylak7eedb1d2019-08-12 15:24:23 -050097 keyword.run_key("Initiate Host PowerOff")
98
George Keishinge635ddc2022-12-08 07:38:02 -060099 status, images = keyword.run_key("Get Software Objects "
100 + var.VERSION_PURPOSE_HOST)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500101 for image_name in images:
George Keishinge635ddc2022-12-08 07:38:02 -0600102 keyword.run_key("Delete Image And Verify " + image_name + " "
103 + var.VERSION_PURPOSE_HOST)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500104
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500105
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500106def wait_for_activation_state_change(version_id, initial_state):
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500107 r"""
108 Wait for the current activation state of ${version_id} to
109 change from the state provided by the calling function.
110
111 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500112 version_id The version ID whose state change we are
113 waiting for.
114 initial_state The activation state we want to wait for.
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500115 """
116
117 keyword.run_key_u("Open Connection And Log In")
118 retry = 0
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500119 num_read_errors = 0
120 read_fail_threshold = 1
George Keishinge635ddc2022-12-08 07:38:02 -0600121 while (retry < 60):
122 status, software_state = keyword.run_key("Read Properties "
123 + var.SOFTWARE_VERSION_URI
124 + str(version_id),
125 ignore=1)
126 if status == 'FAIL':
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500127 num_read_errors += 1
128 if num_read_errors > read_fail_threshold:
George Keishinge635ddc2022-12-08 07:38:02 -0600129 message = "Read errors exceeds threshold:\n " \
130 + gp.sprint_vars(num_read_errors, read_fail_threshold)
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500131 BuiltIn().fail(message)
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500132 time.sleep(10)
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500133 continue
134
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500135 current_state = (software_state)["Activation"]
George Keishinge635ddc2022-12-08 07:38:02 -0600136 if (initial_state == current_state):
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500137 time.sleep(10)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500138 retry += 1
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500139 num_read_errors = 0
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500140 else:
141 return
142 return
143
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500144
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500145def get_latest_file(dir_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500146 r"""
147 Get the path to the latest uploaded file.
148
149 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500150 dir_path Path to the dir from which the name of the
151 last updated file or folder will be
152 returned to the calling function.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500153 """
154
George Keishinge635ddc2022-12-08 07:38:02 -0600155 stdout, stderr, rc = \
156 bsu.bmc_execute_command("cd " + dir_path
157 + "; stat -c '%Y %n' * |"
158 + " sort -k1,1nr | head -n 1")
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500159 return stdout.split(" ")[-1]
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500160
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500161
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500162def get_version_tar(tar_file_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500163 r"""
164 Read the image version from the MANIFEST inside the tarball.
165
166 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500167 tar_file_path The path to a tar file that holds the image
168 version inside the MANIFEST.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500169 """
170
Sushil Singh3c77d782019-10-14 05:29:42 -0500171 version = ""
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500172 tar = tarfile.open(tar_file_path)
173 for member in tar.getmembers():
George Keishing42ade542020-07-22 09:51:46 -0500174 BuiltIn().log_to_console(member.name)
175 if member.name != "MANIFEST":
176 continue
Gunnar Mills096cd562018-03-26 10:19:12 -0500177 f = tar.extractfile(member)
178 content = f.read()
George Keishing36efbc02018-12-12 10:18:23 -0600179 if content.find(b"version=") == -1:
180 # This tar member does not contain the version.
181 continue
George Keishing42ade542020-07-22 09:51:46 -0500182 content = content.decode("utf-8", "ignore").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600183 content = [x for x in content if "version=" in x]
184 version = content[0].split("=")[-1]
185 break
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500186 tar.close()
187 return version
188
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500189
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500190def get_image_version(file_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500191 r"""
192 Read the file for a version object.
193
194 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500195 file_path The path to a file that holds the image
196 version.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500197 """
198
George Keishinge635ddc2022-12-08 07:38:02 -0600199 stdout, stderr, rc = \
200 bsu.bmc_execute_command("cat " + file_path
201 + " | grep \"version=\"", ignore_err=1)
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500202 return (stdout.split("\n")[0]).split("=")[-1]
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500203
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500204
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500205def get_image_purpose(file_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500206 r"""
207 Read the file for a purpose object.
208
209 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500210 file_path The path to a file that holds the image
211 purpose.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500212 """
213
George Keishinge635ddc2022-12-08 07:38:02 -0600214 stdout, stderr, rc = \
215 bsu.bmc_execute_command("cat " + file_path
216 + " | grep \"purpose=\"", ignore_err=1)
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500217 return stdout.split("=")[-1]
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500218
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500219
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500220def get_image_path(image_version):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500221 r"""
222 Query the upload image dir for the presence of image matching
223 the version that was read from the MANIFEST before uploading
224 the image. Based on the purpose verify the activation object
225 exists and is either READY or INVALID.
226
227 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500228 image_version The version of the image that should match
229 one of the images in the upload dir.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500230 """
231
George Keishinge635ddc2022-12-08 07:38:02 -0600232 stdout, stderr, rc = \
233 bsu.bmc_execute_command("ls -d " + var.IMAGE_UPLOAD_DIR_PATH + "*/")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500234
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500235 image_list = stdout.split("\n")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500236 retry = 0
George Keishinge635ddc2022-12-08 07:38:02 -0600237 while (retry < 10):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500238 for i in range(0, len(image_list)):
239 version = get_image_version(image_list[i] + "MANIFEST")
George Keishinge635ddc2022-12-08 07:38:02 -0600240 if (version == image_version):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500241 return image_list[i]
242 time.sleep(10)
243 retry += 1
244
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500245
George Keishinge635ddc2022-12-08 07:38:02 -0600246def verify_image_upload(image_version,
247 timeout=3):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500248 r"""
249 Verify the image was uploaded correctly and that it created
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500250 a valid d-bus object. If the first check for the image
251 fails, try again until we reach the timeout.
252
253 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500254 image_version The version from the image's manifest file
255 (e.g. "v2.2-253-g00050f1").
256 timeout How long, in minutes, to keep trying to
257 find the image on the BMC. Default is 3 minutes.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500258 """
259
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500260 image_path = get_image_path(image_version)
261 image_version_id = image_path.split("/")[-2]
262
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500263 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500264 image_purpose = get_image_purpose(image_path + "MANIFEST")
George Keishinge635ddc2022-12-08 07:38:02 -0600265 if (image_purpose == var.VERSION_PURPOSE_BMC
266 or image_purpose == var.VERSION_PURPOSE_HOST):
George Keishingff1e3ec2017-07-20 01:58:21 -0500267 uri = var.SOFTWARE_VERSION_URI + image_version_id
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500268 ret_values = ""
269 for itr in range(timeout * 2):
George Keishinge635ddc2022-12-08 07:38:02 -0600270 status, ret_values = \
271 keyword.run_key("Read Attribute " + uri + " Activation")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500272
George Keishinge635ddc2022-12-08 07:38:02 -0600273 if ((ret_values == var.READY) or (ret_values == var.INVALID)
274 or (ret_values == var.ACTIVE)):
Charles Paul Hofercef61992017-08-18 10:14:18 -0500275 return True, image_version_id
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500276 else:
277 time.sleep(30)
278
279 # If we exit the for loop, the timeout has been reached
280 gp.print_var(ret_values)
Charles Paul Hofercef61992017-08-18 10:14:18 -0500281 return False, None
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500282 else:
Saqib Khanbb8b63f2017-05-24 10:58:01 -0500283 gp.print_var(image_purpose)
Charles Paul Hofercef61992017-08-18 10:14:18 -0500284 return False, None
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500285
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500286
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500287def verify_image_not_in_bmc_uploads_dir(image_version, timeout=3):
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500288 r"""
289 Check that an image with the given version is not unpacked inside of the
290 BMCs image uploads directory. If no image is found, retry every 30 seconds
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500291 until the given timeout is hit, in case the BMC takes time
292 unpacking the image.
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500293
294 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500295 image_version The version of the image to look for on
296 the BMC.
297 timeout How long, in minutes, to try to find an
298 image on the BMC. Default is 3 minutes.
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500299 """
300
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500301 for i in range(timeout * 2):
George Keishinge635ddc2022-12-08 07:38:02 -0600302 stdout, stderr, rc = \
303 bsu.bmc_execute_command('ls ' + var.IMAGE_UPLOAD_DIR_PATH
304 + '*/MANIFEST 2>/dev/null '
305 + '| xargs grep -rl "version='
306 + image_version + '"')
307 image_dir = os.path.dirname(stdout.split('\n')[0])
308 if '' != image_dir:
309 bsu.bmc_execute_command('rm -rf ' + image_dir)
310 BuiltIn().fail('Found invalid BMC Image: ' + image_dir)
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500311 time.sleep(30)