mirror of
https://github.com/midoks/mdserver-web.git
synced 2026-10-10 07:09:25 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
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 | ||
|
|
b6f7334f5e | ||
|
|
27b77f8570 | ||
|
|
3d888961bc | ||
|
|
5edc4fb713 | ||
|
|
214954b298 | ||
|
|
13b0b2752e | ||
|
|
a2918e651f | ||
|
|
55dd1d7d5a | ||
|
|
df50eceeed | ||
|
|
e1de6dd514 | ||
|
|
08328bbb86 | ||
|
|
6abc5b365b | ||
|
|
6cc1279729 | ||
|
|
aeafaa2832 | ||
|
|
e74a511763 | ||
|
|
f86159eeac | ||
|
|
8097164475 | ||
|
|
4ebb44e4c0 | ||
|
|
584f93461a | ||
|
|
e21f0a53e5 | ||
|
|
1d31a0eae0 | ||
|
|
ded33ed6b4 | ||
|
|
b703758d0e | ||
|
|
33493ac03c | ||
|
|
74e63c5bbd | ||
|
|
f2d34e5551 | ||
|
|
89c529f44c | ||
|
|
56b728601b | ||
|
|
bf1d2daeaa | ||
|
|
cac45b3732 | ||
|
|
ee498b7094 | ||
|
|
385113fe4d | ||
|
|
5dbfc5bd51 | ||
|
|
b76e0f606a | ||
|
|
047702f26d | ||
|
|
eb219caada | ||
|
|
78b2046f19 | ||
|
|
5fe85730e6 | ||
|
|
adb72ef33b | ||
|
|
d9c8a46031 | ||
|
|
24f520bdc9 | ||
|
|
7492756997 | ||
|
|
616af16635 | ||
|
|
916d39e205 | ||
|
|
017958b6b0 | ||
|
|
d403c4c4ad | ||
|
|
9f1481db07 | ||
|
|
47e0ec5fae | ||
|
|
a2377d960e | ||
|
|
60f1ce2575 | ||
|
|
0e368f7157 | ||
|
|
3cf5c5b190 | ||
|
|
4ed07beca3 | ||
|
|
cee9619883 | ||
|
|
5db4a96fc9 | ||
|
|
2e6b7bf5cd | ||
|
|
f404caa763 | ||
|
|
062a518492 | ||
|
|
0310cab3ae | ||
|
|
4a0b8df57f | ||
|
|
63e427b488 | ||
|
|
c688c692f9 | ||
|
|
c9f074b319 | ||
|
|
38b4042c5a | ||
|
|
bf32390f0e | ||
|
|
91a9be4cc0 | ||
|
|
be5f438f84 | ||
|
|
2705fd7ba2 | ||
|
|
4de7e72f0a | ||
|
|
da668c723c | ||
|
|
20624217bf | ||
|
|
2403af08c6 | ||
|
|
2350b73896 | ||
|
|
464fa9cc0f | ||
|
|
9a79f0b728 | ||
|
|
52cfff7038 | ||
|
|
8d42f8137c | ||
|
|
41fb9759a3 | ||
|
|
7d3833b2ef | ||
|
|
0badb053e0 | ||
|
|
80b9e7cbf7 | ||
|
|
94df21192f | ||
|
|
346d687368 | ||
|
|
46ec655365 | ||
|
|
e852020c38 | ||
|
|
d06e83676b | ||
|
|
7a511f8217 | ||
|
|
8c5021b9dc | ||
|
|
b7d50540ac | ||
|
|
2a95fcc59a | ||
|
|
2b04cb3947 | ||
|
|
7f0ad25342 | ||
|
|
09f7e6f5b5 | ||
|
|
17a7ffa0b4 | ||
|
|
ba6dcabd04 | ||
|
|
0ff5c170d3 | ||
|
|
b78e020993 | ||
|
|
9586eeda07 | ||
|
|
ea462aa51d | ||
|
|
aaac8b5239 | ||
|
|
2b86c375b0 | ||
|
|
600e2688f9 | ||
|
|
3537bc520f | ||
|
|
9ffdffadd6 | ||
|
|
3942f2fbf5 | ||
|
|
8ff2f217b3 | ||
|
|
480bd154c6 | ||
|
|
5eb3ed4524 | ||
|
|
50e78ae6f6 | ||
|
|
0ec9b31c2f | ||
|
|
191b54821e | ||
|
|
c2188a2c7e | ||
|
|
d23b64a92c | ||
|
|
3ae97e1c75 | ||
|
|
f0e7361436 | ||
|
|
5f85d41352 | ||
|
|
6fc8803446 | ||
|
|
b3120f3435 | ||
|
|
f9f1b1a113 | ||
|
|
2645297cee | ||
|
|
7f171f5986 | ||
|
|
c3b3e3b01c | ||
|
|
3824b394ad | ||
|
|
270660fb53 | ||
|
|
c4171a9506 | ||
|
|
222943e312 | ||
|
|
92f8a4e949 | ||
|
|
eff1f55a21 | ||
|
|
0b54da9747 | ||
|
|
0bec57937f | ||
|
|
6c64f8ee5e | ||
|
|
b65ad9de80 | ||
|
|
07be263d81 | ||
|
|
bf9cb52fec | ||
|
|
f7135a6ded | ||
|
|
7b98dde1aa | ||
|
|
b51f3fdd68 | ||
|
|
e02c52df49 | ||
|
|
730bc7171b | ||
|
|
c065eabb48 | ||
|
|
1ad1e3326d | ||
|
|
d4346a51bc | ||
|
|
8260cc5f4a | ||
|
|
021b299b7d | ||
|
|
a767e7e578 | ||
|
|
57da2aef27 | ||
|
|
5b43438cb1 | ||
|
|
7ab88a1bea | ||
|
|
31291a13c7 | ||
|
|
43d0b75d98 | ||
|
|
5490197b8a | ||
|
|
8f03574bce | ||
|
|
94487e0b3d | ||
|
|
45cc0159af | ||
|
|
504a618eb1 | ||
|
|
5e25849464 | ||
|
|
9bb59a1559 | ||
|
|
6883316efc | ||
|
|
de7ea503e5 | ||
|
|
4fcad95c79 | ||
|
|
75dc1bd70d | ||
|
|
44758e3e55 | ||
|
|
140624e62f | ||
|
|
65f90b473c | ||
|
|
0a089fcedf | ||
|
|
010624023f | ||
|
|
9399a14a92 | ||
|
|
2875b40e62 | ||
|
|
78c3686091 | ||
|
|
d7447197ec | ||
|
|
9b64ec5c6d | ||
|
|
dad51dad77 | ||
|
|
d89751f733 | ||
|
|
1dc486711b | ||
|
|
60a2f85f02 | ||
|
|
830d387ddb | ||
|
|
ae225780f9 | ||
|
|
e0a0a82d68 | ||
|
|
0b23c5f330 | ||
|
|
fb01c68f5a | ||
|
|
5755121fa5 | ||
|
|
3d1c613864 | ||
|
|
9590c4bb7d | ||
|
|
32c0bdf093 | ||
|
|
4f5424a746 | ||
|
|
81ba3bce9d | ||
|
|
22b3a1bc42 | ||
|
|
df9a34aa31 | ||
|
|
2400213533 | ||
|
|
465eb118a9 | ||
|
|
7e81aa109f | ||
|
|
b23b41c7a7 | ||
|
|
724a77ae81 | ||
|
|
3499ed74ee | ||
|
|
52997049e2 | ||
|
|
a96a36b087 | ||
|
|
5926f688a6 | ||
|
|
1b754f5c43 | ||
|
|
c4c20de520 | ||
|
|
616895785f | ||
|
|
29d6c8740a | ||
|
|
64aa9a9d01 | ||
|
|
ffbe8ba6d4 | ||
|
|
ed39c5d243 | ||
|
|
4bb2115040 | ||
|
|
6b0cf8129d | ||
|
|
ab7bbe942b | ||
|
|
a8a3fa1754 | ||
|
|
e343f33b47 | ||
|
|
f55367ab5e | ||
|
|
050bd158c1 | ||
|
|
d35a680fec | ||
|
|
4a4ddeaabe | ||
|
|
0e74b0cccf | ||
|
|
806e29577e | ||
|
|
75923f5363 | ||
|
|
834196883c | ||
|
|
341826c641 | ||
|
|
1bd1ce5b31 | ||
|
|
eef504e172 | ||
|
|
a0434ef7d6 | ||
|
|
893bbb8ea7 | ||
|
|
92e3e277cc | ||
|
|
58e48bf013 | ||
|
|
644760d5b0 | ||
|
|
d6ccd81def | ||
|
|
d32e71b2d9 | ||
|
|
ae9e56c56c | ||
|
|
d7c0285bbf | ||
|
|
5cc0957ffd | ||
|
|
1e44d64ace | ||
|
|
907851c413 | ||
|
|
0faafc654b | ||
|
|
4cdc399b77 | ||
|
|
a085e5b1ea | ||
|
|
bdbf4dddc6 | ||
|
|
5cee2f2b6d | ||
|
|
b9652a7940 | ||
|
|
dc7ddbcf6b | ||
|
|
87a8bfe59e | ||
|
|
cfdd5e5f73 | ||
|
|
e2acf621ca | ||
|
|
0711a922d2 | ||
|
|
055ea0ca0c | ||
|
|
772d9c50f6 | ||
|
|
0809b51725 | ||
|
|
4e901e6750 | ||
|
|
5c62397234 | ||
|
|
63021a3eab | ||
|
|
e617b07790 | ||
|
|
960eeed4ce | ||
|
|
ccf020bf6b | ||
|
|
c4918d8cd7 | ||
|
|
b3d3ceb058 | ||
|
|
17a301c745 | ||
|
|
1bfa2ae3ab | ||
|
|
9be5dcfd8a | ||
|
|
d9e8f1d4ad | ||
|
|
d85f544773 | ||
|
|
577ac1f8ee | ||
|
|
ed117a1b40 | ||
|
|
9d54f0b6cd | ||
|
|
707eced7bf | ||
|
|
dd96833c09 | ||
|
|
4c61143918 | ||
|
|
8cb8a1bc70 | ||
|
|
c55c3c23d1 | ||
|
|
04e6b9367a | ||
|
|
f4f25b8ab3 | ||
|
|
a0b0b9b294 | ||
|
|
699ad0b8ca | ||
|
|
a45eaf1c3b | ||
|
|
0f51a6d481 | ||
|
|
142d5f7ed8 | ||
|
|
72bd528a24 | ||
|
|
af2dc0585b | ||
|
|
0a0021b09d | ||
|
|
c5811d4494 | ||
|
|
e329892cd2 | ||
|
|
368324a813 | ||
|
|
6a7cc4f054 | ||
|
|
1d3cba599c | ||
|
|
7d902a50eb | ||
|
|
25feb7c0ad | ||
|
|
e15d1716e5 | ||
|
|
ee16e0142e | ||
|
|
68e06aa8f5 | ||
|
|
d88003ca52 | ||
|
|
8757c646f6 | ||
|
|
c3e9d8aa4c | ||
|
|
7e3983f612 | ||
|
|
a4e43b492d | ||
|
|
1f57517ea7 | ||
|
|
b2fe35771d | ||
|
|
00ce3e00d3 | ||
|
|
c7c28731a4 | ||
|
|
3305eab770 | ||
|
|
b595359f38 | ||
|
|
5dc06b90ca | ||
|
|
651fa7672c | ||
|
|
7a0db5abef | ||
|
|
d21a5dfacc | ||
|
|
0c49749b63 | ||
|
|
11bb65a739 | ||
|
|
ce44353cbf | ||
|
|
2e5c5ef5b9 | ||
|
|
d1b687476b | ||
|
|
a46eabce10 | ||
|
|
08e378a3e4 | ||
|
|
c80ce63a4b | ||
|
|
72bb94df42 | ||
|
|
e9b7aca47a | ||
|
|
f25d4f5a4f | ||
|
|
59fcef76fe | ||
|
|
4ab6ccbcbb | ||
|
|
fd457df3c8 | ||
|
|
147bec02a5 | ||
|
|
34c126fbb7 | ||
|
|
4d21c920a8 | ||
|
|
2d810fe7ab | ||
|
|
fb5260b9a5 | ||
|
|
32b5542534 | ||
|
|
c665486122 | ||
|
|
d3b885b1f9 | ||
|
|
e476e36420 | ||
|
|
587503dc67 | ||
|
|
cecfe9470f | ||
|
|
abc37acacc | ||
|
|
e0197fef3a | ||
|
|
04c4e7ddc8 | ||
|
|
6fb3e29a91 | ||
|
|
66fe66b479 | ||
|
|
4329d2470c | ||
|
|
0cd4527234 | ||
|
|
bdba9149f2 | ||
|
|
e05f7a9c3f | ||
|
|
bddd81c94d | ||
|
|
f470392382 | ||
|
|
895a250f06 | ||
|
|
dd579b7e5c | ||
|
|
cd0653d092 | ||
|
|
f2bc938ade | ||
|
|
dc694cae35 | ||
|
|
0b98e40fec | ||
|
|
10c40800ff | ||
|
|
424d9fa799 | ||
|
|
1350fc7a4a | ||
|
|
d678ade262 | ||
|
|
0b0b0bc9c5 | ||
|
|
f3eee40e1e | ||
|
|
8e0327a084 | ||
|
|
0a4b5529b9 | ||
|
|
a8c17e1f3c | ||
|
|
4d242dd322 | ||
|
|
272a08f4eb | ||
|
|
453009da40 | ||
|
|
9c8880e1bb | ||
|
|
4f716830ef | ||
|
|
b4d799f8bd | ||
|
|
e9fc7d5344 | ||
|
|
585d3d1839 | ||
|
|
3278dd23b5 | ||
|
|
5b406eaeb1 | ||
|
|
0a354f649d | ||
|
|
176dd4a5b8 | ||
|
|
4bb9cc2d67 | ||
|
|
f1edb26540 | ||
|
|
0692537cbd | ||
|
|
0710ca590a | ||
|
|
c19b12e8df | ||
|
|
99eeee19ef | ||
|
|
fff3707031 | ||
|
|
0d0cb4add1 | ||
|
|
5ed37443da | ||
|
|
25b836e6f5 | ||
|
|
4ca5c8e1a8 | ||
|
|
b522287a87 | ||
|
|
05cec7e0bf | ||
|
|
b731868e06 | ||
|
|
9c4ceca41f | ||
|
|
22d266e710 | ||
|
|
d35bf118ff | ||
|
|
1adb2f751c | ||
|
|
54e743037e | ||
|
|
6debb93fd1 | ||
|
|
7229f9c569 | ||
|
|
844dcbda00 | ||
|
|
af2b45a6f4 | ||
|
|
d848d41a71 | ||
|
|
826ebfb2e5 | ||
|
|
e1807c1585 | ||
|
|
6e9d5a19c0 | ||
|
|
6eadad5db4 | ||
|
|
2b2fc08120 | ||
|
|
175061884d | ||
|
|
cc3fa8ac95 | ||
|
|
c9d736e338 | ||
|
|
e4437e42f3 | ||
|
|
644fc2c81f | ||
|
|
d2314bf26f |
+3
-4
@@ -110,7 +110,6 @@ tmp/*
|
||||
*.zip
|
||||
logs/*
|
||||
data/*.db
|
||||
data/control.conf
|
||||
data/iplist.txt
|
||||
data/json/index.json
|
||||
data/json/config.json
|
||||
@@ -159,11 +158,11 @@ data/unauthorized_status.pl
|
||||
plugins/vip_*
|
||||
plugins/own_*
|
||||
plugins/my_*
|
||||
plugins/op_auth
|
||||
plugins/l2tp
|
||||
plugins/openlitespeed
|
||||
plugins/tamper_proof
|
||||
plugins/cryptocurrency_trade
|
||||
plugins/gdrive
|
||||
plugins/mtproxy
|
||||
plugins/zimg
|
||||
plugins/bk_demo
|
||||
@@ -177,5 +176,5 @@ debug.out
|
||||
|
||||
|
||||
|
||||
mdioks.session-journal
|
||||
*.session
|
||||
mdioks.session-journal
|
||||
*.session
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
简单的Linux面板,感谢BT.CN写出如此好的web管理软件。我一看到,就知道这是我一直想要的页面化管理方式。
|
||||
复制了后台管理界面,按照自己想要的方式写了一版。
|
||||
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
@@ -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
|
||||
|
||||
@@ -77,6 +81,13 @@ PHP[53-72]支持phpMyAdmin[4.4.15]
|
||||
PHP[72-82]支持phpMyAdmin[5.2.0]
|
||||
```
|
||||
|
||||
# 郑重声明
|
||||
|
||||
不卖、不会监控(统计使用除外)、更不会注入病毒,大家使用方便(望大家不吝捐赠)。
|
||||
|
||||
- https://www.youtube.com/watch?v=2taa5K-Jmmw
|
||||
|
||||
|
||||
# 特别赞助
|
||||
|
||||
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.pw/)
|
||||
@@ -99,15 +110,18 @@ docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:
|
||||
```
|
||||
|
||||
|
||||
### 版本更新 0.15.2
|
||||
### 版本更新 0.16.2
|
||||
|
||||
* OpenResty升级到1.21.4.2
|
||||
* 计划任务自动脚本运行时间
|
||||
* rsyncd添加优化
|
||||
* 使用mariadb二进制导入备份文件
|
||||
* docker插件-镜像导入导出功能
|
||||
* 网站设置反向代理升级功能
|
||||
* 优化初始化安装SSH端口识别
|
||||
* keepalived插件改造,集成mysql高可用配置。
|
||||
* redis(主从/集群)配置识别。
|
||||
* MySQL主从同步1236错误,添加修复功能。
|
||||
* MySQL二进制日志查看。
|
||||
* 源码安装成功后删除解压包,节省体积。
|
||||
* 网站统计-增加查询条件。
|
||||
* php增加yaml扩展。
|
||||
* php扩展ioncube修复。
|
||||
* php-fpm增加【按需】配置。
|
||||
* gitea/gogs同步功能改造。
|
||||
|
||||
### JSDelivr安装地址
|
||||
|
||||
@@ -166,6 +180,8 @@ curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_dev.sh | bash
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash
|
||||
|
||||
wget --no-check-certificate -O install.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install.sh && bash install.sh
|
||||
|
||||
wget --no-check-certificate -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/uninstall.sh && bash uninstall.sh
|
||||
|
||||
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh | bash
|
||||
|
||||
+17
-8
@@ -123,6 +123,11 @@ class cert_api:
|
||||
return True
|
||||
|
||||
def createCertCron(self):
|
||||
|
||||
if mw.isAppleSystem():
|
||||
print('在Macos上不支持创建证书自动续签任务!')
|
||||
return ''
|
||||
|
||||
# 创建证书自动续签任务
|
||||
try:
|
||||
import crontab_api
|
||||
@@ -1496,8 +1501,9 @@ fullchain.pem 粘贴到证书输入框
|
||||
'cert_timeout'] = int(time.time())
|
||||
|
||||
if self.__config['orders'][i]['cert_timeout'] > start_time:
|
||||
writeLog(
|
||||
"|-本次跳过域名: {},未过期!".format(self.__config['orders'][i]['domains'][0]))
|
||||
msg = "|-本次跳过域名: {},未过期!".format(
|
||||
self.__config['orders'][i]['domains'][0])
|
||||
writeLog(msg)
|
||||
continue
|
||||
|
||||
# 已删除的网站直接跳过续签
|
||||
@@ -1514,8 +1520,9 @@ fullchain.pem 粘贴到证书输入框
|
||||
break
|
||||
if not mw.M('domain').where("name=?", (domain,)).count() and not mw.M('binding').where("domain=?", domain).count():
|
||||
auth_to = None
|
||||
writeLog(
|
||||
"|-跳过被删除的域名: {}".format(self.__config['orders'][i]['domains']))
|
||||
msg = "|-跳过被删除的域名: {}".format(
|
||||
self.__config['orders'][i]['domains'])
|
||||
writeLog(msg)
|
||||
if not auth_to:
|
||||
continue
|
||||
|
||||
@@ -1526,15 +1533,17 @@ fullchain.pem 粘贴到证书输入框
|
||||
timeout = self.__config['orders'][i][
|
||||
'next_retry_time'] - int(time.time())
|
||||
if timeout > 0:
|
||||
writeLog('|-本次跳过域名:{},因第上次续签失败,还需要等待{}小时后再重试'.format(
|
||||
self.__config['orders'][i]['domains'], int(timeout / 60 / 60)))
|
||||
msg = '|-本次跳过域名:{},因第上次续签失败,还需要等待{}小时后再重试'.format(
|
||||
self.__config['orders'][i]['domains'], int(timeout / 60 / 60))
|
||||
writeLog(msg)
|
||||
continue
|
||||
|
||||
# 是否到了最大重试次数
|
||||
if 'retry_count' in self.__config['orders'][i]:
|
||||
if self.__config['orders'][i]['retry_count'] >= 5:
|
||||
writeLog('|-本次跳过域名:{},因连续5次续签失败,不再续签此证书(可尝试手动续签此证书,成功后错误次数将被重置)'.format(
|
||||
self.__config['orders'][i]['domains']))
|
||||
msg = '|-本次跳过域名:{},因连续5次续签失败,不再续签此证书(可尝试手动续签此证书,成功后错误次数将被重置)'.format(
|
||||
self.__config['orders'][i]['domains'])
|
||||
writeLog(msg)
|
||||
continue
|
||||
|
||||
# 加入到续签订单
|
||||
|
||||
@@ -149,6 +149,7 @@ def initUserInfo():
|
||||
|
||||
data = mw.M('users').where('id=?', (1,)).getField('password')
|
||||
if data == '21232f297a57a5a743894a0e4a801fc3':
|
||||
|
||||
pwd = mw.getRandomString(8).lower()
|
||||
file_pw = mw.getRunDir() + '/data/default.pl'
|
||||
mw.writeFile(file_pw, pwd)
|
||||
|
||||
@@ -27,7 +27,7 @@ from flask import request
|
||||
|
||||
class config_api:
|
||||
|
||||
__version = '0.15.3'
|
||||
__version = '0.16.2'
|
||||
__api_addr = 'data/api.json'
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@@ -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, '添加失败')
|
||||
@@ -602,20 +605,22 @@ echo "--------------------------------------------------------------------------
|
||||
|
||||
# 将Shell脚本写到文件
|
||||
def writeShell(self, config):
|
||||
u_file = '/var/spool/cron/crontabs/root'
|
||||
if not os.path.exists(u_file):
|
||||
file = '/var/spool/cron/crontabs/root'
|
||||
current_os = mw.getOs()
|
||||
if current_os == 'darwin':
|
||||
file = '/etc/crontab'
|
||||
elif current_os.startswith("freebsd"):
|
||||
file = '/var/cron/tabs/root'
|
||||
|
||||
if not os.path.exists(file):
|
||||
file = '/var/spool/cron/root'
|
||||
if mw.isAppleSystem():
|
||||
file = '/etc/crontab'
|
||||
else:
|
||||
file = u_file
|
||||
|
||||
if not os.path.exists(file):
|
||||
mw.writeFile(file, '')
|
||||
conf = mw.readFile(file)
|
||||
conf += str(config) + "\n"
|
||||
if mw.writeFile(file, conf):
|
||||
if not os.path.exists(u_file):
|
||||
if not os.path.exists(file):
|
||||
mw.execShell("chmod 600 '" + file +
|
||||
"' && chown root.root " + file)
|
||||
else:
|
||||
|
||||
+63
-11
@@ -64,8 +64,13 @@ class files_api:
|
||||
filename = request.args.get('filename', '')
|
||||
if not os.path.exists(filename):
|
||||
return ''
|
||||
|
||||
is_attachment = True
|
||||
if filename.endswith(".svg"):
|
||||
is_attachment = False
|
||||
|
||||
response = make_response(send_from_directory(
|
||||
os.path.dirname(filename), os.path.basename(filename), as_attachment=True))
|
||||
os.path.dirname(filename), os.path.basename(filename), as_attachment=is_attachment))
|
||||
return response
|
||||
|
||||
def zipApi(self):
|
||||
@@ -82,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', '')
|
||||
@@ -708,10 +719,7 @@ class files_api:
|
||||
return not path in nDirs
|
||||
|
||||
def getDirSize(self, path):
|
||||
if mw.isAppleSystem():
|
||||
tmp = mw.execShell('du -sh ' + path)
|
||||
else:
|
||||
tmp = mw.execShell('du -sbh ' + path)
|
||||
tmp = mw.execShell('du -sh ' + path)
|
||||
return tmp
|
||||
|
||||
def checkFileName(self, filename):
|
||||
@@ -799,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))
|
||||
@@ -823,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'
|
||||
@@ -848,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
-70
@@ -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))
|
||||
@@ -178,12 +212,6 @@ class firewall_api:
|
||||
limit = request.form.get('limit', '10').strip()
|
||||
return self.getList(int(p), int(limit))
|
||||
|
||||
def getLogListApi(self):
|
||||
p = request.form.get('p', '1').strip()
|
||||
limit = request.form.get('limit', '10').strip()
|
||||
search = request.form.get('search', '').strip()
|
||||
return self.getLogList(int(p), int(limit), search)
|
||||
|
||||
def getSshInfoApi(self):
|
||||
data = {}
|
||||
|
||||
@@ -220,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
|
||||
@@ -305,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,18 +420,13 @@ class firewall_api:
|
||||
|
||||
return mw.returnData(True, '设置成功!')
|
||||
|
||||
def delPanelLogsApi(self):
|
||||
mw.M('logs').where('id>?', (0,)).delete()
|
||||
mw.writeLog('面板设置', '面板操作日志已清空!')
|
||||
return mw.returnJson(True, '面板操作日志已清空!')
|
||||
|
||||
##### ----- start ----- ###
|
||||
|
||||
def getList(self, page, limit):
|
||||
|
||||
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
|
||||
@@ -414,38 +440,40 @@ class firewall_api:
|
||||
data['page'] = mw.getPage(_page)
|
||||
return mw.getJson(data)
|
||||
|
||||
def getLogList(self, page, limit, search=''):
|
||||
find_search = ''
|
||||
if search != '':
|
||||
find_search = "type like '%" + search + "%' or log like '%" + \
|
||||
search + "%' or addtime like '%" + search + "%'"
|
||||
|
||||
start = (page - 1) * limit
|
||||
|
||||
_list = mw.M('logs').where(find_search, ()).field(
|
||||
'id,type,log,addtime').limit(str(start) + ',' + str(limit)).order('id desc').select()
|
||||
data = {}
|
||||
data['data'] = _list
|
||||
|
||||
count = mw.M('logs').where(find_search, ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['tojs'] = 'getLogs'
|
||||
_page['p'] = page
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
# coding: utf-8
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# MW-Linux面板
|
||||
# ---------------------------------------------------------------------------------
|
||||
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Author: midoks <midoks@163.com>
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# 日志类操作
|
||||
# ---------------------------------------------------------------------------------
|
||||
|
||||
import psutil
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import mw
|
||||
import re
|
||||
import json
|
||||
import pwd
|
||||
|
||||
from datetime import datetime
|
||||
from flask import request
|
||||
|
||||
|
||||
class logs_api:
|
||||
|
||||
__months = {'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06',
|
||||
'Jul': '07', 'Aug': '08', 'Sep': '09', 'Sept': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'}
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def delPanelLogsApi(self):
|
||||
mw.M('logs').where('id>?', (0,)).delete()
|
||||
mw.writeLog('面板设置', '面板操作日志已清空!')
|
||||
return mw.returnJson(True, '面板操作日志已清空!')
|
||||
|
||||
def getLogListApi(self):
|
||||
p = request.form.get('p', '1').strip()
|
||||
limit = request.form.get('limit', '10').strip()
|
||||
search = request.form.get('search', '').strip()
|
||||
return self.getLogList(int(p), int(limit), search)
|
||||
|
||||
def getLogList(self, page, limit, search=''):
|
||||
find_search = ''
|
||||
if search != '':
|
||||
find_search = "type like '%" + search + "%' or log like '%" + \
|
||||
search + "%' or addtime like '%" + search + "%'"
|
||||
|
||||
start = (page - 1) * limit
|
||||
|
||||
_list = mw.M('logs').where(find_search, ()).field(
|
||||
'id,type,log,addtime').limit(str(start) + ',' + str(limit)).order('id desc').select()
|
||||
data = {}
|
||||
data['data'] = _list
|
||||
|
||||
count = mw.M('logs').where(find_search, ()).count()
|
||||
_page = {}
|
||||
_page['count'] = count
|
||||
_page['tojs'] = 'getLogs'
|
||||
_page['p'] = page
|
||||
|
||||
data['page'] = mw.getPage(_page)
|
||||
return mw.getJson(data)
|
||||
|
||||
def getLogsTitle(self, log_name):
|
||||
log_name = log_name.replace('.1', '')
|
||||
if log_name in ['mw-update.log']:
|
||||
return '面板更新日志'
|
||||
if log_name in ['mw-install.log']:
|
||||
return '面板安装日志'
|
||||
if log_name in ['auth.log', 'secure'] or log_name.find('auth.') == 0:
|
||||
return '授权日志'
|
||||
if log_name in ['dmesg'] or log_name.find('dmesg') == 0:
|
||||
return '内核缓冲区日志'
|
||||
if log_name in ['syslog'] or log_name.find('syslog') == 0:
|
||||
return '系统警告/错误日志'
|
||||
if log_name in ['btmp']:
|
||||
return '失败的登录记录'
|
||||
if log_name in ['utmp', 'wtmp']:
|
||||
return '登录和重启记录'
|
||||
if log_name in ['lastlog']:
|
||||
return '用户最后登录'
|
||||
if log_name in ['yum.log']:
|
||||
return 'yum包管理器日志'
|
||||
if log_name in ['anaconda.log']:
|
||||
return 'Anaconda日志'
|
||||
if log_name in ['dpkg.log']:
|
||||
return 'dpkg日志'
|
||||
if log_name in ['daemon.log']:
|
||||
return '系统后台守护进程日志'
|
||||
if log_name in ['boot.log']:
|
||||
return '启动日志'
|
||||
if log_name in ['kern.log']:
|
||||
return '内核日志'
|
||||
if log_name in ['maillog', 'mail.log']:
|
||||
return '邮件日志'
|
||||
if log_name.find('Xorg') == 0:
|
||||
return 'Xorg日志'
|
||||
if log_name in ['cron.log']:
|
||||
return '定时任务日志'
|
||||
if log_name in ['alternatives.log']:
|
||||
return '更新替代信息'
|
||||
if log_name in ['debug']:
|
||||
return '调试信息'
|
||||
if log_name.find('apt') == 0:
|
||||
return 'apt-get相关日志'
|
||||
if log_name.find('installer') == 0:
|
||||
return '系统安装相关日志'
|
||||
if log_name in ['messages']:
|
||||
return '综合日志'
|
||||
return '{}日志'.format(log_name.split('.')[0])
|
||||
|
||||
def getAuditLogsFilesApi(self):
|
||||
log_dir = '/var/log'
|
||||
log_files = []
|
||||
for log_file in os.listdir(log_dir):
|
||||
log_suffix = log_file.split('.')[-1:]
|
||||
if log_suffix[0] in ['gz', 'xz', 'bz2', 'asl']:
|
||||
continue
|
||||
|
||||
if log_file in ['.', '..', 'faillog', 'fontconfig.log', 'unattended-upgrades', 'tallylog']:
|
||||
continue
|
||||
|
||||
filename = os.path.join(log_dir, log_file)
|
||||
if os.path.isfile(filename):
|
||||
file_size = os.path.getsize(filename)
|
||||
if not file_size:
|
||||
continue
|
||||
|
||||
tmp = {
|
||||
'name': log_file,
|
||||
'size': file_size,
|
||||
'log_file': filename,
|
||||
'title': self.getLogsTitle(log_file),
|
||||
'uptime': os.path.getmtime(filename)
|
||||
}
|
||||
|
||||
log_files.append(tmp)
|
||||
else:
|
||||
for next_name in os.listdir(filename):
|
||||
if next_name[-3:] in ['.gz', '.xz']:
|
||||
continue
|
||||
next_file = os.path.join(filename, next_name)
|
||||
if not os.path.isfile(next_file):
|
||||
continue
|
||||
file_size = os.path.getsize(next_file)
|
||||
if not file_size:
|
||||
continue
|
||||
log_name = '{}/{}'.format(log_file, next_name)
|
||||
tmp = {
|
||||
'name': log_name,
|
||||
'size': file_size,
|
||||
'log_file': next_file,
|
||||
'title': self.getLogsTitle(log_name),
|
||||
'uptime': os.path.getmtime(next_file)
|
||||
}
|
||||
log_files.append(tmp)
|
||||
log_files = sorted(log_files, key=lambda x: x['name'], reverse=True)
|
||||
return mw.getJson(log_files)
|
||||
|
||||
def getAuditFileApi(self):
|
||||
log_name = request.form.get('log_name', '').strip()
|
||||
return self.getAuditLogsName(log_name)
|
||||
|
||||
def __to_date2(self, date_str):
|
||||
tmp = date_str.split()
|
||||
s_date = str(tmp[-1]) + '-' + self.__months.get(tmp[1],
|
||||
tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
|
||||
return s_date
|
||||
|
||||
def __to_date3(self, date_str):
|
||||
tmp = date_str.split()
|
||||
s_date = str(datetime.now().year) + '-' + \
|
||||
self.__months.get(tmp[1], tmp[1]) + '-' + tmp[2] + ' ' + tmp[3]
|
||||
return s_date
|
||||
|
||||
def __to_date4(self, date_str):
|
||||
tmp = date_str.split()
|
||||
s_date = str(datetime.now().year) + '-' + \
|
||||
self.__months.get(tmp[0], tmp[0]) + '-' + tmp[1] + ' ' + tmp[2]
|
||||
return s_date
|
||||
|
||||
def getAuditLast(self, log_name):
|
||||
# 获取日志
|
||||
cmd = '''LANG=en_US.UTF-8 last -n 200 -x -f {} |grep -v 127.0.0.1|grep -v " begins"'''.format(
|
||||
'/var/log/' + log_name)
|
||||
result = mw.execShell(cmd)
|
||||
lastlog_list = []
|
||||
for _line in result[0].split("\n"):
|
||||
if not _line:
|
||||
continue
|
||||
tmp = {}
|
||||
sp_arr = _line.split()
|
||||
tmp['用户'] = sp_arr[0]
|
||||
if sp_arr[0] == 'runlevel':
|
||||
tmp['来源'] = sp_arr[4]
|
||||
tmp['端口'] = ' '.join(sp_arr[1:4])
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[5:])) + ' ' + ' '.join(sp_arr[-2:])
|
||||
elif sp_arr[0] in ['reboot', 'shutdown']:
|
||||
tmp['来源'] = sp_arr[3]
|
||||
tmp['端口'] = ' '.join(sp_arr[1:3])
|
||||
if sp_arr[-3] == '-':
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[4:])) + ' ' + ' '.join(sp_arr[-3:])
|
||||
else:
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[4:])) + ' ' + ' '.join(sp_arr[-2:])
|
||||
elif sp_arr[1] in ['tty1', 'tty', 'tty2', 'tty3', 'hvc0', 'hvc1', 'hvc2'] or len(sp_arr) == 9:
|
||||
tmp['来源'] = ''
|
||||
tmp['端口'] = sp_arr[1]
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[2:])) + ' ' + ' '.join(sp_arr[-3:])
|
||||
else:
|
||||
tmp['来源'] = sp_arr[2]
|
||||
tmp['端口'] = sp_arr[1]
|
||||
tmp['时间'] = self.__to_date3(
|
||||
' '.join(sp_arr[3:])) + ' ' + ' '.join(sp_arr[-3:])
|
||||
|
||||
# tmp['_line'] = _line
|
||||
lastlog_list.append(tmp)
|
||||
# lastlog_list = sorted(lastlog_list,key=lambda x:x['时间'],reverse=True)
|
||||
return mw.returnData(True, 'ok!', lastlog_list)
|
||||
|
||||
def getAuditLastLog(self):
|
||||
cmd = '''LANG=en_US.UTF-8 lastlog|grep -v Username'''
|
||||
result = mw.execShell(cmd)
|
||||
lastlog_list = []
|
||||
for _line in result[0].split("\n"):
|
||||
if not _line:
|
||||
continue
|
||||
tmp = {}
|
||||
sp_arr = _line.split()
|
||||
tmp['用户'] = sp_arr[0]
|
||||
# tmp['_line'] = _line
|
||||
if _line.find('Never logged in') != -1:
|
||||
tmp['最后登录时间'] = '0'
|
||||
tmp['最后登录来源'] = '-'
|
||||
tmp['最后登录端口'] = '-'
|
||||
lastlog_list.append(tmp)
|
||||
continue
|
||||
tmp['最后登录来源'] = sp_arr[2]
|
||||
tmp['最后登录端口'] = sp_arr[1]
|
||||
tmp['最后登录时间'] = self.__to_date2(' '.join(sp_arr[3:]))
|
||||
|
||||
lastlog_list.append(tmp)
|
||||
lastlog_list = sorted(lastlog_list, key=lambda x: x[
|
||||
'最后登录时间'], reverse=True)
|
||||
for i in range(len(lastlog_list)):
|
||||
if lastlog_list[i]['最后登录时间'] == '0':
|
||||
lastlog_list[i]['最后登录时间'] = '从未登录过'
|
||||
return mw.returnData(True, 'ok!', lastlog_list)
|
||||
|
||||
def parseAuditFile(self, log_name, result):
|
||||
log_list = []
|
||||
is_string = True
|
||||
for _line in result.split("\n"):
|
||||
if not _line.strip():
|
||||
continue
|
||||
if log_name.find('sa/sa') == -1:
|
||||
if _line[:3] in self.__months:
|
||||
_msg = _line[16:]
|
||||
_tmp = _msg.split(": ")
|
||||
_act = ''
|
||||
if len(_tmp) > 1:
|
||||
_act = _tmp[0]
|
||||
_msg = _tmp[1]
|
||||
else:
|
||||
_msg = _tmp[0]
|
||||
_line = {
|
||||
"时间": self.__to_date4(_line[:16].strip()),
|
||||
"角色": _act,
|
||||
"事件": _msg
|
||||
}
|
||||
is_string = False
|
||||
elif _line[:2] in ['19', '20', '21', '22', '23', '24']:
|
||||
_msg = _line[19:]
|
||||
_tmp = _msg.split(" ")
|
||||
_act = _tmp[1]
|
||||
_msg = ' '.join(_tmp[2:])
|
||||
_line = {
|
||||
"时间": _line[:19].strip(),
|
||||
"角色": _act,
|
||||
"事件": _msg
|
||||
}
|
||||
is_string = False
|
||||
elif log_name.find('alternatives') == 0:
|
||||
_tmp = _line.split(": ")
|
||||
_last = _tmp[0].split(" ")
|
||||
_act = _last[0]
|
||||
_msg = ' '.join(_tmp[1:])
|
||||
_line = {
|
||||
"时间": ' '.join(_last[1:]).strip(),
|
||||
"角色": _act,
|
||||
"事件": _msg
|
||||
}
|
||||
is_string = False
|
||||
else:
|
||||
if not is_string:
|
||||
if type(_line) != dict:
|
||||
continue
|
||||
|
||||
log_list.append(_line)
|
||||
|
||||
return log_list
|
||||
|
||||
def getAuditLogsName(self, log_name):
|
||||
# print(log_name)
|
||||
if log_name in ['wtmp', 'btmp', 'utmp'] or log_name.find('wtmp') == 0 or log_name.find('btmp') == 0 or log_name.find('utmp') == 0:
|
||||
return self.getAuditLast(log_name)
|
||||
|
||||
if log_name.find('lastlog') == 0:
|
||||
return self.getAuditLastLog()
|
||||
|
||||
if log_name.find('sa/sa') == 0:
|
||||
if log_name.find('sa/sar') == -1:
|
||||
return mw.execShell("sar -f /var/log/{}".format(log_name))[0]
|
||||
log_dir = '/var/log'
|
||||
log_file = log_dir + '/' + log_name
|
||||
if not os.path.exists(log_file):
|
||||
return mw.returnData(False, '日志文件不存在!')
|
||||
result = mw.getLastLine(log_file, 100)
|
||||
try:
|
||||
log_list = self.parseAuditFile(log_name, result)
|
||||
_string = []
|
||||
_dict = []
|
||||
_list = []
|
||||
for _line in log_list:
|
||||
if isinstance(_line, str):
|
||||
_string.append(_line.strip())
|
||||
elif isinstance(_line, dict):
|
||||
_dict.append(_line)
|
||||
elif isinstance(_line, list):
|
||||
_list.append(_line)
|
||||
else:
|
||||
continue
|
||||
_str_len = len(_string)
|
||||
_dict_len = len(_dict)
|
||||
_list_len = len(_list)
|
||||
if _str_len > _dict_len + _list_len:
|
||||
return "\n".join(_string)
|
||||
elif _dict_len > _str_len + _list_len:
|
||||
return mw.returnData(True, 'ok!', _dict)
|
||||
else:
|
||||
return mw.returnData(True, 'ok!', _list)
|
||||
|
||||
except:
|
||||
return mw.returnData(True, 'ok!', result)
|
||||
+19
-10
@@ -349,7 +349,8 @@ def restartMw():
|
||||
|
||||
def checkWebConfig():
|
||||
op_dir = getServerDir() + '/openresty/nginx'
|
||||
cmd = "ulimit -n 10240 && " + op_dir + \
|
||||
# "ulimit -n 10240 && " +
|
||||
cmd = op_dir + \
|
||||
"/sbin/nginx -t -c " + op_dir + "/conf/nginx.conf"
|
||||
result = execShell(cmd)
|
||||
searchStr = 'test is successful'
|
||||
@@ -424,13 +425,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():
|
||||
@@ -1355,6 +1356,12 @@ def getCpuType():
|
||||
cpuinfo = execShell(cmd)
|
||||
return cpuinfo[0].strip()
|
||||
|
||||
current_os = getOs()
|
||||
if current_os.startswith('freebsd'):
|
||||
cmd = "sysctl -a | egrep -i 'hw.model' | awk -F ':' '{print $2}'"
|
||||
cpuinfo = execShell(cmd)
|
||||
return cpuinfo[0].strip()
|
||||
|
||||
# 取CPU类型
|
||||
cpuinfo = open('/proc/cpuinfo', 'r').read()
|
||||
rep = "model\s+name\s+:\s+(.+)"
|
||||
@@ -1411,7 +1418,7 @@ def makeConf():
|
||||
file = getRunDir() + '/data/json/config.json'
|
||||
if not os.path.exists(file):
|
||||
c = {}
|
||||
c['title'] = '金灵面板'
|
||||
c['title'] = '老子面板'
|
||||
c['home'] = 'http://github/midoks/mdserver-web'
|
||||
c['recycle_bin'] = True
|
||||
c['template'] = 'default'
|
||||
@@ -1550,7 +1557,9 @@ def checkInput(data):
|
||||
|
||||
def checkCert(certPath='ssl/certificate.pem'):
|
||||
# 验证证书
|
||||
openssl = '/usr/local/openssl/bin/openssl'
|
||||
openssl = '/usr/bin/openssl'
|
||||
if not os.path.exists(openssl):
|
||||
openssl = '/usr/local/openssl/bin/openssl'
|
||||
if not os.path.exists(openssl):
|
||||
openssl = 'openssl'
|
||||
certPem = readFile(certPath)
|
||||
@@ -2097,15 +2106,15 @@ done
|
||||
|
||||
|
||||
def echoStart(tag):
|
||||
print("=" * 90)
|
||||
print("=" * 89)
|
||||
print("★开始{}[{}]".format(tag, formatDate()))
|
||||
print("=" * 90)
|
||||
print("=" * 89)
|
||||
|
||||
|
||||
def echoEnd(tag):
|
||||
print("=" * 90)
|
||||
print("=" * 89)
|
||||
print("☆{}完成[{}]".format(tag, formatDate()))
|
||||
print("=" * 90)
|
||||
print("=" * 89)
|
||||
print("\n")
|
||||
|
||||
|
||||
|
||||
+51
-20
@@ -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')
|
||||
@@ -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)
|
||||
|
||||
+38
-10
@@ -1149,8 +1149,9 @@ class site_api:
|
||||
domains = request.form.get('domains', '')
|
||||
status = request.form.get('status', '')
|
||||
name = request.form.get('name', '')
|
||||
none = request.form.get('none', '')
|
||||
sid = request.form.get('id', '')
|
||||
return self.setSecurity(sid, name, fix, domains, status)
|
||||
return self.setSecurity(sid, name, fix, domains, status, none)
|
||||
|
||||
def getLogsApi(self):
|
||||
siteName = request.form.get('siteName', '')
|
||||
@@ -2430,9 +2431,28 @@ location ^~ {from} {\n\
|
||||
tmp = re.search(rep, conf).group()
|
||||
data['fix'] = re.search(
|
||||
"\(.+\)\$", tmp).group().replace('(', '').replace(')$', '').replace('|', ',')
|
||||
data['domains'] = ','.join(re.search(
|
||||
"valid_referers\s+none\s+blocked\s+(.+);\n", tmp).groups()[0].split())
|
||||
data['status'] = True
|
||||
|
||||
data['status'] = False
|
||||
data['none'] = False
|
||||
|
||||
valid_referers = re.search(
|
||||
"valid_referers\s+(.+);\n", tmp)
|
||||
valid_referers_none = re.search(
|
||||
"valid_referers\s+none\s+blocked\s+(.+);\n", tmp)
|
||||
|
||||
if valid_referers or valid_referers_none:
|
||||
data['status'] = True
|
||||
|
||||
if valid_referers_none:
|
||||
domain_t = valid_referers_none.groups()[0].split()
|
||||
data['domains'] = ','.join(domain_t)
|
||||
data['none'] = True
|
||||
elif valid_referers:
|
||||
domain_t = valid_referers.groups()[0].split()
|
||||
data['domains'] = ','.join(domain_t)
|
||||
data['none'] = False
|
||||
|
||||
# print(data)
|
||||
else:
|
||||
data['fix'] = 'jpg,jpeg,gif,png,js,css'
|
||||
domains = mw.M('domain').where(
|
||||
@@ -2442,19 +2462,27 @@ location ^~ {from} {\n\
|
||||
tmp.append(domain['name'])
|
||||
data['domains'] = ','.join(tmp)
|
||||
data['status'] = False
|
||||
data['none'] = False
|
||||
return mw.getJson(data)
|
||||
|
||||
def setSecurity(self, sid, name, fix, domains, status):
|
||||
def setSecurity(self, sid, name, fix, domains, status, none=''):
|
||||
if len(fix) < 2:
|
||||
return mw.returnJson(False, 'URL后缀不能为空!')
|
||||
file = self.getHostConf(name)
|
||||
if os.path.exists(file):
|
||||
conf = mw.readFile(file)
|
||||
if conf.find('SECURITY-START') != -1:
|
||||
if status == 'false':
|
||||
rep = "\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
|
||||
conf = re.sub(rep, '', conf)
|
||||
mw.writeLog('网站管理', '站点[' + name + ']已关闭防盗链设置!')
|
||||
else:
|
||||
rep = "\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
|
||||
conf = re.sub(rep, '', conf)
|
||||
|
||||
valid_referers = domains.strip().replace(',', ' ')
|
||||
if none == 'true':
|
||||
valid_referers = 'none blocked ' + valid_referers
|
||||
|
||||
pre_path = self.setupPath + "/php/conf"
|
||||
re_path = "include\s+" + pre_path + "/enable-php-"
|
||||
rconf = '''#SECURITY-START 防盗链配置
|
||||
@@ -2462,13 +2490,13 @@ location ^~ {from} {\n\
|
||||
{
|
||||
expires 30d;
|
||||
access_log /dev/null;
|
||||
valid_referers none blocked %s;
|
||||
valid_referers %s;
|
||||
if ($invalid_referer){
|
||||
return 404;
|
||||
}
|
||||
}
|
||||
#SECURITY-END
|
||||
include %s/enable-php-''' % (fix.strip().replace(',', '|'), domains.strip().replace(',', ' '), pre_path)
|
||||
include %s/enable-php-''' % (fix.strip().replace(',', '|'), valid_referers, pre_path)
|
||||
conf = re.sub(re_path, rconf, conf)
|
||||
mw.writeLog('网站管理', '站点[' + name + ']已开启防盗链!')
|
||||
mw.writeFile(file, conf)
|
||||
@@ -2477,7 +2505,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 = {}
|
||||
@@ -2760,7 +2788,7 @@ location ^~ {from} {\n\
|
||||
|
||||
self.saveCert(keyPath, certPath)
|
||||
|
||||
msg = mw.getInfo('网站[{1}]开启SSL成功!', siteName)
|
||||
msg = mw.getInfo('网站[{1}]开启SSL成功!', (siteName,))
|
||||
mw.writeLog('网站管理', msg)
|
||||
|
||||
mw.restartWeb()
|
||||
|
||||
@@ -273,27 +273,60 @@ 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):
|
||||
#
|
||||
# 取操作系统版本
|
||||
if mw.getOs() == 'darwin':
|
||||
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] + ' '
|
||||
return mac_version
|
||||
|
||||
arch_ver = mw.execShell("arch")
|
||||
return mac_version + " (" + arch_ver[0].strip() + ")"
|
||||
|
||||
# freebsd
|
||||
if current_os.startswith('freebsd'):
|
||||
version = mw.execShell(
|
||||
"cat /etc/*-release | grep PRETTY_NAME | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
|
||||
arch_ver = mw.execShell(
|
||||
"sysctl -a | egrep -i 'hw.machine_arch' | awk -F ':' '{print $2}'")
|
||||
return version[0].strip() + " (" + arch_ver[0].strip() + ")"
|
||||
|
||||
redhat_series = '/etc/redhat-release'
|
||||
if os.path.exists(redhat_series):
|
||||
version = mw.readFile('/etc/redhat-release')
|
||||
version = version.replace('release ', '').strip()
|
||||
return version
|
||||
|
||||
arch_ver = mw.execShell("arch")
|
||||
return version + " (" + arch_ver[0].strip() + ")"
|
||||
|
||||
os_series = '/etc/os-release'
|
||||
if os.path.exists(os_series):
|
||||
version = mw.execShell(
|
||||
"cat /etc/*-release | grep PRETTY_NAME | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
|
||||
return version[0].strip()
|
||||
|
||||
arch_ver = mw.execShell("arch")
|
||||
return version[0].strip() + " (" + arch_ver[0].strip() + ")"
|
||||
|
||||
return '未识别系统信息'
|
||||
|
||||
@@ -318,7 +351,7 @@ class system_api:
|
||||
cpuCount = psutil.cpu_count()
|
||||
cpuLogicalNum = psutil.cpu_count(logical=False)
|
||||
used = psutil.cpu_percent(interval=interval)
|
||||
|
||||
cpuLogicalNum = 0
|
||||
if os.path.exists('/proc/cpuinfo'):
|
||||
c_tmp = mw.readFile('/proc/cpuinfo')
|
||||
d_tmp = re.findall("physical id.+", c_tmp)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -7,6 +7,10 @@ MDIR=$(dirname "$DIR")
|
||||
PATH=$PATH:$DIR/bin
|
||||
if [ -f bin/activate ];then
|
||||
source bin/activate
|
||||
|
||||
if [ "$?" != "0" ];then
|
||||
echo "load local python env fail!"
|
||||
fi
|
||||
fi
|
||||
|
||||
export LC_ALL="en_US.UTF-8"
|
||||
@@ -42,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,16 @@
|
||||
- 面板相关命令
|
||||
|
||||
```
|
||||
/etc/init.d/mw default
|
||||
/etc/init.d/mw default | 显示登录信息
|
||||
/etc/init.d/mw db | 快捷连接数据库
|
||||
----------------------------------------
|
||||
|
||||
mw debug | 开发测试
|
||||
mw venv | 进入虚拟环境
|
||||
mw mirror | 切换镜像
|
||||
mw install_app | 快捷安装常用软件
|
||||
mw update | 更新到正式
|
||||
mw update_dev | 更新到开发
|
||||
|
||||
service mw [start|stop|reload|restart|status]
|
||||
```
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -14,6 +14,7 @@ if sys.platform != "darwin":
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
import db
|
||||
|
||||
_ver = sys.version_info
|
||||
is_py2 = (_ver[0] == 2)
|
||||
@@ -185,6 +186,35 @@ def backupAllFunc(stype):
|
||||
"path": "path",
|
||||
}
|
||||
|
||||
backups = []
|
||||
sql = db.Sql()
|
||||
|
||||
# print("stype:", stype)
|
||||
# 提前获取-清理多余备份
|
||||
if stype == 'site':
|
||||
pid = sql.table('sites').where('name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('0', pid)).field('id,filename').select()
|
||||
if stype == 'database':
|
||||
db_path = mw.getServerDir() + '/mysql'
|
||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
|
||||
'name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('1', pid)).field('id,filename').select()
|
||||
if stype == 'path':
|
||||
backup_path = backup_dir + '/path'
|
||||
_name = 'path_{}'.format(os.path.basename(name))
|
||||
backups = findPathName(backup_path, _name)
|
||||
|
||||
# 其他类型关系性数据库(mysql类的)
|
||||
if stype.find('database_') > -1:
|
||||
plugin_name = stype.replace('database_', '')
|
||||
db_path = mw.getServerDir() + '/' + plugin_name
|
||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
|
||||
'name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('1', pid)).field('id,filename').select()
|
||||
|
||||
args = stype + " " + name + " " + num
|
||||
cmd = 'python3 ' + mw.getRunDir() + '/scripts/backup.py ' + args
|
||||
if stype.find('database_') > -1:
|
||||
@@ -213,19 +243,31 @@ def backupAllFunc(stype):
|
||||
filename = mw.execShell(find_new_file)[0].strip()
|
||||
if filename == "":
|
||||
mw.echoInfo("not find upload file!")
|
||||
return False
|
||||
return ''
|
||||
|
||||
print("|-准备上传文件 {}".format(filename))
|
||||
ftp = FtpPSClient()
|
||||
ftp.uploadFile(filename, stype)
|
||||
|
||||
# print(backups)
|
||||
backups = sorted(backups, key=lambda x: x['filename'], reverse=False)
|
||||
mw.echoStart('开始删除远程备份')
|
||||
num = int(num)
|
||||
sep = len(backups) - num
|
||||
if sep > -1:
|
||||
for backup in backups:
|
||||
fn = os.path.basename(backup['filename'])
|
||||
object_name = ftp.buildDirName(stype, fn)
|
||||
ftp.deleteFile(object_name)
|
||||
mw.echoInfo("---已清理远程过期备份文件:" + object_name)
|
||||
sep -= 1
|
||||
if sep < 0:
|
||||
break
|
||||
mw.echoEnd('结束删除远程备份')
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
def backupSite():
|
||||
# 备份站点
|
||||
pass
|
||||
|
||||
|
||||
def in_array(name, arr=[]):
|
||||
for x in arr:
|
||||
if name == x:
|
||||
|
||||
@@ -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: 3.1 KiB |
Executable
+19
@@ -0,0 +1,19 @@
|
||||
<div class="bt-form">
|
||||
<div class='plugin_version'></div>
|
||||
<div class="bt-w-main">
|
||||
<div class="bt-w-menu">
|
||||
<p class="bgw" onclick="pluginService('dynamic-tracking');">服务</p>
|
||||
<p onclick="pluginInitD('dynamic-tracking');">自启动</p>
|
||||
</div>
|
||||
<div class="bt-w-con pd15">
|
||||
<div class="soft-man-con"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
resetPluginWinHeight(300);
|
||||
resetPluginWinWidth(500);
|
||||
$.getScript( "/plugins/file?name=dynamic-tracking&f=static/js/dynamic-tracking.js", function(){
|
||||
pluginService('dynamic-tracking', $('.plugin_version').attr('version'));
|
||||
});
|
||||
</script>
|
||||
Executable
+228
@@ -0,0 +1,228 @@
|
||||
# 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 'dynamic-tracking'
|
||||
|
||||
|
||||
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 getInitDTpl():
|
||||
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
|
||||
return path
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
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():
|
||||
dir_path = getServerDir() + '/trace'
|
||||
if not os.path.exists(dir_path):
|
||||
os.mkdir(dir_path)
|
||||
return 'start'
|
||||
|
||||
|
||||
def dtOp(method):
|
||||
return 'ok'
|
||||
|
||||
|
||||
def start():
|
||||
return dtOp('start')
|
||||
|
||||
|
||||
def stop():
|
||||
return dtOp('stop')
|
||||
|
||||
|
||||
def restart():
|
||||
status = dtOp('restart')
|
||||
return status
|
||||
|
||||
|
||||
def reload():
|
||||
return dtOp('reload')
|
||||
|
||||
|
||||
def initdStatus():
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdInstall():
|
||||
return 'ok'
|
||||
|
||||
|
||||
def initdUinstall():
|
||||
return 'ok'
|
||||
|
||||
|
||||
def get_file(args):
|
||||
dir_path = getServerDir() + '/trace'
|
||||
|
||||
path = dir_path + '/' + args['file'] + '/main.svg'
|
||||
|
||||
if os.path.exists(path):
|
||||
d = mw.readFile(path)
|
||||
return mw.returnData(True, 'ok', d)
|
||||
else:
|
||||
return mw.returnData(False, '无效目录')
|
||||
|
||||
|
||||
def get_file_path(args):
|
||||
dir_path = getServerDir() + '/trace'
|
||||
path = dir_path + '/' + args['file'] + '/main.svg'
|
||||
if os.path.exists(path):
|
||||
return mw.returnData(True, 'ok', path)
|
||||
else:
|
||||
return mw.returnData(False, '无效目录')
|
||||
|
||||
|
||||
def dtGetFilePath():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
dir_path = getServerDir() + '/trace'
|
||||
path = dir_path + '/' + args['file'] + '/main.svg'
|
||||
if os.path.exists(path):
|
||||
return mw.returnJson(True, 'ok', path)
|
||||
else:
|
||||
return mw.returnJson(False, '无效目录')
|
||||
|
||||
|
||||
def dtRemoveFilePath():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
dir_path = getServerDir() + '/trace'
|
||||
path = dir_path + '/' + args['file']
|
||||
if os.path.exists(path):
|
||||
mw.execShell('rm -rf ' + path)
|
||||
return mw.returnJson(True, '删除成功!')
|
||||
|
||||
|
||||
def dtFileList():
|
||||
dir_path = getServerDir() + '/trace'
|
||||
if not os.path.exists(dir_path):
|
||||
os.mkdir(dir_path)
|
||||
|
||||
file_info = []
|
||||
for name in os.listdir(dir_path):
|
||||
if name == ".DS_Store":
|
||||
continue
|
||||
|
||||
# print(name)
|
||||
info = {}
|
||||
try:
|
||||
info['name'] = name
|
||||
info['abs_path'] = dir_path + '/' + name + '/main.svg'
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, str(e))
|
||||
|
||||
file_info.append(info)
|
||||
|
||||
file_info = sorted(file_info, key=lambda x: x['name'], reverse=False)
|
||||
return mw.returnJson(True, 'ok!', file_info)
|
||||
|
||||
|
||||
def dtSimpleTrace():
|
||||
if mw.isAppleSystem():
|
||||
return mw.returnJson(False, 'macosx只能手动执行!')
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['pid'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
plugins_shell = getPluginDir() + '/shell/simple_trace.sh'
|
||||
cmd = plugins_shell + ' "' + args['pid'] + '"'
|
||||
|
||||
data = mw.execShell("bash " + cmd + " &")
|
||||
return mw.returnJson(True, '执行成功!')
|
||||
|
||||
|
||||
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 == 'file_list':
|
||||
print(dtFileList())
|
||||
elif func == 'get_file_path':
|
||||
print(dtGetFilePath())
|
||||
elif func == 'remove_file_path':
|
||||
print(dtRemoveFilePath())
|
||||
elif func == 'simple_trace':
|
||||
print(dtSimpleTrace())
|
||||
else:
|
||||
print('error')
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"hook":[
|
||||
{
|
||||
"tag":"menu",
|
||||
"menu": {
|
||||
"title":"动态追踪",
|
||||
"name":"dynamic-tracking",
|
||||
"path":"static/html/index.html",
|
||||
"css_path":"static/css/dynamic-tracking.css",
|
||||
"js_path":"static/js/dynamic-tracking.js"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag":"global_static",
|
||||
"global_static": {
|
||||
"title":"动态追踪",
|
||||
"name":"dynamic-tracking",
|
||||
"css_path":"static/css/ico.css"
|
||||
}
|
||||
}
|
||||
],
|
||||
"sort": 7,
|
||||
"ps": "专业使用,动态追踪调试程序<无侵入>![<span style='color:red;'>潜龙勿用|实验</span>]",
|
||||
"name": "dynamic-tracking",
|
||||
"title": "动态追踪",
|
||||
"shell": "install.sh",
|
||||
"versions":["0.1"],
|
||||
"tip": "soft",
|
||||
"checks": "server/dynamic-tracking",
|
||||
"path": "server/dynamic-tracking",
|
||||
"display": 1,
|
||||
"author": "midoks",
|
||||
"date": "2023-08-17",
|
||||
"type": 0,
|
||||
"pid": "4"
|
||||
}
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
# cd /www/server/mdserver-web/plugins/dynamic-tracking && /bin/bash install.sh uninstall 1.0
|
||||
# cd /www/server/mdserver-web/plugins/dynamic-tracking && /bin/bash install.sh install 1.0
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
VERSION=$2
|
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
|
||||
OSNAME=`bash ${rootPath}/scripts/getos.sh`
|
||||
|
||||
if [ "" == "$OSNAME" ];then
|
||||
OSNAME=`cat ${rootPath}/data/osname.pl`
|
||||
fi
|
||||
|
||||
if [ "macos" != "$OSNAME" ];then
|
||||
SYS_VERSION_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
|
||||
fi
|
||||
|
||||
Install_App()
|
||||
{
|
||||
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
mkdir -p $serverPath/source
|
||||
mkdir -p $serverPath/dynamic-tracking
|
||||
|
||||
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
|
||||
HTTP_PREFIX="https://"
|
||||
if [ ! -z "$cn" ];then
|
||||
HTTP_PREFIX="https://ghproxy.com/"
|
||||
fi
|
||||
|
||||
# FlameGraph start
|
||||
if [ ! -d $serverPath/dynamic-tracking/FlameGraph ];then
|
||||
if [ ! -f $serverPath/source/FlameGraph.zip ]; then
|
||||
wget --no-check-certificate -O $serverPath/source/FlameGraph.zip ${HTTP_PREFIX}github.com/brendangregg/FlameGraph/archive/refs/heads/master.zip
|
||||
fi
|
||||
|
||||
cd $serverPath/source && unzip $serverPath/source/FlameGraph.zip
|
||||
mv $serverPath/source/FlameGraph-master $serverPath/dynamic-tracking/FlameGraph
|
||||
fi
|
||||
# FlameGraph end
|
||||
|
||||
|
||||
|
||||
shell_file=${curPath}/versions/${OSNAME}.sh
|
||||
echo $shell_file
|
||||
if [ ! -f $shell_file ];then
|
||||
echo '不支持...' > $install_tmp
|
||||
exit 1
|
||||
fi
|
||||
|
||||
bash -x $shell_file
|
||||
|
||||
echo "cp -rf ${curPath}/shell $serverPath/dynamic-tracking"
|
||||
cp -rf ${curPath}/shell $serverPath/dynamic-tracking
|
||||
|
||||
echo "${VERSION}" > $serverPath/dynamic-tracking/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
|
||||
cd ${rootPath} && python3 ${rootPath}/plugins/dynamic-tracking/index.py start
|
||||
# cd ${rootPath} && python3 ${rootPath}/plugins/dynamic-tracking/index.py initd_install
|
||||
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
rm -rf $serverPath/dynamic-tracking
|
||||
echo "Uninstall_App" > $install_tmp
|
||||
}
|
||||
|
||||
action=$1
|
||||
if [ "${1}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
|
||||
# debug
|
||||
# cd /www/server/mdserver-web
|
||||
# bash /www/server/mdserver-web/plugins/dynamic-tracking/shell/simple_macosx_trace.sh "22431"
|
||||
|
||||
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web
|
||||
# bash /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/dynamic-tracking/shell/simple_macosx_trace.sh "22431"
|
||||
|
||||
# dtrace -x ustackframes=100 -n 'pid$target::mach_msg_trap:entry { @[ustack()] = count(); } tick-30s { exit(0); }' -p 18572 -o out.SystemUIServer_stacks
|
||||
# /Users/midoks/Desktop/mwdev/server/dynamic-tracking/FlameGraph/stackcollapse.pl out.SystemUIServer_stacks > kernel.cbt
|
||||
# /Users/midoks/Desktop/mwdev/server/dynamic-tracking/FlameGraph/flamegraph.pl kernel.cbt > kernel.svg
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
sysName=`uname`
|
||||
PID=$1
|
||||
|
||||
echo $rootPath # /Users/midoks/Desktop/mwdev/server
|
||||
echo $curPath # /Users/midoks/Desktop/mwdev/server/mdserver-web
|
||||
|
||||
APP_DIR=${rootPath}/dynamic-tracking
|
||||
DST_FILE_DIR=${APP_DIR}/trace/PID_${PID}
|
||||
mkdir -p $DST_FILE_DIR
|
||||
|
||||
DST_FILE=${DST_FILE_DIR}/out.SystemUIServer_stacks
|
||||
|
||||
if [ ! -f $DST_FILE ];then
|
||||
sudo dtrace -x ustackframes=100 -n 'pid$target::mach_msg_trap:entry { @[ustack()] = count(); } tick-30s { exit(0); }' -p "$PID" -o $DST_FILE
|
||||
fi
|
||||
|
||||
${APP_DIR}/FlameGraph/stackcollapse.pl $DST_FILE > ${DST_FILE_DIR}/kernel.cbt
|
||||
${APP_DIR}/FlameGraph/flamegraph.pl ${DST_FILE_DIR}/kernel.cbt > ${DST_FILE_DIR}/main.svg
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
|
||||
# debug
|
||||
# cd /www/server/mdserver-web
|
||||
# bash /www/server/mdserver-web/plugins/dynamic-tracking/shell/simple_trace.sh "2401699"
|
||||
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
sysName=`uname`
|
||||
PID=$1
|
||||
|
||||
echo $rootPath # /Users/midoks/Desktop/mwdev/server
|
||||
echo $curPath # /Users/midoks/Desktop/mwdev/server/mdserver-web
|
||||
|
||||
APP_DIR=/www/server/dynamic-tracking
|
||||
DST_FILE_DIR=${APP_DIR}/trace/PID_${PID}
|
||||
mkdir -p $DST_FILE_DIR
|
||||
|
||||
# DST_FILE=${DST_FILE_DIR}/main.strace
|
||||
|
||||
# perf record -F 99 -p 335584 -g -- sleep 30
|
||||
|
||||
cd ${DST_FILE_DIR}
|
||||
perf record -F 99 -p ${PID} -g -- sleep 30
|
||||
|
||||
perf script > out.perf
|
||||
${APP_DIR}/FlameGraph/stackcollapse-perf.pl ${DST_FILE_DIR}/out.perf > ${DST_FILE_DIR}/out.folded
|
||||
${APP_DIR}/FlameGraph/flamegraph.pl ${DST_FILE_DIR}/out.folded > ${DST_FILE_DIR}/main.svg
|
||||
|
||||
# perf record -F 99 -p 2401699 -g -- sleep 30
|
||||
# perf script > out.perf
|
||||
# /www/server/dynamic-tracking/FlameGraph/stackcollapse-perf.pl out.perf > out.folded
|
||||
# /www/server/dynamic-tracking/FlameGraph/flamegraph.pl out.folded > php-zend-flame-graph.svg
|
||||
|
||||
# ${APP_DIR}/FlameGraph/stackcollapse.pl $DST_FILE > ${DST_FILE_DIR}/kernel.cbt
|
||||
# ${APP_DIR}/FlameGraph/flamegraph.pl ${DST_FILE_DIR}/kernel.cbt > ${DST_FILE_DIR}/main.svg
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
.screen-all {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.s-right .panel-default{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.s-left .panel-default{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
.data-collect {
|
||||
width: 45px;
|
||||
height: 30px;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
margin-right: 2px;
|
||||
margin-top: 10px;
|
||||
color: #fff;
|
||||
background-color: #20a53a;
|
||||
border-color: #20a53a;
|
||||
}
|
||||
|
||||
|
||||
#file_list .list {
|
||||
list-style: none;
|
||||
border-top: none;
|
||||
border: 1px solid #ececec;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#file_list .list li.active {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
#file_list .tab-con{
|
||||
padding: 0px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#file_list .list li>span {
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#file_list .list li {
|
||||
display: inline-block;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
color: #444;
|
||||
border-bottom: 1px solid #ececec;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#file_list .file {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
#file_list .list li .tootls{
|
||||
width: 70px;
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
/* display: none; */
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
/*.tab-con .tab-block.on {
|
||||
display: inline-block;
|
||||
}*/
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
/* menu start */
|
||||
.menu .current .menu_dynamic-tracking:hover {
|
||||
background-image: url("/plugins/file?name=dynamic-tracking&f=ico.png");
|
||||
}
|
||||
|
||||
.menu .menu_plugin_dynamic-tracking {
|
||||
background-image: url("/plugins/file?name=dynamic-tracking&f=ico.png");
|
||||
}
|
||||
|
||||
/* menu end */
|
||||
@@ -0,0 +1,81 @@
|
||||
<style>
|
||||
.weblog{
|
||||
font-size: 12px;
|
||||
display:inline-block;
|
||||
line-height:30px;
|
||||
}
|
||||
.weblog em{
|
||||
font-style:normal;
|
||||
color:#666;
|
||||
margin: 0 30px;
|
||||
}
|
||||
.weblog span{
|
||||
margin-right:5px;
|
||||
}
|
||||
.weblog a{
|
||||
color:#20a53a;
|
||||
}
|
||||
.firewall-port-box{
|
||||
margin-bottom:15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="container-fluid">
|
||||
<div class="pos-box bgw mtb15">
|
||||
<div class="position f14 c9 pull-left">
|
||||
<a class="plr10 c4" href="/">首页</a>/<span class="plr10 c4">动态追踪</span>
|
||||
</div>
|
||||
|
||||
<div class="search pull-right">
|
||||
<form target="hid" onsubmit='return false;'>
|
||||
<input type="text" id="searchValue" class="ser-text pull-left" placeholder="进程ID" />
|
||||
<button type="button" class="data-collect pull-left">采样</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- //// -->
|
||||
<div class="safe bgw pd15 mtb15" id="ff_box">
|
||||
|
||||
<div id="file_list" style="float:left;width:300px;">
|
||||
<div class="tab-nav">
|
||||
<span class="on">文件列表</span>
|
||||
</div>
|
||||
|
||||
<div class="tab-con">
|
||||
<div class="tab-block on">
|
||||
<ul class="list" style="display: block; height: 94px;"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="flame_graph" style="float:left;">
|
||||
<div class="tab-nav">
|
||||
<span class="on">火焰图</span>
|
||||
</div>
|
||||
|
||||
<div class="tab-con">
|
||||
<iframe class="tab-block on" width="100%" height="100%"
|
||||
src=""
|
||||
frameborder="0"
|
||||
border="0"
|
||||
marginwidth="0"
|
||||
marginheight="0"
|
||||
scrolling="yes"
|
||||
noresize=""
|
||||
allowfullscreen="allowfullscreen"
|
||||
mozallowfullscreen="mozallowfullscreen"
|
||||
msallowfullscreen="msallowfullscreen"
|
||||
oallowfullscreen="oallowfullscreen"
|
||||
webkitallowfullscreen="webkitallowfullscreen"
|
||||
allowfullscreen="true"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- //// -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
function changeDivH(){
|
||||
var l = $(window).height();
|
||||
var w = $(window).width();
|
||||
|
||||
$('#ff_box').css('height',l-80-60);
|
||||
|
||||
$('#file_list').css('height',l-80-60);
|
||||
$('#file_list .tab-con .list').css('height', l-80-60-70);
|
||||
|
||||
|
||||
$('#flame_graph').css('height',l-80-60).css('width',w-300-200-40);
|
||||
$('#flame_graph iframe').css('height',l-80-60-70);
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function(){
|
||||
var tag = $.getUrlParam('tag');
|
||||
if(tag == 'dynamic-tracking'){
|
||||
dynamicTrackingLoad();
|
||||
}
|
||||
});
|
||||
|
||||
function dynamicTrackingLoad(){
|
||||
changeDivH();
|
||||
$(window).resize(function(){
|
||||
changeDivH();
|
||||
});
|
||||
|
||||
//加载采样数据列表
|
||||
dtFileList();
|
||||
}
|
||||
|
||||
|
||||
$('.data-collect').click(function(){
|
||||
layer.msg('开始采样',{icon:0,time:2000});
|
||||
var pid = $('#searchValue').val();
|
||||
|
||||
dtPost('simple_trace', '', {pid:pid}, function(rdata){
|
||||
// console.log(rdata);
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
layer.msg(rdata['msg'],{icon:rdata['status']?1:2,time:2000,shade: [0.3, '#000']});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function dtPost(method, version, args,callback){
|
||||
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
var req_data = {};
|
||||
req_data['name'] = 'dynamic-tracking';
|
||||
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 dtPostCb(method, version, args,callback){
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
|
||||
var pdata = {};
|
||||
pdata['name'] = 'dynamic-tracking';
|
||||
pdata['func'] = method;
|
||||
args['version'] = version;
|
||||
|
||||
if (typeof(args) == 'string'){
|
||||
pdata['args'] = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
pdata['args'] = JSON.stringify(args);
|
||||
}
|
||||
|
||||
$.post('/plugins/callback', pdata, 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 dtFileList(){
|
||||
dtPost('file_list', '', {}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
var alist = rdata.data;
|
||||
|
||||
if (alist.length == 0){
|
||||
var em ='<li class="data-file-list" style="text-align: center;">无数据</li>';
|
||||
$('#file_list .list').html(em);
|
||||
return;
|
||||
}
|
||||
|
||||
var tli = '';
|
||||
for (var i = 0; i < alist.length; i++) {
|
||||
if (i==0){
|
||||
tli +='<li title="双击打开浏览" class="data-file-list active" data-index="'+i+'" data-file="'+alist[i]['name']+'">\
|
||||
<span class="file">'+alist[i]['name']+'</span>\
|
||||
<span class="tootls">\
|
||||
<span class="glyphicon glyphicon-link" aria-hidden="true" title="外部连接"></span>\
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true" title="删除"></span>\
|
||||
</span>\
|
||||
</li>';
|
||||
} else{
|
||||
tli +='<li class="data-file-list" data-index="'+i+'" data-file="'+alist[i]['name']+'">\
|
||||
<span class="file">'+alist[i]['name']+'</span>\
|
||||
<span class="tootls">\
|
||||
<span class="glyphicon glyphicon-link" aria-hidden="true" title="外部连接"></span>\
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true" title="删除"></span>\
|
||||
</span>\
|
||||
</li>';
|
||||
}
|
||||
}
|
||||
|
||||
$('#file_list .list').html(tli);
|
||||
|
||||
dtGetFile(alist[0]['name']);
|
||||
$('#file_list li .file').click(function(){
|
||||
$('#file_list li').removeClass('active');
|
||||
$(this).parent().addClass('active');
|
||||
var i = $(this).parent().data('index');
|
||||
dtGetFile(alist[i]['name']);
|
||||
});
|
||||
|
||||
|
||||
$('#file_list li .glyphicon-link').click(function(){
|
||||
var i = $(this).parent().parent().data('index');
|
||||
var abs_p = alist[i]['abs_path'];
|
||||
|
||||
var durl = '/files/download?filename='+abs_p;
|
||||
window.open(durl);
|
||||
});
|
||||
|
||||
$('#file_list li .glyphicon-trash').click(function(){
|
||||
var i = $(this).parent().parent().data('index');
|
||||
var f = alist[i]['name'];
|
||||
dtPost('remove_file_path', '',{file:f}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
layer.msg(rdata['msg'],{icon:rdata['status']?1:2,time:2000});
|
||||
if (rdata.status){
|
||||
dtFileList();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function dtGetFile(file){
|
||||
dtPost('get_file_path', '', {file:file}, function(data){
|
||||
var rdata = $.parseJSON(data.data);
|
||||
// console.log(rdata);
|
||||
if (!rdata.status){
|
||||
layer.msg(rdata.msg,{icon:0,time:2000,shade: [2, '#000']});
|
||||
return;
|
||||
}
|
||||
var durl = '/files/download?filename='+rdata.data;
|
||||
$('#flame_graph .tab-con .tab-block').attr('src',durl);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
SYS_ARCH=`arch`
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
SYS_ARCH=`arch`
|
||||
|
||||
# apt-get install linux-perf
|
||||
# apt-get update -y
|
||||
# strace -p $(ps -ef|grep "pool www" | awk '{print $2}' | grep -v grep | tr '\n' ',' )
|
||||
|
||||
# perf record -F 99 -p 2401699 -g -- sleep 30
|
||||
# perf script > out.perf
|
||||
# /www/server/dynamic-tracking/FlameGraph/stackcollapse-perf.pl out.perf > out.folded
|
||||
# /www/server/dynamic-tracking/FlameGraph/flamegraph.pl out.folded > php-zend-flame-graph.svg
|
||||
|
||||
# WWW_PID=$(ps -ef|grep "pool www" | awk '{print $2}' | grep -v grep | tr '\n' ',')
|
||||
# WWW_PID=${WWW_PID//,/}
|
||||
# WWW_PID=${var%,}
|
||||
# perf record -F 99 -p "1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1127,1128,1129,1130,1131,1473,1768,2848,2962,21582,35891" \
|
||||
# -g -- sleep 30
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
SYS_ARCH=`arch`
|
||||
|
||||
# 关于macosx使用dtrace
|
||||
|
||||
# https://groups.google.com/g/openresty/c/MswlH_8DDHA
|
||||
# http://dtrace.org/blogs/brendan/2012/11/14/dtracing-in-anger/
|
||||
|
||||
|
||||
# dtrace -x ustackframes=100 -n 'pid$target::mach_msg_trap:entry { @[ustack()] = count(); } tick-30s { exit(0); }' -p 18572 -o out.SystemUIServer_stacks
|
||||
# /Users/midoks/Desktop/mwdev/server/dynamic-tracking/FlameGraph/stackcollapse.pl out.SystemUIServer_stacks > kernel.cbt
|
||||
# /Users/midoks/Desktop/mwdev/server/dynamic-tracking/FlameGraph/flamegraph.pl kernel.cbt > kernel.svg
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
SYS_ARCH=`arch`
|
||||
@@ -0,0 +1,365 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
import io
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
# -----------------------------
|
||||
import google.oauth2.credentials
|
||||
import google_auth_oauthlib.flow
|
||||
from googleapiclient.discovery import build
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from google.auth.transport.requests import Request
|
||||
from googleapiclient.http import MediaFileUpload
|
||||
from googleapiclient.http import MediaIoBaseDownload
|
||||
|
||||
|
||||
class gdriveclient():
|
||||
__plugin_dir = ''
|
||||
__server_dir = ''
|
||||
|
||||
__credentials = "/root/credentials.json"
|
||||
__backup_dir_name = "backup"
|
||||
__creds = None
|
||||
__exclude = ""
|
||||
__scpos = ['https://www.googleapis.com/auth/drive.file']
|
||||
_title = 'Google Drive'
|
||||
_name = 'Google Drive'
|
||||
__debug = False
|
||||
|
||||
_DEFAULT_AUTH_PROMPT_MESSAGE = (
|
||||
'Please visit this URL to authorize this application: {url}')
|
||||
"""str: The message to display when prompting the user for
|
||||
authorization."""
|
||||
_DEFAULT_AUTH_CODE_MESSAGE = (
|
||||
'Enter the authorization code: ')
|
||||
"""str: The message to display when prompting the user for the
|
||||
authorization code. Used only by the console strategy."""
|
||||
|
||||
_DEFAULT_WEB_SUCCESS_MESSAGE = (
|
||||
'The authentication flow has completed, you may close this window.')
|
||||
|
||||
def __init__(self, plugin_dir, server_dir):
|
||||
self.__plugin_dir = plugin_dir
|
||||
self.__server_dir = server_dir
|
||||
self.set_creds()
|
||||
|
||||
# self.get_exclode()
|
||||
|
||||
def setDebug(self, d=False):
|
||||
self.__debug = d
|
||||
|
||||
def D(self, msg=''):
|
||||
if self.__debug:
|
||||
print(msg)
|
||||
|
||||
# 检查gdrive连接
|
||||
def _check_connect(self):
|
||||
try:
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(
|
||||
pageSize=10, fields="nextPageToken, files(id, name)").execute()
|
||||
results.get('files', [])
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
# 设置creds
|
||||
def set_creds(self):
|
||||
token_file = self.__server_dir + '/token.json'
|
||||
if os.path.exists(token_file):
|
||||
with open(token_file, 'rb') as token:
|
||||
tmp_data = json.load(token)['credentials']
|
||||
self.__creds = google.oauth2.credentials.Credentials(
|
||||
tmp_data['token'],
|
||||
tmp_data['refresh_token'],
|
||||
tmp_data['id_token'],
|
||||
tmp_data['token_uri'],
|
||||
tmp_data['client_id'],
|
||||
tmp_data['client_secret'],
|
||||
tmp_data['scopes'])
|
||||
# if not self._check_connect():
|
||||
# return False
|
||||
# else:
|
||||
# return True
|
||||
|
||||
def get_sign_in_url(self):
|
||||
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
|
||||
self.__plugin_dir + '/credentials.json',
|
||||
scopes=self.__scpos)
|
||||
# flow.redirect_uri = 'https://drive.aapanel.com'
|
||||
flow.redirect_uri = 'https://drive.aapanel.com'
|
||||
auth_url, state = flow.authorization_url(
|
||||
access_type='offline',
|
||||
prompt='consent',
|
||||
include_granted_scopes='false')
|
||||
return auth_url, state
|
||||
|
||||
def set_auth_url(self, url):
|
||||
token_file = self.__server_dir + '/token.json'
|
||||
if os.path.exists(token_file):
|
||||
return mw.returnJson(True, "验证成功")
|
||||
|
||||
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
|
||||
self.__plugin_dir + '/credentials.json',
|
||||
scopes=self.__scpos,
|
||||
state=url.split('state=')[1].split('&code=')[0])
|
||||
# flow.redirect_uri = 'https://localhost'
|
||||
flow.redirect_uri = 'https://drive.aapanel.com'
|
||||
flow.fetch_token(authorization_response=url)
|
||||
credentials = flow.credentials
|
||||
|
||||
credentials_data = {}
|
||||
credentials_data['credentials'] = {
|
||||
'token': credentials.token,
|
||||
'id_token': credentials.id_token,
|
||||
'refresh_token': credentials.refresh_token,
|
||||
'token_uri': credentials.token_uri,
|
||||
'client_id': credentials.client_id,
|
||||
'client_secret': credentials.client_secret,
|
||||
'scopes': credentials.scopes}
|
||||
with open(token_file, 'w') as token:
|
||||
json.dump(credentials_data, token)
|
||||
if not self.set_creds():
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
return mw.returnJson(True, "验证成功")
|
||||
|
||||
# 获取token
|
||||
def get_token(self, get):
|
||||
token_file = self.__server_dir + '/token.json'
|
||||
import requests
|
||||
try:
|
||||
respone = requests.get("https://www.google.com", timeout=2)
|
||||
except:
|
||||
return mw.returnJson(False, "连接谷歌失败")
|
||||
if respone.status_code != 200:
|
||||
return mw.returnJson(False, "连接谷歌失败")
|
||||
if not self.set_creds():
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
if not os.path.exists(token_file):
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
return mw.returnJson(True, "验证成功")
|
||||
|
||||
# 获取auth_url
|
||||
def get_auth_url(self, get):
|
||||
self.get_sign_in_url()
|
||||
if os.path.exists("/tmp/auth_url"):
|
||||
return mw.readFile("/tmp/auth_url")
|
||||
|
||||
# 检查连接
|
||||
def check_connect(self, get):
|
||||
token_file = self.__server_dir + '/token.json'
|
||||
if os.path.exists(token_file):
|
||||
with open(token_file, 'rb') as token:
|
||||
self.set_creds()
|
||||
else:
|
||||
self.D("Failed to get Google token, please verify before use")
|
||||
return mw.returnJson(True, "Failed to get Google token, please verify before use")
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(
|
||||
pageSize=10, fields="nextPageToken, files(id, name)").execute()
|
||||
try:
|
||||
results.get('files', [])
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
return mw.returnJson(True, "验证成功")
|
||||
except:
|
||||
return mw.returnJson(False, "验证失败,请根据页面1 2 3 步骤完成验证")
|
||||
|
||||
def _get_filename(self, filename):
|
||||
l = filename.split("/")
|
||||
return l[-1]
|
||||
|
||||
def _create_folder_cycle(self, filepath):
|
||||
l = filepath.split("/")
|
||||
fid_list = []
|
||||
for i in l:
|
||||
if not i:
|
||||
continue
|
||||
fid = self.__get_folder_id(i)
|
||||
if fid:
|
||||
fid_list.append(fid)
|
||||
continue
|
||||
if not fid_list:
|
||||
fid_list.append("")
|
||||
fid_list.append(self.create_folder(i, fid_list[-1]))
|
||||
return fid_list[-1]
|
||||
|
||||
def build_object_name(self, data_type, file_name):
|
||||
"""根据数据类型构建对象存储名称
|
||||
|
||||
:param data_type:
|
||||
:param file_name:
|
||||
:return:
|
||||
"""
|
||||
|
||||
import re
|
||||
prefix_dict = {
|
||||
"site": "web",
|
||||
"database": "db",
|
||||
"path": "path",
|
||||
}
|
||||
|
||||
if not prefix_dict.get(data_type):
|
||||
print("data_type 类型错误!!!")
|
||||
exit(1)
|
||||
|
||||
file_regx = prefix_dict.get(data_type) + "_(.+)_20\d+_\d+\."
|
||||
sub_search = re.search(file_regx.lower(), file_name)
|
||||
sub_path_name = ""
|
||||
if sub_search:
|
||||
sub_path_name = sub_search.groups()[0]
|
||||
sub_path_name += '/'
|
||||
# 构建OS存储路径
|
||||
object_name = self.__backup_dir_name + \
|
||||
'/{}/{}'.format(data_type, sub_path_name)
|
||||
|
||||
if object_name[:1] == "/":
|
||||
object_name = object_name[1:]
|
||||
return object_name
|
||||
|
||||
# 上传文件
|
||||
def upload_file(self, filename, data_type=None):
|
||||
"""
|
||||
get.filename 上传后的文件名
|
||||
get.filepath 上传文件路径
|
||||
被面板新版计划任务调用时
|
||||
get表示file_name
|
||||
:param get:
|
||||
:return:
|
||||
"""
|
||||
# filename = filename
|
||||
filepath = self.build_object_name(data_type, filename)
|
||||
_filename = self._get_filename(filename)
|
||||
self.D(filepath)
|
||||
self.D(filename)
|
||||
|
||||
parents = self._create_folder_cycle(filepath)
|
||||
self.D(parents)
|
||||
drive_service = build('drive', 'v3', credentials=self.__creds)
|
||||
file_metadata = {'name': _filename, 'parents': [parents]}
|
||||
media = MediaFileUpload(filename, resumable=True)
|
||||
file = drive_service.files().create(
|
||||
body=file_metadata, media_body=media, fields='id').execute()
|
||||
self.D('Upload Success ,File ID: %s' % file.get('id'))
|
||||
return True
|
||||
|
||||
def _get_file_id(self, filename):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(pageSize=10, q="name='{}'".format(
|
||||
filename), fields="nextPageToken, files(id, name)").execute()
|
||||
items = results.get('files', [])
|
||||
if not items:
|
||||
return []
|
||||
else:
|
||||
for item in items:
|
||||
return item["id"]
|
||||
|
||||
def delete_file(self, filename=None, data_type=None):
|
||||
file_id = self._get_file_id(filename)
|
||||
self.delete_file_by_id(file_id)
|
||||
return True
|
||||
|
||||
def delete_file_by_id(self, file_id):
|
||||
self.D("delete id:{}".format(file_id))
|
||||
try:
|
||||
drive_service = build('drive', 'v3', credentials=self.__creds)
|
||||
drive_service.files().delete(fileId=file_id).execute()
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
# 创建目录
|
||||
def create_folder(self, folder_name, parents=""):
|
||||
self.D(self.__creds)
|
||||
self.D("folder_name: {}".format(folder_name))
|
||||
self.D("parents: {}".format(parents))
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
file_metadata = {
|
||||
'name': folder_name,
|
||||
'mimeType': 'application/vnd.google-apps.folder'
|
||||
}
|
||||
if parents:
|
||||
file_metadata['parents'] = [parents]
|
||||
folder = service.files().create(body=file_metadata, fields='id').execute()
|
||||
self.D('Create Folder ID: %s' % folder.get('id'))
|
||||
return folder.get('id')
|
||||
|
||||
def get_rootdir_id(self, folder_name='backup'):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(pageSize=10, q="name='{}' and mimeType='application/vnd.google-apps.folder'".format(folder_name),
|
||||
fields="nextPageToken, files(id, name,size,parents,webViewLink)").execute()
|
||||
items = results.get('files', [])
|
||||
if len(items) == 0:
|
||||
self.create_folder(folder_name)
|
||||
return self.get_rootdir_id(folder_name)
|
||||
|
||||
return items[0]['parents'][0]
|
||||
|
||||
# 获取目录id
|
||||
def __get_folder_id(self, floder_name):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(pageSize=10, q="name='{}' and mimeType='application/vnd.google-apps.folder'".format(floder_name),
|
||||
fields="nextPageToken, files(id, name)").execute()
|
||||
items = results.get('files', [])
|
||||
if not items:
|
||||
return []
|
||||
else:
|
||||
for item in items:
|
||||
return item["id"]
|
||||
|
||||
def get_res_info(self, rid):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().get(fileId='{}'.format(rid)).execute()
|
||||
return results
|
||||
|
||||
def get_id_list(self, driveId=''):
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
results = service.files().list(pageSize=10, driveId="{}".format(driveId),
|
||||
fields="nextPageToken, files(id, name,size,parents)").execute()
|
||||
items = results.get('files', [])
|
||||
return items
|
||||
|
||||
def get_list(self, dir_id='', next_page_token=''):
|
||||
if dir_id == '':
|
||||
dir_id = self.get_rootdir_id(self.__backup_dir_name)
|
||||
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
cmd_query = "trashed=false and '{}' in parents".format(dir_id)
|
||||
results = service.files().list(pageSize=10, q=cmd_query, orderBy='folder asc',
|
||||
fields="nextPageToken, files(id, name,size,createdTime,parents,webViewLink)").execute()
|
||||
items = results.get('files', [])
|
||||
nextPageToken = results.get('nextPageToken', [])
|
||||
# print(items)
|
||||
# print(nextPageToken)
|
||||
return items
|
||||
|
||||
def get_exclode(self, exclude=[]):
|
||||
if not exclude:
|
||||
tmp_exclude = os.getenv('MW_EXCLUDE')
|
||||
if tmp_exclude:
|
||||
exclude = tmp_exclude.split(',')
|
||||
if not exclude:
|
||||
return ""
|
||||
for ex in exclude:
|
||||
self.__exclude += " --exclude=\"" + ex + "\""
|
||||
self.__exclude += " "
|
||||
return self.__exclude
|
||||
|
||||
def download_file(self, filename):
|
||||
file_id = self._get_file_id(filename)
|
||||
service = build('drive', 'v3', credentials=self.__creds)
|
||||
request = service.files().get_media(fileId=file_id)
|
||||
with open('/tmp/{}'.format(filename), 'wb') as fh:
|
||||
downloader = MediaIoBaseDownload(fh, request)
|
||||
done = False
|
||||
while done is False:
|
||||
status, done = downloader.next_chunk()
|
||||
print("Download %d%%." % int(status.progress() * 100))
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"web": {
|
||||
"client_id": "226011946234-d3e1vashgag64utjedu1ljt9u39ncrpq.apps.googleusercontent.com",
|
||||
"project_id": "light-willow-341609",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_secret": "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",
|
||||
"redirect_uris": [
|
||||
"https://drive.aapanel.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"web": {
|
||||
"client_id": "540181629246-1horo9i4htamdbhiqar9rcbq33bqe2ob.apps.googleusercontent.com",
|
||||
"project_id": "plated-inn-369901",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_secret": "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",
|
||||
"redirect_uris": ["https://drive.aapanel.com"]
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,310 @@
|
||||
<style>
|
||||
.upyunCon {
|
||||
height: 428px;
|
||||
}
|
||||
|
||||
.up-place {
|
||||
height: 62px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.up-place .btn {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.up-place .place-input {
|
||||
background-color: #f3f3f3;
|
||||
border: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 28px;
|
||||
overflow: hidden;
|
||||
margin: 1px 0 0 -1px;
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
.place-input ul {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.place-input ul li {
|
||||
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
.place-input ul li a {
|
||||
height: 28px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.upyunlist {
|
||||
height: 516px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.up-bottom {
|
||||
background-color: #fafafa;
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.up-use {
|
||||
line-height: 50px
|
||||
}
|
||||
|
||||
.list-list .cursor span {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.btn-title {
|
||||
margin-top: 1px
|
||||
}
|
||||
|
||||
.tip {
|
||||
font-size: 10px;
|
||||
font-style: oblique;
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
<div class="upyunCon">
|
||||
<div class="up-place pd15">
|
||||
<button id="backBtn" class="btn btn-default btn-sm glyphicon glyphicon-arrow-left pull-left" title="后退"></button>
|
||||
<input id="myPath" type="hidden" value="">
|
||||
<input id="curPath" type="hidden" value="">
|
||||
<div class="place-input pull-left">
|
||||
<div style="width:1400px;height:28px"><ul></ul></div>
|
||||
</div>
|
||||
<button class="refreshBtn btn btn-default btn-sm glyphicon glyphicon-refresh pull-left mr20" title="刷新" style="margin-left:-1px;"></button>
|
||||
<button class="btn btn-default btn-sm pull-right btn-title" onclick="authApi()">授权</button>
|
||||
<button class="btn btn-default btn-sm pull-right mr20 btn-title" onclick="createDir()">新建文件夹</button>
|
||||
</div>
|
||||
|
||||
<div class="upyunlist pd15">
|
||||
<div class="divtable" style="margin-bottom:15px">
|
||||
<table class="table table-hover">
|
||||
<thead><tr><th>名称</th><th>大小</th><th>更新时间</th><th class="text-right">操作</th></tr></thead>
|
||||
<tbody class="list-list"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style type="text/css">
|
||||
.check_api {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.up-place {
|
||||
height: 62px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.up-place .btn {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.up-place .place-input {
|
||||
background-color: #f3f3f3;
|
||||
border: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 28px;
|
||||
overflow: hidden;
|
||||
margin: 1px 0 0 -1px;
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
.place-input ul {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.place-input ul li {
|
||||
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
.place-input ul li a {
|
||||
height: 28px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.upyunlist {
|
||||
height: 546px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.up-bottom {
|
||||
background-color: #fafafa;
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.up-use {
|
||||
line-height: 50px
|
||||
}
|
||||
|
||||
.list-list .cursor span {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.btn-title {
|
||||
margin-top: 1px
|
||||
}
|
||||
|
||||
.step_item{
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.step_item .serial_box{
|
||||
display: inline-block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.step_item .serial{
|
||||
width: 70px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
}
|
||||
.step_item .serial span{
|
||||
display: inline-block;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
line-height: 28px;
|
||||
font-size: 11px;
|
||||
border-radius: 50%;
|
||||
color: #20a53a;
|
||||
border: 2px solid #20a53a;
|
||||
}
|
||||
.step_item .serial_title{
|
||||
margin-bottom: 10px;
|
||||
font-size: 15px;
|
||||
line-height: 30px;
|
||||
color: #666;
|
||||
}
|
||||
.step_two_url{
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
width: 380px;
|
||||
/*text-overflow: ellipsis;*/
|
||||
white-space: nowrap;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
margin-right: 15px;
|
||||
border-radius: 2px;
|
||||
padding: 0 10px;
|
||||
float: left;
|
||||
width:360px;
|
||||
padding-right: 35px;
|
||||
}
|
||||
.btn_btlink{
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
border: 1px solid #20a53a;
|
||||
color: #fff;
|
||||
background-color: #20a53a;
|
||||
margin-right:10px;
|
||||
}
|
||||
.btn_btlink:hover{
|
||||
color: #fff;
|
||||
background-color: #10952a;
|
||||
border-color: #398439;
|
||||
}
|
||||
.btn_btlink a:visited{
|
||||
color: #fff;
|
||||
background-color: #10952a;
|
||||
border-color: #398439;
|
||||
}
|
||||
.view_video{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.view_video ul li{
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.setp_one i{
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 25px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
.google_drive{
|
||||
width:465px;
|
||||
height:100px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/html" id="check_api">
|
||||
<div class="check_api">
|
||||
<div class="step_two">
|
||||
<div class="step_item">
|
||||
<div class="serial"><span>1</span></div>
|
||||
<div class="serial_box">
|
||||
<div class="serial_title">阅读简易操作教程:如何获取Google Drive授权?</div>
|
||||
<div class="serial_conter">
|
||||
<div class="view_video">
|
||||
<ul>
|
||||
<li>1. 点击下面第<div class="serial" style="float: none;width: 45px;"><span>2</span></div>步中的 打开授权链接。<li>
|
||||
<li>2. 在新窗口页面上登录Google Drive账号。阅读授权权限,并同意。<li>
|
||||
<li>3. 页面跳转后,将浏览器的地址栏地址复制到第<div class="serial" style="float: none;width: 45px;"><span>3</span></div>步的文本框中。<li>
|
||||
<li>4. 点击 获取授权,随即完成授权。<li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step_item pb15">
|
||||
<div class="serial"><span>2</span></div>
|
||||
<div class="serial_box">
|
||||
<div class="serial_title">操作1:👇打开授权链接,根据网页提示对插件进行授权。</div>
|
||||
<div class="serial_conter step_two" style="width: 500px;">
|
||||
<input class="bt-input-text mr5 step_two_url" type="text" disabled>
|
||||
<span class="ico-copy mr10" data-copy="" style="vertical-align: middle;cursor: pointer;margin-left: -37px;margin-right: 20px;"></span>
|
||||
<a href="" class="btn_btlink open_btlink" target="_blank" style="padding: 7px 10px;">打开授权链接</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="step_item">
|
||||
<div class="serial"><span>3</span></div>
|
||||
<div class="serial_box">
|
||||
<div class="serial_title">操作2:复制回浏览器跳转后的地址:</div>
|
||||
<div class="serial_conter">
|
||||
<textarea row="3" placeholder="验证URL地址" class="bt-input-text google_drive" style="resize: none;"/></br>
|
||||
<button type="button" class="btn btn-success btn-sm set_auth_btn">获取授权</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/javascript" src="/plugins/file?name=gdrive&f=js/gdrive.js"></script>
|
||||
<script type="text/javascript">
|
||||
$.getScript( "/plugins/file?name=gdrive&f=js/gdrive.js", function(){
|
||||
gdList('');
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,338 @@
|
||||
# coding:utf-8
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
|
||||
# print(sys.platform)
|
||||
if sys.platform != "darwin":
|
||||
os.chdir("/www/server/mdserver-web")
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
import db
|
||||
|
||||
_ver = sys.version_info
|
||||
is_py2 = (_ver[0] == 2)
|
||||
is_py3 = (_ver[0] == 3)
|
||||
|
||||
DEBUG = False
|
||||
|
||||
if is_py2:
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
|
||||
app_debug = False
|
||||
if mw.isAppleSystem():
|
||||
app_debug = True
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'gdrive'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def in_array(name, arr=[]):
|
||||
for x in arr:
|
||||
if name == x:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
sys.path.append(getPluginDir() + "/class")
|
||||
from gdriveclient import gdriveclient
|
||||
|
||||
|
||||
gd = gdriveclient(getPluginDir(), getServerDir())
|
||||
gd.setDebug(False)
|
||||
|
||||
|
||||
def getArgs():
|
||||
args = sys.argv[2:]
|
||||
tmp = {}
|
||||
args_len = len(args)
|
||||
if args_len == 1:
|
||||
t = args[0].strip('{').strip('}')
|
||||
if t.strip() == '':
|
||||
tmp = []
|
||||
else:
|
||||
t = t.split(':', 1)
|
||||
tmp[t[0]] = t[1]
|
||||
elif args_len > 1:
|
||||
for i in range(len(args)):
|
||||
t = args[i].split(':', 1)
|
||||
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 isAuthApi():
|
||||
cfg = getServerDir() + "/token.json"
|
||||
if os.path.exists(cfg):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def getConf():
|
||||
if not isAuthApi():
|
||||
sign_in_url, state = gd.get_sign_in_url()
|
||||
return mw.returnJson(False, "未授权!", {'auth_url': sign_in_url})
|
||||
return mw.returnJson(True, "OK")
|
||||
|
||||
|
||||
def setAuthUrl():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['url'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
url = args['url']
|
||||
|
||||
try:
|
||||
if url.startswith("http://"):
|
||||
url = url.replace("http://", "https://")
|
||||
token = gd.set_auth_url(url)
|
||||
# gd.store_token(token)
|
||||
# gd.store_user()
|
||||
return mw.returnJson(True, "授权成功!")
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, "授权失败2!:" + str(e))
|
||||
return mw.returnJson(False, "授权失败!:" + str(e))
|
||||
|
||||
|
||||
def clearAuth():
|
||||
token = getServerDir() + "/token.json"
|
||||
if os.path.exists(token):
|
||||
os.remove(token)
|
||||
return mw.returnJson(True, "清空授权成功!")
|
||||
|
||||
|
||||
def getList():
|
||||
if not isAuthApi():
|
||||
return mw.returnJson(False, "未配置,请点击`授权`", [])
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file_id'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
try:
|
||||
flist = gd.get_list(args['file_id'])
|
||||
return mw.returnJson(True, "ok", flist)
|
||||
except Exception as e:
|
||||
return mw.returnJson(False, str(e), [])
|
||||
|
||||
|
||||
def createDir():
|
||||
if not isAuthApi():
|
||||
return mw.returnJson(False, "未配置,请点击`授权`", [])
|
||||
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['parents', 'name'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
isok = gd.create_folder(args['name'], args['parents'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "创建成功")
|
||||
return mw.returnJson(False, "创建失败")
|
||||
|
||||
|
||||
def deleteDir():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['dir_name', 'path'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
isok = gd.delete_file_by_id(args['dir_name'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "删除成功")
|
||||
return mw.returnJson(False, "文件不为空,删除失败!")
|
||||
|
||||
|
||||
def deleteFile():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['path', 'filename'])
|
||||
if not data[0]:
|
||||
return data[1]
|
||||
|
||||
isok = gd.delete_file(args['filename'])
|
||||
if isok:
|
||||
return mw.returnJson(True, "删除成功")
|
||||
return mw.returnJson(False, "删除失败")
|
||||
|
||||
|
||||
def findPathName(path, filename):
|
||||
f = os.scandir(path)
|
||||
l = []
|
||||
for ff in f:
|
||||
t = {}
|
||||
if ff.name.find(filename) > -1:
|
||||
t['filename'] = path + '/' + ff.name
|
||||
l.append(t)
|
||||
return l
|
||||
|
||||
|
||||
def backupAllFunc(stype):
|
||||
if not isAuthApi():
|
||||
mw.echoInfo("未授权API,无法使用!!!")
|
||||
return ''
|
||||
|
||||
os.chdir(mw.getRunDir())
|
||||
backup_dir = mw.getBackupDir()
|
||||
run_dir = mw.getRunDir()
|
||||
|
||||
stype = sys.argv[1]
|
||||
name = sys.argv[2]
|
||||
num = sys.argv[3]
|
||||
|
||||
prefix_dict = {
|
||||
"site": "web",
|
||||
"database": "db",
|
||||
"path": "path",
|
||||
}
|
||||
|
||||
backups = []
|
||||
sql = db.Sql()
|
||||
|
||||
# print("stype:", stype)
|
||||
# 提前获取-清理多余备份
|
||||
if stype == 'site':
|
||||
pid = sql.table('sites').where('name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('0', pid)).field('id,filename').select()
|
||||
if stype == 'database':
|
||||
db_path = mw.getServerDir() + '/mysql'
|
||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
|
||||
'name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('1', pid)).field('id,filename').select()
|
||||
if stype == 'path':
|
||||
backup_path = backup_dir + '/path'
|
||||
_name = 'path_{}'.format(os.path.basename(name))
|
||||
backups = findPathName(backup_path, _name)
|
||||
|
||||
# 其他类型关系性数据库(mysql类的)
|
||||
if stype.find('database_') > -1:
|
||||
plugin_name = stype.replace('database_', '')
|
||||
db_path = mw.getServerDir() + '/' + plugin_name
|
||||
pid = mw.M('databases').dbPos(db_path, 'mysql').where(
|
||||
'name=?', (name,)).getField('id')
|
||||
backups = sql.table('backup').where(
|
||||
'type=? and pid=?', ('1', pid)).field('id,filename').select()
|
||||
|
||||
args = stype + " " + name + " " + num
|
||||
cmd = 'python3 ' + run_dir + '/scripts/backup.py ' + args
|
||||
if stype.find('database_') > -1:
|
||||
plugin_name = stype.replace('database_', '')
|
||||
args = "database " + name + " " + num
|
||||
cmd = 'python3 ' + run_dir + '/plugins/' + \
|
||||
plugin_name + '/scripts/backup.py ' + args
|
||||
|
||||
if stype == 'path':
|
||||
name = os.path.basename(name)
|
||||
|
||||
# print("cmd:", cmd)
|
||||
os.system(cmd)
|
||||
|
||||
# 开始执行上传信息.
|
||||
if stype.find('database_') > -1:
|
||||
bk_name = 'database'
|
||||
plugin_name = stype.replace('database_', '')
|
||||
bk_prefix = plugin_name + '/db'
|
||||
stype = 'database'
|
||||
else:
|
||||
bk_prefix = prefix_dict[stype]
|
||||
bk_name = stype
|
||||
|
||||
find_path = backup_dir + '/' + bk_name + '/' + bk_prefix + '_' + name
|
||||
find_new_file = "ls " + find_path + \
|
||||
"_* | grep '.gz' | cut -d \ -f 1 | awk 'END {print}'"
|
||||
|
||||
# print(find_new_file)
|
||||
|
||||
filename = mw.execShell(find_new_file)[0].strip()
|
||||
if filename == "":
|
||||
mw.echoInfo("not find upload file!")
|
||||
return False
|
||||
|
||||
mw.echoInfo("准备上传文件 {}".format(filename))
|
||||
mw.echoStart('开始上传')
|
||||
# gd.setDebug(False)
|
||||
gd.upload_file(filename, stype)
|
||||
mw.echoEnd('上传成功')
|
||||
|
||||
# print(backups)
|
||||
backups = sorted(backups, key=lambda x: x['filename'], reverse=False)
|
||||
mw.echoStart('开始删除远程备份')
|
||||
num = int(num)
|
||||
sep = len(backups) - num
|
||||
if sep > -1:
|
||||
for backup in backups:
|
||||
fn = os.path.basename(backup['filename'])
|
||||
gd.delete_file(fn, stype)
|
||||
mw.echoInfo("---已清理远程过期备份文件:" + fn)
|
||||
sep -= 1
|
||||
if sep < 0:
|
||||
break
|
||||
mw.echoEnd('结束删除远程备份')
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
def installPreInspection():
|
||||
return 'ok'
|
||||
|
||||
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 == 'install_pre_inspection':
|
||||
print(installPreInspection())
|
||||
elif func == 'conf':
|
||||
print(getConf())
|
||||
elif func == 'set_auth_url':
|
||||
print(setAuthUrl())
|
||||
elif func == 'clear_auth':
|
||||
print(clearAuth())
|
||||
elif func == "get_list":
|
||||
print(getList())
|
||||
elif func == "create_dir":
|
||||
print(createDir())
|
||||
elif func == "delete_dir":
|
||||
print(deleteDir())
|
||||
elif func == 'delete_file':
|
||||
print(deleteFile())
|
||||
elif in_array(func, ['site', 'database', 'path']) or func.find('database_') > -1:
|
||||
print(backupAllFunc(func))
|
||||
else:
|
||||
print('error')
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"hook":["backup"],
|
||||
"id":998,
|
||||
"title":"谷歌云网盘",
|
||||
"tip":"lib",
|
||||
"name":"gdrive",
|
||||
"type":"扩展",
|
||||
"ps":"备份你的数据到谷歌云网盘",
|
||||
"versions":"2.0",
|
||||
"shell":"install.sh",
|
||||
"checks": "server/gdrive",
|
||||
"path":"server/gdrive",
|
||||
"author":"google",
|
||||
"home":"https://drive.google.com/",
|
||||
"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":"5"
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||
export PATH
|
||||
|
||||
# cd /www/server/mdserver-web/plugins/gdrive && /bin/bash install.sh install 2.0
|
||||
|
||||
|
||||
curPath=`pwd`
|
||||
rootPath=$(dirname "$curPath")
|
||||
rootPath=$(dirname "$rootPath")
|
||||
serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
|
||||
PATH=$PATH:${rootPath}/bin
|
||||
export PATH
|
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
VERSION=$2
|
||||
|
||||
Install_App()
|
||||
{
|
||||
tmp_ping=`ping -c 1 google.com 2>&1`
|
||||
echo $tmp_ping
|
||||
if [ $? -eq 0 ];then
|
||||
tmp=`python -V 2>&1|awk '{print $2}'`
|
||||
pVersion=${tmp:0:3}
|
||||
|
||||
|
||||
which pip
|
||||
if [ "$?" -eq "0" ];then
|
||||
tmp=$(pip list|grep google-api-python-client|awk '{print $2}')
|
||||
if [ "$tmp" != '2.39.0' ];then
|
||||
pip install --upgrade google-api-python-client
|
||||
# pip uninstall google-api-python-client -y
|
||||
pip install -I google-api-python-client==2.39.0 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
tmp=$(pip list|grep google-auth-httplib2|awk '{print $2}')
|
||||
if [ "$tmp" != '0.1.0' ];then
|
||||
pip uninstall google-auth-httplib2 -y
|
||||
pip install -I google-auth-httplib2==0.1.0 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
tmp=$(pip list|grep google-auth-oauthlib|awk '{print $2}')
|
||||
if [ "$tmp" != '0.5.0' ];then
|
||||
# pip uninstall google-auth-oauthlib -y
|
||||
pip install -I google-auth-oauthlib==0.5.0 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
tmp=$(pip list|grep -E '^httplib2'|awk '{print $2}')
|
||||
if [ "$tmp" != '0.18.1' ];then
|
||||
# pip uninstall httplib2 -y
|
||||
pip install -I httplib2==0.18.1 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
else
|
||||
pip install -I pyOpenSSL
|
||||
pip install -I google-api-python-client==2.39.0 google-auth-httplib2==0.1.0 google-auth-oauthlib==0.5.0 -i https://pypi.Python.org/simple
|
||||
pip install -I httplib2==0.18.1 -i https://pypi.Python.org/simple
|
||||
fi
|
||||
echo '正在安装脚本文件...' > $install_tmp
|
||||
|
||||
mkdir -p $serverPath/gdrive
|
||||
echo "${VERSION}" > $serverPath/gdrive/version.pl
|
||||
echo '安装完成' > $install_tmp
|
||||
else
|
||||
echo '服务器连接不上谷歌云!安装失败!' > $install_tmp
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
Uninstall_App()
|
||||
{
|
||||
rm -rf $serverPath/gdrive
|
||||
echo '卸载完成' > $install_tmp
|
||||
}
|
||||
|
||||
|
||||
action=$1
|
||||
type=$2
|
||||
|
||||
echo $action $type
|
||||
if [ "${action}" == 'install' ];then
|
||||
Install_App
|
||||
else
|
||||
Uninstall_App
|
||||
fi
|
||||
@@ -0,0 +1,260 @@
|
||||
|
||||
function gdPost(method,args,callback){
|
||||
var _args = null;
|
||||
if (typeof(args) == 'string'){
|
||||
_args = JSON.stringify(toArrayObject(args));
|
||||
} else {
|
||||
_args = JSON.stringify(args);
|
||||
}
|
||||
|
||||
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
|
||||
$.post('/plugins/run', {name:'gdrive', func:method, args:_args}, 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 createDir(){
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: "400px",
|
||||
title: "创建目录",
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
btn: ['确定','取消'],
|
||||
content:'<div class="bingfa bt-form c6" style="padding-bottom: 10px;">\
|
||||
<p>\
|
||||
<span class="span_tit">目录名称:</span>\
|
||||
<input style="width: 200px;" type="text" name="newPath" value="">\
|
||||
</p>\
|
||||
</div>',
|
||||
success:function(){
|
||||
$("input[name='newPath']").focus().keyup(function(e){
|
||||
if(e.keyCode == 13) $(".layui-layer-btn0").click();
|
||||
});
|
||||
},
|
||||
yes:function(index,layero){
|
||||
var name = $("input[name='newPath']").val();
|
||||
if(name == ''){
|
||||
layer.msg('目录名称不能为空!',{icon:2});
|
||||
return;
|
||||
}
|
||||
var parents = $("#myPath").val();
|
||||
var cur_file_id = $('#curPath').val();
|
||||
if (cur_file_id!=''){
|
||||
parents = cur_file_id;
|
||||
}
|
||||
|
||||
var dirname = name;
|
||||
var loadT = layer.msg('正在创建目录['+dirname+']...',{icon:16,time:0,shade: [0.3, '#000']});
|
||||
gdPost('create_dir', {parents:parents,name:dirname}, function(data){
|
||||
layer.close(loadT);
|
||||
var rdata = $.parseJSON(data.data);
|
||||
if(rdata.status) {
|
||||
showMsg(rdata.msg, function(){
|
||||
layer.close(index);
|
||||
var file_id = $('#myPath').val();
|
||||
if (cur_file_id!=''){
|
||||
file_id = cur_file_id;
|
||||
}
|
||||
gdList(file_id);
|
||||
} ,{icon:1}, 2000);
|
||||
} else{
|
||||
layer.msg(rdata.msg,{icon:2});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//设置API
|
||||
function authApi(){
|
||||
|
||||
gdPost('conf', {}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
|
||||
// console.log(rdata);
|
||||
// console.log(rdata.data.auth_url);
|
||||
var apicon = '';
|
||||
if (rdata.status){
|
||||
|
||||
var html = '';
|
||||
html += '<button id="clear_auth" onclick="clearAuth();" class="btn btn-default btn-sm">清空配置</button>';
|
||||
|
||||
var loadOpen = layer.open({
|
||||
type: 1,
|
||||
title: '已授权',
|
||||
area: '240px',
|
||||
content:'<div class="change-default pd20">'+html+'</div>',
|
||||
success: function(){
|
||||
$('#clear_auth').click(function(){
|
||||
gdPost('clear_auth', {}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
layer.close(loadOpen);
|
||||
gdList('');
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return true;
|
||||
|
||||
} else{
|
||||
apicon = '<div class="new_form">'+$("#check_api").html()+'</div>';
|
||||
}
|
||||
|
||||
var layer_auth = layer.open({
|
||||
type: 1,
|
||||
area: "620px",
|
||||
title: "Google Drive 授权",
|
||||
closeBtn: 1,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
content:apicon,
|
||||
success:function(layero,index){
|
||||
// console.log(layero,index);
|
||||
if (!rdata.status){
|
||||
$('.check_api .step_two_url').val(rdata.data['auth_url']);
|
||||
$('.check_api .open_btlink').attr('href',rdata.data['auth_url']);
|
||||
|
||||
$('.check_api .ico-copy').click(function(){
|
||||
copyPass(rdata.data['auth_url']);
|
||||
});
|
||||
|
||||
$('.check_api .set_auth_btn').click(function(){
|
||||
|
||||
var url = $('.check_api .google_drive').val();
|
||||
if ( url == ''){
|
||||
layer.msg("验证URL不能为空",{icon:2});
|
||||
return;
|
||||
}
|
||||
// console.log(url);
|
||||
gdPost('set_auth_url', {url:url}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
var show_time = 2000;
|
||||
if (!rdata.status){
|
||||
show_time = 10000;
|
||||
}
|
||||
|
||||
showMsg(rdata.msg,function(){
|
||||
if (rdata.status){
|
||||
layer.close(layer_auth);
|
||||
gdList('');
|
||||
}
|
||||
},{icon:rdata.status?1:2},show_time);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//计算当前目录偏移
|
||||
function upPathLeft(){
|
||||
var UlWidth = $(".place-input ul").width();
|
||||
var SpanPathWidth = $(".place-input").width() - 20;
|
||||
var Ml = UlWidth - SpanPathWidth;
|
||||
if(UlWidth > SpanPathWidth ){
|
||||
$(".place-input ul").css("left",-Ml)
|
||||
}
|
||||
else{
|
||||
$(".place-input ul").css("left",0)
|
||||
}
|
||||
}
|
||||
|
||||
function getGDTime(a) {
|
||||
return new Date(a).format("yyyy/MM/dd hh:mm:ss")
|
||||
}
|
||||
|
||||
function gdList(file_id){
|
||||
$('#curPath').val(file_id);
|
||||
gdPost('get_list', {file_id:file_id}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
console.log(rdata);
|
||||
if(rdata.status === false){
|
||||
showMsg(rdata.msg,function(){
|
||||
authApi();
|
||||
},{icon:2},2000);
|
||||
return;
|
||||
}
|
||||
|
||||
var mlist = rdata.data;
|
||||
var listBody = '';
|
||||
var listFiles = '';
|
||||
for(var i=0;i<mlist.length;i++){
|
||||
if(mlist[i].size == null){
|
||||
listFiles += '<tr><td class="cursor" onclick="gdList(\''+(mlist[i].id).replace('//','/')+'\')"><span class="ico ico-folder"></span>\<span>'+mlist[i].name+'</span></td>\
|
||||
<td>-</td>\
|
||||
<td>-</td>\
|
||||
<td class="text-right"><a class="btlink" onclick="deleteFile(\''+mlist[i].id+'\', true)">删除</a></td></tr>'
|
||||
}else{
|
||||
listFiles += '<tr><td class="cursor"><span class="ico ico-file"></span><span>'+mlist[i].name+'</span></td>\
|
||||
<td>'+toSize(mlist[i].size)+'</td>\
|
||||
<td>'+getGDTime(mlist[i].createdTime)+'</td>\
|
||||
<td class="text-right"><a target="_blank" href="'+mlist[i].webViewLink+'" class="btlink">下载</a> | <a class="btlink" onclick="deleteFile(\''+mlist[i].name+'\', false)">删除</a></td></tr>'
|
||||
}
|
||||
}
|
||||
listBody += listFiles;
|
||||
var pathLi = '<li><a title="根目录" onclick="gdList(\'\')">根目录</a></li>';
|
||||
|
||||
if (mlist.length>0){
|
||||
$('#myPath').val(mlist[0]['parents'][0]);
|
||||
}
|
||||
|
||||
$(".upyunCon .place-input ul").html(pathLi);
|
||||
$(".upyunlist .list-list").html(listBody);
|
||||
|
||||
$('#backBtn').unbind().click(function() {
|
||||
gdList('');
|
||||
});
|
||||
|
||||
$('.upyunCon .refreshBtn').unbind().click(function(){
|
||||
var file_id = $('#myPath').val();
|
||||
gdList(file_id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//删除文件
|
||||
function deleteFile(name, is_dir){
|
||||
if (is_dir === false){
|
||||
safeMessage('删除文件','删除后将无法恢复,真的要删除['+name+']吗?',function(){
|
||||
var path = $("#myPath").val();
|
||||
var filename = name;
|
||||
gdPost('delete_file', {filename:filename,path:path}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
var file_id = $('#myPath').val();
|
||||
gdList(file_id);
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
safeMessage('删除文件夹','删除后将无法恢复,真的要删除文件资源['+name+']吗?',function(){
|
||||
var path = $("#myPath").val();
|
||||
gdPost('delete_dir', {dir_name:name,path:path}, function(rdata){
|
||||
var rdata = $.parseJSON(rdata.data);
|
||||
showMsg(rdata.msg,function(){
|
||||
var file_id = $('#myPath').val();
|
||||
gdList(file_id);
|
||||
},{icon:rdata.status?1:2},2000);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/python
|
||||
# coding: utf-8
|
||||
|
||||
# python3 plugins/gdrive/t/test.py
|
||||
# https://console.cloud.google.com/apis/credentials/consent?project=plated-inn-369901
|
||||
|
||||
# https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=226011946234-d3e1vashgag64utjedu1ljt9u39ncrpq.apps.googleusercontent.com&redirect_uri=https%3A%2F%2Fdrive.aapanel.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&state=I2da4aZUwqgmikrgrqAwwSjyoEHVs1&access_type=offline&prompt=consent&include_granted_scopes=false
|
||||
|
||||
|
||||
# https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/08125e6b-6502-4ac9-9548-ad682f00848d/objectId/62b1d655-9828-47ed-be99-65eb18c3a929/isMSAApp~/false/defaultBlade/Overview/appSignInAudience/AzureADandPersonalMicrosoftAccount/servicePrincipalCreated~/true
|
||||
|
||||
# 0WA8Q~sZkZFZKv50ryP4ux~.fpVtbHw7BuTZmbQB
|
||||
# client_id:d9878fac-8526-4ff6-8036-e1c92dd9dd80
|
||||
|
||||
# 08125e6b-6502-4ac9-9548-ad682f00848d
|
||||
|
||||
|
||||
# /drive/v2internal/files?openDrive=false&reason=102&syncType=0&errorRecovery=false&q=trashed = false and '1-z6gUXseXmlxmntvkLzOe_tYFT5tdhM9' in parents&fields=kind,nextPageToken,items(kind,modifiedDate,hasVisitorPermissions,containsUnsubscribedChildren,modifiedByMeDate,lastViewedByMeDate,alternateLink,fileSize,owners(kind,permissionId,emailAddressFromAccount,id),lastModifyingUser(kind,permissionId,emailAddressFromAccount,id),customerId,ancestorHasAugmentedPermissions,hasThumbnail,thumbnailVersion,title,id,resourceKey,abuseIsAppealable,abuseNoticeReason,shared,accessRequestsCount,sharedWithMeDate,userPermission(role),explicitlyTrashed,mimeType,quotaBytesUsed,copyable,subscribed,folderColor,hasChildFolders,fileExtension,primarySyncParentId,sharingUser(kind,permissionId,emailAddressFromAccount,id),flaggedForAbuse,folderFeatures,spaces,sourceAppId,recency,recencyReason,version,actionItems,teamDriveId,hasAugmentedPermissions,createdDate,primaryDomainName,organizationDisplayName,passivelySubscribed,trashingUser(kind,permissionId,emailAddressFromAccount,id),trashedDate,parents(id),capabilities(canMoveItemIntoTeamDrive,canUntrash,canModifyContentRestriction,canMoveItemWithinTeamDrive,canMoveItemOutOfTeamDrive,canDeleteChildren,canTrashChildren,canRequestApproval,canReadCategoryMetadata,canEditCategoryMetadata,canAddMyDriveParent,canRemoveMyDriveParent,canShareChildFiles,canShareChildFolders,canRead,canMoveItemWithinDrive,canMoveChildrenWithinDrive,canAddFolderFromAnotherDrive,canChangeSecurityUpdateEnabled,canBlockOwner,canReportSpamOrAbuse,canCopy,canDownload,canEdit,canAddChildren,canDelete,canRemoveChildren,canShare,canTrash,canRename,canReadTeamDrive,canMoveTeamDriveItem),contentRestrictions(readOnly),approvalMetadata(approvalVersion,approvalSummaries,hasIncomingApproval),shortcutDetails(targetId,targetMimeType,targetLookupStatus,targetFile,canRequestAccessToTarget),spamMetadata(markedAsSpamDate,inSpamView),labels(starred,trashed,restricted,viewed)),incompleteSearch&appDataFilter=NO_APP_DATA&spaces=drive&maxResults=200&supportsTeamDrives=true&includeItemsFromAllDrives=true&corpora=default&orderBy=folder,title_natural asc&retryCount=0&key=AIzaSyD_InbmSFufIEps5UAt2NmB_3LvBH3Sz_8 HTTP/1.1
|
||||
|
||||
# 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 database t1 3
|
||||
# python3 /www/server/mdserver-web/plugins/msonedrive/index.py path
|
||||
# /Users/midoks/Desktop/dev/python 3
|
||||
|
||||
|
||||
import sys
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
import json
|
||||
|
||||
|
||||
sys.path.append(os.getcwd() + "/class/core")
|
||||
import mw
|
||||
|
||||
|
||||
def getPluginName():
|
||||
return 'gdrive'
|
||||
|
||||
|
||||
def getPluginDir():
|
||||
return mw.getPluginDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
def getServerDir():
|
||||
return mw.getServerDir() + '/' + getPluginName()
|
||||
|
||||
|
||||
# print(getPluginDir())
|
||||
sys.path.append(getPluginDir() + "/class")
|
||||
from gdriveclient import gdriveclient
|
||||
|
||||
|
||||
gd = gdriveclient(getPluginDir(), getServerDir())
|
||||
gd.setDebug(True)
|
||||
# sign_in_url, state = gd.get_sign_in_url()
|
||||
# print(sign_in_url)
|
||||
|
||||
# url = 'https://localhost/?state=GH2YZ1VeytzVB1BqJJpQZIBk2GGAub&code=4/0Adeu5BXnD2dQvXx8Sg0WPn1XiMpihcRBNaG1yaFKIo86gUiG7q65KU1MaNCxrj_f2bjkwQ&scope=https://www.googleapis.com/auth/drive.file'
|
||||
# t = gd.set_auth_url(url)
|
||||
# print(t)
|
||||
|
||||
# def set_auth_url(url):
|
||||
# try:
|
||||
# if url.startswith("http://"):
|
||||
# url = url.replace("http://", "https://")
|
||||
# token = msodc.get_token_from_authorized_url(
|
||||
# authorized_url=url)
|
||||
# msodc.store_token(token)
|
||||
# msodc.store_user()
|
||||
# return mw.returnJson(True, "授权成功!")
|
||||
# except Exception as e:
|
||||
# print(e)
|
||||
# return mw.returnJson(False, "授权失败2!:" + str(e))
|
||||
# return mw.returnJson(False, "授权失败!:" + str(e))
|
||||
|
||||
# url = 'http://localhost/?code=M.C106_BAY.2.310112f3-a158-c400-9667-d158cbd1de6c&state=jEJz0ucR9bpZYD9PGxp2GgRDotrzO6'
|
||||
# token = set_auth_url(url)
|
||||
# print(token)
|
||||
|
||||
# token = msodc.get_token()
|
||||
# print("token:", token)
|
||||
|
||||
# t = gd.get_list('')
|
||||
# print(t)
|
||||
|
||||
# t = gd.get_id_list('1u7LjXGj1KoN-ltAdTRaib7IZJpsEnPdz')
|
||||
# print(t)
|
||||
|
||||
# t = gd.create_folder('backup_demo')
|
||||
# print(t)
|
||||
|
||||
# t = msodc.delete_object('backup')
|
||||
# print(t)
|
||||
|
||||
|
||||
# t = gd.upload_file('web_t1.cn_20230830_134549.tar.gz', 'site')
|
||||
# print(t)
|
||||
# print(gd.error_msg)
|
||||
|
||||
# /Users/midoks/Desktop/mwdev/server/mdserver-web/paramiko.log
|
||||
# backup/site/paramiko.log
|
||||
# |-正在上传到 backup/site/paramiko.log...
|
||||
# True
|
||||
|
||||
|
||||
t = gd.upload_file(
|
||||
'db_zzzvps_20230830_210727.sql.gz', 'datebase')
|
||||
print(t)
|
||||
@@ -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':
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"ps": "Gogs是一款极易搭建的自助Git服务",
|
||||
"name": "gogs",
|
||||
"title": "Gogs",
|
||||
"versions": ["0.11.86","0.12.9"],
|
||||
"versions": ["0.11.86","0.12.9","0.13.0"],
|
||||
"tip": "soft",
|
||||
"checks": "server/gogs",
|
||||
"path":"server/gogs",
|
||||
|
||||
@@ -9,6 +9,10 @@ serverPath=$(dirname "$rootPath")
|
||||
|
||||
install_tmp=${rootPath}/tmp/mw_install.pl
|
||||
|
||||
if [ -f ${rootPath}/bin/activate ];then
|
||||
source ${rootPath}/bin/activate
|
||||
fi
|
||||
|
||||
|
||||
GOGS_DOWNLOAD='https://dl.gogs.io'
|
||||
|
||||
|
||||
+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.me/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
|
||||
@@ -402,6 +402,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 +414,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
|
||||
|
||||
|
||||
@@ -755,6 +755,11 @@ def importDbBackup():
|
||||
return mw.returnJson(True, 'ok')
|
||||
|
||||
|
||||
def rootPwd():
|
||||
return pSqliteDb('config').where(
|
||||
'id=?', (1,)).getField('mysql_root')
|
||||
|
||||
|
||||
def importDbExternal():
|
||||
args = getArgs()
|
||||
data = checkArgs(args, ['file', 'name'])
|
||||
@@ -2740,6 +2745,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':
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -87,7 +87,7 @@ class backupTools:
|
||||
pid = mw.M('databases').dbPos(db_path, db_name).where(
|
||||
'name=?', (name,)).getField('id')
|
||||
|
||||
mw.M('backup').add('type,name,pid,filename,addtime,size', (1, os.path.basename(
|
||||
mw.M('backup').add('type,name,pid,filename,addtime,size', (3, os.path.basename(
|
||||
filename), pid, filename, endDate, os.path.getsize(filename)))
|
||||
log = "数据库[" + name + "]备份成功,用时[" + str(round(outTime, 2)) + "]秒"
|
||||
mw.writeLog('计划任务', log)
|
||||
@@ -97,7 +97,7 @@ class backupTools:
|
||||
|
||||
# 清理多余备份
|
||||
backups = mw.M('backup').where(
|
||||
'type=? and pid=?', ('1', pid)).field('id,filename').select()
|
||||
'type=? and pid=?', ('3', pid)).field('id,filename').select()
|
||||
|
||||
num = len(backups) - int(count)
|
||||
if num > 0:
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.3
|
||||
|
||||
Install_app()
|
||||
{
|
||||
@@ -101,16 +101,18 @@ 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()
|
||||
|
||||
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.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 '10.11' > $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.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 '10.11' > $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.0
|
||||
|
||||
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 '10.11' > $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
|
||||
+49
-12
@@ -31,8 +31,13 @@ def getServerDir():
|
||||
|
||||
|
||||
def getInitDFile():
|
||||
if app_debug:
|
||||
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()
|
||||
|
||||
|
||||
@@ -87,8 +92,10 @@ def checkArgs(data, ck=[]):
|
||||
|
||||
|
||||
def status():
|
||||
data = mw.execShell(
|
||||
"ps -ef|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'
|
||||
@@ -113,8 +120,8 @@ def initDreplace():
|
||||
# systemd
|
||||
systemDir = mw.systemdCfgDir()
|
||||
systemService = systemDir + '/memcached.service'
|
||||
systemServiceTpl = getPluginDir() + '/init.d/memcached.service.tpl'
|
||||
if os.path.exists(systemDir) and not os.path.exists(systemService):
|
||||
systemServiceTpl = getPluginDir() + '/init.d/memcached.service.tpl'
|
||||
service_path = mw.getServerDir()
|
||||
se_content = mw.readFile(systemServiceTpl)
|
||||
se_content = se_content.replace('{$SERVER_PATH}', service_path)
|
||||
@@ -137,13 +144,20 @@ def initDreplace():
|
||||
def memOp(method):
|
||||
file = initDreplace()
|
||||
|
||||
if not mw.isAppleSystem():
|
||||
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
|
||||
current_os = mw.getOs()
|
||||
if current_os == "darwin":
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
if data[1] == '':
|
||||
return 'ok'
|
||||
return data[1]
|
||||
|
||||
data = mw.execShell(file + ' ' + method)
|
||||
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]
|
||||
@@ -226,9 +240,15 @@ def saveConf():
|
||||
|
||||
|
||||
def initdStatus():
|
||||
if mw.isAppleSystem():
|
||||
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)
|
||||
@@ -238,17 +258,34 @@ def initdStatus():
|
||||
|
||||
|
||||
def initdInstall():
|
||||
if mw.isAppleSystem():
|
||||
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():
|
||||
if not app_debug:
|
||||
if mw.isAppleSystem():
|
||||
return "Apple Computer does not support"
|
||||
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'
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"title": "Memcached",
|
||||
"shell": "install.sh",
|
||||
"versions":["1.6"],
|
||||
"updates":["1.6.15"],
|
||||
"updates":["1.6.21"],
|
||||
"tip": "soft",
|
||||
"checks": "server/memcached",
|
||||
"path":"server/memcached",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user