diff --git a/jcloud/api/aliyun_server_light.py b/jcloud/api/aliyun_server_light.py index 9bc0e61..d02b4cd 100644 --- a/jcloud/api/aliyun_server_light.py +++ b/jcloud/api/aliyun_server_light.py @@ -1515,7 +1515,8 @@ def update_server_record(instance_ids): if 'origin_price' in plan and plan['origin_price'] is not None: server.plan_price = float(plan['origin_price']) break - + + sync_firewall_rules(instance_id) # 保存更新 server.save(ignore_permissions=True) jingrow.db.commit() @@ -1724,4 +1725,58 @@ def delete_aliyun_firewall_rules(instance_id, rule_ids, region_id='cn-shanghai') except Exception as e: jingrow.log_error("批量删除防火墙规则失败", f"删除实例 {instance_id} 防火墙规则时发生错误: {str(e)}") - return {"success": False, "error": str(e), "message": "批量删除防火墙规则失败"} \ No newline at end of file + return {"success": False, "error": str(e), "message": "批量删除防火墙规则失败"} + +@jingrow.whitelist() +def sync_firewall_rules(instance_id): + """同步阿里云防火墙规则到本地Jsite Server记录""" + try: + # 查找对应的Jsite Server记录 + server = jingrow.get_pg("Jsite Server", {"instance_id": instance_id}) + if not server: + return {"success": False, "message": "找不到对应的服务器记录"} + + region_id = server.region + if not region_id: + return {"success": False, "message": "服务器记录缺少region信息"} + + # 获取阿里云防火墙规则 + firewall_result = get_aliyun_firewall_rules(instance_id, region_id) + if not firewall_result or not firewall_result.get('success'): + error_msg = f"获取阿里云防火墙规则失败: {firewall_result.get('message', '未知错误')}" + jingrow.log_error("同步防火墙规则失败", error_msg) + return {"success": False, "message": error_msg} + + firewall_rules_data = firewall_result.get('data', {}).get('firewall_rules', []) + + # 转换防火墙规则格式 + converted_rules = [] + for rule in firewall_rules_data: + converted_rule = { + "rule_id": rule.get('rule_id', ''), + "protocol": rule.get('rule_protocol', ''), + "port": rule.get('port', ''), + "source_ip": rule.get('source_cidr_ip', '0.0.0.0/0'), + "remark": rule.get('remark', '') + } + converted_rules.append(converted_rule) + + # 清空现有的防火墙规则并添加新的 + server.firewall_rules = [] + for rule_data in converted_rules: + server.append('firewall_rules', rule_data) + + # 保存更新 + server.save(ignore_permissions=True) + jingrow.db.commit() + + return { + "success": True, + "message": f"防火墙规则同步成功,共同步 {len(converted_rules)} 条规则", + "rules_count": len(converted_rules), + "server_name": server.name + } + + except Exception as e: + jingrow.log_error("同步防火墙规则失败", f"同步实例 {instance_id} 防火墙规则时发生错误: {str(e)}") + return {"success": False, "error": str(e), "message": "同步防火墙规则失败"} \ No newline at end of file diff --git a/jcloud/jcloud/pagetype/firewall_rules/firewall_rules.json b/jcloud/jcloud/pagetype/firewall_rules/firewall_rules.json index 8fa9a8c..1d07f85 100644 --- a/jcloud/jcloud/pagetype/firewall_rules/firewall_rules.json +++ b/jcloud/jcloud/pagetype/firewall_rules/firewall_rules.json @@ -5,6 +5,7 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ + "rule_id", "protocol", "port", "source_ip", @@ -14,30 +15,42 @@ { "fieldname": "protocol", "fieldtype": "Select", + "in_list_view": 1, "label": "协议", "options": "TCP\nUDP\nICMP" }, { "fieldname": "port", "fieldtype": "Data", + "in_list_view": 1, "label": "端口范围" }, { "fieldname": "source_ip", "fieldtype": "Data", + "in_list_view": 1, "label": "来源IP" }, { "fieldname": "remark", "fieldtype": "Data", + "in_list_view": 1, "label": "备注" + }, + { + "columns": 2, + "fieldname": "rule_id", + "fieldtype": "Data", + "in_list_view": 1, + "label": "规则ID", + "read_only": 1 } ], "grid_page_length": 50, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2025-08-09 17:34:59.806703", + "modified": "2025-08-09 18:39:46.276289", "modified_by": "Administrator", "module": "Jcloud", "name": "Firewall Rules", diff --git a/jcloud/jcloud/pagetype/firewall_rules/firewall_rules.py b/jcloud/jcloud/pagetype/firewall_rules/firewall_rules.py index c8aeae9..bf1845a 100644 --- a/jcloud/jcloud/pagetype/firewall_rules/firewall_rules.py +++ b/jcloud/jcloud/pagetype/firewall_rules/firewall_rules.py @@ -20,6 +20,7 @@ class FirewallRules(Document): port: DF.Data | None protocol: DF.Literal["TCP", "UDP", "ICMP"] remark: DF.Data | None + rule_id: DF.Data | None source_ip: DF.Data | None # end: auto-generated types pass diff --git a/jcloud/jcloud/pagetype/jsite_server/jsite_server.js b/jcloud/jcloud/pagetype/jsite_server/jsite_server.js index fbfdf2d..3bb1ed7 100644 --- a/jcloud/jcloud/pagetype/jsite_server/jsite_server.js +++ b/jcloud/jcloud/pagetype/jsite_server/jsite_server.js @@ -107,6 +107,16 @@ jingrow.ui.form.on("Jsite Server", { }); dialog.show(); }); + + frm.add_custom_button(__('同步防火墙规则'), function() { + // 弹出确认对话框 + jingrow.confirm( + __('确定要同步防火墙规则吗?'), + function() { + sync_firewall_rules(frm); + } + ); + }); } // 为password字段添加眼睛图标 @@ -208,6 +218,10 @@ function create_firewall_rule(frm, rule_protocol, port, remark) { message: __('防火墙规则创建成功'), indicator: 'green' }); + // 创建成功后自动同步防火墙规则 + setTimeout(function() { + sync_firewall_rules(frm); + }, 2000); } else { jingrow.msgprint({ title: __('错误'), @@ -218,3 +232,29 @@ function create_firewall_rule(frm, rule_protocol, port, remark) { } }); } + +function sync_firewall_rules(frm) { + jingrow.call({ + method: 'jcloud.api.aliyun_server_light.sync_firewall_rules', + args: { + instance_id: frm.pg.instance_id + }, + callback: function(r) { + if (r.message && r.message.success) { + jingrow.msgprint({ + title: __('成功'), + message: r.message.message || __('防火墙规则同步成功'), + indicator: 'green' + }); + // 刷新表单以显示最新的防火墙规则 + frm.reload_pg(); + } else { + jingrow.msgprint({ + title: __('错误'), + message: r.message ? r.message.message : __('同步防火墙规则失败'), + indicator: 'red' + }); + } + } + }); +}