• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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