ansible_image_validation/azure-table-data.py (132 lines of code) (raw):

import os import datetime import dateutil.parser import argparse from os import path from azure.cosmosdb.table.tableservice import TableService from azure.cosmosdb.table.models import Entity class AzureTableData: """ This class handles the functionality of getting data from Azure Table Storage and generating the HTML report """ def __init__(self, args): connect_str = args.connection_str self.table_service = TableService(connection_string=connect_str) def get_report_line(self, index, image, context): """ This function generates a single row of resultant validation report """ result_line = "\t<tr class='" + context + "'>\n" if hasattr(image, 'ErrorMessages'): err_msg = str(image.ErrorMessages).replace("\n", "</br>") else: err_msg = "" result_line = result_line + "\t\t<td>" + str(index) + "</td>\n" result_line = result_line + "\t\t<td>" + str(image.PartitionKey) + "</td>\n" result_line = result_line + "\t\t<td>" + str(image.ValidationResult) + "</td>\n" result_line = result_line + "\t\t<td>" + err_msg + "</td>\n" result_line = result_line + "\t</tr>\n" return result_line def generate_validation_report(self, args): """ This functions generates the HTML report of validations """ imagequeryresult = self.table_service.query_entities(args.table_name, filter="IsDeleted eq '0'", accept='application/json;odata=minimalmetadata') current_date_time = datetime.datetime.now(datetime.timezone.utc) index = 1 result_line = """ <!DOCTYPE html> <html lang="en"> <head> <title>Marketplace Image Validation Report</title> <meta charset="utf-8"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <table class="table"> <tr> <td> # </td> <td> VM Name </td> <td> Validation Result </td> <td> Error Messages </td> </tr>\n""" with open('./report/index.html', 'w') as report: context = "danger" for image in imagequeryresult: if image.ValidationResult == "Failed": result_line = result_line + self.get_report_line(index, image, context) index += 1 context = "success" for image in imagequeryresult: if image.ValidationResult == "Success": result_line = result_line + self.get_report_line(index, image, context) index += 1 context = "warning" for image in imagequeryresult: if image.ValidationResult == "NA": result_line = result_line + self.get_report_line(index, image, context) index += 1 result_line = result_line + "</table></body></html>" report.write("%s\n" % result_line) def select_images_to_validate(self, args): """ This function iterates over all the entries in the Azure Table Storage and selects at max 'args.max_vm_to_validate' images which should get validated during this run. """ max_vms_to_validate_at_a_time = int(args.max_vm_to_validate ) validation_period = int(args.validation_period) allimages = open(args.all_image_list, 'r') Lines = allimages.readlines() imagequeryresult = self.table_service.query_entities(args.table_name, filter="IsDeleted eq '0'", accept='application/json;odata=minimalmetadata') entries = [] list_of_images_to_validate = [] current_date_time = datetime.datetime.now(datetime.timezone.utc) for image in imagequeryresult: entries.append(image) for line in Lines: publisher = line.split(':')[0] offer = line.split(':')[1] sku = line.split(':')[2] disk_version = line.split(':')[3].replace('\n', '') image_name = offer.replace("_", "-") + "-" + sku.replace("_", "-") + "-" + disk_version image_entry_exists = False for image in entries: # if the image entry exists and it was last validated 2 days ago, # add it to the list to be validated if image.PartitionKey == image_name: image_entry_exists = True if image.ValidationResult == 'NA' or (current_date_time - image.Timestamp).days > validation_period: list_of_images_to_validate.append(line) break if not image_entry_exists: list_of_images_to_validate.append(line) ## insert the entry as well args.image_name = image_name args.validation_result = 'NA' self.insert_data(args) i = 0 with open(args.filtered_image_list, 'w') as filteredimagefile: filteredimagefile.write("") for image in list_of_images_to_validate: if i == max_vms_to_validate_at_a_time: break filteredimagefile.write("%s" % image) i += 1 def insert_data(self, args): """ Inserts/updates the records in the Azure Table Storage """ table_name = args.table_name image_name = args.image_name validation_time = args.validation_time validation_result = args.validation_result validation_epoch = args.validation_epoch print("error message path", args.err_msg_file) if args.err_msg_file != None and path.exists(args.err_msg_file): err_msgs = open(args.err_msg_file, "r").read() else: err_msgs = "" validationResult = { 'PartitionKey': image_name, 'RowKey': "1", 'ValidationResult': validation_result, "ErrorMessages": err_msgs, "IsDeleted": "0" } print(validationResult) self.table_service.insert_or_replace_entity(table_name, validationResult) def parse_arguments(): parser = argparse.ArgumentParser(description= "Build Template Generator Arguments") parser.add_argument('--method', '-m', help = "Method to execute") parser.add_argument('--connection-str', '-c', help = "connection string for the storage account") parser.add_argument('--container-name', '-n', help = "Container name") parser.add_argument('--table-name', '-t', help = "Table name") parser.add_argument('--image-name', '-i', help = "Image name which was validated") parser.add_argument('--validation-epoch', '-e', help = "Epoch value at the time of validation") parser.add_argument('--validation-time', help = "Time of validation") parser.add_argument('--validation-result', help = "Validation result") parser.add_argument('--err-msg-file', help = "File which contains error messages") parser.add_argument('--all-image-list', '-in', help = "connection string for the storage account") parser.add_argument('--filtered-image-list', '-out', help = "connection string for the storage account") parser.add_argument('--max-vm-to-validate', help = "Number of VMs to validate in a single run") parser.add_argument('--validation-period', help = "Number of days to wait before validating a VM again") return parser.parse_args() if __name__ == "__main__": args = parse_arguments() tabledata = AzureTableData(args) if args.method == "insert-data": tabledata.insert_data(args) elif args.method == "select-images-to-validate": tabledata.select_images_to_validate(args) elif args.method == "generate-report": tabledata.generate_validation_report(args)