blob: 9b9fbf7ee9531b845314ca5fdb7bdac420b12de9 [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
12
13robot_pgm_dir_path = os.path.dirname(__file__) + os.sep
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050014repo_data_path = re.sub('/lib', '/data', robot_pgm_dir_path)
Saqib Khanfb1f6ae2017-04-26 13:24:41 -050015sys.path.append(repo_data_path)
16
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050017import gen_robot_keyword as keyword
Saqib Khanfb1f6ae2017-04-26 13:24:41 -050018import gen_print as gp
19import variables as var
20from robot.libraries.BuiltIn import BuiltIn
21
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050022
Gunnar Mills096cd562018-03-26 10:19:12 -050023def verify_no_duplicate_image_priorities(image_purpose):
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050024 r"""
25 Check that there are no active images with the same purpose and priority.
26
27 Description of argument(s):
28 image_purpose The purpose that images must have to be checked for
29 priority duplicates.
30 """
31
32 taken_priorities = {}
33 _, image_names = keyword.run_key("Get Software Objects "
34 + "version_type=" + image_purpose)
35
36 for image_name in image_names:
37 _, image = keyword.run_key("Get Host Software Property " + image_name)
38 if image["Activation"] != var.ACTIVE:
39 continue
40 image_priority = image["Priority"]
41 if image_priority in taken_priorities:
42 BuiltIn().fail("Found active images with the same priority.\n"
Gunnar Mills096cd562018-03-26 10:19:12 -050043 + gp.sprint_vars(image, taken_priorities[image_priority]))
Charles Paul Hofera5673162017-08-30 09:49:16 -050044 taken_priorities[image_priority] = image
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050045
Charles Paul Hoferc1fa2bc2017-08-18 16:44:03 -050046
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050047def get_non_running_bmc_software_object():
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050048 r"""
49 Get the URI to a BMC image from software that is not running on the BMC.
50 """
51
52 # Get the version of the image currently running on the BMC.
53 _, cur_img_version = keyword.run_key("Get BMC Version")
54 # Remove the surrounding double quotes from the version.
55 cur_img_version = cur_img_version.replace('"', '')
56
57 _, images = keyword.run_key("Read Properties "
58 + var.SOFTWARE_VERSION_URI + "enumerate")
59
60 for image_name in images:
61 _, image_properties = keyword.run_key(
Gunnar Mills096cd562018-03-26 10:19:12 -050062 "Get Host Software Property " + image_name)
Charles Paul Hofer1e487272017-09-14 12:55:11 -050063 if 'Purpose' in image_properties and 'Version' in image_properties \
64 and image_properties['Purpose'] != var.VERSION_PURPOSE_HOST \
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -050065 and image_properties['Version'] != cur_img_version:
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050066 return image_name
67 BuiltIn().fail("Did not find any non-running BMC images.")
68
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050069
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050070def delete_all_pnor_images():
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050071 r"""
72 Delete all PNOR images from the BMC.
73 """
74
George Keishing8e984782017-08-30 14:16:18 -050075 status, images = keyword.run_key("Get Software Objects "
76 + var.VERSION_PURPOSE_HOST)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050077 for image_name in images:
George Keishing8e984782017-08-30 14:16:18 -050078 BuiltIn().log_to_console(image_name)
79 # Delete twice, in case the image is in the /tmp/images directory
80 keyword.run_key("Call Method " + image_name
81 + " delete data={\"data\":[]}")
82 keyword.run_key("Call Method " + image_name
83 + " delete data={\"data\":[]}")
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050084
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050085
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050086def wait_for_activation_state_change(version_id, initial_state):
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050087 r"""
88 Wait for the current activation state of ${version_id} to
89 change from the state provided by the calling function.
90
91 Description of argument(s):
92 version_id The version ID whose state change we are waiting for.
93 initial_state The activation state we want to wait for.
94 """
95
96 keyword.run_key_u("Open Connection And Log In")
97 retry = 0
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -050098 num_read_errors = 0
99 read_fail_threshold = 1
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500100 while (retry < 30):
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500101 # TODO: Use retry option in run_key when available.
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500102 status, software_state = keyword.run_key("Read Properties " +
Gunnar Mills096cd562018-03-26 10:19:12 -0500103 var.SOFTWARE_VERSION_URI +
104 str(version_id),
105 ignore=1)
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500106 if status == 'FAIL':
107 num_read_errors += 1
108 if num_read_errors > read_fail_threshold:
109 message = "Read errors exceeds threshold:\n " \
Gunnar Mills096cd562018-03-26 10:19:12 -0500110 + gp.sprint_vars(num_read_errors, read_fail_threshold)
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500111 BuiltIn().fail(message)
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500112 time.sleep(10)
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500113 continue
114
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500115 current_state = (software_state)["Activation"]
116 if (initial_state == current_state):
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500117 time.sleep(10)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500118 retry += 1
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500119 num_read_errors = 0
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500120 else:
121 return
122 return
123
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500124
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500125def get_latest_file(dir_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500126 r"""
127 Get the path to the latest uploaded file.
128
129 Description of argument(s):
130 dir_path Path to the dir from which the name of the last
131 updated file or folder will be returned to the
132 calling function.
133 """
134
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500135 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500136 status, ret_values =\
Gunnar Mills096cd562018-03-26 10:19:12 -0500137 keyword.run_key("Execute Command On BMC cd " + dir_path
138 + "; stat -c '%Y %n' * | sort -k1,1nr | head -n 1", ignore=1)
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500139 return ret_values.split(" ")[-1]
140
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500141
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500142def get_version_tar(tar_file_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500143 r"""
144 Read the image version from the MANIFEST inside the tarball.
145
146 Description of argument(s):
147 tar_file_path The path to a tar file that holds the image
148 version inside the MANIFEST.
149 """
150
151 tar = tarfile.open(tar_file_path)
152 for member in tar.getmembers():
Gunnar Mills096cd562018-03-26 10:19:12 -0500153 f = tar.extractfile(member)
154 content = f.read()
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500155 if "version=" in content:
156 content = content.split("\n")
157 content = [x for x in content if "version=" in x]
158 version = content[0].split("=")[-1]
159 break
160 tar.close()
161 return version
162
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500163
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500164def get_image_version(file_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500165 r"""
166 Read the file for a version object.
167
168 Description of argument(s):
169 file_path The path to a file that holds the image version.
170 """
171
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500172 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500173 status, ret_values =\
Gunnar Mills096cd562018-03-26 10:19:12 -0500174 keyword.run_key("Execute Command On BMC cat "
175 + file_path + " | grep \"version=\"", ignore=1)
Saqib Khanbb8b63f2017-05-24 10:58:01 -0500176 return (ret_values.split("\n")[0]).split("=")[-1]
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500177
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500178
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500179def get_image_purpose(file_path):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500180 r"""
181 Read the file for a purpose object.
182
183 Description of argument(s):
184 file_path The path to a file that holds the image purpose.
185 """
186
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500187 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500188 status, ret_values =\
Gunnar Mills096cd562018-03-26 10:19:12 -0500189 keyword.run_key("Execute Command On BMC cat "
190 + file_path + " | grep \"purpose=\"", ignore=1)
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500191 return ret_values.split("=")[-1]
192
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500193
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500194def get_image_path(image_version):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500195 r"""
196 Query the upload image dir for the presence of image matching
197 the version that was read from the MANIFEST before uploading
198 the image. Based on the purpose verify the activation object
199 exists and is either READY or INVALID.
200
201 Description of argument(s):
202 image_version The version of the image that should match one
203 of the images in the upload dir.
204 """
205
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500206 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500207 status, image_list =\
Gunnar Mills096cd562018-03-26 10:19:12 -0500208 keyword.run_key("Execute Command On BMC ls -d "
209 + var.IMAGE_UPLOAD_DIR_PATH + "*/")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500210
211 image_list = image_list.split("\n")
212 retry = 0
213 while (retry < 10):
214 for i in range(0, len(image_list)):
215 version = get_image_version(image_list[i] + "MANIFEST")
216 if (version == image_version):
217 return image_list[i]
218 time.sleep(10)
219 retry += 1
220
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500221
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -0500222def verify_image_upload(image_version,
223 timeout=3):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500224 r"""
225 Verify the image was uploaded correctly and that it created
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500226 a valid d-bus object. If the first check for the image
227 fails, try again until we reach the timeout.
228
229 Description of argument(s):
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -0500230 image_version The version from the image's manifest file
231 (e.g. "IBM-witherspoon-redbud-ibm-OP9_v1.17_1.68").
232 timeout How long, in minutes, to keep trying to find the
233 image on the BMC. Default is 3 minutes.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500234 """
235
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500236 image_path = get_image_path(image_version)
237 image_version_id = image_path.split("/")[-2]
238
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500239 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500240 image_purpose = get_image_purpose(image_path + "MANIFEST")
Saqib Khanbb8b63f2017-05-24 10:58:01 -0500241 if (image_purpose == var.VERSION_PURPOSE_BMC or
Gunnar Mills096cd562018-03-26 10:19:12 -0500242 image_purpose == var.VERSION_PURPOSE_HOST):
George Keishingff1e3ec2017-07-20 01:58:21 -0500243 uri = var.SOFTWARE_VERSION_URI + image_version_id
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500244 ret_values = ""
245 for itr in range(timeout * 2):
246 status, ret_values = \
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500247 keyword.run_key("Read Attribute " + uri + " Activation")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500248
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500249 if ((ret_values == var.READY) or (ret_values == var.INVALID)
250 or (ret_values == var.ACTIVE)):
Charles Paul Hofercef61992017-08-18 10:14:18 -0500251 return True, image_version_id
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500252 else:
253 time.sleep(30)
254
255 # If we exit the for loop, the timeout has been reached
256 gp.print_var(ret_values)
Charles Paul Hofercef61992017-08-18 10:14:18 -0500257 return False, None
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500258 else:
Saqib Khanbb8b63f2017-05-24 10:58:01 -0500259 gp.print_var(image_purpose)
Charles Paul Hofercef61992017-08-18 10:14:18 -0500260 return False, None
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500261
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500262
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500263def verify_image_not_in_bmc_uploads_dir(image_version, timeout=3):
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500264 r"""
265 Check that an image with the given version is not unpacked inside of the
266 BMCs image uploads directory. If no image is found, retry every 30 seconds
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500267 until the given timeout is hit, in case the BMC takes time
268 unpacking the image.
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500269
270 Description of argument(s):
271 image_version The version of the image to look for on the BMC.
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500272 timeout How long, in minutes, to try to find an image on the BMC.
273 Default is 3 minutes.
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500274 """
275
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500276 keyword.run_key('Open Connection And Log In')
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500277 for i in range(timeout * 2):
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500278 stat, grep_res = keyword.run_key('Execute Command On BMC '
Gunnar Mills096cd562018-03-26 10:19:12 -0500279 + 'ls ' + var.IMAGE_UPLOAD_DIR_PATH + '*/MANIFEST 2>/dev/null '
280 + '| xargs grep -rl "version=' + image_version + '"')
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500281 image_dir = os.path.dirname(grep_res.split('\n')[0])
282 if '' != image_dir:
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500283 keyword.run_key('Execute Command On BMC rm -rf ' + image_dir)
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500284 BuiltIn().fail('Found invalid BMC Image: ' + image_dir)
285 time.sleep(30)