-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathispconfig-cli
More file actions
executable file
·495 lines (454 loc) · 13.1 KB
/
ispconfig-cli
File metadata and controls
executable file
·495 lines (454 loc) · 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
#!/bin/bash
# Command line for ISPConfig remote user REST API using either smart functions or raw methods.
# Author: Johan Ehnberg, johan@molnix.com
set -e
### Variables
VERSION=2018-04-24
PROGNAME=$(basename $0)
DATESTAMP=`date +%s`
### Common commands
# usage
usage() {
echo "Command line for ISPConfig remote user REST API using either smart functions or raw methods."
echo
echo "Usage: $PROGNAME -h/-f <function>/-m <method> [options] ..."
echo
echo "Common options:"
echo
echo " -a <file>"
echo " Config file. Options are read in the following order: system configuration, user configuration, the file specified in this option, other command line options. The last occurrence overrides previous ones."
echo
echo " -e <url>"
echo " API endpoint url such as https://myserver.example.com:8080/remote/json.php ."
echo
echo " -h"
echo " Show this help text."
echo
echo " -i <id>"
echo " Server id (defaults to 1)."
echo
echo " -k"
echo " Do not validate server certificate (for self-signed certificates)."
echo
echo " -q"
echo " Quiet, only outputs results."
echo
echo " -v"
echo " Verbose, outputs all info where available."
echo
echo "Functions combine several methods to carry out common tasks. Function options:"
echo
echo " -b <file>"
echo " Batch file for processing of functions, one per row. Cannot be used with -m, -f or -t."
echo
echo " -c <client>"
echo " Username of the client whose records are to be accessed, see Client->Clients and Client->Resellers."
echo
echo " -f \"<function>\""
echo " Function to perform. Note the qoutes around the full function command. Cannot be used with -m, -b or -t."
echo
echo " -p <password>"
echo " Password of the remote user as specified in System->Remote Users."
echo
echo " -t"
echo " Read batch for processing of functions from stdin, one per row. Cannot be used with -m, -b or -f."
echo
echo " -u <user>"
echo " Username of the remote user as specified in System->Remote Users."
echo
echo " Available functions:"
echo
echo " clients List all clients"
echo " dns_as <zone> List all A records for a zone"
echo " dns_a_add <zone> <name> <ip> Add or update a DNS A record"
echo " dns_a_delete <zone> <name> Delete a DNS A record"
echo " dns_cnames <zone> List all CNAME records for a zone"
echo " dns_rr <zone> List all records for a zone"
echo " dns_zones List all zones"
echo " methods List available methods"
echo " log_in Create a session (not needed by default)"
echo " log_out <session> Log out a session (not needed by default)"
echo " servers List all servers"
echo
echo "Using a method wraps the JSON data to the API call and returns a JSON response. Method options:"
echo
echo " -d <string>"
echo " Read JSON data from command line. Use escapes and quotes! Cannot be used with -j or -s."
echo
echo " -j <file>"
echo " Read JSON data from file. Cannot be used with -d or -s."
echo
echo " -m <method>"
echo " Raw method to use such as dns_a_add. Cannot be used with -f. Requires one of -d, -j or -s."
echo
echo " -s"
echo " Read JSON data from stdin. Cannot be used with -d or -j."
echo
echo "For details on methods, see:"
echo "https://git.ispconfig.org/ispconfig/ispconfig3/tree/master/remoting_client/API-docs"
echo
echo "Config files are bash files that can contain the following variables:"
echo
echo "remote_user=myuser # see -u"
echo "remote_password=mypassword # see -p"
echo "remote_url=https://myserver.example.com:8080/remote/json.php # see -e"
echo "client_user=myclient # see -c"
echo "server_id=1 # see -i"
echo "ssl_validate=off # see -k"
echo
echo "Example uses:"
echo " 1. Log in using the method and escaped JSON on the command line, without config file"
echo ' ispconfig-cli -m login -d "{\"username\": \"myuser\",\"password\": \"mypassword\"}" -e https://myserver.example.com:8080/remote/json.php'
echo
echo " 2. Log in using the function, without config file"
echo " ispconfig-cli -f \"log_in\" -u myuser -p mypassword -e https://myserver.example.com:8080/remote/json.php -c myclient"
echo
echo " 3. Update a DNS A record or update if it already exists, with complete config file"
echo " ispconfig-cli -f \"dns_a_add example.com. johnscomputer 192.168.0.99\""
echo
}
# message verbosity message
message() {
if [ $1 -le $VERBOSITY ]; then
MESSAGE="${MESSAGE}${2}"
fi
}
# restCall method data
restCall() {
curl $CURLK -sS -X POST -H "Content-Type: application/json" -H "Cache-Control: no-cache" -d "${2}" "${remote_url}?${1}"
}
# method method
method() {
restCall $1 "$JSONDATA"
}
### Smart functions
# List all clients
# clients
clients() {
clientsGet | jq .response
}
# List all A records for a zone
# dns_as zone
dns_as() {
dns_rr $1 | jq -r ".[] | select(.type == \"A\") | .name"
}
# Add or update an A record
# dns_a_add zone name ip
dns_a_add() {
dns_zone_id $1
dns_a_id $1 $2
if [[ $dns_a_id =~ ^-?[0-9]+$ ]]; then
message 2 "DNS A $2 exists with id $dns_a_id, updating rows: "
message 1 "`dnsUpdateAByIdAndIp $dns_a_id $3 | jq -r .response`\n"
elif [[ $dns_a_id == "" ]]; then
message 2 "DNS A $2 does not exist, created ID: "
message 1 "`dnsAddAByZoneAndNameAndIp $dns_zone_id $2 $3 | jq -r .response`\n"
fi
}
# Delete an A record if it exists
# dns_a_delete zone name
dns_a_delete() {
dns_zone_id $1
dns_a_id $1 $2
if [[ $dns_a_id =~ ^-?[0-9]+$ ]]; then
message 2 "DNS A $2 has id $dns_a_id, deleted rows: "
message 1 "`dnsDeleteAById $dns_a_id | jq -r .response`\n"
else
message 2 "DNS A $2 does not exist, skipping.\n"
fi
}
# List all CNAME records for a zone
# dns_cnames zone
dns_cnames() {
dns_rr $1 | jq -r ".[] | select(.type == \"CNAME\") | .name"
}
# List all records for a zone
# dns_rr zone
dns_rr() {
dns_zone_id $1
dnsGetRrByZone $dns_zone_id | jq .response
}
# List all zones
# dns_zones
dns_zones() {
dnsGetZones | jq .response
}
# List all available methods
# methods
methods() {
methods=`functionsGet | jq .response`
if [[ $methods == "false" ]]; then
message 1 "Getting methods (Server functions) failed, check permissions?\n"
else
echo $methods | jq
fi
}
# List all servers
# server
servers() {
serversGet | jq .response
}
# Log in
# log_in remote_user remote_password
log_in() {
log_in=`logInByUserAndPassword $1 $2 | jq -r '.response'`
if [[ $log_in == "false" ]]; then
message 1 "Login failed!\n"
else
message 3 "Logged in session_id $log_in as $1.\n"
echo "$log_in"
fi
}
# Log out
# log_out session
log_out() {
if [[ `logOutBySession $1 | jq -r .response` == "true" ]]; then
message 3 "Logged out session $1 successfully.\n"
else
message 1 "Logging out failed!\n"
fi
}
### ID helpers
# Due to bash limitations, id's should only be set in _id functions below.
# This is due to nested subshells losing the variables.
# As such, some helpers may be called several times redundantly when both
# a child and parent function are also to be available on the CLI.
# Get client id
# client_id client_user
client_id() {
client_id=`clients | jq -r ".[] | select(.username == \"${1}\") | .client_id"`
message 3 "Client $1 has id $client_id.\n"
}
# Get dns A id
# dns_a_id zone name
dns_a_id() {
dns_a_id=`dns_rr $1 | jq -r ".[] | select(.name == \"${2}\") | .id"`
message 3 "DNS A $2 has id $dns_a_id.\n"
}
# Get zone id
# dns_zone_id zone
dns_zone_id() {
dns_zone_id=`dns_zones | jq -r ".[] | select(.origin == \"${1}\") | .id"`
message 3 "DNS zone $1 has id $dns_zone_id.\n"
}
### Methods
# Get clients
clientsGet() {
restCall client_get "{\"session_id\": \"${session_id}\",\"client_id\":{}}"
}
# Add A by zone and name and IP
dnsAddAByZoneAndNameAndIp() {
restCall dns_a_add "{\"session_id\": \"${session_id}\",\"client_id\": \"${client_id}\",\"params\": {\"server_id\": ${SERVER},\"zone\": \"${1}\",\"name\": \"${2}\",\"type\": \"a\",\"data\": \"${3}\",\"aux\": \"0\", \"ttl\": \"3600\", \"active\": \"y\", \"stamp\": \"${datestamp}\", \"serial\": \"1\"}}"
}
# Delete A by id
dnsDeleteAById() {
restCall dns_a_delete "{\"session_id\": \"${session_id}\",\"primary_id\": \"${1}\"}"
}
# Get RR by id
dnsGetRrByZone() {
restCall dns_rr_get_all_by_zone "{\"session_id\": \"${session_id}\",\"zone_id\": \"${1}\"}"
}
# Get zones
dnsGetZones() {
restCall dns_zone_get_by_user "{\"session_id\": \"${session_id}\",\"client_id\": \"${client_id}\",\"server_id\": ${SERVER}}"
}
# Update A by id and IP
dnsUpdateAByIdAndIp() {
restCall dns_a_update "{\"session_id\": \"${session_id}\",\"client_id\": \"${client_id}\",\"primary_id\": \"${1}\",\"params\": {\"data\": \"${2}\", \"stamp\": \"${datestamp}\"}}"
}
# Get functions
functionsGet() {
restCall get_function_list "{\"session_id\": \"${session_id}\"}"
}
# Log in by user and password
logInByUserAndPassword() {
restCall login "{\"username\": \"${1}\",\"password\": \"${2}\"}"
}
# Log out by session
logOutBySession() {
restCall logout "{\"session_id\": \"${1}\"}"
}
# Get servers info
serversGet() {
restCall server_get "{\"session_id\": \"${session_id}\",\"server_id\":{}}"
}
### Run
# Check dependencies
if ! [ -x "$(command -v curl)" ]; then
echo 'Error: curl is not installed.' >&2
exit 1
fi
if ! [ -x "$(command -v jq)" ]; then
echo 'Error: jq is not installed.' >&2
exit 1
fi
# Check config files
if [ -r /etc/ispconfig-cli.conf ]; then
. /etc/ispconfig-cli.conf
fi
if [ -r ~/.ispconfig-cli ]; then
. ~/.ispconfig-cli
fi
# Check command line
if [[ $1 == "" ]]; then
usage
exit 1
fi
SERVER=1
VERBOSITY=2
while getopts :a:e:hi:kqvb:c:f:p:tu:d:j:m:s opt; do
case $opt in
a)
if [[ -e $OPTARG ]]; then
source $OPTARG
else
echo "Config file $OPTARG not found!"
exit 1
fi
;;
e)
remote_url=$OPTARG
;;
h)
usage
exit 1
;;
i)
SERVER=$OPTARG
;;
k)
$ssl_validate=off
;;
q)
if [[ $VERBOSITY == "2" ]]; then
VERBOSITY=1
else
echo "-q and -v cannot be specified at the same time!"
exit 1
fi
;;
v)
if [[ $VERBOSITY == "2" ]]; then
VERBOSITY=3
else
echo "-q and -v cannot be specified at the same time!"
exit 1
fi
;;
b)
if [[ $METHOD == "" ]]; then
if [[ $FUNCTION == "" ]]; then
FUNCTION=`cat $OPTARG`
else
echo "You can only use one function source!"
exit 1
fi
else
echo "Function and method cannot be specified at the same time!"
exit 1
fi
;;
c)
client_user=$OPTARG
;;
f)
if [[ $METHOD == "" ]]; then
if [[ $FUNCTION == "" ]]; then
FUNCTION=$OPTARG
else
echo "You can only use one function source!"
exit 1
fi
else
echo "Function and method cannot be specified at the same time!"
exit 1
fi
;;
p)
remote_password=$OPTARG
;;
t)
if [[ $METHOD == "" ]]; then
if [[ $FUNCTION == "" ]]; then
FUNCTION=`cat`
else
echo "You can only use one function source!"
exit 1
fi
else
echo "Function and method cannot be specified at the same time!"
exit 1
fi
;;
u)
remote_user=$OPTARG
;;
d)
if [[ $JSONMODE == "" ]]; then
JSONMODE=cli
JSONDATA=$OPTARG
else
echo "You can only use one JSON data source!"
exit 1
fi
;;
j)
if [[ $JSONMODE == "" ]]; then
JSONMODE=fil
JSONDATA=`cat $OPTARG`
else
echo "You can only use one JSON data source!"
exit 1
fi
;;
m)
if [[ $FUNCTION == "" ]]; then
METHOD=$OPTARG
else
echo "Function and method cannot be specified at the same time!"
exit 1
fi
;;
s)
if [[ $JSONMODE == "" ]]; then
JSONMODE=std
JSONDATA=`cat`
else
echo "You can only use one JSON data source!"
exit 1
fi
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
if [[ $remote_url == "" ]]; then
echo "No url provided!"
exit 1
fi
if [[ $ssl_validate == "off" ]]; then
CURLK="-k"
fi
if [[ $METHOD != "" ]]; then
method $METHOD
elif [[ $FUNCTION != "" ]]; then
session_id="`log_in $remote_user $remote_password`" # This is the only ID that has to be set outside ID helpers
message 3 "Using session_id $session_id as $remote_user for CLI operations.\n"
client_id $client_user
#echo $FUNCTION|while read i; do message 1 `$i`; done # Does not work here due to creating subshells
IFS=$'\n'
for i in $FUNCTION; do eval $i; done
unset IFS
log_out $session_id
else
echo "Neither method nor function specified!"
exit 1
fi
echo -e $MESSAGE
exit 0