blob: ac1efc952928f1516cd33a1d87a1de451455edd1 [file] [log] [blame]
Saqib Khanfb1f6ae2017-04-26 13:24:41 -05001#!/usr/bin/env python
2
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 Keishing42ade542020-07-22 09:51:46 -050012from robot.libraries.BuiltIn import BuiltIn
Saqib Khanfb1f6ae2017-04-26 13:24:41 -050013
14robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050015repo_data_path = re.sub('/lib', '/data', robot_pgm_dir_path)
Saqib Khanfb1f6ae2017-04-26 13:24:41 -050016sys.path.append(repo_data_path)
17
Joy Onyerikwu9b668972018-05-22 19:10:43 -050018import bmc_ssh_utils as bsu
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050019import gen_robot_keyword as keyword
Saqib Khanfb1f6ae2017-04-26 13:24:41 -050020import gen_print as gp
21import variables as var
22from robot.libraries.BuiltIn import BuiltIn
23
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050024
Gunnar Mills096cd562018-03-26 10:19:12 -050025def verify_no_duplicate_image_priorities(image_purpose):
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050026 r"""
27 Check that there are no active images with the same purpose and priority.
28
29 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050030 image_purpose The purpose that images must have to be
31 checked for priority duplicates.
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050032 """
33
34 taken_priorities = {}
35 _, image_names = keyword.run_key("Get Software Objects "
36 + "version_type=" + image_purpose)
37
38 for image_name in image_names:
39 _, image = keyword.run_key("Get Host Software Property " + image_name)
40 if image["Activation"] != var.ACTIVE:
41 continue
42 image_priority = image["Priority"]
43 if image_priority in taken_priorities:
44 BuiltIn().fail("Found active images with the same priority.\n"
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050045 + gp.sprint_vars(image,
46 taken_priorities[image_priority]))
Charles Paul Hofera5673162017-08-30 09:49:16 -050047 taken_priorities[image_priority] = image
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050048
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050049
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050050def get_non_running_bmc_software_object():
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050051 r"""
52 Get the URI to a BMC image from software that is not running on the BMC.
53 """
54
55 # Get the version of the image currently running on the BMC.
56 _, cur_img_version = keyword.run_key("Get BMC Version")
57 # Remove the surrounding double quotes from the version.
58 cur_img_version = cur_img_version.replace('"', '')
59
60 _, images = keyword.run_key("Read Properties "
61 + var.SOFTWARE_VERSION_URI + "enumerate")
62
63 for image_name in images:
64 _, image_properties = keyword.run_key(
Gunnar Mills096cd562018-03-26 10:19:12 -050065 "Get Host Software Property " + image_name)
Charles Paul Hofer1e487272017-09-14 12:55:11 -050066 if 'Purpose' in image_properties and 'Version' in image_properties \
67 and image_properties['Purpose'] != var.VERSION_PURPOSE_HOST \
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -050068 and image_properties['Version'] != cur_img_version:
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050069 return image_name
70 BuiltIn().fail("Did not find any non-running BMC images.")
71
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050072
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050073def delete_all_pnor_images():
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050074 r"""
75 Delete all PNOR images from the BMC.
76 """
77
Adriana Kobylak7eedb1d2019-08-12 15:24:23 -050078 keyword.run_key("Initiate Host PowerOff")
79
George Keishing8e984782017-08-30 14:16:18 -050080 status, images = keyword.run_key("Get Software Objects "
81 + var.VERSION_PURPOSE_HOST)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050082 for image_name in images:
Adriana Kobylak7eedb1d2019-08-12 15:24:23 -050083 keyword.run_key("Delete Image And Verify " + image_name + " "
84 + var.VERSION_PURPOSE_HOST)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050085
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050086
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050087def wait_for_activation_state_change(version_id, initial_state):
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050088 r"""
89 Wait for the current activation state of ${version_id} to
90 change from the state provided by the calling function.
91
92 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050093 version_id The version ID whose state change we are
94 waiting for.
95 initial_state The activation state we want to wait for.
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050096 """
97
98 keyword.run_key_u("Open Connection And Log In")
99 retry = 0
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500100 num_read_errors = 0
101 read_fail_threshold = 1
George Keishing532f6c42018-11-27 09:01:57 -0600102 while (retry < 60):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500103 status, software_state = keyword.run_key("Read Properties "
104 + var.SOFTWARE_VERSION_URI
105 + str(version_id),
Gunnar Mills096cd562018-03-26 10:19:12 -0500106 ignore=1)
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500107 if status == 'FAIL':
108 num_read_errors += 1
109 if num_read_errors > read_fail_threshold:
110 message = "Read errors exceeds threshold:\n " \
Gunnar Mills096cd562018-03-26 10:19:12 -0500111 + gp.sprint_vars(num_read_errors, read_fail_threshold)
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500112 BuiltIn().fail(message)
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500113 time.sleep(10)
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500114 continue
115
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500116 current_state = (software_state)["Activation"]
117 if (initial_state == current_state):
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500118 time.sleep(10)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500119 retry += 1
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500120 num_read_errors = 0
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500121 else:
122 return
123 return
124
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500125
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500126def get_latest_file(dir_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500127 r"""
128 Get the path to the latest uploaded file.
129
130 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500131 dir_path Path to the dir from which the name of the
132 last updated file or folder will be
133 returned to the calling function.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500134 """
135
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500136 stdout, stderr, rc = \
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500137 bsu.bmc_execute_command("cd " + dir_path
138 + "; stat -c '%Y %n' * |"
139 + " sort -k1,1nr | head -n 1")
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500140 return stdout.split(" ")[-1]
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500141
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500142
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500143def get_version_tar(tar_file_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500144 r"""
145 Read the image version from the MANIFEST inside the tarball.
146
147 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500148 tar_file_path The path to a tar file that holds the image
149 version inside the MANIFEST.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500150 """
151
Sushil Singh3c77d782019-10-14 05:29:42 -0500152 version = ""
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500153 tar = tarfile.open(tar_file_path)
154 for member in tar.getmembers():
George Keishing42ade542020-07-22 09:51:46 -0500155 BuiltIn().log_to_console(member.name)
156 if member.name != "MANIFEST":
157 continue
Gunnar Mills096cd562018-03-26 10:19:12 -0500158 f = tar.extractfile(member)
159 content = f.read()
George Keishing36efbc02018-12-12 10:18:23 -0600160 if content.find(b"version=") == -1:
161 # This tar member does not contain the version.
162 continue
George Keishing42ade542020-07-22 09:51:46 -0500163 content = content.decode("utf-8", "ignore").split("\n")
George Keishing36efbc02018-12-12 10:18:23 -0600164 content = [x for x in content if "version=" in x]
165 version = content[0].split("=")[-1]
166 break
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500167 tar.close()
168 return version
169
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500170
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500171def get_image_version(file_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500172 r"""
173 Read the file for a version object.
174
175 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500176 file_path The path to a file that holds the image
177 version.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500178 """
179
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500180 stdout, stderr, rc = \
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500181 bsu.bmc_execute_command("cat " + file_path
182 + " | grep \"version=\"", ignore_err=1)
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500183 return (stdout.split("\n")[0]).split("=")[-1]
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500184
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500185
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500186def get_image_purpose(file_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500187 r"""
188 Read the file for a purpose object.
189
190 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500191 file_path The path to a file that holds the image
192 purpose.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500193 """
194
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500195 stdout, stderr, rc = \
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500196 bsu.bmc_execute_command("cat " + file_path
197 + " | grep \"purpose=\"", ignore_err=1)
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500198 return stdout.split("=")[-1]
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500199
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500200
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500201def get_image_path(image_version):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500202 r"""
203 Query the upload image dir for the presence of image matching
204 the version that was read from the MANIFEST before uploading
205 the image. Based on the purpose verify the activation object
206 exists and is either READY or INVALID.
207
208 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500209 image_version The version of the image that should match
210 one of the images in the upload dir.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500211 """
212
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500213 stdout, stderr, rc = \
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500214 bsu.bmc_execute_command("ls -d " + var.IMAGE_UPLOAD_DIR_PATH + "*/")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500215
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500216 image_list = stdout.split("\n")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500217 retry = 0
218 while (retry < 10):
219 for i in range(0, len(image_list)):
220 version = get_image_version(image_list[i] + "MANIFEST")
221 if (version == image_version):
222 return image_list[i]
223 time.sleep(10)
224 retry += 1
225
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500226
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -0500227def verify_image_upload(image_version,
228 timeout=3):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500229 r"""
230 Verify the image was uploaded correctly and that it created
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500231 a valid d-bus object. If the first check for the image
232 fails, try again until we reach the timeout.
233
234 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500235 image_version The version from the image's manifest file
236 (e.g. "v2.2-253-g00050f1").
237 timeout How long, in minutes, to keep trying to
238 find the image on the BMC. Default is 3 minutes.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500239 """
240
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500241 image_path = get_image_path(image_version)
242 image_version_id = image_path.split("/")[-2]
243
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500244 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500245 image_purpose = get_image_purpose(image_path + "MANIFEST")
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500246 if (image_purpose == var.VERSION_PURPOSE_BMC
247 or image_purpose == var.VERSION_PURPOSE_HOST):
George Keishingff1e3ec2017-07-20 01:58:21 -0500248 uri = var.SOFTWARE_VERSION_URI + image_version_id
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500249 ret_values = ""
250 for itr in range(timeout * 2):
251 status, ret_values = \
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500252 keyword.run_key("Read Attribute " + uri + " Activation")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500253
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500254 if ((ret_values == var.READY) or (ret_values == var.INVALID)
255 or (ret_values == var.ACTIVE)):
Charles Paul Hofercef61992017-08-18 10:14:18 -0500256 return True, image_version_id
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500257 else:
258 time.sleep(30)
259
260 # If we exit the for loop, the timeout has been reached
261 gp.print_var(ret_values)
Charles Paul Hofercef61992017-08-18 10:14:18 -0500262 return False, None
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500263 else:
Saqib Khanbb8b63f2017-05-24 10:58:01 -0500264 gp.print_var(image_purpose)
Charles Paul Hofercef61992017-08-18 10:14:18 -0500265 return False, None
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500266
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500267
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500268def verify_image_not_in_bmc_uploads_dir(image_version, timeout=3):
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500269 r"""
270 Check that an image with the given version is not unpacked inside of the
271 BMCs image uploads directory. If no image is found, retry every 30 seconds
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500272 until the given timeout is hit, in case the BMC takes time
273 unpacking the image.
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500274
275 Description of argument(s):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500276 image_version The version of the image to look for on
277 the BMC.
278 timeout How long, in minutes, to try to find an
279 image on the BMC. Default is 3 minutes.
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500280 """
281
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500282 for i in range(timeout * 2):
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500283 stdout, stderr, rc = \
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500284 bsu.bmc_execute_command('ls ' + var.IMAGE_UPLOAD_DIR_PATH
285 + '*/MANIFEST 2>/dev/null '
286 + '| xargs grep -rl "version='
287 + image_version + '"')
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500288 image_dir = os.path.dirname(stdout.split('\n')[0])
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500289 if '' != image_dir:
Joy Onyerikwu9b668972018-05-22 19:10:43 -0500290 bsu.bmc_execute_command('rm -rf ' + image_dir)
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500291 BuiltIn().fail('Found invalid BMC Image: ' + image_dir)
292 time.sleep(30)