|
| 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