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 image_properties['Purpose'] != var.VERSION_PURPOSE_HOST \ 69 and image_properties['Version'] != cur_img_version: 70 return image_name 71 BuiltIn().fail("Did not find any non-running BMC images.") 72 73############################################################################### 74 75 76############################################################################### 77def delete_all_pnor_images(): 78 79 r""" 80 Delete all PNOR images from the BMC. 81 """ 82 83 status, images = keyword.run_key("Get Software Objects " 84 + var.VERSION_PURPOSE_HOST) 85 for image_name in images: 86 BuiltIn().log_to_console(image_name) 87 # Delete twice, in case the image is in the /tmp/images directory 88 keyword.run_key("Call Method " + image_name 89 + " delete data={\"data\":[]}") 90 keyword.run_key("Call Method " + image_name 91 + " delete data={\"data\":[]}") 92 93############################################################################### 94 95 96############################################################################### 97def wait_for_activation_state_change(version_id, initial_state): 98 99 r""" 100 Wait for the current activation state of ${version_id} to 101 change from the state provided by the calling function. 102 103 Description of argument(s): 104 version_id The version ID whose state change we are waiting for. 105 initial_state The activation state we want to wait for. 106 """ 107 108 keyword.run_key_u("Open Connection And Log In") 109 retry = 0 110 while (retry < 20): 111 status, software_state = keyword.run_key("Read Properties " + 112 var.SOFTWARE_VERSION_URI + str(version_id)) 113 current_state = (software_state)["Activation"] 114 if (initial_state == current_state): 115 time.sleep(60) 116 retry += 1 117 else: 118 return 119 return 120 121############################################################################### 122 123 124############################################################################### 125def get_latest_file(dir_path): 126 127 r""" 128 Get the path to the latest uploaded file. 129 130 Description of argument(s): 131 dir_path Path to the dir from which the name of the last 132 updated file or folder will be returned to the 133 calling function. 134 """ 135 136 keyword.run_key_u("Open Connection And Log In") 137 status, ret_values =\ 138 keyword.run_key("Execute Command On BMC cd " + dir_path 139 + "; stat -c '%Y %n' * | sort -k1,1nr | head -n 1", ignore=1) 140 return ret_values.split(" ")[-1] 141 142############################################################################### 143 144 145############################################################################### 146def get_version_tar(tar_file_path): 147 148 r""" 149 Read the image version from the MANIFEST inside the tarball. 150 151 Description of argument(s): 152 tar_file_path The path to a tar file that holds the image 153 version inside the MANIFEST. 154 """ 155 156 tar = tarfile.open(tar_file_path) 157 for member in tar.getmembers(): 158 f=tar.extractfile(member) 159 content=f.read() 160 if "version=" in content: 161 content = content.split("\n") 162 content = [x for x in content if "version=" in x] 163 version = content[0].split("=")[-1] 164 break 165 tar.close() 166 return version 167 168############################################################################### 169 170 171############################################################################### 172def get_image_version(file_path): 173 174 r""" 175 Read the file for a version object. 176 177 Description of argument(s): 178 file_path The path to a file that holds the image version. 179 """ 180 181 keyword.run_key_u("Open Connection And Log In") 182 status, ret_values =\ 183 keyword.run_key("Execute Command On BMC cat " 184 + file_path + " | grep \"version=\"", ignore=1) 185 return (ret_values.split("\n")[0]).split("=")[-1] 186 187############################################################################### 188 189 190############################################################################### 191def get_image_purpose(file_path): 192 193 r""" 194 Read the file for a purpose object. 195 196 Description of argument(s): 197 file_path The path to a file that holds the image purpose. 198 """ 199 200 keyword.run_key_u("Open Connection And Log In") 201 status, ret_values =\ 202 keyword.run_key("Execute Command On BMC cat " 203 + file_path + " | grep \"purpose=\"", ignore=1) 204 return ret_values.split("=")[-1] 205 206############################################################################### 207 208 209############################################################################### 210def get_image_path(image_version): 211 212 r""" 213 Query the upload image dir for the presence of image matching 214 the version that was read from the MANIFEST before uploading 215 the image. Based on the purpose verify the activation object 216 exists and is either READY or INVALID. 217 218 Description of argument(s): 219 image_version The version of the image that should match one 220 of the images in the upload dir. 221 """ 222 223 keyword.run_key_u("Open Connection And Log In") 224 status, image_list =\ 225 keyword.run_key("Execute Command On BMC ls -d " 226 + var.IMAGE_UPLOAD_DIR_PATH + "*/") 227 228 image_list = image_list.split("\n") 229 retry = 0 230 while (retry < 10): 231 for i in range(0, len(image_list)): 232 version = get_image_version(image_list[i] + "MANIFEST") 233 if (version == image_version): 234 return image_list[i] 235 time.sleep(10) 236 retry += 1 237 238############################################################################### 239 240 241############################################################################### 242def verify_image_upload(image_version, 243 timeout=3): 244 245 r""" 246 Verify the image was uploaded correctly and that it created 247 a valid d-bus object. If the first check for the image 248 fails, try again until we reach the timeout. 249 250 Description of argument(s): 251 image_version The version from the image's manifest file 252 (e.g. "IBM-witherspoon-redbud-ibm-OP9_v1.17_1.68"). 253 timeout How long, in minutes, to keep trying to find the 254 image on the BMC. Default is 3 minutes. 255 """ 256 257 image_path = get_image_path(image_version) 258 image_version_id = image_path.split("/")[-2] 259 260 keyword.run_key_u("Open Connection And Log In") 261 image_purpose = get_image_purpose(image_path + "MANIFEST") 262 if (image_purpose == var.VERSION_PURPOSE_BMC or 263 image_purpose == var.VERSION_PURPOSE_HOST): 264 uri = var.SOFTWARE_VERSION_URI + image_version_id 265 ret_values = "" 266 for itr in range(timeout * 2): 267 status, ret_values = \ 268 keyword.run_key("Read Attribute " + uri + " Activation") 269 270 if ((ret_values == var.READY) or (ret_values == var.INVALID) 271 or (ret_values == var.ACTIVE)): 272 return True, image_version_id 273 else: 274 time.sleep(30) 275 276 # If we exit the for loop, the timeout has been reached 277 gp.print_var(ret_values) 278 return False, None 279 else: 280 gp.print_var(image_purpose) 281 return False, None 282 283############################################################################### 284 285 286############################################################################### 287def verify_image_not_in_bmc_uploads_dir(image_version, timeout=3): 288 289 r""" 290 Check that an image with the given version is not unpacked inside of the 291 BMCs image uploads directory. If no image is found, retry every 30 seconds 292 until the given timeout is hit, in case the BMC takes time 293 unpacking the image. 294 295 Description of argument(s): 296 image_version The version of the image to look for on the BMC. 297 timeout How long, in minutes, to try to find an image on the BMC. 298 Default is 3 minutes. 299 """ 300 301 keyword.run_key('Open Connection And Log In') 302 for i in range(timeout * 2): 303 stat, grep_res = keyword.run_key('Execute Command On BMC ' 304 + 'ls ' + var.IMAGE_UPLOAD_DIR_PATH + '*/MANIFEST 2>/dev/null ' 305 + '| xargs grep -rl "version=' + image_version + '"') 306 image_dir = os.path.dirname(grep_res.split('\n')[0]) 307 if '' != image_dir: 308 keyword.run_key('Execute Command On BMC rm -rf ' + image_dir) 309 BuiltIn().fail('Found invalid BMC Image: ' + image_dir) 310 time.sleep(30) 311 312############################################################################### 313