Setting the file. One moment. Functions · RDS Db2 · aws/agent-toolkit-for-aws · Skills Docs70
Creating Amazon Aurora Db Cluster With Instances
93
Routing Traffic With Route53 And CloudFront
Resilience Program Design
Creating API Gateway Stage
This file
- Number
- 72.23
- Position
- 23 of 28
- Type
- Shell
- Size
- 19 KB
- Lines
- 445
scripts/functions.sh
Shell·445 lines·19 KB
[
-n
"${
_DB2_FUNCTIONS_LOADED
:-
}"
] &&
return
0
16_DB2_FUNCTIONS_LOADED=1
17
18RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
19BLUE='\033[0;34m'; CYAN='\033[0;36m'; NC='\033[0m'
20
21log_info() { echo -e "${BLUE}[ INFO]${NC} $(date '+%H:%M:%S') - $1" >&2; }
22log_success() { echo -e "${GREEN}[SUCCESS]${NC} $(date '+%H:%M:%S') - $1" >&2; }
23log_warning() { echo -e "${YELLOW}[WARNING]${NC} $(date '+%H:%M:%S') - $1" >&2; }
24log_error() { echo -e "${RED}[ ERROR]${NC} $(date '+%H:%M:%S') - $1" >&2; }
25log_debug() { [[ "${VERBOSE:-}" == "true" ]] && echo -e "${CYAN}[ DEBUG]${NC} $(date '+%H:%M:%S') - $1" >&2 || true; }
26
27DB2_ENV_FILE="${HOME}/.db2env"
28
29# =============================================================================
30# Credentials
31# =============================================================================
32set_credentials() {
33 if curl -s --connect-timeout 1 http://127.0.0.1:1338/latest/meta-data/ >/dev/null 2>&1; then
34 log_info "Detected AWS CloudShell environment"
35 local token creds
36 token=$(curl -sX PUT "http://127.0.0.1:1338/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
37 creds=$(curl -s -H "Authorization: $token" "http://127.0.0.1:1338/latest/meta-data/container/security-credentials")
38 export AWS_ACCESS_KEY_ID=$(echo "$creds" | jq -r .AccessKeyId)
39 export AWS_SECRET_ACCESS_KEY=$(echo "$creds" | jq -r .SecretAccessKey)
40 export AWS_SESSION_TOKEN=$(echo "$creds" | jq -r .Token)
41 return
42 fi
43 if curl -s --connect-timeout 1 http://169.254.169.254/latest/meta-data/ >/dev/null 2>&1; then
44 log_info "Detected EC2 environment"
45 local token role creds
46 token=$(curl -sX PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
47 role=$(curl -s -H "X-aws-ec2-metadata-token: $token" http://169.254.169.254/latest/meta-data/iam/security-credentials/)
48 creds=$(curl -s -H "X-aws-ec2-metadata-token: $token" "http://169.254.169.254/latest/meta-data/iam/security-credentials/$role")
49 export AWS_ACCESS_KEY_ID=$(echo "$creds" | jq -r .AccessKeyId)
50 export AWS_SECRET_ACCESS_KEY=$(echo "$creds" | jq -r .SecretAccessKey)
51 export AWS_SESSION_TOKEN=$(echo "$creds" | jq -r .Token)
52 return
53 fi
54}
55
56# =============================================================================
57# Region detection
58# =============================================================================
59detect_region() {
60 [ -n "${REGION:-}" ] && return 0
61 [ -n "${AWS_DEFAULT_REGION:-}" ] && export REGION="$AWS_DEFAULT_REGION" && return 0
62 if curl -s --connect-timeout 1 http://169.254.169.254/latest/meta-data/ >/dev/null 2>&1; then
63 local token
64 token=$(curl -sX PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
65 REGION=$(curl -s -H "X-aws-ec2-metadata-token: $token" \
66 http://169.254.169.254/latest/meta-data/placement/region 2>/dev/null)
67 [ -n "$REGION" ] && export REGION && return 0
68 fi
69 REGION=$(aws configure get region 2>/dev/null)
70 [ -n "$REGION" ] && export REGION && return 0
71 log_error "Cannot detect region. Set: export REGION=us-east-1"
72 return 1
73}
74
75# =============================================================================
76# Persistent env file — ~/.db2env
77# =============================================================================
78
79# Save current instance credentials to ~/.db2env
80# WARNING: ~/.db2env contains the master password. It is written `chmod 600`
81# (owner-only), but it MUST NEVER be (1) committed to version control,
82# (2) shared with others, (3) backed up to unencrypted storage, or (4) used in
83# production AWS environments. For production, obtain credentials from Secrets
84# Manager via an IAM role (provision with --manage-master-user-password).
85# Uses printf %q to safely escape special characters in the password
86# (e.g. $, >, &, !) that would be re-expanded or misinterpreted by the
87# shell when the file is sourced later.
88db2_save_env() {
89 {
90 echo "export REGION=$(printf '%q' "${REGION:-}")"
91 echo "export DB_INSTANCE_ID=$(printf '%q' "${DB_INSTANCE_ID:-}")"
92 echo "export DB_DSN=$(printf '%q' "${DB_DSN:-}")"
93 echo "export MASTER_USER_NAME=$(printf '%q' "${MASTER_USER_NAME:-}")"
94 echo "export MASTER_USER_PASSWORD=$(printf '%q' "${MASTER_USER_PASSWORD:-}")"
95 } > "$DB2_ENV_FILE"
96 chmod 600 "$DB2_ENV_FILE"
97 log_success "Credentials saved to $DB2_ENV_FILE"
98}
99
100# Load credentials from ~/.db2env
101db2_load_env() {
102 if [ ! -f "$DB2_ENV_FILE" ]; then
103 log_warning "$DB2_ENV_FILE not found — run db2_use first"
104 return 1
105 fi
106 source "$DB2_ENV_FILE"
107 log_success "Loaded: instance=$DB_INSTANCE_ID dsn=$DB_DSN user=$MASTER_USER_NAME"
108}
109
110# Show current active instance/credentials
111db2_show_env() {
112 echo " REGION : ${REGION:-<not set>}"
113 echo " DB_INSTANCE_ID : ${DB_INSTANCE_ID:-<not set>}"
114 echo " DB_DSN : ${DB_DSN:-<not set>}"
115 echo " DB_SSL_DSN : ${DB_SSL_DSN:-<not set>}"
116 echo " MASTER_USER_NAME : ${MASTER_USER_NAME:-<not set>}"
117 echo " MASTER_USER_PASSWORD: ${MASTER_USER_PASSWORD:+<set>}${MASTER_USER_PASSWORD:-<not set>}"
118}
119# Switch active instance — fetches fresh password, rewrites ~/.db2env
120# Usage: db2_use [instance-id]
121db2_use() {
122 local registry="$HOME/.db2instances"
123 if [ ! -f "$registry" ]; then
124 log_error "No instance registry found. Run db2client-configure.sh first."
125 return 1
126 fi
127
128 # List available instances from registry
129 local instances
130 mapfile -t instances < <(cut -d'|' -f1 "$registry")
131 if [ ${#instances[@]} -eq 0 ]; then
132 log_error "No instances in registry. Run db2client-configure.sh first."
133 return 1
134 fi
135
136 local selected
137 if [ -n "${1:-}" ]; then
138 # Validate provided instance exists in registry
139 if ! grep -q "^${1}|" "$registry"; then
140 log_error "Instance '$1' not found in registry. Available:"
141 cut -d'|' -f1 "$registry" | while read -r i; do echo " $i" >&2; done
142 return 1
143 fi
144 selected="$1"
145 elif [ ${#instances[@]} -eq 1 ]; then
146 selected="${instances[0]}"
147 log_info "Auto-selected: $selected"
148 else
149 echo "Available DB2 instances:" >&2
150 for i in "${!instances[@]}"; do
151 local marker=""; [ "${instances[$i]}" = "${DB_INSTANCE_ID:-}" ] && marker=" (active)"
152 echo " $((i+1)). ${instances[$i]}${marker}" >&2
153 done
154 local choice
155 while true; do
156 read -p "Select instance (1-${#instances[@]}): " choice
157 [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= ${#instances[@]} )) && break
158 log_warning "Invalid choice"
159 done
160 selected="${instances[$((choice-1))]}"
161 fi
162
163 # Parse registry entry: instance|master_user|tcp_dsn|ssl_dsn|krb_dsn|region
164 # (db2client-configure.sh writes 6 pipe-delimited fields; read all 6 so the
165 # trailing `region` is not corrupted by the krb_dsn field.)
166 local entry master_user tcp_dsn ssl_dsn krb_dsn region
167 entry=$(grep "^${selected}|" "$registry")
168 IFS='|' read -r _ master_user tcp_dsn ssl_dsn krb_dsn region <<< "$entry"
169
170 detect_region || true
171 [ -n "$region" ] && export REGION="$region"
172 set_credentials
173
174 # Fetch password — Secrets Manager → ~/.need_password → prompt
175 local secret_arn secret_json password
176 secret_arn=$(aws rds describe-db-instances \
177 --db-instance-identifier "$selected" \
178 --region "$REGION" \
179 --query "DBInstances[0].MasterUserSecret.SecretArn" \
180 --output text 2>/dev/null)
181
182 if [ -n "$secret_arn" ] && [ "$secret_arn" != "None" ]; then
183 secret_json=$(aws secretsmanager get-secret-value \
184 --secret-id "$secret_arn" --region "$REGION" \
185 --query "SecretString" --output text 2>/dev/null)
186 password=$(jq -r '.password' <<< "$secret_json")
187 [ -n "$password" ] && log_success "Password fetched from Secrets Manager"
188 fi
189
190 if [ -z "${password:-}" ]; then
191 # ~/.need_password is a DEVELOPMENT/TEST-ONLY fallback for instances not
192 # using Secrets Manager. It MUST be kept private (`chmod 600`), MUST NEVER be
193 # committed to version control, and MUST NEVER be shared or deployed to
194 # production. For production, provision with --manage-master-user-password so
195 # RDS stores and rotates the credential in Secrets Manager, and do not keep
196 # plaintext passwords on disk.
197 local file_password
198 file_password=$(grep "^${selected} " "$HOME/.need_password" 2>/dev/null | cut -d' ' -f2-)
199 if [ -n "$file_password" ] && [ "$file_password" != "replace this with the master user password" ]; then
200 password="$file_password"
201 log_warning "Password loaded from ~/.need_password (dev/test only — use --manage-master-user-password in production)"
202 fi
203 fi
204
205 if [ -z "${password:-}" ]; then
206 read -rsp "Password for ${master_user}@${selected}: " password; echo
207 fi
208
209 export DB_INSTANCE_ID="$selected"
210 export MASTER_USER_NAME="$master_user"
211 export MASTER_USER_PASSWORD="$password"
212 export DB_DSN="$tcp_dsn"
213 export DB_SSL_DSN="$ssl_dsn"
214
215 # Write ~/.db2env with printf %q so special chars ($, >, &, !) in the
216 # password are shell-escaped and survive being sourced later.
217 {
218 echo "export REGION=$(printf '%q' "$REGION")"
219 echo "export DB_INSTANCE_ID=$(printf '%q' "$selected")"
220 echo "export DB_DSN=$(printf '%q' "$tcp_dsn")"
221 echo "export DB_SSL_DSN=$(printf '%q' "$ssl_dsn")"
222 echo "export MASTER_USER_NAME=$(printf '%q' "$master_user")"
223 echo "export MASTER_USER_PASSWORD=$(printf '%q' "$password")"
224 } > "$DB2_ENV_FILE"
225 chmod 600 "$DB2_ENV_FILE"
226 log_success "Active instance: $selected | TCP: $tcp_dsn | SSL: $ssl_dsn"
227 log_info "Connect: db2 \"connect to $tcp_dsn user $master_user using '\$MASTER_USER_PASSWORD'\""
228 [ -n "$ssl_dsn" ] && \
229 log_info "SSL: db2 \"connect to $ssl_dsn user $master_user using '\$MASTER_USER_PASSWORD'\""
230}
231
232
233
234# Connect to a DSN — uses stored credentials, optional DSN override
235# Usage: db2_connect [DSN]
236db2_connect() {
237 local dsn="${1:-${DB_DSN:-${DB_SSL_DSN:-RDSADMIN}}}"
238
239 if [ -z "${MASTER_USER_NAME:-}" ] || [ -z "${MASTER_USER_PASSWORD:-}" ]; then
240 if [ -f "$DB2_ENV_FILE" ]; then
241 source "$DB2_ENV_FILE"
242 else
243 log_error "No credentials loaded. Run db2_use first."
244 return 1
245 fi
246 fi
247
248 # Escape single quotes in password for Db2 CLP: Db2 uses '' inside a
249 # single-quoted string to represent a literal single quote.
250 local _db2pw="${MASTER_USER_PASSWORD//\'/\'\'}"
251 log_info "Connecting to $dsn as $MASTER_USER_NAME ..."
252 db2 "connect to $dsn user $MASTER_USER_NAME using '$_db2pw'"
253}
254
255# Disconnect
256db2_disconnect() {
257 db2 connect reset
258 db2 terminate
259}
260
261# =============================================================================
262# Connection diagnostics
263# =============================================================================
264db2_test_connection() {
265 local dsn="${1:-${DB_DSN:-${DB_SSL_DSN:-RDSADMIN}}}"
266
267 if [ -z "${MASTER_USER_NAME:-}" ] || [ -z "${MASTER_USER_PASSWORD:-}" ]; then
268 [ -f "$DB2_ENV_FILE" ] && source "$DB2_ENV_FILE"
269 fi
270
271 echo "============================================================================"
272 echo " DB2 Connection Diagnostics"
273 echo " DSN : $dsn"
274 echo " User : ${MASTER_USER_NAME:-<not set>}"
275 echo " Password : ${MASTER_USER_PASSWORD:+<set>}${MASTER_USER_PASSWORD:-<not set>}"
276 echo " DB_INSTANCE_ID : ${DB_INSTANCE_ID:-<not set>}"
277 echo "============================================================================"
278
279 # 1. Check DSN exists in db2dsdriver.cfg
280 if db2cli validate -dsn "$dsn" 2>&1 | grep -q "not found\|invalid"; then
281 log_error "DSN '$dsn' not found in db2dsdriver.cfg"
282 log_info "Run: db2cli writecfg list — to see configured DSNs"
283 log_info "Run: BUCKET=... REGION=... source ~/db2client-configure.sh — to reconfigure"
284 return 1
285 fi
286 log_success "DSN '$dsn' found in db2dsdriver.cfg"
287
288 # 2. Extract host/port from DSN and test TCP reachability
289 local host port
290 host=$(db2cli validate -dsn "$dsn" 2>/dev/null | grep -i "hostname" | awk '{print $NF}')
291 port=$(db2cli validate -dsn "$dsn" 2>/dev/null | grep -i "port" | awk '{print $NF}')
292 if [ -n "$host" ] && [ -n "$port" ]; then
293 log_info "Testing TCP connectivity to $host:$port ..."
294 if timeout 5 bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null; then
295 log_success "TCP connection to $host:$port OK"
296 else
297 log_error "Cannot reach $host:$port — check security group / VPC routing"
298 return 1
299 fi
300 fi
301
302 # 3. Attempt DB2 connect and capture error
303 log_info "Attempting db2 connect to $dsn ..."
304 local out rc _db2pw
305 _db2pw="${MASTER_USER_PASSWORD//\'/\'\'}"
306 out=$(db2 "connect to $dsn user $MASTER_USER_NAME using '$_db2pw'" 2>&1)
307 rc=$?
308
309 if [ $rc -eq 0 ]; then
310 log_success "Connection successful"
311 db2 connect reset >/dev/null 2>&1
312 return 0
313 fi
314
315 # Diagnose common error codes
316 log_error "Connection failed (rc=$rc)"
317 echo "$out" >&2
318
319 if echo "$out" | grep -q "SQL30082N"; then
320 log_error "Authentication failed — wrong username or password"
321 log_info "Check: MASTER_USER_NAME=$MASTER_USER_NAME"
322 log_info "Run db2_use to refresh credentials"
323 elif echo "$out" | grep -q "SQL08001N\|SQL30061N"; then
324 log_error "Database not found — DSN may point to wrong database name"
325 log_info "Run: BUCKET=... REGION=... source ~/db2client-configure.sh — to reconfigure DSNs"
326 elif echo "$out" | grep -q "SQL01013N\|TCP"; then
327 log_error "Network error — cannot reach DB2 server"
328 log_info "Check security group allows port $port from this host"
329 elif echo "$out" | grep -q "GSKit\|SSL\|certificate"; then
330 log_error "SSL certificate error"
331 log_info "Check: ls -la ~/$REGION-bundle.pem"
332 log_info "Run: BUCKET=... REGION=... source ~/db2client-configure.sh — to re-download cert"
333 fi
334 return 1
335}
336
337# List all configured DSNs
338db2_list_dsns() {
339 log_info "Configured DSNs in db2dsdriver.cfg:"
340 db2cli validate -dsn 2>/dev/null | grep -i "data source\|dsn" || \
341 cat "$HOME/sqllib/cfg/db2dsdriver.cfg" 2>/dev/null || \
342 log_warning "No DSNs found"
343}
344
345# =============================================================================
346# RDS task monitoring (uses stored credentials)
347# =============================================================================
348get_task_status() {
349 db2_connect RDSADMIN || return 1
350 db2 "SELECT VARCHAR(task_type,25) AS task_type,
351 VARCHAR(lifecycle,15) AS lifecycle,
352 created_at,
353 completed_work_bytes
354 FROM TABLE(rdsadmin.get_task_status(null,null,null)) AS r
355 ORDER BY created_at DESC"
356 db2_disconnect
357}
358
359get_task_elapsed() {
360 db2_connect RDSADMIN || return 1
361 db2 "SELECT task_id,
362 VARCHAR(task_type,25) AS task_type,
363 VARCHAR(lifecycle,15) AS lifecycle,
364 NVL(TIMESTAMPDIFF(2, (last_updated_at - created_at)),-1) AS elapsed_seconds
365 FROM TABLE(rdsadmin.get_task_status(null,null,null)) AS r
366 ORDER BY created_at DESC"
367 db2_disconnect
368}
369
370get_task_output() {
371 db2_connect RDSADMIN || return 1
372 db2 "SELECT VARCHAR(r.task_type,25) AS task_type,
373 VARCHAR(r.lifecycle,15) AS lifecycle,
374 r.created_at,
375 r.completed_work_bytes,
376 VARCHAR(bson_to_json(task_input_params),256) AS input_params,
377 VARCHAR(r.task_output,1024) AS task_output
378 FROM TABLE(rdsadmin.get_task_status(null,null,null)) AS r
379 ORDER BY created_at DESC
380 LIMIT 1"
381 db2_disconnect
382}
383
384# =============================================================================
385# RDS instance monitoring
386# =============================================================================
387monitor_db_instance_creation() {
388 [ -z "${DB_INSTANCE_ID:-}" ] && log_error "DB_INSTANCE_ID not set. Run db2_use first." && return 1
389 detect_region || return 1
390 log_info "Monitoring RDS instance '$DB_INSTANCE_ID' ..."
391 local status=""
392 while [ "$status" != "available" ]; do
393 status=$(aws rds describe-db-instances \
394 --db-instance-identifier "$DB_INSTANCE_ID" \
395 --region "$REGION" \
396 --query "DBInstances[0].DBInstanceStatus" \
397 --output text 2>/dev/null)
398 if [ "$status" = "available" ]; then
399 log_success "Instance '$DB_INSTANCE_ID' is available"
400 else
401 log_info "$(date '+%H:%M:%S') status: $status — waiting 30s ..."
402 sleep 30
403 fi
404 done
405}
406
407# =============================================================================
408# Help
409# =============================================================================
410db2_help() {
411 echo
412 echo " DB2 Helper Functions (source ~/functions.sh to load)"
413 echo " ======================================================"
414 echo
415 echo " Setup"
416 echo " db2_use [instance-id] Switch active instance — fetches fresh password, rewrites ~/.db2env"
417 echo " db2_load_env Load saved credentials from ~/.db2env"
418 echo " db2_save_env Save current credentials to ~/.db2env"
419 echo " db2_show_env Show current instance/credentials in use"
420 echo
421 echo " Connection"
422 echo " db2_connect [DSN] Connect using stored credentials (default DSN: RDSADMIN)"
423 echo " db2_disconnect Reset and terminate current connection"
424 echo " db2_list_dsns List all configured DSNs from db2dsdriver.cfg"
425 echo
426 echo " Diagnostics"
427 echo " db2_test_connection [DSN] Test connectivity — checks DSN, TCP, auth, SSL"
428 echo
429 echo " RDS Tasks"
430 echo " get_task_status Show RDS task status (connects to RDSADMIN)"
431 echo " get_task_elapsed Show RDS task elapsed time"
432 echo " get_task_output Show latest task output, input params, and lifecycle"
433 echo " monitor_db_instance_creation Poll instance status until available"
434 echo
435 echo " Quick start"
436 echo " db2_use # select instance and fetch credentials"
437 echo " db2_connect # connect using saved credentials"
438 echo " db2_test_connection # if connection fails, run this to diagnose"
439 echo
440}
441
442# =============================================================================
443# Auto-load ~/.db2env if it exists (silent)
444# =============================================================================
445[ -f "$DB2_ENV_FILE" ] && source "$DB2_ENV_FILE" 2>/dev/null || true