-
Notifications
You must be signed in to change notification settings - Fork 71
/
rhcos-toolbox
executable file
·225 lines (197 loc) · 7.32 KB
/
rhcos-toolbox
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
#!/bin/bash
set -eo pipefail
trap cleanup EXIT
# Defaults
REGISTRY=registry.redhat.io
IMAGE=rhel9/support-tools
AUTHFILE=/var/lib/kubelet/config.json
TOOLBOX_NAME=toolbox-"$(whoami)"
TOOLBOXRC="${HOME}"/.toolboxrc
errecho() {
>&2 echo "${@}"
}
setup() {
# Allow user overrides
if [ -f "${TOOLBOXRC}" ]; then
errecho ".toolboxrc file detected, overriding defaults..."
# This file only potentially exists on a running system
# shellcheck disable=SC1090
source "${TOOLBOXRC}"
fi
TOOLBOX_IMAGE="${REGISTRY}"/"${IMAGE}"
}
run() {
# Pull the container image if it does not exists yet
if ! image_exists; then
image_pull
if container_exists; then
sudo podman rm "${TOOLBOX_NAME}"
fi
# If it already exists, make sure it is up-to-date
elif ! image_fresh; then
>&2 read -r -p "There is a newer version of ${TOOLBOX_IMAGE} available. Would you like to pull it? [y/N] "
if [[ ${REPLY} =~ ^([Yy][Ee][Ss]|[Yy])+$ ]]; then
image_pull
if container_exists; then
sudo podman rm "${TOOLBOX_NAME}"
fi
else
errecho "Skipping retrieval of new image.."
fi
fi
# If the container does not already exists, create it, while making sure to
# use the option from the RUN label if provided
local runlabel
runlabel=$(image_runlabel)
if ! container_exists; then
errecho "Spawning a container '${TOOLBOX_NAME}' with image '${TOOLBOX_IMAGE}'"
if [[ -z "${runlabel}" ]] || [[ "${runlabel}" == "<no value>" ]]; then
container_create
else
errecho "Detected RUN label in the container image. Using that as the default..."
container_create_runlabel
fi
else
errecho "Container '${TOOLBOX_NAME}' already exists. Trying to start..."
errecho "(To remove the container and start with a fresh toolbox, run: sudo podman rm '${TOOLBOX_NAME}')"
fi
# Start our freshly created container
local state
state=$(container_state)
if [[ "${state}" == configured ]] || [[ "${state}" == created ]] || [[ "${state}" == exited ]] || [[ "${state}" == stopped ]]; then
container_start
elif [[ "${state}" != running ]]; then
errecho "Container '${TOOLBOX_NAME}' in unknown state: '$state'"
return 1
fi
if [[ "$#" -eq "0" ]]; then
errecho "Container started successfully. To exit, type 'exit'."
fi
# Attach to the interactive shell in the container or directly execute the
# command passed as argument
container_exec "$@"
}
cleanup() {
sudo podman stop "${TOOLBOX_NAME}" &>/dev/null
}
container_exists() {
sudo podman container inspect "${TOOLBOX_NAME}" &>/dev/null
}
container_state() {
sudo podman container inspect "${TOOLBOX_NAME}" --format '{{.State.Status}}'
}
image_exists() {
sudo podman image inspect "${TOOLBOX_IMAGE}" &>/dev/null
}
# returns 0 if the image on disk is "fresh", i.e. no newer image on remote
# registry. (or if we couldn't inspect the registry successfully)
image_fresh() {
errecho "Checking if there is a newer version of ${TOOLBOX_IMAGE} available..."
local_date=$(sudo podman image inspect "${TOOLBOX_IMAGE}" --format '{{.Created}}')
if ! remote_date=$(sudo --preserve-env skopeo inspect --authfile "${AUTHFILE}" docker://"${TOOLBOX_IMAGE}" --format '{{.Created}}'); then
errecho "Error inspecting ${TOOLBOX_IMAGE} via skopeo"
return
fi
# if the date on the registry is *NOT* newer than the local image date
# then we return 1. (doing a less-than comparison of the strings always
# fails if they are the same, hence the weird conditional here)
! [[ "${remote_date}" > "${local_date}" ]]
}
image_runlabel() {
sudo podman image inspect "${TOOLBOX_IMAGE}" --format '{{- if index .Labels "run" -}}{{.Labels.run}}{{- end -}}'
}
image_pull() {
if ! sudo --preserve-env podman pull --authfile "${AUTHFILE}" "${TOOLBOX_IMAGE}"; then
>&2 read -r -p "Would you like to manually authenticate to registry: '${REGISTRY}' and try again? [y/N] "
if [[ ${REPLY} =~ ^([Yy][Ee][Ss]|[Yy])+$ ]]; then
sudo --preserve-env podman login --authfile "${AUTHFILE}" "${REGISTRY}"
sudo --preserve-env podman pull --authfile "${AUTHFILE}" "${TOOLBOX_IMAGE}"
else
errecho "Exiting..."
exit 1
fi
fi
}
container_create() {
local -r cmd=$(sudo podman image inspect "${TOOLBOX_IMAGE}" | jq -re ".[].Config.Cmd[0]") || cmd="/bin/sh"
if ! sudo podman create \
--hostname toolbox \
--name "${TOOLBOX_NAME}" \
--privileged \
--net=host \
--pid=host \
--ipc=host \
--tty \
--interactive \
--env HOST=/host \
--env NAME="${TOOLBOX_NAME}" \
--env IMAGE="${IMAGE}" \
--security-opt label=disable \
--volume /run:/run \
--volume /var/log:/var/log \
--volume /etc/machine-id:/etc/machine-id \
--volume /etc/localtime:/etc/localtime \
--volume /:/host \
"${TOOLBOX_IMAGE}" "${cmd}"; then
errecho "$0: failed to create container '${TOOLBOX_NAME}'"
exit 1
fi
}
container_start() {
if ! sudo podman start "${TOOLBOX_NAME}"; then
errecho "$0: failed to start container '${TOOLBOX_NAME}'"
exit 1
fi
}
container_create_runlabel() {
# Variable replacement logic reproduced from:
# https://github.com/containers/podman/blob/29d7ab3f82e38c442e449739e218349b9a4a16ea/pkg/domain/infra/abi/containers_runlabel.go#L226
local pod
pod="$(echo "${runlabel}" \
| sed 's/podman run/sudo podman create/' \
| sed 's/--name NAME/--name ${TOOLBOX_NAME}/' \
| sed 's/NAME=NAME/NAME=${TOOLBOX_NAME}/' \
| sed 's/IMAGE=IMAGE/IMAGE=${TOOLBOX_IMAGE}/' \
| sed 's/host IMAGE/host ${TOOLBOX_IMAGE}/')"
if ! eval "${pod}" ; then
errecho "$0: failed to create container from runlabel '${TOOLBOX_NAME}'"
exit 1
fi
}
container_exec() {
if [[ "$#" -eq 0 ]]; then
sudo podman attach "${TOOLBOX_NAME}"
else
echo "${*}; exit" | sudo podman attach "${TOOLBOX_NAME}"
fi
}
show_help() {
errecho "USAGE: toolbox [-h/--help] [command]
toolbox is a small script that launches a container to let you bring in your favorite debugging or admin tools.
The toolbox container is a pet container and will be restarted on following runs.
To remove the container and start fresh, do sudo podman rm ${TOOLBOX_NAME}.
Options:
-h/--help: Shows this help message
You may override the following variables by setting them in ${TOOLBOXRC}:
- REGISTRY: The registry to pull from. Default: ${REGISTRY}
- IMAGE: The image and tag from the registry to pull. Default: ${IMAGE}
- TOOLBOX_NAME: The name to use for the local container. Default: ${TOOLBOX_NAME}
- AUTHFILE: The location where your registry credentials are stored. Default: ${AUTHFILE}
Example toolboxrc:
REGISTRY=my.special.registry.example.com
IMAGE=debug:latest
TOOLBOX_NAME=special-debug-container
AUTHFILE=/home/core/.docker/config.json"
}
main() {
# Execute setup first so we get proper variables
setup
# If we are passed a help switch, show help and exit
if [[ "$1" =~ ^(--help|-h)$ ]]; then
show_help
exit 0
fi
run "$@"
cleanup
}
main "$@"