-
Notifications
You must be signed in to change notification settings - Fork 26
/
ops-pod
executable file
·193 lines (172 loc) · 6.36 KB
/
ops-pod
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
#!/bin/bash -e
# SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors
#
# SPDX-License-Identifier: Apache-2.0
# open terminal into cluster node
function print_usage() {
cat <<EOF
ops-pod: Deploy privileged pod in a kubernetes cluster and open terminal into cluster node using the current kubectl context.
When specifying <pod-name> the node of the specified pod will be used.
Usage:
ops-pod [OPTIONS] <node|pod-name>
Options:
-n|--namespace The namespace into which the pod will be deployed. The namespace of the current kubectl context is used by default.
-t|--tolerations When this flag is set the taints of the selected node will be used as tolerations for the ops pod. By default
the ops pod is started with the following tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
- operator: Exists
effect: NoExecute
- key: CriticalAddonsOnly
operator: Exists
-i|--image Image to use for the privileged pod. The default value is: europe-docker.pkg.dev/sap-se-gcp-k8s-delivery/releases-public/eu_gcr_io/gardener-project/gardener/ops-toolbelt:latest
-c|--chroot When this flag is set the host's root directory will also be used as root directory of the pod. By default the host's
root directory is mounted under /host on the pod.
-o|--hostnetwork Whether to change the hostNetwork attribute to true.
EOF
}
FALSE=0
TRUE=1
namespace=
node=
image=
tolerations_array="
- operator: Exists
"
hostnetwork="false"
copy_tolerations=${FALSE}
node_chroot=${FALSE}
sanitize_hostname() {
# K8s rejects pod names that violate this RE '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*'
# due to RFC1123 (Only allow lower-case and alphanumerical values for hostnames)
echo "$@" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g'
}
name="$(sanitize_hostname "ops-pod-$(whoami)")"
default_image="europe-docker.pkg.dev/gardener-project/releases/gardener/ops-toolbelt:latest"
function get_default_namespace() {
_namespace=$(kubectl config view -o jsonpath="{.contexts[?(@.name == \"$(kubectl config current-context)\")].context.namespace}")
echo "${_namespace:-default}"
}
positional=()
while [[ $# -gt 0 ]]; do
key="${1}"
case ${key} in
-n|--namespace)
namespace="${2}"
shift
shift
;;
-i|--image)
image="${2}"
shift
shift
;;
-c|--chroot)
node_chroot=${TRUE}
shift
;;
-t|--toleration)
copy_tolerations=${TRUE}
shift
;;
-o|--hostnetwork)
hostnetwork="true"
shift
;;
-h|--help)
print_usage
exit 0
;;
*)
positional+=("${1}")
shift
;;
esac
done
if [[ ${#positional[@]} -ne 1 ]]; then
echo -e "Error: Required one positional argument: <node|pod-name> found ${#positional[@]}\n"
print_usage
exit 1
fi
node=${positional[0]}
image=${image:-$default_image}
namespace=${namespace:-$(get_default_namespace)}
node_of_pod=$(kubectl -n ${namespace} get pod ${node} -o jsonpath={.spec.nodeName} 2> /dev/null || true)
if [[ -n ${node_of_pod} ]]; then
echo -e "Pod name provided. Deploying ops pod on the node where ${node} is running: ${node_of_pod}\n"
node=$node_of_pod
else
echo "Node name provided ..."
available_nodes=( $(kubectl get nodes | awk '{print $1}' | grep -v NAME) )
if [[ " ${available_nodes[*]} " =~ " ${node} " ]]; then
echo -e "Deploying ops pod on ${node}\n"
else
echo -e "Error: node ${node} does not exist in the cluster.\n"
print_usage
fi
fi
# check if the node name was a pod name and we should actually identify the node from the pod (node that runs the pod)
# Kubify nodes have labels that differ from the names (need an additional suffix)
node=$(echo "$node" | sed -r "s/^(garden-.*)/\1.openstack.local/")
if [[ $copy_tolerations -eq $TRUE ]]; then
tolerations_array=$(kubectl get nodes ${node} -o jsonpath='{range .spec.taints[*]} - effect: "{@.effect}"{"\n"} key: "{@.key}"{"\n"} value: "{@.value}"{"\n"} operator: "{@.operator}"{"\n"}{end}')
fi
# get rid of former pod (if present; best effort)
kubectl -n $namespace delete pod $name &> /dev/null || true
while kubectl -n $namespace get pod $name &> /dev/null; do echo "Waiting for old pod to be deleted..."; sleep 1; done
# get rid of pod
trap "EC=\$?; kubectl -n $namespace delete pod $name --wait=false >&2 || true; exit \$EC" EXIT INT TERM
# launch pod
kubectl -n $namespace create -f <(cat << EOF
apiVersion: v1
kind: Pod
metadata:
name: $name
spec:
$([[ ! -z $node ]] && echo -e "nodeSelector:\n kubernetes.io/hostname: $node")
tolerations:
$tolerations_array
containers:
- name: ops-pod
image: ${image}
command:
- sleep
- "43200"
resources:
limits:
cpu: 200m
memory: 100Mi
requests:
cpu: 100m
memory: 50Mi
stdin: true
securityContext:
privileged: true
volumeMounts:
- name: host-root-volume
mountPath: /host
readOnly: false
mountPropagation: HostToContainer
volumes:
- name: host-root-volume
hostPath:
path: /
hostNetwork: ${hostnetwork}
hostPID: true
restartPolicy: Never
enableServiceLinks: false
EOF
)
while [[ $(kubectl -n $namespace get pods | sed -n -r "s/^$name.*Running.*$/Running/p") != "Running" ]]; do echo "Waiting for pod to be running..."; sleep 1; done;
# exec into pod (and chroot into node if a node was selected)
if [[ ${node_chroot} -eq ${TRUE} ]]; then
kubectl -n $namespace exec -ti $name -- bash -c 'rm -rf /host/root/dotfiles 1> /dev/null; \
cp -r /root/dotfiles /host/root 1> /dev/null; \
cp -r /hacks /host 1> /dev/null; rm -f /host/root/.bashrc; \
ln -s /root/dotfiles/.bashrc /host/root/.bashrc 1> /dev/null; export PATH="/hacks:$PATH"; \
echo -e "\nBE CAREFUL!!! Node root directory mounted under / \n"; \
chroot /host /bin/bash'
else
kubectl -n $namespace exec -ti $name -- bash -c "echo -e '\nNode root dir is mounted under /host' >> /etc/motd; /bin/bash"
fi