1e7e9171eSGeorge Keishing#!/usr/bin/env python3 2de7d408dSCharles Paul Hofer 3de7d408dSCharles Paul Hoferr""" 4de7d408dSCharles Paul HoferThis module provides utilities for code updates. 5de7d408dSCharles Paul Hofer""" 6de7d408dSCharles Paul Hofer 7*09679890SGeorge Keishingfrom robot.libraries.BuiltIn import BuiltIn 8*09679890SGeorge Keishing 9de7d408dSCharles Paul Hoferimport os 10de7d408dSCharles Paul Hoferimport re 11de7d408dSCharles Paul Hoferimport sys 12de7d408dSCharles Paul Hoferimport tarfile 13de7d408dSCharles Paul Hoferimport time 14e635ddc0SGeorge Keishingimport collections 1537c58c8cSGeorge Keishingfrom robot.libraries.BuiltIn import BuiltIn 16de7d408dSCharles Paul Hofer 17de7d408dSCharles Paul Hoferrobot_pgm_dir_path = os.path.dirname(__file__) + os.sep 18e635ddc0SGeorge Keishingrepo_data_path = re.sub('/lib', '/data', robot_pgm_dir_path) 19de7d408dSCharles Paul Hofersys.path.append(repo_data_path) 20de7d408dSCharles Paul Hofer 21*09679890SGeorge Keishingimport bmc_ssh_utils as bsu # NOQA 22*09679890SGeorge Keishingimport gen_robot_keyword as keyword # NOQA 23*09679890SGeorge Keishingimport gen_print as gp # NOQA 24*09679890SGeorge Keishingimport variables as var # NOQA 2537c58c8cSGeorge Keishing 26c1fa2bc9SCharles Paul Hofer 278469a485SSushil Singhdef get_bmc_firmware(image_type, sw_dict): 288469a485SSushil Singh r""" 298469a485SSushil Singh Get the dictionary of image based on image type like either BMC or Host. 308469a485SSushil Singh 318469a485SSushil Singh Description of argument(s): 328469a485SSushil Singh image_type This value is either BMC update or Host update type. 3316b3c7bfSGeorge Keishing sw_dict This contain dictionary of firmware inventory properties. 348469a485SSushil Singh """ 358469a485SSushil Singh 368469a485SSushil Singh temp_dict = collections.OrderedDict() 378469a485SSushil Singh for key, value in sw_dict.items(): 38e635ddc0SGeorge Keishing if value['image_type'] == image_type: 398469a485SSushil Singh temp_dict[key] = value 408469a485SSushil Singh else: 418469a485SSushil Singh pass 428469a485SSushil Singh return temp_dict 438469a485SSushil Singh 448469a485SSushil Singh 45096cd565SGunnar Millsdef verify_no_duplicate_image_priorities(image_purpose): 46c1fa2bc9SCharles Paul Hofer r""" 47c1fa2bc9SCharles Paul Hofer Check that there are no active images with the same purpose and priority. 48c1fa2bc9SCharles Paul Hofer 49c1fa2bc9SCharles Paul Hofer Description of argument(s): 50004ad3c9SJoy Onyerikwu image_purpose The purpose that images must have to be 51004ad3c9SJoy Onyerikwu checked for priority duplicates. 52c1fa2bc9SCharles Paul Hofer """ 53c1fa2bc9SCharles Paul Hofer 54c1fa2bc9SCharles Paul Hofer taken_priorities = {} 55e635ddc0SGeorge Keishing _, image_names = keyword.run_key("Get Software Objects " 56e635ddc0SGeorge Keishing + "version_type=" + image_purpose) 57c1fa2bc9SCharles Paul Hofer 58c1fa2bc9SCharles Paul Hofer for image_name in image_names: 59c1fa2bc9SCharles Paul Hofer _, image = keyword.run_key("Get Host Software Property " + image_name) 60c1fa2bc9SCharles Paul Hofer if image["Activation"] != var.ACTIVE: 61c1fa2bc9SCharles Paul Hofer continue 62c1fa2bc9SCharles Paul Hofer image_priority = image["Priority"] 63c1fa2bc9SCharles Paul Hofer if image_priority in taken_priorities: 64e635ddc0SGeorge Keishing BuiltIn().fail("Found active images with the same priority.\n" 65e635ddc0SGeorge Keishing + gp.sprint_vars(image, 66e635ddc0SGeorge Keishing taken_priorities[image_priority])) 67c1fa2bc9SCharles Paul Hofer taken_priorities[image_priority] = image 68c1fa2bc9SCharles Paul Hofer 69c1fa2bc9SCharles Paul Hofer 70da24d0a0SCharles Paul Hoferdef get_non_running_bmc_software_object(): 71da24d0a0SCharles Paul Hofer r""" 72da24d0a0SCharles Paul Hofer Get the URI to a BMC image from software that is not running on the BMC. 73da24d0a0SCharles Paul Hofer """ 74da24d0a0SCharles Paul Hofer 75da24d0a0SCharles Paul Hofer # Get the version of the image currently running on the BMC. 76da24d0a0SCharles Paul Hofer _, cur_img_version = keyword.run_key("Get BMC Version") 77da24d0a0SCharles Paul Hofer # Remove the surrounding double quotes from the version. 78e635ddc0SGeorge Keishing cur_img_version = cur_img_version.replace('"', '') 79da24d0a0SCharles Paul Hofer 80e635ddc0SGeorge Keishing _, images = keyword.run_key("Read Properties " 81e635ddc0SGeorge Keishing + var.SOFTWARE_VERSION_URI + "enumerate") 82da24d0a0SCharles Paul Hofer 83da24d0a0SCharles Paul Hofer for image_name in images: 84da24d0a0SCharles Paul Hofer _, image_properties = keyword.run_key( 85e635ddc0SGeorge Keishing "Get Host Software Property " + image_name) 86e635ddc0SGeorge Keishing if 'Purpose' in image_properties and 'Version' in image_properties \ 87e635ddc0SGeorge Keishing and image_properties['Purpose'] != var.VERSION_PURPOSE_HOST \ 88e635ddc0SGeorge Keishing and image_properties['Version'] != cur_img_version: 89da24d0a0SCharles Paul Hofer return image_name 90da24d0a0SCharles Paul Hofer BuiltIn().fail("Did not find any non-running BMC images.") 91da24d0a0SCharles Paul Hofer 92da24d0a0SCharles Paul Hofer 93de7d408dSCharles Paul Hoferdef delete_all_pnor_images(): 94de7d408dSCharles Paul Hofer r""" 95de7d408dSCharles Paul Hofer Delete all PNOR images from the BMC. 96de7d408dSCharles Paul Hofer """ 97de7d408dSCharles Paul Hofer 987eedb1ddSAdriana Kobylak keyword.run_key("Initiate Host PowerOff") 997eedb1ddSAdriana Kobylak 100e635ddc0SGeorge Keishing status, images = keyword.run_key("Get Software Objects " 101e635ddc0SGeorge Keishing + var.VERSION_PURPOSE_HOST) 102de7d408dSCharles Paul Hofer for image_name in images: 103e635ddc0SGeorge Keishing keyword.run_key("Delete Image And Verify " + image_name + " " 104e635ddc0SGeorge Keishing + var.VERSION_PURPOSE_HOST) 105de7d408dSCharles Paul Hofer 106de7d408dSCharles Paul Hofer 107de7d408dSCharles Paul Hoferdef wait_for_activation_state_change(version_id, initial_state): 108de7d408dSCharles Paul Hofer r""" 109de7d408dSCharles Paul Hofer Wait for the current activation state of ${version_id} to 110de7d408dSCharles Paul Hofer change from the state provided by the calling function. 111de7d408dSCharles Paul Hofer 112de7d408dSCharles Paul Hofer Description of argument(s): 113004ad3c9SJoy Onyerikwu version_id The version ID whose state change we are 114004ad3c9SJoy Onyerikwu waiting for. 115de7d408dSCharles Paul Hofer initial_state The activation state we want to wait for. 116de7d408dSCharles Paul Hofer """ 117de7d408dSCharles Paul Hofer 118de7d408dSCharles Paul Hofer keyword.run_key_u("Open Connection And Log In") 119de7d408dSCharles Paul Hofer retry = 0 120290b8bd2SCharles Paul Hofer num_read_errors = 0 121290b8bd2SCharles Paul Hofer read_fail_threshold = 1 122e635ddc0SGeorge Keishing while (retry < 60): 123e635ddc0SGeorge Keishing status, software_state = keyword.run_key("Read Properties " 124e635ddc0SGeorge Keishing + var.SOFTWARE_VERSION_URI 125e635ddc0SGeorge Keishing + str(version_id), 126e635ddc0SGeorge Keishing ignore=1) 127e635ddc0SGeorge Keishing if status == 'FAIL': 128290b8bd2SCharles Paul Hofer num_read_errors += 1 129290b8bd2SCharles Paul Hofer if num_read_errors > read_fail_threshold: 130e635ddc0SGeorge Keishing message = "Read errors exceeds threshold:\n " \ 131e635ddc0SGeorge Keishing + gp.sprint_vars(num_read_errors, read_fail_threshold) 132290b8bd2SCharles Paul Hofer BuiltIn().fail(message) 1334d26c008SCharles Paul Hofer time.sleep(10) 134290b8bd2SCharles Paul Hofer continue 135290b8bd2SCharles Paul Hofer 136de7d408dSCharles Paul Hofer current_state = (software_state)["Activation"] 137e635ddc0SGeorge Keishing if (initial_state == current_state): 1384d26c008SCharles Paul Hofer time.sleep(10) 139de7d408dSCharles Paul Hofer retry += 1 140290b8bd2SCharles Paul Hofer num_read_errors = 0 141de7d408dSCharles Paul Hofer else: 142de7d408dSCharles Paul Hofer return 143de7d408dSCharles Paul Hofer return 144de7d408dSCharles Paul Hofer 145de7d408dSCharles Paul Hofer 146de7d408dSCharles Paul Hoferdef get_latest_file(dir_path): 147de7d408dSCharles Paul Hofer r""" 148de7d408dSCharles Paul Hofer Get the path to the latest uploaded file. 149de7d408dSCharles Paul Hofer 150de7d408dSCharles Paul Hofer Description of argument(s): 151004ad3c9SJoy Onyerikwu dir_path Path to the dir from which the name of the 152004ad3c9SJoy Onyerikwu last updated file or folder will be 153004ad3c9SJoy Onyerikwu returned to the calling function. 154de7d408dSCharles Paul Hofer """ 155de7d408dSCharles Paul Hofer 156e635ddc0SGeorge Keishing stdout, stderr, rc = \ 157e635ddc0SGeorge Keishing bsu.bmc_execute_command("cd " + dir_path 158004ad3c9SJoy Onyerikwu + "; stat -c '%Y %n' * |" 159e635ddc0SGeorge Keishing + " sort -k1,1nr | head -n 1") 1609b66897bSJoy Onyerikwu return stdout.split(" ")[-1] 161de7d408dSCharles Paul Hofer 162de7d408dSCharles Paul Hofer 163de7d408dSCharles Paul Hoferdef get_version_tar(tar_file_path): 164de7d408dSCharles Paul Hofer r""" 165de7d408dSCharles Paul Hofer Read the image version from the MANIFEST inside the tarball. 166de7d408dSCharles Paul Hofer 167de7d408dSCharles Paul Hofer Description of argument(s): 168de7d408dSCharles Paul Hofer tar_file_path The path to a tar file that holds the image 169de7d408dSCharles Paul Hofer version inside the MANIFEST. 170de7d408dSCharles Paul Hofer """ 171de7d408dSCharles Paul Hofer 1723c77d78fSSushil Singh version = "" 173de7d408dSCharles Paul Hofer tar = tarfile.open(tar_file_path) 174de7d408dSCharles Paul Hofer for member in tar.getmembers(): 17542ade549SGeorge Keishing BuiltIn().log_to_console(member.name) 17642ade549SGeorge Keishing if member.name != "MANIFEST": 17742ade549SGeorge Keishing continue 178de7d408dSCharles Paul Hofer f = tar.extractfile(member) 179de7d408dSCharles Paul Hofer content = f.read() 18036efbc04SGeorge Keishing if content.find(b"version=") == -1: 18136efbc04SGeorge Keishing # This tar member does not contain the version. 18236efbc04SGeorge Keishing continue 18342ade549SGeorge Keishing content = content.decode("utf-8", "ignore").split("\n") 184de7d408dSCharles Paul Hofer content = [x for x in content if "version=" in x] 185de7d408dSCharles Paul Hofer version = content[0].split("=")[-1] 186de7d408dSCharles Paul Hofer break 187de7d408dSCharles Paul Hofer tar.close() 188de7d408dSCharles Paul Hofer return version 189de7d408dSCharles Paul Hofer 190de7d408dSCharles Paul Hofer 191de7d408dSCharles Paul Hoferdef get_image_version(file_path): 192de7d408dSCharles Paul Hofer r""" 193de7d408dSCharles Paul Hofer Read the file for a version object. 194de7d408dSCharles Paul Hofer 195de7d408dSCharles Paul Hofer Description of argument(s): 196004ad3c9SJoy Onyerikwu file_path The path to a file that holds the image 197004ad3c9SJoy Onyerikwu version. 198de7d408dSCharles Paul Hofer """ 199de7d408dSCharles Paul Hofer 200e635ddc0SGeorge Keishing stdout, stderr, rc = \ 201e635ddc0SGeorge Keishing bsu.bmc_execute_command("cat " + file_path 202e635ddc0SGeorge Keishing + " | grep \"version=\"", ignore_err=1) 2039b66897bSJoy Onyerikwu return (stdout.split("\n")[0]).split("=")[-1] 204de7d408dSCharles Paul Hofer 205de7d408dSCharles Paul Hofer 206de7d408dSCharles Paul Hoferdef get_image_purpose(file_path): 207de7d408dSCharles Paul Hofer r""" 208de7d408dSCharles Paul Hofer Read the file for a purpose object. 209de7d408dSCharles Paul Hofer 210de7d408dSCharles Paul Hofer Description of argument(s): 211004ad3c9SJoy Onyerikwu file_path The path to a file that holds the image 212004ad3c9SJoy Onyerikwu purpose. 213de7d408dSCharles Paul Hofer """ 214de7d408dSCharles Paul Hofer 215e635ddc0SGeorge Keishing stdout, stderr, rc = \ 216e635ddc0SGeorge Keishing bsu.bmc_execute_command("cat " + file_path 217e635ddc0SGeorge Keishing + " | grep \"purpose=\"", ignore_err=1) 2189b66897bSJoy Onyerikwu return stdout.split("=")[-1] 219de7d408dSCharles Paul Hofer 220de7d408dSCharles Paul Hofer 221de7d408dSCharles Paul Hoferdef get_image_path(image_version): 222de7d408dSCharles Paul Hofer r""" 223de7d408dSCharles Paul Hofer Query the upload image dir for the presence of image matching 224de7d408dSCharles Paul Hofer the version that was read from the MANIFEST before uploading 225de7d408dSCharles Paul Hofer the image. Based on the purpose verify the activation object 226de7d408dSCharles Paul Hofer exists and is either READY or INVALID. 227de7d408dSCharles Paul Hofer 228de7d408dSCharles Paul Hofer Description of argument(s): 229004ad3c9SJoy Onyerikwu image_version The version of the image that should match 230004ad3c9SJoy Onyerikwu one of the images in the upload dir. 231de7d408dSCharles Paul Hofer """ 232de7d408dSCharles Paul Hofer 233e635ddc0SGeorge Keishing stdout, stderr, rc = \ 234e635ddc0SGeorge Keishing bsu.bmc_execute_command("ls -d " + var.IMAGE_UPLOAD_DIR_PATH + "*/") 235de7d408dSCharles Paul Hofer 2369b66897bSJoy Onyerikwu image_list = stdout.split("\n") 237de7d408dSCharles Paul Hofer retry = 0 238e635ddc0SGeorge Keishing while (retry < 10): 239de7d408dSCharles Paul Hofer for i in range(0, len(image_list)): 240de7d408dSCharles Paul Hofer version = get_image_version(image_list[i] + "MANIFEST") 241e635ddc0SGeorge Keishing if (version == image_version): 242de7d408dSCharles Paul Hofer return image_list[i] 243de7d408dSCharles Paul Hofer time.sleep(10) 244de7d408dSCharles Paul Hofer retry += 1 245de7d408dSCharles Paul Hofer 246de7d408dSCharles Paul Hofer 247e635ddc0SGeorge Keishingdef verify_image_upload(image_version, 248e635ddc0SGeorge Keishing timeout=3): 249de7d408dSCharles Paul Hofer r""" 250de7d408dSCharles Paul Hofer Verify the image was uploaded correctly and that it created 251de7d408dSCharles Paul Hofer a valid d-bus object. If the first check for the image 252de7d408dSCharles Paul Hofer fails, try again until we reach the timeout. 253de7d408dSCharles Paul Hofer 254de7d408dSCharles Paul Hofer Description of argument(s): 2559f74d3afSCharles Paul Hofer image_version The version from the image's manifest file 256e0a81289SGeorge Keishing (e.g. "v2.2-253-g00050f1"). 257004ad3c9SJoy Onyerikwu timeout How long, in minutes, to keep trying to 258004ad3c9SJoy Onyerikwu find the image on the BMC. Default is 3 minutes. 259de7d408dSCharles Paul Hofer """ 260de7d408dSCharles Paul Hofer 261de7d408dSCharles Paul Hofer image_path = get_image_path(image_version) 262de7d408dSCharles Paul Hofer image_version_id = image_path.split("/")[-2] 263de7d408dSCharles Paul Hofer 264de7d408dSCharles Paul Hofer keyword.run_key_u("Open Connection And Log In") 265de7d408dSCharles Paul Hofer image_purpose = get_image_purpose(image_path + "MANIFEST") 266e635ddc0SGeorge Keishing if (image_purpose == var.VERSION_PURPOSE_BMC 267e635ddc0SGeorge Keishing or image_purpose == var.VERSION_PURPOSE_HOST): 268de7d408dSCharles Paul Hofer uri = var.SOFTWARE_VERSION_URI + image_version_id 269de7d408dSCharles Paul Hofer ret_values = "" 270de7d408dSCharles Paul Hofer for itr in range(timeout * 2): 271e635ddc0SGeorge Keishing status, ret_values = \ 272e635ddc0SGeorge Keishing keyword.run_key("Read Attribute " + uri + " Activation") 273de7d408dSCharles Paul Hofer 274e635ddc0SGeorge Keishing if ((ret_values == var.READY) or (ret_values == var.INVALID) 275e635ddc0SGeorge Keishing or (ret_values == var.ACTIVE)): 276cef6199aSCharles Paul Hofer return True, image_version_id 277de7d408dSCharles Paul Hofer else: 278de7d408dSCharles Paul Hofer time.sleep(30) 279de7d408dSCharles Paul Hofer 280de7d408dSCharles Paul Hofer # If we exit the for loop, the timeout has been reached 281de7d408dSCharles Paul Hofer gp.print_var(ret_values) 282cef6199aSCharles Paul Hofer return False, None 283de7d408dSCharles Paul Hofer else: 284de7d408dSCharles Paul Hofer gp.print_var(image_purpose) 285cef6199aSCharles Paul Hofer return False, None 286de7d408dSCharles Paul Hofer 287de7d408dSCharles Paul Hofer 288de7d408dSCharles Paul Hoferdef verify_image_not_in_bmc_uploads_dir(image_version, timeout=3): 289de7d408dSCharles Paul Hofer r""" 290de7d408dSCharles Paul Hofer Check that an image with the given version is not unpacked inside of the 291de7d408dSCharles Paul Hofer BMCs image uploads directory. If no image is found, retry every 30 seconds 292de7d408dSCharles Paul Hofer until the given timeout is hit, in case the BMC takes time 293de7d408dSCharles Paul Hofer unpacking the image. 294de7d408dSCharles Paul Hofer 295de7d408dSCharles Paul Hofer Description of argument(s): 296004ad3c9SJoy Onyerikwu image_version The version of the image to look for on 297004ad3c9SJoy Onyerikwu the BMC. 298004ad3c9SJoy Onyerikwu timeout How long, in minutes, to try to find an 299004ad3c9SJoy Onyerikwu image on the BMC. Default is 3 minutes. 300de7d408dSCharles Paul Hofer """ 301de7d408dSCharles Paul Hofer 302de7d408dSCharles Paul Hofer for i in range(timeout * 2): 303e635ddc0SGeorge Keishing stdout, stderr, rc = \ 304e635ddc0SGeorge Keishing bsu.bmc_execute_command('ls ' + var.IMAGE_UPLOAD_DIR_PATH 305e635ddc0SGeorge Keishing + '*/MANIFEST 2>/dev/null ' 306004ad3c9SJoy Onyerikwu + '| xargs grep -rl "version=' 307e635ddc0SGeorge Keishing + image_version + '"') 308e635ddc0SGeorge Keishing image_dir = os.path.dirname(stdout.split('\n')[0]) 309e635ddc0SGeorge Keishing if '' != image_dir: 310e635ddc0SGeorge Keishing bsu.bmc_execute_command('rm -rf ' + image_dir) 311e635ddc0SGeorge Keishing BuiltIn().fail('Found invalid BMC Image: ' + image_dir) 312de7d408dSCharles Paul Hofer time.sleep(30) 313