mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-10 18:09:25 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4efe740504 | ||
|
|
bde0ed59ad | ||
|
|
19c855790f | ||
|
|
4a90f1b8b0 | ||
|
|
f83bdffed8 | ||
|
|
087cb4fc37 | ||
|
|
66bcd15502 | ||
|
|
29e3dedbe9 | ||
|
|
f10160c239 | ||
|
|
376d09a955 | ||
|
|
9076a3a11a | ||
|
|
57719990d5 | ||
|
|
7073d66662 | ||
|
|
1983d02107 | ||
|
|
b4acb2942f | ||
|
|
c94a662235 | ||
|
|
1d61026dd3 | ||
|
|
48a55e279e | ||
|
|
55e9313711 | ||
|
|
5ab59c3b75 | ||
|
|
9c045b8e85 | ||
|
|
65e87fec1a | ||
|
|
dc8f508ac5 | ||
|
|
ce0c2fb9ea | ||
|
|
d7e70aa701 | ||
|
|
ceacaaf7ae | ||
|
|
36ad902250 | ||
|
|
7a871d3e16 | ||
|
|
f36ba4a351 | ||
|
|
5093265a24 | ||
|
|
9c4347f692 | ||
|
|
cb882ab7a1 | ||
|
|
0d5fd1b423 | ||
|
|
e694635088 | ||
|
|
3386ae2064 | ||
|
|
bbaced5976 | ||
|
|
c0d5c5c0e6 | ||
|
|
f9f7de48ef | ||
|
|
5555eab5c0 | ||
|
|
654737cbd2 | ||
|
|
04568df3df | ||
|
|
b1e8839ace | ||
|
|
80c6f91206 | ||
|
|
315b8e0e48 | ||
|
|
ed295d5456 | ||
|
|
eb38d81674 | ||
|
|
0bc3b42819 | ||
|
|
8a640981d2 | ||
|
|
7b94a61b65 | ||
|
|
e24151f332 | ||
|
|
dc43953c05 | ||
|
|
160ff6a4a7 | ||
|
|
a218ba05d2 | ||
|
|
65cb4941af | ||
|
|
53a12e7c4b | ||
|
|
6db8a906ff | ||
|
|
fc6c86e3ce | ||
|
|
f5989c881d | ||
|
|
b4946a87ee | ||
|
|
562e153371 | ||
|
|
63ea0cc129 | ||
|
|
8eacae7c6a | ||
|
|
3e48c3871a | ||
|
|
22df4cb5b1 | ||
|
|
2d5d954586 | ||
|
|
63ce3805ee | ||
|
|
3fe4918b55 | ||
|
|
24cc733e45 | ||
|
|
1ebb9e1ff3 | ||
|
|
9769f2c190 | ||
|
|
de91e4545b | ||
|
|
8d3c87a25e | ||
|
|
660e393cf1 | ||
|
|
fa5f2d6de5 | ||
|
|
f27406d343 | ||
|
|
488577af68 | ||
|
|
0f7b462b43 | ||
|
|
998f1ceae5 | ||
|
|
2a9bec3fb8 | ||
|
|
5c301296df | ||
|
|
45b0e94132 | ||
|
|
06be751d1a | ||
|
|
f939b03a0b | ||
|
|
3339406f37 | ||
|
|
f32d07ccc9 | ||
|
|
ab8f1623bf | ||
|
|
d467d73230 | ||
|
|
4b0dd7d3fb | ||
|
|
91d243f8b1 | ||
|
|
d682882d25 | ||
|
|
0b3745c933 | ||
|
|
935c3012f9 | ||
|
|
a191548a83 | ||
|
|
9a01d61e1e | ||
|
|
7524798385 | ||
|
|
86e3796524 | ||
|
|
37d68f5ff8 | ||
|
|
647e3904d2 | ||
|
|
c5abb3eea1 | ||
|
|
65c94c64ae | ||
|
|
dbc132951b | ||
|
|
440ba49e7b | ||
|
|
6a0f78b1a0 | ||
|
|
a69ff3e373 | ||
|
|
770d37e575 | ||
|
|
e725ad90ca | ||
|
|
bf5d8f7f27 | ||
|
|
9bc72b23d6 | ||
|
|
3ac3350240 | ||
|
|
c1d04b0a16 | ||
|
|
1962cece21 | ||
|
|
0d24b8aebd | ||
|
|
de50de0a75 | ||
|
|
190fc88d4f | ||
|
|
727a7872a7 | ||
|
|
d408d56826 | ||
|
|
1cccd63edc | ||
|
|
cc50816286 | ||
|
|
04426c7a67 | ||
|
|
3979820eae | ||
|
|
3a850a31a1 | ||
|
|
6f5487b487 | ||
|
|
d09a96ec84 | ||
|
|
dcc4e14e7b | ||
|
|
e947b8db4e | ||
|
|
158a66ab62 | ||
|
|
df596fc673 | ||
|
|
707fd668d5 | ||
|
|
b96c4c00e3 | ||
|
|
bc6cf72cfe | ||
|
|
48dacb4c27 | ||
|
|
78c9abbde2 | ||
|
|
d8d772c6dc | ||
|
|
33e114ffdd | ||
|
|
552b63d329 | ||
|
|
36637260a7 | ||
|
|
53fbb5039b | ||
|
|
74152af289 | ||
|
|
5bf4401fb0 | ||
|
|
12117a3b27 | ||
|
|
d726f1bb15 | ||
|
|
a2b316b4d2 | ||
|
|
0d48e5250a | ||
|
|
d3cd606432 | ||
|
|
600435f23c | ||
|
|
b4831d64b9 | ||
|
|
6638967636 | ||
|
|
ead409a58c | ||
|
|
971da145cb | ||
|
|
055d440484 | ||
|
|
97e2d131b4 | ||
|
|
e2784d2d55 | ||
|
|
6b697ae3be | ||
|
|
207fa1d15e | ||
|
|
454e399d3d | ||
|
|
6ea8f20a9d | ||
|
|
9dc3496c27 | ||
|
|
b523b84609 | ||
|
|
e443b88ad9 | ||
|
|
480ae78579 | ||
|
|
fb31e3ca15 | ||
|
|
53fdaed5c3 | ||
|
|
37f6f2b6bc | ||
|
|
d1028bcc41 | ||
|
|
72e7800b50 | ||
|
|
bb717d2963 | ||
|
|
16787aebd0 | ||
|
|
d769822731 | ||
|
|
b6073ba8d3 | ||
|
|
8d50f75f18 | ||
|
|
8077b4cb13 | ||
|
|
7a9f1ebf5e | ||
|
|
21f5670a85 | ||
|
|
dbd0664c72 | ||
|
|
f9e53164d9 | ||
|
|
62e0321126 | ||
|
|
51b82ecbbb | ||
|
|
0229f50fef | ||
|
|
be176001ea | ||
|
|
3bea21bb94 | ||
|
|
4b3104c849 | ||
|
|
0cbb1ad02e | ||
|
|
221f114dd4 | ||
|
|
5a5c2f3e33 | ||
|
|
69de62f8c3 | ||
|
|
af7698e157 | ||
|
|
f0af84f940 | ||
|
|
4802dde50a | ||
|
|
fcbf7be2b6 | ||
|
|
f77484df84 | ||
|
|
64ccba7595 | ||
|
|
b1935372a1 | ||
|
|
03c9afed4a | ||
|
|
4e63c82e93 | ||
|
|
6fa2fde791 | ||
|
|
98353df1ee | ||
|
|
50978741aa | ||
|
|
d4431f11be | ||
|
|
3faad62dd8 | ||
|
|
6d2550e607 | ||
|
|
f835e4d6a1 | ||
|
|
e33bdc5b7d | ||
|
|
1e6fe01819 | ||
|
|
c522738df5 | ||
|
|
5a8be9de7c | ||
|
|
fd9c860d9b | ||
|
|
306a6d450f | ||
|
|
79fd1d7157 | ||
|
|
9276e811c2 | ||
|
|
d1493ca13f | ||
|
|
13c605d58a | ||
|
|
36d19f2250 | ||
|
|
8f229c99be | ||
|
|
72b16e9540 | ||
|
|
dbe2a1f0df | ||
|
|
4c3f8c095f | ||
|
|
589933dc33 | ||
|
|
de36f41182 | ||
|
|
8e1b4881c4 | ||
|
|
692872ecd6 | ||
|
|
d422a640d5 | ||
|
|
46d293613e | ||
|
|
b775625890 | ||
|
|
eb2bb595de | ||
|
|
0ddc3bf762 | ||
|
|
e45604f211 | ||
|
|
4f22d9ae70 | ||
|
|
732363ec41 | ||
|
|
bc688aa93f | ||
|
|
56ed68b888 | ||
|
|
90539a5049 | ||
|
|
df15100272 | ||
|
|
4bfec3ac06 | ||
|
|
3a80a27970 | ||
|
|
09e79aff63 | ||
|
|
41a36a6fd3 | ||
|
|
fc0974dc91 | ||
|
|
4942c92b33 | ||
|
|
e173c2e51a | ||
|
|
daddf317e2 | ||
|
|
7e919050b2 | ||
|
|
af9d050536 | ||
|
|
a9e6acd407 | ||
|
|
180e67dde9 | ||
|
|
f8451fadba | ||
|
|
558bfcb1ee | ||
|
|
6a27e69ee7 | ||
|
|
b5d28b4ef2 | ||
|
|
8f80336901 | ||
|
|
0a78dda06c | ||
|
|
b6c3020705 | ||
|
|
ed70d4faa3 | ||
|
|
46e4f55105 | ||
|
|
235f0b6d66 | ||
|
|
633066088d | ||
|
|
48f223f4f9 | ||
|
|
709a91dcec | ||
|
|
2592291b49 | ||
|
|
502893194e | ||
|
|
8976e97ea5 | ||
|
|
22cb5f3bc2 | ||
|
|
0888b89ea7 | ||
|
|
738e69562e | ||
|
|
511b62d911 | ||
|
|
d748674b49 | ||
|
|
828372f16f | ||
|
|
a349b2bc81 | ||
|
|
4f3fe2af54 | ||
|
|
4670811fd6 | ||
|
|
e1fb85859a | ||
|
|
c0fc1148eb | ||
|
|
50052e7650 | ||
|
|
8053f9b593 | ||
|
|
1a5cdca70d | ||
|
|
341690d234 | ||
|
|
d76654b853 | ||
|
|
0ef35e1474 | ||
|
|
9ea52e452a | ||
|
|
5e39e1a463 | ||
|
|
36421ae254 | ||
|
|
a34f025a36 | ||
|
|
7be4f9ea98 | ||
|
|
2dc93bf490 | ||
|
|
73fb46fcc0 | ||
|
|
f4ea1dc544 | ||
|
|
d17cc990fe | ||
|
|
8edd40393b | ||
|
|
98e653710c | ||
|
|
3eb6937778 | ||
|
|
974eaf3583 | ||
|
|
dadcc2df6d | ||
|
|
639d5413e5 | ||
|
|
1d114d9db7 | ||
|
|
dfa669a032 | ||
|
|
bf370685b3 | ||
|
|
8f9bdde0a1 | ||
|
|
dbbc32258a | ||
|
|
bf79e3028a | ||
|
|
0650858824 | ||
|
|
83f736d5b2 | ||
|
|
bafee3782a | ||
|
|
1aff003ba3 | ||
|
|
30e779686a | ||
|
|
15eccc72f3 | ||
|
|
f69691fac7 | ||
|
|
1ffcb9ca7d | ||
|
|
75514f8e5c | ||
|
|
098be84816 | ||
|
|
8752e394a3 | ||
|
|
0350f3ecbb | ||
|
|
3c855afc43 | ||
|
|
0c8ec2132f | ||
|
|
e3deac06b4 | ||
|
|
b92dbea2c8 | ||
|
|
4da6738909 | ||
|
|
1665256627 | ||
|
|
d49ebe9fa8 | ||
|
|
6dbdf26d80 | ||
|
|
114ed15c02 | ||
|
|
315eb82a89 | ||
|
|
f4ef03304d | ||
|
|
9877d04979 | ||
|
|
e6f379db9d | ||
|
|
ecad324fc6 | ||
|
|
ed13ee1645 | ||
|
|
603c436f4e | ||
|
|
d917c23fda | ||
|
|
a0c4273280 | ||
|
|
8e71d0a306 | ||
|
|
01dfb6f248 | ||
|
|
4ab1d14ffe | ||
|
|
665fe41014 | ||
|
|
ddba4f3abe | ||
|
|
1f65f80bef | ||
|
|
8dd9f707a6 | ||
|
|
14437611c8 | ||
|
|
bfe857ee59 | ||
|
|
01efa67bf1 | ||
|
|
3b3356d5c6 | ||
|
|
6dbfd385fb | ||
|
|
1e9fa587f5 | ||
|
|
fd673b76e8 | ||
|
|
d2340872c0 | ||
|
|
1c14566b6c | ||
|
|
adde0086aa | ||
|
|
b6ca99f1ef | ||
|
|
c920b46a13 | ||
|
|
338e64d295 | ||
|
|
f030f7a97d | ||
|
|
ef7da2ec96 | ||
|
|
6dec09741f | ||
|
|
6d75a65a09 | ||
|
|
8eeb55d555 | ||
|
|
f54feaa87b | ||
|
|
b828fc2188 | ||
|
|
e645be4285 | ||
|
|
05a7b8818e | ||
|
|
391b313a65 | ||
|
|
df7bff4a72 | ||
|
|
2eefd7d3fa | ||
|
|
130e4cf546 | ||
|
|
096dfa6b96 | ||
|
|
77361259c3 | ||
|
|
cf00bd3d98 | ||
|
|
ad3f42059d | ||
|
|
9a1d3f5e15 | ||
|
|
f2246cf8ba | ||
|
|
81aabd3910 | ||
|
|
235b1dc5e4 | ||
|
|
ad007b07a5 | ||
|
|
53cc020108 | ||
|
|
71d63f3d68 | ||
|
|
917b3f6099 | ||
|
|
36341f66f1 | ||
|
|
2a16e1d262 | ||
|
|
d27db369dc | ||
|
|
6619ae0bc5 | ||
|
|
da1646eaed | ||
|
|
bf88621629 | ||
|
|
7497c4608a | ||
|
|
b0ee844b84 | ||
|
|
3efa46ce70 | ||
|
|
aaaef570a4 | ||
|
|
53c651724a | ||
|
|
dd8c97f4b8 | ||
|
|
b4e1a5947e | ||
|
|
784056d465 | ||
|
|
b1fbdf8d60 | ||
|
|
f9459089a4 | ||
|
|
36c3967e38 | ||
|
|
c7ba5fa2d9 | ||
|
|
5f2f6d15ed | ||
|
|
5e3c81d785 | ||
|
|
76560bc4fd | ||
|
|
e84a104584 | ||
|
|
afe7175941 | ||
|
|
4b7c821a91 | ||
|
|
1941479092 | ||
|
|
bfcfc2015a | ||
|
|
8a5daeb327 | ||
|
|
66049068aa | ||
|
|
e2d680cb2a | ||
|
|
719eec4b98 | ||
|
|
9ea859f94c | ||
|
|
0bdd384f46 | ||
|
|
c3d20f358c | ||
|
|
7a6454e126 | ||
|
|
d683069fef | ||
|
|
5e7e7af1a7 | ||
|
|
5894323eec | ||
|
|
1cd4996527 | ||
|
|
78786a92e9 | ||
|
|
67d5d3fac5 | ||
|
|
5caf8f52bc | ||
|
|
b838caea8b | ||
|
|
57d4ef5fc9 | ||
|
|
ca3d8cccc9 | ||
|
|
c56aa2efa3 | ||
|
|
f41ef634bf | ||
|
|
80e3a73fa4 | ||
|
|
c4788c03f9 | ||
|
|
501012b4e6 | ||
|
|
e7b927bdef | ||
|
|
9c818b0a5d | ||
|
|
8faf553e1d | ||
|
|
e22f296e38 | ||
|
|
b3deeb5a39 | ||
|
|
2ddb4e9ef8 | ||
|
|
74b1d424b9 | ||
|
|
cd13d0bbe7 | ||
|
|
5dc97276c1 | ||
|
|
9da7f04379 | ||
|
|
0bee208795 | ||
|
|
af660daa30 | ||
|
|
71a2b43c06 | ||
|
|
ad644c3cf9 | ||
|
|
e676790250 | ||
|
|
135b307a98 | ||
|
|
c95c760aef | ||
|
|
60125e6bbb | ||
|
|
fbef641839 | ||
|
|
37431a76b6 | ||
|
|
49cfeb7a39 | ||
|
|
faf433b77d | ||
|
|
d0b70841c2 | ||
|
|
bf8a820343 | ||
|
|
ae1e2cd972 | ||
|
|
46da6c0dd0 | ||
|
|
1e827944ab | ||
|
|
09bbd5280d | ||
|
|
01a887efad | ||
|
|
aa236bac0b | ||
|
|
bcc1ae3b8f | ||
|
|
1acc9a4b76 | ||
|
|
e1b57621d5 | ||
|
|
0f9bd8d387 | ||
|
|
24eb4fe994 | ||
|
|
7799d3436a | ||
|
|
f3f1aaa041 | ||
|
|
d7d907945a | ||
|
|
6961ff7996 | ||
|
|
27047cb169 | ||
|
|
25f3b5b18d | ||
|
|
a9efe0f808 | ||
|
|
847a40e743 | ||
|
|
9f59f479a2 | ||
|
|
c8b955f282 | ||
|
|
b4cee43517 | ||
|
|
a33c1261b3 | ||
|
|
8fd3476126 | ||
|
|
664852c26f | ||
|
|
b356ad5a43 | ||
|
|
ce96f54aa7 | ||
|
|
028bfe13ab | ||
|
|
93061a1138 | ||
|
|
66f0b8691c | ||
|
|
22ac89bc2c | ||
|
|
4edf9c1bb7 | ||
|
|
8169f89ddb | ||
|
|
8c82641cb0 | ||
|
|
5e5606a586 | ||
|
|
d4d0538996 | ||
|
|
d03c630b48 | ||
|
|
698b5c2623 | ||
|
|
c9817cb1c6 | ||
|
|
76d2acac76 | ||
|
|
feb58ca3ad | ||
|
|
2748d248b4 | ||
|
|
e008de3d2c | ||
|
|
57c9ca8e78 | ||
|
|
db90443239 | ||
|
|
883ce06c1c | ||
|
|
9c9b0b9ae5 | ||
|
|
dd8341867f | ||
|
|
15e6ca97e1 | ||
|
|
1996cb03ce | ||
|
|
7d0834397d | ||
|
|
54055f2174 | ||
|
|
33c77f0e90 | ||
|
|
7d4c4a9ef9 | ||
|
|
fbe211b3ec | ||
|
|
53e98bd5fe | ||
|
|
8a7be7e61c | ||
|
|
4aad9f90db | ||
|
|
29de642a1a | ||
|
|
e73533b611 | ||
|
|
89e5d57926 | ||
|
|
283d3c5f1f | ||
|
|
69cde4ebc3 | ||
|
|
e5a9f2c197 | ||
|
|
b3f495efb8 | ||
|
|
c0310a2628 | ||
|
|
496e94ad54 | ||
|
|
beb00d46e0 | ||
|
|
9e123f067b | ||
|
|
aba594caf2 | ||
|
|
f67be6d59f | ||
|
|
bb5240dc43 | ||
|
|
e24bf5313c | ||
|
|
f17a986461 | ||
|
|
2c31318a5c | ||
|
|
7c4231d9c0 | ||
|
|
462f7b78ec | ||
|
|
83466e927e | ||
|
|
d8123d9350 | ||
|
|
23c3b553e9 | ||
|
|
9c2129e638 | ||
|
|
a29b2ac731 | ||
|
|
944040cc03 | ||
|
|
9d9615acc9 | ||
|
|
e3f42c8f67 | ||
|
|
6e9dbe4bd5 | ||
|
|
e71329485a | ||
|
|
5d0e24f0d5 | ||
|
|
78263f6a06 | ||
|
|
ce70fdc784 | ||
|
|
184610acb9 | ||
|
|
1b668d546f | ||
|
|
b7df4f57ad | ||
|
|
817e7607e5 | ||
|
|
d36df7b24c | ||
|
|
e63a643c7b | ||
|
|
0cfd2fc971 | ||
|
|
9b3383dd0e | ||
|
|
9b266ffd7d | ||
|
|
345a5be488 | ||
|
|
0a178f196a | ||
|
|
8abc166dd2 | ||
|
|
a3e0fe817b | ||
|
|
7ab4572bdd | ||
|
|
165f6ee323 | ||
|
|
e565390d5b | ||
|
|
7502fb7e08 | ||
|
|
026f191de2 | ||
|
|
6d7b58e65c | ||
|
|
6953140238 | ||
|
|
97963a67aa | ||
|
|
1112e31a5f | ||
|
|
5358191adf | ||
|
|
4f52e4a520 | ||
|
|
abcabeb2a1 | ||
|
|
c592086d29 | ||
|
|
f93dd8ebec | ||
|
|
92283d1cfc | ||
|
|
f29b15dd60 | ||
|
|
84f2d212f4 | ||
|
|
5fb00f7108 | ||
|
|
fcea7a0610 | ||
|
|
f9b364c435 | ||
|
|
e9743ce97e | ||
|
|
8c2475192b | ||
|
|
35c279d93a | ||
|
|
7c5a7fe822 | ||
|
|
09ee8a0c61 | ||
|
|
7bda3c0cd6 | ||
|
|
d8a5fcab90 | ||
|
|
1d8bc48a9b | ||
|
|
2d39f431c5 | ||
|
|
b78cbb3c39 | ||
|
|
d55450e0c9 | ||
|
|
7cc10a9bdb | ||
|
|
fdebeab6b2 | ||
|
|
fdc1a93e51 | ||
|
|
e9978642c8 | ||
|
|
823c6f1f79 | ||
|
|
7bbb49a459 | ||
|
|
2bbbe3f17f | ||
|
|
9e8d036ee7 | ||
|
|
7ee6e491e8 | ||
|
|
10ffa66dd8 | ||
|
|
85d2f2f702 | ||
|
|
0917ec52de | ||
|
|
da872c1d92 | ||
|
|
91919426f4 | ||
|
|
7f7196c55e | ||
|
|
cb86245a35 | ||
|
|
a319c43d54 | ||
|
|
d07faf396e | ||
|
|
fc718ff727 | ||
|
|
bacac94186 | ||
|
|
c925e09ea6 | ||
|
|
2de9b736f5 | ||
|
|
24d3aeabb0 | ||
|
|
3a33a4c758 | ||
|
|
109f562f06 | ||
|
|
f74702cbad | ||
|
|
be9365e4e6 | ||
|
|
6a61e66c05 | ||
|
|
42d07c1cec | ||
|
|
3886dab6b5 | ||
|
|
d17ebf1e9c | ||
|
|
a6644cc706 | ||
|
|
43071db317 | ||
|
|
e5c53323a5 | ||
|
|
d08ba45f5f | ||
|
|
eba73c71bc | ||
|
|
fe63f684f3 | ||
|
|
f19ef94dca | ||
|
|
685aa7868d | ||
|
|
2e927da78c | ||
|
|
4391a3ccd7 | ||
|
|
27041ee0e0 | ||
|
|
e09085a64c | ||
|
|
8216000f35 | ||
|
|
36d59c6c67 | ||
|
|
363f97119c | ||
|
|
f86980b805 | ||
|
|
805b804a10 | ||
|
|
2f22cdb36e | ||
|
|
7254b9b862 | ||
|
|
ad9ab2d7af | ||
|
|
c8c4a0dbbe | ||
|
|
f425fb1ea2 | ||
|
|
970c6dbe54 | ||
|
|
3f529ac798 | ||
|
|
4be2f60b5b | ||
|
|
305b9ca7cf | ||
|
|
fdf0c4e02f | ||
|
|
52dc2210a4 | ||
|
|
579b118495 | ||
|
|
0fac1b026b | ||
|
|
a0c891ed92 | ||
|
|
98f3ad52dd | ||
|
|
ada1aeac05 | ||
|
|
272d71ed97 | ||
|
|
1a69d55da1 | ||
|
|
8a4174a8a4 | ||
|
|
7d58ba316d | ||
|
|
d4af727e5a | ||
|
|
3a8c93b595 | ||
|
|
25fe2e79bb | ||
|
|
84ebfc4254 | ||
|
|
2bdba8aa8d | ||
|
|
60be806398 | ||
|
|
b919de1fd6 | ||
|
|
087dcc7f40 | ||
|
|
be2cfa4407 | ||
|
|
e86707d752 | ||
|
|
b31c49ac11 | ||
|
|
d013595431 | ||
|
|
9e9dad7325 | ||
|
|
1f52d69410 | ||
|
|
5a221d9cb3 | ||
|
|
4abd1df942 | ||
|
|
ee84266acb | ||
|
|
4fadf4c275 | ||
|
|
89b5a762d1 | ||
|
|
759e1432f8 | ||
|
|
d3e9fbb5db | ||
|
|
e3c60de0e7 | ||
|
|
1cd7667f7b | ||
|
|
d0ac8bd70c | ||
|
|
89e20482a0 | ||
|
|
9036d88fab | ||
|
|
919ca8ed83 | ||
|
|
e41055443e | ||
|
|
ad15bb303f | ||
|
|
a6e0af5672 | ||
|
|
dbd3c86970 | ||
|
|
7659e654a9 | ||
|
|
32c74fd85d | ||
|
|
383fd3b068 | ||
|
|
d8aed860a7 | ||
|
|
68a8751137 | ||
|
|
bb0f0ced62 | ||
|
|
04ce9541a2 | ||
|
|
2be2565736 | ||
|
|
b5776f903f | ||
|
|
5052ea11b0 | ||
|
|
a578eeef01 | ||
|
|
d1dcbcb0d6 | ||
|
|
0916e96448 | ||
|
|
7616acccb9 | ||
|
|
2499c296e7 | ||
|
|
ceb41fef68 | ||
|
|
aaaefdb996 | ||
|
|
0bef98d83e | ||
|
|
a21ac3fa6c | ||
|
|
de9fdd6e87 | ||
|
|
6991a3ecfc | ||
|
|
863b42800b | ||
|
|
3bf83a6202 | ||
|
|
ee6e6f8286 | ||
|
|
7370ef9816 | ||
|
|
8572b93ed0 | ||
|
|
337ba1fa1e | ||
|
|
1ad11de98e | ||
|
|
a9aaf268fc | ||
|
|
d618f36f89 | ||
|
|
929ead12bc | ||
|
|
89991b8417 | ||
|
|
af8f9fb1a9 | ||
|
|
4a09695343 | ||
|
|
5aead0ad7c | ||
|
|
8324a89edb | ||
|
|
de6ed476fb | ||
|
|
9342e31faf | ||
|
|
061c2d86eb | ||
|
|
1937a6344e | ||
|
|
5e91ac8fe9 | ||
|
|
ff32ab721f | ||
|
|
8d213a2444 | ||
|
|
ca10177754 | ||
|
|
7cbabaa04b | ||
|
|
805bd0a3ad | ||
|
|
cf003d9f62 | ||
|
|
2e22b7307c | ||
|
|
4d346dd6c8 | ||
|
|
35a7025530 | ||
|
|
9ad51c81d8 | ||
|
|
30da2fe60d | ||
|
|
b16ca19ca8 | ||
|
|
986687b829 | ||
|
|
0cec515297 | ||
|
|
e54ea53017 | ||
|
|
755901b4ca | ||
|
|
90d0d3ba72 | ||
|
|
f65a8a24e0 | ||
|
|
2c7d50e3bc | ||
|
|
91a71a1eb3 | ||
|
|
875acda8a5 | ||
|
|
52e138ae56 | ||
|
|
a769623a24 | ||
|
|
d7a4e1d4be | ||
|
|
057e152845 | ||
|
|
f80ac8e9f0 | ||
|
|
aceb26e309 | ||
|
|
1d078a63ca | ||
|
|
f0ba3d58d6 | ||
|
|
14f2fad644 | ||
|
|
58f0cd69b7 | ||
|
|
9326138c6e | ||
|
|
ceffb49d61 | ||
|
|
a4e2b2d8b4 | ||
|
|
1ba42fdc4b | ||
|
|
b0ab2e28cb | ||
|
|
2471784d1f | ||
|
|
78049fa34f | ||
|
|
09c25924fe | ||
|
|
e8e2487f27 | ||
|
|
cf930aeca1 | ||
|
|
e6d380c321 | ||
|
|
065b6430f2 | ||
|
|
e1c03474eb | ||
|
|
3aef5f7bbf | ||
|
|
cebeb7fe90 | ||
|
|
c5d8166a2a | ||
|
|
ff30de33ab | ||
|
|
7700eb92ec | ||
|
|
0c8f84e81f | ||
|
|
245d026726 | ||
|
|
1ac8bf51f2 | ||
|
|
248e6b1e0e | ||
|
|
6ff5d4128b | ||
|
|
82e39f6be4 | ||
|
|
780dfb08a3 | ||
|
|
dd586576a7 | ||
|
|
c77efccd19 | ||
|
|
962b0fa9c5 | ||
|
|
5532dcd968 | ||
|
|
ce2d060c94 | ||
|
|
3c388ada21 | ||
|
|
c81ddebcd4 | ||
|
|
9ff01c3cfb | ||
|
|
6a981e1e8f | ||
|
|
3643d63a90 | ||
|
|
8560880944 | ||
|
|
4210bb87a9 | ||
|
|
6473d68421 | ||
|
|
009b599831 | ||
|
|
1c4536980c | ||
|
|
9b62a46312 | ||
|
|
bb100b6bf2 | ||
|
|
81fba581bd | ||
|
|
36cc799c1a | ||
|
|
6d64401e22 | ||
|
|
8e81f423f9 | ||
|
|
ea4677b2c4 | ||
|
|
774cf403f1 | ||
|
|
3e3e53e58b | ||
|
|
e0678c8b4c | ||
|
|
c0bdf2659f | ||
|
|
ae3cc4bd0b | ||
|
|
0f8c9ee740 | ||
|
|
4bc4ff5eda | ||
|
|
7568bd10d8 | ||
|
|
28410d2bf5 | ||
|
|
c56246a9d7 | ||
|
|
5770c6d3c5 | ||
|
|
b9fed0b6e9 | ||
|
|
899e58500e | ||
|
|
c6a8841a91 | ||
|
|
40e8393c43 | ||
|
|
ec3d29fc2b | ||
|
|
fba632c393 | ||
|
|
5dec539d40 | ||
|
|
0119e72771 | ||
|
|
c1ffb36642 | ||
|
|
29d8779233 | ||
|
|
6e9a26c331 | ||
|
|
e2a491ab97 | ||
|
|
f1fb16366c | ||
|
|
29ffc62b7c | ||
|
|
f0d8f12f89 | ||
|
|
ef36d8729e | ||
|
|
28bf685e73 | ||
|
|
3f424668a7 | ||
|
|
dfa53c4c4c | ||
|
|
0b712c7242 | ||
|
|
101792a081 | ||
|
|
0055fa98fa | ||
|
|
52a8cc6946 | ||
|
|
3da1ff214f | ||
|
|
ed509e2d8d | ||
|
|
5dfc0f7ebb | ||
|
|
1129d5753a | ||
|
|
0c48e0fcbb | ||
|
|
6a28e72273 | ||
|
|
82fc1a3609 | ||
|
|
73ff1c664e | ||
|
|
9093d4bc3f | ||
|
|
d50936349c | ||
|
|
20d85d0bd7 | ||
|
|
fc904c9a5d | ||
|
|
59e616919f | ||
|
|
3447c1e48f | ||
|
|
d7c6879d2f | ||
|
|
c0240836f7 | ||
|
|
99c6c26859 | ||
|
|
7b0e65de42 | ||
|
|
29c737121b | ||
|
|
318d123015 | ||
|
|
093f8b14f8 | ||
|
|
2f48df6013 | ||
|
|
7f42ee741c | ||
|
|
abfb92eaa5 | ||
|
|
3f8a822d5e | ||
|
|
f9bec73252 | ||
|
|
a9530b0630 | ||
|
|
33fe1095d7 | ||
|
|
ae5a947898 | ||
|
|
b1128cbddb | ||
|
|
ead8de6e0f | ||
|
|
caf3924b09 | ||
|
|
526caf0497 | ||
|
|
c20dc4af94 | ||
|
|
be500c898e | ||
|
|
d2ccea3520 | ||
|
|
051f992e91 | ||
|
|
af6b96d18b | ||
|
|
996786a7b7 | ||
|
|
42bedca172 | ||
|
|
51e3d26492 | ||
|
|
5ff6ee2763 | ||
|
|
64f0ff8ad9 | ||
|
|
7a6f4323d2 | ||
|
|
f927914ff1 | ||
|
|
02ad9c95ee | ||
|
|
4d9c102e8b | ||
|
|
ebb53ada1d | ||
|
|
87f4307655 | ||
|
|
21cf48b08b | ||
|
|
dd6d9cf09a | ||
|
|
e0e889bbff | ||
|
|
18b36b08a7 | ||
|
|
1389280a70 | ||
|
|
8bc9500b23 | ||
|
|
49a358ccfa | ||
|
|
c9bf5f59f4 | ||
|
|
577e5f3512 | ||
|
|
343b815823 | ||
|
|
3819e2f470 | ||
|
|
0e5f762919 | ||
|
|
e9eab63e99 | ||
|
|
be43b537cc | ||
|
|
6b85710504 | ||
|
|
c2d89a91ab | ||
|
|
682f8309c4 | ||
|
|
586302b575 | ||
|
|
4af7183dbd | ||
|
|
a488f106ca | ||
|
|
f05de84dc2 | ||
|
|
fe4c95276d | ||
|
|
abc6e8f597 | ||
|
|
0fc03c81db | ||
|
|
8a6dbf22c0 | ||
|
|
8c18023f64 | ||
|
|
fd521eff3f | ||
|
|
55f8e3fd72 | ||
|
|
1a26224b6f | ||
|
|
f9ab290d07 | ||
|
|
70a30412a5 | ||
|
|
ed63341750 | ||
|
|
81fea53bc7 | ||
|
|
eab194f5d1 | ||
|
|
0b5299dbe0 | ||
|
|
e5f399e700 | ||
|
|
f7ee3a9aed | ||
|
|
aa60d52662 | ||
|
|
9249ed7896 | ||
|
|
a470b3c53c | ||
|
|
0851e95fb2 |
+2
-1
@@ -110,7 +110,6 @@ tmp/*
|
||||
*.zip
|
||||
logs/*
|
||||
data/*.db
|
||||
data/control.conf
|
||||
data/iplist.txt
|
||||
data/json/index.json
|
||||
data/json/config.json
|
||||
@@ -159,6 +158,7 @@ data/unauthorized_status.pl
|
||||
plugins/vip_*
|
||||
plugins/own_*
|
||||
plugins/my_*
|
||||
plugins/op_auth
|
||||
plugins/l2tp
|
||||
plugins/openlitespeed
|
||||
plugins/tamper_proof
|
||||
@@ -171,6 +171,7 @@ plugins/fastdfs
|
||||
plugins/v2ray
|
||||
plugins/frp
|
||||
plugins/file_search
|
||||
plugins/proxysql
|
||||
debug.out
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
基本上可以使用,后续会继续优化!欢迎提供意见!
|
||||
|
||||
- 吹水组 - https://t.me/mdserver_web
|
||||
- 交流论坛 - https://bbs.midoks.me
|
||||
- 交流论坛 - https://bbs.midoks.icu
|
||||
|
||||
```
|
||||
如果出现问题,最好私给我面板信息。不要让我猜。如果不提供,不要提出问题,自行解决。 — 座右铭
|
||||
@@ -37,12 +37,12 @@ Talk is cheap, show me the code. -- linus
|
||||
```
|
||||
|
||||
- [兼容性测试报告](/compatibility.md)
|
||||
- [常用命令说明](/cmd.md)
|
||||
- [常用命令说明](/cmd.md) [ mw default ]
|
||||
|
||||
### 主要插件介绍
|
||||
|
||||
* OpenResty - 轻量级,占有内存少,并发能力强。
|
||||
* PHP[53-82] - PHP是世界上最好的编程语言。
|
||||
* PHP[53-83] - PHP是世界上最好的编程语言。
|
||||
* MySQL - 一种关系数据库管理系统。
|
||||
* MariaDB - 是MySQL的一个重要分支。
|
||||
* MySQL[APT/YUM] - 一种关系数据库管理系统。
|
||||
@@ -66,6 +66,10 @@ Talk is cheap, show me the code. -- linus
|
||||
- 插件地址 - https://github.com/mw-plugin
|
||||
- 开发文档 - https://github.com/midoks/mdserver-web/wiki/插件开发
|
||||
|
||||
## 其他插件
|
||||
|
||||
- OP鉴权 - https://github.com/mw-plugin/op_auth
|
||||
|
||||
|
||||
# Note
|
||||
|
||||
@@ -74,13 +78,19 @@ phpMyAdmin[4.4.15]支持MySQL[5.5-5.7]
|
||||
phpMyAdmin[5.2.0]支持MySQL[8.0]
|
||||
|
||||
PHP[53-72]支持phpMyAdmin[4.4.15]
|
||||
PHP[72-82]支持phpMyAdmin[5.2.0]
|
||||
PHP[72-83]支持phpMyAdmin[5.2.0]
|
||||
```
|
||||
|
||||
# 郑重声明
|
||||
|
||||
不卖、不会监控(统计使用除外)、更不会注入病毒,大家使用方便(望大家不吝捐赠)。
|
||||
|
||||
- https://www.youtube.com/watch?v=2taa5K-Jmmw
|
||||
|
||||
|
||||
# 特别赞助
|
||||
|
||||
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.pw/)
|
||||
- [鲲鹏vpn,免费试用,解锁流媒体和chatGPT](https://down.xbjc888.top/?agent_code=github)
|
||||
|
||||
# AD - VPS推荐 - 🙏
|
||||
|
||||
@@ -92,22 +102,23 @@ PHP[72-82]支持phpMyAdmin[5.2.0]
|
||||
|
||||
# Docker
|
||||
|
||||
- 由[DDSRem](https://github.com/DDSRem)开发维护。
|
||||
- https://hub.docker.com/r/ddsderek/mw
|
||||
- 由[DDS-Derek](https://github.com/DDS-Derek)开发维护。
|
||||
- https://github.com/DDS-Derek/mdserver-web-Docker
|
||||
|
||||
```
|
||||
docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:443 -p 888:888 ddsderek/mw-server:latest
|
||||
```
|
||||
|
||||
|
||||
### 版本更新 0.16.1
|
||||
### 版本更新 0.16.3
|
||||
|
||||
* 给防盗链增加禁止空来源。
|
||||
* OpenResty安装兼容。
|
||||
* Debian10安装优化。
|
||||
* 安装时默认监控开启。
|
||||
* MySQL/MYSQL-YUM/MySQL-APT添加重置master功能。
|
||||
* 支持华为欧拉系统。
|
||||
* 面板配置-可以配置时区。
|
||||
* PHP(GD)扩展安装优化。
|
||||
* PHP界面功能调整。
|
||||
* PHP-FPM设置多个应用池(提高高并发稳定性)。
|
||||
* MySQL(apt/yum)调整优化。
|
||||
* 网站类型优化。
|
||||
* 增加数据管理插件。
|
||||
|
||||
### JSDelivr安装地址
|
||||
|
||||
@@ -135,7 +146,7 @@ wget --no-check-certificate -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/m
|
||||
|
||||
```
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | bash
|
||||
curl --insecure -fsSL https://code.midoks.me/midoks/mdserver-web/raw/branch/master/scripts/install.sh | bash
|
||||
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/master/scripts/install.sh | bash
|
||||
```
|
||||
|
||||
- 直接更新
|
||||
@@ -172,8 +183,8 @@ wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/mi
|
||||
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh | bash
|
||||
|
||||
curl --insecure -fsSL https://code.midoks.me/midoks/mdserver-web/raw/branch/dev/scripts/install_dev.sh | bash
|
||||
curl --insecure -fsSL https://code.midoks.me/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh | bash
|
||||
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/install_dev.sh | bash
|
||||
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh | bash
|
||||
```
|
||||
|
||||
### 捐赠地址 USDT(TRC20)
|
||||
|
||||
@@ -123,6 +123,11 @@ class cert_api:
|
||||
return True
|
||||
|
||||
def createCertCron(self):
|
||||
|
||||
if mw.isAppleSystem():
|
||||
print('在Macos上不支持创建证书自动续签任务!')
|
||||
return ''
|
||||
|
||||
# 创建证书自动续签任务
|
||||
try:
|
||||
import crontab_api
|
||||
|
||||
+1
-24
@@ -32,12 +32,11 @@ from flask import redirect
|
||||
|
||||
|
||||
def init():
|
||||
initSystemControl()
|
||||
initDB()
|
||||
initDBSshPort()
|
||||
initUserInfo()
|
||||
initInitD()
|
||||
initInitTask()
|
||||
return True
|
||||
|
||||
|
||||
def local():
|
||||
@@ -64,17 +63,6 @@ def initDB():
|
||||
print(str(ex))
|
||||
|
||||
|
||||
def initDBSshPort():
|
||||
# SSH端口必须放开
|
||||
import firewall_api
|
||||
cmd_data = mw.execShell(
|
||||
"cat /etc/ssh/sshd_config | grep '^Port \d*' | tail -1")
|
||||
ssh_port = cmd_data[0].replace("Port ", '').strip()
|
||||
if ssh_port == '':
|
||||
ssh_port = '22'
|
||||
firewall_api.firewall_api().addAcceptPortArgs(ssh_port, 'SSH远程管理服务', 'port')
|
||||
|
||||
|
||||
def doContentReplace(src, dst):
|
||||
content = mw.readFile(src)
|
||||
content = content.replace("{$SERVER_PATH}", mw.getRunDir())
|
||||
@@ -146,17 +134,6 @@ def initInitTask():
|
||||
api.createCertCron()
|
||||
|
||||
|
||||
def initSystemControl():
|
||||
path = 'data/default.db'
|
||||
if os.path.exists(path):
|
||||
return False
|
||||
|
||||
import system_api
|
||||
sapi = system_api.system_api()
|
||||
r = sapi.setControl(1, 30)
|
||||
print(r)
|
||||
|
||||
|
||||
def initUserInfo():
|
||||
|
||||
data = mw.M('users').where('id=?', (1,)).getField('password')
|
||||
|
||||
@@ -20,6 +20,7 @@ import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
import pytz
|
||||
|
||||
from flask import session
|
||||
from flask import request
|
||||
@@ -27,7 +28,7 @@ from flask import request
|
||||
|
||||
class config_api:
|
||||
|
||||
__version = '0.16.1'
|
||||
__version = '0.16.3'
|
||||
__api_addr = 'data/api.json'
|
||||
|
||||
def __init__(self):
|
||||
@@ -911,6 +912,21 @@ class config_api:
|
||||
data['status_code_msg'] = "默认-安全入口错误提示"
|
||||
return data
|
||||
|
||||
|
||||
def getTimezoneListApi(self):
|
||||
# 获取时区列表
|
||||
# pytz.all_timezones | 所有
|
||||
# pytz.common_timezones
|
||||
return pytz.all_timezones
|
||||
|
||||
def setTimezoneApi(self):
|
||||
# 设置时区列表
|
||||
timezone = request.form.get('timezone', '').strip()
|
||||
cmd = 'timedatectl set-timezone "'+timezone+'"'
|
||||
mw.execShell(cmd)
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
|
||||
def get(self):
|
||||
|
||||
data = {}
|
||||
|
||||
@@ -283,6 +283,9 @@ class crontab_api:
|
||||
return mw.returnJson(is_check_pass, msg)
|
||||
|
||||
addData = self.add(params)
|
||||
if type(addData) == str:
|
||||
return addData
|
||||
|
||||
if addData > 0:
|
||||
return mw.returnJson(True, '添加成功')
|
||||
return mw.returnJson(False, '添加失败')
|
||||
|
||||
+56
-6
@@ -87,6 +87,12 @@ class files_api:
|
||||
path = request.form.get('path', '')
|
||||
return self.unzip(sfile, dfile, stype, path)
|
||||
|
||||
def uncompressApi(self):
|
||||
sfile = request.form.get('sfile', '')
|
||||
dfile = request.form.get('dfile', '')
|
||||
path = request.form.get('path', '')
|
||||
return self.uncompress(sfile, dfile, path)
|
||||
|
||||
# 移动文件或目录
|
||||
def mvFileApi(self):
|
||||
sfile = request.form.get('sfile', '')
|
||||
@@ -801,7 +807,7 @@ class files_api:
|
||||
if path.find("web_conf") > 0:
|
||||
mw.restartWeb()
|
||||
|
||||
mw.writeLog('文件管理', '文件保存成功', (path,))
|
||||
mw.writeLog('文件管理', '文件[{1}]保存成功', (path,))
|
||||
return mw.returnJson(True, '文件保存成功')
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, '文件保存错误:' + str(ex))
|
||||
@@ -825,15 +831,59 @@ class files_api:
|
||||
mw.execShell("cd '" + path + "' && tar -zcvf '" +
|
||||
dfile + "' " + sfiles + " > " + tmps + " 2>&1")
|
||||
self.setFileAccept(dfile)
|
||||
mw.writeLog("文件管理", '文件压缩成功!', (sfile, dfile))
|
||||
mw.writeLog("文件管理", '文件[{1}]压缩[{2}]成功!', (sfile, dfile))
|
||||
return mw.returnJson(True, '文件压缩成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '文件压缩失败!')
|
||||
|
||||
def unzip(self, sfile, dfile, stype, path):
|
||||
|
||||
def uncompress(self, sfile, dfile, path):
|
||||
if not os.path.exists(sfile):
|
||||
return mw.returnMsg(False, '指定文件不存在!')
|
||||
return mw.returnJson(False, '指定文件不存在!')
|
||||
|
||||
filename = os.path.basename(sfile)
|
||||
extension = os.path.splitext(filename)[-1]
|
||||
extension = extension.strip('.')
|
||||
|
||||
tar_gz = 'tar.gz'
|
||||
tar_gz_len = len(tar_gz)
|
||||
suffix_gz = sfile[-tar_gz_len:]
|
||||
if suffix_gz == tar_gz:
|
||||
extension = suffix_gz
|
||||
|
||||
if not extension in ['tar.gz', 'gz', 'zip', 'rar']:
|
||||
return mw.returnJson(False, '现在仅支持gz,zip,rar格式解压!')
|
||||
|
||||
if mw.isAppleSystem() and extension == 'rar':
|
||||
return mw.returnJson(False, 'macosx暂时不支持rar格式解压')
|
||||
|
||||
try:
|
||||
tmps = mw.getRunDir() + '/tmp/panelExec.log'
|
||||
if extension == 'zip':
|
||||
cmd = "cd " + path + " && unzip -o -d '" + dfile + \
|
||||
"' '" + sfile + "' > " + tmps + " 2>&1 &"
|
||||
mw.execShell(cmd)
|
||||
if extension == 'tar.gz':
|
||||
cmd = "cd " + path + " && tar -zxvf " + sfile + \
|
||||
" -C " + dfile + " > " + tmps + " 2>&1 &"
|
||||
mw.execShell(cmd)
|
||||
if extension == 'gz':
|
||||
cmd = "cd " + path + " && gunzip -k " + sfile + " > " + tmps + " 2>&1 &"
|
||||
mw.execShell(cmd)
|
||||
if extension == 'rar':
|
||||
cmd = "cd " + path + " && unrar x " + sfile + \
|
||||
" " + dfile + " > " + tmps + " 2>&1 &"
|
||||
mw.execShell(cmd)
|
||||
|
||||
if os.path.exists(dfile):
|
||||
self.setFileAccept(dfile)
|
||||
mw.writeLog("文件管理", '文件[{1}]解压[{2}]成功!', (sfile, dfile))
|
||||
return mw.returnJson(True, '文件解压成功!')
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '文件解压失败!:' + str(e))
|
||||
|
||||
def unzip(self, sfile, dfile, stype, path):
|
||||
if not os.path.exists(sfile):
|
||||
return mw.returnJson(False, '指定文件不存在!')
|
||||
|
||||
try:
|
||||
tmps = mw.getRunDir() + '/tmp/panelExec.log'
|
||||
@@ -850,7 +900,7 @@ class files_api:
|
||||
" -C " + dfile + " > " + tmps + " 2>&1 &")
|
||||
|
||||
self.setFileAccept(dfile)
|
||||
mw.writeLog("文件管理", '文件解压成功!', (sfile, dfile))
|
||||
mw.writeLog("文件管理", '文件[{1}]解压[{2}]成功!', (sfile, dfile))
|
||||
return mw.returnJson(True, '文件解压成功!')
|
||||
except:
|
||||
return mw.returnJson(False, '文件解压失败!')
|
||||
|
||||
+98
-37
@@ -84,12 +84,13 @@ class firewall_api:
|
||||
port = request.form.get('port', '').strip()
|
||||
ps = request.form.get('ps', '').strip()
|
||||
stype = request.form.get('type', '').strip()
|
||||
protocol = request.form.get('protocol', '').strip()
|
||||
|
||||
data = self.addAcceptPortArgs(port, ps, stype)
|
||||
data = self.addAcceptPortArgs(port, ps, stype, protocol)
|
||||
return mw.getJson(data)
|
||||
|
||||
# 添加放行端口
|
||||
def addAcceptPortArgs(self, port, ps, stype):
|
||||
def addAcceptPortArgs(self, port, ps, stype, protocol='tcp'):
|
||||
import re
|
||||
import time
|
||||
|
||||
@@ -103,12 +104,13 @@ class firewall_api:
|
||||
if mw.M('firewall').where("port=?", (port,)).count() > 0:
|
||||
return mw.returnData(False, '您要放行的端口已存在,无需重复放行!')
|
||||
|
||||
msg = mw.getInfo('放行端口[{1}]成功', (port,))
|
||||
msg = mw.getInfo('放行端口[{1}][{2}]成功', (port, protocol,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
mw.M('firewall').add('port,ps,addtime', (port, ps, addtime))
|
||||
mw.M('firewall').add('port,protocol,ps,addtime',
|
||||
(port, protocol, ps, addtime))
|
||||
|
||||
self.addAcceptPort(port)
|
||||
self.addAcceptPort(port, protocol)
|
||||
self.firewallReload()
|
||||
return mw.returnData(True, '添加放行(' + port + ')端口成功!')
|
||||
|
||||
@@ -139,32 +141,64 @@ class firewall_api:
|
||||
self.firewallReload()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
|
||||
# 删除放行端口
|
||||
def delAcceptPortApi(self):
|
||||
port = request.form.get('port', '').strip()
|
||||
sid = request.form.get('id', '').strip()
|
||||
mw_port = mw.readFile('data/port.pl')
|
||||
try:
|
||||
if(port == mw_port):
|
||||
return mw.returnJson(False, '失败,不能删除当前面板端口!')
|
||||
if self.__isUfw:
|
||||
def delAcceptPortArgs(self, port, protocol='tcp'):
|
||||
if self.__isUfw:
|
||||
if protocol == 'tcp':
|
||||
mw.execShell('ufw delete allow ' + port + '/tcp')
|
||||
elif self.__isFirewalld:
|
||||
port = port.replace(':', '-')
|
||||
if protocol == 'udp':
|
||||
mw.execShell('ufw delete allow ' + port + '/udp')
|
||||
if protocol == 'tcp/udp':
|
||||
mw.execShell('ufw delete allow ' + port + '/tcp')
|
||||
mw.execShell('ufw delete allow ' + port + '/udp')
|
||||
elif self.__isFirewalld:
|
||||
port = port.replace(':', '-')
|
||||
if protocol == 'tcp':
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
|
||||
if protocol == 'udp':
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
|
||||
if protocol == 'tcp/udp':
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
|
||||
mw.execShell(
|
||||
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
|
||||
elif self.__isIptables:
|
||||
elif self.__isIptables:
|
||||
if protocol == 'tcp':
|
||||
mw.execShell(
|
||||
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
|
||||
else:
|
||||
pass
|
||||
msg = mw.getInfo('删除防火墙放行端口[{1}]成功!', (port,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
if protocol == 'udp':
|
||||
mw.execShell(
|
||||
'iptables -D INPUT -p udp -m state --state NEW -m udp --dport ' + port + ' -j ACCEPT')
|
||||
if protocol == 'tcp/udp':
|
||||
mw.execShell(
|
||||
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
|
||||
mw.execShell(
|
||||
'iptables -D INPUT -p udp -m state --state NEW -m udp --dport ' + port + ' -j ACCEPT')
|
||||
else:
|
||||
pass
|
||||
|
||||
mw.M('firewall').where("port=?", (port,)).delete()
|
||||
|
||||
msg = mw.getInfo('删除防火墙放行端口[{1}][{2}]成功!', (port, protocol,))
|
||||
mw.writeLog("防火墙管理", msg)
|
||||
|
||||
self.firewallReload()
|
||||
return True
|
||||
|
||||
# 删除放行端口
|
||||
def delAcceptPortApi(self):
|
||||
port = request.form.get('port', '').strip()
|
||||
protocol = request.form.get('protocol', 'tcp').strip()
|
||||
sid = request.form.get('id', '').strip()
|
||||
mw_port = mw.readFile('data/port.pl')
|
||||
|
||||
if(port == mw_port):
|
||||
return mw.returnJson(False, '失败,不能删除当前面板端口!')
|
||||
try:
|
||||
self.delAcceptPortArgs(port, protocol)
|
||||
mw.M('firewall').where("id=?", (sid,)).delete()
|
||||
|
||||
self.firewallReload()
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, '删除失败!:' + str(e))
|
||||
@@ -214,16 +248,13 @@ class firewall_api:
|
||||
|
||||
data['pass_prohibit_status'] = False
|
||||
# 密码登陆配置检查
|
||||
pass_rep = "#PasswordAuthentication\s+(\w*)\s*\n"
|
||||
pass_rep = "PasswordAuthentication\s+(\w*)\s*\n"
|
||||
pass_status = re.search(pass_rep, conf)
|
||||
if pass_status:
|
||||
data['pass_prohibit_status'] = True
|
||||
|
||||
if not data['pass_prohibit_status']:
|
||||
pass_rep = "PasswordAuthentication\s+(\w*)\s*\n"
|
||||
pass_status = re.search(pass_rep, conf)
|
||||
if pass_status and pass_status.groups(0)[0].strip() == 'no':
|
||||
data['pass_prohibit_status'] = True
|
||||
else:
|
||||
data['pass_prohibit_status'] = True
|
||||
|
||||
data['port'] = port
|
||||
data['status'] = status
|
||||
@@ -299,11 +330,17 @@ class firewall_api:
|
||||
|
||||
conf = mw.readFile(file)
|
||||
|
||||
if status == '1':
|
||||
pass_rep = "PasswordAuthentication\s+(\w*)\s*\n"
|
||||
pass_status = re.search(pass_rep, conf)
|
||||
if not pass_status:
|
||||
rep = "(#)?PasswordAuthentication\s+(\w*)\s*\n"
|
||||
conf = re.sub(rep, "PasswordAuthentication yes\n", conf)
|
||||
|
||||
if status == '1':
|
||||
rep = "PasswordAuthentication\s+(\w*)\s*\n"
|
||||
conf = re.sub(rep, "PasswordAuthentication yes\n", conf)
|
||||
else:
|
||||
rep = "(#)?PasswordAuthentication\s+(\w*)\s*\n"
|
||||
rep = "PasswordAuthentication\s+(\w*)\s*\n"
|
||||
conf = re.sub(rep, "PasswordAuthentication no\n", conf)
|
||||
mw.writeFile(file, conf)
|
||||
mw.execShell("systemctl restart sshd.service")
|
||||
@@ -389,7 +426,7 @@ class firewall_api:
|
||||
|
||||
start = (page - 1) * limit
|
||||
|
||||
_list = mw.M('firewall').field('id,port,ps,addtime').limit(
|
||||
_list = mw.M('firewall').field('id,port,protocol,ps,addtime').limit(
|
||||
str(start) + ',' + str(limit)).order('id desc').select()
|
||||
data = {}
|
||||
data['data'] = _list
|
||||
@@ -403,16 +440,40 @@ class firewall_api:
|
||||
data['page'] = mw.getPage(_page)
|
||||
return mw.getJson(data)
|
||||
|
||||
def addAcceptPort(self, port):
|
||||
def addAcceptPort(self, port, protocol='tcp'):
|
||||
if self.__isUfw:
|
||||
mw.execShell('ufw allow ' + port + '/tcp')
|
||||
if protocol == 'tcp':
|
||||
mw.execShell('ufw allow ' + port + '/tcp')
|
||||
if protocol == 'udp':
|
||||
mw.execShell('ufw allow ' + port + '/udp')
|
||||
if protocol == 'tcp/udp':
|
||||
mw.execShell('ufw allow ' + port + '/tcp')
|
||||
mw.execShell('ufw allow ' + port + '/udp')
|
||||
elif self.__isFirewalld:
|
||||
port = port.replace(':', '-')
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'tcp':
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'udp':
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/udp'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'tcp/udp':
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
|
||||
mw.execShell(cmd)
|
||||
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/udp'
|
||||
mw.execShell(cmd)
|
||||
elif self.__isIptables:
|
||||
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'tcp':
|
||||
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'udp':
|
||||
cmd = 'iptables -I INPUT -p udp -m state --state NEW -m udp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
if protocol == 'tcp/udp':
|
||||
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
cmd = 'iptables -I INPUT -p udp -m state --state NEW -m udp --dport ' + port + ' -j ACCEPT'
|
||||
mw.execShell(cmd)
|
||||
else:
|
||||
pass
|
||||
return True
|
||||
|
||||
@@ -77,7 +77,9 @@ class logs_api:
|
||||
if log_name in ['dmesg'] or log_name.find('dmesg') == 0:
|
||||
return '内核缓冲区日志'
|
||||
if log_name in ['syslog'] or log_name.find('syslog') == 0:
|
||||
return '系统警告/错误日志'
|
||||
return '系统日志'
|
||||
if log_name in ['rsyncd.log']:
|
||||
return '远程同步日志'
|
||||
if log_name in ['btmp']:
|
||||
return '失败的登录记录'
|
||||
if log_name in ['utmp', 'wtmp']:
|
||||
|
||||
+21
-3
@@ -394,6 +394,9 @@ def getPageObject(args, result='1,2,3,4,5,8'):
|
||||
if 'tojs' in args:
|
||||
info['return_js'] = args['tojs']
|
||||
|
||||
if 'args_tpl' in args:
|
||||
info['args_tpl'] = args['args_tpl']
|
||||
|
||||
return (page.GetPage(info, result), page)
|
||||
|
||||
|
||||
@@ -425,13 +428,13 @@ def getFileMd5(filename):
|
||||
|
||||
def getRandomString(length):
|
||||
# 取随机字符串
|
||||
str = ''
|
||||
rnd_str = ''
|
||||
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
|
||||
chrlen = len(chars) - 1
|
||||
random = Random()
|
||||
for i in range(length):
|
||||
str += chars[random.randint(0, chrlen)]
|
||||
return str
|
||||
rnd_str += chars[random.randint(0, chrlen)]
|
||||
return rnd_str
|
||||
|
||||
|
||||
def getUniqueId():
|
||||
@@ -905,7 +908,22 @@ def aesDecrypt_Crypto(data, key, vi):
|
||||
text_decrypted = text_decrypted.decode('utf8').rstrip() # 去掉补位的右侧空格
|
||||
return text_decrypted
|
||||
|
||||
def encodeImage(imgsrc, newsrc):
|
||||
# 图片加密
|
||||
import struct
|
||||
old_fp = open(imgsrc, 'rb')
|
||||
imgFile = old_fp.read()
|
||||
old_fp.close()
|
||||
|
||||
new_fp = open(newsrc,"wb")
|
||||
for x in imgFile:
|
||||
value = x ^ 86
|
||||
value = hex(value)
|
||||
s = struct.pack('B',int(value,16))
|
||||
new_fp.write(s)
|
||||
new_fp.close()
|
||||
return True
|
||||
|
||||
def buildSoftLink(src, dst, force=False):
|
||||
'''
|
||||
建立软连接
|
||||
|
||||
+14
-6
@@ -39,6 +39,7 @@ class Page():
|
||||
__RTURN_JS = False # 是否返回JS回调
|
||||
__START_NUM = None # 起始行
|
||||
__END_NUM = None # 结束行
|
||||
__ARGS_TPL = ''
|
||||
|
||||
def __init__(self):
|
||||
if False:
|
||||
@@ -51,12 +52,19 @@ class Page():
|
||||
self.__FO = tmp['FO']
|
||||
self.__LINE = tmp['LINE']
|
||||
|
||||
def getPageNum(self, num):
|
||||
return str(num) + self.__ARGS_TPL
|
||||
|
||||
def GetPage(self, pageInfo, limit='1,2,3,4,5,6,7,8'):
|
||||
# 取分页信息
|
||||
# @param pageInfo 传入分页参数字典
|
||||
# @param limit 返回系列
|
||||
self.__RTURN_JS = pageInfo['return_js']
|
||||
self.__COUNT_ROW = pageInfo['count']
|
||||
|
||||
if 'args_tpl' in pageInfo:
|
||||
self.__ARGS_TPL = pageInfo['args_tpl']
|
||||
|
||||
self.ROW = pageInfo['row']
|
||||
self.__C_PAGE = self.__GetCpage(pageInfo['p'])
|
||||
self.__START_NUM = self.__StartRow()
|
||||
@@ -111,7 +119,7 @@ class Page():
|
||||
str(self.__COUNT_PAGE) + "'>" + str(self.__END) + "</a>"
|
||||
else:
|
||||
endStr = "<a class='Pend' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(self.__COUNT_PAGE) + ")'>" + \
|
||||
"(" + self.getPageNum(self.__COUNT_PAGE) + ")'>" + \
|
||||
str(self.__END) + "</a>"
|
||||
return endStr
|
||||
|
||||
@@ -126,7 +134,7 @@ class Page():
|
||||
str(self.__C_PAGE + 1) + "'>" + str(self.__NEXT) + "</a>"
|
||||
else:
|
||||
nextStr = "<a class='Pnext' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(self.__C_PAGE + 1) + ")'>" + \
|
||||
"(" + self.getPageNum(self.__C_PAGE + 1) + ")'>" + \
|
||||
str(self.__NEXT) + "</a>"
|
||||
|
||||
return nextStr
|
||||
@@ -151,7 +159,7 @@ class Page():
|
||||
"p=" + str(page) + "'>" + str(page) + "</a>"
|
||||
else:
|
||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(page) + ")'>" + str(page) + "</a>"
|
||||
"(" + self.getPageNum(page) + ")'>" + str(page) + "</a>"
|
||||
|
||||
# 当前页
|
||||
if self.__C_PAGE > 0:
|
||||
@@ -174,7 +182,7 @@ class Page():
|
||||
"p=" + str(page) + "'>" + str(page) + "</a>"
|
||||
else:
|
||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(page) + ")'>" + str(page) + "</a>"
|
||||
"(" + self.getPageNum(page) + ")'>" + str(page) + "</a>"
|
||||
|
||||
return pages
|
||||
|
||||
@@ -189,7 +197,7 @@ class Page():
|
||||
str(self.__C_PAGE - 1) + "'>" + str(self.__PREV) + "</a>"
|
||||
else:
|
||||
startStr = "<a class='Ppren' onclick='" + self.__RTURN_JS + \
|
||||
"(" + str(self.__C_PAGE - 1) + ")'>" + \
|
||||
"(" + self.getPageNum(self.__C_PAGE - 1) + ")'>" + \
|
||||
str(self.__PREV) + "</a>"
|
||||
return startStr
|
||||
|
||||
@@ -204,7 +212,7 @@ class Page():
|
||||
self.__URI + "p=1'>" + str(self.__START) + "</a>"
|
||||
else:
|
||||
startStr = "<a class='Pstart' onclick='" + \
|
||||
self.__RTURN_JS + "(1)'>" + str(self.__START) + "</a>"
|
||||
self.__RTURN_JS + "("+self.getPageNum(1)+")'>" + str(self.__START) + "</a>"
|
||||
return startStr
|
||||
|
||||
def __GetCpage(self, p):
|
||||
|
||||
+52
-21
@@ -52,6 +52,7 @@ class plugins_api:
|
||||
__plugin_dir = 'plugins'
|
||||
__type = 'data/json/type.json'
|
||||
__index = 'data/json/index.json'
|
||||
__index_data = None
|
||||
setupPath = None
|
||||
|
||||
def __init__(self):
|
||||
@@ -60,6 +61,14 @@ class plugins_api:
|
||||
self.__type = mw.getRunDir() + '/data/json/type.json'
|
||||
self.__index = mw.getRunDir() + '/data/json/index.json'
|
||||
|
||||
self.initIndexData()
|
||||
|
||||
def initIndexData(self):
|
||||
if not os.path.exists(self.__index):
|
||||
mw.writeFile(self.__index, '[]')
|
||||
|
||||
self.__index_data = json.loads(mw.readFile(self.__index))
|
||||
|
||||
##### ----- start ----- ###
|
||||
def listApi(self):
|
||||
sType = request.args.get('type', '0')
|
||||
@@ -139,7 +148,7 @@ class plugins_api:
|
||||
def initApi(self):
|
||||
|
||||
plugin_names = {
|
||||
'openresty': '1.21.4.2',
|
||||
'openresty': '1.21.4.3',
|
||||
'php': '56',
|
||||
'swap': '1.1',
|
||||
'mysql': '5.7',
|
||||
@@ -615,20 +624,37 @@ class plugins_api:
|
||||
|
||||
return plugins_info
|
||||
|
||||
def checkDisplayIndex(self, name, version):
|
||||
if not os.path.exists(self.__index):
|
||||
mw.writeFile(self.__index, '[]')
|
||||
def checkIndexList(self, name, version):
|
||||
indexList = self.__index_data
|
||||
for i in indexList:
|
||||
nv = i.split('-')
|
||||
if nv[0] == name:
|
||||
return True
|
||||
return False
|
||||
|
||||
indexList = json.loads(mw.readFile(self.__index))
|
||||
if type(version) == list:
|
||||
for index in range(len(version)):
|
||||
vname = name + '-' + version[index]
|
||||
def checkDisplayIndex(self, name, version, coexist):
|
||||
# if not os.path.exists(self.__index):
|
||||
# mw.writeFile(self.__index, '[]')
|
||||
# indexList = json.loads(mw.readFile(self.__index))
|
||||
|
||||
indexList = self.__index_data
|
||||
if coexist:
|
||||
if type(version) == list:
|
||||
for index in range(len(version)):
|
||||
vname = name + '-' + version[index]
|
||||
if vname in indexList:
|
||||
return True
|
||||
else:
|
||||
vname = name + '-' + version
|
||||
if vname in indexList:
|
||||
return True
|
||||
|
||||
else:
|
||||
vname = name + '-' + version
|
||||
if vname in indexList:
|
||||
return True
|
||||
if type(version) == list:
|
||||
for index in range(len(version)):
|
||||
return self.checkIndexList(name, version)
|
||||
else:
|
||||
return self.checkIndexList(name, version)
|
||||
return False
|
||||
|
||||
def getVersion(self, path):
|
||||
@@ -695,7 +721,7 @@ class plugins_api:
|
||||
pInfo['task'] = self.checkSetupTask(
|
||||
pInfo['name'], info['versions'], coexist)
|
||||
pInfo['display'] = self.checkDisplayIndex(
|
||||
info['name'], pInfo['versions'])
|
||||
info['name'], pInfo['versions'], coexist)
|
||||
|
||||
pInfo['setup'] = os.path.exists(pInfo['install_checks'])
|
||||
|
||||
@@ -800,10 +826,10 @@ class plugins_api:
|
||||
continue
|
||||
path = self.__plugin_dir + '/' + dirinfo
|
||||
if os.path.isdir(path):
|
||||
json_file = path + '/info.json'
|
||||
if os.path.exists(json_file):
|
||||
info_file = path + '/info.json'
|
||||
if os.path.exists(info_file):
|
||||
try:
|
||||
data = json.loads(mw.readFile(json_file))
|
||||
data = json.loads(mw.readFile(info_file))
|
||||
# 判断是否搜索
|
||||
if kw != '' and not self.searchKey(data, kw):
|
||||
continue
|
||||
@@ -976,19 +1002,24 @@ class plugins_api:
|
||||
plugin_name = '-'.join(tmpArr)
|
||||
plugin_ver = tmp[tmp_len - 1]
|
||||
|
||||
json_file = self.__plugin_dir + '/' + plugin_name + '/info.json'
|
||||
if os.path.exists(json_file):
|
||||
content = mw.readFile(json_file)
|
||||
read_json_file = self.__plugin_dir + '/' + plugin_name + '/info.json'
|
||||
if os.path.exists(read_json_file):
|
||||
content = mw.readFile(read_json_file)
|
||||
try:
|
||||
data = json.loads(content)
|
||||
data = self.makeList(data)
|
||||
for index in range(len(data)):
|
||||
if data[index]['versions'] == plugin_ver or plugin_ver in data[index]['versions']:
|
||||
if data[index]['coexist']:
|
||||
if data[index]['versions'] == plugin_ver or plugin_ver in data[index]['versions']:
|
||||
data[index]['display'] = True
|
||||
plist.append(data[index])
|
||||
continue
|
||||
else:
|
||||
data[index]['display'] = True
|
||||
plist.append(data[index])
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
print('getIndexList:', e)
|
||||
print('getIndexList:', mw.getTracebackInfo())
|
||||
|
||||
# 使用gevent模式时,无法使用多进程
|
||||
# plist = self.checkStatusMProcess(plist)
|
||||
|
||||
+32
-13
@@ -105,7 +105,7 @@ class site_api:
|
||||
|
||||
start = (int(p) - 1) * (int(limit))
|
||||
|
||||
siteM = mw.M('sites').field('id,name,path,status,ps,addtime,edate')
|
||||
siteM = siteC = mw.M('sites').field('id,name,path,status,ps,addtime,edate,type_id')
|
||||
|
||||
sql_where = ''
|
||||
if search != '':
|
||||
@@ -113,30 +113,37 @@ class site_api:
|
||||
|
||||
if type_id != '' and int(type_id) >= 0 and search != '':
|
||||
sql_where = sql_where + " and type_id=" + type_id + ""
|
||||
elif type_id != '' and int(type_id) >= 0:
|
||||
if type_id != '' and int(type_id) >= 0:
|
||||
sql_where = " type_id=" + type_id
|
||||
|
||||
if sql_where != '':
|
||||
siteM.where(sql_where)
|
||||
|
||||
_list = siteM.limit((str(start)) + ',' +
|
||||
limit).order('id desc').select()
|
||||
|
||||
_list = siteM.limit((str(start)) + ',' +limit).order('id desc').select()
|
||||
if _list != None:
|
||||
for i in range(len(_list)):
|
||||
_list[i]['backup_count'] = mw.M('backup').where(
|
||||
"pid=? AND type=?", (_list[i]['id'], 0)).count()
|
||||
_list[i]['backup_count'] = mw.M('backup').where("pid=? AND type=?", (_list[i]['id'], 0)).count()
|
||||
|
||||
_ret = {}
|
||||
_ret['data'] = _list
|
||||
|
||||
count = siteM.count()
|
||||
if sql_where != '':
|
||||
count = siteC.where(sql_where).count()
|
||||
else:
|
||||
count = siteC.count()
|
||||
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['tojs'] = 'getWeb'
|
||||
_page['p'] = p
|
||||
_page['row'] = limit
|
||||
|
||||
page_args_tpl = ''
|
||||
page_args_tpl += ','+type_id+''
|
||||
if search != '':
|
||||
page_args_tpl += ',"'+search+'"'
|
||||
_page['args_tpl'] = page_args_tpl
|
||||
|
||||
_ret['page'] = mw.getPage(_page)
|
||||
return mw.getJson(_ret)
|
||||
|
||||
@@ -973,6 +980,9 @@ class site_api:
|
||||
siteInfo = mw.M('sites').where(
|
||||
'name=?', (siteName,)).field('id,name,path').find()
|
||||
path = self.getSitePath(siteName)
|
||||
if path == '':
|
||||
return mw.returnJson(False, '【'+siteName+'】配置文件,异常!')
|
||||
|
||||
srcPath = siteInfo['path']
|
||||
|
||||
# 检测acme是否安装
|
||||
@@ -2201,7 +2211,10 @@ location ^~ {from} {\n\
|
||||
if os.path.exists(file):
|
||||
conf = mw.readFile(file)
|
||||
rep = '\s*root\s*(.+);'
|
||||
path = re.search(rep, conf).groups()[0]
|
||||
find_cnf = re.search(rep, conf)
|
||||
if not find_cnf:
|
||||
return ''
|
||||
path = find_cnf.groups()[0]
|
||||
return path
|
||||
return ''
|
||||
|
||||
@@ -2300,9 +2313,15 @@ location ^~ {from} {\n\
|
||||
def getSitePhpVersion(self, siteName):
|
||||
conf = mw.readFile(self.getHostConf(siteName))
|
||||
rep = "enable-php-(.*)\.conf"
|
||||
tmp = re.search(rep, conf).groups()
|
||||
find_php_cnf = re.search(rep, conf)
|
||||
|
||||
def_pver = '00'
|
||||
if find_php_cnf:
|
||||
tmp = find_php_cnf.groups()
|
||||
def_pver = tmp[0]
|
||||
|
||||
data = {}
|
||||
data['phpversion'] = tmp[0]
|
||||
data['phpversion'] = def_pver
|
||||
return mw.getJson(data)
|
||||
|
||||
def getIndex(self, sid):
|
||||
@@ -2505,7 +2524,7 @@ location ^~ {from} {\n\
|
||||
|
||||
def getPhpVersion(self):
|
||||
phpVersions = ('00', '52', '53', '54', '55',
|
||||
'56', '70', '71', '72', '73', '74', '80', '81', '82')
|
||||
'56', '70', '71', '72', '73', '74', '80', '81', '82', '83')
|
||||
data = []
|
||||
for val in phpVersions:
|
||||
tmp = {}
|
||||
@@ -2788,7 +2807,7 @@ location ^~ {from} {\n\
|
||||
|
||||
self.saveCert(keyPath, certPath)
|
||||
|
||||
msg = mw.getInfo('网站[{}]开启SSL成功!', siteName)
|
||||
msg = mw.getInfo('网站[{1}]开启SSL成功!', (siteName,))
|
||||
mw.writeLog('网站管理', msg)
|
||||
|
||||
mw.restartWeb()
|
||||
|
||||
@@ -273,17 +273,34 @@ class system_api:
|
||||
title = mw.readFile(titlePl).strip()
|
||||
return title
|
||||
|
||||
def getSystemDeviceTemperature(self):
|
||||
if not hasattr(psutil, "sensors_temperatures"):
|
||||
return False, "platform not supported"
|
||||
temps = psutil.sensors_temperatures()
|
||||
if not temps:
|
||||
return False, "can't read any temperature"
|
||||
for name, entries in temps.items():
|
||||
for entry in entries:
|
||||
return True, entry.label
|
||||
# print("%-20s %s °C (high = %s °C, critical = %s °C)" % (
|
||||
# entry.label or name, entry.current, entry.high,
|
||||
# entry.critical))
|
||||
return False, ""
|
||||
|
||||
def getSystemVersion(self):
|
||||
#
|
||||
# 取操作系统版本
|
||||
current_os = mw.getOs()
|
||||
# sys_temper = self.getSystemDeviceTemperature()
|
||||
# print(sys_temper)
|
||||
# mac
|
||||
if current_os == 'darwin':
|
||||
data = mw.execShell('sw_vers')[0]
|
||||
data_list = data.strip().split("\n")
|
||||
mac_version = ''
|
||||
for x in data_list:
|
||||
mac_version += x.split("\t")[1] + ' '
|
||||
xlist = x.split("\t")
|
||||
mac_version += xlist[len(xlist)-1] + ' '
|
||||
|
||||
arch_ver = mw.execShell("arch")
|
||||
return mac_version + " (" + arch_ver[0].strip() + ")"
|
||||
@@ -350,15 +367,15 @@ class system_api:
|
||||
mem = psutil.virtual_memory()
|
||||
if mw.getOs() == 'darwin':
|
||||
memInfo = {
|
||||
'memTotal': mem.total / 1024 / 1024
|
||||
'memTotal': mem.total,
|
||||
}
|
||||
memInfo['memRealUsed'] = memInfo['memTotal'] * (mem.percent / 100)
|
||||
else:
|
||||
memInfo = {
|
||||
'memTotal': mem.total / 1024 / 1024,
|
||||
'memFree': mem.free / 1024 / 1024,
|
||||
'memBuffers': mem.buffers / 1024 / 1024,
|
||||
'memCached': mem.cached / 1024 / 1024
|
||||
'memTotal': mem.total,
|
||||
'memFree': mem.free,
|
||||
'memBuffers': mem.buffers,
|
||||
'memCached': mem.cached
|
||||
}
|
||||
|
||||
memInfo['memRealUsed'] = memInfo['memTotal'] - \
|
||||
@@ -542,9 +559,9 @@ class system_api:
|
||||
networkInfo['upTotal'] = networkIo[0]
|
||||
networkInfo['downTotal'] = networkIo[1]
|
||||
networkInfo['up'] = round(float(
|
||||
networkIo[0] - session['up']) / 1024 / (ntime - session['otime']), 2)
|
||||
networkIo[0] - session['up']) / (ntime - session['otime']), 2)
|
||||
networkInfo['down'] = round(
|
||||
float(networkIo[1] - session['down']) / 1024 / (ntime - session['otime']), 2)
|
||||
float(networkIo[1] - session['down']) / (ntime - session['otime']), 2)
|
||||
networkInfo['downPackets'] = networkIo[3]
|
||||
networkInfo['upPackets'] = networkIo[2]
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import requests
|
||||
|
||||
class vip_api:
|
||||
|
||||
api_url = 'https://wo.midoks.me/api/wp-json/vip'
|
||||
api_url = 'https://wo.midoks.icu/api/wp-json/vip'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
DIR=$(cd "$(dirname "$0")"; pwd)
|
||||
MDIR=$(dirname "$DIR")
|
||||
|
||||
@@ -46,6 +46,10 @@ mw_start(){
|
||||
|
||||
|
||||
mw_start_debug(){
|
||||
if [ ! -f $DIR/logs/task.log ];then
|
||||
echo '' > $DIR/logs/task.log
|
||||
fi
|
||||
|
||||
python3 task.py >> $DIR/logs/task.log 2>&1 &
|
||||
port=7200
|
||||
if [ -f /www/server/mdserver-web/data/port.pl ];then
|
||||
|
||||
@@ -4,7 +4,18 @@
|
||||
- 面板相关命令
|
||||
|
||||
```
|
||||
/etc/init.d/mw default
|
||||
/etc/init.d/mw default | 显示登录信息
|
||||
/etc/init.d/mw db | 快捷连接数据库
|
||||
----------------------------------------
|
||||
mw open | 开启面板
|
||||
mw close | 关闭面板
|
||||
|
||||
mw debug | 开发测试
|
||||
mw venv | 进入虚拟环境
|
||||
mw mirror | 切换镜像
|
||||
mw install_app | 快捷安装常用软件
|
||||
mw update | 更新到正式
|
||||
mw update_dev | 更新到开发
|
||||
|
||||
service mw [start|stop|reload|restart|status]
|
||||
```
|
||||
|
||||
+18
-18
@@ -29,24 +29,24 @@ cd /www/server/mdserver-web/plugins/php/versions && bash all_test.sh
|
||||
|
||||
|
||||
|
||||
| 系统名称 |PHP53 |PHP54 |PHP55 |PHP56 |PHP70 |PHP71 |PHP72 |PHP73 |PHP74 |PHP80 |PHP81 |PHP82 |
|
||||
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
|
||||
| CentOS 7.9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 9 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 10.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 11.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 12 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Fedora 31 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Fedora 32 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| AlmaLinux 9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Arch Linux |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| openSUSE 15.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| 系统名称 |PHP53 |PHP54 |PHP55 |PHP56 |PHP70 |PHP71 |PHP72 |PHP73 |PHP74 |PHP80 |PHP81 |PHP82 |PHP83 |
|
||||
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
|
||||
| CentOS 7.9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 8 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| CentOS 9 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 10.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 11.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Debian 12 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Fedora 31 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Fedora 32 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| AlmaLinux 9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| Arch Linux |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
| openSUSE 15.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
30
|
||||
@@ -40,14 +40,16 @@ CREATE TABLE IF NOT EXISTS `crontab` (
|
||||
CREATE TABLE IF NOT EXISTS `firewall` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`port` TEXT,
|
||||
`protocol` TEXT DEFAULT 'tcp',
|
||||
`ps` TEXT,
|
||||
`addtime` TEXT
|
||||
);
|
||||
|
||||
INSERT INTO `firewall` (`id`, `port`, `ps`, `addtime`) VALUES
|
||||
(1, '80', '网站默认端口', '0000-00-00 00:00:00'),
|
||||
(2, '443', 'HTTPS', '0000-00-00 00:00:00'),
|
||||
(3, '888', 'phpMyAdmin默认端口', '0000-00-00 00:00:00');
|
||||
ALTER TABLE `firewall` ADD COLUMN `protocol` TEXT DEFAULT 'tcp';
|
||||
|
||||
INSERT INTO `firewall` (`id`, `port`, `protocol`, `ps`, `addtime`) VALUES
|
||||
(1, '80', 'tcp','网站默认端口', '0000-00-00 00:00:00'),
|
||||
(2, '443', 'tcp', 'HTTPS', '0000-00-00 00:00:00');
|
||||
|
||||
|
||||
|
||||
@@ -55,7 +57,7 @@ CREATE TABLE IF NOT EXISTS `logs` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`type` TEXT,
|
||||
`log` TEXT,
|
||||
`uid` TEXT,
|
||||
`uid` INTEGER DEFAULT '1',
|
||||
`addtime` TEXT
|
||||
);
|
||||
ALTER TABLE `logs` ADD COLUMN `uid` INTEGER DEFAULT '1';
|
||||
|
||||
@@ -52,8 +52,8 @@ def createBgTask():
|
||||
removeBgTask()
|
||||
args = {
|
||||
"period": "day",
|
||||
"hour": "2",
|
||||
"minute": "30",
|
||||
"hour": "0",
|
||||
"minute": "15",
|
||||
}
|
||||
createBgTaskByName(getPluginName(), args)
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
Executable
+25
@@ -0,0 +1,25 @@
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('data_query');">服务</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinHeight(300);
|
||||
resetPluginWinWidth(380);
|
||||
pluginService('data_query', $('.plugin_version').attr('version'));
|
||||
</script>
|
||||
Executable
+97
@@ -0,0 +1,97 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'data_query'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[3:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
return tmp
|
||||
|
||||
def checkArgs(data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
if not ck[i] in data:
|
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
def status():
|
||||
return 'start'
|
||||
|
||||
def appOp(method):
|
||||
return 'ok'
|
||||
|
||||
|
||||
|
||||
def start():
|
||||
return appOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return appOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = appOp('restart')
|
||||
return status
|
||||
|
||||
def reload():
|
||||
return appOp('reload')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
print(status())
|
||||
elif func == 'start':
|
||||
print(start())
|
||||
elif func == 'stop':
|
||||
print(stop())
|
||||
elif func == 'restart':
|
||||
print(restart())
|
||||
elif func == 'reload':
|
||||
print(reload())
|
||||
else:
|
||||
print('error')
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"hook":[
|
||||
{
|
||||
"tag":"menu",
|
||||
"menu": {
|
||||
"title":"数据管理",
|
||||
"name":"data_query",
|
||||
"path":"static/html/index.html",
|
||||
"css_path":"static/css/data.css",
|
||||
"js_path":"static/js/app.js"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag":"global_static",
|
||||
"global_static": {
|
||||
"title":"数据管理",
|
||||
"name":"data_query",
|
||||
"css_path":"static/css/ico.css"
|
||||
}
|
||||
}
|
||||
],
|
||||
"sort": 7,
|
||||
"ps": "数据简单管理(memcached,redis,mongodb)",
|
||||
"name": "data_query",
|
||||
"title": "数据管理",
|
||||
"shell": "install.sh",
|
||||
"versions":"1.0",
|
||||
"tip": "soft",
|
||||
"checks": "server/data_query",
|
||||
"path": "server/data_query",
|
||||
"display": 1,
|
||||
"author": "midoks",
|
||||
"date": "2024-01-22",
|
||||
"type": 0,
|
||||
"pid": "2"
|
||||
}
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
Install_App()
|
||||
{
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/source
|
||||
mkdir -p $serverPath/data_query
|
||||
echo "${VERSION}" > $serverPath/data_query/version.pl
|
||||
|
||||
echo '安装完成'
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
rm -rf $serverPath/data_query
|
||||
echo "卸载成功"
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
Executable
+253
@@ -0,0 +1,253 @@
|
||||
# coding:utf-8
|
||||
|
||||
# https://pypi.org/project/pymemcache/
|
||||
# https://pymemcache.readthedocs.io/en/latest/getting_started.html#using-a-client-pool
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
import pymemcache
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def inner():
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls()
|
||||
return _instance[cls]
|
||||
return inner
|
||||
|
||||
@singleton
|
||||
class nosqlMemcached():
|
||||
|
||||
__DB_PASS = None
|
||||
__DB_USER = None
|
||||
__DB_PORT = 11211
|
||||
__DB_HOST = '127.0.0.1'
|
||||
__DB_CONN = None
|
||||
__DB_ERR = None
|
||||
|
||||
__DB_LOCAL = None
|
||||
|
||||
def __init__(self):
|
||||
self.__config = self.get_options(None)
|
||||
|
||||
|
||||
def conn(self):
|
||||
|
||||
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
|
||||
mem_path = "{}/memcached".format(mw.getServerDir())
|
||||
if not os.path.exists(mem_path): return False
|
||||
|
||||
if not self.__DB_LOCAL:
|
||||
self.__DB_PORT = int(self.__config['port'])
|
||||
try:
|
||||
self.__DB_CONN = pymemcache.client.base.PooledClient((self.__DB_HOST,self.__DB_PORT), max_pool_size=4)
|
||||
return self.__DB_CONN
|
||||
except pymemcache.exceptions.MemcacheError:
|
||||
return False
|
||||
except Exception:
|
||||
self.__DB_ERR = mw.getTracebackInfo()
|
||||
return False
|
||||
|
||||
# 获取配置项
|
||||
def get_options(self, get=None):
|
||||
|
||||
result = {}
|
||||
mem_content = mw.readFile("{}/memcached/memcached.env".format(mw.getServerDir()))
|
||||
if not mem_content: return False
|
||||
|
||||
keys = ["bind", "PORT"]
|
||||
rep = 'PORT\s*=\s*(.*)'
|
||||
port_re = re.search(rep, mem_content)
|
||||
if port_re:
|
||||
result['port'] = int(port_re.groups()[0].strip())
|
||||
else:
|
||||
result['port'] = 11211
|
||||
return result
|
||||
|
||||
def set_host(self, host, port, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__DB_LOCAL = 1
|
||||
return self
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlMemcachedCtr():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getInstanceBySid(self, sid = 0):
|
||||
instance = nosqlMemcached()
|
||||
return instance
|
||||
|
||||
def getItems(self, args):
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = {}
|
||||
m_items = mem_instance.stats('items')
|
||||
|
||||
item_no = []
|
||||
for i in m_items:
|
||||
item_match = b'items:(\d*?):number'
|
||||
item_match_re = re.search(item_match, i)
|
||||
if item_match_re:
|
||||
v = item_match_re.groups()[0].strip()
|
||||
v_str = v.decode()
|
||||
if not v_str in item_no:
|
||||
item_no.append(v_str)
|
||||
|
||||
if len(item_no) == 0:
|
||||
item_no = [0]
|
||||
|
||||
result['items'] = item_no
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getKeyList(self, args):
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
|
||||
p = 1
|
||||
size = 10
|
||||
if 'p' in args:
|
||||
p = args['p']
|
||||
|
||||
if 'size' in args:
|
||||
size = args['size']
|
||||
|
||||
item_id = args['item_id']
|
||||
if item_id == '0':
|
||||
return mw.returnData(False,'ok')
|
||||
|
||||
m_items = mem_instance.stats('items')
|
||||
|
||||
item_key = 'items:%s:number' % item_id
|
||||
item_key_b = item_key.encode("utf-8")
|
||||
m_items_v = m_items[item_key_b]
|
||||
|
||||
|
||||
start = (p-1)*size
|
||||
end = start+size
|
||||
if end > m_items_v:
|
||||
end = m_items_v
|
||||
|
||||
|
||||
all_key = mem_instance.stats('cachedump', str(item_id) , str(0))
|
||||
# print(all_key)
|
||||
all_key_list = []
|
||||
cur_time_t = time.time()
|
||||
for k in all_key:
|
||||
t = {}
|
||||
t['k'] = k.decode("utf-8")
|
||||
v = all_key[k].decode("utf-8")
|
||||
v = v.strip('[').strip(']').split(';')
|
||||
t['s'] = v[0]
|
||||
cur_time = v[1].strip().split(' ')[0]
|
||||
|
||||
if int(cur_time) != 0 :
|
||||
t['t'] = int(cur_time) - int(cur_time_t)
|
||||
else:
|
||||
t['t'] = 0
|
||||
all_key_list.append(t)
|
||||
|
||||
# print(len(all_key_list))
|
||||
# print(start,end)
|
||||
return_all_key = all_key_list[start:end]
|
||||
|
||||
for x in range(len(return_all_key)):
|
||||
v = mem_instance.get(return_all_key[x]['k'])
|
||||
return_all_key[x]['v'] = v.decode('utf-8')
|
||||
|
||||
result = {}
|
||||
result['list'] = return_all_key
|
||||
result['p'] = p
|
||||
|
||||
page_args = {}
|
||||
page_args['count'] = len(all_key_list)
|
||||
page_args['tojs'] = 'memcachedGetKeyList'
|
||||
page_args['p'] = p
|
||||
page_args['row'] = size
|
||||
result['page'] = mw.getPage(page_args)
|
||||
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def delVal(self, args):
|
||||
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
key = args['key']
|
||||
mem_instance.delete(key)
|
||||
return mw.returnData(True,'删除成功!')
|
||||
|
||||
def setKv(self, args):
|
||||
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
key = args['key']
|
||||
val = args['val']
|
||||
endtime = args['endtime']
|
||||
mem_instance.set(key, val, int(endtime))
|
||||
return mw.returnData(True,'设置成功!')
|
||||
|
||||
def clear(self, args):
|
||||
sid = args['sid']
|
||||
mem_instance = self.getInstanceBySid(sid).conn()
|
||||
if mem_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
mem_instance.flush_all()
|
||||
return mw.returnData(True,'清空成功!')
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
# 获取 memcached 列表
|
||||
def get_items(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.getItems(args)
|
||||
|
||||
def get_key_list(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.getKeyList(args)
|
||||
|
||||
def del_val(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.delVal(args)
|
||||
|
||||
def set_kv(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.setKv(args)
|
||||
|
||||
def clear(args):
|
||||
t = nosqlMemcachedCtr()
|
||||
return t.clear(args)
|
||||
|
||||
# 测试
|
||||
def test(args):
|
||||
sid = args['sid']
|
||||
t = nosqlMemcachedCtr()
|
||||
print(t.get_options())
|
||||
print("test")
|
||||
return 'ok'
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
|
||||
Executable
+254
@@ -0,0 +1,254 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import pymongo
|
||||
import json
|
||||
|
||||
from bson.objectid import ObjectId
|
||||
from bson.json_util import dumps
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def inner():
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls()
|
||||
return _instance[cls]
|
||||
return inner
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlMongodb():
|
||||
|
||||
__DB_PASS = None
|
||||
__DB_USER = None
|
||||
__DB_PORT = 6379
|
||||
__DB_HOST = '127.0.0.1'
|
||||
__DB_CONN = None
|
||||
__DB_ERR = None
|
||||
|
||||
__DB_LOCAL = None
|
||||
|
||||
def __init__(self):
|
||||
self.__config = self.get_options(None)
|
||||
|
||||
|
||||
def mgdb_conn(self):
|
||||
|
||||
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
|
||||
mgdb_path = "{}/mongodb".format(mw.getServerDir())
|
||||
if not os.path.exists(mgdb_path): return False
|
||||
|
||||
if not self.__DB_LOCAL:
|
||||
self.__DB_PORT = int(self.__config['port'])
|
||||
|
||||
# print(self.__DB_HOST,self.__DB_PORT, self.__DB_PASS)
|
||||
try:
|
||||
self.__DB_CONN = pymongo.MongoClient(host=self.__DB_HOST, port=self.__DB_PORT, maxPoolSize=10)
|
||||
self.__DB_CONN.admin.command('ping')
|
||||
return self.__DB_CONN
|
||||
except pymongo.errors.ConnectionFailure:
|
||||
return False
|
||||
except Exception:
|
||||
self.__DB_ERR = mw.get_error_info()
|
||||
return False
|
||||
|
||||
# 获取配置项
|
||||
def get_options(self, get=None):
|
||||
result = {}
|
||||
mgdb_content = mw.readFile("{}/mongodb/mongodb.conf".format(mw.getServerDir()))
|
||||
if not mgdb_content: return False
|
||||
|
||||
keys = ["bind_ip", "port"]
|
||||
|
||||
result['host'] = '127.0.0.1'
|
||||
rep = 'port\s*=\s*(.*)'
|
||||
ip_re = re.search(rep, mgdb_content)
|
||||
if ip_re:
|
||||
result['port'] = int(ip_re.groups()[0].strip())
|
||||
else:
|
||||
result['port'] = 27017
|
||||
return result
|
||||
|
||||
def set_host(self, host, port, name, username, password, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_NAME = name
|
||||
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
|
||||
self.__DB_USER = str(username)
|
||||
self._USER = str(username)
|
||||
self.__DB_PASS = str(password)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__DB_LOCAL = 1
|
||||
return self
|
||||
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlMongodbCtr():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getInstanceBySid(self, sid = 0):
|
||||
instance = nosqlMongodb()
|
||||
return instance
|
||||
|
||||
def getDbList(self, args):
|
||||
sid = args['sid']
|
||||
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
|
||||
if mgdb_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = {}
|
||||
doc_list = mgdb_instance.list_database_names()
|
||||
rlist = []
|
||||
for x in doc_list:
|
||||
if not x in ['admin', 'config', 'local']:
|
||||
rlist.append(x)
|
||||
result['list'] = rlist
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getCollectionsList(self, args):
|
||||
sid = args['sid']
|
||||
name = args['name']
|
||||
|
||||
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
|
||||
if mgdb_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = {}
|
||||
collections = mgdb_instance[name].list_collection_names()
|
||||
result['collections'] = collections
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getDataList(self, args):
|
||||
sid = args['sid']
|
||||
db = args['db']
|
||||
collection = args['collection']
|
||||
p = 1
|
||||
size = 10
|
||||
if 'p' in args:
|
||||
p = args['p']
|
||||
|
||||
if 'size' in args:
|
||||
size = args['size']
|
||||
|
||||
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
|
||||
if mgdb_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
db_instance = mgdb_instance[db]
|
||||
collection_instance = db_instance[collection]
|
||||
|
||||
start_index = (p - 1) * size
|
||||
end_index = p * size
|
||||
args_where = args['where']
|
||||
|
||||
where = {}
|
||||
if 'field' in args_where:
|
||||
mg_field = args_where['field']
|
||||
|
||||
if mg_field == '_id':
|
||||
mg_value = ObjectId(args_where['value'])
|
||||
where[mg_field] = mg_value
|
||||
else:
|
||||
mg_value = args_where['value']
|
||||
where[mg_field] = re.compile(mg_value)
|
||||
|
||||
# print(where)
|
||||
result = collection_instance.find(where).skip(start_index).limit(size).sort({'_id':-1})
|
||||
count = collection_instance.count_documents(where)
|
||||
d = []
|
||||
for document in result:
|
||||
d.append(document)
|
||||
|
||||
doc_str_json = dumps(d)
|
||||
result = json.loads(doc_str_json)
|
||||
|
||||
|
||||
page_args = {}
|
||||
page_args['count'] = count
|
||||
page_args['tojs'] = 'mongodbDataList'
|
||||
page_args['p'] = p
|
||||
page_args['row'] = size
|
||||
|
||||
rdata = {}
|
||||
rdata['page'] = mw.getPage(page_args)
|
||||
rdata['list'] = result
|
||||
rdata['count'] = count
|
||||
|
||||
rdata['soso_field'] = ''
|
||||
if 'field' in args_where:
|
||||
rdata['soso_field'] = args_where['field']
|
||||
|
||||
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
def delById(self,args):
|
||||
sid = args['sid']
|
||||
db = args['db']
|
||||
collection = args['collection']
|
||||
|
||||
mgdb_instance = self.getInstanceBySid(sid).mgdb_conn()
|
||||
if mgdb_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
db_instance = mgdb_instance[db]
|
||||
collection_instance = db_instance[collection]
|
||||
|
||||
_id = args['_id']
|
||||
result = collection_instance.delete_one({"_id": ObjectId(_id)})
|
||||
|
||||
return mw.returnData(True,'文档删除【%d】个成功!' % result.deleted_count)
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
# 获取 mongodb databases 列表
|
||||
def get_db_list(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.getDbList(args)
|
||||
|
||||
# 获取 mongodb collections 列表
|
||||
def get_collections_list(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.getCollectionsList(args)
|
||||
|
||||
def get_data_list(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.getDataList(args)
|
||||
|
||||
def set_kv(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.setKv(args)
|
||||
|
||||
|
||||
def del_val(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.delVal(args)
|
||||
|
||||
def batch_del_val(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.batchDelVal(args)
|
||||
|
||||
def clear_flushdb(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.clearFlushDB(args)
|
||||
|
||||
def del_by_id(args):
|
||||
t = nosqlMongodbCtr()
|
||||
return t.delById(args)
|
||||
|
||||
# 测试
|
||||
def test(args):
|
||||
sid = args['sid']
|
||||
t = nosqlMongodbCtr()
|
||||
print(t.get_options())
|
||||
print("test")
|
||||
return 'ok'
|
||||
Executable
+347
@@ -0,0 +1,347 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import redis
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
# def getPluginName():
|
||||
# return 'data_query'
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def inner():
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls()
|
||||
return _instance[cls]
|
||||
return inner
|
||||
|
||||
@singleton
|
||||
class nosqlRedis():
|
||||
|
||||
__DB_PASS = None
|
||||
__DB_USER = None
|
||||
__DB_PORT = 6379
|
||||
__DB_HOST = '127.0.0.1'
|
||||
__DB_CONN = None
|
||||
__DB_ERR = None
|
||||
|
||||
__DB_LOCAL = None
|
||||
|
||||
def __init__(self):
|
||||
self.__config = self.get_options(None)
|
||||
|
||||
|
||||
def redis_conn(self, db_idx=0):
|
||||
|
||||
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
|
||||
redis_path = "{}/redis".format(mw.getServerDir())
|
||||
if not os.path.exists(redis_path): return False
|
||||
|
||||
if not self.__DB_LOCAL:
|
||||
self.__DB_PASS = self.__config['requirepass']
|
||||
self.__DB_PORT = int(self.__config['port'])
|
||||
|
||||
# print(self.__DB_HOST,self.__DB_PORT, self.__DB_PASS)
|
||||
try:
|
||||
redis_pool = redis.ConnectionPool(host=self.__DB_HOST, port=self.__DB_PORT, password=self.__DB_PASS, db=db_idx, socket_timeout=3)
|
||||
self.__DB_CONN = redis.Redis(connection_pool=redis_pool)
|
||||
self.__DB_CONN.ping()
|
||||
return self.__DB_CONN
|
||||
except redis.exceptions.ConnectionError:
|
||||
return False
|
||||
except Exception:
|
||||
self.__DB_ERR = mw.getTracebackInfo()
|
||||
return False
|
||||
|
||||
# 获取配置项
|
||||
def get_options(self, get=None):
|
||||
|
||||
result = {}
|
||||
redis_conf = mw.readFile("{}/redis/redis.conf".format(mw.getServerDir()))
|
||||
if not redis_conf: return False
|
||||
|
||||
keys = ["bind", "port", "timeout", "maxclients", "databases", "requirepass", "maxmemory"]
|
||||
for k in keys:
|
||||
v = ""
|
||||
rep = "\n%s\s+(.+)" % k
|
||||
group = re.search(rep, redis_conf)
|
||||
if not group:
|
||||
if k == "maxmemory":
|
||||
v = "0"
|
||||
if k == "maxclients":
|
||||
v = "10000"
|
||||
if k == "requirepass":
|
||||
v = ""
|
||||
else:
|
||||
if k == "maxmemory":
|
||||
v = int(group.group(1).strip("mb"))
|
||||
else:
|
||||
v = group.group(1)
|
||||
result[k] = v
|
||||
return result
|
||||
|
||||
def set_host(self, host, port, name, username, password, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_NAME = name
|
||||
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
|
||||
self.__DB_USER = str(username)
|
||||
self._USER = str(username)
|
||||
self.__DB_PASS = str(password)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__DB_LOCAL = 1
|
||||
return self
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlRedisCtr():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getInstanceBySid(self, sid = 0):
|
||||
instance = nosqlRedis()
|
||||
return instance
|
||||
|
||||
def getList(self, args):
|
||||
|
||||
sid = args['sid']
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(0)
|
||||
if redis_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
is_cluster = redis_info.get("cluster_enabled", 0)
|
||||
if is_cluster != 0:
|
||||
return mw.returnData(False, "当前不支持连接redis集群!")
|
||||
|
||||
db_num = 16
|
||||
if sid != 0:
|
||||
db_num = 1000
|
||||
|
||||
result = []
|
||||
for x in range(0, db_num):
|
||||
data = {}
|
||||
data['id'] = x
|
||||
data['name'] = 'DB{}'.format(x)
|
||||
try:
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(x)
|
||||
data['keynum'] = redis_instance.dbsize()
|
||||
result.append(data)
|
||||
except:
|
||||
break
|
||||
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getDbKeyList(self, args):
|
||||
p = 1
|
||||
size = 10
|
||||
|
||||
if not 'sid' in args:
|
||||
return mw.returnData(False, "缺少参数!sid")
|
||||
|
||||
if 'p' in args:
|
||||
p = args['p']
|
||||
if p < 1:
|
||||
p = 1
|
||||
if p > 10:
|
||||
p = 10
|
||||
|
||||
if 'size' in args:
|
||||
size = args['size']
|
||||
|
||||
sid = args['sid']
|
||||
idx = args['idx']
|
||||
search = '*'
|
||||
if 'search' in args and args['search'] != '':
|
||||
search = args['search']
|
||||
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
total = redis_instance.dbsize()
|
||||
|
||||
if search != '*':
|
||||
keylist = redis_instance.keys(search)
|
||||
total = len(keylist)
|
||||
else:
|
||||
keys = redis_instance.scan(cursor=0, match="{}".format(search), count=p*size)
|
||||
keylist = keys[1]
|
||||
|
||||
slist = keylist[(p - 1) * size:p*size]
|
||||
|
||||
items = []
|
||||
for key in slist:
|
||||
item = {}
|
||||
try:
|
||||
item['name'] = key.decode()
|
||||
except Exception as e:
|
||||
item['name'] = str(key)
|
||||
|
||||
item['endtime'] = redis_instance.ttl(key)
|
||||
item['type'] = redis_instance.type(key).decode()
|
||||
|
||||
if item['type'] == 'string':
|
||||
try:
|
||||
item['val'] = redis_instance.get(key).decode()
|
||||
except Exception as e:
|
||||
item['val'] = str(redis_instance.get(key))
|
||||
elif item['type'] == 'hash':
|
||||
if redis_instance.hlen(key) > 500:
|
||||
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.hlen(key))
|
||||
else:
|
||||
item['val'] = str(redis_instance.hgetall(key))
|
||||
elif item['type'] == 'list':
|
||||
if redis_instance.llen(key) > 500:
|
||||
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.llen(key))
|
||||
else:
|
||||
item['val'] = str(redis_instance.lrange(key, 0, -1))
|
||||
elif item['type'] == 'set':
|
||||
if redis_instance.scard(key) > 500:
|
||||
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.scard(key))
|
||||
else:
|
||||
item['val'] = str(redis_instance.smembers(key))
|
||||
elif item['type'] == 'zset':
|
||||
if redis_instance.zcard(key) > 500:
|
||||
item['val'] = "数据量过大无法显示!共 {} 条".format(redis_instance.zcard(key))
|
||||
else:
|
||||
item['val'] = str(redis_instance.zrange(key, 0, -1, withscores=True))
|
||||
else:
|
||||
item['val'] = ''
|
||||
|
||||
try:
|
||||
item['len'] = redis_instance.strlen(key)
|
||||
except:
|
||||
item['len'] = len(item['val'])
|
||||
items.append(item)
|
||||
|
||||
|
||||
page_args = {}
|
||||
page_args['count'] = total
|
||||
page_args['tojs'] = 'redisGetKeyList'
|
||||
page_args['p'] = p
|
||||
page_args['row'] = size
|
||||
|
||||
rdata = {}
|
||||
rdata['page'] = mw.getPage(page_args)
|
||||
rdata['data'] = items
|
||||
return mw.returnData(True,'ok',rdata)
|
||||
|
||||
def setKv(self,args):
|
||||
if not 'name' in args:
|
||||
return mw.returnData(False, "缺少参数!name")
|
||||
if not 'val' in args:
|
||||
return mw.returnData(False, "缺少参数!val")
|
||||
if not 'idx' in args:
|
||||
return mw.returnData(False, "缺少参数!idx")
|
||||
|
||||
sid = args['sid']
|
||||
idx = args['idx']
|
||||
|
||||
name = args["name"]
|
||||
val = args["val"]
|
||||
endtime = args["endtime"]
|
||||
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
if redis_info['role'] == 'slave':
|
||||
return mw.returnData(False,'从库不能写操作!')
|
||||
|
||||
if endtime != '0':
|
||||
redis_instance.set(name, val, int(endtime))
|
||||
else:
|
||||
redis_instance.set(name, val)
|
||||
|
||||
return mw.returnData(True,'操作成功')
|
||||
|
||||
def delVal(self, args):
|
||||
sid = args['sid']
|
||||
idx = args['idx']
|
||||
name = args["name"]
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
if redis_info['role'] == 'slave':
|
||||
return mw.returnData(False,'从库不能删除操作!')
|
||||
|
||||
redis_instance.delete(name)
|
||||
return mw.returnData(True,'操作成功')
|
||||
|
||||
def batchDelVal(self, args):
|
||||
sid = args['sid']
|
||||
idx = args['idx']
|
||||
keys = args["keys"]
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
if redis_info['role'] == 'slave':
|
||||
return mw.returnData(False,'从库不能删除操作!')
|
||||
|
||||
for k in keys:
|
||||
redis_instance.delete(k)
|
||||
return mw.returnData(True,'操作成功')
|
||||
|
||||
def clearFlushDB(self, args):
|
||||
|
||||
sid = args['sid']
|
||||
idxs = args['idxs']
|
||||
|
||||
for idx in idxs:
|
||||
redis_instance = self.getInstanceBySid(sid).redis_conn(idx)
|
||||
|
||||
redis_info = redis_instance.info()
|
||||
if redis_info['role'] == 'slave':
|
||||
return mw.returnData(False,'从库不能清空操作!')
|
||||
|
||||
redis_instance.flushdb()
|
||||
|
||||
return mw.returnData(True,'操作成功')
|
||||
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
# 获取 redis databases 列表
|
||||
def get_list(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.getList(args)
|
||||
|
||||
# 获取 redis key 列表
|
||||
def get_dbkey_list(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.getDbKeyList(args)
|
||||
|
||||
|
||||
def set_kv(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.setKv(args)
|
||||
|
||||
|
||||
def del_val(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.delVal(args)
|
||||
|
||||
def batch_del_val(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.batchDelVal(args)
|
||||
|
||||
def clear_flushdb(args):
|
||||
t = nosqlRedisCtr()
|
||||
return t.clearFlushDB(args)
|
||||
|
||||
# 测试
|
||||
def test(args):
|
||||
sid = args['sid']
|
||||
t = nosqlRedis()
|
||||
print(t.get_options())
|
||||
print("test")
|
||||
return 'ok'
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
|
||||
Executable
+296
@@ -0,0 +1,296 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import pymongo
|
||||
import json
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
def singleton(cls):
|
||||
_instance = {}
|
||||
|
||||
def inner():
|
||||
if cls not in _instance:
|
||||
_instance[cls] = cls()
|
||||
return _instance[cls]
|
||||
return inner
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlMySQL():
|
||||
|
||||
__DB_PASS = None
|
||||
__DB_USER = None
|
||||
__DB_PORT = 3306
|
||||
__DB_HOST = '127.0.0.1'
|
||||
__DB_CONN = None
|
||||
__DB_ERR = None
|
||||
__DB_SOCKET = None
|
||||
|
||||
__DB_LOCAL = None
|
||||
|
||||
def __init__(self):
|
||||
self.__config = self.get_options(None)
|
||||
|
||||
|
||||
def conn(self):
|
||||
|
||||
if self.__DB_HOST in ['127.0.0.1', 'localhost']:
|
||||
my_path = "{}/mysql".format(mw.getServerDir())
|
||||
if not os.path.exists(my_path): return False
|
||||
|
||||
if not self.__DB_LOCAL:
|
||||
# print(self.__config)
|
||||
self.__DB_PORT = int(self.__config['port'])
|
||||
self.__DB_USER = self.__config['username']
|
||||
self.__DB_PASS = self.__config['password']
|
||||
self.__DB_SOCKET = self.__config['socket']
|
||||
|
||||
try:
|
||||
|
||||
db = mw.getMyORM()
|
||||
db.setPort(self.__DB_PORT)
|
||||
db.setPwd(self.__DB_PASS)
|
||||
db.setUser(self.__DB_USER)
|
||||
if self.__DB_SOCKET != '':
|
||||
db.setSocket(self.__DB_SOCKET)
|
||||
|
||||
return db
|
||||
except Exception:
|
||||
self.__DB_ERR = mw.get_error_info()
|
||||
return False
|
||||
|
||||
def sqliteDb(self,dbname='databases'):
|
||||
my_root_path = mw.getServerDir() +'/mysql'
|
||||
name = 'mysql'
|
||||
conn = mw.M(dbname).dbPos(my_root_path, name)
|
||||
return conn
|
||||
|
||||
# 获取配置项
|
||||
def get_options(self, get=None):
|
||||
result = {}
|
||||
|
||||
|
||||
my_cnf_path = "{}/mysql/etc/my.cnf".format(mw.getServerDir())
|
||||
my_content = mw.readFile(my_cnf_path)
|
||||
if not my_content: return False
|
||||
|
||||
mysql_pass = self.sqliteDb('config').where('id=?', (1,)).getField('mysql_root')
|
||||
result['password'] = mysql_pass
|
||||
result['username'] = 'root'
|
||||
keys = ["bind_ip", "port"]
|
||||
|
||||
result['host'] = '127.0.0.1'
|
||||
rep = 'port\s*=\s*(.*)'
|
||||
|
||||
port_re = re.search(rep, my_content)
|
||||
if port_re:
|
||||
result['port'] = int(port_re.groups()[0].strip())
|
||||
else:
|
||||
result['port'] = 3306
|
||||
|
||||
socket_rep = 'socket\s*=\s*(.*)'
|
||||
socket_re = re.search(socket_rep, my_content)
|
||||
if socket_re:
|
||||
result['socket'] = socket_re.groups()[0].strip()
|
||||
else:
|
||||
result['socket'] = ''
|
||||
|
||||
return result
|
||||
|
||||
def set_host(self, host, port, name, username, password, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_NAME = name
|
||||
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
|
||||
self.__DB_USER = str(username)
|
||||
self._USER = str(username)
|
||||
self.__DB_PASS = str(password)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__DB_LOCAL = 1
|
||||
return self
|
||||
|
||||
|
||||
|
||||
@singleton
|
||||
class nosqlMySQLCtr():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def getInstanceBySid(self, sid = 0):
|
||||
instance = nosqlMySQL()
|
||||
return instance
|
||||
|
||||
def getDbList(self, args):
|
||||
sid = args['sid']
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = {}
|
||||
db_list = my_instance.query('show databases')
|
||||
rlist = []
|
||||
for x in db_list:
|
||||
if not x['Database'] in ['information_schema', 'mysql', 'performance_schema','sys']:
|
||||
rlist.append(x['Database'])
|
||||
result['list'] = rlist
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getTableList(self, args):
|
||||
sid = args['sid']
|
||||
db = args['db']
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
sql = "select * from information_schema.tables where table_schema = '"+db+"'"
|
||||
table_list = my_instance.query(sql)
|
||||
# print(table_list)
|
||||
|
||||
rlist = []
|
||||
for x in table_list:
|
||||
# print(x['TABLE_NAME'])
|
||||
rlist.append(x['TABLE_NAME'])
|
||||
result = {}
|
||||
result['list'] = rlist
|
||||
return mw.returnData(True,'ok', result)
|
||||
|
||||
def getDataList(self, args):
|
||||
sid = args['sid']
|
||||
db = args['db']
|
||||
table = args['table']
|
||||
p = 1
|
||||
size = 10
|
||||
if 'p' in args:
|
||||
p = args['p']
|
||||
|
||||
if 'size' in args:
|
||||
size = args['size']
|
||||
|
||||
start_index = (p - 1) * size
|
||||
|
||||
|
||||
args_where = {}
|
||||
where_sql = ''
|
||||
if 'where' in args:
|
||||
args_where = args['where']
|
||||
if 'field' in args_where:
|
||||
if args_where['field'] == 'id' or args_where['field'].find('id')>-1:
|
||||
where_sql = ' where '+args_where['field'] + " = '"+args_where['value']+"' "
|
||||
else:
|
||||
where_sql = ' where '+args_where['field'] + " like '%"+args_where['value']+"%' "
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
my_instance.setDbName(db)
|
||||
sql = 'select count(*) as num from ' + table + where_sql
|
||||
# print(sql)
|
||||
count_result = my_instance.query(sql)
|
||||
count = count_result[0]['num']
|
||||
|
||||
|
||||
sql = 'select * from ' + table + where_sql + ' limit '+str(start_index)+',10';
|
||||
# print(sql)
|
||||
result = my_instance.query(sql)
|
||||
# print(result)
|
||||
|
||||
page_args = {}
|
||||
page_args['count'] = count
|
||||
page_args['tojs'] = 'mysqlGetDataList'
|
||||
page_args['p'] = p
|
||||
page_args['row'] = size
|
||||
|
||||
rdata = {}
|
||||
rdata['page'] = mw.getPage(page_args)
|
||||
rdata['list'] = result
|
||||
rdata['count'] = count
|
||||
|
||||
rdata['soso_field'] = ''
|
||||
if 'field' in args_where:
|
||||
rdata['soso_field'] = args_where['field']
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
def showProcessList(self,args):
|
||||
sql = 'show processlist';
|
||||
sid = args['sid']
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = my_instance.query(sql)
|
||||
rdata = {}
|
||||
rdata['list'] = result
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
def showStatusList(self,args):
|
||||
sql = 'show status';
|
||||
sid = args['sid']
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = my_instance.query(sql)
|
||||
rdata = {}
|
||||
rdata['list'] = result
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
def showStatsList(self, args):
|
||||
sql = "show status like 'Com_%'";
|
||||
sid = args['sid']
|
||||
|
||||
my_instance = self.getInstanceBySid(sid).conn()
|
||||
if my_instance is False:
|
||||
return mw.returnData(False,'无法链接')
|
||||
|
||||
result = my_instance.query(sql)
|
||||
rdata = {}
|
||||
rdata['list'] = result
|
||||
return mw.returnData(True,'ok', rdata)
|
||||
|
||||
# ---------------------------------- run ----------------------------------
|
||||
# 获取 mysql 列表
|
||||
def get_db_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.getDbList(args)
|
||||
|
||||
# 获取 mysql 列表
|
||||
def get_table_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.getTableList(args)
|
||||
|
||||
def get_data_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.getDataList(args)
|
||||
|
||||
def get_proccess_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.showProcessList(args)
|
||||
|
||||
def get_status_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.showStatusList(args)
|
||||
|
||||
def get_stats_list(args):
|
||||
t = nosqlMySQLCtr()
|
||||
return t.showStatsList(args)
|
||||
|
||||
|
||||
# 测试
|
||||
def test(args):
|
||||
sid = args['sid']
|
||||
t = nosqlMySQLCtr()
|
||||
print(t.get_options())
|
||||
print("test")
|
||||
return 'ok'
|
||||
@@ -0,0 +1,48 @@
|
||||
.main-content .safe {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mask_layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgb(255 255 255 / 60%);
|
||||
z-index: 9998;
|
||||
}
|
||||
|
||||
.mask_layer .prompt_description {
|
||||
width: 350px;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-top: -25px;
|
||||
margin-left: -175px;
|
||||
background: #fff;
|
||||
box-shadow: 1px 1px 50px rgb(0 0 0 / 30%);
|
||||
border: 1px solid #eee;
|
||||
border-radius: 2px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#mongodb_search xm-select {
|
||||
min-height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
#mongodb_search xm-select .xm-label .xm-label-block{
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
#mongodb td:last-child, th:last-child {
|
||||
width: 44px;
|
||||
position:sticky;
|
||||
right:0; /* 首行永远固定在左侧 */
|
||||
z-index:1;
|
||||
background-color:white;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
/* menu start */
|
||||
.menu .current .menu_plugin_data_query:hover {
|
||||
background-image: url("/plugins/file?name=data_query&f=ico.png");
|
||||
}
|
||||
|
||||
.menu .menu_plugin_data_query {
|
||||
background-image: url("/plugins/file?name=data_query&f=ico.png");
|
||||
}
|
||||
|
||||
/* menu end */
|
||||
@@ -0,0 +1,294 @@
|
||||
<div class="main-content" style="min-height: 389px;">
|
||||
<div class="container-fluid" style="padding-bottom: 50px;">
|
||||
<div id="cutTab" class="pos-box bgw mtb15" style="height:45px">
|
||||
<div class="tab-list">
|
||||
<div class="tabs-item active" data-name="redis">Redis</div>
|
||||
<div class="tabs-item" data-name="mongodb">Mongodb</div>
|
||||
<div class="tabs-item" data-name="memcached">Memcached</div>
|
||||
<div class="tabs-item" data-name="mysql">MySQL</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bgw mtb15 pd15 tab-view-box firewall-tab-view safe" style="overflow: hidden;">
|
||||
|
||||
<div class="mask_layer" style="display:none;">
|
||||
<div class="prompt_description">当前未安装本地服务器,<a class="btlink install_server" href="/soft">点击安装</a></div>
|
||||
</div>
|
||||
|
||||
<!-- mysql start -->
|
||||
<!-- show w-full -->
|
||||
<div class="tab-con hide" id="mysql" style="padding: 0px;">
|
||||
|
||||
<div class="col-md-12" style="padding: 0px;overflow: hidden;">
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left">
|
||||
<div class="server_list" style="float:left;">
|
||||
<select name="sid" class="bt-input-text c5 mr5">
|
||||
<option value="0">本地服务器</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mysql_db_list" style="float:left;">
|
||||
<select name="mysql_db" class="bt-input-text c5 mr5">
|
||||
<option value="0">数据库空</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mysql_table_list" style="float:left;">
|
||||
<select name="mysql_table" class="bt-input-text c5 mr5">
|
||||
<option value="0">数据表空</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="field" style="float:left;">
|
||||
<select name="mysql_field_key" class="bt-input-text c5 mr5" style="width:80px;">
|
||||
<option value="0">无字段</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="value" style="float:left;">
|
||||
<input name="mysql_field_value" type="text" class="bt-input-text" placeholder="请输入查找内容">
|
||||
</div>
|
||||
|
||||
<button type="button" class="mysql_find btn btn-success btn-sm mr5 ml5" style="float:right;">
|
||||
<span>查找</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="position: relative;">
|
||||
<div id="mysql_table" class="mysql_table divtable mtb10">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th><span>编号</span></th>
|
||||
<th><span>操作类型</span></th>
|
||||
<th><span>详情</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mysql_list_page page">
|
||||
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12" style="padding-left: 3px;">
|
||||
<div id="mysql_list_tab" style="padding-top:0px;">
|
||||
<div class="tab-nav">
|
||||
<span data-name="proccess" class="on">进程</span>
|
||||
<span data-name="status" class="">状态</span>
|
||||
<span data-name="stats" class="">统计</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="position: relative;">
|
||||
<div id="mysql_ot_table" class="divtable">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th><span>编号</span></th>
|
||||
<th><span>操作类型</span></th>
|
||||
<th><span>详情</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- mysql end -->
|
||||
|
||||
<!-- mongodb start -->
|
||||
<!-- show w-full -->
|
||||
<div class="tab-con hide" id="mongodb" style="padding: 0px;">
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left">
|
||||
|
||||
<div class="field" style="float:left;">
|
||||
<select name="mongodb_field_key" class="bt-input-text c5 mr5" style="width:80px;">
|
||||
<option value="0">无字段</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="value" style="float:left;">
|
||||
<input name="mongodb_field_value" type="text" class="bt-input-text" placeholder="请输入查找内容">
|
||||
</div>
|
||||
|
||||
<button type="button" class="mongodb_find btn btn-success btn-sm mr5 ml5" style="float:right;">
|
||||
<span>查找</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" style="padding-top: 5px;">
|
||||
<div class="server_list" style="float:left;">
|
||||
<select name="sid" class="bt-input-text c5 mr5">
|
||||
<option value="0">本地服务器</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="db_list" style="float:left;">
|
||||
<select name="db" class="bt-input-text c5 mr5">
|
||||
<option value="0">空</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="search" id="mongodb_search"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="position: relative;">
|
||||
|
||||
<div id="mongodb_table" class="mongodb_table divtable mtb10">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th><span>编号</span></th>
|
||||
<th><span>操作类型</span></th>
|
||||
<th><span>详情</span></th>
|
||||
<th style="text-align:right;"><span>操作</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mongodb_list_page page">
|
||||
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- mongodb end -->
|
||||
|
||||
<!-- redis start -->
|
||||
<div class="tab-con show w-full" id="redis" style="padding: 0px;">
|
||||
<div id="redis_ctr" style="position: relative;">
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left">
|
||||
<button id="redis_add_key" type="button" class="refresh btn btn-success btn-sm mr5">
|
||||
<span>添加key</span>
|
||||
</button>
|
||||
<button id="redis_clear_all" type="button" class="clear btn btn-default btn-sm mr5" style="border-right: 1px solid #ccc;padding-right: 20px;">
|
||||
<span>清空数据库</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="redis_list_tab" style="padding-top:10px;">
|
||||
<div class="tab-nav">
|
||||
<!-- <span data-id="0" class="on">DB0(0)</span> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left"></div>
|
||||
<div class="pull-right" style="padding-top: 5px;">
|
||||
<div class="search">
|
||||
<input id="redis_ksearch" type="text" class="search_input" placeholder="请输入键名称">
|
||||
<span id="redis_ksearch_span" class="glyphicon glyphicon-search" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divtable mtb10 redis_table_content">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th width="30"><input type="checkbox" onclick="checkSelect();"></th>
|
||||
<th><span>键</span></th>
|
||||
<th><span>值</span></th>
|
||||
<th><span>数据类型</span></th>
|
||||
<th><span>数据长度</span></th>
|
||||
<th><span>有效期</span></th>
|
||||
<th style="text-align:right;"><span>操作</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tootls_group tootls_bottom">
|
||||
<div class="pull-left">
|
||||
<button id="redis_batch_del" type="button" class="btn btn-sm set_batch_option bt-disabled btn-default">批量删除</button>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<div class="page redis_list_page">
|
||||
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- redis end -->
|
||||
|
||||
<!-- memcached start -->
|
||||
<div class="tab-con hide" id="memcached" style="padding: 0px;">
|
||||
|
||||
<div id="memcached_ctr" style="position: relative;">
|
||||
<div class="tootls_group tootls_top">
|
||||
<div class="pull-left">
|
||||
<button id="memcached_add_key" type="button" class="refresh btn btn-success btn-sm mr5">
|
||||
<span>添加key</span>
|
||||
</button>
|
||||
<button id="memcached_clear_all" type="button" class="clear btn btn-default btn-sm mr5" style="border-right: 1px solid #ccc;padding-right: 20px;">
|
||||
<span>清空</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" style="padding-top: 5px;">
|
||||
<div class="item_list" style="float:left;">
|
||||
<select name="item" class="bt-input-text c5 mr5">
|
||||
<option value="0">空</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="search">
|
||||
<input id="memcached_ksearch" type="text" class="search_input" placeholder="请输入键名称">
|
||||
<span id="memcached_ksearch_span" class="glyphicon glyphicon-search" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="divtable mtb10 memcached_table_content">
|
||||
<table class="table table-hover">
|
||||
<thead style="position: relative;z-index: 1;">
|
||||
<tr>
|
||||
<th width="30"><input type="checkbox" onclick="checkSelect();"></th>
|
||||
<th><span>键</span></th>
|
||||
<th><span>值</span></th>
|
||||
<th><span>数据长度</span></th>
|
||||
<th><span>有效期</span></th>
|
||||
<th style="text-align:right;"><span>操作</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tootls_group tootls_bottom">
|
||||
<div class="pull-left">
|
||||
<button id="memcached_batch_del" type="button" class="btn btn-sm set_batch_option bt-disabled btn-default">批量删除</button>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<div class="page memcached_list_page">
|
||||
<div><span class="Pcurrent">0</span><span class="Pcount">共0条</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- memcached end -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Executable
+1281
File diff suppressed because it is too large
Load Diff
@@ -15,5 +15,5 @@
|
||||
"home": "https://docker.io",
|
||||
"doc1":"https://docker-py.readthedocs.io/",
|
||||
"type": 0,
|
||||
"pid": "2"
|
||||
"pid": "4"
|
||||
}
|
||||
@@ -15,5 +15,5 @@
|
||||
"api_doc":"https://developers.google.com/drive/api/guides/about-sdk?hl=zh_CN",
|
||||
"api_doc2":"https://developers.google.cn/drive/api/reference/rest/v3/comments/list?hl=zh-cn",
|
||||
"date":"2022-06-26",
|
||||
"pid":"4"
|
||||
"pid":"5"
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
# http://localhost/?code=M.C106_BAY.2.3e12c859-6107-0c5b-9ef4-14b3fb8269ba&state=JzHdzHXmA7x6zl7Be6cJ6uOlf9Bg69
|
||||
|
||||
|
||||
# python3 /www/mdserver-web/plugins/gdrive/index.py site bbs.midoks.me 3
|
||||
# python3 /www/mdserver-web/plugins/gdrive/index.py site bbs.midoks.icu 3
|
||||
# python3 /www/mdserver-web/plugins/gdrive/index.py database t1 3
|
||||
# python3 /www/server/mdserver-web/plugins/msonedrive/index.py path
|
||||
# /Users/midoks/Desktop/dev/python 3
|
||||
|
||||
@@ -8,6 +8,10 @@ GIT_SDIR="{$CODE_DIR}"
|
||||
GIT_USER_DIR="${GIT_SDIR}/{$USERNAME}"
|
||||
GIT_PROJECT_DIR="${GIT_USER_DIR}/{$PROJECT}"
|
||||
|
||||
if [ ! -d $GIT_USER_DIR ];then
|
||||
mkdir -p $GIT_USER_DIR
|
||||
chown -R www:www $GIT_USER_DIR
|
||||
fi
|
||||
|
||||
git config --global credential.helper store
|
||||
git config --global pull.rebase false
|
||||
@@ -34,7 +38,7 @@ if [ ! -d $WEB_PATH ];then
|
||||
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
else
|
||||
if [ -f $GIT_PROJECT_DIR/exclude.list ];then
|
||||
rsync -vauP --delete --exclude-from="$GIT_PROJECT_DIR/exclude.list" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
rsync -vauP --exclude-from="$GIT_PROJECT_DIR/exclude.list" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
else
|
||||
rsync -vauP --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
H_DIR={$HOOK_DIR}
|
||||
HL_DIR={$HOOK_LOGS_DIR}
|
||||
|
||||
|
||||
SH_LIST=`cd ${H_DIR} && ls | grep ".sh$"`
|
||||
|
||||
for sh_f in $SH_LIST; do
|
||||
ABS_FILE=${H_DIR}/${sh_f}
|
||||
ABS_LOGS=${HL_DIR}/${sh_f}.log
|
||||
echo "sh ${ABS_FILE} 2>${ABS_LOGS}"
|
||||
sh -x ${ABS_FILE} 2>${ABS_LOGS}
|
||||
done
|
||||
@@ -1,13 +1,21 @@
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
<div class="bt-form">
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('gitea');">服务</p>
|
||||
<p onclick="pluginInitD('gitea');">自启动</p>
|
||||
<!-- <p onclick="pluginConfig('gitea',null, 'init_conf');">启动配置</p> -->
|
||||
<p onclick="gogsEdit();">手动编辑</p>
|
||||
<p onclick="pluginConfig('gitea',null, 'conf');">配置文件</p>
|
||||
<p onclick="gogsSetConfig();">配置修改</p>
|
||||
<p onclick="giteaUserList();">用户列表</p>
|
||||
<p onclick="giteaRepoList();">项目列表</p>
|
||||
<!-- <p onclick="pluginLogs('gitea',null,'run_log');">运行日志</p> -->
|
||||
<!-- <p onclick="pluginLogs('gitea',null,'post_receive_log');" title="提交post-receive日志">提交日志</p> -->
|
||||
<p onclick="giteaRead();">使用说明</p>
|
||||
@@ -18,6 +26,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinHeight(530);
|
||||
$.getScript( "/plugins/file?name=gitea&f=js/gitea.js",function(){
|
||||
pluginService('gitea');
|
||||
});
|
||||
|
||||
+402
-19
@@ -453,6 +453,13 @@ def submitGogsConf():
|
||||
return mw.returnJson(True, '设置成功')
|
||||
|
||||
|
||||
def gogsEditTpl():
|
||||
data = {}
|
||||
data['post_receive'] = getPluginDir() + '/hook/post-receive.tpl'
|
||||
data['commit'] = getPluginDir() + '/hook/commit.tpl'
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def userList():
|
||||
|
||||
conf = getConf()
|
||||
@@ -473,7 +480,66 @@ def userList():
|
||||
|
||||
page = int(args['page'])
|
||||
page_size = int(args['page_size'])
|
||||
tojs = args['tojs']
|
||||
search = ''
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
user_where1 = ''
|
||||
user_where2 = ''
|
||||
if search != '':
|
||||
user_where1 = ' where name like "%' + search + '%"'
|
||||
user_where2 = ' where name like "%' + search + '%"'
|
||||
|
||||
data = {}
|
||||
|
||||
data['root_url'] = getRootUrl()
|
||||
|
||||
start = (page - 1) * page_size
|
||||
list_count = pQuery('select count(id) as num from user' + user_where1)
|
||||
count = list_count[0]["num"]
|
||||
list_data = pQuery(
|
||||
'select id,name,email from user ' + user_where2 + ' order by id desc limit ' + str(start) + ',' + str(page_size))
|
||||
data['list'] = mw.getPage({'count': count, 'p': page,
|
||||
'row': page_size, 'tojs': 'gogsUserList'})
|
||||
data['page'] = page
|
||||
data['page_size'] = page_size
|
||||
data['page_count'] = int(math.ceil(count / page_size))
|
||||
data['data'] = list_data
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
|
||||
|
||||
def checkRepoListIsHasScript(data):
|
||||
path = getRootPath()
|
||||
for x in range(len(data)):
|
||||
name = data[x]['name'] + '/' + data[x]['repo'] + '.git'
|
||||
path_tmp = path + '/' + name + '/custom_hooks/commit'
|
||||
if os.path.exists(path_tmp):
|
||||
data[x]['has_hook'] = True
|
||||
else:
|
||||
data[x]['has_hook'] = False
|
||||
return data
|
||||
|
||||
|
||||
def repoList():
|
||||
|
||||
conf = getConf()
|
||||
if not os.path.exists(conf):
|
||||
return mw.returnJson(False, "请先安装初始化!<br/>默认地址:http://" + mw.getLocalIp() + ":3000")
|
||||
|
||||
conf = getDbConfValue()
|
||||
gtype = getGiteaDbType(conf)
|
||||
if gtype != 'mysql':
|
||||
return mw.returnJson(False, "仅支持mysql数据操作!")
|
||||
|
||||
import math
|
||||
args = getArgs()
|
||||
|
||||
data = checkArgs(args, ['page', 'page_size'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
page = int(args['page'])
|
||||
page_size = int(args['page_size'])
|
||||
search = ''
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
@@ -482,14 +548,25 @@ def userList():
|
||||
|
||||
data['root_url'] = getRootUrl()
|
||||
|
||||
start = (page - 1) * page_size
|
||||
list_count = pQuery('select count(id) as num from user')
|
||||
repo_where1 = ''
|
||||
repo_where2 = ''
|
||||
if search != '':
|
||||
repo_where1 = ' where name like "%' + search + '%"'
|
||||
repo_where2 = ' where r.name like "%' + search + '%"'
|
||||
|
||||
start = (page - 1) * page_size
|
||||
list_count = pQuery(
|
||||
'select count(id) as num from repository' + repo_where1)
|
||||
count = list_count[0]["num"]
|
||||
list_data = pQuery(
|
||||
'select id,name,email from user order by id desc limit ' + str(start) + ',' + str(page_size))
|
||||
data['list'] = mw.getPage(
|
||||
{'count': count, 'p': page, 'row': page_size, 'tojs': tojs})
|
||||
sql = 'select r.id,r.owner_id,r.name as repo, u.name from repository r left join user u on r.owner_id=u.id ' + repo_where2 + ' order by r.id desc limit ' + \
|
||||
str(start) + ',' + str(page_size)
|
||||
# print(sql)
|
||||
list_data = pQuery(sql)
|
||||
# print(list_data)
|
||||
list_data = checkRepoListIsHasScript(list_data)
|
||||
|
||||
data['list'] = mw.getPage({'count': count, 'p': page,
|
||||
'row': page_size, 'tojs': 'gogsRepoListPage'})
|
||||
data['page'] = page
|
||||
data['page_size'] = page_size
|
||||
data['page_count'] = int(math.ceil(count / page_size))
|
||||
@@ -586,11 +663,9 @@ def projectScriptEdit():
|
||||
|
||||
def projectScriptLoad():
|
||||
args = getArgs()
|
||||
if not 'user' in args:
|
||||
return mw.returnJson(True, 'username missing')
|
||||
|
||||
if not 'name' in args:
|
||||
return mw.returnJson(True, 'project name missing')
|
||||
data = checkArgs(args, ['user', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
@@ -670,11 +745,299 @@ def projectScriptDebug():
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def gogsEdit():
|
||||
data = {}
|
||||
data['post_receive'] = getPluginDir() + '/hook/post-receive.tpl'
|
||||
data['commit'] = getPluginDir() + '/hook/commit.tpl'
|
||||
return mw.getJson(data)
|
||||
def projectScriptRun():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
|
||||
path = getRootPath() + '/' + user + '/' + name
|
||||
commit_sh = path + '/custom_hooks/commit'
|
||||
commit_log = path + '/custom_hooks/sh.log'
|
||||
script_run = 'sh -x ' + commit_sh + ' 2>' + commit_log
|
||||
|
||||
if not os.path.exists(commit_sh):
|
||||
return mw.returnJson(False, '脚本文件不存在!')
|
||||
|
||||
mw.execShell(script_run)
|
||||
mw.execShell('chown -R www:www ' + commit_log)
|
||||
return mw.returnJson(True, '脚本文件执行成功,观察日志!')
|
||||
|
||||
|
||||
def projectScriptSelf():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
|
||||
self_path = custom_hooks + '/self'
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
mw.execShell("chown -R www:www " + self_path)
|
||||
|
||||
self_logs_path = custom_hooks + '/self_logs'
|
||||
if not os.path.exists(self_logs_path):
|
||||
os.mkdir(self_logs_path)
|
||||
mw.execShell("chown -R www:www " + self_logs_path)
|
||||
|
||||
self_hook_file = custom_hooks + '/self_hook.sh'
|
||||
self_hook_exist = False
|
||||
if os.path.exists(self_hook_file):
|
||||
self_hook_exist = True
|
||||
|
||||
dlist = []
|
||||
if os.path.exists(self_path):
|
||||
for filename in os.listdir(self_path):
|
||||
tmp = {}
|
||||
filePath = self_path + '/' + filename
|
||||
if os.path.isfile(filePath):
|
||||
tmp['path'] = filePath
|
||||
tmp['name'] = os.path.basename(filePath)
|
||||
tmp['is_hidden'] = False
|
||||
if tmp['name'].endswith('.txt'):
|
||||
tmp['is_hidden'] = True
|
||||
|
||||
dlist.append(tmp)
|
||||
|
||||
dlist_sum = len(dlist)
|
||||
# print(dlist)
|
||||
rdata = {}
|
||||
rdata['data'] = dlist
|
||||
rdata['self_hook'] = self_hook_exist
|
||||
rdata['list'] = mw.getPage(
|
||||
{'count': dlist_sum, 'p': 1, 'row': 100, 'tojs': 'self_page'})
|
||||
|
||||
return mw.returnJson(True, 'ok', rdata)
|
||||
|
||||
|
||||
def projectScriptSelf_Create():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
|
||||
self_path = path = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks/self'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
abs_file = self_path + '/' + file + '.sh'
|
||||
if os.path.exists(abs_file):
|
||||
return mw.returnJson(False, '脚本已经存在!')
|
||||
|
||||
mw.writeFile(abs_file, "#!/bin/bash\necho `date +'%Y-%m-%d %H:%M:%S'`\n")
|
||||
mw.execShell('chown -R www:www ' + abs_file)
|
||||
rdata = {}
|
||||
rdata['abs_file'] = abs_file
|
||||
return mw.returnJson(True, '创建文件成功!', rdata)
|
||||
|
||||
|
||||
def projectScriptSelf_Del():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
self_path = custom_hooks + '/self'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
abs_file = self_path + '/' + file
|
||||
# print(abs_file)
|
||||
if not os.path.exists(abs_file):
|
||||
return mw.returnJson(False, '脚本已经删除!')
|
||||
|
||||
os.remove(abs_file)
|
||||
|
||||
# 日志也删除
|
||||
log_file = custom_hooks + '/self_logs/' + file + '.log'
|
||||
if os.path.exists(log_file):
|
||||
os.remove(log_file)
|
||||
|
||||
return mw.returnJson(True, '脚本删除成功!')
|
||||
|
||||
|
||||
def projectScriptSelf_Logs():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
|
||||
self_path = path = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks/self_logs'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
logs_file = self_path + '/' + file + '.log'
|
||||
if os.path.exists(logs_file):
|
||||
rdata = {}
|
||||
rdata['path'] = logs_file
|
||||
return mw.returnJson(True, 'ok', rdata)
|
||||
|
||||
return mw.returnJson(False, '日志不存在!')
|
||||
|
||||
|
||||
def projectScriptSelf_Run():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
self_path = custom_hooks + '/self/' + file
|
||||
self_logs_path = custom_hooks + '/self_logs/' + file + '.log'
|
||||
|
||||
shell = "sh -x " + self_path + " 2>" + self_logs_path + ' &'
|
||||
mw.execShell(shell)
|
||||
mw.execShell("chown -R www:www " + self_logs_path)
|
||||
return mw.returnJson(True, '执行成功!')
|
||||
|
||||
|
||||
def projectScriptSelf_Rename():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'o_file', 'n_file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
o_file = args['o_file']
|
||||
n_file = args['n_file']
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
self_path = custom_hooks + '/self'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
o_file_abs = self_path + '/' + o_file + '.sh'
|
||||
if not os.path.exists(o_file_abs):
|
||||
return mw.returnJson(False, '原文件已经不存在了!')
|
||||
|
||||
n_file_abs = self_path + '/' + n_file + '.sh'
|
||||
|
||||
os.rename(o_file_abs, n_file_abs)
|
||||
|
||||
# 日志也删除
|
||||
log_file = custom_hooks + '/self_logs/' + o_file + '.sh.log'
|
||||
if os.path.exists(log_file):
|
||||
os.remove(log_file)
|
||||
|
||||
return mw.returnJson(True, '重命名成功!')
|
||||
|
||||
|
||||
def projectScriptSelf_Enable():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'enable'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
enable = args['enable']
|
||||
|
||||
custom_path = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
|
||||
# 替换commit配置
|
||||
commit_path = custom_path + '/commit'
|
||||
note = '#Gogs Script Don`t Remove and Change'
|
||||
|
||||
self_file = custom_path + '/self_hook.sh'
|
||||
self_hook_tpl = getPluginDir() + '/hook/self_hook.tpl'
|
||||
|
||||
if enable == '1':
|
||||
content = mw.readFile(self_hook_tpl)
|
||||
content = content.replace('{$HOOK_DIR}', custom_path + '/self')
|
||||
content = content.replace(
|
||||
'{$HOOK_LOGS_DIR}', custom_path + '/self_logs')
|
||||
mw.writeFile(self_file, content)
|
||||
mw.execShell("chmod 777 " + self_file)
|
||||
mw.execShell("chown -R www:www " + self_file)
|
||||
|
||||
commit_content = mw.readFile(commit_path)
|
||||
commit_content += "\n\n" + "bash " + self_file + " " + note
|
||||
mw.writeFile(commit_path, commit_content)
|
||||
|
||||
return mw.returnJson(True, '开启成功!')
|
||||
else:
|
||||
commit_content = mw.readFile(commit_path)
|
||||
rep = ".*" + note
|
||||
commit_content = re.sub(rep, '', commit_content, re.M)
|
||||
commit_content = commit_content.strip()
|
||||
mw.writeFile(commit_path, commit_content)
|
||||
if os.path.exists(self_file):
|
||||
os.remove(self_file)
|
||||
return mw.returnJson(True, '关闭成功!')
|
||||
|
||||
|
||||
def projectScriptSelf_Status():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file', 'status'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
status = args['status']
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
self_path = custom_hooks + '/self'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
# 日志也删除
|
||||
log_file = custom_hooks + '/self_logs/' + file + '.log'
|
||||
if os.path.exists(log_file):
|
||||
os.remove(log_file)
|
||||
|
||||
if status == '1':
|
||||
file_abs = self_path + '/' + file
|
||||
file_text_abs = self_path + '/' + file + '.txt'
|
||||
os.rename(file_abs, file_text_abs)
|
||||
return mw.returnJson(True, '开始禁用成功!')
|
||||
else:
|
||||
file_abs = self_path + '/' + file.strip('.txt')
|
||||
file_text_abs = self_path + '/' + file
|
||||
os.rename(file_text_abs, file_abs)
|
||||
return mw.returnJson(True, '开始使用成功!')
|
||||
|
||||
return mw.returnJson(True, '禁用成功!')
|
||||
|
||||
|
||||
def getRsaPublic():
|
||||
@@ -745,8 +1108,12 @@ if __name__ == "__main__":
|
||||
print(getGogsConf())
|
||||
elif func == 'submit_gogs_conf':
|
||||
print(submitGogsConf())
|
||||
elif func == 'gogs_edit_tpl':
|
||||
print(gogsEditTpl())
|
||||
elif func == 'user_list':
|
||||
print(userList())
|
||||
elif func == 'repo_list':
|
||||
print(repoList())
|
||||
elif func == 'user_project_list':
|
||||
print(userProjectList())
|
||||
elif func == 'project_script_edit':
|
||||
@@ -757,8 +1124,24 @@ if __name__ == "__main__":
|
||||
print(projectScriptUnload())
|
||||
elif func == 'project_script_debug':
|
||||
print(projectScriptDebug())
|
||||
elif func == 'gogs_edit':
|
||||
print(gogsEdit())
|
||||
elif func == 'project_script_run':
|
||||
print(projectScriptRun())
|
||||
elif func == 'project_script_self':
|
||||
print(projectScriptSelf())
|
||||
elif func == 'project_script_self_create':
|
||||
print(projectScriptSelf_Create())
|
||||
elif func == 'project_script_self_del':
|
||||
print(projectScriptSelf_Del())
|
||||
elif func == 'project_script_self_logs':
|
||||
print(projectScriptSelf_Logs())
|
||||
elif func == 'project_script_self_run':
|
||||
print(projectScriptSelf_Run())
|
||||
elif func == 'project_script_self_rename':
|
||||
print(projectScriptSelf_Rename())
|
||||
elif func == 'project_script_self_enable':
|
||||
print(projectScriptSelf_Enable())
|
||||
elif func == 'project_script_self_status':
|
||||
print(projectScriptSelf_Status())
|
||||
elif func == 'get_rsa_public':
|
||||
print(getRsaPublic())
|
||||
elif func == 'get_total_statistics':
|
||||
|
||||
+414
-10
@@ -118,6 +118,7 @@ function gogsEdit(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
function giteaUserList(page, search) {
|
||||
|
||||
var _data = {};
|
||||
@@ -130,7 +131,6 @@ function giteaUserList(page, search) {
|
||||
if(typeof(search) != 'undefined'){
|
||||
_data['search'] = search;
|
||||
}
|
||||
_data['tojs'] = 'giteaUserList';
|
||||
|
||||
gogsPost('user_list', _data, function(data){
|
||||
|
||||
@@ -140,7 +140,7 @@ function giteaUserList(page, search) {
|
||||
return;
|
||||
}
|
||||
content = '<div class="finduser"><input class="bt-input-text mr5 outline_no" type="text" placeholder="查找用户名" id="find_user" style="height: 28px; border-radius: 3px;width: 435px;">';
|
||||
content += '<button class="btn btn-success btn-sm" onclick="userFind();">查找</button></div>';
|
||||
content += '<button class="btn btn-success btn-sm find_user" >查找</button></div>';
|
||||
|
||||
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
|
||||
content += '<thead><tr>';
|
||||
@@ -154,24 +154,31 @@ function giteaUserList(page, search) {
|
||||
|
||||
ulist = rdata['data']['data'];
|
||||
for (i in ulist){
|
||||
email = ulist[i]["email"] == '' ? '无' : ulist[i]["email"];
|
||||
|
||||
var email = ulist[i]["email"] == '' ? '无' : ulist[i]["email"];
|
||||
var user_url = rdata['data']['root_url'] + ulist[i]["name"];
|
||||
content += '<tr><td>'+ulist[i]["id"]+'</td>'+
|
||||
'<td>'+ulist[i]["name"]+'</td>'+
|
||||
'<td>'+email+'</td>'+
|
||||
'<td><a class="btlink" onclick="userProjectList(\''+ulist[i]["name"]+'\')">项目管理</a></td>'+
|
||||
'<td><a class="btlink" target="_blank" href="'+user_url+'">项目管理</a></td>'+
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
content += '</tbody>';
|
||||
content += '</table></div>';
|
||||
|
||||
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
|
||||
page += rdata['data']['list'];
|
||||
page += '</div></ul></div>';
|
||||
var page_html = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
|
||||
page_html += rdata['data']['list'];
|
||||
page_html += '</div></ul></div>';
|
||||
|
||||
content += page;
|
||||
content += page_html;
|
||||
|
||||
$(".soft-man-con").html(content);
|
||||
|
||||
$('.find_user').click(function(){
|
||||
var name = $('#find_user').val();
|
||||
giteaUserList(page, name);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -336,6 +343,403 @@ function projectScriptDebug(user,name,index){
|
||||
});
|
||||
}
|
||||
|
||||
function gogsRepoListPage(page, search){
|
||||
var _data = {};
|
||||
if (typeof(page) =='undefined'){
|
||||
var page = 1;
|
||||
}
|
||||
|
||||
_data['page'] = page;
|
||||
_data['page_size'] = 10;
|
||||
if(typeof(search) != 'undefined'){
|
||||
_data['search'] = search;
|
||||
}
|
||||
|
||||
gogsPost('repo_list', _data, function(data){
|
||||
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (!rdata.status){
|
||||
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
var ulist = rdata['data']['data'];
|
||||
var body = ''
|
||||
for (i in ulist){
|
||||
// console.log(ulist[i]);
|
||||
|
||||
var option = '';
|
||||
if(ulist[i]['has_hook']){
|
||||
option += '<a class="btlink unload" data-index="'+i+'">卸载脚本</a>' + ' | ';
|
||||
option += '<a class="btlink load" data-index="'+i+'">重载</a>' + ' | ';
|
||||
option += '<a class="btlink edit" data-index="'+i+'">编辑</a>' + ' | ';
|
||||
option += '<a class="btlink debug" data-index="'+i+'">日志</a>' + ' | ';
|
||||
option += '<a class="btlink run" data-index="'+i+'">手动</a>' + ' | ';
|
||||
option += '<a class="btlink scripts" data-index="'+i+'" onclick="projectScriptSelf(\''+ulist[i]["name"]+'\',\''+ulist[i]["repo"]+'\')" >自定义</a>';
|
||||
} else{
|
||||
option += '<a data-index="'+i+'" class="btlink load">加载脚本</a>';
|
||||
}
|
||||
|
||||
|
||||
body += '<tr><td>'+ulist[i]["id"]+'</td>'+
|
||||
'<td class="overflow_hide" style="width:70px;">' + ulist[i]["name"]+'</td>'+
|
||||
'<td class="overflow_hide" style="width:70px;display: inline-block;">' + ulist[i]["repo"]+'</td>'+
|
||||
'<td>' +
|
||||
'<a class="btlink" target="_blank" href="'+rdata['data']['root_url']+ulist[i]["name"]+'/'+ulist[i]["repo"]+'">源码</a>' + ' | ' +
|
||||
option +
|
||||
'</td>' +
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
$('#repo_list tbody').html(body);
|
||||
$('#repo_list_page').html(rdata['data']['list']);
|
||||
|
||||
$('.find_repo').click(function(){
|
||||
var find_repo = $('#find_repo').val();
|
||||
gogsRepoListPage(page, find_repo);
|
||||
});
|
||||
|
||||
|
||||
$('#repo_list .load').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_load', {'user':user,'name':name}, function(data){
|
||||
if (data.data != 'ok'){
|
||||
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
layer.msg('加载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
setTimeout(function(){
|
||||
gogsRepoListPage(page, search);
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
$('#repo_list .unload').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_unload', {'user':user,'name':name}, function(data){
|
||||
if (data.data != 'ok'){
|
||||
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.msg('卸载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
setTimeout(function(){
|
||||
gogsRepoListPage(page, search);
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
$('#repo_list .edit').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_edit', {'user':user,'name':name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (rdata['status']){
|
||||
onlineEditFile(0, rdata['data']['path']);
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#repo_list .debug').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_debug', {'user':user,'name':name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (rdata['status']){
|
||||
onlineEditFile(0, rdata['path']);
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#repo_list .run').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_run', {'user':user,'name':name}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
layer.msg(data.msg,{icon:data.status?1:2,time:2000,shade: [0.3, '#000']});
|
||||
});
|
||||
});
|
||||
|
||||
//---------
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function giteaRepoList() {
|
||||
content = '<div class="finduser"><input class="bt-input-text mr5 outline_no" type="text" placeholder="查找项目" id="find_repo" style="height: 28px; border-radius: 3px;width: 435px;">';
|
||||
content += '<button class="btn btn-success btn-sm find_repo">查找</button></div>';
|
||||
|
||||
content += '<div id="repo_list" class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
|
||||
content += '<thead><tr>';
|
||||
content += '<th style="width:50px;">序号</th>';
|
||||
content += '<th style="width:80px;">用户/组织</th>';
|
||||
content += '<th style="width:80px;">项目名</th>';
|
||||
content += '<th>操作</th>';
|
||||
content += '</tr></thead>';
|
||||
|
||||
content += '<tbody></tbody>';
|
||||
content += '</table></div>';
|
||||
|
||||
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="repo_list_page" class="page"></ul></div>';
|
||||
|
||||
content += page;
|
||||
|
||||
$(".soft-man-con").html(content);
|
||||
|
||||
gogsRepoListPage(1);
|
||||
}
|
||||
|
||||
function projectScriptSelfRender(user, name){
|
||||
gogsPost('project_script_self', {'user':user,'name':name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
|
||||
var data = rdata['data']['data'];
|
||||
|
||||
if (rdata['data']['self_hook']){
|
||||
$('#open_script').prop('checked',true);
|
||||
}
|
||||
|
||||
var body = '';
|
||||
if(data.length == 0 ){
|
||||
body += '<tr><td colspan="3" style="text-align:center;">无脚本数据</td></tr>';
|
||||
} else{
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var b_status = '<a class="btlink status" data-index="'+i+'" target="_blank">已使用</a>';
|
||||
if (data[i]["is_hidden"]){
|
||||
b_status = '<a class="btlink status" data-index="'+i+'" target="_blank">已隐藏</a>';
|
||||
}
|
||||
|
||||
body += '<tr>'+
|
||||
'<td>' + data[i]["name"]+'</td>'+
|
||||
'<td>' + b_status + '</td>'+
|
||||
'<td>' +
|
||||
'<a class="btlink del" data-index="'+i+'" target="_blank">删除</a>' + ' | ' +
|
||||
'<a class="btlink edit" data-index="'+i+'" target="_blank">编辑</a>' + ' | ' +
|
||||
'<a class="btlink logs" data-index="'+i+'" target="_blank">日志</a>' + ' | ' +
|
||||
'<a class="btlink run" data-index="'+i+'" target="_blank">手动</a>' + ' | ' +
|
||||
'<a class="btlink rename" data-index="'+i+'" target="_blank">重命名</a>' +
|
||||
'</td></tr>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$('#gogs_self_table tbody').html(body);
|
||||
$('#gogs_self_table .page').html(rdata['data']['list']);
|
||||
|
||||
$('#gogs_self_table .status').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
var status = '1';
|
||||
if (data[i]["is_hidden"]){
|
||||
status = '0';
|
||||
}
|
||||
gogsPost('project_script_self_status', {'user':user,'name':name,'file':file, status:status}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
showMsg(data.msg ,function(){
|
||||
projectScriptSelfRender(user, name);
|
||||
},{icon:data.code?2:1,time:2000,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
});
|
||||
|
||||
$('#gogs_self_table .del').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
gogsPost('project_script_self_del', {'user':user,'name':name,'file':file}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
showMsg(data.msg ,function(){
|
||||
projectScriptSelfRender(user, name);
|
||||
},{icon:data.code?2:1,time:2000,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
});
|
||||
|
||||
$('#gogs_self_table .edit').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var path = data[i]["path"];
|
||||
onlineEditFile(0,path);
|
||||
});
|
||||
|
||||
$('#gogs_self_table .logs').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
gogsPost('project_script_self_logs', {'user':user,'name':name,'file':file}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
// console.log(rdata);
|
||||
if (rdata['status']){
|
||||
onlineEditFile(0, rdata['data']['path']);
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:data.status?2:1,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#gogs_self_table .run').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
if (data[i]["is_hidden"]){
|
||||
layer.msg("已经禁用,不能执行!",{icon:2,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
gogsPost('project_script_self_run', {'user':user,'name':name,'file':file}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.msg(rdata.msg,{icon:data.status?1:2,time:2000,shade: [0.3, '#000']});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#gogs_self_table .rename').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
|
||||
if (data[i]["is_hidden"]){
|
||||
layer.msg("已经禁用,不能执行!",{icon:2,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
file = file.split('.sh')[0];
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
shift: 5,
|
||||
closeBtn: 1,
|
||||
area: '320px',
|
||||
title: '重命名',
|
||||
btn:['设置','关闭'],
|
||||
content: '<div class="bt-form pd20">\
|
||||
<div class="line">\
|
||||
<input type="text" class="bt-input-text" name="Name" id="newFileName" value="'+file+'" placeholder="文件名" style="width:100%" />\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
$("#newFileName").focus().keyup(function(e){
|
||||
if(e.keyCode == 13) $(".layui-layer-btn0").click();
|
||||
});
|
||||
},
|
||||
yes:function(){
|
||||
var n_file = $("#newFileName").val();
|
||||
var o_file = file;
|
||||
|
||||
gogsPost('project_script_self_rename', {'user':user,'name':name,'o_file':o_file,'n_file':n_file}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
showMsg(data.msg ,function(){
|
||||
$(".layui-layer-btn1").click();
|
||||
projectScriptSelfRender(user, name);
|
||||
},{icon:data.code?2:1,time:2000,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
//-----
|
||||
});
|
||||
//------
|
||||
});
|
||||
}
|
||||
|
||||
//新建文件
|
||||
function createScriptFile(type, user, name, file) {
|
||||
if (type == 1) {
|
||||
gogsPost('project_script_self_create', {'user':user,'name':name,'file': file }, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if(!rdata['status']){
|
||||
layer.msg(rdata.msg,{icon:2,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
showMsg(rdata.msg, function(){
|
||||
$(".layui-layer-btn1").click();
|
||||
onlineEditFile(0,rdata['data']['abs_file']);
|
||||
projectScriptSelfRender(user, name);
|
||||
}, {icon:1,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
return;
|
||||
}
|
||||
layer.open({
|
||||
type: 1,
|
||||
shift: 5,
|
||||
closeBtn: 1,
|
||||
area: '320px',
|
||||
title: '新建自定义脚本',
|
||||
btn:['新建','关闭'],
|
||||
content: '<div class="bt-form pd20">\
|
||||
<div class="line">\
|
||||
<input type="text" class="bt-input-text" name="Name" id="newFileName" value="" placeholder="文件名" style="width:100%" />\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
$("#newFileName").focus().keyup(function(e){
|
||||
if(e.keyCode == 13) $(".layui-layer-btn0").click();
|
||||
});
|
||||
},
|
||||
yes:function(){
|
||||
var file = $("#newFileName").val();;
|
||||
createScriptFile(1, user, name, file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function projectScriptSelf(user, name){
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '项目('+user+'/'+name+')自定义脚本',
|
||||
area: '500px',
|
||||
content:"<div class='bt-form pd15'>\
|
||||
<button id='create_script' class='btn btn-success btn-sm' type='button' style='margin-right: 5px;''>添加脚本</button>\
|
||||
<div style='float:right;'>\
|
||||
<span style='line-height: 23px;'>开启自定义脚本</span>\
|
||||
<input class='btswitch btswitch-ios' id='open_script' type='checkbox'>\
|
||||
<label id='script_hook_enable' class='btswitch-btn' for='open_script' style='display: inline-flex;line-height:38px;margin-left: 4px;float: right;'></label>\
|
||||
</div>\
|
||||
<div id='gogs_self_table' class='divtable' style='margin-top:5px;'>\
|
||||
<table class='table table-hover'>\
|
||||
<thead><tr><th style='width:100px;'>脚本文件名</th><th>状态</th><th>操作</th></tr></thead>\
|
||||
<tbody></tbody>\
|
||||
</table>\
|
||||
<div class='dataTables_paginate paging_bootstrap pagination' style='margin-top:0px;'>\
|
||||
<ul class='page'><div class='gogs_page'></div></ul>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>",
|
||||
success:function(){
|
||||
projectScriptSelfRender(user, name);
|
||||
|
||||
$('#create_script').click(function(){
|
||||
createScriptFile(0, user, name);
|
||||
});
|
||||
|
||||
$('#script_hook_enable').click(function(){
|
||||
var enable = $('#open_script').prop('checked');
|
||||
var enable_option = '0';
|
||||
if (!enable){
|
||||
enable_option = '1';
|
||||
}
|
||||
gogsPost('project_script_self_enable', {'user':user,'name':name,'enable':enable_option}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
showMsg(data.msg ,function(){
|
||||
projectScriptSelfRender(user, name);
|
||||
},{icon:data.status?1:2,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getRsaPublic(){
|
||||
gogsPost('get_rsa_public', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
@@ -361,8 +765,8 @@ function giteaRead(){
|
||||
|
||||
var readme = '<ul class="help-info-text c7">';
|
||||
readme += '<li>默认使用MySQL,第一个启动加载各种配置,并修改成正确的数据库配置</li>';
|
||||
readme += '<li>邮件端口使用456,gogs仅支持使用STARTTLS的SMTP协议</li>';
|
||||
readme += '<li>如果使用项目中脚本本地同步,<a target="_blank" href="https://github.com/midoks/mdserver-web/wiki/%E6%8F%92%E4%BB%B6%E7%AE%A1%E7%90%86%5Bgogs%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%5D#%E5%90%AF%E5%8A%A8gogs%E5%90%8E%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BD%BF%E7%94%A8hook%E8%84%9A%E6%9C%AC%E5%90%8C%E6%AD%A5%E4%BB%A3%E7%A0%81%E9%9C%80%E8%A6%81%E5%BC%80%E5%90%AFssh%E7%AB%AF%E5%8F%A3">点击查看</></li>';
|
||||
readme += '<li>邮件端口使用456,gitea仅支持使用STARTTLS的SMTP协议</li>';
|
||||
readme += '<li>项目【加载脚本】后,会自动同步到wwwroot目录下</li>';
|
||||
readme += '<li><a href="#" onclick="getRsaPublic();">点击查看本机公钥</></li>';
|
||||
readme += '</ul>';
|
||||
|
||||
|
||||
@@ -10,14 +10,19 @@ GIT_PROJECT_DIR="${GIT_USER_DIR}/{$PROJECT}"
|
||||
|
||||
|
||||
git config --global credential.helper store
|
||||
git config --global pull.rebase false
|
||||
|
||||
# echo $GIT_PROJECT_DIR
|
||||
if [ ! -d $GIT_PROJECT_DIR ];then
|
||||
mkdir -p $GIT_USER_DIR && cd $GIT_USER_DIR
|
||||
git clone $GITADDR
|
||||
git clone $GITADDR --branch main
|
||||
if [ "$?" != "0" ];then
|
||||
git clone $GITADDR
|
||||
fi
|
||||
fi
|
||||
|
||||
unset GIT_DIR
|
||||
|
||||
cd $GIT_PROJECT_DIR && git pull
|
||||
|
||||
# func 2
|
||||
@@ -26,9 +31,17 @@ cd $GIT_PROJECT_DIR && git pull
|
||||
|
||||
#更新的目的地址
|
||||
WEB_PATH={$WEB_ROOT}/{$USERNAME}/{$PROJECT}
|
||||
mkdir -p $WEB_PATH
|
||||
|
||||
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
if [ ! -d $WEB_PATH ];then
|
||||
mkdir -p $WEB_PATH
|
||||
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
else
|
||||
if [ -f $GIT_PROJECT_DIR/exclude.list ];then
|
||||
rsync -vauP --delete --exclude-from="$GIT_PROJECT_DIR/exclude.list" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
else
|
||||
rsync -vauP --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
|
||||
fi
|
||||
fi
|
||||
|
||||
sysName=`uname`
|
||||
if [ $sysName == 'Darwin' ]; then
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
H_DIR={$HOOK_DIR}
|
||||
HL_DIR={$HOOK_LOGS_DIR}
|
||||
|
||||
|
||||
SH_LIST=`cd ${H_DIR} && ls | grep ".sh$"`
|
||||
|
||||
for sh_f in $SH_LIST; do
|
||||
ABS_FILE=${H_DIR}/${sh_f}
|
||||
ABS_LOGS=${HL_DIR}/${sh_f}.log
|
||||
echo "sh ${ABS_FILE} 2>${ABS_LOGS}"
|
||||
sh -x ${ABS_FILE} 2>${ABS_LOGS}
|
||||
done
|
||||
+14
-3
@@ -1,13 +1,22 @@
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
<div class="bt-form">
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('gogs');">服务</p>
|
||||
<p onclick="pluginInitD('gogs');">自启动</p>
|
||||
<!-- <p onclick="pluginConfig('gogs',null, 'init_conf');">启动配置</p> -->
|
||||
<p onclick="gogsEdit();">手动编辑</p>
|
||||
<p onclick="gogsEditTpl();">手动编辑</p>
|
||||
<p onclick="pluginConfig('gogs',null, 'conf');">配置文件</p>
|
||||
<p onclick="gogsSetConfig();">配置修改</p>
|
||||
<p onclick="gogsUserList();">用户列表</p>
|
||||
<p onclick="gogsRepoList();">项目列表</p>
|
||||
<p onclick="pluginLogs('gogs',null,'run_log');">运行日志</p>
|
||||
<p onclick="pluginLogs('gogs',null,'post_receive_log');" title="提交post-receive日志">提交日志</p>
|
||||
<p onclick="gogsRead();">使用说明</p>
|
||||
@@ -18,6 +27,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=gogs&f=js/gogs.js");
|
||||
pluginService('gogs');
|
||||
resetPluginWinHeight(530);
|
||||
$.getScript( "/plugins/file?name=gogs&f=js/gogs.js",function(){
|
||||
pluginService('gogs');
|
||||
});
|
||||
</script>
|
||||
+394
-12
@@ -456,6 +456,13 @@ def submitGogsConf():
|
||||
return mw.returnJson(True, '设置成功')
|
||||
|
||||
|
||||
def gogsEditTpl():
|
||||
data = {}
|
||||
data['post_receive'] = getPluginDir() + '/hook/post-receive.tpl'
|
||||
data['commit'] = getPluginDir() + '/hook/commit.tpl'
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def userList():
|
||||
|
||||
conf = getConf()
|
||||
@@ -470,6 +477,66 @@ def userList():
|
||||
import math
|
||||
args = getArgs()
|
||||
|
||||
data = checkArgs(args, ['page', 'page_size'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
page = int(args['page'])
|
||||
page_size = int(args['page_size'])
|
||||
search = ''
|
||||
if 'search' in args:
|
||||
search = args['search']
|
||||
|
||||
user_where1 = ''
|
||||
user_where2 = ''
|
||||
if search != '':
|
||||
user_where1 = ' where name like "%' + search + '%"'
|
||||
user_where2 = ' where name like "%' + search + '%"'
|
||||
|
||||
data = {}
|
||||
|
||||
data['root_url'] = getRootUrl()
|
||||
|
||||
start = (page - 1) * page_size
|
||||
list_count = pQuery('select count(id) as num from user' + user_where1)
|
||||
count = list_count[0]["num"]
|
||||
list_data = pQuery(
|
||||
'select id,name,email from user ' + user_where2 + ' order by id desc limit ' + str(start) + ',' + str(page_size))
|
||||
data['list'] = mw.getPage({'count': count, 'p': page,
|
||||
'row': page_size, 'tojs': 'gogsUserList'})
|
||||
data['page'] = page
|
||||
data['page_size'] = page_size
|
||||
data['page_count'] = int(math.ceil(count / page_size))
|
||||
data['data'] = list_data
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
|
||||
|
||||
def checkRepoListIsHasScript(data):
|
||||
path = getRootPath()
|
||||
for x in range(len(data)):
|
||||
name = data[x]['name'] + '/' + data[x]['repo'] + '.git'
|
||||
path_tmp = path + '/' + name + '/custom_hooks/post-receive'
|
||||
if os.path.exists(path_tmp):
|
||||
data[x]['has_hook'] = True
|
||||
else:
|
||||
data[x]['has_hook'] = False
|
||||
return data
|
||||
|
||||
|
||||
def repoList():
|
||||
|
||||
conf = getConf()
|
||||
if not os.path.exists(conf):
|
||||
return mw.returnJson(False, "请先安装初始化!<br/>默认地址:http://" + mw.getLocalIp() + ":3000")
|
||||
|
||||
conf = getDbConfValue()
|
||||
gtype = getGogsDbType(conf)
|
||||
if gtype != 'mysql':
|
||||
return mw.returnJson(False, "仅支持mysql数据操作!")
|
||||
|
||||
import math
|
||||
args = getArgs()
|
||||
|
||||
data = checkArgs(args, ['page', 'page_size'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
@@ -484,13 +551,25 @@ def userList():
|
||||
|
||||
data['root_url'] = getRootUrl()
|
||||
|
||||
repo_where1 = ''
|
||||
repo_where2 = ''
|
||||
if search != '':
|
||||
repo_where1 = ' where name like "%' + search + '%"'
|
||||
repo_where2 = ' where r.name like "%' + search + '%"'
|
||||
|
||||
start = (page - 1) * page_size
|
||||
list_count = pQuery('select count(id) as num from user')
|
||||
list_count = pQuery(
|
||||
'select count(id) as num from repository' + repo_where1)
|
||||
count = list_count[0]["num"]
|
||||
list_data = pQuery(
|
||||
'select id,name,email from user order by id desc limit ' + str(start) + ',' + str(page_size))
|
||||
sql = 'select r.id,r.owner_id,r.name as repo, u.name from repository r left join user u on r.owner_id=u.id ' + repo_where2 + ' order by r.id desc limit ' + \
|
||||
str(start) + ',' + str(page_size)
|
||||
# print(sql)
|
||||
list_data = pQuery(sql)
|
||||
# print(list_data)
|
||||
list_data = checkRepoListIsHasScript(list_data)
|
||||
|
||||
data['list'] = mw.getPage({'count': count, 'p': page,
|
||||
'row': page_size, 'tojs': 'gogsUserList'})
|
||||
'row': page_size, 'tojs': 'gogsRepoListPage'})
|
||||
data['page'] = page
|
||||
data['page_size'] = page_size
|
||||
data['page_count'] = int(math.ceil(count / page_size))
|
||||
@@ -561,7 +640,7 @@ def userProjectList():
|
||||
data['data'] = ret_data
|
||||
data['args'] = args
|
||||
data['list'] = mw.getPage(
|
||||
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'userProjectList'})
|
||||
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'userProjectListPage'})
|
||||
|
||||
return mw.returnJson(True, 'OK', data)
|
||||
|
||||
@@ -668,11 +747,294 @@ def projectScriptDebug():
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def gogsEdit():
|
||||
data = {}
|
||||
data['post_receive'] = getPluginDir() + '/hook/post-receive.tpl'
|
||||
data['commit'] = getPluginDir() + '/hook/commit.tpl'
|
||||
return mw.getJson(data)
|
||||
def projectScriptRun():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
|
||||
path = getRootPath() + '/' + user + '/' + name
|
||||
commit_sh = path + '/custom_hooks/commit'
|
||||
commit_log = path + '/custom_hooks/sh.log'
|
||||
script_run = 'sh -x ' + commit_sh + ' 2>' + commit_log
|
||||
|
||||
if not os.path.exists(commit_sh):
|
||||
return mw.returnJson(False, '脚本文件不存在!')
|
||||
|
||||
mw.execShell(script_run)
|
||||
return mw.returnJson(True, '脚本文件执行成功,观察日志!')
|
||||
|
||||
|
||||
def projectScriptSelf():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
|
||||
self_path = custom_hooks + '/self'
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
self_logs_path = custom_hooks + '/self_logs'
|
||||
if not os.path.exists(self_logs_path):
|
||||
os.mkdir(self_logs_path)
|
||||
|
||||
self_hook_file = custom_hooks + '/self_hook.sh'
|
||||
self_hook_exist = False
|
||||
if os.path.exists(self_hook_file):
|
||||
self_hook_exist = True
|
||||
|
||||
dlist = []
|
||||
if os.path.exists(self_path):
|
||||
for filename in os.listdir(self_path):
|
||||
tmp = {}
|
||||
filePath = self_path + '/' + filename
|
||||
if os.path.isfile(filePath):
|
||||
tmp['path'] = filePath
|
||||
tmp['name'] = os.path.basename(filePath)
|
||||
tmp['is_hidden'] = False
|
||||
if tmp['name'].endswith('.txt'):
|
||||
tmp['is_hidden'] = True
|
||||
|
||||
dlist.append(tmp)
|
||||
|
||||
dlist_sum = len(dlist)
|
||||
# print(dlist)
|
||||
rdata = {}
|
||||
rdata['data'] = dlist
|
||||
rdata['self_hook'] = self_hook_exist
|
||||
rdata['list'] = mw.getPage(
|
||||
{'count': dlist_sum, 'p': 1, 'row': 100, 'tojs': 'self_page'})
|
||||
|
||||
return mw.returnJson(True, 'ok', rdata)
|
||||
|
||||
|
||||
def projectScriptSelf_Create():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
|
||||
self_path = path = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks/self'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
abs_file = self_path + '/' + file + '.sh'
|
||||
if os.path.exists(abs_file):
|
||||
return mw.returnJson(False, '脚本已经存在!')
|
||||
|
||||
mw.writeFile(abs_file, "#!/bin/bash\necho `date +'%Y-%m-%d %H:%M:%S'`\n")
|
||||
|
||||
rdata = {}
|
||||
rdata['abs_file'] = abs_file
|
||||
return mw.returnJson(True, '创建文件成功!', rdata)
|
||||
|
||||
|
||||
def projectScriptSelf_Del():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
self_path = custom_hooks + '/self'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
abs_file = self_path + '/' + file
|
||||
# print(abs_file)
|
||||
if not os.path.exists(abs_file):
|
||||
return mw.returnJson(False, '脚本已经删除!')
|
||||
|
||||
os.remove(abs_file)
|
||||
|
||||
# 日志也删除
|
||||
log_file = custom_hooks + '/self_logs/' + file + '.log'
|
||||
if os.path.exists(log_file):
|
||||
os.remove(log_file)
|
||||
|
||||
return mw.returnJson(True, '脚本删除成功!')
|
||||
|
||||
|
||||
def projectScriptSelf_Logs():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
|
||||
self_path = path = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks/self_logs'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
logs_file = self_path + '/' + file + '.log'
|
||||
if os.path.exists(logs_file):
|
||||
rdata = {}
|
||||
rdata['path'] = logs_file
|
||||
return mw.returnJson(True, 'ok', rdata)
|
||||
|
||||
return mw.returnJson(False, '日志不存在!')
|
||||
|
||||
|
||||
def projectScriptSelf_Run():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
self_path = custom_hooks + '/self/' + file
|
||||
self_logs_path = custom_hooks + '/self_logs/' + file + '.log'
|
||||
|
||||
shell = "sh -x " + self_path + " 2>" + self_logs_path + ' &'
|
||||
mw.execShell(shell)
|
||||
return mw.returnJson(True, '执行成功!')
|
||||
|
||||
|
||||
def projectScriptSelf_Rename():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'o_file', 'n_file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
o_file = args['o_file']
|
||||
n_file = args['n_file']
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
self_path = custom_hooks + '/self'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
o_file_abs = self_path + '/' + o_file + '.sh'
|
||||
if not os.path.exists(o_file_abs):
|
||||
return mw.returnJson(False, '原文件已经不存在了!')
|
||||
|
||||
n_file_abs = self_path + '/' + n_file + '.sh'
|
||||
|
||||
os.rename(o_file_abs, n_file_abs)
|
||||
|
||||
# 日志也删除
|
||||
log_file = custom_hooks + '/self_logs/' + o_file + '.sh.log'
|
||||
if os.path.exists(log_file):
|
||||
os.remove(log_file)
|
||||
|
||||
return mw.returnJson(True, '重命名成功!')
|
||||
|
||||
|
||||
def projectScriptSelf_Enable():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'enable'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
enable = args['enable']
|
||||
|
||||
custom_path = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
|
||||
# 替换commit配置
|
||||
commit_path = custom_path + '/commit'
|
||||
note = '#Gogs Script Don`t Remove and Change'
|
||||
|
||||
self_file = custom_path + '/self_hook.sh'
|
||||
self_hook_tpl = getPluginDir() + '/hook/self_hook.tpl'
|
||||
|
||||
if enable == '1':
|
||||
content = mw.readFile(self_hook_tpl)
|
||||
content = content.replace('{$HOOK_DIR}', custom_path + '/self')
|
||||
content = content.replace(
|
||||
'{$HOOK_LOGS_DIR}', custom_path + '/self_logs')
|
||||
mw.writeFile(self_file, content)
|
||||
mw.execShell("chmod 777 " + self_file)
|
||||
|
||||
commit_content = mw.readFile(commit_path)
|
||||
commit_content += "\n\n" + "bash " + self_file + " " + note
|
||||
mw.writeFile(commit_path, commit_content)
|
||||
|
||||
return mw.returnJson(True, '开启成功!')
|
||||
else:
|
||||
commit_content = mw.readFile(commit_path)
|
||||
rep = ".*" + note
|
||||
commit_content = re.sub(rep, '', commit_content, re.M)
|
||||
commit_content = commit_content.strip()
|
||||
mw.writeFile(commit_path, commit_content)
|
||||
if os.path.exists(self_file):
|
||||
os.remove(self_file)
|
||||
return mw.returnJson(True, '关闭成功!')
|
||||
|
||||
|
||||
def projectScriptSelf_Status():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['user', 'name', 'file', 'status'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
user = args['user']
|
||||
name = args['name'] + '.git'
|
||||
file = args['file']
|
||||
status = args['status']
|
||||
|
||||
custom_hooks = getRootPath() + '/' + user + '/' + \
|
||||
name + '/custom_hooks'
|
||||
self_path = custom_hooks + '/self'
|
||||
|
||||
if not os.path.exists(self_path):
|
||||
os.mkdir(self_path)
|
||||
|
||||
# 日志也删除
|
||||
log_file = custom_hooks + '/self_logs/' + file + '.log'
|
||||
if os.path.exists(log_file):
|
||||
os.remove(log_file)
|
||||
|
||||
if status == '1':
|
||||
file_abs = self_path + '/' + file
|
||||
file_text_abs = self_path + '/' + file + '.txt'
|
||||
os.rename(file_abs, file_text_abs)
|
||||
return mw.returnJson(True, '开始禁用成功!')
|
||||
else:
|
||||
file_abs = self_path + '/' + file.strip('.txt')
|
||||
file_text_abs = self_path + '/' + file
|
||||
os.rename(file_text_abs, file_abs)
|
||||
return mw.returnJson(True, '开始使用成功!')
|
||||
|
||||
return mw.returnJson(True, '禁用成功!')
|
||||
|
||||
|
||||
def getRsaPublic():
|
||||
@@ -732,8 +1094,12 @@ if __name__ == "__main__":
|
||||
print(getGogsConf())
|
||||
elif func == 'submit_gogs_conf':
|
||||
print(submitGogsConf())
|
||||
elif func == 'gogs_edit_tpl':
|
||||
print(gogsEditTpl())
|
||||
elif func == 'user_list':
|
||||
print(userList())
|
||||
elif func == 'repo_list':
|
||||
print(repoList())
|
||||
elif func == 'user_project_list':
|
||||
print(userProjectList())
|
||||
elif func == 'project_script_edit':
|
||||
@@ -744,8 +1110,24 @@ if __name__ == "__main__":
|
||||
print(projectScriptUnload())
|
||||
elif func == 'project_script_debug':
|
||||
print(projectScriptDebug())
|
||||
elif func == 'gogs_edit':
|
||||
print(gogsEdit())
|
||||
elif func == 'project_script_run':
|
||||
print(projectScriptRun())
|
||||
elif func == 'project_script_self':
|
||||
print(projectScriptSelf())
|
||||
elif func == 'project_script_self_create':
|
||||
print(projectScriptSelf_Create())
|
||||
elif func == 'project_script_self_del':
|
||||
print(projectScriptSelf_Del())
|
||||
elif func == 'project_script_self_logs':
|
||||
print(projectScriptSelf_Logs())
|
||||
elif func == 'project_script_self_run':
|
||||
print(projectScriptSelf_Run())
|
||||
elif func == 'project_script_self_rename':
|
||||
print(projectScriptSelf_Rename())
|
||||
elif func == 'project_script_self_enable':
|
||||
print(projectScriptSelf_Enable())
|
||||
elif func == 'project_script_self_status':
|
||||
print(projectScriptSelf_Status())
|
||||
elif func == 'get_rsa_public':
|
||||
print(getRsaPublic())
|
||||
elif func == 'get_total_statistics':
|
||||
|
||||
+482
-45
@@ -1,19 +1,8 @@
|
||||
|
||||
function str2Obj(str){
|
||||
var data = {};
|
||||
kv = str.split('&');
|
||||
for(i in kv){
|
||||
v = kv[i].split('=');
|
||||
data[v[0]] = v[1];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function gogsPost(method,args,callback, title){
|
||||
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(str2Obj(args));
|
||||
_args = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
@@ -113,9 +102,8 @@ function submitGogsConf() {
|
||||
});
|
||||
}
|
||||
|
||||
function gogsEdit(){
|
||||
|
||||
gogsPost('gogs_edit',{} , function(data){
|
||||
function gogsEditTpl(){
|
||||
gogsPost('gogs_edit_tpl',{} , function(data){
|
||||
// console.log(data);
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var edit = '<p class="status">通用的手动编辑:</p>';
|
||||
@@ -149,7 +137,7 @@ function gogsUserList(page, search) {
|
||||
return;
|
||||
}
|
||||
content = '<div class="finduser"><input class="bt-input-text mr5 outline_no" type="text" placeholder="查找用户名" id="find_user" style="height: 28px; border-radius: 3px;width: 435px;">';
|
||||
content += '<button class="btn btn-success btn-sm" onclick="userFind();">查找</button></div>';
|
||||
content += '<button class="btn btn-success btn-sm find_user" >查找</button></div>';
|
||||
|
||||
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
|
||||
content += '<thead><tr>';
|
||||
@@ -163,28 +151,84 @@ function gogsUserList(page, search) {
|
||||
|
||||
ulist = rdata['data']['data'];
|
||||
for (i in ulist){
|
||||
email = ulist[i]["email"] == '' ? '无' : ulist[i]["email"];
|
||||
|
||||
var email = ulist[i]["email"] == '' ? '无' : ulist[i]["email"];
|
||||
var user_url = rdata['data']['root_url'] + ulist[i]["name"];
|
||||
content += '<tr><td>'+ulist[i]["id"]+'</td>'+
|
||||
'<td>'+ulist[i]["name"]+'</td>'+
|
||||
'<td>'+email+'</td>'+
|
||||
'<td><a class="btlink" onclick="userProjectList(\''+ulist[i]["name"]+'\')">项目管理</a></td>'+
|
||||
'<td><a class="btlink" target="_blank" href="'+user_url+'">项目管理</a></td>'+
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
content += '</tbody>';
|
||||
content += '</table></div>';
|
||||
|
||||
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
|
||||
page += rdata['data']['list'];
|
||||
page += '</div></ul></div>';
|
||||
var page_html = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
|
||||
page_html += rdata['data']['list'];
|
||||
page_html += '</div></ul></div>';
|
||||
|
||||
content += page;
|
||||
content += page_html;
|
||||
|
||||
$(".soft-man-con").html(content);
|
||||
|
||||
$('.find_user').click(function(){
|
||||
var name = $('#find_user').val();
|
||||
gogsUserList(page, name);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function userProjectList(user, search){
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '用户('+user+')项目列表',
|
||||
area: '500px',
|
||||
content:"<div class='bt-form pd20 c6'>\
|
||||
<div>\
|
||||
<div id='gogs_table' class='divtable' style='margin-top:5px;'>\
|
||||
<table class='table table-hover'>\
|
||||
<thead><tr><th>项目</th><th>操作</th></tr></thead>\
|
||||
<tbody></tbody>\
|
||||
</table>\
|
||||
<div class='dataTables_paginate paging_bootstrap pagination' style='margin-top:0px;'>\
|
||||
<ul class='page'><div class='gogs_page'></div></ul>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>",
|
||||
success:function(){
|
||||
userProjectListPage(user,search);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function userProjectList2(user, search){
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '用户('+user+')项目列表',
|
||||
area: '500px',
|
||||
content:"<div class='bt-form pd20 c6'>\
|
||||
<div>\
|
||||
<div id='gogs_table' class='divtable' style='margin-top:5px;'>\
|
||||
<table class='table table-hover'>\
|
||||
<thead><tr><th>项目</th><th>操作</th></tr></thead>\
|
||||
<tbody></tbody>\
|
||||
</table>\
|
||||
<div class='dataTables_paginate paging_bootstrap pagination' style='margin-top:0px;'>\
|
||||
<ul class='page'><div class='gogs_page'></div></ul>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>",
|
||||
success:function(){
|
||||
userProjectListPage(user,search);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function userProjectListPage(user, search){
|
||||
var req = {};
|
||||
if (!isNaN(user)){
|
||||
req['page'] = user;
|
||||
@@ -200,8 +244,7 @@ function userProjectList(user, search){
|
||||
if(typeof(search) != 'undefined'){
|
||||
req['search'] = search;
|
||||
}
|
||||
|
||||
$('.layui-layer-close1').click();
|
||||
|
||||
gogsPost('user_project_list', req, function(data){
|
||||
var rdata = [];
|
||||
try {
|
||||
@@ -218,7 +261,8 @@ function userProjectList(user, search){
|
||||
var project_list = rdata['data']['data'];
|
||||
for (i in project_list) {
|
||||
var name = project_list[i]['name'];
|
||||
list += '<tr><td>'+name+'</td>\
|
||||
list += '<tr>\
|
||||
<td>'+name+'</td>\
|
||||
<td>\
|
||||
<a class="btlink" target="_blank" href="'+rdata['data']['root_url']+user+'/'+name+'">源码</a> | \
|
||||
<a class="btlink" onclick="projectScript(\''+user+'\',\''+name+'\','+project_list[i]['has_hook']+');">脚本</a>\
|
||||
@@ -226,28 +270,180 @@ function userProjectList(user, search){
|
||||
</tr>';
|
||||
}
|
||||
|
||||
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
|
||||
page += rdata['data']['list'];
|
||||
page += '</div></ul></div>';
|
||||
$('#gogs_table tbody').html(list);
|
||||
|
||||
var loadOpen = layer.open({
|
||||
type: 1,
|
||||
title: '用户('+user+')项目列表',
|
||||
area: '500px',
|
||||
content:"<div class='bt-form pd20 c6'>\
|
||||
<div>\
|
||||
<div class='divtable' style='margin-top:5px;'>\
|
||||
<table class='table table-hover'>\
|
||||
<thead><tr><th>项目</th><th>操作</th></tr></thead>\
|
||||
<tbody>" + list + "</tbody>\
|
||||
</table>" +
|
||||
page +
|
||||
"</div></div></div>"
|
||||
});
|
||||
var page = rdata['data']['list'];
|
||||
$('#gogs_table .gogs_page').html(page);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function gogsRepoListPage(page, search){
|
||||
var _data = {};
|
||||
if (typeof(page) =='undefined'){
|
||||
var page = 1;
|
||||
}
|
||||
|
||||
_data['page'] = page;
|
||||
_data['page_size'] = 10;
|
||||
if(typeof(search) != 'undefined'){
|
||||
_data['search'] = search;
|
||||
}
|
||||
|
||||
gogsPost('repo_list', _data, function(data){
|
||||
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (!rdata.status){
|
||||
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
var ulist = rdata['data']['data'];
|
||||
var body = ''
|
||||
for (i in ulist){
|
||||
// console.log(ulist[i]);
|
||||
|
||||
var option = '';
|
||||
if(ulist[i]['has_hook']){
|
||||
option += '<a class="btlink unload" data-index="'+i+'">卸载脚本</a>' + ' | ';
|
||||
option += '<a class="btlink load" data-index="'+i+'">重载</a>' + ' | ';
|
||||
option += '<a class="btlink edit" data-index="'+i+'">编辑</a>' + ' | ';
|
||||
option += '<a class="btlink debug" data-index="'+i+'">日志</a>' + ' | ';
|
||||
option += '<a class="btlink run" data-index="'+i+'">手动</a>' + ' | ';
|
||||
option += '<a class="btlink scripts" data-index="'+i+'" onclick="projectScriptSelf(\''+ulist[i]["name"]+'\',\''+ulist[i]["repo"]+'\')" >自定义</a>';
|
||||
} else{
|
||||
option += '<a data-index="'+i+'" class="btlink load">加载脚本</a>';
|
||||
}
|
||||
|
||||
|
||||
body += '<tr><td>'+ulist[i]["id"]+'</td>'+
|
||||
'<td class="overflow_hide" style="width:70px;">' + ulist[i]["name"]+'</td>'+
|
||||
'<td class="overflow_hide" style="width:70px;display: inline-block;">' + ulist[i]["repo"]+'</td>'+
|
||||
'<td>' +
|
||||
'<a class="btlink" target="_blank" href="'+rdata['data']['root_url']+ulist[i]["name"]+'/'+ulist[i]["repo"]+'">源码</a>' + ' | ' +
|
||||
option +
|
||||
'</td>' +
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
$('#repo_list tbody').html(body);
|
||||
$('#repo_list_page').html(rdata['data']['list']);
|
||||
|
||||
$('.find_repo').click(function(){
|
||||
var find_repo = $('#find_repo').val();
|
||||
gogsRepoListPage(page, find_repo);
|
||||
});
|
||||
|
||||
|
||||
$('#repo_list .load').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_load', {'user':user,'name':name}, function(data){
|
||||
if (data.data != 'ok'){
|
||||
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
layer.msg('加载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
setTimeout(function(){
|
||||
gogsRepoListPage(page, search);
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
$('#repo_list .unload').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_unload', {'user':user,'name':name}, function(data){
|
||||
if (data.data != 'ok'){
|
||||
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.msg('卸载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
setTimeout(function(){
|
||||
gogsRepoListPage(page, search);
|
||||
}, 2000);
|
||||
});
|
||||
});
|
||||
|
||||
$('#repo_list .edit').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_edit', {'user':user,'name':name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (rdata['status']){
|
||||
onlineEditFile(0, rdata['data']['path']);
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#repo_list .debug').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_debug', {'user':user,'name':name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if (rdata['status']){
|
||||
onlineEditFile(0, rdata['path']);
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#repo_list .run').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var user = ulist[i]["name"];
|
||||
var name = ulist[i]["repo"];
|
||||
|
||||
gogsPost('project_script_run', {'user':user,'name':name}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
layer.msg(data.msg,{icon:data.status?1:2,time:2000,shade: [0.3, '#000']});
|
||||
});
|
||||
});
|
||||
|
||||
//---------
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function gogsRepoList() {
|
||||
content = '<div class="finduser"><input class="bt-input-text mr5 outline_no" type="text" placeholder="查找项目" id="find_repo" style="height: 28px; border-radius: 3px;width: 435px;">';
|
||||
content += '<button class="btn btn-success btn-sm find_repo" >查找</button></div>';
|
||||
|
||||
content += '<div id="repo_list" class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
|
||||
content += '<thead><tr>';
|
||||
content += '<th style="width:50px;">序号</th>';
|
||||
content += '<th style="width:80px;">用户/组织</th>';
|
||||
content += '<th style="width:80px;">项目名</th>';
|
||||
content += '<th>操作</th>';
|
||||
content += '</tr></thead>';
|
||||
|
||||
content += '<tbody></tbody>';
|
||||
content += '</table></div>';
|
||||
|
||||
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="repo_list_page" class="page"></ul></div>';
|
||||
|
||||
content += page;
|
||||
|
||||
$(".soft-man-con").html(content);
|
||||
|
||||
gogsRepoListPage(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function projectScript(user, name,has_hook){
|
||||
// console.log(user,name,has_hook);
|
||||
var html = '';
|
||||
@@ -288,7 +484,7 @@ function projectScriptLoad(user,name){
|
||||
|
||||
layer.msg('加载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
setTimeout(function(){
|
||||
userProjectList(1);
|
||||
gogsRepoListPage(1);
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
@@ -302,11 +498,18 @@ function projectScriptUnload(user,name){
|
||||
|
||||
layer.msg('卸载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
|
||||
setTimeout(function(){
|
||||
userProjectList(1);
|
||||
gogsRepoListPage(1);
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
function projectScriptRun(user, name){
|
||||
gogsPost('project_script_run', {'user':user,'name':name}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
layer.msg(data.msg,{icon:data.code?2:1,time:2000,shade: [0.3, '#000']});
|
||||
});
|
||||
}
|
||||
|
||||
function projectScriptDebug(user,name){
|
||||
gogsPost('project_script_debug', {'user':user,'name':name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
@@ -318,6 +521,240 @@ function projectScriptDebug(user,name){
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function projectScriptSelfRender(user, name){
|
||||
gogsPost('project_script_self', {'user':user,'name':name}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
|
||||
var data = rdata['data']['data'];
|
||||
|
||||
if (rdata['data']['self_hook']){
|
||||
$('#open_script').prop('checked',true);
|
||||
}
|
||||
|
||||
var body = '';
|
||||
if(data.length == 0 ){
|
||||
body += '<tr><td colspan="3" style="text-align:center;">无脚本数据</td></tr>';
|
||||
} else{
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var b_status = '<a class="btlink status" data-index="'+i+'" target="_blank">已使用</a>';
|
||||
if (data[i]["is_hidden"]){
|
||||
b_status = '<a class="btlink status" data-index="'+i+'" target="_blank">已隐藏</a>';
|
||||
}
|
||||
|
||||
body += '<tr>'+
|
||||
'<td>' + data[i]["name"]+'</td>'+
|
||||
'<td>' + b_status + '</td>'+
|
||||
'<td>' +
|
||||
'<a class="btlink del" data-index="'+i+'" target="_blank">删除</a>' + ' | ' +
|
||||
'<a class="btlink edit" data-index="'+i+'" target="_blank">编辑</a>' + ' | ' +
|
||||
'<a class="btlink logs" data-index="'+i+'" target="_blank">日志</a>' + ' | ' +
|
||||
'<a class="btlink run" data-index="'+i+'" target="_blank">手动</a>' + ' | ' +
|
||||
'<a class="btlink rename" data-index="'+i+'" target="_blank">重命名</a>' +
|
||||
'</td></tr>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$('#gogs_self_table tbody').html(body);
|
||||
$('#gogs_self_table .page').html(rdata['data']['list']);
|
||||
|
||||
$('#gogs_self_table .status').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
var status = '1';
|
||||
if (data[i]["is_hidden"]){
|
||||
status = '0';
|
||||
}
|
||||
gogsPost('project_script_self_status', {'user':user,'name':name,'file':file, status:status}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
showMsg(data.msg ,function(){
|
||||
projectScriptSelfRender(user, name);
|
||||
},{icon:data.code?2:1,time:2000,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
});
|
||||
|
||||
$('#gogs_self_table .del').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
gogsPost('project_script_self_del', {'user':user,'name':name,'file':file}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
showMsg(data.msg ,function(){
|
||||
projectScriptSelfRender(user, name);
|
||||
},{icon:data.code?2:1,time:2000,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
});
|
||||
|
||||
$('#gogs_self_table .edit').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var path = data[i]["path"];
|
||||
onlineEditFile(0,path);
|
||||
});
|
||||
|
||||
$('#gogs_self_table .logs').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
gogsPost('project_script_self_logs', {'user':user,'name':name,'file':file}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
// console.log(rdata);
|
||||
if (rdata['status']){
|
||||
onlineEditFile(0, rdata['data']['path']);
|
||||
} else {
|
||||
layer.msg(rdata.msg,{icon:data.status?2:1,time:2000,shade: [0.3, '#000']});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#gogs_self_table .run').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
if (data[i]["is_hidden"]){
|
||||
layer.msg("已经禁用,不能执行!",{icon:2,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
gogsPost('project_script_self_run', {'user':user,'name':name,'file':file}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
layer.msg(rdata.msg,{icon:data.status?1:2,time:2000,shade: [0.3, '#000']});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#gogs_self_table .rename').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = data[i]["name"];
|
||||
|
||||
if (data[i]["is_hidden"]){
|
||||
layer.msg("已经禁用,不能执行!",{icon:2,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
file = file.split('.sh')[0];
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
shift: 5,
|
||||
closeBtn: 1,
|
||||
area: '320px',
|
||||
title: '重命名',
|
||||
btn:['设置','关闭'],
|
||||
content: '<div class="bt-form pd20">\
|
||||
<div class="line">\
|
||||
<input type="text" class="bt-input-text" name="Name" id="newFileName" value="'+file+'" placeholder="文件名" style="width:100%" />\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
$("#newFileName").focus().keyup(function(e){
|
||||
if(e.keyCode == 13) $(".layui-layer-btn0").click();
|
||||
});
|
||||
},
|
||||
yes:function(){
|
||||
var n_file = $("#newFileName").val();
|
||||
var o_file = file;
|
||||
|
||||
gogsPost('project_script_self_rename', {'user':user,'name':name,'o_file':o_file,'n_file':n_file}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
showMsg(data.msg ,function(){
|
||||
$(".layui-layer-btn1").click();
|
||||
projectScriptSelfRender(user, name);
|
||||
},{icon:data.code?2:1,time:2000,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
//-----
|
||||
});
|
||||
//------
|
||||
});
|
||||
}
|
||||
|
||||
//新建文件
|
||||
function createScriptFile(type, user, name, file) {
|
||||
if (type == 1) {
|
||||
gogsPost('project_script_self_create', {'user':user,'name':name,'file': file }, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if(!rdata['status']){
|
||||
layer.msg(rdata.msg,{icon:2,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
showMsg(rdata.msg, function(){
|
||||
$(".layui-layer-btn1").click();
|
||||
onlineEditFile(0,rdata['data']['abs_file']);
|
||||
projectScriptSelfRender(user, name);
|
||||
}, {icon:1,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
return;
|
||||
}
|
||||
layer.open({
|
||||
type: 1,
|
||||
shift: 5,
|
||||
closeBtn: 1,
|
||||
area: '320px',
|
||||
title: '新建自定义脚本',
|
||||
btn:['新建','关闭'],
|
||||
content: '<div class="bt-form pd20">\
|
||||
<div class="line">\
|
||||
<input type="text" class="bt-input-text" name="Name" id="newFileName" value="" placeholder="文件名" style="width:100%" />\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function(){
|
||||
$("#newFileName").focus().keyup(function(e){
|
||||
if(e.keyCode == 13) $(".layui-layer-btn0").click();
|
||||
});
|
||||
},
|
||||
yes:function(){
|
||||
var file = $("#newFileName").val();;
|
||||
createScriptFile(1, user, name, file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function projectScriptSelf(user, name){
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '项目('+user+'/'+name+')自定义脚本',
|
||||
area: '500px',
|
||||
content:"<div class='bt-form pd15'>\
|
||||
<button id='create_script' class='btn btn-success btn-sm' type='button' style='margin-right: 5px;''>添加脚本</button>\
|
||||
<div style='float:right;'>\
|
||||
<span style='line-height: 23px;'>开启自定义脚本</span>\
|
||||
<input class='btswitch btswitch-ios' id='open_script' type='checkbox'>\
|
||||
<label id='script_hook_enable' class='btswitch-btn' for='open_script' style='display: inline-flex;line-height:38px;margin-left: 4px;float: right;'></label>\
|
||||
</div>\
|
||||
<div id='gogs_self_table' class='divtable' style='margin-top:5px;'>\
|
||||
<table class='table table-hover'>\
|
||||
<thead><tr><th style='width:100px;'>脚本文件名</th><th>状态</th><th>操作</th></tr></thead>\
|
||||
<tbody></tbody>\
|
||||
</table>\
|
||||
<div class='dataTables_paginate paging_bootstrap pagination' style='margin-top:0px;'>\
|
||||
<ul class='page'><div class='gogs_page'></div></ul>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>",
|
||||
success:function(){
|
||||
projectScriptSelfRender(user, name);
|
||||
|
||||
$('#create_script').click(function(){
|
||||
createScriptFile(0, user, name);
|
||||
});
|
||||
|
||||
$('#script_hook_enable').click(function(){
|
||||
var enable = $('#open_script').prop('checked');
|
||||
var enable_option = '0';
|
||||
if (!enable){
|
||||
enable_option = '1';
|
||||
}
|
||||
gogsPost('project_script_self_enable', {'user':user,'name':name,'enable':enable_option}, function(data){
|
||||
var data = $.parseJSON(data.data);
|
||||
showMsg(data.msg ,function(){
|
||||
projectScriptSelfRender(user, name);
|
||||
},{icon:data.status?1:2,shade: [0.3, '#000']},2000);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getRsaPublic(){
|
||||
gogsPost('get_rsa_public', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
@@ -344,7 +781,7 @@ function gogsRead(){
|
||||
var readme = '<ul class="help-info-text c7">';
|
||||
readme += '<li>默认使用MySQL,第一个启动加载各种配置,并修改成正确的数据库配置</li>';
|
||||
readme += '<li>邮件端口使用456,gogs仅支持使用STARTTLS的SMTP协议</li>';
|
||||
readme += '<li>如果使用项目中脚本本地同步,<a target="_blank" href="https://github.com/midoks/mdserver-web/wiki/%E6%8F%92%E4%BB%B6%E7%AE%A1%E7%90%86%5Bgogs%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%5D#%E5%90%AF%E5%8A%A8gogs%E5%90%8E%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BD%BF%E7%94%A8hook%E8%84%9A%E6%9C%AC%E5%90%8C%E6%AD%A5%E4%BB%A3%E7%A0%81%E9%9C%80%E8%A6%81%E5%BC%80%E5%90%AFssh%E7%AB%AF%E5%8F%A3">点击查看</></li>';
|
||||
readme += '<li>项目【加载脚本】后,会自动同步到wwwroot目录下</li>';
|
||||
readme += '<li><a href="#" onclick="getRsaPublic();">点击查看本机公钥</></li>';
|
||||
readme += '</ul>';
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
global
|
||||
daemon
|
||||
#一般情况下,可关闭
|
||||
log 127.0.0.1 local0
|
||||
pidfile /tmp/haproxy.pid
|
||||
maxconn 4000
|
||||
user haproxy
|
||||
group haproxy
|
||||
|
||||
|
||||
defaults
|
||||
mode http
|
||||
log global
|
||||
@@ -20,6 +20,7 @@ listen stats
|
||||
mode http
|
||||
bind *:10800
|
||||
stats enable
|
||||
stats refresh 10
|
||||
stats uri /haproxy
|
||||
stats realm Haproxy\ Statistics
|
||||
stats auth admin:admin
|
||||
@@ -28,10 +29,11 @@ frontend http-in
|
||||
bind *:1080
|
||||
default_backend servers
|
||||
option forwardfor
|
||||
option httpclose
|
||||
#option httpclose
|
||||
option http-keep-alive
|
||||
|
||||
backend servers
|
||||
balance roundrobin
|
||||
server web1 0.0.0.0:9090 check
|
||||
server web1 0.0.0.0:9090 check inter 2000 rise 2 fall 5
|
||||
|
||||
|
||||
|
||||
+11
-15
@@ -97,6 +97,8 @@ def contentReplace(content):
|
||||
service_path = mw.getServerDir()
|
||||
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = content.replace('{$HA_USER}', mw.getRandomString(8))
|
||||
content = content.replace('{$HA_PWD}', mw.getRandomString(10))
|
||||
content = content.replace('{$SERVER_APP}', service_path + '/haproxy')
|
||||
return content
|
||||
|
||||
@@ -150,6 +152,13 @@ def initDreplace():
|
||||
def haOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
# check config
|
||||
sdir = getServerDir()
|
||||
cmd_check = sdir+'/sbin/haproxy -c -f ' + sdir + '/haproxy.conf'
|
||||
chk_data = mw.execShell(cmd_check)
|
||||
if chk_data[1]!= '':
|
||||
return chk_data[1]
|
||||
|
||||
if not mw.isAppleSystem():
|
||||
data = mw.execShell('systemctl ' + method + ' haproxy')
|
||||
if data[1] == '':
|
||||
@@ -206,19 +215,8 @@ def initdUinstall():
|
||||
|
||||
|
||||
def runLog():
|
||||
path = getConf()
|
||||
content = mw.readFile(path)
|
||||
rep = 'log\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
def getPort():
|
||||
path = getConf()
|
||||
content = mw.readFile(path)
|
||||
rep = 'listen\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0]
|
||||
path = getServerDir() + "/haproxy.log"
|
||||
return path
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -247,7 +245,5 @@ if __name__ == "__main__":
|
||||
print(readConfigTpl())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'query_log':
|
||||
print(queryLog())
|
||||
else:
|
||||
print('error')
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
# for mac
|
||||
export PATH=$PATH:/opt/homebrew/bin
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
@@ -23,12 +25,12 @@ else
|
||||
fi
|
||||
|
||||
if [ "${2}" == "" ];then
|
||||
echo '缺少安装脚本...' > $install_tmp
|
||||
echo '缺少安装脚本...'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -d $curPath/versions/$2 ];then
|
||||
echo '缺少安装脚本2...' > $install_tmp
|
||||
echo '缺少安装脚本2...'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ function spPostMin(method, args, callback){
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
layer.msg(data.msg,{icon:0,time:10000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
global
|
||||
daemon
|
||||
pidfile /tmp/haproxy.pid
|
||||
maxconn 4000
|
||||
user haproxy
|
||||
group haproxy
|
||||
|
||||
|
||||
defaults
|
||||
mode http
|
||||
log global
|
||||
option httplog
|
||||
timeout connect 10s
|
||||
timeout client 15s
|
||||
timeout server 15s
|
||||
|
||||
|
||||
listen stats
|
||||
mode http
|
||||
bind *:10800
|
||||
stats enable
|
||||
stats refresh 10
|
||||
stats uri /haproxy
|
||||
stats realm Haproxy\ Statistics
|
||||
stats auth {$HA_USER}:{$HA_PWD}
|
||||
|
||||
frontend http-in
|
||||
bind *:1080
|
||||
default_backend servers
|
||||
option forwardfor
|
||||
option http-keep-alive
|
||||
|
||||
backend servers
|
||||
balance roundrobin
|
||||
server web1 0.0.0.0:9090 check inter 2000 rise 2 fall 5
|
||||
|
||||
|
||||
@@ -20,12 +20,26 @@ VERSION=2.6.4
|
||||
MIN_VERSION=2.6
|
||||
Install_App()
|
||||
{
|
||||
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
echo '正在安装Haproxy软件...'
|
||||
mkdir -p $serverPath/haproxy
|
||||
|
||||
APP_DIR=${serverPath}/source/haproxy
|
||||
mkdir -p $APP_DIR
|
||||
|
||||
|
||||
LOCAL_ADDR=common
|
||||
cn=$(curl -fsSL -m 10 -s http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
if [ ! -z "$cn" ] || [ "$?" == "0" ] ;then
|
||||
LOCAL_ADDR=cn
|
||||
fi
|
||||
|
||||
|
||||
if [ "${LOCAL_ADDR}" == "cn" ];then
|
||||
if [ ! -f ${APP_DIR}/haproxy-${VERSION}.tar.gz ];then
|
||||
wget -O ${APP_DIR}/haproxy-${VERSION}.tar.gz https://dl.midoks.icu/soft/haproxy/haproxy-${VERSION}.tar.gz
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -f ${APP_DIR}/haproxy-${VERSION}.tar.gz ];then
|
||||
if [ $sysName == 'Darwin' ]; then
|
||||
@@ -49,7 +63,28 @@ Install_App()
|
||||
fi
|
||||
|
||||
echo $MIN_VERSION > $serverPath/haproxy/version.pl
|
||||
echo 'Install_HA' > $install_tmp
|
||||
echo '安装Haproxy成功' > $install_tmp
|
||||
|
||||
#Haproxy日志配置
|
||||
if [ -f /etc/rsyslog.conf ];then
|
||||
find_ha=`cat /etc/rsyslog.conf | grep haproxy`
|
||||
if [ "$find_ha" != "" ];then
|
||||
echo $find_ha
|
||||
else
|
||||
echo "---------------------------------------------"
|
||||
echo "" > ${serverPath}/haproxy/haproxy.log
|
||||
echo "local0.* ${serverPath}/haproxy/haproxy.log" >> /etc/rsyslog.conf
|
||||
systemctl restart syslog
|
||||
echo "syslog默认的haproxy配置"
|
||||
echo "local0.* ${serverPath}/haproxy/haproxy.log >> /etc/rsyslog.conf"
|
||||
echo "---------------------------------------------"
|
||||
fi
|
||||
fi
|
||||
|
||||
#删除解压源码
|
||||
if [ -d ${APP_DIR}/haproxy-${VERSION} ];then
|
||||
rm -rf ${APP_DIR}/haproxy-${VERSION}
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
@@ -59,7 +94,7 @@ Uninstall_App()
|
||||
fi
|
||||
|
||||
rm -rf $serverPath/haproxy
|
||||
echo "Uninstall_HA" > $install_tmp
|
||||
echo "卸载Haproxy成功"
|
||||
}
|
||||
|
||||
action=$1
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
! Configuration File for keepalived
|
||||
|
||||
global_defs {
|
||||
router_id MYSQL_MHA
|
||||
}
|
||||
|
||||
vrrp_script chk_mysql_port {
|
||||
script "{$SERVER_PATH}/keepalived/scripts/chk.sh mysql"
|
||||
interval 2
|
||||
weight –5
|
||||
fall 2
|
||||
rise 1
|
||||
}
|
||||
|
||||
vrrp_instance VI_MYSQL {
|
||||
state MASTER
|
||||
interface {$ETH_XX}
|
||||
virtual_router_id 51
|
||||
priority 100
|
||||
advert_int 1
|
||||
authentication {
|
||||
auth_type PASS
|
||||
auth_pass 1111
|
||||
}
|
||||
virtual_ipaddress {
|
||||
192.168.10.10
|
||||
}
|
||||
|
||||
track_script {
|
||||
chk_mysql_port
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 562 B |
Executable
+22
@@ -0,0 +1,22 @@
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('keepalived');">服务</p>
|
||||
<p onclick="pluginInitD('keepalived');">自启动</p>
|
||||
<!-- <p onclick="pluginConfig('keepalived');">配置修改</p> -->
|
||||
<p onclick="pluginConfigTpl('keepalived',$('.plugin_version').attr('version'));">配置修改</p>
|
||||
<p onclick="pluginConfigListTpl('keepalived',$('.plugin_version').attr('version'),'config_scripts_tpl','read_config_tpl');">脚本模板</p>
|
||||
<p onclick="pluginLogs('keepalived','','run_log');">日志</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinHeight(530);
|
||||
$.getScript( "/plugins/file?name=keepalived&f=js/keepalived.js", function(){
|
||||
pluginService('keepalived', $('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
Executable
+353
@@ -0,0 +1,353 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'keepalived'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return '/tmp/' + getPluginName()
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
return '/etc/rc.d/' + getPluginName()
|
||||
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + "/etc/keepalived/keepalived.conf"
|
||||
return path
|
||||
|
||||
|
||||
def getConfTpl():
|
||||
path = getPluginDir() + "/config/keepalived.conf"
|
||||
return path
|
||||
|
||||
|
||||
def getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[3:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
return tmp
|
||||
|
||||
def checkArgs(data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
if not ck[i] in data:
|
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
def configTpl():
|
||||
path = getPluginDir() + '/tpl'
|
||||
pathFile = os.listdir(path)
|
||||
tmp = []
|
||||
for one in pathFile:
|
||||
file = path + '/' + one
|
||||
tmp.append(file)
|
||||
return mw.getJson(tmp)
|
||||
|
||||
|
||||
def readConfigTpl():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
content = mw.readFile(args['file'])
|
||||
content = contentReplace(content)
|
||||
return mw.returnJson(True, 'ok', content)
|
||||
|
||||
|
||||
def defaultScriptsTpl():
|
||||
path = getServerDir() + "/scripts/chk.sh"
|
||||
return path
|
||||
|
||||
def configScriptsTpl():
|
||||
path = getServerDir() + '/scripts'
|
||||
pathFile = os.listdir(path)
|
||||
tmp = []
|
||||
for one in pathFile:
|
||||
file = path + '/' + one
|
||||
tmp.append(file)
|
||||
return mw.getJson(tmp)
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps aux|grep keepalived |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
|
||||
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
|
||||
def contentReplace(content):
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
content = content.replace('{$PLUGIN_PATH}', getPluginDir())
|
||||
|
||||
# 网络接口
|
||||
ethx = mw.execShell("route -n | grep ^0.0.0.0 | awk '{print $8}'")
|
||||
if ethx[1]!='':
|
||||
# 未找到
|
||||
content = content.replace('{$ETH_XX}', 'eth1')
|
||||
else:
|
||||
# 已找到
|
||||
content = content.replace('{$ETH_XX}', ethx[0])
|
||||
|
||||
|
||||
return content
|
||||
|
||||
|
||||
def copyScripts():
|
||||
# 复制检查脚本
|
||||
src_scripts_path = getPluginDir() + '/scripts'
|
||||
dst_scripts_path = getServerDir() + '/scripts'
|
||||
if not os.path.exists(dst_scripts_path):
|
||||
mw.execShell('mkdir -p ' + dst_scripts_path)
|
||||
olist = os.listdir(src_scripts_path)
|
||||
for o in range(len(olist)):
|
||||
src_file = src_scripts_path+'/'+olist[o]
|
||||
dst_file = dst_scripts_path+'/'+olist[o]
|
||||
|
||||
content = mw.readFile(src_file)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(dst_file, content)
|
||||
|
||||
cmd = 'chmod +x ' + dst_file
|
||||
mw.execShell(cmd)
|
||||
return True
|
||||
return False
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitDTpl()
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
# initd replace
|
||||
if not os.path.exists(file_bin):
|
||||
content = mw.readFile(file_tpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(file_bin, content)
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
# log
|
||||
dataLog = getServerDir() + '/data'
|
||||
if not os.path.exists(dataLog):
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
# config replace
|
||||
dst_conf = getServerDir() + '/etc/keepalived/keepalived.conf'
|
||||
dst_conf_init = getServerDir() + '/init.pl'
|
||||
if not os.path.exists(dst_conf_init):
|
||||
content = mw.readFile(getConfTpl())
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(dst_conf, content)
|
||||
mw.writeFile(dst_conf_init, 'ok')
|
||||
|
||||
# 复制检查脚本
|
||||
copyScripts()
|
||||
|
||||
# systemd
|
||||
systemDir = mw.systemdCfgDir()
|
||||
systemService = systemDir + '/' + getPluginName() + '.service'
|
||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
||||
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
|
||||
service_path = mw.getServerDir()
|
||||
content = mw.readFile(systemServiceTpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(systemService, content)
|
||||
mw.execShell('systemctl daemon-reload')
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def kpOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
current_os = mw.getOs()
|
||||
if current_os == "darwin":
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
if current_os.startswith("freebsd"):
|
||||
data = mw.execShell('service ' + getPluginName() + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
|
||||
def start():
|
||||
return kpOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return kpOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = kpOp('restart')
|
||||
|
||||
log_file = runLog()
|
||||
mw.execShell("echo '' > " + log_file)
|
||||
return status
|
||||
|
||||
|
||||
def reload():
|
||||
return kpOp('reload')
|
||||
|
||||
|
||||
def getPort():
|
||||
conf = getServerDir() + '/keepalived.conf'
|
||||
content = mw.readFile(conf)
|
||||
|
||||
rep = "^(" + 'port' + ')\s*([.0-9A-Za-z_& ~]+)'
|
||||
tmp = re.search(rep, content, re.M)
|
||||
if tmp:
|
||||
return tmp.groups()[1]
|
||||
|
||||
return '6379'
|
||||
|
||||
|
||||
def initdStatus():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
if os.path.exists(initd_bin):
|
||||
return 'ok'
|
||||
|
||||
shell_cmd = 'systemctl status ' + \
|
||||
getPluginName() + ' | grep loaded | grep "enabled;"'
|
||||
data = mw.execShell(shell_cmd)
|
||||
if data[0] == '':
|
||||
return 'fail'
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
# freebsd initd install
|
||||
if current_os.startswith('freebsd'):
|
||||
import shutil
|
||||
source_bin = initDreplace()
|
||||
initd_bin = getInitDFile()
|
||||
shutil.copyfile(source_bin, initd_bin)
|
||||
mw.execShell('chmod +x ' + initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl enable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
os.remove(initd_bin)
|
||||
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
|
||||
return 'ok'
|
||||
|
||||
mw.execShell('systemctl disable ' + getPluginName())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def runLog():
|
||||
return getServerDir() + '/' + getPluginName() + '.log'
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
print(status())
|
||||
elif func == 'start':
|
||||
print(start())
|
||||
elif func == 'stop':
|
||||
print(stop())
|
||||
elif func == 'restart':
|
||||
print(restart())
|
||||
elif func == 'reload':
|
||||
print(reload())
|
||||
elif func == 'initd_status':
|
||||
print(initdStatus())
|
||||
elif func == 'initd_install':
|
||||
print(initdInstall())
|
||||
elif func == 'initd_uninstall':
|
||||
print(initdUinstall())
|
||||
elif func == 'run_info':
|
||||
print(runInfo())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'config_tpl':
|
||||
print(configTpl())
|
||||
elif func == 'default_scripts_tpl':
|
||||
print(defaultScriptsTpl())
|
||||
elif func == 'config_scripts_tpl':
|
||||
print(configScriptsTpl())
|
||||
elif func == 'read_config_tpl':
|
||||
print(readConfigTpl())
|
||||
else:
|
||||
print('error')
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "[<span style='color:red;'>内网</span>]优秀的高可用软件",
|
||||
"name": "keepalived",
|
||||
"title": "keepalived",
|
||||
"shell": "install.sh",
|
||||
"versions":["2.2.8"],
|
||||
"tip": "soft",
|
||||
"checks": "server/keepalived",
|
||||
"path": "server/keepalived",
|
||||
"display": 1,
|
||||
"author": "keepalived",
|
||||
"date": "2023-10-22",
|
||||
"home": "https://keepalived.org/download.html",
|
||||
"type": "soft",
|
||||
"pid": "4"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Redis In-Memory Data Store
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStart={$SERVER_PATH}/keepalived/sbin/keepalived -D
|
||||
ExecReload=/bin/kill -USR1 $MAINPID
|
||||
Restart=on-failure
|
||||
StandardOutput={$SERVER_PATH}/keepalived/keepalived.log
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Startup script for the Keepalived daemon
|
||||
#
|
||||
# processname: keepalived
|
||||
# pidfile: /var/run/keepalived.pid
|
||||
# config: /etc/keepalived/keepalived.conf
|
||||
# chkconfig: - 21 79
|
||||
# description: Start and stop Keepalived
|
||||
|
||||
# Source function library
|
||||
if [ -f /etc/rc.d/init.d/functions ];then
|
||||
. /etc/rc.d/init.d/functions
|
||||
fi
|
||||
|
||||
SYS_KP_FILE={$SERVER_PATH}/keepalived/etc/sysconfig/keepalived
|
||||
# Source configuration file (we set KEEPALIVED_OPTIONS there)
|
||||
if [ -f $SYS_KP_FILE ];then
|
||||
. $SYS_KP_FILE
|
||||
fi
|
||||
|
||||
RETVAL=0
|
||||
prog="keepalived"
|
||||
|
||||
start() {
|
||||
echo -n $"Starting $prog: "
|
||||
{$SERVER_PATH}/keepalived/sbin/keepalived ${KEEPALIVED_OPTIONS}
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
|
||||
}
|
||||
|
||||
stop() {
|
||||
echo -n $"Stopping $prog: "
|
||||
pkill keepalived
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
|
||||
}
|
||||
|
||||
reload() {
|
||||
echo -n $"Reloading $prog: "
|
||||
pkill keepalived -1
|
||||
RETVAL=$?
|
||||
echo
|
||||
}
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
reload)
|
||||
reload
|
||||
;;
|
||||
restart)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
condrestart)
|
||||
if [ -f /var/lock/subsys/$prog ]; then
|
||||
stop
|
||||
start
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
status keepalived
|
||||
RETVAL=$?
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|reload|restart|condrestart|status}"
|
||||
RETVAL=1
|
||||
esac
|
||||
|
||||
exit $RETVAL
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
|
||||
# for mac
|
||||
export PATH=$PATH:/opt/homebrew/bin
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/keepalived && bash install.sh install 2.2.8
|
||||
# cd /www/server/mdserver-web/plugins/keepalived && bash install.sh install 2.2.8
|
||||
|
||||
# /www/server/keepalived/init.d/keepalived start
|
||||
|
||||
# systemctl status keepalived
|
||||
# systemctl restart keepalived
|
||||
# ifconfig
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
|
||||
VERSION=$2
|
||||
|
||||
Install_App()
|
||||
{
|
||||
echo '正在安装keepalived脚本文件...'
|
||||
mkdir -p $serverPath/source/keepalived
|
||||
|
||||
if [ ! -f $serverPath/source/keepalived/keepalived-${VERSION}.tar.gz ];then
|
||||
wget -O $serverPath/source/keepalived/keepalived-${VERSION}.tar.gz https://keepalived.org/software/keepalived-${VERSION}.tar.gz
|
||||
fi
|
||||
|
||||
#检测文件是否损坏.
|
||||
md5_file_ok=8c26f75a8767e5341d82696e1e717115
|
||||
if [ -f $serverPath/source/keepalived/keepalived-${VERSION}.tar.gz ];then
|
||||
md5_file=`md5sum $serverPath/source/keepalived/keepalived-${VERSION}.tar.gz | awk '{print $1}'`
|
||||
if [ "${md5_file}" != "${md5_file_ok}" ]; then
|
||||
echo "keepalived-${version} 下载文件不完整,重新安装"
|
||||
rm -rf $serverPath/source/keepalived/keepalived-${VERSION}.tar.gz
|
||||
fi
|
||||
fi
|
||||
|
||||
echo $serverPath/keepalived/keepalived-${VERSION}
|
||||
if [ -d $serverPath/keepalived/keepalived-${VERSION} ];then
|
||||
cd $serverPath/keepalived/keepalived-${VERSION}
|
||||
else
|
||||
cd $serverPath/source/keepalived && tar -zxvf keepalived-${VERSION}.tar.gz
|
||||
cd $serverPath/keepalived/keepalived-${VERSION}
|
||||
fi
|
||||
|
||||
cd $serverPath/source/keepalived/keepalived-${VERSION}
|
||||
|
||||
./configure --prefix=$serverPath/keepalived && make && make install
|
||||
|
||||
# for test
|
||||
# mkdir -p $serverPath/keepalived
|
||||
if [ -d $serverPath/keepalived ];then
|
||||
echo "${VERSION}" > $serverPath/keepalived/version.pl
|
||||
echo 'keepalived安装完成'
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/keepalived/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/keepalived/index.py initd_install
|
||||
fi
|
||||
|
||||
if [ -d $serverPath/source/keepalived/keepalived-${VERSION} ];then
|
||||
rm -rf $serverPath/source/keepalived/keepalived-${VERSION}
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
if [ -f /usr/lib/systemd/system/keepalived.service ];then
|
||||
systemctl stop keepalived
|
||||
systemctl disable keepalived
|
||||
rm -rf /usr/lib/systemd/system/keepalived.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f /lib/systemd/system/keepalived.service ];then
|
||||
systemctl stop keepalived
|
||||
systemctl disable keepalived
|
||||
rm -rf /lib/systemd/system/keepalived.service
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ -f $serverPath/keepalived/initd/keepalived ];then
|
||||
$serverPath/keepalived/initd/keepalived stop
|
||||
fi
|
||||
|
||||
rm -rf $serverPath/keepalived
|
||||
echo "keepalived卸载完成"
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
Executable
+143
@@ -0,0 +1,143 @@
|
||||
function kpPost(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'keepalived';
|
||||
req_data['func'] = method;
|
||||
req_data['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
//错误展示10S
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function kpPostCallbak(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'keepalived';
|
||||
req_data['func'] = method;
|
||||
args['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/callback', req_data, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
//redis负载状态 start
|
||||
function redisStatus(version) {
|
||||
|
||||
redisPost('run_info',version, {},function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
// if (!rdata.status){
|
||||
// layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
// return;
|
||||
// }
|
||||
|
||||
hit = (parseInt(rdata.keyspace_hits) / (parseInt(rdata.keyspace_hits) + parseInt(rdata.keyspace_misses)) * 100).toFixed(2);
|
||||
var con = '<div class="divtable">\
|
||||
<table class="table table-hover table-bordered" style="width: 490px;">\
|
||||
<thead><th>字段</th><th>当前值</th><th>说明</th></thead>\
|
||||
<tbody>\
|
||||
<tr><th>uptime_in_days</th><td>' + rdata.uptime_in_days + '</td><td>已运行天数</td></tr>\
|
||||
<tr><th>tcp_port</th><td>' + rdata.tcp_port + '</td><td>当前监听端口</td></tr>\
|
||||
<tr><th>connected_clients</th><td>' + rdata.connected_clients + '</td><td>连接的客户端数量</td></tr>\
|
||||
<tr><th>used_memory_rss</th><td>' + toSize(rdata.used_memory_rss) + '</td><td>Redis当前占用的系统内存总量</td></tr>\
|
||||
<tr><th>used_memory</th><td>' + toSize(rdata.used_memory) + '</td><td>Redis当前已分配的内存总量</td></tr>\
|
||||
<tr><th>used_memory_peak</th><td>' + toSize(rdata.used_memory_peak) + '</td><td>Redis历史分配内存的峰值</td></tr>\
|
||||
<tr><th>mem_fragmentation_ratio</th><td>' + rdata.mem_fragmentation_ratio + '%</td><td>内存碎片比率</td></tr>\
|
||||
<tr><th>total_connections_received</th><td>' + rdata.total_connections_received + '</td><td>运行以来连接过的客户端的总数量</td></tr>\
|
||||
<tr><th>total_commands_processed</th><td>' + rdata.total_commands_processed + '</td><td>运行以来执行过的命令的总数量</td></tr>\
|
||||
<tr><th>instantaneous_ops_per_sec</th><td>' + rdata.instantaneous_ops_per_sec + '</td><td>服务器每秒钟执行的命令数量</td></tr>\
|
||||
<tr><th>keyspace_hits</th><td>' + rdata.keyspace_hits + '</td><td>查找数据库键成功的次数</td></tr>\
|
||||
<tr><th>keyspace_misses</th><td>' + rdata.keyspace_misses + '</td><td>查找数据库键失败的次数</td></tr>\
|
||||
<tr><th>hit</th><td>' + hit + '%</td><td>查找数据库键命中率</td></tr>\
|
||||
<tr><th>latest_fork_usec</th><td>' + rdata.latest_fork_usec + '</td><td>最近一次 fork() 操作耗费的微秒数</td></tr>\
|
||||
<tbody>\
|
||||
</table></div>';
|
||||
$(".soft-man-con").html(con);
|
||||
});
|
||||
}
|
||||
//redis负载状态 end
|
||||
|
||||
//配置修改
|
||||
function getRedisConfig(version) {
|
||||
redisPost('get_redis_conf', version,'',function(data){
|
||||
// console.log(data);
|
||||
var rdata = $.parseJSON(data.data);
|
||||
// console.log(rdata);
|
||||
var mlist = '';
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
var w = '70'
|
||||
if (rdata[i].name == 'error_reporting') w = '250';
|
||||
var ibody = '<input style="width: ' + w + 'px;" class="bt-input-text mr5" name="' + rdata[i].name + '" value="' + rdata[i].value + '" type="text" >';
|
||||
switch (rdata[i].type) {
|
||||
case 0:
|
||||
var selected_1 = (rdata[i].value == 1) ? 'selected' : '';
|
||||
var selected_0 = (rdata[i].value == 0) ? 'selected' : '';
|
||||
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;"><option value="1" ' + selected_1 + '>开启</option><option value="0" ' + selected_0 + '>关闭</option></select>'
|
||||
break;
|
||||
case 1:
|
||||
var selected_1 = (rdata[i].value == 'On') ? 'selected' : '';
|
||||
var selected_0 = (rdata[i].value == 'Off') ? 'selected' : '';
|
||||
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;"><option value="On" ' + selected_1 + '>开启</option><option value="Off" ' + selected_0 + '>关闭</option></select>'
|
||||
break;
|
||||
}
|
||||
mlist += '<p><span>' + rdata[i].name + '</span>' + ibody + ', <font>' + rdata[i].ps + '</font></p>'
|
||||
}
|
||||
var con = '<style>.conf_p p{margin-bottom: 2px}</style><div class="conf_p" style="margin-bottom:0">' + mlist + '\
|
||||
<div style="margin-top:10px; padding-right:15px" class="text-right"><button class="btn btn-success btn-sm mr5" onclick="getRedisConfig(\'' + version + '\')">刷新</button>\
|
||||
<button class="btn btn-success btn-sm" onclick="submitConf(\'' + version + '\')">保存</button></div>\
|
||||
</div>'
|
||||
$(".soft-man-con").html(con);
|
||||
});
|
||||
}
|
||||
|
||||
//提交配置
|
||||
function submitConf(version) {
|
||||
var data = {
|
||||
version: version,
|
||||
bind: $("input[name='bind']").val(),
|
||||
'port': $("input[name='port']").val(),
|
||||
'timeout': $("input[name='timeout']").val(),
|
||||
maxclients: $("input[name='maxclients']").val(),
|
||||
databases: $("input[name='databases']").val(),
|
||||
requirepass: $("input[name='requirepass']").val(),
|
||||
maxmemory: $("input[name='maxmemory']").val(),
|
||||
};
|
||||
|
||||
redisPost('submit_redis_conf', version, data, function(ret_data){
|
||||
var rdata = $.parseJSON(ret_data.data);
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 计划任务,恢复后,可自动拉起keepalived
|
||||
# bash {$SERVER_PATH}/keepalived/scripts/chk.sh mysql
|
||||
|
||||
cd {$SERVER_PATH}/keepalived
|
||||
|
||||
# check script bash
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
|
||||
SOFT=$1
|
||||
|
||||
if [ "$SOFT" == "mysql" ];then
|
||||
bash ${rootPath}/keepalived/scripts/chk_mysql.sh > ${rootPath}/keepalived/keepalived.log
|
||||
else
|
||||
echo "you should use [chk.sh mysql] exp ."
|
||||
fi
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 计划任务,恢复后,可自动拉起keepalived
|
||||
# bash {$SERVER_PATH}/keepalived/scripts/chk_mysql.sh
|
||||
|
||||
counter=$(netstat -na|grep "LISTEN"|grep "3306"|wc -l)
|
||||
data_time=`date +'%Y-%m-%d %H:%M:%S'`
|
||||
|
||||
if [ "${counter}" -eq "0" ]; then
|
||||
echo "${data_time}: start check mysql status, mysql is down, stop keepalive ..."
|
||||
systemctl stop keepalived
|
||||
echo "${data_time}: start check mysql end !!!"
|
||||
fi
|
||||
|
||||
|
||||
# 恢复后,自动拉起
|
||||
# systemctl start keepalived
|
||||
if [ "${counter}" -gt "0" ]; then
|
||||
echo "${data_time}: start check mysql status, mysql is up, start keepalive"
|
||||
|
||||
keepalived_status=`which systemctl && systemctl status keepalived | grep Active | grep inactive`
|
||||
if [ "$keepalived_status" != "" ];then
|
||||
systemctl start keepalived
|
||||
fi
|
||||
|
||||
echo "${data_time}: start check mysql end !!!"
|
||||
fi
|
||||
@@ -0,0 +1,46 @@
|
||||
# keepalived for lvs-nat
|
||||
# 未测试通过
|
||||
|
||||
global_defs {
|
||||
router_id HA_LVS
|
||||
}
|
||||
|
||||
vrrp_sync_group HA_LVS_NAT {
|
||||
group {
|
||||
HA_LVS_NAT
|
||||
}
|
||||
}
|
||||
|
||||
vrrp_instance HA_LVS_NAT {
|
||||
state MASTER
|
||||
interface bond1
|
||||
virtual_router_id 222
|
||||
priority 100
|
||||
advert_int 1
|
||||
nopreempt
|
||||
authentication {
|
||||
auth_type PASS
|
||||
auth_pass 1111
|
||||
}
|
||||
virtual_ipaddress {
|
||||
192.168.212.100/25 dev bond1
|
||||
}
|
||||
}
|
||||
|
||||
virtual_server 192.168.212.100 80 {
|
||||
delay_loop 6
|
||||
lb_algo rr
|
||||
lb_kind NAT
|
||||
protocol TCP
|
||||
|
||||
real_server 192.168.212.129 80 {
|
||||
weight 100
|
||||
TCP_CHECK {
|
||||
connect_timeout 3
|
||||
nb_get_retry 3
|
||||
delay_before_retry 3
|
||||
connect_port 15000
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
! Configuration File for keepalived
|
||||
|
||||
global_defs {
|
||||
router_id MYSQL_MHA
|
||||
}
|
||||
|
||||
vrrp_script chk_mysql_port {
|
||||
script "{$SERVER_PATH}/scripts/chk.sh mysql"
|
||||
interval 2
|
||||
weight –5
|
||||
fall 2
|
||||
rise 1
|
||||
}
|
||||
|
||||
vrrp_instance VI_MYSQL {
|
||||
state 这里所有节点定义为BACKUP
|
||||
interface {$ETH_XX}
|
||||
virtual_router_id 51
|
||||
priority 100
|
||||
advert_int 1
|
||||
authentication {
|
||||
auth_type PASS
|
||||
auth_pass 1111
|
||||
}
|
||||
virtual_ipaddress {
|
||||
192.168.10.10
|
||||
}
|
||||
|
||||
track_script {
|
||||
chk_mysql_port
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
! Configuration File for keepalived
|
||||
|
||||
global_defs {
|
||||
router_id MYSQL_MHA
|
||||
}
|
||||
|
||||
vrrp_script chk_mysql_port {
|
||||
script "{$SERVER_PATH}/scripts/chk.sh mysql"
|
||||
interval 2
|
||||
weight –5
|
||||
fall 2
|
||||
rise 1
|
||||
}
|
||||
|
||||
vrrp_instance VI_MYSQL {
|
||||
state MASTER
|
||||
interface {$ETH_XX}
|
||||
virtual_router_id 51
|
||||
priority 101
|
||||
advert_int 1
|
||||
authentication {
|
||||
auth_type PASS
|
||||
auth_pass 1111
|
||||
}
|
||||
virtual_ipaddress {
|
||||
192.168.10.10
|
||||
}
|
||||
|
||||
track_script {
|
||||
chk_mysql_port
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
! Configuration File for keepalived
|
||||
|
||||
global_defs {
|
||||
# 路由标识,主从保持一致
|
||||
router_id MYSQL_MHA
|
||||
}
|
||||
|
||||
#检测mysql服务是否在运行。有很多方式,比如进程,用脚本检测等等
|
||||
vrrp_script chk_mysql_port {
|
||||
# 这里通过脚本监测
|
||||
script "{$SERVER_PATH}/scripts/chk.sh mysql"
|
||||
# 脚本执行间隔,每2s检测一次
|
||||
interval 2
|
||||
# 脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5
|
||||
weight –5
|
||||
# 检测连续2次失败才算确定是真失败。会用weight减少优先级(1-255之间)
|
||||
fall 2
|
||||
# 检测1次成功就算成功。但不修改优先级
|
||||
rise 1
|
||||
}
|
||||
|
||||
vrrp_instance VI_1 {
|
||||
# 这里所有节点定义为BACKUP/MASTER
|
||||
state BACKUP
|
||||
# 指定虚拟ip的网卡(可能需要手动查看)
|
||||
# route -n | grep ^0.0.0.0 | awk '{print $8}'
|
||||
interface {$ETH_XX}
|
||||
# 路由器标识,MASTER和BACKUP必须是一致的
|
||||
virtual_router_id 51
|
||||
# 定义优先级,数字越大,优先级越高,在同一个vrrp_instance下,MASTER的优先级必须大于BACKUP的优先级
|
||||
priority 99
|
||||
# 通知间隔秒数(心跳频率)
|
||||
advert_int 1
|
||||
# 不抢占模式,在优先级高的机器上设置即可,优先级低的机器可不设置
|
||||
nopreempt
|
||||
# 认证信息配置,主从服务器保持一致
|
||||
authentication {
|
||||
auth_type PASS
|
||||
auth_pass 1111
|
||||
}
|
||||
virtual_ipaddress {
|
||||
# 虚拟IP(VIP) | 根据情况设置
|
||||
192.168.10.10
|
||||
}
|
||||
|
||||
track_script {
|
||||
chk_mysql_port
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Executable
+19
@@ -0,0 +1,19 @@
|
||||
<div class="bt-form">
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('lvs');">服务</p>
|
||||
<p onclick="pluginInitD('lvs');">自启动</p>
|
||||
<p onclick="pluginConfig('lvs');">配置修改</p>
|
||||
<!-- <p onclick="pluginLogs('lvs','','run_log',30);">运行日志</p> -->
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinHeight(480);
|
||||
$.getScript( "/plugins/file?name=lvs&f=js/lvs.js", function(){
|
||||
pluginService('lvs');
|
||||
});
|
||||
</script>
|
||||
Executable
+180
@@ -0,0 +1,180 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import string
|
||||
import subprocess
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'lvs'
|
||||
|
||||
def getIpvsadm():
|
||||
return 'ipvsadm'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
if app_debug:
|
||||
return '/tmp/' + getPluginName()
|
||||
return '/etc/init.d/' + getPluginName()
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
t = t.split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':')
|
||||
tmp[t[0]] = t[1]
|
||||
return tmp
|
||||
|
||||
|
||||
def checkArgs(data, ck=[]):
|
||||
for i in range(len(ck)):
|
||||
if not ck[i] in data:
|
||||
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
|
||||
return (True, mw.returnJson(True, 'ok'))
|
||||
|
||||
|
||||
def getConf():
|
||||
path = '/etc/default/ipvsadm'
|
||||
return path
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell("which ipvsadm")
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
|
||||
def initDreplace():
|
||||
|
||||
file_tpl = getInitDTpl()
|
||||
service_path = os.path.dirname(os.getcwd())
|
||||
|
||||
initD_path = getServerDir() + '/init.d'
|
||||
if not os.path.exists(initD_path):
|
||||
os.mkdir(initD_path)
|
||||
file_bin = initD_path + '/' + getPluginName()
|
||||
|
||||
# initd replace
|
||||
if not os.path.exists(file_bin):
|
||||
content = mw.readFile(file_tpl)
|
||||
content = contentReplace(content)
|
||||
mw.writeFile(file_bin, content)
|
||||
mw.execShell('chmod +x ' + file_bin)
|
||||
|
||||
|
||||
return file_bin
|
||||
|
||||
|
||||
def haOp(method):
|
||||
return 'ok'
|
||||
|
||||
|
||||
def start():
|
||||
return haOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return haOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
return haOp('restart')
|
||||
|
||||
|
||||
def reload():
|
||||
return haOp('reload')
|
||||
|
||||
def initdStatus():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
if current_os.startswith('freebsd'):
|
||||
initd_bin = getInitDFile()
|
||||
if os.path.exists(initd_bin):
|
||||
return 'ok'
|
||||
|
||||
shell_cmd = 'systemctl status ' + \
|
||||
getPluginName() + ' | grep loaded | grep "enabled;"'
|
||||
data = mw.execShell(shell_cmd)
|
||||
if data[0] == '':
|
||||
return 'fail'
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mw.execShell('systemctl enable ' + getIpvsadm())
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
return "Apple Computer does not support"
|
||||
|
||||
mw.execShell('systemctl disable ' + getIpvsadm())
|
||||
return 'ok'
|
||||
|
||||
def runLog():
|
||||
path = getConf()
|
||||
content = mw.readFile(path)
|
||||
rep = 'log\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0]
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
func = sys.argv[1]
|
||||
if func == 'status':
|
||||
print(status())
|
||||
elif func == 'start':
|
||||
print(start())
|
||||
elif func == 'stop':
|
||||
print(stop())
|
||||
elif func == 'restart':
|
||||
print(restart())
|
||||
elif func == 'reload':
|
||||
print(reload())
|
||||
elif func == 'initd_status':
|
||||
print(initdStatus())
|
||||
elif func == 'initd_install':
|
||||
print(initdInstall())
|
||||
elif func == 'initd_uninstall':
|
||||
print(initdUinstall())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
else:
|
||||
print('error')
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"sort": 7,
|
||||
"ps": "[<span style='color:red;'>内网</span>]LVS超强负载均衡,通过ipvsadm管理[<span style='color:red;'>暂时不可用</span>]",
|
||||
"name": "lvs",
|
||||
"title": "LVS",
|
||||
"shell": "install.sh",
|
||||
"versions":["1.0"],
|
||||
"updates":["1.0"],
|
||||
"tip": "soft",
|
||||
"checks": "server/lvs",
|
||||
"path": "server/lvs",
|
||||
"display": 1,
|
||||
"author": "midoks",
|
||||
"date": "2023-11-17",
|
||||
"home": "http://www.linuxvirtualserver.org/",
|
||||
"type": 0,
|
||||
"pid": "4"
|
||||
}
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH=$PATH:/opt/homebrew/bin
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
sys_os=`uname`
|
||||
VERSION=1.6.22
|
||||
|
||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/lvs && bash install.sh install 1.0
|
||||
# cd /www/server/mdserver-web/plugins/lvs && bash install.sh install 1.0
|
||||
|
||||
|
||||
Install_LVS(){
|
||||
mkdir -p $serverPath/source
|
||||
|
||||
which ipvsadm
|
||||
if [ "$?" == "0" ];then
|
||||
echo '已安装LVS!!'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo '正在安装LVS...'
|
||||
|
||||
# 检测平台命令
|
||||
which apt
|
||||
if [ "$?" == "0" ];then
|
||||
apt install -y ipvsadm
|
||||
fi
|
||||
|
||||
which yum
|
||||
if [ "$?" == "0" ];then
|
||||
yum install -y ipvsadm
|
||||
fi
|
||||
|
||||
which ipvsadm
|
||||
if [ "$?" == "0" ];then
|
||||
echo '正在安装LVS成功!'
|
||||
mkdir -p $serverPath/lvs
|
||||
|
||||
ipv_version=`ipvsadm -v | awk '{print $2}'`
|
||||
if [ "$ipv_version" != "" ];then
|
||||
echo "$ipv_version" > $serverPath/lvs/version.pl
|
||||
else
|
||||
echo '1.0' > $serverPath/lvs/version.pl
|
||||
fi
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/lvs/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/lvs/index.py initd_install
|
||||
else
|
||||
echo '正在安装LVS失败!'
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_LVS()
|
||||
{
|
||||
# 检测平台命令
|
||||
which apt
|
||||
if [ "$?" == "0" ];then
|
||||
apt remove -y ipvsadm
|
||||
fi
|
||||
|
||||
which yum
|
||||
if [ "$?" == "0" ];then
|
||||
yum uninstall -y ipvsadm
|
||||
fi
|
||||
echo "卸载LVS完成"
|
||||
|
||||
if [ -d $serverPath/lvs ];then
|
||||
rm -rf $serverPath/lvs
|
||||
fi
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_LVS
|
||||
else
|
||||
Uninstall_LVS
|
||||
fi
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
function lvsPostMin(method, args, callback){
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'lvs';
|
||||
req_data['func'] = method;
|
||||
|
||||
if (typeof(args) != 'undefined' && args!=''){
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/run', req_data, function(data) {
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function lvsPost(method, args, callback, msg = '正在获取...'){
|
||||
var loadT = layer.msg(msg, { icon: 16, time: 0, shade: 0.3 });
|
||||
lvsPostMin(method,args,function(data){
|
||||
layer.close(loadT);
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function secToTime(s) {
|
||||
var t;
|
||||
if(s > -1){
|
||||
var hour = Math.floor(s/3600);
|
||||
var min = Math.floor(s/60) % 60;
|
||||
var sec = s % 60;
|
||||
if(hour < 10) {
|
||||
t = '0'+ hour + ":";
|
||||
} else {
|
||||
t = hour + ":";
|
||||
}
|
||||
|
||||
if(min < 10){t += "0";}
|
||||
t += min + ":";
|
||||
if(sec < 10){t += "0";}
|
||||
t += sec.toFixed(2);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
debian
|
||||
|
||||
# 查看网卡
|
||||
ls /sys/class/net/
|
||||
|
||||
ifconfig ens256 172.16.204.100 netmask 255.255.255.255 broadcast 192.168.212.100 up
|
||||
|
||||
route add -host 172.16.204.100 dev ens256
|
||||
|
||||
|
||||
ipvsadm -A -t 172.16.204.100:80 -s rr
|
||||
ipvsadm -a -t 172.16.204.100:80 -r 172.16.204.129:80 -m
|
||||
|
||||
# 清空LVS规则
|
||||
|
||||
ipvsadm -C
|
||||
|
||||
# 查看LVS
|
||||
|
||||
ipvsadm -L -n
|
||||
@@ -12,6 +12,7 @@
|
||||
<p onclick="myPerfOpt();">性能优化</p>
|
||||
<p onclick="myLogs();">日志</p>
|
||||
<p onclick="pluginLogs('mariadb',$('.plugin_version').attr('version'),'show_log');">慢日志</p>
|
||||
<p onclick="myBinLogs();">BINLOG</p>
|
||||
<p onclick="dbList()">管理列表</p>
|
||||
<p onclick="masterOrSlaveConf($('.plugin_version').attr('version'))">主从配置</p>
|
||||
</div>
|
||||
|
||||
+211
-35
@@ -90,6 +90,12 @@ def getDataDir():
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
def getLogBinName():
|
||||
file = getConf()
|
||||
content = mw.readFile(file)
|
||||
rep = 'log-bin\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
def getPidFile():
|
||||
file = getConf()
|
||||
@@ -294,6 +300,53 @@ def binLog():
|
||||
mw.writeFile(conf, con)
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
def binLogList():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['page', 'page_size', 'tojs'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
page = int(args['page'])
|
||||
page_size = int(args['page_size'])
|
||||
|
||||
data_dir = getDataDir()
|
||||
log_bin_name = getLogBinName()
|
||||
|
||||
alist = os.listdir(data_dir)
|
||||
log_bin_l = []
|
||||
for x in range(len(alist)):
|
||||
f = alist[x]
|
||||
t = {}
|
||||
if f.startswith(log_bin_name) and not f.endswith('.index'):
|
||||
abspath = data_dir + '/' + f
|
||||
t['name'] = f
|
||||
t['size'] = os.path.getsize(abspath)
|
||||
t['time'] = mw.getDataFromInt(os.path.getctime(abspath))
|
||||
log_bin_l.append(t)
|
||||
|
||||
log_bin_l = sorted(log_bin_l, key=lambda x: x['time'], reverse=True)
|
||||
|
||||
# print(log_bin_l)
|
||||
# print(data_dir, log_bin_name)
|
||||
|
||||
count = len(log_bin_l)
|
||||
|
||||
page_start = (page - 1) * page_size
|
||||
page_end = page_start + page_size
|
||||
if page_end > count:
|
||||
page_end = count
|
||||
|
||||
data = {}
|
||||
page_args = {}
|
||||
page_args['count'] = count
|
||||
page_args['p'] = page
|
||||
page_args['row'] = page_size
|
||||
page_args['tojs'] = args['tojs']
|
||||
data['page'] = mw.getPage(page_args)
|
||||
data['data'] = log_bin_l[page_start:page_end]
|
||||
|
||||
return mw.getJson(data)
|
||||
|
||||
|
||||
def cleanBinLog():
|
||||
db = pMysqlDb()
|
||||
@@ -302,21 +355,6 @@ def cleanBinLog():
|
||||
return mw.returnJson(True, '清理BINLOG成功!')
|
||||
|
||||
|
||||
def setSkipGrantTables(v):
|
||||
'''
|
||||
设置是否密码验证
|
||||
'''
|
||||
conf = getConf()
|
||||
con = mw.readFile(conf)
|
||||
if v:
|
||||
if con.find('#skip-grant-tables') != -1:
|
||||
con = con.replace('#skip-grant-tables', 'skip-grant-tables')
|
||||
else:
|
||||
con = con.replace('skip-grant-tables', '#skip-grant-tables')
|
||||
mw.writeFile(conf, con)
|
||||
return True
|
||||
|
||||
|
||||
def getErrorLog():
|
||||
args = getArgs()
|
||||
path = getDataDir()
|
||||
@@ -402,6 +440,8 @@ def initMariaDbPwd():
|
||||
pwd + ' -e "drop database test";'
|
||||
mw.execShell(drop_test_db)
|
||||
|
||||
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
|
||||
|
||||
# 删除冗余账户
|
||||
hostname = mw.execShell('hostname')[0].strip()
|
||||
if hostname != 'localhost':
|
||||
@@ -412,8 +452,6 @@ def initMariaDbPwd():
|
||||
drop_root_hostname = serverdir + '/bin/mysql --defaults-file=' + \
|
||||
myconf + ' -uroot -p' + pwd + ' -e "drop user \'root\'@\'' + hostname + '\'";'
|
||||
mw.execShell(drop_root_hostname)
|
||||
|
||||
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
|
||||
return True
|
||||
|
||||
|
||||
@@ -579,7 +617,7 @@ def setMyPort():
|
||||
restart()
|
||||
return mw.returnJson(True, '编辑成功!')
|
||||
|
||||
|
||||
# python3 plugins/mariadb/index.py run_info {}
|
||||
def runInfo(version):
|
||||
|
||||
if status(version) == 'stop':
|
||||
@@ -755,6 +793,13 @@ def importDbBackup():
|
||||
return mw.returnJson(True, 'ok')
|
||||
|
||||
|
||||
def rootPwd():
|
||||
return pSqliteDb('config').where(
|
||||
'id=?', (1,)).getField('mysql_root')
|
||||
|
||||
|
||||
# python3 plugins/mariadb/index.py import_db_external {"file":"xx.sql","name":"demo1"}
|
||||
# python3 plugins/mariadb/index.py import_db_external {"file":"db_demo1_20231221_203614 2.sql","name":"demo1"}
|
||||
def importDbExternal():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file', 'name'])
|
||||
@@ -801,6 +846,9 @@ def importDbExternal():
|
||||
mw.execShell(cmd)
|
||||
import_sql = import_dir + tmpFile
|
||||
|
||||
if file.find(".sql") > -1 and file.find(".sql.gz") == -1:
|
||||
import_sql = import_dir + file
|
||||
|
||||
if import_sql == "":
|
||||
return mw.returnJson(False, '未找SQL文件')
|
||||
|
||||
@@ -808,12 +856,14 @@ def importDbExternal():
|
||||
sock = getSocketFile()
|
||||
|
||||
os.environ["MYSQL_PWD"] = pwd
|
||||
mysql_cmd = getServerDir() + '/bin/mariadb -S ' + sock + ' -uroot -p' + \
|
||||
pwd + ' ' + name + ' < ' + import_sql
|
||||
mysql_cmd = getServerDir() + '/bin/mariadb -S ' + sock + ' -uroot -p"' + \
|
||||
pwd + '" ' + name + ' < "' + import_sql+'"'
|
||||
|
||||
# print(mysql_cmd)
|
||||
os.system(mysql_cmd)
|
||||
os.remove(import_sql)
|
||||
|
||||
if ext != 'sql':
|
||||
os.remove(import_sql)
|
||||
|
||||
return mw.returnJson(True, 'ok')
|
||||
|
||||
@@ -977,7 +1027,7 @@ def syncGetDatabases():
|
||||
host = user["Host"]
|
||||
break
|
||||
|
||||
ps = mw.getMsg('INPUT_PS')
|
||||
ps = vdb_name
|
||||
if vdb_name == 'test':
|
||||
ps = mw.getMsg('DATABASE_TEST')
|
||||
addTime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
@@ -1049,12 +1099,21 @@ def setRootPwd(version=''):
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
#强制修改
|
||||
force = 0
|
||||
if 'force' in args and args['force'] == '1':
|
||||
force = 1
|
||||
|
||||
|
||||
password = args['password']
|
||||
try:
|
||||
pdb = pMysqlDb('mysql')
|
||||
result = pdb.query("show databases")
|
||||
isError = isSqlError(result)
|
||||
if isError != None:
|
||||
if force == 1:
|
||||
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
|
||||
return mw.returnJson(True, '【强制修改】数据库root密码修改成功(不意为成功连接数据)!')
|
||||
return isError
|
||||
|
||||
cmd = "ALTER USER 'root'@'localhost' IDENTIFIED BY '" + password + "';"
|
||||
@@ -1064,7 +1123,12 @@ def setRootPwd(version=''):
|
||||
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (password,))
|
||||
orm = pMysqlDb()
|
||||
orm.execute("flush privileges")
|
||||
return mw.returnJson(True, '数据库root密码修改成功!')
|
||||
|
||||
msg = ''
|
||||
if force == 1:
|
||||
msg = ',无须强制!'
|
||||
|
||||
return mw.returnJson(True, '数据库root密码修改成功!' + msg)
|
||||
except Exception as ex:
|
||||
return mw.returnJson(False, '修改错误:' + str(ex))
|
||||
|
||||
@@ -1271,16 +1335,58 @@ def setDbAccess():
|
||||
psdb.where('username=?', (name,)).save('accept,rw', (access, 'rw',))
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
def openSkipGrantTables():
|
||||
mycnf = getConf()
|
||||
content = mw.readFile(mycnf)
|
||||
content = content.replace('#skip-grant-tables','skip-grant-tables')
|
||||
mw.writeFile(mycnf, content)
|
||||
return True
|
||||
|
||||
def closeSkipGrantTables():
|
||||
mycnf = getConf()
|
||||
content = mw.readFile(mycnf)
|
||||
content = content.replace('skip-grant-tables','#skip-grant-tables')
|
||||
mw.writeFile(mycnf, content)
|
||||
return True
|
||||
|
||||
|
||||
def resetDbRootPwd(version):
|
||||
serverdir = getServerDir()
|
||||
myconf = serverdir + "/etc/my.cnf"
|
||||
pwd = mw.getRandomString(16)
|
||||
pSqliteDb('config').where('id=?', (1,)).save('mysql_root', (pwd,))
|
||||
|
||||
db_option = "-S " + serverdir + "/mysql.sock"
|
||||
cmd_pass = serverdir + '/bin/mariadb ' + db_option + ' -uroot -e'
|
||||
cmd_pass = cmd_pass + \
|
||||
"\"flush privileges;use mysql;grant all privileges on *.* to 'root'@'localhost' identified by '" + pwd + "';"
|
||||
cmd_pass = cmd_pass + "flush privileges;\""
|
||||
|
||||
data = mw.execShell(cmd_pass)
|
||||
# print(data)
|
||||
return True
|
||||
|
||||
def fixDbAccess(version):
|
||||
|
||||
pdb = pMysqlDb()
|
||||
mdb_ddir = getDataDir()
|
||||
if not os.path.exists(mdb_ddir):
|
||||
return mw.returnJson(False, '数据目录不存在,尝试重启重建!')
|
||||
|
||||
try:
|
||||
pdb = pMysqlDb()
|
||||
psdb = pSqliteDb('databases')
|
||||
data = pdb.query('show databases')
|
||||
isError = isSqlError(data)
|
||||
if isError != None:
|
||||
# 重置密码
|
||||
appCMD(version, 'stop')
|
||||
mw.execShell("rm -rf " + getServerDir() + "/data")
|
||||
openSkipGrantTables()
|
||||
appCMD(version, 'start')
|
||||
time.sleep(3)
|
||||
resetDbRootPwd(version)
|
||||
|
||||
appCMD(version, 'stop')
|
||||
closeSkipGrantTables()
|
||||
appCMD(version, 'start')
|
||||
return mw.returnJson(True, '修复成功!')
|
||||
return mw.returnJson(True, '正常无需修复!')
|
||||
@@ -1583,6 +1689,13 @@ def setDbMasterAccess():
|
||||
psdb.where('username=?', (username,)).save('accept', (access,))
|
||||
return mw.returnJson(True, '设置成功!')
|
||||
|
||||
def resetMaster(version=''):
|
||||
pdb = pMysqlDb()
|
||||
r = pdb.execute('reset master')
|
||||
isError = isSqlError(r)
|
||||
if isError != None:
|
||||
return isError
|
||||
return mw.returnJson(True, '重置成功!')
|
||||
|
||||
def getMasterDbList(version=''):
|
||||
args = getArgs()
|
||||
@@ -1894,8 +2007,7 @@ def getMasterRepSlaveUserCmd(version):
|
||||
if mode == "gtid":
|
||||
sql = "CHANGE MASTER " + connection_name + "TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||
clist[0]['password'] + "', " + "MASTER_LOG_FILE='" + mstatus[0]["File"] + \
|
||||
"',MASTER_USE_GTID=no,MASTER_CONNECT_RETRY=10;"
|
||||
clist[0]['password'] + "',MASTER_USE_GTID=no,MASTER_CONNECT_RETRY=10;"
|
||||
else:
|
||||
sql = "CHANGE MASTER " + connection_name + "TO MASTER_HOST='" + ip + "', MASTER_PORT=" + port + ", MASTER_USER='" + \
|
||||
clist[0]['username'] + "', MASTER_PASSWORD='" + \
|
||||
@@ -2181,6 +2293,58 @@ def getSlaveList(version=''):
|
||||
data['data'] = dlist
|
||||
return mw.getJson(data)
|
||||
|
||||
def trySlaveSyncBugfix(version=''):
|
||||
if status(version) == 'stop':
|
||||
return mw.returnJson(False, 'MySQL未启动', [])
|
||||
|
||||
mode_file = getSyncModeFile()
|
||||
if not os.path.exists(mode_file):
|
||||
return mw.returnJson(False, '需要先设置同步配置')
|
||||
|
||||
mode = mw.readFile(mode_file)
|
||||
if mode != 'sync-user':
|
||||
return mw.returnJson(False, '仅支持【同步账户】模式')
|
||||
|
||||
conn = pSqliteDb('slave_sync_user')
|
||||
slave_sync_data = conn.field('ip,port,user,pass,mode,cmd').select()
|
||||
if len(slave_sync_data) < 1:
|
||||
return mw.returnJson(False, '需要先添加【同步用户】配置!')
|
||||
|
||||
# print(slave_sync_data)
|
||||
# 本地从库
|
||||
sdb = pMysqlDb()
|
||||
|
||||
gtid_purged = ''
|
||||
|
||||
for i in range(len(slave_sync_data)):
|
||||
port = slave_sync_data[i]['port']
|
||||
password = slave_sync_data[i]['pass']
|
||||
host = slave_sync_data[i]['ip']
|
||||
user = slave_sync_data[i]['user']
|
||||
|
||||
# print(port, password, host)
|
||||
|
||||
mdb = mw.getMyORM()
|
||||
mdb.setHost(host)
|
||||
mdb.setPort(port)
|
||||
mdb.setUser(user)
|
||||
mdb.setPwd(password)
|
||||
mdb.setSocket('')
|
||||
|
||||
# var_gtid = mdb.query('show VARIABLES like "%gtid_purged%"')
|
||||
var_gtid = mdb.query('select @@global.gtid_current_pos as Value')
|
||||
#print(var_gtid)
|
||||
if len(var_gtid) > 0:
|
||||
gtid_purged += var_gtid[0]['Value'] + ','
|
||||
|
||||
gtid_purged = gtid_purged.strip(',')
|
||||
sql = "set @@global.gtid_slave_pos='" + gtid_purged + "'"
|
||||
|
||||
sdb.query('stop all slaves')
|
||||
# print(sql)
|
||||
sdb.query(sql)
|
||||
sdb.query('start all slaves')
|
||||
return mw.returnJson(True, '修复成功!')
|
||||
|
||||
def getSlaveSyncCmd(version=''):
|
||||
root = mw.getRunDir()
|
||||
@@ -2221,7 +2385,7 @@ def parseSlaveSyncCmd(cmd):
|
||||
a[kv[0]] = kv[1].replace("'", '').replace("'", '').replace(";", '')
|
||||
return a
|
||||
|
||||
|
||||
# python3 plugins/mariadb/index.py init_slave_status {}
|
||||
def initSlaveStatusSyncUser(version=''):
|
||||
conn = pSqliteDb('slave_sync_user')
|
||||
|
||||
@@ -2262,7 +2426,7 @@ def initSlaveStatusSyncUser(version=''):
|
||||
try:
|
||||
pinfo = parseSlaveSyncCmd(cmd_sql)
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, base_t + '->CMD同步命令不合规范!')
|
||||
return mw.returnJson(False, base_t + '->CMD同步命令不合规范:'+str(e))
|
||||
|
||||
pdb.query(cmd_sql)
|
||||
|
||||
@@ -2447,8 +2611,7 @@ def fullSync(version=''):
|
||||
if args['begin'] == '1':
|
||||
cmd = 'cd ' + mw.getRunDir() + ' && python3 ' + \
|
||||
getPluginDir() + \
|
||||
'/index.py do_full_sync {"db":"' + \
|
||||
args['db'] + '","sign":"' + sign + '"} &'
|
||||
'/index.py do_full_sync {"db":"' + args['db'] + '","sign":"' + sign + '"} &'
|
||||
# print(cmd)
|
||||
mw.execShell(cmd)
|
||||
return json.dumps({'code': 0, 'msg': '同步数据中!', 'progress': 0})
|
||||
@@ -2470,6 +2633,7 @@ def fullSync(version=''):
|
||||
return json.dumps({'code': 0, 'msg': '点击开始,开始同步!', 'progress': 0})
|
||||
|
||||
|
||||
# python3 plugins/mariadb/index.py do_full_sync {"db":"demo1","sign":"","beigin":"1"}
|
||||
def doFullSync(version=''):
|
||||
mode_file = getSyncModeFile()
|
||||
if not os.path.exists(mode_file):
|
||||
@@ -2507,13 +2671,16 @@ def doFullSyncUser(version=''):
|
||||
ip = data['ip']
|
||||
|
||||
bak_file = '/tmp/tmp.sql'
|
||||
if os.path.exists(bak_file):
|
||||
os.system("rm -rf " + bak_file)
|
||||
|
||||
writeDbSyncStatus({'code': 0, 'msg': '开始同步...', 'progress': 0})
|
||||
writeDbSyncStatus({'code': 1, 'msg': '远程导出数据...', 'progress': 10})
|
||||
|
||||
if not os.path.exists(bak_file):
|
||||
dump_sql_data = getServerDir() + "/bin/mysqldump --force --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
|
||||
port + " -u" + user + " -p" + apass + " " + sync_db + " > " + bak_file
|
||||
# https://mariadb.com/kb/zh-cn/mariadb-dump/
|
||||
dump_sql_data = getServerDir() + "/bin/mariadb-dump -f --opt --default-character-set=utf8 --single-transaction -h" + ip + " -P" + \
|
||||
port + " -u" + user + " -p'" + apass + "' " + sync_db + ">" + bak_file
|
||||
print(dump_sql_data)
|
||||
mw.execShell(dump_sql_data)
|
||||
|
||||
@@ -2521,8 +2688,9 @@ def doFullSyncUser(version=''):
|
||||
if os.path.exists(bak_file):
|
||||
pwd = pSqliteDb('config').where('id=?', (1,)).getField('mysql_root')
|
||||
sock = getSocketFile()
|
||||
my_import_cmd = getServerDir() + '/bin/mysql -S ' + sock + ' -uroot -p' + pwd + \
|
||||
' ' + sync_db + ' < ' + bak_file
|
||||
my_import_cmd = getServerDir() + '/bin/mariadb -S ' + sock + " -uroot -p'" + pwd + \
|
||||
"' " + sync_db + '<' + bak_file
|
||||
print(my_import_cmd)
|
||||
mw.execShell(my_import_cmd)
|
||||
|
||||
pinfo = parseSlaveSyncCmd(data['cmd'])
|
||||
@@ -2724,6 +2892,8 @@ if __name__ == "__main__":
|
||||
print(getConf())
|
||||
elif func == 'bin_log':
|
||||
print(binLog())
|
||||
elif func == 'binlog_list':
|
||||
print(binLogList())
|
||||
elif func == 'clean_bin_log':
|
||||
print(cleanBinLog())
|
||||
elif func == 'error_log':
|
||||
@@ -2740,6 +2910,8 @@ if __name__ == "__main__":
|
||||
print(setMyPort())
|
||||
elif func == 'init_pwd':
|
||||
print(initMysqlPwd())
|
||||
elif func == 'root_pwd':
|
||||
print(rootPwd())
|
||||
elif func == 'get_db_list':
|
||||
print(getDbList())
|
||||
elif func == 'set_db_backup':
|
||||
@@ -2790,6 +2962,8 @@ if __name__ == "__main__":
|
||||
print(getDbrunMode(version))
|
||||
elif func == 'set_dbrun_mode':
|
||||
print(setDbrunMode(version))
|
||||
elif func == 'reset_master':
|
||||
print(resetMaster(version))
|
||||
elif func == 'get_masterdb_list':
|
||||
print(getMasterDbList(version))
|
||||
elif func == 'get_master_status':
|
||||
@@ -2814,6 +2988,8 @@ if __name__ == "__main__":
|
||||
print(getMasterRepSlaveUserCmd(version))
|
||||
elif func == 'get_slave_list':
|
||||
print(getSlaveList(version))
|
||||
elif func == 'try_slave_sync_bugfix':
|
||||
print(trySlaveSyncBugfix(version))
|
||||
elif func == 'get_slave_sync_cmd':
|
||||
print(getSlaveSyncCmd(version))
|
||||
elif func == 'get_slave_ssh_list':
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import re
|
||||
import json
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
|
||||
if mw.isAppleSystem():
|
||||
cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
|
||||
info = mw.execShell(cmd)
|
||||
p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
|
||||
sys.path.append(p)
|
||||
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'mariadb'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getSPluginDir():
|
||||
return '/www/server/mdserver-web/plugins/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getConf():
|
||||
path = getServerDir() + '/etc/my.cnf'
|
||||
return path
|
||||
|
||||
|
||||
def getDataDir():
|
||||
file = getConf()
|
||||
content = mw.readFile(file)
|
||||
rep = 'datadir\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
|
||||
def getRelayLogName():
|
||||
file = getConf()
|
||||
content = mw.readFile(file)
|
||||
rep = 'relay-log\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
|
||||
def getLogBinName():
|
||||
file = getConf()
|
||||
content = mw.readFile(file)
|
||||
rep = 'log-bin\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
|
||||
def binLogListLook(args):
|
||||
|
||||
file = args['file']
|
||||
line = args['line']
|
||||
|
||||
data_dir = getDataDir()
|
||||
my_bin = getServerDir() + '/bin'
|
||||
my_binlog_cmd = my_bin + '/mysqlbinlog'
|
||||
|
||||
cmd = my_binlog_cmd + ' --no-defaults ' + \
|
||||
data_dir + '/' + file + '|tail -' + str(line)
|
||||
|
||||
data = mw.execShell(cmd)
|
||||
|
||||
rdata = {}
|
||||
rdata['cmd'] = cmd
|
||||
rdata['data'] = data[0]
|
||||
|
||||
return rdata
|
||||
|
||||
|
||||
def binLogListLookDecode(args):
|
||||
|
||||
file = args['file']
|
||||
line = args['line']
|
||||
|
||||
data_dir = getDataDir()
|
||||
my_bin = getServerDir() + '/bin'
|
||||
my_binlog_cmd = my_bin + '/mysqlbinlog'
|
||||
|
||||
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
|
||||
data_dir + '/' + file + '|tail -' + str(line)
|
||||
|
||||
data = mw.execShell(cmd)
|
||||
|
||||
rdata = {}
|
||||
rdata['cmd'] = cmd
|
||||
rdata['data'] = data[0]
|
||||
|
||||
return rdata
|
||||
|
||||
|
||||
def binLogListTraceRelay(args):
|
||||
rdata = {}
|
||||
file = args['file']
|
||||
line = args['line']
|
||||
|
||||
relay_name = getRelayLogName()
|
||||
data_dir = getDataDir()
|
||||
alist = os.listdir(data_dir)
|
||||
relay_list = []
|
||||
for x in range(len(alist)):
|
||||
f = alist[x]
|
||||
t = {}
|
||||
if f.startswith(relay_name) and not f.endswith('.index'):
|
||||
relay_list.append(f)
|
||||
|
||||
relay_list = sorted(relay_list, reverse=True)
|
||||
if len(relay_list) == 0:
|
||||
rdata['cmd'] = ''
|
||||
rdata['data'] = '无Relay日志'
|
||||
return rdata
|
||||
|
||||
file = relay_list[0]
|
||||
|
||||
my_bin = getServerDir() + '/bin'
|
||||
my_binlog_cmd = my_bin + '/mysqlbinlog'
|
||||
|
||||
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
|
||||
data_dir + '/' + file + '|tail -' + str(line)
|
||||
|
||||
data = mw.execShell(cmd)
|
||||
|
||||
rdata['cmd'] = cmd
|
||||
rdata['data'] = data[0]
|
||||
|
||||
return rdata
|
||||
|
||||
|
||||
def binLogListTraceBinLog(args):
|
||||
rdata = {}
|
||||
file = args['file']
|
||||
line = args['line']
|
||||
|
||||
data_dir = getDataDir()
|
||||
log_bin_name = getLogBinName()
|
||||
|
||||
alist = os.listdir(data_dir)
|
||||
log_bin_l = []
|
||||
for x in range(len(alist)):
|
||||
f = alist[x]
|
||||
t = {}
|
||||
if f.startswith(log_bin_name) and not f.endswith('.index'):
|
||||
log_bin_l.append(f)
|
||||
|
||||
if len(log_bin_l) == 0:
|
||||
rdata['cmd'] = ''
|
||||
rdata['data'] = '无BINLOG'
|
||||
return rdata
|
||||
|
||||
log_bin_l = sorted(log_bin_l, reverse=True)
|
||||
file = log_bin_l[0]
|
||||
|
||||
my_bin = getServerDir() + '/bin'
|
||||
my_binlog_cmd = my_bin + '/mysqlbinlog'
|
||||
|
||||
cmd = my_binlog_cmd + ' --no-defaults --base64-output=decode-rows -vvvv ' + \
|
||||
data_dir + '/' + file + '|tail -' + str(line)
|
||||
|
||||
data = mw.execShell(cmd)
|
||||
|
||||
rdata['cmd'] = cmd
|
||||
rdata['data'] = data[0]
|
||||
|
||||
return rdata
|
||||
@@ -8,7 +8,7 @@
|
||||
"uninstall_pre_inspection":true,
|
||||
"checks": "server/mariadb",
|
||||
"path": "server/mariadb",
|
||||
"versions":["10.6","10.7","10.8","10.9","10.11","11.0"],
|
||||
"versions":["10.6","10.7","10.8","10.9","10.11","11.0","11.1","11.2","11.3"],
|
||||
"shell":"install.sh",
|
||||
"checks":"server/mariadb",
|
||||
"path":"server/mariadb",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
|
||||
+269
-10
@@ -58,6 +58,62 @@ function myAsyncPost(method,args){
|
||||
return syncPost('/plugins/run', {name:'mysql', func:method, args:_args});
|
||||
}
|
||||
|
||||
function myPostCallbak(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'mariadb';
|
||||
req_data['func'] = method;
|
||||
req_data['script']='index_mariadb';
|
||||
args['version'] = version;
|
||||
|
||||
|
||||
if (typeof(args) == 'string' && args == ''){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/callback', req_data, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function myPostCallbakN(method, version, args,callback){
|
||||
|
||||
var req_data = {};
|
||||
req_data['name'] = 'mariadb';
|
||||
req_data['func'] = method;
|
||||
req_data['script']='index_mariadb';
|
||||
args['version'] = version;
|
||||
|
||||
|
||||
if (typeof(args) == 'string' && args == ''){
|
||||
req_data['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
req_data['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/callback', req_data, function(data) {
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof(callback) == 'function'){
|
||||
callback(data);
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
|
||||
function runInfo(){
|
||||
myPost('run_info','',function(data){
|
||||
|
||||
@@ -83,7 +139,7 @@ function runInfo(){
|
||||
<tr><th>活动/峰值连接数</th><td>' + rdata.Threads_running + '/' + rdata.Max_used_connections + '</td><td colspan="2">若值过大,增加max_connections</td></tr>\
|
||||
<tr><th>线程缓存命中率</th><td>' + ((1 - rdata.Threads_created / rdata.Connections) * 100).toFixed(2) + '%</td><td colspan="2">若过低,增加thread_cache_size</td></tr>\
|
||||
<tr><th>索引命中率</th><td>' + ((1 - rdata.Key_reads / rdata.Key_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">若过低,增加key_buffer_size</td></tr>\
|
||||
<tr><th>Innodb索引命中率</th><td>' + ((1 - rdata.Innodb_buffer_pool_reads / rdata.Innodb_buffer_pool_read_requests) * 100).toFixed(2) + '%</td><td colspan="2">若过低,增加innodb_buffer_pool_size</td></tr>\
|
||||
<tr><th>Innodb索引命中率</th><td>' + (rdata.Innodb_buffer_pool_read_requests / (rdata.Innodb_buffer_pool_read_requests+rdata.Innodb_buffer_pool_reads)).toFixed(2) + '%</td><td colspan="2">若过低,增加innodb_buffer_pool_size</td></tr>\
|
||||
<tr><th>查询缓存命中率</th><td>' + cache_size + '</td><td colspan="2">' + lan.soft.mysql_status_ps5 + '</td></tr>\
|
||||
<tr><th>创建临时表到磁盘</th><td>' + ((rdata.Created_tmp_disk_tables / rdata.Created_tmp_tables) * 100).toFixed(2) + '%</td><td colspan="2">若过大,尝试增加tmp_table_size</td></tr>\
|
||||
<tr><th>已打开的表</th><td>' + rdata.Open_tables + '</td><td colspan="2">若过大,增加table_cache_size</td></tr>\
|
||||
@@ -438,13 +494,24 @@ function syncToDatabase(type){
|
||||
}
|
||||
|
||||
function setRootPwd(type, pwd){
|
||||
if (type==1){
|
||||
var password = $("#MyPassword").val();
|
||||
myPost('set_root_pwd', {password:password}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
dbList();
|
||||
},{icon: rdata.status ? 1 : 2});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var index = layer.open({
|
||||
type: 1,
|
||||
area: '500px',
|
||||
title: '修改数据库密码',
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
btn:["提交","关闭"],
|
||||
btn:["提交", "关闭", "复制ROOT密码", "强制修改"],
|
||||
shadeClose: true,
|
||||
content: "<form class='bt-form pd20' id='mod_pwd'>\
|
||||
<div class='line'>\
|
||||
@@ -454,16 +521,36 @@ function setRootPwd(type, pwd){
|
||||
</div>\
|
||||
</div>\
|
||||
</form>",
|
||||
yes:function(index,layero){
|
||||
yes:function(layerIndex){
|
||||
var password = $("#MyPassword").val();
|
||||
myPost('set_root_pwd', {password:password}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
layer.close(layerIndex);
|
||||
dbList();
|
||||
layer.close(index);
|
||||
},{icon: rdata.status ? 1 : 2});
|
||||
});
|
||||
return;
|
||||
},
|
||||
btn3:function(){
|
||||
var password = $("#MyPassword").val();
|
||||
copyText(password);
|
||||
return false;
|
||||
},
|
||||
btn4:function(layerIndex){
|
||||
layer.confirm('强制修改,是为了在重建时使用,确定强制?', {
|
||||
btn: ['确定', '取消']
|
||||
}, function(index, layero){
|
||||
layer.close(index);
|
||||
var password = $("#MyPassword").val();
|
||||
myPost('set_root_pwd', {password:password,force:'1'}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
layer.close(layerIndex);
|
||||
dbList();
|
||||
},{icon: rdata.status ? 1 : 2});
|
||||
});
|
||||
});
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1160,6 +1247,146 @@ function dbList(page, search){
|
||||
});
|
||||
}
|
||||
|
||||
function myBinRollingLogs(_name, func, _args, line){
|
||||
|
||||
var file_line = 100;
|
||||
if ( typeof(line) != 'undefined' ){
|
||||
file_line = line;
|
||||
}
|
||||
|
||||
var reqTimer = null;
|
||||
|
||||
function requestLogs(func,file,line){
|
||||
myPostCallbakN(func,'',{'file':file,"line":line}, function(rdata){
|
||||
var data = rdata.data.data;
|
||||
var cmd = rdata.data.cmd;
|
||||
if(data == '') {
|
||||
data = '当前没有日志!';
|
||||
}
|
||||
|
||||
$('#my_rolling_cmd').html(cmd);
|
||||
|
||||
$('#my_rolling_copy').click(function(){
|
||||
copyText(cmd);
|
||||
});
|
||||
|
||||
var ebody = '<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log">'+data+'</textarea>';
|
||||
$("#my_rolling_logs").html(ebody);
|
||||
var ob = document.getElementById('roll_info_log');
|
||||
ob.scrollTop = ob.scrollHeight;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: _name + '日志',
|
||||
area: ['800px','700px'],
|
||||
end: function(){
|
||||
if (reqTimer){
|
||||
clearInterval(reqTimer);
|
||||
}
|
||||
},
|
||||
content:'<div class="change-default" style="padding:0px 20px 0px;">\
|
||||
<div class="divtable mtb10">\
|
||||
<table class="table table-hover"><tr>\
|
||||
<td id="my_rolling_cmd">cmd</td>\
|
||||
<td id="my_rolling_copy" style="width:35px;"><span class="ico-copy cursor btcopy" title="复制密码"></span></td>\
|
||||
<tr>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="change-default" style="padding:0px 20px 0px;" id="my_rolling_logs">\
|
||||
<textarea readonly="readonly" style="margin: 0px;width: 100%;height: 570px;background-color: #333;color:#fff; padding:0 5px" id="roll_info_log"></textarea>\
|
||||
</div>',
|
||||
success:function(){
|
||||
var fileName = _args['file'];
|
||||
requestLogs(func,fileName,file_line);
|
||||
reqTimer = setInterval(function(){
|
||||
requestLogs(func,fileName,file_line);
|
||||
},1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function myBinLogsRender(page){
|
||||
var _data = {};
|
||||
if (typeof(page) =='undefined'){
|
||||
var page = 1;
|
||||
}
|
||||
|
||||
_data['page'] = page;
|
||||
_data['page_size'] = 10;
|
||||
_data['tojs'] = 'myBinLogsRender';
|
||||
myPost('binlog_list', _data, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
// console.log(rdata);
|
||||
var list = '';
|
||||
for(i in rdata.data){
|
||||
list += '<tr>';
|
||||
|
||||
list += '<td>' + rdata.data[i]['name'] +'</td>';
|
||||
list += '<td>' + toSize(rdata.data[i]['size'])+'</td>';
|
||||
list += '<td>' + rdata.data[i]['time'] +'</td>';
|
||||
|
||||
|
||||
list += '<td style="text-align:right">';
|
||||
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look" class="btlink">查看</a> | ';
|
||||
list += '<a href="javascript:;" data-index="'+i+'" class="btlink look_decode" class="btlink">解码查看</a>';
|
||||
list += '</td></tr>';
|
||||
}
|
||||
|
||||
if (rdata.data.length ==0){
|
||||
list = '<tr><td colspan="4">无数据</td</tr>';
|
||||
}
|
||||
|
||||
$("#binlog_list tbody").html(list);
|
||||
$('#binlog_page').html(rdata.page);
|
||||
|
||||
|
||||
$('#binlog_list .look').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = rdata.data[i]['name'];
|
||||
myBinRollingLogs('查看BINLOG','binLogListLook',{'file':file },100);
|
||||
});
|
||||
|
||||
$('#binlog_list .look_decode').click(function(){
|
||||
var i = $(this).data('index');
|
||||
var file = rdata.data[i]['name'];
|
||||
myBinRollingLogs('查看解码BINLOG','binLogListLookDecode',{'file':file },100);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function myBinLogs(){
|
||||
var con = '<div class="safe bgw">\
|
||||
<button class="btn btn-success btn-sm relay_trace" type="button" style="margin-right: 5px;">中继日志跟踪</button>\
|
||||
<button class="btn btn-default btn-sm binlog_trace" type="button" style="margin-right: 5px;">最新BINLOG日志跟踪</button>\
|
||||
<div id="binlog_list" class="divtable mtb10">\
|
||||
<div class="tablescroll">\
|
||||
<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
|
||||
<thead><tr>\
|
||||
<th>文件名称</th>\
|
||||
<th>大小</th>\
|
||||
<th>时间</th>\
|
||||
<th style="text-align:right;">操作</th>\
|
||||
</tr></thead>\
|
||||
<tbody></tbody></table>\
|
||||
</div>\
|
||||
<div id="binlog_page" class="dataTables_paginate paging_bootstrap page"></div>\
|
||||
</div>\
|
||||
</div>';
|
||||
$(".soft-man-con").html(con);
|
||||
myBinLogsRender(1);
|
||||
|
||||
$('.soft-man-con .relay_trace').click(function(){
|
||||
myBinRollingLogs('中继日志跟踪','binLogListTraceRelay',{'file':''},100);
|
||||
});
|
||||
|
||||
$('.soft-man-con .binlog_trace').click(function(){
|
||||
myBinRollingLogs('最新BINLOG日志跟踪','binLogListTraceBinLog',{'file':''},100);
|
||||
});
|
||||
}
|
||||
|
||||
function myLogs(){
|
||||
|
||||
@@ -1603,6 +1830,14 @@ function setDbMasterAccess(username){
|
||||
});
|
||||
}
|
||||
|
||||
function resetMaster(){
|
||||
myPost('reset_master', '', function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
},{icon: rdata.status ? 1 : 2});
|
||||
},'正在执行重置master命令[reset master]');
|
||||
}
|
||||
|
||||
function getMasterRepSlaveList(){
|
||||
var _data = {};
|
||||
if (typeof(page) =='undefined'){
|
||||
@@ -2329,11 +2564,16 @@ function masterOrSlaveConf(version=''){
|
||||
<td>"+(info['Slave_SQL_Running_State'] == '' ? '无':info['Slave_SQL_Running_State']) +"</td>\
|
||||
</tr>";
|
||||
|
||||
var btn_list = ['复制错误',"取消"];
|
||||
if (info['Last_IO_Error'].search(/1236/i)>0){
|
||||
btn_list = ['复制错误',"取消","尝试修复"];
|
||||
}
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '同步异常信息',
|
||||
area: ['600px','300px'],
|
||||
btn:['复制错误',"取消"],
|
||||
btn:btn_list,
|
||||
content:"<form class='bt-form pd15'>\
|
||||
<div class='divtable mtb10'>\
|
||||
<div class='tablescroll'>\
|
||||
@@ -2348,10 +2588,20 @@ function masterOrSlaveConf(version=''){
|
||||
</div>\
|
||||
</form>",
|
||||
success:function(){
|
||||
// copyText(v['Error']);
|
||||
// $('.class-copy-db-err').click(function(){
|
||||
// copyText(v['Error']);
|
||||
// });
|
||||
if (info['Last_IO_Error'] != ''){
|
||||
copyText(info['Last_IO_Error']);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info['Last_SQL_Error'] != ''){
|
||||
copyText(info['Last_SQL_Error']);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info['Slave_SQL_Running_State'] != ''){
|
||||
copyText(info['Slave_SQL_Running_State']);
|
||||
return;
|
||||
}
|
||||
},
|
||||
yes:function(){
|
||||
if (info['Last_IO_Error'] != ''){
|
||||
@@ -2368,6 +2618,14 @@ function masterOrSlaveConf(version=''){
|
||||
copyText(info['Slave_SQL_Running_State']);
|
||||
return;
|
||||
}
|
||||
},
|
||||
btn3:function(){
|
||||
myPost('try_slave_sync_bugfix', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
showMsg(rdata.msg, function(){
|
||||
masterOrSlaveConf();
|
||||
},{ icon: rdata.status ? 1 : 5 },2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -2437,6 +2695,7 @@ function masterOrSlaveConf(version=''){
|
||||
<p class="conf_p">\
|
||||
<span class="f14 c6 mr20">Master[主]配置</span><span class="f14 c6 mr20"></span>\
|
||||
<button class="btn '+(!rdata.status ? 'btn-danger' : 'btn-success')+' btn-xs btn-master">'+(!rdata.status ? '未开启' : '已开启') +'</button>\
|
||||
<button class="btn btn-success btn-xs" onclick="resetMaster()">重置</button>\
|
||||
</p>\
|
||||
<hr/>\
|
||||
<!-- master list -->\
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
|
||||
@@ -14,7 +14,7 @@ sysName=`uname`
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mariadbDir=${serverPath}/source/mariadb
|
||||
|
||||
MY_VER=10.11.2
|
||||
MY_VER=10.11.6
|
||||
|
||||
Install_app()
|
||||
{
|
||||
@@ -102,16 +102,17 @@ Install_app()
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '10.11' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败' > $install_tmp
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
# https://mariadb.org/download/?t=mariadb
|
||||
@@ -13,7 +13,7 @@ sysName=`uname`
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mariadbDir=${serverPath}/source/mariadb
|
||||
|
||||
MY_VER=10.6.12
|
||||
MY_VER=10.6.16
|
||||
|
||||
Install_app()
|
||||
{
|
||||
@@ -105,16 +105,17 @@ Install_app()
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '10.6' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败' > $install_tmp
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
|
||||
@@ -92,16 +92,17 @@ Install_app()
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '10.7' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败' > $install_tmp
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
|
||||
@@ -92,16 +92,17 @@ Install_app()
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '10.8' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败' > $install_tmp
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
|
||||
@@ -14,7 +14,7 @@ sysName=`uname`
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mariadbDir=${serverPath}/source/mariadb
|
||||
|
||||
MY_VER=10.9.5
|
||||
MY_VER=10.9.8
|
||||
|
||||
Install_app()
|
||||
{
|
||||
@@ -102,16 +102,17 @@ Install_app()
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '10.9' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败' > $install_tmp
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
|
||||
@@ -14,7 +14,7 @@ sysName=`uname`
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mariadbDir=${serverPath}/source/mariadb
|
||||
|
||||
MY_VER=11.0.1
|
||||
MY_VER=11.0.4
|
||||
|
||||
Install_app()
|
||||
{
|
||||
@@ -100,17 +100,19 @@ Install_app()
|
||||
make -j${cpuCore} && make install && make clean
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '10.11' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
echo '11.0' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败' > $install_tmp
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
|
||||
Executable
+129
@@ -0,0 +1,129 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
|
||||
#https://dev.mysql.com/downloads/file/?id=480541
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
sysName=`uname`
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mariadbDir=${serverPath}/source/mariadb
|
||||
|
||||
MY_VER=11.1.3
|
||||
|
||||
Install_app()
|
||||
{
|
||||
mkdir -p ${mariadbDir}
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
|
||||
if id mysql &> /dev/null ;then
|
||||
echo "mysql uid is `id -u www`"
|
||||
echo "mysql shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
|
||||
else
|
||||
groupadd mysql
|
||||
useradd -g mysql mysql
|
||||
fi
|
||||
|
||||
if [ "$sysName" != "Darwin" ];then
|
||||
mkdir -p /var/log/mariadb
|
||||
touch /var/log/mariadb/mariadb.log
|
||||
fi
|
||||
|
||||
# ----- cpu start ------
|
||||
if [ -z "${cpuCore}" ]; then
|
||||
cpuCore="1"
|
||||
fi
|
||||
|
||||
if [ -f /proc/cpuinfo ];then
|
||||
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
|
||||
fi
|
||||
|
||||
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
|
||||
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
|
||||
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
|
||||
cpuCore="${MEM_INFO}"
|
||||
fi
|
||||
else
|
||||
cpuCore="1"
|
||||
fi
|
||||
|
||||
if [ "$cpuCore" -gt "2" ];then
|
||||
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
|
||||
else
|
||||
cpuCore="1"
|
||||
fi
|
||||
# ----- cpu end ------
|
||||
|
||||
# if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
|
||||
# wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://mirrors.aliyun.com/mariadb/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
|
||||
# fi
|
||||
|
||||
# https://downloads.mariadb.org/interstitial/mariadb-10.9.1/source/mariadb-10.9.1.tar.gz
|
||||
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
|
||||
wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://archive.mariadb.org/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
|
||||
fi
|
||||
|
||||
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
fi
|
||||
|
||||
INSTALL_CMD=cmake
|
||||
# check cmake version
|
||||
CMAKE_VERSION=`cmake -version | grep version | awk '{print $3}' | awk -F '.' '{print $1}'`
|
||||
if [ "$CMAKE_VERSION" -eq "2" ];then
|
||||
mkdir -p /var/log/mariadb
|
||||
touch /var/log/mariadb/mariadb.log
|
||||
INSTALL_CMD=cmake3
|
||||
fi
|
||||
|
||||
if [ ! -d $serverPath/mariadb ];then
|
||||
cd ${mariadbDir}/mariadb-${MY_VER} && ${INSTALL_CMD} \
|
||||
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
||||
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
||||
-DMYSQL_USER=mysql \
|
||||
-DMYSQL_UNIX_ADDR=$serverPath/mariadb/mysql.sock \
|
||||
-DWITH_MYISAM_STORAGE_ENGINE=1 \
|
||||
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
|
||||
-DWITH_MEMORY_STORAGE_ENGINE=1 \
|
||||
-DENABLED_LOCAL_INFILE=1 \
|
||||
-DWITH_PARTITION_STORAGE_ENGINE=1 \
|
||||
-DEXTRA_CHARSETS=all \
|
||||
-DDEFAULT_CHARSET=utf8mb4 \
|
||||
-DDEFAULT_COLLATION=utf8mb4_general_ci \
|
||||
-DCMAKE_C_COMPILER=/usr/bin/gcc \
|
||||
-DCMAKE_CXX_COMPILER=/usr/bin/g++
|
||||
make -j${cpuCore} && make install && make clean
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '11.1' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
{
|
||||
rm -rf $serverPath/mariadb
|
||||
echo '卸载完成' > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_app
|
||||
else
|
||||
Uninstall_app
|
||||
fi
|
||||
Executable
+129
@@ -0,0 +1,129 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
|
||||
#https://dev.mysql.com/downloads/file/?id=480541
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
sysName=`uname`
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mariadbDir=${serverPath}/source/mariadb
|
||||
|
||||
MY_VER=11.2.2
|
||||
|
||||
Install_app()
|
||||
{
|
||||
mkdir -p ${mariadbDir}
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
|
||||
if id mysql &> /dev/null ;then
|
||||
echo "mysql uid is `id -u www`"
|
||||
echo "mysql shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
|
||||
else
|
||||
groupadd mysql
|
||||
useradd -g mysql mysql
|
||||
fi
|
||||
|
||||
if [ "$sysName" != "Darwin" ];then
|
||||
mkdir -p /var/log/mariadb
|
||||
touch /var/log/mariadb/mariadb.log
|
||||
fi
|
||||
|
||||
# ----- cpu start ------
|
||||
if [ -z "${cpuCore}" ]; then
|
||||
cpuCore="1"
|
||||
fi
|
||||
|
||||
if [ -f /proc/cpuinfo ];then
|
||||
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
|
||||
fi
|
||||
|
||||
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
|
||||
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
|
||||
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
|
||||
cpuCore="${MEM_INFO}"
|
||||
fi
|
||||
else
|
||||
cpuCore="1"
|
||||
fi
|
||||
|
||||
if [ "$cpuCore" -gt "2" ];then
|
||||
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
|
||||
else
|
||||
cpuCore="1"
|
||||
fi
|
||||
# ----- cpu end ------
|
||||
|
||||
# if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
|
||||
# wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://mirrors.aliyun.com/mariadb/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
|
||||
# fi
|
||||
|
||||
# https://downloads.mariadb.org/interstitial/mariadb-10.9.1/source/mariadb-10.9.1.tar.gz
|
||||
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
|
||||
wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://archive.mariadb.org/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
|
||||
fi
|
||||
|
||||
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
fi
|
||||
|
||||
INSTALL_CMD=cmake
|
||||
# check cmake version
|
||||
CMAKE_VERSION=`cmake -version | grep version | awk '{print $3}' | awk -F '.' '{print $1}'`
|
||||
if [ "$CMAKE_VERSION" -eq "2" ];then
|
||||
mkdir -p /var/log/mariadb
|
||||
touch /var/log/mariadb/mariadb.log
|
||||
INSTALL_CMD=cmake3
|
||||
fi
|
||||
|
||||
if [ ! -d $serverPath/mariadb ];then
|
||||
cd ${mariadbDir}/mariadb-${MY_VER} && ${INSTALL_CMD} \
|
||||
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
||||
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
||||
-DMYSQL_USER=mysql \
|
||||
-DMYSQL_UNIX_ADDR=$serverPath/mariadb/mysql.sock \
|
||||
-DWITH_MYISAM_STORAGE_ENGINE=1 \
|
||||
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
|
||||
-DWITH_MEMORY_STORAGE_ENGINE=1 \
|
||||
-DENABLED_LOCAL_INFILE=1 \
|
||||
-DWITH_PARTITION_STORAGE_ENGINE=1 \
|
||||
-DEXTRA_CHARSETS=all \
|
||||
-DDEFAULT_CHARSET=utf8mb4 \
|
||||
-DDEFAULT_COLLATION=utf8mb4_general_ci \
|
||||
-DCMAKE_C_COMPILER=/usr/bin/gcc \
|
||||
-DCMAKE_CXX_COMPILER=/usr/bin/g++
|
||||
make -j${cpuCore} && make install && make clean
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '11.2' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
{
|
||||
rm -rf $serverPath/mariadb
|
||||
echo '卸载完成' > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_app
|
||||
else
|
||||
Uninstall_app
|
||||
fi
|
||||
Executable
+129
@@ -0,0 +1,129 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
|
||||
#https://dev.mysql.com/downloads/file/?id=480541
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
sysName=`uname`
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
mariadbDir=${serverPath}/source/mariadb
|
||||
|
||||
MY_VER=11.3.1
|
||||
|
||||
Install_app()
|
||||
{
|
||||
mkdir -p ${mariadbDir}
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
|
||||
if id mysql &> /dev/null ;then
|
||||
echo "mysql uid is `id -u www`"
|
||||
echo "mysql shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
|
||||
else
|
||||
groupadd mysql
|
||||
useradd -g mysql mysql
|
||||
fi
|
||||
|
||||
if [ "$sysName" != "Darwin" ];then
|
||||
mkdir -p /var/log/mariadb
|
||||
touch /var/log/mariadb/mariadb.log
|
||||
fi
|
||||
|
||||
# ----- cpu start ------
|
||||
if [ -z "${cpuCore}" ]; then
|
||||
cpuCore="1"
|
||||
fi
|
||||
|
||||
if [ -f /proc/cpuinfo ];then
|
||||
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
|
||||
fi
|
||||
|
||||
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
|
||||
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
|
||||
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
|
||||
cpuCore="${MEM_INFO}"
|
||||
fi
|
||||
else
|
||||
cpuCore="1"
|
||||
fi
|
||||
|
||||
if [ "$cpuCore" -gt "2" ];then
|
||||
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
|
||||
else
|
||||
cpuCore="1"
|
||||
fi
|
||||
# ----- cpu end ------
|
||||
|
||||
# if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
|
||||
# wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://mirrors.aliyun.com/mariadb/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
|
||||
# fi
|
||||
|
||||
# https://downloads.mariadb.org/interstitial/mariadb-10.9.1/source/mariadb-10.9.1.tar.gz
|
||||
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
|
||||
wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://archive.mariadb.org/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
|
||||
fi
|
||||
|
||||
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
|
||||
fi
|
||||
|
||||
INSTALL_CMD=cmake
|
||||
# check cmake version
|
||||
CMAKE_VERSION=`cmake -version | grep version | awk '{print $3}' | awk -F '.' '{print $1}'`
|
||||
if [ "$CMAKE_VERSION" -eq "2" ];then
|
||||
mkdir -p /var/log/mariadb
|
||||
touch /var/log/mariadb/mariadb.log
|
||||
INSTALL_CMD=cmake3
|
||||
fi
|
||||
|
||||
if [ ! -d $serverPath/mariadb ];then
|
||||
cd ${mariadbDir}/mariadb-${MY_VER} && ${INSTALL_CMD} \
|
||||
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
|
||||
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
|
||||
-DMYSQL_USER=mysql \
|
||||
-DMYSQL_UNIX_ADDR=$serverPath/mariadb/mysql.sock \
|
||||
-DWITH_MYISAM_STORAGE_ENGINE=1 \
|
||||
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
|
||||
-DWITH_MEMORY_STORAGE_ENGINE=1 \
|
||||
-DENABLED_LOCAL_INFILE=1 \
|
||||
-DWITH_PARTITION_STORAGE_ENGINE=1 \
|
||||
-DEXTRA_CHARSETS=all \
|
||||
-DDEFAULT_CHARSET=utf8mb4 \
|
||||
-DDEFAULT_COLLATION=utf8mb4_general_ci \
|
||||
-DCMAKE_C_COMPILER=/usr/bin/gcc \
|
||||
-DCMAKE_CXX_COMPILER=/usr/bin/g++
|
||||
make -j${cpuCore} && make install && make clean
|
||||
|
||||
if [ -d $serverPath/mariadb ];then
|
||||
echo '11.3' > $serverPath/mariadb/version.pl
|
||||
echo '安装完成'
|
||||
else
|
||||
echo '安装失败'
|
||||
echo 'install fail'>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
|
||||
rm -rf ${mariadbDir}/mariadb-${MY_VER}
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
Uninstall_app()
|
||||
{
|
||||
rm -rf $serverPath/mariadb
|
||||
echo '卸载完成' > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_app
|
||||
else
|
||||
Uninstall_app
|
||||
fi
|
||||
@@ -92,8 +92,10 @@ def checkArgs(data, ck=[]):
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps aux|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
|
||||
cmd = "ps aux|grep " + getPluginName() + " |grep -v grep | grep -v mdserver-web | awk '{print $2}'"
|
||||
# print(cmd)
|
||||
data = mw.execShell(cmd)
|
||||
# print(data)
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
return 'start'
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH=$PATH:/opt/homebrew/bin
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
@@ -9,8 +8,10 @@ rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
sys_os=`uname`
|
||||
VERSION=1.6.22
|
||||
|
||||
VERSION=1.6.15
|
||||
echo $sys_os
|
||||
|
||||
Install_mem(){
|
||||
mkdir -p $serverPath/source
|
||||
@@ -23,9 +24,18 @@ Install_mem(){
|
||||
|
||||
cd $serverPath/source && tar -zxvf memcached.tar.gz
|
||||
|
||||
|
||||
OPTIONS=''
|
||||
if [ ${sys_os} == "Darwin" ]; then
|
||||
LIB_DEPEND_DIR=`brew info libevent | grep /opt/homebrew/Cellar/libevent | cut -d \ -f 1 | awk 'END {print}'`
|
||||
OPTIONS="${OPTIONS} --with-libevent=${LIB_DEPEND_DIR}"
|
||||
fi
|
||||
|
||||
echo "./configure --prefix=${serverPath}/memcached && make && make install"
|
||||
cd $serverPath/source/memcached-${VERSION} && ./configure --prefix=$serverPath/memcached && make && make install
|
||||
cd $serverPath/source/memcached-${VERSION}
|
||||
./configure --prefix=$serverPath/memcached \
|
||||
$OPTIONS
|
||||
|
||||
make && make install
|
||||
|
||||
if [ -d $serverPath/memcached ];then
|
||||
echo '1.6' > $serverPath/memcached/version.pl
|
||||
@@ -33,6 +43,8 @@ Install_mem(){
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/memcached/index.py start
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/memcached/index.py initd_install
|
||||
|
||||
rm -rf $serverPath/source/memcached-${VERSION}
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -404,8 +404,8 @@ class classApi:
|
||||
write_log("|-正在解压文件到目录[{}]...".format(dpath))
|
||||
self.write_speed('done', '正在解压')
|
||||
|
||||
self.send('/files/unzip', {"sfile": zip_dst, "dfile": dpath,
|
||||
"type": "tar", "coding": "UTF-8", "password": "undefined"})
|
||||
self.send('/files/uncompress',
|
||||
{"sfile": zip_dst, "dfile": dpath, 'path': dpath})
|
||||
self.send('/files/exec_shell',
|
||||
{"shell": "rm -f " + zip_dst, "path": "/www"}, 30)
|
||||
return True
|
||||
|
||||
@@ -5,8 +5,13 @@ bind_ip = 127.0.0.1
|
||||
port = 27017
|
||||
fork = true
|
||||
auth = false
|
||||
#smallfiles = true
|
||||
|
||||
oplogSize=100
|
||||
|
||||
# Master/slave replication is no longer supported
|
||||
#master = true
|
||||
|
||||
#replSet = test
|
||||
|
||||
pidfilepath = {$SERVER_PATH}/mongodb/mongodb.pid
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
|
||||
<style>
|
||||
.overflow_hide {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bt-form">
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
@@ -5,19 +16,20 @@
|
||||
<p onclick="pluginInitD('mongodb');">自启动</p>
|
||||
<p onclick="pluginConfig('mongodb');">配置修改</p>
|
||||
<p onclick="mongoStatus();">负载状态</p>
|
||||
<p onclick="mongoDocStatus();">文档状态</p>
|
||||
<p onclick="mongoReplStatus();">复制状态</p>
|
||||
<p onclick="pluginLogs('mongodb','','run_log');">日志</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
<div class="soft-man-con" style="height:455px;overflow: auto;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
//mongodb start
|
||||
var loading = layer.msg("资源加载中...", { icon: 16, time: 0, shade: 0.3 });
|
||||
$.getScript( "/plugins/file?name=mongodb&f=js/mongodb.js", function(){
|
||||
layer.close(loading);
|
||||
pluginService('mongodb')
|
||||
resetPluginWinHeight(530);
|
||||
$.getScript('/plugins/file?name=mongodb&f=js/mongodb.js', function(){
|
||||
pluginService('mongodb');
|
||||
});
|
||||
//mongodb end
|
||||
</script>
|
||||
+138
-15
@@ -4,6 +4,9 @@ import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
import datetime
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
@@ -49,6 +52,13 @@ def getInitDTpl():
|
||||
return path
|
||||
|
||||
|
||||
def getConfPort():
|
||||
file = getConf()
|
||||
content = mw.readFile(file)
|
||||
rep = 'port\s*=\s*(.*)'
|
||||
tmp = re.search(rep, content)
|
||||
return tmp.groups()[0].strip()
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
@@ -68,7 +78,7 @@ def getArgs():
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps -ef|grep mongod |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
|
||||
"ps -ef|grep mongod |grep -v grep | grep -v /Applications | grep -v python | grep -v mdserver-web | awk '{print $2}'")
|
||||
|
||||
if data[0] == '':
|
||||
return 'stop'
|
||||
@@ -93,6 +103,11 @@ def initDreplace():
|
||||
if not os.path.exists(data_dir):
|
||||
os.mkdir(data_dir)
|
||||
|
||||
install_ok = getServerDir() + "/install.lock"
|
||||
if os.path.exists(install_ok):
|
||||
return file_bin
|
||||
mw.writeFile(install_ok, 'ok')
|
||||
|
||||
# initd replace
|
||||
content = mw.readFile(file_tpl)
|
||||
content = content.replace('{$SERVER_PATH}', service_path)
|
||||
@@ -122,6 +137,7 @@ def mgOp(method):
|
||||
file = initDreplace()
|
||||
if mw.isAppleSystem():
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
# print(data)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
@@ -133,6 +149,8 @@ def mgOp(method):
|
||||
|
||||
|
||||
def start():
|
||||
mw.execShell(
|
||||
'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/www/server/lib/openssl11/lib')
|
||||
return mgOp('start')
|
||||
|
||||
|
||||
@@ -153,35 +171,134 @@ def restart():
|
||||
|
||||
def runInfo():
|
||||
import pymongo
|
||||
client = pymongo.MongoClient(host='127.0.0.1', port=27017)
|
||||
|
||||
port = getConfPort()
|
||||
client = pymongo.MongoClient(host='127.0.0.1', port=int(port))
|
||||
db = client.admin
|
||||
serverStatus = db.command('serverStatus')
|
||||
|
||||
listDbs = client.list_database_names()
|
||||
|
||||
result = {}
|
||||
result["host"] = serverStatus['host']
|
||||
result["version"] = serverStatus['version']
|
||||
result["uptime"] = serverStatus['uptime']
|
||||
result['db_path'] = getServerDir() + "/data"
|
||||
result["connections"] = serverStatus['connections']['current']
|
||||
result["collections"] = len(listDbs)
|
||||
|
||||
pf = serverStatus['opcounters']
|
||||
result['pf'] = pf
|
||||
|
||||
return mw.getJson(result)
|
||||
|
||||
|
||||
def runDocInfo():
|
||||
import pymongo
|
||||
|
||||
port = getConfPort()
|
||||
client = pymongo.MongoClient(host='127.0.0.1', port=int(port))
|
||||
db = client.admin
|
||||
serverStatus = db.command('serverStatus')
|
||||
|
||||
listDbs = client.list_database_names()
|
||||
showDbList = []
|
||||
result = {}
|
||||
for x in range(len(listDbs)):
|
||||
mongd = client[listDbs[x]]
|
||||
stats = mongd.command({"dbstats": 1})
|
||||
if 'operationTime' in stats:
|
||||
del stats['operationTime']
|
||||
|
||||
if '$clusterTime' in stats:
|
||||
del stats['$clusterTime']
|
||||
showDbList.append(stats)
|
||||
# print(showDbList)
|
||||
# print(serverStatus)
|
||||
# for key, value in serverStatus.items():
|
||||
# print(key, value)
|
||||
result = {}
|
||||
result["version"] = serverStatus['version']
|
||||
result["uptime"] = serverStatus['uptime']
|
||||
|
||||
result['db_path'] = getServerDir() + "/data"
|
||||
|
||||
result["connections"] = serverStatus['connections']['current']
|
||||
if 'catalogStats' in serverStatus:
|
||||
result["collections"] = serverStatus['catalogStats']['collections']
|
||||
|
||||
result["dbs"] = showDbList
|
||||
return mw.getJson(result)
|
||||
|
||||
|
||||
def runReplInfo():
|
||||
import pymongo
|
||||
|
||||
port = getConfPort()
|
||||
client = pymongo.MongoClient(host='127.0.0.1', port=int(port))
|
||||
db = client.admin
|
||||
serverStatus = db.command('serverStatus')
|
||||
|
||||
result = {}
|
||||
result['status'] = '无'
|
||||
result['doc_name'] = '无'
|
||||
if 'repl' in serverStatus:
|
||||
repl = serverStatus['repl']
|
||||
# print(repl)
|
||||
if 'ismaster' in repl and repl['ismaster']:
|
||||
result['status'] = '主'
|
||||
else:
|
||||
result['status'] = '从'
|
||||
|
||||
result['setName'] = repl['setName']
|
||||
result['primary'] = repl['primary']
|
||||
result['me'] = repl['me']
|
||||
|
||||
hosts = repl['hosts']
|
||||
result['hosts'] = ','.join(hosts)
|
||||
|
||||
|
||||
return mw.returnJson(True, 'OK', result)
|
||||
|
||||
def test():
|
||||
# https://pymongo.readthedocs.io/en/stable/examples/high_availability.html
|
||||
import pymongo
|
||||
from pymongo import ReadPreference
|
||||
|
||||
port = getConfPort()
|
||||
client = pymongo.MongoClient(host='127.0.0.1', port=int(port))
|
||||
db = client.admin
|
||||
|
||||
# config = {
|
||||
# '_id': 'test',
|
||||
# 'members': [
|
||||
# {'_id': 1, 'host': '127.0.0.1:27018','priority': 10 },
|
||||
# {'_id': 2, 'host': '127.0.0.1:27019','priority': 1 },
|
||||
# {'_id': 3, 'host': '127.0.0.1:27020','priority': 0 },
|
||||
# # {'_id': 2, 'host': 'localhost:27019'}
|
||||
# ]
|
||||
# }
|
||||
|
||||
# rsStatus = client.admin.command("replSetInitiate", config)
|
||||
|
||||
# 需要通过命令行操作
|
||||
# -> rs.initiate({
|
||||
# _id: 'test',
|
||||
# members: [{
|
||||
# _id: 1,
|
||||
# host: '127.0.0.1:27018',
|
||||
# priority: 2 // 这个priority不设置为1,值越高,当主库故障的时候会优先被选举成主库
|
||||
# }, {
|
||||
# _id: 2,
|
||||
# host: '127.0.0.1:27019',
|
||||
# priority: 0 //设置为0则不能成为主库
|
||||
# }, {
|
||||
# _id: 3,
|
||||
# host: '127.0.0.1:27020',
|
||||
# priority: 1
|
||||
# }]
|
||||
# });
|
||||
|
||||
# > rs.status(); // 查询状态
|
||||
# // "stateStr" : "PRIMARY", 主节点
|
||||
# // "stateStr" : "SECONDARY", 副本节点
|
||||
|
||||
# > rs.add({"_id":3, "host":"127.0.0.1:27318","priority":0,"votes":0});
|
||||
|
||||
|
||||
serverStatus = db.command('serverStatus')
|
||||
print(serverStatus)
|
||||
|
||||
# return mw.returnJson(True, 'OK', result)
|
||||
|
||||
|
||||
def initdStatus():
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
@@ -264,9 +381,15 @@ if __name__ == "__main__":
|
||||
print(initdUinstall())
|
||||
elif func == 'run_info':
|
||||
print(runInfo())
|
||||
elif func == 'run_doc_info':
|
||||
print(runDocInfo())
|
||||
elif func == 'run_repl_info':
|
||||
print(runReplInfo())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'run_log':
|
||||
print(runLog())
|
||||
elif func == 'test':
|
||||
print(test())
|
||||
else:
|
||||
print('error')
|
||||
|
||||
@@ -9,6 +9,7 @@ User=root
|
||||
Group=root
|
||||
#EnvironmentFile=-/etc/default/mongod
|
||||
Environment="MONGODB_CONFIG_OVERRIDE_NOFORK=1"
|
||||
Environment="LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib64:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/www/server/lib/openssl11/lib"
|
||||
PIDFile={$SERVER_PATH}/mongodb/mongodb.pid
|
||||
ExecStart={$SERVER_PATH}/mongodb/bin/mongod -f {$SERVER_PATH}/mongodb/mongodb.conf
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
# https://www.mongodb.com/try/download/community
|
||||
|
||||
'''
|
||||
cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 5.0.4
|
||||
cd /www/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 7.0
|
||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 5.0.4
|
||||
# cd /www/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 7.0
|
||||
# cd /www/server/mdserver-web && python3 /www/server/mdserver-web/plugins/mongodb/index.py start
|
||||
|
||||
cd /www/server/mdserver-web && python3 /www/server/mdserver-web/plugins/mongodb/index.py start
|
||||
'''
|
||||
|
||||
|
||||
curPath=`pwd`
|
||||
@@ -58,6 +56,8 @@ Install_app()
|
||||
# OSNAME=rhel
|
||||
# fi
|
||||
|
||||
cd ${rootPath}/plugins/php/lib && /bin/bash openssl_11.sh
|
||||
|
||||
shell_file=${curPath}/versions/${VERSION}/${OSNAME}.sh
|
||||
|
||||
if [ -f $shell_file ];then
|
||||
@@ -70,7 +70,7 @@ Install_app()
|
||||
if [ "$?" == "0" ];then
|
||||
mkdir -p $serverPath/mongodb
|
||||
echo "${VERSION}" > $serverPath/mongodb/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
echo 'mongodb安装完成'
|
||||
|
||||
#初始化
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/mongodb/index.py start
|
||||
@@ -92,7 +92,7 @@ Uninstall_app()
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
|
||||
echo "Uninstall_mongodb" > $install_tmp
|
||||
echo 'mongodb卸载完成'
|
||||
}
|
||||
|
||||
action=$1
|
||||
|
||||
@@ -8,18 +8,40 @@ function mongoStatus() {
|
||||
}
|
||||
|
||||
var rdata = $.parseJSON(data.data);
|
||||
hit = (parseInt(rdata.keyspace_hits) / (parseInt(rdata.keyspace_hits) + parseInt(rdata.keyspace_misses)) * 100).toFixed(2);
|
||||
var Con = '<div class="divtable">\
|
||||
var con = '<div class="divtable">\
|
||||
<table class="table table-hover table-bordered" style="width: 490px;">\
|
||||
<thead><th>字段</th><th>当前值</th><th>说明</th></thead>\
|
||||
<tbody>\
|
||||
<tr><th>host</th><td>' + rdata.host + '</td><td>服务器</td></tr>\
|
||||
<tr><th>version</th><td>' + rdata.version + '</td><td>版本</td></tr>\
|
||||
<tr><th>db_path</th><td>' + rdata.db_path + '</td><td>数据路径</td></tr>\
|
||||
<tr><th>uptime</th><td>' + rdata.uptime + '</td><td>已运行秒</td></tr>\
|
||||
<tr><th>connections</th><td>' + rdata.connections + '</td><td>当前链接数</td></tr>\
|
||||
<tr><th>collections</th><td>' + rdata.collections + '</td><td>文档数</td></tr>\
|
||||
<tr><th>insert</th><td>' + rdata.pf['insert'] + '</td><td>插入命令数</td></tr>\
|
||||
<tr><th>query</th><td>' + rdata.pf['query'] + '</td><td>查询命令数</td></tr>\
|
||||
<tr><th>update</th><td>' + rdata.pf['update'] + '</td><td>更新命令数</td></tr>\
|
||||
<tr><th>delete</th><td>' + rdata.pf['delete'] + '</td><td>删除命令数</td></tr>\
|
||||
<tr><th>getmore</th><td>' + rdata.pf['getmore'] + '</td><td>getmore命令数</td></tr>\
|
||||
<tr><th>command</th><td>' + rdata.pf['command'] + '</td><td>执行命令数</td></tr>\
|
||||
<tbody>\
|
||||
</table></div><hr/>';
|
||||
</table></div>';
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
},'json');
|
||||
}
|
||||
|
||||
|
||||
function mongoDocStatus() {
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
$.post('/plugins/run', {name:'mongodb', func:'run_doc_info'}, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
var rdata = $.parseJSON(data.data);
|
||||
|
||||
var t = '';
|
||||
for(var i=0; i<rdata.dbs.length;i++){
|
||||
@@ -35,13 +57,54 @@ function mongoStatus() {
|
||||
}
|
||||
// console.log(t);
|
||||
|
||||
Con += '<div class="divtable">\
|
||||
var con = '<div class="divtable">\
|
||||
<table class="table table-hover table-bordered" style="width: 490px;">\
|
||||
<thead><th>库名</th><th>大小</th><th>存储大小</th><th>数据</th><th>索引</th><th>文档数据</th><th>对象</th></thead>\
|
||||
<tbody>'+t+'<tbody>\
|
||||
</table></div>';
|
||||
// console.log(rdata.dbs);
|
||||
|
||||
$(".soft-man-con").html(Con);
|
||||
$(".soft-man-con").html(con);
|
||||
},'json');
|
||||
}
|
||||
}
|
||||
|
||||
function mongoReplStatus() {
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
$.post('/plugins/run', {name:'mongodb', func:'run_repl_info'}, function(data) {
|
||||
layer.close(loadT);
|
||||
if (!data.status){
|
||||
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
|
||||
return;
|
||||
}
|
||||
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var rdata = rdata.data;
|
||||
|
||||
var tbody = '';
|
||||
if (rdata.status == '无'){
|
||||
tbody += '<tr><td colspan="3" style="text-align:center;">无数据</td></tr>';
|
||||
} else{
|
||||
tbody += '<tr><th>状态</th><td>' + rdata.status + '</td><td>主/从</td></tr>\
|
||||
<tr><th>同步文档</th><td>' + rdata.setName + '</td><td>文档名</td></tr>\
|
||||
<tr><th>hosts</th><td><span class="overflow_hide" style="width:260px;" title="'+rdata.hosts+'">' + rdata.hosts + '</span></td><td>服务器所有节点</td></tr>\
|
||||
<tr><th>primary</th><td>' + rdata.primary + '</td><td>primary</td></tr>\
|
||||
<tr><th>me</th><td>' + rdata.me + '</td><td>me</td></tr>';
|
||||
}
|
||||
|
||||
var con = '<div class="divtable">\
|
||||
<table class="table table-hover table-bordered" style="width: 490px;">\
|
||||
<thead><th>字段</th><th>当前值</th><th>说明</th></thead>\
|
||||
<tbody>\
|
||||
'+tbody+'\
|
||||
<tbody>\
|
||||
</table>\
|
||||
</div>';
|
||||
|
||||
$(".soft-man-con").html(con);
|
||||
},'json');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
@@ -63,4 +64,6 @@ fi
|
||||
if [ ! -d $serverPath/mongodb/bin ];then
|
||||
mkdir -p $serverPath/mongodb
|
||||
cd $MG_DIR/${FILE_NAME} && cp -rf ./bin $serverPath/mongodb
|
||||
fi
|
||||
fi
|
||||
|
||||
cd ${MG_DIR} && rm -rf ${MG_DIR}/${FILE_NAME}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user