Skip to content

Commit de91283

Browse files
authored
Allow the Kubernetes agent to be registered with a pre-install hook (#1057)
* Add register.sh preinstall hook * Add migration command for agent pre-installation * Fix downloader tools on MacOS * Add migration command tests * Test fixes * Add unimplemented client config provider to allow help initialization * Add better exception logging * Set environment variable to allow test to run * Update test * PR Feedback * PR feedback * Add environment variable for specifying alternate stores for the agent
1 parent ea2aeed commit de91283

File tree

14 files changed

+726
-10
lines changed

14 files changed

+726
-10
lines changed

docker/kubernetes-agent-tentacle/scripts/configure-and-run.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ function validateWorkerVariables() {
156156
echo " - worker pools '$WorkerPools'"
157157
}
158158

159+
function migrateFromPreinstallScript() {
160+
tentacle migrate-preinstalled-k8s-config \
161+
--source-config-map-name "tentacle-config-pre" \
162+
--source-secret-name "tentacle-secret-pre" \
163+
--destination-config-map-name "tentacle-config" \
164+
--destination-secret-name "tentacle-secret"
165+
}
166+
159167
function configureTentacle() {
160168
tentacle create-instance --instance "$instanceName" --config "$configurationDirectory/tentacle.config" --home "$configurationDirectory"
161169

@@ -409,6 +417,9 @@ function markAsInitialised() {
409417
setupVariablesForRegistrationCheck
410418
getStatusOfRegistration
411419

420+
# We expect the tentacle to always be registered due to the new pre-install hook
421+
# But keeping this here just in case
422+
# We can remove it in future if we need to
412423
if [ "$IS_REGISTERED" == "true" ]; then
413424
echo "Tentacle is already configured and registered with server."
414425
addAdditionalServerInstancesIfRequired
@@ -421,6 +432,7 @@ else
421432

422433
echo "==============================================="
423434

435+
migrateFromPreinstallScript
424436
configureTentacle
425437
registerTentacle
426438
addAdditionalServerInstancesIfRequired
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
#!/bin/bash
2+
set -eu
3+
4+
if [[ "$ACCEPT_EULA" != "Y" ]]; then
5+
echo "ERROR: You must accept the EULA at https://octopus.com/company/legal by passing an environment variable 'ACCEPT_EULA=Y'"
6+
exit 1
7+
fi
8+
9+
# In the scenario where a customer is using a custom certificate (which is mounted via a config map), we need to rehash the certificates
10+
# We just do this all the time because there is no downside
11+
echo "Rehashing SSL/TLS certificates"
12+
openssl rehash /etc/ssl/certs
13+
14+
# Tentacle Docker images only support once instance per container. Running multiple instances can be achieved by running multiple containers.
15+
instanceName=Tentacle
16+
internalListeningPort=10933
17+
18+
#If TentacleHome environment variable exists, use that
19+
configurationDirectory=/etc/octopus
20+
if [[ -n "$TentacleHome" ]]; then
21+
configurationDirectory="$TentacleHome"
22+
fi
23+
24+
#If TentacleApplications environment variable exists, use that
25+
applicationsDirectory=/home/Octopus/Applications
26+
if [[ -n "$TentacleApplications" ]]; then
27+
applicationsDirectory="$TentacleApplications"
28+
fi
29+
30+
mkdir -p $configurationDirectory
31+
mkdir -p $applicationsDirectory
32+
33+
if [ ! -f /usr/bin/tentacle ]; then
34+
ln -s /opt/octopus/tentacle/Tentacle /usr/bin/tentacle
35+
fi
36+
37+
function getPublicHostName() {
38+
if [[ "$PublicHostNameConfiguration" == "PublicIp" ]]; then
39+
curl https://api.ipify.org/
40+
elif [[ "$PublicHostNameConfiguration" == "FQDN" ]]; then
41+
hostname --fqdn
42+
elif [[ "$PublicHostNameConfiguration" == "ComputerName" ]]; then
43+
hostname
44+
else
45+
echo $CustomPublicHostName
46+
fi
47+
}
48+
49+
function validateVariables() {
50+
validateCommonVariables
51+
52+
if [[ "$DeploymentTargetEnabled" != "true" && "$WorkerEnabled" != "true" ]]; then
53+
echo "Please specify whether to install as a worker or a deployment target with the 'WorkerEnabled' or 'DeploymentTargetEnabled' environment variables" >&2
54+
exit 1
55+
fi
56+
57+
if [[ "$DeploymentTargetEnabled" == "true" && "$WorkerEnabled" == "true" ]]; then
58+
echo "The installation cannot be as both a worker and a deployment target, please choose one" >&2
59+
exit 1
60+
fi
61+
62+
if [[ "$DeploymentTargetEnabled" == "true" ]]; then
63+
validateDeploymentTargetVariables
64+
fi
65+
66+
if [[ "$WorkerEnabled" == "true" ]]; then
67+
validateWorkerVariables
68+
fi
69+
}
70+
71+
function validateCommonVariables() {
72+
if [[ -z "$ServerApiKey" && -z "$BearerToken" ]]; then
73+
if [[ -z "$ServerPassword" || -z "$ServerUsername" ]]; then
74+
echo "Please specify either an API key, a Bearer Token or a username/password with the 'ServerApiKey' or 'ServerUsername'/'ServerPassword' environment variables" >&2
75+
exit 1
76+
fi
77+
fi
78+
79+
if [[ -z "$ServerUrl" ]]; then
80+
echo "Please specify an Octopus Server with the 'ServerUrl' environment variable" >&2
81+
exit 1
82+
fi
83+
84+
echo " - server endpoint '$ServerUrl'"
85+
echo " - api key '##########'"
86+
echo " - host '$PublicHostNameConfiguration'"
87+
88+
if [[ -n "$ServerCommsAddress" || -n "$ServerCommsAddresses" || -n "$ServerPort" ]]; then
89+
echo " - communication mode 'Kubernetes' (Polling)"
90+
91+
if [[ -n "$ServerCommsAddress" ]]; then
92+
echo " - server comms address $ServerCommsAddress"
93+
fi
94+
if [[ -n "$ServerCommsAddresses" ]]; then
95+
echo " - HA server comms addresses $ServerCommsAddresses"
96+
fi
97+
if [[ -n "$ServerPort" ]]; then
98+
echo " - server port $ServerPort"
99+
fi
100+
if [[ -n "$ServerSubscriptionId" ]]; then
101+
echo " - server subscription id '$ServerSubscriptionId'"
102+
fi
103+
else
104+
echo " - communication mode 'Kubernetes' (Listening)"
105+
echo " - registered port $ListeningPort"
106+
fi
107+
108+
if [[ -n "$AgentName" ]]; then
109+
echo " - name '$AgentName'"
110+
fi
111+
112+
if [[ -n "$Space" ]]; then
113+
echo " - space '$Space'"
114+
fi
115+
116+
if [[ -n "$TentacleCertificateBase64" ]]; then
117+
echo " - tentacle certificate '${TentacleCertificateBase64:0:3}...${TentacleCertificateBase64: -3}'"
118+
fi
119+
}
120+
121+
function validateDeploymentTargetVariables() {
122+
if [[ -z "$TargetEnvironment" ]]; then
123+
echo "Please specify one or more environment names/ids/slugs (comma delimited) with the 'TargetEnvironment' environment variable" >&2
124+
exit 1
125+
fi
126+
127+
if [[ -z "$TargetRole" ]]; then
128+
echo "Please specify one or more role names (comma delimited) with the 'TargetRole' environment variable" >&2
129+
exit 1
130+
fi
131+
132+
echo " - environment '$TargetEnvironment'"
133+
echo " - role '$TargetRole'"
134+
135+
if [[ -n "$TargetTenant" ]]; then
136+
echo " - tenant '$TargetTenant'"
137+
fi
138+
if [[ -n "$TargetTenantTag" ]]; then
139+
echo " - tenant tag '$TargetTenantTag'"
140+
fi
141+
if [[ -n "$TargetTenantedDeploymentParticipation" ]]; then
142+
echo " - tenanted deployment participation '$TargetTenantedDeploymentParticipation'"
143+
fi
144+
145+
if [[ -n "$DefaultNamespace" ]]; then
146+
echo " - default namespace '$DefaultNamespace'"
147+
fi
148+
}
149+
150+
function validateWorkerVariables() {
151+
if [[ -z "$WorkerPools" ]]; then
152+
echo "Please specify one or more worker pool names/ids/slugs (comma delimited) with the 'WorkerPools' environment variable" >&2
153+
exit 1
154+
fi
155+
156+
echo " - worker pools '$WorkerPools'"
157+
}
158+
159+
function configureTentacle() {
160+
tentacle create-instance --instance "$instanceName" --config "$configurationDirectory/tentacle.config" --home "$configurationDirectory"
161+
162+
echo "Setting directory paths ..."
163+
tentacle configure --instance "$instanceName" --app "$applicationsDirectory"
164+
165+
echo "Configuring communication type ..."
166+
if [[ -n "$ServerCommsAddress" || -n "$ServerCommsAddresses" || -n "$ServerPort" ]]; then
167+
tentacle configure --instance "$instanceName" --noListen "True"
168+
else
169+
tentacle configure --instance "$instanceName" --port $internalListeningPort --noListen "False"
170+
fi
171+
172+
if [[ -n "$TentacleCertificateBase64" ]]; then
173+
echo "Importing custom certificate ..."
174+
tentacle import-certificate --instance "$instanceName" --from-base64="$TentacleCertificateBase64"
175+
else
176+
echo "Creating certificate ..."
177+
tentacle new-certificate --instance "$instanceName" --if-blank
178+
fi
179+
}
180+
181+
function setupVariablesForRegistrationCheck() {
182+
local namespace=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
183+
local config_map_name="tentacle-config"
184+
SERVICE_URL="https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1/namespaces/$namespace/configmaps/$config_map_name"
185+
SERVICE_ACCOUNT_TOKEN_PATH="/var/run/secrets/kubernetes.io/serviceaccount/token"
186+
}
187+
188+
function getStatusOfRegistration() {
189+
echo "Checking registration status..."
190+
191+
IS_REGISTERED=$(curl -s --request GET \
192+
--url "$SERVICE_URL" \
193+
--header "Authorization: Bearer $(cat $SERVICE_ACCOUNT_TOKEN_PATH)" \
194+
--header 'Accept: application/json' \
195+
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt |
196+
grep -o '"Tentacle.Services.IsRegistered": "[^"]*"' |
197+
cut -d'"' -f4)
198+
}
199+
200+
function registerTentacle() {
201+
echo "Registering with server ..."
202+
203+
local ARGS=()
204+
205+
if [[ "$DeploymentTargetEnabled" == "true" ]]; then
206+
ARGS+=('register-k8s-target')
207+
208+
if [[ -n "$TargetEnvironment" ]]; then
209+
IFS=',' read -ra ENVIRONMENTS <<<"$TargetEnvironment"
210+
for i in "${ENVIRONMENTS[@]}"; do
211+
ARGS+=('--environment' "$i")
212+
done
213+
fi
214+
215+
if [[ -n "$TargetRole" ]]; then
216+
IFS=',' read -ra ROLES <<<"$TargetRole"
217+
for i in "${ROLES[@]}"; do
218+
ARGS+=('--role' "$i")
219+
done
220+
fi
221+
222+
if [[ -n "$TargetTenant" ]]; then
223+
IFS=',' read -ra TENANTS <<<"$TargetTenant"
224+
for i in "${TENANTS[@]}"; do
225+
ARGS+=('--tenant' "$i")
226+
done
227+
fi
228+
229+
if [[ -n "$TargetTenantTag" ]]; then
230+
IFS=',' read -ra TENANTTAGS <<<"$TargetTenantTag"
231+
for i in "${TENANTTAGS[@]}"; do
232+
ARGS+=('--tenanttag' "$i")
233+
done
234+
fi
235+
236+
if [[ -n "$TargetTenantedDeploymentParticipation" ]]; then
237+
ARGS+=('--tenanted-deployment-participation' "$TargetTenantedDeploymentParticipation")
238+
fi
239+
240+
if [[ -n "$DefaultNamespace" ]]; then
241+
ARGS+=('--default-namespace' "$DefaultNamespace")
242+
fi
243+
elif [[ "$WorkerEnabled" == "true" ]]; then
244+
ARGS+=('register-k8s-worker')
245+
246+
if [[ -n "$WorkerPools" ]]; then
247+
IFS=',' read -ra WORKERPOOLS <<<"$WorkerPools"
248+
for i in "${WORKERPOOLS[@]}"; do
249+
ARGS+=('--workerpool' "$i")
250+
done
251+
fi
252+
fi
253+
254+
ARGS+=(
255+
'--instance' "$instanceName"
256+
'--server' "$ServerUrl"
257+
'--space' "$Space"
258+
'--policy' "$MachinePolicy")
259+
260+
if [[ -n "$AgentName" ]]; then
261+
ARGS+=('--name' "$AgentName")
262+
fi
263+
264+
if [[ -n "$ServerCommsAddress" || -n "$ServerCommsAddresses" || -n "$ServerPort" ]]; then
265+
ARGS+=('--comms-style' 'TentacleActive')
266+
267+
# If ServerCommsAddress (singular) is not set, use the first value in ServerCommsAddresses (plural)
268+
if [[ -n "$ServerCommsAddress" ]]; then
269+
ARGS+=('--server-comms-address' "$ServerCommsAddress")
270+
elif [[ -n "$ServerCommsAddresses" ]]; then
271+
IFS=',' read -ra SERVER_ADDRESSES <<<"$ServerCommsAddresses"
272+
ARGS+=('--server-comms-address' "${SERVER_ADDRESSES[0]}")
273+
fi
274+
275+
if [[ -n "$ServerPort" ]]; then
276+
ARGS+=('--server-comms-port' $ServerPort)
277+
fi
278+
279+
if [[ -n "$ServerSubscriptionId" ]]; then
280+
ARGS+=('--server-subscription-id' $ServerSubscriptionId)
281+
fi
282+
else
283+
ARGS+=(
284+
'--comms-style' 'TentaclePassive'
285+
'--publicHostName' $(getPublicHostName))
286+
287+
if [[ -n "$ListeningPort" && "$ListeningPort" != "$internalListeningPort" ]]; then
288+
ARGS+=('--tentacle-comms-port' $ListeningPort)
289+
fi
290+
fi
291+
292+
if [[ -n "$ServerApiKey" ]]; then
293+
echo "Registering Tentacle with API key"
294+
ARGS+=('--apiKey' $ServerApiKey)
295+
elif [[ -n "$BearerToken" ]]; then
296+
echo "Registering Tentacle with Bearer Token"
297+
ARGS+=('--bearerToken' "$BearerToken")
298+
else
299+
echo "Registering Tentacle with username/password"
300+
ARGS+=(
301+
'--username' "$ServerUsername"
302+
'--password' "$ServerPassword")
303+
fi
304+
305+
tentacle "${ARGS[@]}"
306+
}
307+
308+
setupVariablesForRegistrationCheck
309+
getStatusOfRegistration
310+
311+
if [ "$IS_REGISTERED" == "true" ]; then
312+
echo "Tentacle is already configured and registered with server."
313+
else
314+
echo "==============================================="
315+
echo "Configuring Octopus Deploy Kubernetes Tentacle"
316+
echo "==============================================="
317+
318+
validateVariables
319+
320+
configureTentacle
321+
registerTentacle
322+
echo "Configuration successful"
323+
fi
324+
325+
echo "==============================================="
326+
echo "Finished Configuring Octopus Deploy Kubernetes Tentacle"
327+
echo "==============================================="
328+
exit 0

0 commit comments

Comments
 (0)