shadowsocks-manager 0.1.2__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bin/ssm-dev-start +34 -0
- bin/ssm-dev-stop +20 -0
- bin/ssm-setup +221 -0
- bin/ssm-test +113 -0
- shadowsocks_manager/.env +18 -0
- shadowsocks_manager/__init__.py +0 -0
- shadowsocks_manager/__main__.py +45 -0
- shadowsocks_manager/args_formatter/__init__.py +74 -0
- shadowsocks_manager/args_formatter/tests.py +42 -0
- shadowsocks_manager/domain/__init__.py +0 -0
- shadowsocks_manager/domain/admin.py +78 -0
- shadowsocks_manager/domain/apps.py +10 -0
- shadowsocks_manager/domain/fixtures/nameserver.json +1 -0
- shadowsocks_manager/domain/migrations/__init__.py +0 -0
- shadowsocks_manager/domain/models.py +265 -0
- shadowsocks_manager/domain/serializers.py +25 -0
- shadowsocks_manager/domain/tests.py +138 -0
- shadowsocks_manager/domain/urls.py +18 -0
- shadowsocks_manager/domain/views.py +38 -0
- shadowsocks_manager/dynamicmethod/__init__.py +0 -0
- shadowsocks_manager/dynamicmethod/admin.py +8 -0
- shadowsocks_manager/dynamicmethod/apps.py +10 -0
- shadowsocks_manager/dynamicmethod/migrations/__init__.py +0 -0
- shadowsocks_manager/dynamicmethod/models.py +96 -0
- shadowsocks_manager/dynamicmethod/tests.py +8 -0
- shadowsocks_manager/dynamicmethod/views.py +8 -0
- shadowsocks_manager/fixtures/auth.group.json +1 -0
- shadowsocks_manager/fixtures/django_celery_beat.crontabschedule.json +38 -0
- shadowsocks_manager/fixtures/django_celery_beat.intervalschedule.json +10 -0
- shadowsocks_manager/fixtures/django_celery_beat.periodictask.json +108 -0
- shadowsocks_manager/fixtures/sites.site.json +1 -0
- shadowsocks_manager/manage.py +29 -0
- shadowsocks_manager/notification/__init__.py +0 -0
- shadowsocks_manager/notification/admin.py +18 -0
- shadowsocks_manager/notification/apps.py +10 -0
- shadowsocks_manager/notification/fixtures/template.json +13 -0
- shadowsocks_manager/notification/migrations/__init__.py +0 -0
- shadowsocks_manager/notification/models.py +66 -0
- shadowsocks_manager/notification/serializers.py +13 -0
- shadowsocks_manager/notification/tests.py +93 -0
- shadowsocks_manager/notification/urls.py +16 -0
- shadowsocks_manager/notification/views.py +19 -0
- shadowsocks_manager/retry/__init__.py +68 -0
- shadowsocks_manager/retry/tests.py +42 -0
- shadowsocks_manager/shadowsocks_manager/__init__.py +6 -0
- shadowsocks_manager/shadowsocks_manager/celery.py +27 -0
- shadowsocks_manager/shadowsocks_manager/settings.py +217 -0
- shadowsocks_manager/shadowsocks_manager/urls.py +31 -0
- shadowsocks_manager/shadowsocks_manager/wsgi.py +19 -0
- shadowsocks_manager/shadowsocksz/__init__.py +0 -0
- shadowsocks_manager/shadowsocksz/admin.py +188 -0
- shadowsocks_manager/shadowsocksz/apps.py +10 -0
- shadowsocks_manager/shadowsocksz/fixtures/config.json +1 -0
- shadowsocks_manager/shadowsocksz/management/__init__.py +0 -0
- shadowsocks_manager/shadowsocksz/management/commands/__init__.py +0 -0
- shadowsocks_manager/shadowsocksz/management/commands/shadowsocks_config.py +24 -0
- shadowsocks_manager/shadowsocksz/migrations/__init__.py +0 -0
- shadowsocks_manager/shadowsocksz/models.py +1024 -0
- shadowsocks_manager/shadowsocksz/serializers.py +41 -0
- shadowsocks_manager/shadowsocksz/tasks.py +21 -0
- shadowsocks_manager/shadowsocksz/tests.py +470 -0
- shadowsocks_manager/shadowsocksz/urls.py +20 -0
- shadowsocks_manager/shadowsocksz/views.py +53 -0
- shadowsocks_manager/singleton/__init__.py +0 -0
- shadowsocks_manager/singleton/admin.py +8 -0
- shadowsocks_manager/singleton/apps.py +10 -0
- shadowsocks_manager/singleton/migrations/__init__.py +0 -0
- shadowsocks_manager/singleton/models.py +46 -0
- shadowsocks_manager/singleton/tests.py +8 -0
- shadowsocks_manager/singleton/views.py +8 -0
- shadowsocks_manager/statistic/__init__.py +0 -0
- shadowsocks_manager/statistic/admin.py +78 -0
- shadowsocks_manager/statistic/apps.py +10 -0
- shadowsocks_manager/statistic/migrations/__init__.py +0 -0
- shadowsocks_manager/statistic/models.py +308 -0
- shadowsocks_manager/statistic/serializers.py +19 -0
- shadowsocks_manager/statistic/tasks.py +17 -0
- shadowsocks_manager/statistic/tests.py +99 -0
- shadowsocks_manager/statistic/urls.py +16 -0
- shadowsocks_manager/statistic/views.py +26 -0
- shadowsocks_manager/utils/__init__.py +0 -0
- shadowsocks_manager/utils/celery.py +28 -0
- shadowsocks_manager/utils/createsuperuser.py +57 -0
- shadowsocks_manager/utils/dotenv.py +70 -0
- shadowsocks_manager/utils/manage.py +29 -0
- shadowsocks_manager/utils/uwsgi.py +27 -0
- shadowsocks_manager-0.1.2.data/scripts/ssm-dev-start +34 -0
- shadowsocks_manager-0.1.2.data/scripts/ssm-dev-stop +20 -0
- shadowsocks_manager-0.1.2.data/scripts/ssm-setup +221 -0
- shadowsocks_manager-0.1.2.data/scripts/ssm-test +113 -0
- shadowsocks_manager-0.1.2.dist-info/LICENSE +21 -0
- shadowsocks_manager-0.1.2.dist-info/METADATA +532 -0
- shadowsocks_manager-0.1.2.dist-info/RECORD +96 -0
- shadowsocks_manager-0.1.2.dist-info/WHEEL +6 -0
- shadowsocks_manager-0.1.2.dist-info/entry_points.txt +7 -0
- shadowsocks_manager-0.1.2.dist-info/top_level.txt +2 -0
bin/ssm-dev-start
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
#? Description:
|
|
4
|
+
#? Start the Django server, and the Celery beat and worker.
|
|
5
|
+
#? If you need to run the server under a specific Python environment, make
|
|
6
|
+
#? sure to activate it before to run the server.
|
|
7
|
+
#?
|
|
8
|
+
#? Usage:
|
|
9
|
+
#? ssm-dev-start.sh [[IP:]PORT]
|
|
10
|
+
#?
|
|
11
|
+
#? Options:
|
|
12
|
+
#? [[IP:]PORT]
|
|
13
|
+
#?
|
|
14
|
+
#? The IP address and the port that the Django server is listening on.
|
|
15
|
+
#? The default IP address is `127.0.0.1`.
|
|
16
|
+
#? The default PORT is `8000`.
|
|
17
|
+
#?
|
|
18
|
+
|
|
19
|
+
# exit on any error
|
|
20
|
+
set -e -o pipefail
|
|
21
|
+
|
|
22
|
+
function main () {
|
|
23
|
+
declare listen=$1
|
|
24
|
+
|
|
25
|
+
# don't quote the variable $listen, leave it this way on purpose
|
|
26
|
+
# shellcheck disable=SC2086
|
|
27
|
+
ssm-manage runserver $listen --insecure &
|
|
28
|
+
sleep 1
|
|
29
|
+
ssm-celery -A shadowsocks_manager worker -l info -B &
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
main "$@"
|
|
33
|
+
|
|
34
|
+
exit
|
bin/ssm-dev-stop
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
#? Description:
|
|
4
|
+
#? Stop the Django server, and the Celery beat and worker.
|
|
5
|
+
#?
|
|
6
|
+
#? Usage:
|
|
7
|
+
#? ssm-dev-stop.sh
|
|
8
|
+
#?
|
|
9
|
+
|
|
10
|
+
function main () {
|
|
11
|
+
# Kill the Celery processes
|
|
12
|
+
pkill -f "celery -A shadowsocks_manager"
|
|
13
|
+
|
|
14
|
+
# Kill the Django runserver process
|
|
15
|
+
pkill -f "python manage.py runserver"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
main "$@"
|
|
19
|
+
|
|
20
|
+
exit
|
bin/ssm-setup
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
#? Description:
|
|
4
|
+
#? Setup shadowsocks-manager in your Python environment.
|
|
5
|
+
#? If you need to run the setup under a specific Python environment, make
|
|
6
|
+
#? sure to activate it before to run the setup.
|
|
7
|
+
#?
|
|
8
|
+
#? Usage:
|
|
9
|
+
#? ssm-setup.sh [-e ENV ...]
|
|
10
|
+
#? [-c] [-m] [-l] [-u USERNAME -p PASSWORD [-M EMAIL]] [-r PORT_BEGIN] [-R PORT_END] [-h]
|
|
11
|
+
#?
|
|
12
|
+
#? Options:
|
|
13
|
+
#? [-e ENV ...]
|
|
14
|
+
#?
|
|
15
|
+
#? Set the environment variables in KEY=VALUE format for .env file.
|
|
16
|
+
#? The .env file is used by Django settings.
|
|
17
|
+
#? This option can be used multiple times.
|
|
18
|
+
#?
|
|
19
|
+
#? The valid KEYs are:
|
|
20
|
+
#?
|
|
21
|
+
#? - SSM_SECRET_KEY
|
|
22
|
+
#?
|
|
23
|
+
#? Set Django's SECRET_KEY.
|
|
24
|
+
#? The default value is hardcoded in the .env file and Django's settings.
|
|
25
|
+
#? Do not use the default value in production environment.
|
|
26
|
+
#? Below command will generate a random SECRET_KEY:
|
|
27
|
+
#? ```sh
|
|
28
|
+
#? $ od -vN 25 -An -tx1 /dev/urandom | tr -d ' \n'
|
|
29
|
+
#? ```
|
|
30
|
+
#?
|
|
31
|
+
#? - SSM_DEBUG
|
|
32
|
+
#?
|
|
33
|
+
#? Set Django's DEBUG.
|
|
34
|
+
#? The value can be 'True' or 'False'.
|
|
35
|
+
#? The default value depends on the .env file and Django's settings.
|
|
36
|
+
#? Do not use value SSM_DEBUG=True in production environment.
|
|
37
|
+
#?
|
|
38
|
+
#? - SSM_TIME_ZONE
|
|
39
|
+
#?
|
|
40
|
+
#? Set Django's TIME_ZONE.
|
|
41
|
+
#? The value can be any valid timezone name.
|
|
42
|
+
#? The default value depends on the .env file and Django's settings.
|
|
43
|
+
#?
|
|
44
|
+
#? - SSM_DATA_HOME
|
|
45
|
+
#?
|
|
46
|
+
#? Set the base directory for the Django database and static files.
|
|
47
|
+
#? The default value depends on the .env file and Django's settings.
|
|
48
|
+
#?
|
|
49
|
+
#? - SSM_MEMCACHED_HOST, SSM_MEMCACHED_PORT
|
|
50
|
+
#?
|
|
51
|
+
#? Set the Memcached server's host and port which are used by Django cache.
|
|
52
|
+
#? The default value depends on the .env file and Django's settings.
|
|
53
|
+
#?
|
|
54
|
+
#? - SSM_RABBITMQ_HOST, SSM_RABBITMQ_PORT
|
|
55
|
+
#?
|
|
56
|
+
#? Set the RabbitMQ server's host and port which are used by Celery.
|
|
57
|
+
#? The default value depends on the .env file and Django's settings.
|
|
58
|
+
#?
|
|
59
|
+
#? However, this script will not check the validity of the KEYs and VALUEs.
|
|
60
|
+
#?
|
|
61
|
+
#? [-c]
|
|
62
|
+
#?
|
|
63
|
+
#? Collect Django static files.
|
|
64
|
+
#? This is necessary for the first time setup.
|
|
65
|
+
#?
|
|
66
|
+
#? [-m]
|
|
67
|
+
#?
|
|
68
|
+
#? Migrate Django database.
|
|
69
|
+
#? This is necessary for the first time setup.
|
|
70
|
+
#?
|
|
71
|
+
#? [-l]
|
|
72
|
+
#?
|
|
73
|
+
#? Load Django fixtures.
|
|
74
|
+
#? This is necessary for the first time setup.
|
|
75
|
+
#?
|
|
76
|
+
#? [-u USERNAME]
|
|
77
|
+
#?
|
|
78
|
+
#? Username for shadowsocks-manager administrator.
|
|
79
|
+
#? No default value.
|
|
80
|
+
#? This is necessary for the first time setup.
|
|
81
|
+
#?
|
|
82
|
+
#? [-p PASSWORD]
|
|
83
|
+
#?
|
|
84
|
+
#? Password for shadowsocks-manager administrator'.
|
|
85
|
+
#? No default value.
|
|
86
|
+
#? This is necessary for the first time setup.
|
|
87
|
+
#?
|
|
88
|
+
#? [-M EMAIL]
|
|
89
|
+
#?
|
|
90
|
+
#? Email for the shadowsocks-manager administrator.
|
|
91
|
+
#? Also, be used as the sender of the account notification Email.
|
|
92
|
+
#? No default value.
|
|
93
|
+
#?
|
|
94
|
+
#? [-r PORT_BEGIN]
|
|
95
|
+
#?
|
|
96
|
+
#? The beginning port number for Shadowsocks nodes.
|
|
97
|
+
#? The default value depends on the Django fixture data.
|
|
98
|
+
#?
|
|
99
|
+
#? [-R PORT_END]
|
|
100
|
+
#?
|
|
101
|
+
#? The ending port number for Shadowsocks nodes.
|
|
102
|
+
#? The default value depends on the Django fixture data.
|
|
103
|
+
#?
|
|
104
|
+
#? [-h]
|
|
105
|
+
#?
|
|
106
|
+
#? This help.
|
|
107
|
+
#?
|
|
108
|
+
#? Example:
|
|
109
|
+
#? # First time setup in development environment:
|
|
110
|
+
#? $ ssm-setup -c -m -l -u admin -p yourpassword
|
|
111
|
+
#?
|
|
112
|
+
#? # Update a development environment to be production ready:
|
|
113
|
+
#? $ ssm-setup -e SSM_SECRET_KEY=yourkey -e SSM_DEBUG=False
|
|
114
|
+
#?
|
|
115
|
+
#? # First time setup in production environment:
|
|
116
|
+
#? $ ssm-setup -e SSM_SECRET_KEY=yourkey -e SSM_DEBUG=False -c -m -l -u admin -p yourpassword -M admin@yourdomain.com
|
|
117
|
+
#?
|
|
118
|
+
|
|
119
|
+
# exit on any error
|
|
120
|
+
set -e -o pipefail
|
|
121
|
+
|
|
122
|
+
function usage () {
|
|
123
|
+
awk '/^#\?/ {sub("^[ ]*#\\?[ ]?", ""); print}' "$0" \
|
|
124
|
+
| awk '{gsub(/^[^ ]+.*/, "\033[1m&\033[0m"); print}'
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function check-os () {
|
|
128
|
+
if [[ $(uname) != 'Linux' && $(uname) != 'Darwin' ]]; then
|
|
129
|
+
printf "fatal: this script support Linux and MacOS only.\n" >&2
|
|
130
|
+
return 255
|
|
131
|
+
fi
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function main () {
|
|
135
|
+
declare -a envs
|
|
136
|
+
declare collect_flag migrate_flag loaddata_flag username password email port_begin port_end \
|
|
137
|
+
OPTIND OPTARG opt
|
|
138
|
+
|
|
139
|
+
while getopts e:cmlu:p:M:r:R:h opt; do
|
|
140
|
+
case $opt in
|
|
141
|
+
e)
|
|
142
|
+
envs+=("$OPTARG")
|
|
143
|
+
;;
|
|
144
|
+
c)
|
|
145
|
+
collect_flag=1
|
|
146
|
+
;;
|
|
147
|
+
m)
|
|
148
|
+
migrate_flag=1
|
|
149
|
+
;;
|
|
150
|
+
l)
|
|
151
|
+
loaddata_flag=1
|
|
152
|
+
;;
|
|
153
|
+
u)
|
|
154
|
+
username=$OPTARG
|
|
155
|
+
;;
|
|
156
|
+
p)
|
|
157
|
+
password=$OPTARG
|
|
158
|
+
;;
|
|
159
|
+
M)
|
|
160
|
+
email=$OPTARG
|
|
161
|
+
;;
|
|
162
|
+
r)
|
|
163
|
+
port_begin=$OPTARG
|
|
164
|
+
;;
|
|
165
|
+
R)
|
|
166
|
+
port_end=$OPTARG
|
|
167
|
+
;;
|
|
168
|
+
*)
|
|
169
|
+
usage
|
|
170
|
+
exit 255
|
|
171
|
+
;;
|
|
172
|
+
esac
|
|
173
|
+
done
|
|
174
|
+
|
|
175
|
+
check-os
|
|
176
|
+
|
|
177
|
+
if [[ $# -eq 0 ]]; then
|
|
178
|
+
usage
|
|
179
|
+
exit 255
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
if [[ -n ${envs[*]} ]]; then
|
|
183
|
+
ssm-dotenv -w "${envs[@]}"
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
if [[ -n $collect_flag ]]; then
|
|
187
|
+
ssm-manage collectstatic --no-input -c
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
if [[ -n $migrate_flag ]]; then
|
|
191
|
+
ssm-manage makemigrations
|
|
192
|
+
ssm-manage migrate
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
if [[ -n $loaddata_flag ]]; then
|
|
196
|
+
ssm-manage loaddata fixtures/auth.group.json \
|
|
197
|
+
fixtures/sites.site.json \
|
|
198
|
+
fixtures/django_celery_beat.crontabschedule.json \
|
|
199
|
+
fixtures/django_celery_beat.intervalschedule.json \
|
|
200
|
+
fixtures/django_celery_beat.periodictask.json \
|
|
201
|
+
config.json \
|
|
202
|
+
template.json \
|
|
203
|
+
nameserver.json
|
|
204
|
+
fi
|
|
205
|
+
|
|
206
|
+
if [[ -n $username && -n $password ]]; then
|
|
207
|
+
ssm-createsuperuser --username "$username" --password "$password" --email "$email"
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
if [[ -n $port_begin ]]; then
|
|
211
|
+
ssm-manage shadowsocks_config --port-begin "$port_begin"
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
if [[ -n $port_end ]]; then
|
|
215
|
+
ssm-manage shadowsocks_config --port-end "$port_end"
|
|
216
|
+
fi
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
main "$@"
|
|
220
|
+
|
|
221
|
+
exit
|
bin/ssm-test
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
#? Description:
|
|
4
|
+
#? Test shadowsocks-manager in your Python environment.
|
|
5
|
+
#? If you need to run the setup under a specific Python environment, make
|
|
6
|
+
#? sure to activate it before to run the setup.
|
|
7
|
+
#?
|
|
8
|
+
#? Usage:
|
|
9
|
+
#? ssm-test.sh [-t] [-c] [-g [-o OUTFILE]] [-u] [-h]
|
|
10
|
+
#?
|
|
11
|
+
#? Options:
|
|
12
|
+
#? [-t]
|
|
13
|
+
#?
|
|
14
|
+
#? Run the test.
|
|
15
|
+
#?
|
|
16
|
+
#? [-c]
|
|
17
|
+
#?
|
|
18
|
+
#? Run the test with coverage.
|
|
19
|
+
#?
|
|
20
|
+
#? [-g]
|
|
21
|
+
#?
|
|
22
|
+
#? Generate coverage report with the previous coverage data.
|
|
23
|
+
#?
|
|
24
|
+
#? [-o OUTFILE]
|
|
25
|
+
#?
|
|
26
|
+
#? The output file for the coverage report.
|
|
27
|
+
#? The default is `coverage.xml`.
|
|
28
|
+
#?
|
|
29
|
+
#? [-u]
|
|
30
|
+
#?
|
|
31
|
+
#? Upload the coverage report to codecov.io.
|
|
32
|
+
#?
|
|
33
|
+
#? [-h]
|
|
34
|
+
#?
|
|
35
|
+
#? This help.
|
|
36
|
+
#?
|
|
37
|
+
#? Environment:
|
|
38
|
+
#? The following environment variables are used by this script:
|
|
39
|
+
#?
|
|
40
|
+
#? - CODECOV_TOKEN
|
|
41
|
+
#?
|
|
42
|
+
#? Required if -u is provided.
|
|
43
|
+
#?
|
|
44
|
+
#? Example:
|
|
45
|
+
#? # run the test without coverage, and generate coverage report, and upload it
|
|
46
|
+
#? $ ssm-test.sh -c -g -u
|
|
47
|
+
#?
|
|
48
|
+
|
|
49
|
+
# exit on any error
|
|
50
|
+
set -e -o pipefail
|
|
51
|
+
|
|
52
|
+
function usage () {
|
|
53
|
+
awk '/^#\?/ {sub("^[ ]*#\\?[ ]?", ""); print}' "$0" \
|
|
54
|
+
| awk '{gsub(/^[^ ]+.*/, "\033[1m&\033[0m"); print}'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function main () {
|
|
58
|
+
declare test=0 coverage=0 report=0 outfile_opt upload=0 \
|
|
59
|
+
OPTIND OPTARG opt
|
|
60
|
+
|
|
61
|
+
while getopts tcgo:u opt; do
|
|
62
|
+
case $opt in
|
|
63
|
+
t)
|
|
64
|
+
test=1
|
|
65
|
+
;;
|
|
66
|
+
c)
|
|
67
|
+
coverage=1
|
|
68
|
+
;;
|
|
69
|
+
g)
|
|
70
|
+
report=1
|
|
71
|
+
;;
|
|
72
|
+
o)
|
|
73
|
+
outfile_opt=(-o "$OPTARG")
|
|
74
|
+
;;
|
|
75
|
+
u)
|
|
76
|
+
upload=1
|
|
77
|
+
;;
|
|
78
|
+
*)
|
|
79
|
+
usage
|
|
80
|
+
exit 255
|
|
81
|
+
;;
|
|
82
|
+
esac
|
|
83
|
+
done
|
|
84
|
+
|
|
85
|
+
if [[ $# -eq 0 ]]; then
|
|
86
|
+
usage
|
|
87
|
+
exit 255
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# run the test
|
|
91
|
+
if [[ ${test} -eq 1 ]]; then
|
|
92
|
+
ssm-manage test --no-input -v 2
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# run the test with coverage
|
|
96
|
+
if [[ ${coverage} -eq 1 ]]; then
|
|
97
|
+
ssm coverage run manage.py test --no-input -v 2
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# generate coverage report
|
|
101
|
+
if [[ ${report} -eq 1 ]]; then
|
|
102
|
+
ssm coverage xml "${outfile_opt[@]}"
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# upload coverage report
|
|
106
|
+
if [[ ${upload} -eq 1 ]]; then
|
|
107
|
+
ssm codecovcli upload-process
|
|
108
|
+
fi
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
main "$@"
|
|
112
|
+
|
|
113
|
+
exit
|
shadowsocks_manager/.env
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Django settings: SECRET_KEY
|
|
2
|
+
# SECURITY WARNING: keep the secret key used in production secret!
|
|
3
|
+
SSM_SECRET_KEY=ef24ff499c58a21711385e8a6b31a7680fb41765b8ca0cb451
|
|
4
|
+
|
|
5
|
+
# Django settings: DEBUG
|
|
6
|
+
# SECURITY WARNING: don't run with debug turned on in production!
|
|
7
|
+
SSM_DEBUG=True
|
|
8
|
+
|
|
9
|
+
# Django settings: TIME_ZONE
|
|
10
|
+
SSM_TIME_ZONE=UTC
|
|
11
|
+
|
|
12
|
+
# Django settings: CACHES
|
|
13
|
+
SSM_MEMCACHED_HOST=localhost
|
|
14
|
+
SSM_MEMCACHED_PORT=11211
|
|
15
|
+
|
|
16
|
+
# Django settings: CELERY_BROKER_URL
|
|
17
|
+
SSM_RABBITMQ_HOST=localhost
|
|
18
|
+
SSM_RABBITMQ_PORT=5672
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import subprocess
|
|
5
|
+
from docopt import docopt
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
"""
|
|
10
|
+
Description:
|
|
11
|
+
Make the proxy call after adding the django root to the python path and changing the current directory to the django root.
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
ssm COMMAND [OPTIONS]
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
COMMAND The command to be run.
|
|
18
|
+
OPTIONS All options are transparently passing to the called command.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
None
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
$ ssm python manage.py runserver
|
|
25
|
+
$ ssm uwsgi --ini uwsgi.ini
|
|
26
|
+
$ ssm celery -A shadowsocks_manager worker -l info
|
|
27
|
+
"""
|
|
28
|
+
#docopt(main.__doc__)
|
|
29
|
+
|
|
30
|
+
django_root = os.path.dirname(os.path.abspath(__file__))
|
|
31
|
+
|
|
32
|
+
# add the django root to the python path to allow django commands to be run from any directory
|
|
33
|
+
if django_root not in sys.path:
|
|
34
|
+
sys.path.insert(0, django_root)
|
|
35
|
+
|
|
36
|
+
# change dir to the django root to allow the dir-sensitive commands(such as loaddata) to be run from any directory
|
|
37
|
+
os.chdir(django_root)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# make the proxy call
|
|
41
|
+
return subprocess.call(sys.argv[1:])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == '__main__':
|
|
45
|
+
sys.exit(main())
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# py2.7 and py3 compatibility imports
|
|
2
|
+
from __future__ import unicode_literals
|
|
3
|
+
from builtins import range
|
|
4
|
+
from builtins import object
|
|
5
|
+
from functools import reduce
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Formatter(object):
|
|
9
|
+
"""
|
|
10
|
+
Return the input-syntax string presentation of args and kwargs list, delimited by comma `, `.
|
|
11
|
+
The value of the args and kwargs are formatted as the canonical string presentation.
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
>>> f = Formatter(*args, **kwargs)
|
|
15
|
+
>>> print(f)
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
>>> print(Formatter('foo', 1, x='bar', y=2))
|
|
19
|
+
'foo', 1, x='bar', y=2
|
|
20
|
+
|
|
21
|
+
Use Case:
|
|
22
|
+
# log the input arguments of methods.
|
|
23
|
+
def foo(*args, **kwargs):
|
|
24
|
+
message = Formatter(*args, **kwargs).to_string())
|
|
25
|
+
logger.debug('foo: {}'.format(message))
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, *args, **kwargs):
|
|
29
|
+
"""
|
|
30
|
+
Initialize the Formatter to have two members: args, kwargs
|
|
31
|
+
"""
|
|
32
|
+
self.args = args
|
|
33
|
+
self.kwargs = kwargs
|
|
34
|
+
|
|
35
|
+
def __str__(self, *args, **kwargs):
|
|
36
|
+
return self.to_string(*args, **kwargs)
|
|
37
|
+
|
|
38
|
+
def args_to_string(self):
|
|
39
|
+
"""
|
|
40
|
+
Return the canonical string presentation of args list, delimited by comma `, `.
|
|
41
|
+
"""
|
|
42
|
+
if self.args:
|
|
43
|
+
self.args = [repr(arg) for arg in self.args]
|
|
44
|
+
formatter = ['{}' for count in range(len(self.args))]
|
|
45
|
+
return ', '.join(formatter).format(*self.args)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def kwargs_to_string(self):
|
|
49
|
+
"""
|
|
50
|
+
Return the input-syntax string presentation of kwargs list, delimited by comma `, `.
|
|
51
|
+
The value of the kwargs are formatted as the canonical string presentation.
|
|
52
|
+
"""
|
|
53
|
+
if self.kwargs:
|
|
54
|
+
formatter = ['{}={}' for count in range(len(self.kwargs))]
|
|
55
|
+
return ', '.join(formatter).format(
|
|
56
|
+
*reduce((lambda x, y: x + y), [list([k, repr(v)]) for k,v in list(self.kwargs.items())]))
|
|
57
|
+
|
|
58
|
+
def to_string(self):
|
|
59
|
+
"""
|
|
60
|
+
Return the input-syntax string presentation of args and kwargs list, delimited by comma `, `.
|
|
61
|
+
The value of the args and kwargs are formatted as the canonical string presentation.
|
|
62
|
+
Be noted to the differences:
|
|
63
|
+
* An empty string `` is returned if no args and kwargs found.
|
|
64
|
+
* The input empty string `` is returned as the literal "``" with the additional quoting.
|
|
65
|
+
* The input NoneType None is returned as the literal `None` without additional quoting.
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
>>> Formatter('foo', 1, x='bar', y=2).to_string()
|
|
69
|
+
"'foo', 1, x='bar', y=2"
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
items = [self.args_to_string(), self.kwargs_to_string()]
|
|
73
|
+
items = [item for item in items if item is not None]
|
|
74
|
+
return ', '.join(items)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
# py2.7 and py3 compatibility imports
|
|
4
|
+
from __future__ import unicode_literals
|
|
5
|
+
from __future__ import absolute_import
|
|
6
|
+
from builtins import str
|
|
7
|
+
|
|
8
|
+
from unittest import TestCase
|
|
9
|
+
|
|
10
|
+
from . import Formatter
|
|
11
|
+
|
|
12
|
+
# Create your tests here.
|
|
13
|
+
class FormatterTestCase(TestCase):
|
|
14
|
+
def test(self):
|
|
15
|
+
# no args and kwargs
|
|
16
|
+
self.assertEqual(Formatter().to_string(), '')
|
|
17
|
+
# one arg as None
|
|
18
|
+
self.assertEqual(Formatter(None).to_string(), 'None')
|
|
19
|
+
# one arg as empty string
|
|
20
|
+
self.assertEqual(Formatter('').to_string(), repr(''))
|
|
21
|
+
# two simple args
|
|
22
|
+
self.assertEqual(Formatter('foo', 1).to_string(), '{}, 1'.format(repr('foo')))
|
|
23
|
+
# one arg as list
|
|
24
|
+
self.assertEqual(Formatter(['foo', 1]).to_string(), '[{}, 1]'.format(repr('foo')))
|
|
25
|
+
# one arg as dict
|
|
26
|
+
self.assertEqual(Formatter({'foo': 1}).to_string(), repr({'foo': 1}))
|
|
27
|
+
# on arg as tuple
|
|
28
|
+
self.assertEqual(Formatter(('foo', 1)).to_string(), repr(('foo', 1)))
|
|
29
|
+
# two simple kwargs, take care of the order, so works with both py2 and py3
|
|
30
|
+
self.assertEqual(Formatter(y=2, x='bar').to_string(), 'y=2, x={}'.format(repr('bar')))
|
|
31
|
+
# one kwarg as list
|
|
32
|
+
self.assertEqual(Formatter(x=['bar', 2]).to_string(), 'x={}'.format(repr(['bar', 2])))
|
|
33
|
+
# one kwarg as dict
|
|
34
|
+
self.assertEqual(Formatter(x={'bar': 2}).to_string(), 'x={}'.format(repr({'bar': 2})))
|
|
35
|
+
# one kwarg as tuple
|
|
36
|
+
self.assertEqual(Formatter(x=('bar', 2)).to_string(), 'x={}'.format(repr(('bar', 2))))
|
|
37
|
+
# two simple args and two simple kwargs, take care of the order, so works with both py2 and py3
|
|
38
|
+
self.assertEqual(
|
|
39
|
+
Formatter('foo', 1, y=2, x='bar').to_string(),
|
|
40
|
+
'{}, 1, y=2, x={}'.format(repr('foo'), repr('bar')))
|
|
41
|
+
# __str__()
|
|
42
|
+
self.assertEqual(str(Formatter(None)), 'None')
|
|
File without changes
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
# py2.7 and py3 compatibility imports
|
|
4
|
+
from __future__ import unicode_literals
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from django.contrib import admin, messages
|
|
8
|
+
|
|
9
|
+
from .models import NameServer, Domain, Record
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Register your models here.
|
|
13
|
+
|
|
14
|
+
@admin.register(NameServer)
|
|
15
|
+
class NameServerAdmin(admin.ModelAdmin):
|
|
16
|
+
fields = ('name', 'api_cls_name', 'user', 'credential',
|
|
17
|
+
'dt_created', 'dt_updated')
|
|
18
|
+
|
|
19
|
+
readonly_fields = ('dt_created', 'dt_updated')
|
|
20
|
+
|
|
21
|
+
list_display = ('name', 'api_cls_name', 'user', 'is_api_accessible',
|
|
22
|
+
'dt_created', 'dt_updated')
|
|
23
|
+
|
|
24
|
+
def is_api_accessible(self, obj):
|
|
25
|
+
return obj.is_api_accessible
|
|
26
|
+
|
|
27
|
+
is_api_accessible.boolean = True
|
|
28
|
+
is_api_accessible.short_description = 'API'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@admin.register(Domain)
|
|
32
|
+
class DomainAdmin(admin.ModelAdmin):
|
|
33
|
+
fields = ('name', 'nameserver',
|
|
34
|
+
'dt_created', 'dt_updated')
|
|
35
|
+
|
|
36
|
+
readonly_fields = ('dt_created', 'dt_updated')
|
|
37
|
+
|
|
38
|
+
list_display = ('name', 'nameserver',
|
|
39
|
+
'dt_created', 'dt_updated')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@admin.register(Record)
|
|
43
|
+
class RecordAdmin(admin.ModelAdmin):
|
|
44
|
+
fields = ('host', 'domain', 'type', 'answer', 'site',
|
|
45
|
+
'dt_created', 'dt_updated')
|
|
46
|
+
|
|
47
|
+
readonly_fields = ('dt_created', 'dt_updated')
|
|
48
|
+
|
|
49
|
+
list_display = ('host', 'domain', 'type', 'answer', 'answer_from_dns_api', 'is_matching_dns_api',
|
|
50
|
+
'answer_from_dns_query', 'is_matching_dns_query', 'site',
|
|
51
|
+
'dt_created', 'dt_updated')
|
|
52
|
+
|
|
53
|
+
def answer_from_dns_api(self, obj):
|
|
54
|
+
return list(obj.answer_from_dns_api) if obj.answer_from_dns_api is not None else obj.answer_from_dns_api
|
|
55
|
+
|
|
56
|
+
def answer_from_dns_query(self, obj):
|
|
57
|
+
return list(obj.answer_from_dns_query) if obj.answer_from_dns_query is not None else obj.answer_from_dns_query
|
|
58
|
+
|
|
59
|
+
def is_matching_dns_api(self, obj):
|
|
60
|
+
return obj.is_matching_dns_api
|
|
61
|
+
|
|
62
|
+
is_matching_dns_api.boolean = True
|
|
63
|
+
is_matching_dns_api.short_description = 'DNS API'
|
|
64
|
+
|
|
65
|
+
def is_matching_dns_query(self, obj):
|
|
66
|
+
return obj.is_matching_dns_query
|
|
67
|
+
|
|
68
|
+
is_matching_dns_query.boolean = True
|
|
69
|
+
is_matching_dns_query.short_description = 'DNS Query'
|
|
70
|
+
|
|
71
|
+
def sync_to_dns(self, request, queryset):
|
|
72
|
+
for obj in queryset:
|
|
73
|
+
result = obj.sync_to_dns()
|
|
74
|
+
messages.info(request, '{0}: {1}'.format(obj.host, json.dumps(result)))
|
|
75
|
+
|
|
76
|
+
sync_to_dns.short_description = 'Synchronize DNS records to DNS server for Selected Domain'
|
|
77
|
+
|
|
78
|
+
actions = (sync_to_dns,)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"model": "domain.nameserver", "pk": 1, "fields": {"name": "name.com", "api_cls_name": "NameNsApi", "user": null, "credential": null, "dt_created": "2021-01-12T16:58:21.432Z", "dt_updated": "2021-01-14T12:25:28.865Z"}}]
|
|
File without changes
|