Python脚本问题:为每个F5 Pool Member分配唯一属性
问题:F5池配置转换脚本的成员属性分配错误
问题背景
我需要解析旧F5系统的池配置文本,转换成新格式。目前逐行读取文件,以每行首词作为属性处理,但池内多个成员的属性值各自不同,现有脚本会把属性的最后值分配给所有成员,无法对应每个成员的专属属性。
输入配置示例
pool BASE { members { 10.250.x.x:http { } 10.250.x.x:http { } } monitor http } pool 10YEARS { members { 10.250.x.x:http { session disabled } 10.250.x.x:http { } 10.250.x.x:http { } } monitor http } pool ADVICE { members { 10.250.x.x:http { priority-group 70 session disabled } 10.250.x.x:http { priority-group 80 session disabled } 10.250.x.x:http { priority-group 90 } } min-active-members 1 monitor http }
现有Python脚本
import json def transform_pool(pool_name, attributes, ip_name_dict): transformed_line = f"ltm pool /Common/{pool_name}{{\n" if "monitor" in attributes: transformed_line += f"\tmonitor /Common/{attributes['monitor']}\n" if "min-active-members" in attributes: transformed_line += f"\tmin-active-members {attributes['min-active-members']}\n" if "load-balancing-mode" in attributes: transformed_line += ( f"\tload-balancing-mode {attributes['load-balancing-mode']}\n" ) transformed_line += "\tmembers {\n" for member in attributes.get("members", []): ip_address, port = member name = ip_name_dict.get( ip_address, ip_address ) # Get name from dictionary, fallback to IP if not found transformed_line += f"\t\t{name}:{port} {{\n" if "priority-group" in attributes: transformed_line += f"\t\tpriority-group {attributes['priority-group']}\n" if "state" in attributes: transformed_line += f"\t\tstate {attributes['state']}\n" if "session" in attributes: transformed_line += f"\t\tsession user-{attributes['session']}\n" transformed_line += "\t\t}\n" transformed_line += "\t}\n" transformed_line += "}\n" return transformed_line def create_dict_from_file(file_name): with open(file_name, "r") as file: lines = file.readlines() dictionary = {} key = "" for line in lines: if "/Common/" in line: key = line.split("/Common/")[1].strip().split(" ")[0] if "address" in line: ip_address = line.split(" ")[-1].strip() dictionary[ip_address] = key return dictionary # Use the functions file_name = "nodes_config_full.txt" dictionary = create_dict_from_file(file_name) # Read original data from pool_data.txt with open("input.txt", "r") as file: lines = file.readlines() # Transform the data transformed_lines = [] pool_name = None attributes = {"members": []} for line in lines: parts = line.strip().split() if len(parts) == 0: continue elif parts[0] == "pool": if pool_name is not None: transformed_lines.append(transform_pool(pool_name, attributes, dictionary)) attributes.clear() attributes["members"] = [] pool_name = parts[1] elif parts[0] == "monitor": attributes["monitor"] = parts[1] elif parts[0] == "min-active-members": attributes["min-active-members"] = parts[1] elif parts[0] == "load-balancing-mode": attributes["load-balancing-mode"] = parts[1] elif parts[0].count(".") == 3: # Assume IP address format ip_address, port = parts[0].split(":") attributes["members"].append((ip_address, port)) elif parts[0] == "priority-group": attributes["priority-group"] = parts[1] elif parts[0] == "state": attributes["state"] = parts[1] elif parts[0] == "session": attributes["session"] = parts[1] # Append the last pool entry if pool_name is not None: transformed_lines.append(transform_pool(pool_name, attributes, dictionary)) # Write transformed string to pools_config.txt with open("pools_config.txt", "w") as file: file.writelines(transformed_lines) print("Transformation complete. Check pools_config.txt for the output.")
当前错误输出
ltm pool /Common/BASE{ monitor /Common/http members { WEBF03N0101:http { } WEBF03N0102:http { } } } ltm pool /Common/10YEARS{ monitor /Common/http members { DMZ0103:http { session user-disabled } DMZ0104:http { session user-disabled } DMZ0107:http { session user-disabled } } } ltm pool /Common/ADVICE{ monitor /Common/http min-active-members 1 members { DMZ0103:http { priority-group 90 session user-disabled } DMZ0104:http { priority-group 90 session user-disabled } DMZ0107:http { priority-group 90 session user-disabled } } }
解决方案
问题核心在于现有脚本把成员的属性存在全局的attributes字典里,导致所有成员共享最后一次赋值的属性值。需要修改数据结构,让每个成员拥有自己的属性字典。
修改后的脚本
import json def transform_pool(pool_name, pool_data, ip_name_dict): transformed_line = f"ltm pool /Common/{pool_name}{{\n" # 处理池级属性 if "monitor" in pool_data: transformed_line += f"\tmonitor /Common/{pool_data['monitor']}\n" if "min-active-members" in pool_data: transformed_line += f"\tmin-active-members {pool_data['min-active-members']}\n" if "load-balancing-mode" in pool_data: transformed_line += f"\tload-balancing-mode {pool_data['load-balancing-mode']}\n" transformed_line += "\tmembers {\n" # 处理每个成员的专属属性 for member in pool_data.get("members", []): ip_address, port, member_attrs = member name = ip_name_dict.get(ip_address, ip_address) transformed_line += f"\t\t{name}:{port} {{\n" if "priority-group" in member_attrs: transformed_line += f"\t\t\tpriority-group {member_attrs['priority-group']}\n" if "state" in member_attrs: transformed_line += f"\t\t\tstate {member_attrs['state']}\n" if "session" in member_attrs: transformed_line += f"\t\t\tsession user-{member_attrs['session']}\n" transformed_line += "\t\t}\n" transformed_line += "\t}\n" transformed_line += "}\n" return transformed_line def create_dict_from_file(file_name): with open(file_name, "r") as file: lines = file.readlines() dictionary = {} key = "" for line in lines: if "/Common/" in line: key = line.split("/Common/")[1].strip().split(" ")[0] if "address" in line: ip_address = line.split(" ")[-1].strip() dictionary[ip_address] = key return dictionary # 使用函数 file_name = "nodes_config_full.txt" dictionary = create_dict_from_file(file_name) # 读取原始数据 with open("input.txt", "r") as file: lines = file.readlines() transformed_lines = [] pool_name = None pool_data = {"members": []} current_member_attrs = None # 跟踪当前成员的属性 for line in lines: parts = line.strip().split() if len(parts) == 0: continue # 遇到新池,先处理上一个池 elif parts[0] == "pool": if pool_name is not None: transformed_lines.append(transform_pool(pool_name, pool_data, dictionary)) pool_data = {"members": []} current_member_attrs = None pool_name = parts[1] # 池级属性 elif parts[0] == "monitor": pool_data["monitor"] = parts[1] elif parts[0] == "min-active-members": pool_data["min-active-members"] = parts[1] elif parts[0] == "load-balancing-mode": pool_data["load-balancing-mode"] = parts[1] # 遇到成员IP,初始化该成员的属性字典 elif parts[0].count(".") == 3: ip_address, port = parts[0].split(":") current_member_attrs = {} pool_data["members"].append((ip_address, port, current_member_attrs)) # 成员专属属性,赋值给当前成员的属性字典 elif parts[0] == "priority-group": if current_member_attrs is not None: current_member_attrs["priority-group"] = parts[1] elif parts[0] == "state": if current_member_attrs is not None: current_member_attrs["state"] = parts[1] elif parts[0] == "session": if current_member_attrs is not None: current_member_attrs["session"] = parts[1] # 处理最后一个池 if pool_name is not None: transformed_lines.append(transform_pool(pool_name, pool_data, dictionary)) # 写入结果 with open("pools_config.txt", "w") as file: file.writelines(transformed_lines) print("转换完成,查看pools_config.txt获取输出。")
修改说明
- 数据结构调整:把
pool_data["members"]中的元素从(ip, port)改成(ip, port, member_attrs_dict),每个成员对应自己的属性字典。 - 跟踪当前成员:新增
current_member_attrs变量,在遇到成员IP时初始化,后续的成员属性都写入这个字典。 - 转换函数适配:修改
transform_pool函数,遍历成员时读取每个成员的专属属性字典,生成对应配置。
正确输出示例
ltm pool /Common/BASE{ monitor /Common/http members { WEBF03N0101:http { } WEBF03N0102:http { } } } ltm pool /Common/10YEARS{ monitor /Common/http members { DMZ0103:http { session user-disabled } DMZ0104:http { } DMZ0107:http { } } } ltm pool /Common/ADVICE{ monitor /Common/http min-active-members 1 members { DMZ0103:http { priority-group 70 session user-disabled } DMZ0104:http { priority-group 80 session user-disabled } DMZ0107:http { priority-group 90 } } }
内容的提问来源于stack exchange,提问作者Amar Ysabie
相关产品推荐
相关产品推荐

