-
Notifications
You must be signed in to change notification settings - Fork 19
/
ph
executable file
·318 lines (274 loc) · 9.09 KB
/
ph
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
#!/bin/bash
########################################################################################################################
#
# Panhandler start up tool
#
# This script will check for updates to the paloaltonetworks/panhandler:dev image and start / restart / recreate
# the panhandler container as necessary
#
# Feel free to leave feedback at: https://github.com/PaloAltoNetworks/panhandler/issues
#
########################################################################################################################
export IMAGE_TAG="${IMAGE_TAG:=latest}"
export DEFAULT_PORT="${DEFAULT_PORT:=8080}"
export FORCE_DEFAULT_PORT="${FORCE_DEFAULT_PORT:=false}"
export RESET_REPOSITORIES=false
export NEEDS_UPDATE=false
export CNC_VOLUME=pan_cnc_volume
export PANHANDLER_VOLUME=panhandler_volume
# used for filtering containers
export DEV_EXPOSED_PORT=8080
export LATEST_EXPOSED_PORT=8080
# used to check if the user has supplied a non-default port
export DEV_DEFAULT_PORT=8081
export LATEST_DEFAULT_PORT=8080
# default panhandler auth if not set from the environment
export CNC_USERNAME="${CNC_USERNAME:=paloalto}"
export CNC_PASSWORD="${CNC_PASSWORD:=panhandler}"
function ensure_docker_volume() {
if [[ ! $(docker volume ls -q -f name=$CNC_VOLUME) ]]; then
echo "Creating data volume"
docker volume create $CNC_VOLUME
fi
if [[ ! $(docker volume ls -q -f name=$PANHANDLER_VOLUME) ]]; then
echo "Creating home volume"
docker volume create $PANHANDLER_VOLUME
fi
}
function validate_container_id() {
# container id will always be 13 characters. Anything is either blank or an error message along the way
# example: b977b1401f9e
PH_ID=$1
echo " " >&2
echo " Checking ${PH_ID}" >&2
if [[ -z $PH_ID ]]; then
return 1
fi
len=$(echo $1 | wc -c | sed -e 's/ //g')
if [[ $len -eq '13' ]]; then
return 0
else
return 1
fi
}
function find_panhandler_container_id() {
# first check for a name and ancestor
PANHANDLER_ID=$(docker ps -a -q -f name=panhandler -f ancestor="$PANHANDLER_IMAGE")
if validate_container_id "${PANHANDLER_ID}"; then
echo "${PANHANDLER_ID}"
return 0
fi
# maybe name hasn't been set but we have the right image here
PANHANDLER_ID=$(docker ps -a -q -f ancestor="$PANHANDLER_IMAGE")
if validate_container_id "${PANHANDLER_ID}"; then
echo "${PANHANDLER_ID}"
return 0
fi
# in the following cases, maybe the user has pulled a new image in which case we can no longer see the ancestor image
# we will have to filter images using the known exposed ports
# ancestor is no longer available after a pull, check for a name being set and the exposed port
PANHANDLER_ID=$(docker ps -a -q -l -f name=panhandler -f expose="${EXPOSED_PORT}")
if validate_container_id "${PANHANDLER_ID}"; then
# since the ancestor is incorrect, we know we're gonna need to stop, rm, and recreate
NEEDS_UPDATE=true
export NEEDS_UPDATE
echo "${PANHANDLER_ID}"
return 0
fi
# ok, no ancestor and no name is set either :-|
# filter on known command string, known exposed port, and ensure a published port (grep tcp ensures this)
# finally, only return the first match found in case we have more than 1 for some reason...
PANHANDLER_ID=$(
docker ps -a --format "{{.ID}} {{.Command}} {{ .Ports}}" -f expose="${EXPOSED_PORT}" |
grep '/app/cnc/tools/ph.sh' |
grep 'tcp' |
head -1 |
awk '{ print $1} '
)
if validate_container_id "${PANHANDLER_ID}"; then
# since the ancestor is incorrect, we know we're gonna need to stop, rm, and recreate
NEEDS_UPDATE=true
export NEEDS_UPDATE
echo "${PANHANDLER_ID}"
return 0
fi
# at this point we can be reasonably sure panhandler does not exist on this instance in some form or fashion
return 1
}
function container_has_correct_image() {
FOUND=$(docker ps -a -q -f id="$PANHANDLER_ID" -f ancestor="$PANHANDLER_IMAGE")
if validate_container_id "$FOUND"; then
return 0
fi
# this container has an out of date image
return 1
}
function create_panhandler_container() {
echo " Creating and running new Panhandler container"
echo " "
# shellcheck disable=SC2086
ensure_docker_volume
docker run -p ${DEFAULT_PORT}:${LATEST_EXPOSED_PORT} -t -d \
-v "$PANHANDLER_VOLUME":/home/cnc_user \
-v "$CNC_VOLUME":/home/cnc_user/.pan_cnc \
-v "/var/run/docker.sock:/var/run/docker.sock" \
-e CNC_USERNAME \
-e CNC_PASSWORD \
--name panhandler "${PANHANDLER_IMAGE}"
# check if on a mac - this is only needed on Linux
if uname -a | grep -q -i darwin; then
return 0
fi
}
function get_existing_published_port() {
FOUND_PORT=$(docker inspect "${PANHANDLER_ID}" |
grep "HostPort" |
head -1 |
awk '{ print $2 }' |
sed -e 's/"//g')
if [[ -n $FOUND_PORT ]]; then
echo "$FOUND_PORT"
else
echo "$DEFAULT_PORT"
fi
}
while getopts ":t:r:p:w:u:h" opt; do
case ${opt} in
t)
IMAGE_TAG="$OPTARG"
;;
p)
DEFAULT_PORT="$OPTARG"
FORCE_DEFAULT_PORT=true
;;
r)
RESET_REPOSITORIES="$OPTARG"
;;
w)
CNC_PASSWORD="$OPTARG"
;;
u)
CNC_USERNAME="$OPTARG"
;;
h)
echo "Valid options are: "
echo "-t Image tag (latest, dev, beta)"
echo "-p local port binding, default is 8080 *note this will be ignored if the container is already running"
echo "-r Reset Panhandler local settings (true, false)"
echo "Reset will remove all imported repositories, local caches, and environments"
exit 0
;;
\?)
echo "Invalid option -$OPTARG" >&2
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
case ${IMAGE_TAG} in
latest) ;;
dev) ;;
beta) ;;
\?)
echo "Invalid tag - Please use latest, dev, or beta"
exit 1
;;
esac
if [[ ! $(command -v docker) ]]; then
echo "Could not find the docker command, please ensure you have docker installed on this machine"
exit 1
fi
echo "==================================================================================================="
echo " "
echo " Welcome to Panhandler"
echo " "
echo "==================================================================================================="
if [[ ${IMAGE_TAG} == latest ]]; then
EXPOSED_PORT=${LATEST_EXPOSED_PORT}
export EXPOSED_PORT
# now that we (maybe?) have the container ID, ensure we use the latest tag from here on out
PANHANDLER_IMAGE=paloaltonetworks/panhandler:latest
export PANHANDLER_IMAGE
PANHANDLER_ID=$(find_panhandler_container_id)
export PANHANDLER_ID
else
EXPOSED_PORT=${DEV_EXPOSED_PORT}
export EXPOSED_PORT
PANHANDLER_IMAGE=paloaltonetworks/panhandler:${IMAGE_TAG}
export PANHANDLER_IMAGE
# fix for returning more than 1 container. This returns only the latest created container
PANHANDLER_ID=$(find_panhandler_container_id)
export PANHANDLER_ID
fi
echo " "
echo " Checking for image updates ... (This may take some time while the image downloads)"
docker pull "${PANHANDLER_IMAGE}" | grep 'Image is up to date' >/dev/null
# shellcheck disable=SC2181
if [[ $? -eq 0 ]]; then
echo " "
echo " ${PANHANDLER_IMAGE} is already up to date!"
else
echo " Panhandler is out of date, and will need to be restarted"
echo " "
NEEDS_UPDATE=true
fi
if [[ ${RESET_REPOSITORIES} == true ]]; then
echo " "
echo " Moving Panhandler data directory to backup"
DATESTRING=$(date "+%Y-%m-%d-%H:%M:%S")
# shellcheck disable=SC2086
mv ~/.pan_cnc/panhandler ~/.pan_cnc/panhandler.backup.${DATESTRING}
mkdir ~/.pan_cnc/panhandler
fi
if [[ -z "${PANHANDLER_ID}" ]]; then
echo " "
echo " ${PANHANDLER_IMAGE} has not been started..."
create_panhandler_container
else
echo " "
echo " Found container id of ${PANHANDLER_ID}"
# we have a valid container id from a previous run, let's ensure it has the correct image as it's ancestor
if container_has_correct_image; then
echo " "
echo " This container is up-to-date!"
NEEDS_UPDATE=false
else
echo " "
echo " This container is out-of-date"
NEEDS_UPDATE=true
fi
if [[ ${NEEDS_UPDATE} == true ]]; then
#
# Set the port to the value the user is already using
#
if [[ ${FORCE_DEFAULT_PORT} == false ]]; then
echo " "
echo " Getting existing port mapping for re-use"
# check if the user has passed in a port that is not the default. If so
# we should always use that one
if [[ ${LATEST_DEFAULT_PORT} == {$DEFAULT_PORT} ]]; then
DEFAULT_PORT=$(get_existing_published_port)
fi
echo " "
echo " Using ${DEFAULT_PORT} as local port mapping"
fi
echo " "
echo " Stopping Panhandler container"
docker stop "${PANHANDLER_ID}"
echo " "
echo " Removing old Panhandler container"
docker rm -f "${PANHANDLER_ID}"
create_panhandler_container
else
DEFAULT_PORT=$(get_existing_published_port)
echo " "
echo " Panhandler is already up to date. Ensuring it's running"
docker start "${PANHANDLER_ID}" >>/dev/null 2>&1
fi
fi
echo " "
echo " You may now use Panhandler by opening a web browser and browsing to http://localhost:${DEFAULT_PORT}"
echo " "
echo "==================================================================================================="