blob: 27ffa34b4de5f92726908e7509e56f5b0d311fb0 [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 -050022def verify_no_duplicate_image_priorities(image_purpose):
23
24 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"
43 + 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():
48
49 r"""
50 Get the URI to a BMC image from software that is not running on the BMC.
51 """
52
53 # Get the version of the image currently running on the BMC.
54 _, cur_img_version = keyword.run_key("Get BMC Version")
55 # Remove the surrounding double quotes from the version.
56 cur_img_version = cur_img_version.replace('"', '')
57
58 _, images = keyword.run_key("Read Properties "
59 + var.SOFTWARE_VERSION_URI + "enumerate")
60
61 for image_name in images:
62 _, image_properties = keyword.run_key(
63 "Get Host Software Property " + image_name)
Charles Paul Hofer1e487272017-09-14 12:55:11 -050064 if 'Purpose' in image_properties and 'Version' in image_properties \
65 and image_properties['Purpose'] != var.VERSION_PURPOSE_HOST \
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -050066 and image_properties['Version'] != cur_img_version:
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050067 return image_name
68 BuiltIn().fail("Did not find any non-running BMC images.")
69
Charles Paul Hoferda24d0a2017-08-09 15:03:40 -050070
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050071def delete_all_pnor_images():
72
73 r"""
74 Delete all PNOR images from the BMC.
75 """
76
George Keishing8e984782017-08-30 14:16:18 -050077 status, images = keyword.run_key("Get Software Objects "
78 + var.VERSION_PURPOSE_HOST)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050079 for image_name in images:
George Keishing8e984782017-08-30 14:16:18 -050080 BuiltIn().log_to_console(image_name)
81 # Delete twice, in case the image is in the /tmp/images directory
82 keyword.run_key("Call Method " + image_name
83 + " delete data={\"data\":[]}")
84 keyword.run_key("Call Method " + image_name
85 + " delete data={\"data\":[]}")
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050086
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050087
Charles Paul Hoferde7d4082017-08-08 14:41:01 -050088def wait_for_activation_state_change(version_id, initial_state):
89
90 r"""
91 Wait for the current activation state of ${version_id} to
92 change from the state provided by the calling function.
93
94 Description of argument(s):
95 version_id The version ID whose state change we are waiting for.
96 initial_state The activation state we want to wait for.
97 """
98
99 keyword.run_key_u("Open Connection And Log In")
100 retry = 0
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500101 num_read_errors = 0
102 read_fail_threshold = 1
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500103 while (retry < 30):
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500104 # TODO: Use retry option in run_key when available.
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500105 status, software_state = keyword.run_key("Read Properties " +
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500106 var.SOFTWARE_VERSION_URI + str(version_id),
107 ignore=1)
108 if status == 'FAIL':
109 num_read_errors += 1
110 if num_read_errors > read_fail_threshold:
111 message = "Read errors exceeds threshold:\n " \
112 + gp.sprint_vars(num_read_errors, read_fail_threshold)
113 BuiltIn().fail(message)
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500114 time.sleep(10)
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500115 continue
116
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500117 current_state = (software_state)["Activation"]
118 if (initial_state == current_state):
Charles Paul Hofer4d26c002017-09-27 08:39:29 -0500119 time.sleep(10)
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500120 retry += 1
Charles Paul Hofer290b8bd2017-09-26 10:02:22 -0500121 num_read_errors = 0
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500122 else:
123 return
124 return
125
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500126
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500127def get_latest_file(dir_path):
128
129 r"""
130 Get the path to the latest uploaded file.
131
132 Description of argument(s):
133 dir_path Path to the dir from which the name of the last
134 updated file or folder will be returned to the
135 calling function.
136 """
137
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500138 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500139 status, ret_values =\
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500140 keyword.run_key("Execute Command On BMC cd " + dir_path
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500141 + "; stat -c '%Y %n' * | sort -k1,1nr | head -n 1", ignore=1)
142 return ret_values.split(" ")[-1]
143
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500144
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500145def get_version_tar(tar_file_path):
146
147 r"""
148 Read the image version from the MANIFEST inside the tarball.
149
150 Description of argument(s):
151 tar_file_path The path to a tar file that holds the image
152 version inside the MANIFEST.
153 """
154
155 tar = tarfile.open(tar_file_path)
156 for member in tar.getmembers():
157 f=tar.extractfile(member)
158 content=f.read()
159 if "version=" in content:
160 content = content.split("\n")
161 content = [x for x in content if "version=" in x]
162 version = content[0].split("=")[-1]
163 break
164 tar.close()
165 return version
166
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500167
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500168def get_image_version(file_path):
169
170 r"""
171 Read the file for a version object.
172
173 Description of argument(s):
174 file_path The path to a file that holds the image version.
175 """
176
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500177 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500178 status, ret_values =\
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500179 keyword.run_key("Execute Command On BMC cat "
Saqib Khanbb8b63f2017-05-24 10:58:01 -0500180 + file_path + " | grep \"version=\"", ignore=1)
181 return (ret_values.split("\n")[0]).split("=")[-1]
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500182
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500183
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500184def get_image_purpose(file_path):
185
186 r"""
187 Read the file for a purpose object.
188
189 Description of argument(s):
190 file_path The path to a file that holds the image purpose.
191 """
192
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500193 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500194 status, ret_values =\
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500195 keyword.run_key("Execute Command On BMC cat "
Saqib Khanbb8b63f2017-05-24 10:58:01 -0500196 + file_path + " | grep \"purpose=\"", ignore=1)
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500197 return ret_values.split("=")[-1]
198
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500199
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500200def get_image_path(image_version):
201
202 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):
209 image_version The version of the image that should match one
210 of the images in the upload dir.
211 """
212
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500213 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500214 status, image_list =\
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -0500215 keyword.run_key("Execute Command On BMC ls -d "
216 + var.IMAGE_UPLOAD_DIR_PATH + "*/")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500217
218 image_list = image_list.split("\n")
219 retry = 0
220 while (retry < 10):
221 for i in range(0, len(image_list)):
222 version = get_image_version(image_list[i] + "MANIFEST")
223 if (version == image_version):
224 return image_list[i]
225 time.sleep(10)
226 retry += 1
227
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500228
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -0500229def verify_image_upload(image_version,
230 timeout=3):
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500231
232 r"""
233 Verify the image was uploaded correctly and that it created
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500234 a valid d-bus object. If the first check for the image
235 fails, try again until we reach the timeout.
236
237 Description of argument(s):
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -0500238 image_version The version from the image's manifest file
239 (e.g. "IBM-witherspoon-redbud-ibm-OP9_v1.17_1.68").
240 timeout How long, in minutes, to keep trying to find the
241 image on the BMC. Default is 3 minutes.
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500242 """
243
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500244 image_path = get_image_path(image_version)
245 image_version_id = image_path.split("/")[-2]
246
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500247 keyword.run_key_u("Open Connection And Log In")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500248 image_purpose = get_image_purpose(image_path + "MANIFEST")
Saqib Khanbb8b63f2017-05-24 10:58:01 -0500249 if (image_purpose == var.VERSION_PURPOSE_BMC or
250 image_purpose == var.VERSION_PURPOSE_HOST):
George Keishingff1e3ec2017-07-20 01:58:21 -0500251 uri = var.SOFTWARE_VERSION_URI + image_version_id
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500252 ret_values = ""
253 for itr in range(timeout * 2):
254 status, ret_values = \
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500255 keyword.run_key("Read Attribute " + uri + " Activation")
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500256
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500257 if ((ret_values == var.READY) or (ret_values == var.INVALID)
258 or (ret_values == var.ACTIVE)):
Charles Paul Hofercef61992017-08-18 10:14:18 -0500259 return True, image_version_id
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500260 else:
261 time.sleep(30)
262
263 # If we exit the for loop, the timeout has been reached
264 gp.print_var(ret_values)
Charles Paul Hofercef61992017-08-18 10:14:18 -0500265 return False, None
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500266 else:
Saqib Khanbb8b63f2017-05-24 10:58:01 -0500267 gp.print_var(image_purpose)
Charles Paul Hofercef61992017-08-18 10:14:18 -0500268 return False, None
Saqib Khanfb1f6ae2017-04-26 13:24:41 -0500269
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500270
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500271def verify_image_not_in_bmc_uploads_dir(image_version, timeout=3):
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500272
273 r"""
274 Check that an image with the given version is not unpacked inside of the
275 BMCs image uploads directory. If no image is found, retry every 30 seconds
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500276 until the given timeout is hit, in case the BMC takes time
277 unpacking the image.
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500278
279 Description of argument(s):
280 image_version The version of the image to look for on the BMC.
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500281 timeout How long, in minutes, to try to find an image on the BMC.
282 Default is 3 minutes.
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500283 """
284
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500285 keyword.run_key('Open Connection And Log In')
Charles Paul Hofer6b972682017-07-20 11:36:56 -0500286 for i in range(timeout * 2):
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500287 stat, grep_res = keyword.run_key('Execute Command On BMC '
Charles Paul Hofer9f74d3a2017-08-18 09:54:28 -0500288 + 'ls ' + var.IMAGE_UPLOAD_DIR_PATH + '*/MANIFEST 2>/dev/null '
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500289 + '| xargs grep -rl "version=' + image_version + '"')
290 image_dir = os.path.dirname(grep_res.split('\n')[0])
291 if '' != image_dir:
Charles Paul Hoferde7d4082017-08-08 14:41:01 -0500292 keyword.run_key('Execute Command On BMC rm -rf ' + image_dir)
Charles P. Hofer1d20acd2017-07-05 15:24:40 -0500293 BuiltIn().fail('Found invalid BMC Image: ' + image_dir)
294 time.sleep(30)
295