1#!/usr/bin/env python 2# coding:utf-8 3 4# 5# Copyright (C) 2025 Huawei Technologies Co., Ltd. 6# Licensed under the Mulan PSL v2. 7# You can use this software according to the terms and conditions of the Mulan 8# PSL v2. 9# You may obtain a copy of Mulan PSL v2 at: 10# http://license.coscl.org.cn/MulanPSL2 11# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY 12# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13# NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14# See the Mulan PSL v2 for more details. 15# 16 17import os 18import logging 19import re 20import xml.etree.ElementTree as ET 21 22 23def whitelist_check(intput_str): 24 """Function check white list.""" 25 if not re.match(r"^[A-Za-z0-9\/\-_.${}]+$", intput_str): 26 return 1 27 return 0 28 29 30def convert_num(field): 31 """convert string to int, and return None if input is invalid.""" 32 return int(field) 33 34 35def convert_boolean(field): 36 """convert string to bool, and return None if input is invalid.""" 37 if field == "y" or field.lower() == "true": 38 return True 39 if field == "n" or field.lower() == "false": 40 return False 41 raise ValueError 42 43 44def convert_mem_limit(field): 45 """convert string and check range for heap_limit/stack_limit.""" 46 value = convert_num(field) 47 if value is None or value <= 0: 48 return None 49 return value 50 51 52def check_manifest(manifest): 53 """check input manifest format.""" 54 return manifest.heap_size > 0 and manifest.stack_size > 0 and \ 55 manifest.instancekeepalive in [0, 1] and manifest.multi_session in [0, 1] 56 57 58def check_memory_baseline(cfg, uuid_str, manifest_val): 59 """check memory baseline in manifest with memctrl config files.""" 60 if cfg.release_type == "0": 61 return True 62 if not check_manifest(manifest_val): 63 logging.error("Invalid manifest for memory control checking.") 64 return False 65 if not cfg.memctrl_path: 66 logging.error("Invalid path to memory control configuration directory. Please specify --memctrl_path in args.") 67 return False 68 cfg_dir_path = os.path.realpath(cfg.memctrl_path) 69 if not os.path.exists(cfg_dir_path): 70 logging.error("memctrl_path does not exist.") 71 return False 72 if whitelist_check(cfg_dir_path): 73 logging.error("memctrl_path contains invalid character.") 74 return False 75 cfg_file = os.path.join(cfg_dir_path, "%s.xml" % (uuid_str,)) 76 if not os.path.exists(cfg_file): 77 logging.error("Memctrl file %s does not exist." % (cfg_file,)) 78 return False 79 80 mandatory_fields = { 81 'heap_limit': convert_mem_limit, 82 'stack_limit': convert_mem_limit, 83 'multi_session': convert_boolean, 84 'keepalive': convert_boolean, 85 } 86 memctrl_dict = {} 87 try: 88 root = ET.parse(cfg_file).getroot() 89 for node in root: 90 tag, value = node.tag, node.text 91 if tag in memctrl_dict: 92 logging.error("Memctrl file contains duplicated tag \"%s\"." % (tag,)) 93 return False 94 if tag in mandatory_fields: 95 try: 96 memctrl_dict[tag] = mandatory_fields[tag](value) 97 except ValueError: 98 memctrl_dict[tag] = None 99 except ET.ParseError: 100 logging.error("Failed to parse memctrl XML file.") 101 return False 102 if any(v is None for v in memctrl_dict.values()): 103 for tag in memctrl_dict: 104 if memctrl_dict[tag] is None: 105 logging.error("Memctrl file contains invalid data in field \"%s\"." % (tag,)) 106 return False 107 if len(memctrl_dict) < len(mandatory_fields): 108 missing_keys = mandatory_fields.keys() - memctrl_dict.keys() 109 logging.error("Memctrl file missing fields: %s" % (', '.join(missing_keys))) 110 return False 111 112 # Check manifest against memctrl config 113 if manifest_val.heap_size > memctrl_dict.get('heap_limit', 0): 114 logging.error("Too large manifest heap limit (%d) compared to memctrl configuration (%d)" 115 % (manifest_val.heap_size, memctrl_dict.get('heap_limit', 0))) 116 return False 117 if manifest_val.stack_size > memctrl_dict.get('stack_limit', 0): 118 logging.error("Too large manifest stack limit (%d) compared to memctrl configuration (%d)" 119 % (manifest_val.stack_size, memctrl_dict.get('stack_limit', 0))) 120 return False 121 if manifest_val.instancekeepalive == 1 and not memctrl_dict.get('keepalive', False): 122 logging.error("Inconsistent manifest keep-alive (%s) compared to memctrl configuration (%s)" 123 % (manifest_val.instancekeepalive == 1, memctrl_dict.get('keepalive', False))) 124 return False 125 if manifest_val.multi_session == 1 and not memctrl_dict.get('multi_session', False): 126 logging.error("Inconsistent manifest multisession (%s) compared to memctrl configuration (%s)" 127 % (manifest_val.multi_session == 1, memctrl_dict.get('multi_session', False))) 128 return False 129 130 logging.info("memory baseline checking passed") 131 return True