-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlocal.sh
More file actions
executable file
·428 lines (361 loc) · 13.5 KB
/
local.sh
File metadata and controls
executable file
·428 lines (361 loc) · 13.5 KB
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
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
#!/bin/bash
set -e
# Configuration
CONFIGMAP_NAME="cluster-vars"
NAMESPACE="flux-system"
TAILNET_NAME="replaceme.ts.net"
# Function for user confirmation
confirm() {
read -p "$1 (y/n): " -n 1 -r
echo
[[ $REPLY =~ ^[Yy]$ ]]
}
# Check for uncommitted changes and new files, offer to commit
echo "Checking for uncommitted changes and new files..."
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
# Check for uncommitted changes in tracked files
has_changes=false
has_untracked=false
if ! git diff-index --quiet HEAD --; then
has_changes=true
fi
# Check for untracked files (excluding common ignore patterns)
untracked_files=$(git ls-files --others --exclude-standard)
if [ -n "$untracked_files" ]; then
has_untracked=true
fi
if [ "$has_changes" = true ] || [ "$has_untracked" = true ]; then
echo "Found uncommitted work:"
echo ""
if [ "$has_changes" = true ]; then
echo "Modified files:"
git status --porcelain
fi
if [ "$has_untracked" = true ]; then
echo "Untracked files:"
echo "$untracked_files"
fi
echo ""
if confirm "Would you like to commit these changes as a WIP commit before proceeding?"; then
# Add all changes and untracked files
if [ "$has_untracked" = true ]; then
echo "Adding untracked files..."
git add .
fi
if [ "$has_changes" = true ]; then
echo "Adding modified files..."
git add -u
fi
# Create WIP commit
echo "Creating WIP commit..."
git commit -m "WIP: Auto-commit before deployment script run"
echo "✓ WIP commit created successfully"
git push
echo "✓ WIP commit successfully pushed"
fi
fi
else
echo "⚠ Warning: Not in a git repository - skipping git status check"
fi
# Generate a random string (6 characters) - do this early so it's available for cleanup
RANDOM_STRING=$(openssl rand -hex 3)
echo "Generated random string: $RANDOM_STRING"
# Cleanup function that will run on script exit (success or failure)
cleanup_tailscale_devices() {
echo ""
echo "=== Running Tailscale cleanup ==="
# Set variables for cleanup
TAILNET="${TAILNET_NAME:-$TAILNET_NAME}"
API_KEY="${TAILSCALE_API_KEY:-$API_KEY}"
# Validate required variables for cleanup
if [[ -z "$TAILNET" || -z "$API_KEY" || -z "$RANDOM_STRING" ]]; then
echo "Warning: Cannot run cleanup - missing TAILNET, API_KEY, or RANDOM_STRING"
echo "TAILNET: ${TAILNET:-'not set'}"
echo "API_KEY: ${API_KEY:+'set (hidden)'}"
echo "RANDOM_STRING: ${RANDOM_STRING:-'not set'}"
return 1
fi
echo "Searching for devices containing '$RANDOM_STRING' in tailnet '$TAILNET'..."
# Get devices and process them
curl -s "https://api.tailscale.com/api/v2/tailnet/$TAILNET/devices" \
-u "$API_KEY:" \
-H "Accept: application/json" | \
jq -r '.devices[]? | select(.name != null) | "\(.id) \(.name)"' | \
while IFS=' ' read -r id name; do
# Skip empty lines
[[ -z "$id" || -z "$name" ]] && continue
if [[ "$name" == *"$RANDOM_STRING"* ]]; then
echo "Found: '$name' (ID: $id) contains '$RANDOM_STRING' - removing it"
# Delete the device
delete_response=$(curl -s -w "%{http_code}" -o /dev/null \
-X DELETE "https://api.tailscale.com/api/v2/device/$id" \
-u "$API_KEY:" \
-H "Accept: application/json")
if [[ "$delete_response" == "200" ]]; then
echo "✓ Successfully deleted device '$name'"
else
echo "✗ Failed to delete device '$name' (HTTP $delete_response)"
fi
fi
done
echo "Device cleanup complete."
}
# Cleanup function for Kind cluster
cleanup_kind_cluster() {
echo "Cleaning up: Deleting flux-e2e cluster..."
if kind get clusters | grep -q "flux-e2e"; then
kind delete cluster --name flux-e2e
echo "✓ Cluster deleted"
else
echo "ℹ No flux-e2e cluster found to delete"
fi
}
# Combined cleanup function
cleanup_all() {
echo ""
echo "=== Starting cleanup process ==="
# Ask what to do with the cluster at the end
echo ""
if confirm "Keep the internal-tools cluster?"; then
echo "✓ Keeping cluster for future use"
echo "You can access your cluster with: kubectl config use-context kind-internal-tools"
KEEP_CLUSTER="true"
else
echo "Will delete cluster during cleanup..."
KEEP_CLUSTER="false"
fi
# Always run Tailscale cleanup
cleanup_tailscale_devices
# Only cleanup cluster if user doesn't want to keep it
if [[ "$KEEP_CLUSTER" != "true" ]]; then
cleanup_kind_cluster
fi
echo "=== Cleanup process completed ==="
}
# Set up trap to run cleanup on script exit (both success and failure)
trap cleanup_all EXIT
# Function to display ingresses in a formatted table and check for missing addresses
list_ingresses_table() {
local max_retries=10
local retry_interval=30
local retry_count=0
echo "Kubernetes Ingresses Table"
echo "=========================="
echo
# Always show the current ingresses table first
kubectl get ingress --all-namespaces -o custom-columns=\
NAMESPACE:.metadata.namespace,\
NAME:.metadata.name,\
CLASS:.spec.ingressClassName,\
ADDRESS:.status.loadBalancer.ingress[0].hostname,\
AGE:.metadata.creationTimestamp | sed '1!s/\([^[:space:]]*[[:space:]]*[^[:space:]]*[[:space:]]*[^[:space:]]*[[:space:]]*\)\([^[:space:]]*\)/\1https:\/\/\2/'
echo
echo "Checking for ingresses without addresses..."
echo "==========================================="
# Retry loop for checking ingress addresses
while [ $retry_count -lt $max_retries ]; do
retry_count=$((retry_count + 1))
echo "Attempt $retry_count of $max_retries..."
# Check for ingresses without addresses
missing_addresses=$(kubectl get ingress --all-namespaces -o json | jq -r '
.items[] |
select(
(.status.loadBalancer.ingress | length) == 0 or
(.status.loadBalancer.ingress[0].hostname // .status.loadBalancer.ingress[0].ip // "") == ""
) |
.metadata.namespace + "/" + .metadata.name
')
if [ -z "$missing_addresses" ]; then
echo "✅ All ingresses have addresses assigned!"
return 0
else
echo "⚠️ Found ingresses without addresses:"
echo "$missing_addresses" | while read -r ingress; do
echo " - $ingress"
done
if [ $retry_count -lt $max_retries ]; then
echo "⏳ Waiting ${retry_interval} seconds before retry..."
sleep $retry_interval
echo
echo "Refreshing ingresses table..."
kubectl get ingress --all-namespaces -o custom-columns=\
NAMESPACE:.metadata.namespace,\
NAME:.metadata.name,\
CLASS:.spec.ingressClassName,\
ADDRESS:.status.loadBalancer.ingress[0].hostname,\
AGE:.metadata.creationTimestamp
echo
fi
fi
done
# If we get here, all retries failed
echo
echo "❌ ERROR: After $max_retries attempts, the following ingresses still do not have addresses assigned:"
echo "$missing_addresses" | while read -r ingress; do
echo " - $ingress"
done
echo
echo "💡 This usually means:"
echo " • Ingress controller is not running"
echo " • Load balancer provisioning failed"
echo " • Ingress controller doesn't support LoadBalancer service type"
echo " • Cloud provider integration issues"
echo " • Tailscale ACL wrong"
echo
exit 1
}
echo ""
echo "=== Collecting required credentials and configuration ==="
# Handle API key with env variables or prompts
API_KEY=${TAILSCALE_API_KEY:-""}
# If environment variable isn't set, prompt for it
if [ -z "$API_KEY" ]; then
read -s -p "Enter Tailscale API key: " API_KEY
echo
fi
# Handle operator OAuth secret with env variables or prompts
CLIENT_ID=${OPERATOR_CLIENT_ID:-""}
CLIENT_SECRET=${OPERATOR_CLIENT_SECRET:-""}
# If environment variables aren't set, prompt for them
if [ -z "$CLIENT_ID" ]; then
read -p "Enter operator client ID: " CLIENT_ID
fi
if [ -z "$CLIENT_SECRET" ]; then
read -s -p "Enter operator client secret: " CLIENT_SECRET
echo
fi
# Get local git branch or use provided branch
if [ -z "$GIT_BRANCH" ]; then
# Try to get current git branch if in a git repository
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
LOCAL_BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null)
GIT_BRANCH=${LOCAL_BRANCH:-"alloy"} # Default to "alloy" if not in a git repo or can't get branch
else
# Not in a git repository, prompt for branch
read -p "Enter Git branch (default: alloy): " BRANCH_INPUT
GIT_BRANCH=${BRANCH_INPUT:-"alloy"}
fi
fi
echo "Using Git branch: $GIT_BRANCH"
# Handle other git credentials with env variables or prompts
GIT_URL=${GIT_URL:-"https://github.com/pmdroid/flux-e2e"}
GIT_USERNAME=${GIT_USERNAME:-"pmdroid"}
GIT_PASSWORD=${GIT_PASSWORD:-""}
# If GIT_PASSWORD not set, prompt for it
if [ -z "$GIT_PASSWORD" ]; then
read -s -p "Enter Git password or token: " GIT_PASSWORD
echo
fi
echo ""
echo "=== All credentials collected, starting cluster operations ==="
# Check if flux-e2e cluster exists
echo "Checking for existing clusters..."
if kind get clusters | grep -q "flux-e2e"; then
echo "✓ flux-e2e cluster found - deleting for fresh start..."
kind delete cluster --name flux-e2e
echo "✓ Old cluster deleted"
else
echo "✗ flux-e2e cluster not found"
fi
echo "Creating fresh flux-e2e cluster..."
kind create cluster --name flux-e2e --config kind-config.yaml
if [ $? -eq 0 ]; then
echo "✓ flux-e2e cluster created successfully"
else
echo "✗ Failed to create cluster"
exit 1
fi
APISERVER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' flux-e2e-control-plane)
echo "API Server IP: $APISERVER_IP"
# Add Cilium
helm repo add cilium https://helm.cilium.io/
docker pull quay.io/cilium/cilium:v1.17.4
kind load docker-image quay.io/cilium/cilium:v1.17.4 --name flux-e2e
helm install cilium cilium/cilium --version 1.17.4 \
--namespace kube-system \
--set operator.replicas=1 \
--set operator.prometheus.enabled=true \
--set devices="{eth+,enp+}" \
--set ipam.operator.clusterPoolIPv4PodCIDRList=10.244.0.0/16 \
--set l7Proxy=false \
--set k8sServiceHost=$APISERVER_IP \
--set k8sServicePort=6443 \
--set ipv4NativeRoutingCIDR=10.244.0.0/16 \
--set egressGateway.enabled=true \
--set bpf.masquerade=true \
--set prometheus.enabled=true \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set hubble.metrics.enabled="{dns,http,drop,tcp,flow,icmp}" \
--set nodePort.enabled=true
# Ensure we're using the correct context
echo "Setting kubectl context to kind-flux-e2e..."
kubectl config use-context kind-flux-e2e
echo ""
echo "=== Starting Kubernetes deployment on flux-e2e cluster ==="
# Create necessary namespaces
echo "Creating namespaces..."
NAMESPACES="flux-system network-tools monitoring echo-server"
for ns in $NAMESPACES; do
kubectl create namespace $ns --dry-run=client -o yaml | kubectl apply -f -
done
# Create the OAuth secret (using variables collected at the top)
echo "Creating OAuth secret..."
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: operator-oauth
namespace: network-tools
type: Opaque
stringData:
client_id: "${CLIENT_ID}"
client_secret: "${CLIENT_SECRET}"
EOF
# Install and configure Flux
echo "Installing Flux..."
flux install
# Apply e2e mocks
echo "Applying e2e configurations..."
kubectl apply -f e2e/config.yaml
kubectl apply -f e2e/secrets.yaml
kubectl apply -f e2e/cluster-vars.yaml
# Patch the ConfigMap using kubectl patch (combine both patches)
kubectl patch configmap "$CONFIGMAP_NAME" -n "$NAMESPACE" \
--type merge \
-p "{\"data\":{\"tailscalePrefix\":\"$RANDOM_STRING-\",\"tailscaleHostname\":\"$RANDOM_STRING-operator\"}}"
# Check if the patch was successful
if [ $? -eq 0 ]; then
echo "Successfully patched ConfigMap '$CONFIGMAP_NAME' in namespace '$NAMESPACE'"
echo "Added tailscalePrefix: $RANDOM_STRING- and tailscaleHostname: $RANDOM_STRING-operator"
else
echo "Failed to patch ConfigMap"
exit 1
fi
# Create flux source (using variables collected at the top)
echo "Creating Flux source..."
flux create source git flux-system \
--url="${GIT_URL}" \
--branch="${GIT_BRANCH}" \
--username="${GIT_USERNAME}" \
--password="${GIT_PASSWORD}" \
--ignore-paths="cluster/flux-system/" \
--ignore-paths="cluster/config.yaml" \
--ignore-paths="cluster/secrets.yaml" \
--ignore-paths="cluster/cluster-vars.yaml"
# Create flux kustomization
echo "Creating Flux kustomization..."
flux create kustomization flux-system \
--source=flux-system \
--path=./cluster
# Wait for kustomizations to be ready
echo "Waiting for kustomizations to be ready..."
KUSTOMIZATIONS="bootstrap network-policies secrets config infrastructure system apps ingress"
for kustomization in $KUSTOMIZATIONS; do
echo "Waiting for $kustomization..."
kubectl -n flux-system wait kustomization/$kustomization --for=condition=ready --timeout=5m
done
echo ""
echo "=== Deployment completed successfully! ==="
list_ingresses_table