1#!/usr/bin/env python 2 3r""" 4This module provides utilities for code updates. 5""" 6 7import os 8import re 9import sys 10import tarfile 11import time 12 13robot_pgm_dir_path = os.path.dirname(__file__) + os.sep 14repo_data_path = re.sub('/lib', '/data', robot_pgm_dir_path) 15sys.path.append(repo_data_path) 16 17import gen_robot_keyword as keyword 18import gen_print as gp 19import variables as var 20from robot.libraries.BuiltIn import BuiltIn 21 22############################################################################### 23def verify_no_duplicate_image_priorities(image_purpose): 24 25 r""" 26 Check that there are no active images with the same purpose and priority. 27 28 Description of argument(s): 29 image_purpose The purpose that images must have to be checked for 30 priority duplicates. 31 """ 32 33 taken_priorities = {} 34 _, image_names = keyword.run_key("Get Software Objects " 35 + "version_type=" + image_purpose) 36 37 for image_name in image_names: 38 _, image = keyword.run_key("Get Host Software Property " + image_name) 39 if image["Activation"] != var.ACTIVE: 40 continue 41 image_priority = image["Priority"] 42 if image_priority in taken_priorities: 43 BuiltIn().fail("Found active images with the same priority.\n" 44 + gp.sprint_vars(image, taken_priorities[image_priority])) 45 taken_priorities[image_priority] = image 46 47############################################################################### 48 49 50############################################################################### 51def get_non_running_bmc_software_object(): 52 53 r""" 54 Get the URI to a BMC image from software that is not running on the BMC. 55 """ 56 57 # Get the version of the image currently running on the BMC. 58 _, cur_img_version = keyword.run_key("Get BMC Version") 59 # Remove the surrounding double quotes from the version. 60 cur_img_version = cur_img_version.replace('"', '') 61 62 _, images = keyword.run_key("Read Properties " 63 + var.SOFTWARE_VERSION_URI + "enumerate") 64 65 for image_name in images: 66 _, image_properties = keyword.run_key( 67 "Get Host Software Property " + image_name) 68 if 'Purpose' in image_properties and 'Version' in image_properties \ 69 and image_properties['Purpose'] != var.VERSION_PURPOSE_HOST \ 70 and image_properties['Version'] != cur_img_version: 71 return image_name 72 BuiltIn().fail("Did not find any non-running BMC images.") 73 74############################################################################### 75 76 77############################################################################### 78def delete_all_pnor_images(): 79 80 r""" 81 Delete all PNOR images from the BMC. 82 """ 83 84 status, images = keyword.run_key("Get Software Objects " 85 + var.VERSION_PURPOSE_HOST) 86 for image_name in images: 87 BuiltIn().log_to_console(image_name) 88 # Delete twice, in case the image is in the /tmp/images directory 89 keyword.run_key("Call Method " + image_name 90 + " delete data={\"data\":[]}") 91 keyword.run_key("Call Method " + image_name 92 + " delete data={\"data\":[]}") 93 94############################################################################### 95 96 97############################################################################### 98def wait_for_activation_state_change(version_id, initial_state): 99 100 r""" 101 Wait for the current activation state of ${version_id} to 102 change from the state provided by the calling function. 103 104 Description of argument(s): 105 version_id The version ID whose state change we are waiting for. 106 initial_state The activation state we want to wait for. 107 """ 108 109 keyword.run_key_u("Open Connection And Log In") 110 retry = 0 111 num_read_errors = 0 112 read_fail_threshold = 1 113 while (retry < 30): 114 # TODO: Use retry option in run_key when available. 115 status, software_state = keyword.run_key("Read Properties " + 116 var.SOFTWARE_VERSION_URI + str(version_id), 117 ignore=1) 118 if status == 'FAIL': 119 num_read_errors += 1 120 if num_read_errors > read_fail_threshold: 121 message = "Read errors exceeds threshold:\n " \ 122 + gp.sprint_vars(num_read_errors, read_fail_threshold) 123 BuiltIn().fail(message) 124 time.sleep(10) 125 continue 126 127 current_state = (software_state)["Activation"] 128 if (initial_state == current_state): 129 time.sleep(10) 130 retry += 1 131 num_read_errors = 0 132 else: 133 return 134 return 135 136############################################################################### 137 138 139############################################################################### 140def get_latest_file(dir_path): 141 142 r""" 143 Get the path to the latest uploaded file. 144 145 Description of argument(s): 146 dir_path Path to the dir from which the name of the last 147 updated file or folder will be returned to the 148 calling function. 149 """ 150 151 keyword.run_key_u("Open Connection And Log In") 152 status, ret_values =\ 153 keyword.run_key("Execute Command On BMC cd " + dir_path 154 + "; stat -c '%Y %n' * | sort -k1,1nr | head -n 1", ignore=1) 155 return ret_values.split(" ")[-1] 156 157############################################################################### 158 159 160############################################################################### 161def get_version_tar(tar_file_path): 162 163 r""" 164 Read the image version from the MANIFEST inside the tarball. 165 166 Description of argument(s): 167 tar_file_path The path to a tar file that holds the image 168 version inside the MANIFEST. 169 """ 170 171 tar = tarfile.open(tar_file_path) 172 for member in tar.getmembers(): 173 f=tar.extractfile(member) 174 content=f.read() 175 if "version=" in content: 176 content = content.split("\n") 177 content = [x for x in content if "version=" in x] 178 version = content[0].split("=")[-1] 179 break 180 tar.close() 181 return version 182 183############################################################################### 184 185 186############################################################################### 187def get_image_version(file_path): 188 189 r""" 190 Read the file for a version object. 191 192 Description of argument(s): 193 file_path The path to a file that holds the image version. 194 """ 195 196 keyword.run_key_u("Open Connection And Log In") 197 status, ret_values =\ 198 keyword.run_key("Execute Command On BMC cat " 199 + file_path + " | grep \"version=\"", ignore=1) 200 return (ret_values.split("\n")[0]).split("=")[-1] 201 202############################################################################### 203 204 205############################################################################### 206def get_image_purpose(file_path): 207 208 r""" 209 Read the file for a purpose object. 210 211 Description of argument(s): 212 file_path The path to a file that holds the image purpose. 213 """ 214 215 keyword.run_key_u("Open Connection And Log In") 216 status, ret_values =\ 217 keyword.run_key("Execute Command On BMC cat " 218 + file_path + " | grep \"purpose=\"", ignore=1) 219 return ret_values.split("=")[-1] 220 221############################################################################### 222 223 224############################################################################### 225def get_image_path(image_version): 226 227 r""" 228 Query the upload image dir for the presence of image matching 229 the version that was read from the MANIFEST before uploading 230 the image. Based on the purpose verify the activation object 231 exists and is either READY or INVALID. 232 233 Description of argument(s): 234 image_version The version of the image that should match one 235 of the images in the upload dir. 236 """ 237 238 keyword.run_key_u("Open Connection And Log In") 239 status, image_list =\ 240 keyword.run_key("Execute Command On BMC ls -d " 241 + var.IMAGE_UPLOAD_DIR_PATH + "*/") 242 243 image_list = image_list.split("\n") 244 retry = 0 245 while (retry < 10): 246 for i in range(0, len(image_list)): 247 version = get_image_version(image_list[i] + "MANIFEST") 248 if (version == image_version): 249 return image_list[i] 250 time.sleep(10) 251 retry += 1 252 253############################################################################### 254 255 256############################################################################### 257def verify_image_upload(image_version, 258 timeout=3): 259 260 r""" 261 Verify the image was uploaded correctly and that it created 262 a valid d-bus object. If the first check for the image 263 fails, try again until we reach the timeout. 264 265 Description of argument(s): 266 image_version The version from the image's manifest file 267 (e.g. "IBM-witherspoon-redbud-ibm-OP9_v1.17_1.68"). 268 timeout How long, in minutes, to keep trying to find the 269 image on the BMC. Default is 3 minutes. 270 """ 271 272 image_path = get_image_path(image_version) 273 image_version_id = image_path.split("/")[-2] 274 275 keyword.run_key_u("Open Connection And Log In") 276 image_purpose = get_image_purpose(image_path + "MANIFEST") 277 if (image_purpose == var.VERSION_PURPOSE_BMC or 278 image_purpose == var.VERSION_PURPOSE_HOST): 279 uri = var.SOFTWARE_VERSION_URI + image_version_id 280 ret_values = "" 281 for itr in range(timeout * 2): 282 status, ret_values = \ 283 keyword.run_key("Read Attribute " + uri + " Activation") 284 285 if ((ret_values == var.READY) or (ret_values == var.INVALID) 286 or (ret_values == var.ACTIVE)): 287 return True, image_version_id 288 else: 289 time.sleep(30) 290 291 # If we exit the for loop, the timeout has been reached 292 gp.print_var(ret_values) 293 return False, None 294 else: 295 gp.print_var(image_purpose) 296 return False, None 297 298############################################################################### 299 300 301############################################################################### 302def verify_image_not_in_bmc_uploads_dir(image_version, timeout=3): 303 304 r""" 305 Check that an image with the given version is not unpacked inside of the 306 BMCs image uploads directory. If no image is found, retry every 30 seconds 307 until the given timeout is hit, in case the BMC takes time 308 unpacking the image. 309 310 Description of argument(s): 311 image_version The version of the image to look for on the BMC. 312 timeout How long, in minutes, to try to find an image on the BMC. 313 Default is 3 minutes. 314 """ 315 316 keyword.run_key('Open Connection And Log In') 317 for i in range(timeout * 2): 318 stat, grep_res = keyword.run_key('Execute Command On BMC ' 319 + 'ls ' + var.IMAGE_UPLOAD_DIR_PATH + '*/MANIFEST 2>/dev/null ' 320 + '| xargs grep -rl "version=' + image_version + '"') 321 image_dir = os.path.dirname(grep_res.split('\n')[0]) 322 if '' != image_dir: 323 keyword.run_key('Execute Command On BMC rm -rf ' + image_dir) 324 BuiltIn().fail('Found invalid BMC Image: ' + image_dir) 325 time.sleep(30) 326 327############################################################################### 328