better-staridc-MNBT
1<?php
2/**
3 * Docker 管理 AJAX 模块(admin/ajax.php 分发)
4 * 指令前缀:docker_*
5 * 依赖:bt_docker(节点容器/配置查询)、docker.member(密码哈希)
6 * 节点独立于 MN_bt,存于 MN_docker_node
7 */
8include_once SYSTEM_ROOT . 'bt_docker.php';
9include_once SYSTEM_ROOT . 'docker.member.php';
10
11/** 根据 MN_docker_node.id 构造 bt_docker 实例 */
12function docker_admin_node_instance($nodeId)
13{
14 global $DB;
15 $node = $DB->get_row_prepare("SELECT * FROM MN_docker_node WHERE id=? limit 1", [(int)$nodeId]);
16 if (!$node) return [null, null];
17 $url = ($node['ptl'] === 'true' ? 'https' : 'http') . '://' . $node['btip'] . ':' . $node['btdk'];
18 return [new bt_docker($url, $node['btmy']), $node];
19}
20
21// ========================================================================
22// Docker 节点管理(独立于 MN_bt)
23// ========================================================================
24
25// ===== 节点列表 =====
26if ($egn === 'docker_node_list') {
27 $rows = $DB->get_all_prepare("SELECT * FROM MN_docker_node ORDER BY id DESC") ?: [];
28 exit(json_encode(['code' => 0, 'msg' => '', 'count' => count($rows), 'data' => $rows], JSON_UNESCAPED_UNICODE));
29}
30
31// ===== 添加节点 =====
32if ($egn === 'docker_node_add') {
33 $name = daddslashes($_POST['name'] ?? '');
34 $btip = daddslashes($_POST['btip'] ?? '');
35 $btdk = daddslashes($_POST['btdk'] ?? '8888');
36 $ptl = daddslashes($_POST['ptl'] ?? 'false');
37 $btmy = daddslashes($_POST['btmy'] ?? '');
38 $ktmy = daddslashes($_POST['ktmy'] ?? '');
39 $qmk = daddslashes($_POST['qmk'] ?? '');
40 $qk = daddslashes($_POST['qk'] ?? 'true');
41 if ($name === '' || $btip === '' || $btmy === '') json_exit('节点名、面板地址、接口密钥不能为空');
42 if ($DB->query_prepare("INSERT INTO MN_docker_node (name,btip,btdk,ptl,btmy,ktmy,qmk,qk,date) VALUES (?,?,?,?,?,?,?,?,?)", [$name, $btip, $btdk, $ptl, $btmy, $ktmy, $qmk, $qk, $date])) {
43 mnbt_log($user, 'Docker节点', '添加节点 ' . $name, '添加成功', $DB);
44 json_exit('添加成功');
45 }
46 json_exit('添加失败:' . $DB->error());
47}
48
49// ===== 编辑节点 =====
50if ($egn === 'docker_node_edit') {
51 $id = (int)($_POST['id'] ?? 0);
52 $name = daddslashes($_POST['name'] ?? '');
53 $btip = daddslashes($_POST['btip'] ?? '');
54 $btdk = daddslashes($_POST['btdk'] ?? '8888');
55 $ptl = daddslashes($_POST['ptl'] ?? 'false');
56 $btmy = daddslashes($_POST['btmy'] ?? '');
57 $ktmy = daddslashes($_POST['ktmy'] ?? '');
58 $qmk = daddslashes($_POST['qmk'] ?? '');
59 $qk = daddslashes($_POST['qk'] ?? 'true');
60 if ($id <= 0) json_exit('参数错误');
61 if ($name === '' || $btip === '' || $btmy === '') json_exit('节点名、面板地址、接口密钥不能为空');
62 if ($DB->query_prepare("UPDATE MN_docker_node SET name=?,btip=?,btdk=?,ptl=?,btmy=?,ktmy=?,qmk=?,qk=? WHERE id=?", [$name, $btip, $btdk, $ptl, $btmy, $ktmy, $qmk, $qk, $id])) {
63 mnbt_log($user, 'Docker节点', '编辑节点 ID' . $id, '编辑成功', $DB);
64 json_exit('编辑成功');
65 }
66 json_exit('编辑失败:' . $DB->error());
67}
68
69// ===== 删除节点 =====
70if ($egn === 'docker_node_del') {
71 $id = (int)($_POST['id'] ?? 0);
72 $inUse = $DB->get_row_prepare("SELECT id FROM MN_docker_user WHERE ssbt=? limit 1", [$id]);
73 if ($inUse) json_exit('该节点下存在用户,无法删除');
74 if ($DB->query_prepare("DELETE FROM MN_docker_node WHERE id=? limit 1", [$id])) {
75 mnbt_log($user, 'Docker节点', '删除节点 ID' . $id, '删除成功', $DB);
76 json_exit('删除成功');
77 }
78 json_exit('删除失败');
79}
80
81// ===== 节点 Docker 配置(检测安装状态)=====
82if ($egn === 'docker_node_config') {
83 $nodeId = (int)($_POST['node_id'] ?? 0);
84 list($bt, ) = docker_admin_node_instance($nodeId);
85 if (!$bt) json_exit('节点不存在');
86 $r = $bt->get_config();
87 exit(json_encode(['code' => 0, 'data' => $r], JSON_UNESCAPED_UNICODE));
88}
89
90// ===== 节点容器列表 =====
91if ($egn === 'docker_node_containers') {
92 $nodeId = (int)($_POST['node_id'] ?? 0);
93 list($bt, ) = docker_admin_node_instance($nodeId);
94 if (!$bt) json_exit('节点不存在');
95 $r = $bt->container_list();
96 exit(json_encode(['code' => 0, 'data' => $r], JSON_UNESCAPED_UNICODE));
97}
98
99// ========================================================================
100// Docker 用户管理
101// ========================================================================
102
103// ===== 用户列表(JOIN 节点名 + 套餐名)=====
104if ($egn === 'docker_user_list') {
105 $rows = $DB->get_all_prepare("SELECT u.*, p.name AS plan_name, n.name AS node_name FROM MN_docker_user u LEFT JOIN MN_docker_plan p ON u.plan_id=p.id LEFT JOIN MN_docker_node n ON u.ssbt=n.id ORDER BY u.id DESC");
106 $list = [];
107 if ($rows) foreach ($rows as $r) {
108 $r['password_hash'] = null;
109 $list[] = $r;
110 }
111 exit(json_encode(['code' => 0, 'msg' => '', 'count' => count($list), 'data' => $list], JSON_UNESCAPED_UNICODE));
112}
113
114// ===== 添加用户 =====
115if ($egn === 'docker_user_add') {
116 $username = daddslashes($_POST['username'] ?? '');
117 $password = (string)($_POST['password'] ?? '');
118 $email = daddslashes($_POST['email'] ?? '');
119 $ssbt = (int)($_POST['ssbt'] ?? 0);
120 $plan_id = (int)($_POST['plan_id'] ?? 0);
121 $datae = daddslashes($_POST['datae'] ?? '0000-00-00');
122 if ($username === '' || $password === '') json_exit('账号和密码不能为空');
123 if ($ssbt <= 0) json_exit('请选择 Docker 节点');
124 $addNode = $DB->get_row_prepare("SELECT id,qk FROM MN_docker_node WHERE id=? limit 1", [$ssbt]);
125 if (!$addNode || $addNode['qk'] !== 'true') json_exit('所选节点不存在或已停用');
126 if ($DB->get_row_prepare("SELECT id FROM MN_docker_user WHERE username=? limit 1", [$username])) json_exit('账号已存在');
127 $hash = docker_auth_password_hash($password);
128 $plan_id = $plan_id > 0 ? $plan_id : null;
129 if ($DB->query_prepare("INSERT INTO MN_docker_user (username,password_hash,email,ssbt,data,datae,qk,plan_id,container_status,created_at) VALUES (?,?,?,?,?,?, 'active',?, 'none',?)", [$username, $hash, $email, $ssbt, $date, $datae, $plan_id, $date])) {
130 mnbt_log($user, 'Docker用户', '添加 Docker 用户 ' . $username, '添加成功', $DB);
131 json_exit('添加成功');
132 }
133 json_exit('添加失败:' . $DB->error());
134}
135
136// ===== 编辑用户 =====
137if ($egn === 'docker_user_edit') {
138 $id = (int)($_POST['id'] ?? 0);
139 $email = daddslashes($_POST['email'] ?? '');
140 $ssbt = (int)($_POST['ssbt'] ?? 0);
141 $plan_id = (int)($_POST['plan_id'] ?? 0);
142 $datae = daddslashes($_POST['datae'] ?? '0000-00-00');
143 $qk = daddslashes($_POST['qk'] ?? 'active');
144 // qk 枚举白名单(install.sql MN_docker_user.qk 注释:active/expired/paused/pruned)
145 if (!in_array($qk, ['active', 'paused', 'expired', 'pruned'], true)) json_exit('状态值非法');
146 // 注意:username 与节点侧容器 service_name/容器命名前缀强绑定,本接口禁止修改(改了会导致容器关联断裂)
147 // 注意:ssbt(所属节点)修改仅转移账户归属,节点上的容器不会自动迁移,修改后需管理员自行在节点间迁移容器
148 if ($id <= 0) json_exit('参数错误');
149 if ($ssbt <= 0) json_exit('请选择 Docker 节点');
150 $plan_id = $plan_id > 0 ? $plan_id : null;
151 if ($DB->query_prepare("UPDATE MN_docker_user SET email=?,ssbt=?,plan_id=?,datae=?,qk=? WHERE id=?", [$email, $ssbt, $plan_id, $datae, $qk, $id])) {
152 mnbt_log($user, 'Docker用户', '编辑 Docker 用户 ID' . $id, '编辑成功', $DB);
153 json_exit('编辑成功');
154 }
155 json_exit('编辑失败:' . $DB->error());
156}
157
158// ===== 删除用户 =====
159if ($egn === 'docker_user_del') {
160 $id = (int)($_POST['id'] ?? 0);
161 $row = $DB->get_row_prepare("SELECT * FROM MN_docker_user WHERE id=? limit 1", [$id]);
162 if (!$row) json_exit('用户不存在');
163 if ($DB->query_prepare("DELETE FROM MN_docker_user WHERE id=? limit 1", [$id])) {
164 mnbt_log($user, 'Docker用户', '删除 Docker 用户 ' . ($row['username'] ?? $id), '删除成功', $DB);
165 json_exit('删除成功');
166 }
167 json_exit('删除失败');
168}
169
170// ===== 重置密码 =====
171if ($egn === 'docker_user_reset') {
172 $id = (int)($_POST['id'] ?? 0);
173 $password = (string)($_POST['password'] ?? '');
174 if ($id <= 0 || $password === '') json_exit('参数错误');
175 $hash = docker_auth_password_hash($password);
176 if ($DB->query_prepare("UPDATE MN_docker_user SET password_hash=? WHERE id=?", [$hash, $id])) {
177 mnbt_log($user, 'Docker用户', '重置 Docker 用户 ID' . $id . ' 密码', '重置成功', $DB);
178 json_exit('重置成功');
179 }
180 json_exit('重置失败');
181}
182
183// ===== 暂停 / 恢复 =====
184if ($egn === 'docker_user_pause' || $egn === 'docker_user_resume') {
185 $id = (int)($_POST['id'] ?? 0);
186 $qk = $egn === 'docker_user_pause' ? 'paused' : 'active';
187 if ($DB->query_prepare("UPDATE MN_docker_user SET qk=? WHERE id=?", [$qk, $id])) {
188 mnbt_log($user, 'Docker用户', ($qk === 'paused' ? '暂停' : '恢复') . ' Docker 用户 ID' . $id, '成功', $DB);
189 json_exit('操作成功');
190 }
191 json_exit('操作失败');
192}
193
194// ========================================================================
195// 套餐管理
196// ========================================================================
197
198if ($egn === 'docker_plan_list') {
199 $rows = $DB->get_all_prepare("SELECT * FROM MN_docker_plan ORDER BY id DESC") ?: [];
200 exit(json_encode(['code' => 0, 'msg' => '', 'count' => count($rows), 'data' => $rows], JSON_UNESCAPED_UNICODE));
201}
202
203if ($egn === 'docker_plan_add') {
204 $name = daddslashes($_POST['name'] ?? '');
205 $jc = daddslashes($_POST['jc'] ?? '');
206 $cpu_max = daddslashes($_POST['cpu_max'] ?? '1');
207 $mem_max = daddslashes($_POST['mem_max'] ?? '512');
208 $disk_max = daddslashes($_POST['disk_max'] ?? '0');
209 $proxy_max = daddslashes($_POST['proxy_max'] ?? '0');
210 $jg = daddslashes($_POST['jg'] ?? '0');
211 $qk = daddslashes($_POST['qk'] ?? 'true');
212 if ($name === '') json_exit('套餐名不能为空');
213 if ($DB->query_prepare("INSERT INTO MN_docker_plan (name,jc,cpu_max,mem_max,disk_max,proxy_max,jg,qk,date) VALUES (?,?,?,?,?,?,?,?,?)", [$name, $jc, $cpu_max, $mem_max, $disk_max, $proxy_max, $jg, $qk, $date])) {
214 mnbt_log($user, 'Docker套餐', '添加套餐 ' . $name, '添加成功', $DB);
215 json_exit('添加成功');
216 }
217 json_exit('添加失败:' . $DB->error());
218}
219
220if ($egn === 'docker_plan_edit') {
221 $id = (int)($_POST['id'] ?? 0);
222 $name = daddslashes($_POST['name'] ?? '');
223 $jc = daddslashes($_POST['jc'] ?? '');
224 $cpu_max = daddslashes($_POST['cpu_max'] ?? '1');
225 $mem_max = daddslashes($_POST['mem_max'] ?? '512');
226 $disk_max = daddslashes($_POST['disk_max'] ?? '0');
227 $proxy_max = daddslashes($_POST['proxy_max'] ?? '0');
228 $jg = daddslashes($_POST['jg'] ?? '0');
229 $qk = daddslashes($_POST['qk'] ?? 'true');
230 if ($id <= 0) json_exit('参数错误');
231 if ($DB->query_prepare("UPDATE MN_docker_plan SET name=?,jc=?,cpu_max=?,mem_max=?,disk_max=?,proxy_max=?,jg=?,qk=? WHERE id=?", [$name, $jc, $cpu_max, $mem_max, $disk_max, $proxy_max, $jg, $qk, $id])) {
232 mnbt_log($user, 'Docker套餐', '编辑套餐 ID' . $id, '编辑成功', $DB);
233 json_exit('编辑成功');
234 }
235 json_exit('编辑失败:' . $DB->error());
236}
237
238if ($egn === 'docker_plan_del') {
239 $id = (int)($_POST['id'] ?? 0);
240 $inUse = $DB->get_row_prepare("SELECT id FROM MN_docker_user WHERE plan_id=? limit 1", [$id]);
241 if ($inUse) json_exit('该套餐下存在用户,无法删除');
242 if ($DB->query_prepare("DELETE FROM MN_docker_plan WHERE id=? limit 1", [$id])) {
243 mnbt_log($user, 'Docker套餐', '删除套餐 ID' . $id, '删除成功', $DB);
244 json_exit('删除成功');
245 }
246 json_exit('删除失败:' . $DB->error());
247}
248
249// ========================================================================
250// 选项数据(节点/套餐下拉,密钥字段不回传)
251// ========================================================================
252if ($egn === 'docker_options') {
253 $nodes = $DB->get_all_prepare("SELECT id,name,btip,btdk,ptl,qk FROM MN_docker_node ORDER BY id") ?: [];
254 $plans = $DB->get_all_prepare("SELECT id,name,cpu_max,mem_max,disk_max,proxy_max,jg,qk FROM MN_docker_plan WHERE qk='true' ORDER BY id") ?: [];
255 exit(json_encode(['code' => 0, 'nodes' => $nodes, 'plans' => $plans], JSON_UNESCAPED_UNICODE));
256}
257
258return; // 本模块未命中指令,交还主分发