View a markdown version of this page

Get started with Redshift Serverless using the CLI - Amazon Redshift

Amazon Redshift will no longer support the creation of new Python UDFs starting Patch 198. Existing Python UDFs will continue to function until June 30, 2026. For more information, see the blog post .

Get started with Redshift Serverless using the CLI

The following code example shows how to:

  • Use secrets-manager CreateSecret

  • Use secrets-manager DeleteSecret

  • Use secrets-manager GetSecretValue

  • Use redshift CreateNamespace

  • Use redshift CreateWorkgroup

  • Use redshift DeleteNamespace

  • Use iam CreateRole

Bash
AWS CLI with Bash script
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials repository.

#!/bin/bash # Amazon Redshift Serverless Tutorial Script with Secrets Manager (No jq dependency) # This script creates a Redshift Serverless environment, loads sample data, and runs queries # Uses AWS Secrets Manager for secure password management without requiring jq # Set up logging LOG_FILE="redshift-serverless-tutorial-v4.log" exec > >(tee -a "$LOG_FILE") 2>&1 echo "Starting Amazon Redshift Serverless tutorial script at $(date)" echo "All commands and outputs will be logged to $LOG_FILE" # Function to check for errors in command output check_error() { local output=$1 local cmd=$2 if echo "$output" | grep -i "error\|exception\|fail" > /dev/null; then echo "ERROR: Command failed: $cmd" echo "Output: $output" cleanup_resources exit 1 fi } # Function to generate a secure password that meets Redshift requirements generate_secure_password() { # Redshift password requirements: # - 8-64 characters # - At least one uppercase letter # - At least one lowercase letter # - At least one decimal digit # - Can contain printable ASCII characters except /, ", ', \, @, space local password="" local valid=false local attempts=0 local max_attempts=10 while [[ "$valid" == false && $attempts -lt $max_attempts ]]; do # Generate base password with safe characters local base=$(openssl rand -base64 12 | tr -d '/+=' | head -c 12) # Ensure we have at least one of each required character type local upper=$(echo "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | fold -w1 | shuf -n1) local lower=$(echo "abcdefghijklmnopqrstuvwxyz" | fold -w1 | shuf -n1) local digit=$(echo "0123456789" | fold -w1 | shuf -n1) local special=$(echo "!#$%&*()_+-=[]{}|;:,.<>?" | fold -w1 | shuf -n1) # Combine and shuffle password="${base}${upper}${lower}${digit}${special}" password=$(echo "$password" | fold -w1 | shuf | tr -d '\n') # Validate password meets requirements if [[ ${#password} -ge 8 && ${#password} -le 64 ]] && \ [[ "$password" =~ [A-Z] ]] && \ [[ "$password" =~ [a-z] ]] && \ [[ "$password" =~ [0-9] ]] && \ [[ ! "$password" =~ [/\"\'\\@[:space:]] ]]; then valid=true fi ((attempts++)) done if [[ "$valid" == false ]]; then echo "ERROR: Failed to generate valid password after $max_attempts attempts" exit 1 fi echo "$password" } # Function to create secret in AWS Secrets Manager create_secret() { local secret_name=$1 local username=$2 local password=$3 local description=$4 echo "Creating secret in AWS Secrets Manager: $secret_name" # Create the secret using AWS CLI without jq local secret_output=$(aws secretsmanager create-secret \ --name "$secret_name" \ --description "$description" \ --secret-string "{\"username\":\"$username\",\"password\":\"$password\"}" 2>&1) if echo "$secret_output" | grep -i "error\|exception\|fail" > /dev/null; then echo "ERROR: Failed to create secret: $secret_output" return 1 fi echo "Secret created successfully: $secret_name" return 0 } # Function to retrieve password from AWS Secrets Manager get_password_from_secret() { local secret_name=$1 # Get the secret value and extract password using sed/grep instead of jq local secret_value=$(aws secretsmanager get-secret-value \ --secret-id "$secret_name" \ --query 'SecretString' \ --output text 2>/dev/null) if [[ $? -eq 0 ]]; then # Extract password from JSON using sed echo "$secret_value" | sed -n 's/.*"password":"\([^"]*\)".*/\1/p' else echo "" fi } # Function to wait for a resource to be available wait_for_resource() { local resource_type=$1 local resource_name=$2 local max_attempts=$3 local wait_seconds=$4 local check_cmd=$5 echo "Waiting for $resource_type $resource_name to be available..." for ((i=1; i<=$max_attempts; i++)); do local output=$($check_cmd 2>/dev/null) local status=$(echo "$output" | grep -o '"Status": "[^"]*' | cut -d'"' -f4 || echo "") if [[ "$status" == "AVAILABLE" ]]; then echo "$resource_type $resource_name is now available" return 0 fi echo "Attempt $i/$max_attempts: $resource_type $resource_name status: $status. Waiting $wait_seconds seconds..." sleep $wait_seconds done echo "ERROR: Timed out waiting for $resource_type $resource_name to be available" return 1 } # Function to wait for a resource to be deleted wait_for_resource_deletion() { local resource_type=$1 local resource_name=$2 local max_attempts=$3 local wait_seconds=$4 local check_cmd=$5 echo "Waiting for $resource_type $resource_name to be deleted..." for ((i=1; i<=$max_attempts; i++)); do local output=$($check_cmd 2>&1) if echo "$output" | grep -i "not found\|does not exist" > /dev/null; then echo "$resource_type $resource_name has been deleted" return 0 fi echo "Attempt $i/$max_attempts: $resource_type $resource_name is still being deleted. Waiting $wait_seconds seconds..." sleep $wait_seconds done echo "ERROR: Timed out waiting for $resource_type $resource_name to be deleted" return 1 } # Function to clean up resources cleanup_resources() { echo "" echo "===========================================" echo "CLEANUP CONFIRMATION" echo "===========================================" echo "The following resources were created:" echo "- Redshift Serverless Workgroup: $WORKGROUP_NAME" echo "- Redshift Serverless Namespace: $NAMESPACE_NAME" echo "- IAM Role: $ROLE_NAME" echo "- Secrets Manager Secret: $SECRET_NAME" echo "" echo "Do you want to clean up all created resources? (y/n): " read -r CLEANUP_CHOICE if [[ "${CLEANUP_CHOICE,,}" == "y" ]]; then echo "Cleaning up resources..." # Delete the workgroup echo "Deleting Redshift Serverless workgroup $WORKGROUP_NAME..." WORKGROUP_DELETE_OUTPUT=$(aws redshift-serverless delete-workgroup --workgroup-name "$WORKGROUP_NAME" 2>&1) echo "$WORKGROUP_DELETE_OUTPUT" # Wait for workgroup to be deleted before deleting namespace wait_for_resource_deletion "workgroup" "$WORKGROUP_NAME" 20 30 "aws redshift-serverless get-workgroup --workgroup-name $WORKGROUP_NAME" # Delete the namespace echo "Deleting Redshift Serverless namespace $NAMESPACE_NAME..." NAMESPACE_DELETE_OUTPUT=$(aws redshift-serverless delete-namespace --namespace-name "$NAMESPACE_NAME" 2>&1) echo "$NAMESPACE_DELETE_OUTPUT" # Wait for namespace to be deleted wait_for_resource_deletion "namespace" "$NAMESPACE_NAME" 20 30 "aws redshift-serverless get-namespace --namespace-name $NAMESPACE_NAME" # Delete the IAM role policy echo "Deleting IAM role policy..." POLICY_DELETE_OUTPUT=$(aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name S3Access 2>&1) echo "$POLICY_DELETE_OUTPUT" # Delete the IAM role echo "Deleting IAM role $ROLE_NAME..." ROLE_DELETE_OUTPUT=$(aws iam delete-role --role-name "$ROLE_NAME" 2>&1) echo "$ROLE_DELETE_OUTPUT" # Delete the secret echo "Deleting Secrets Manager secret $SECRET_NAME..." SECRET_DELETE_OUTPUT=$(aws secretsmanager delete-secret --secret-id "$SECRET_NAME" --force-delete-without-recovery 2>&1) echo "$SECRET_DELETE_OUTPUT" echo "Cleanup completed." else echo "Cleanup skipped. Resources will remain in your AWS account." fi } # Check if required tools are available if ! command -v openssl &> /dev/null; then echo "ERROR: openssl is required but not installed. Please install openssl to continue." exit 1 fi # Generate unique names for resources RANDOM_SUFFIX=$(cat /dev/urandom | tr -dc 'a-z0-9' | head -c 6) NAMESPACE_NAME="rs-namespace-${RANDOM_SUFFIX}" WORKGROUP_NAME="rs-workgroup-${RANDOM_SUFFIX}" ROLE_NAME="RedshiftServerlessS3Role-${RANDOM_SUFFIX}" SECRET_NAME="redshift-serverless-admin-${RANDOM_SUFFIX}" DB_NAME="dev" ADMIN_USERNAME="admin" # Generate secure password echo "Generating secure password..." ADMIN_PASSWORD=$(generate_secure_password) # Create secret in AWS Secrets Manager create_secret "$SECRET_NAME" "$ADMIN_USERNAME" "$ADMIN_PASSWORD" "Admin credentials for Redshift Serverless namespace $NAMESPACE_NAME" if [[ $? -ne 0 ]]; then echo "ERROR: Failed to create secret in AWS Secrets Manager" exit 1 fi # Track created resources CREATED_RESOURCES=() echo "Using the following resource names:" echo "- Namespace: $NAMESPACE_NAME" echo "- Workgroup: $WORKGROUP_NAME" echo "- IAM Role: $ROLE_NAME" echo "- Secret: $SECRET_NAME" echo "- Database: $DB_NAME" echo "- Admin Username: $ADMIN_USERNAME" echo "- Admin Password: [STORED IN SECRETS MANAGER]" # Step 1: Create IAM role for S3 access echo "Creating IAM role for Redshift Serverless S3 access..." # Create trust policy document cat > redshift-trust-policy.json << EOF { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "redshift-serverless.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF # Create S3 access policy document cat > redshift-s3-policy.json << EOF { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::redshift-downloads", "arn:aws:s3:::redshift-downloads/*" ] } ] } EOF # Create IAM role echo "Creating IAM role $ROLE_NAME..." ROLE_OUTPUT=$(aws iam create-role --role-name "$ROLE_NAME" --assume-role-policy-document file://redshift-trust-policy.json 2>&1) echo "$ROLE_OUTPUT" check_error "$ROLE_OUTPUT" "aws iam create-role" CREATED_RESOURCES+=("IAM Role: $ROLE_NAME") # Attach S3 policy to the role echo "Attaching S3 access policy to role $ROLE_NAME..." POLICY_OUTPUT=$(aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name S3Access --policy-document file://redshift-s3-policy.json 2>&1) echo "$POLICY_OUTPUT" check_error "$POLICY_OUTPUT" "aws iam put-role-policy" # Get the role ARN ROLE_ARN=$(aws iam get-role --role-name "$ROLE_NAME" --query 'Role.Arn' --output text) echo "Role ARN: $ROLE_ARN" # Step 2: Create a namespace echo "Creating Redshift Serverless namespace $NAMESPACE_NAME..." NAMESPACE_OUTPUT=$(aws redshift-serverless create-namespace \ --namespace-name "$NAMESPACE_NAME" \ --admin-username "$ADMIN_USERNAME" \ --admin-user-password "$ADMIN_PASSWORD" \ --db-name "$DB_NAME" 2>&1) echo "$NAMESPACE_OUTPUT" check_error "$NAMESPACE_OUTPUT" "aws redshift-serverless create-namespace" CREATED_RESOURCES+=("Redshift Serverless Namespace: $NAMESPACE_NAME") # Wait for namespace to be available wait_for_resource "namespace" "$NAMESPACE_NAME" 10 30 "aws redshift-serverless get-namespace --namespace-name $NAMESPACE_NAME" # Associate IAM role with namespace echo "Associating IAM role with namespace..." UPDATE_NAMESPACE_OUTPUT=$(aws redshift-serverless update-namespace \ --namespace-name "$NAMESPACE_NAME" \ --iam-roles "$ROLE_ARN" 2>&1) echo "$UPDATE_NAMESPACE_OUTPUT" check_error "$UPDATE_NAMESPACE_OUTPUT" "aws redshift-serverless update-namespace" # Step 3: Create a workgroup echo "Creating Redshift Serverless workgroup $WORKGROUP_NAME..." WORKGROUP_OUTPUT=$(aws redshift-serverless create-workgroup \ --workgroup-name "$WORKGROUP_NAME" \ --namespace-name "$NAMESPACE_NAME" \ --base-capacity 8 2>&1) echo "$WORKGROUP_OUTPUT" check_error "$WORKGROUP_OUTPUT" "aws redshift-serverless create-workgroup" CREATED_RESOURCES+=("Redshift Serverless Workgroup: $WORKGROUP_NAME") # Wait for workgroup to be available wait_for_resource "workgroup" "$WORKGROUP_NAME" 20 30 "aws redshift-serverless get-workgroup --workgroup-name $WORKGROUP_NAME" # Get workgroup endpoint WORKGROUP_ENDPOINT=$(aws redshift-serverless get-workgroup \ --workgroup-name "$WORKGROUP_NAME" \ --query 'workgroup.endpoint.address' \ --output text) echo "Workgroup endpoint: $WORKGROUP_ENDPOINT" # Wait additional time for the endpoint to be fully operational echo "Waiting for endpoint to be fully operational..." sleep 60 # Step 4: Create tables for sample data echo "Creating tables for sample data..." # Create users table echo "Creating users table..." USERS_TABLE_OUTPUT=$(aws redshift-data execute-statement \ --database "$DB_NAME" \ --workgroup-name "$WORKGROUP_NAME" \ --sql "CREATE TABLE users( userid INTEGER NOT NULL DISTKEY SORTKEY, username CHAR(8), firstname VARCHAR(30), lastname VARCHAR(30), city VARCHAR(30), state CHAR(2), email VARCHAR(100), phone CHAR(14), likesports BOOLEAN, liketheatre BOOLEAN, likeconcerts BOOLEAN, likejazz BOOLEAN, likeclassical BOOLEAN, likeopera BOOLEAN, likerock BOOLEAN, likevegas BOOLEAN, likebroadway BOOLEAN, likemusicals BOOLEAN );" 2>&1) echo "$USERS_TABLE_OUTPUT" check_error "$USERS_TABLE_OUTPUT" "aws redshift-data execute-statement (users table)" USERS_QUERY_ID=$(echo "$USERS_TABLE_OUTPUT" | grep -o '"Id": "[^"]*' | cut -d'"' -f4) # Wait for query to complete echo "Waiting for users table creation to complete..." sleep 5 # Create event table echo "Creating event table..." EVENT_TABLE_OUTPUT=$(aws redshift-data execute-statement \ --database "$DB_NAME" \ --workgroup-name "$WORKGROUP_NAME" \ --sql "CREATE TABLE event( eventid INTEGER NOT NULL DISTKEY, venueid SMALLINT NOT NULL, catid SMALLINT NOT NULL, dateid SMALLINT NOT NULL SORTKEY, eventname VARCHAR(200), starttime TIMESTAMP );" 2>&1) echo "$EVENT_TABLE_OUTPUT" check_error "$EVENT_TABLE_OUTPUT" "aws redshift-data execute-statement (event table)" EVENT_QUERY_ID=$(echo "$EVENT_TABLE_OUTPUT" | grep -o '"Id": "[^"]*' | cut -d'"' -f4) # Wait for query to complete echo "Waiting for event table creation to complete..." sleep 5 # Create sales table echo "Creating sales table..." SALES_TABLE_OUTPUT=$(aws redshift-data execute-statement \ --database "$DB_NAME" \ --workgroup-name "$WORKGROUP_NAME" \ --sql "CREATE TABLE sales( salesid INTEGER NOT NULL, listid INTEGER NOT NULL DISTKEY, sellerid INTEGER NOT NULL, buyerid INTEGER NOT NULL, eventid INTEGER NOT NULL, dateid SMALLINT NOT NULL SORTKEY, qtysold SMALLINT NOT NULL, pricepaid DECIMAL(8,2), commission DECIMAL(8,2), saletime TIMESTAMP );" 2>&1) echo "$SALES_TABLE_OUTPUT" check_error "$SALES_TABLE_OUTPUT" "aws redshift-data execute-statement (sales table)" SALES_QUERY_ID=$(echo "$SALES_TABLE_OUTPUT" | grep -o '"Id": "[^"]*' | cut -d'"' -f4) # Wait for tables to be created echo "Waiting for tables to be created..." sleep 10 # Step 5: Load sample data from Amazon S3 echo "Loading sample data from Amazon S3..." # Load data into users table echo "Loading data into users table..." USERS_LOAD_OUTPUT=$(aws redshift-data execute-statement \ --database "$DB_NAME" \ --workgroup-name "$WORKGROUP_NAME" \ --sql "COPY users FROM 's3://redshift-downloads/tickit/allusers_pipe.txt' DELIMITER '|' TIMEFORMAT 'YYYY-MM-DD HH:MI:SS' IGNOREHEADER 1 IAM_ROLE '$ROLE_ARN';" 2>&1) echo "$USERS_LOAD_OUTPUT" check_error "$USERS_LOAD_OUTPUT" "aws redshift-data execute-statement (load users)" USERS_LOAD_QUERY_ID=$(echo "$USERS_LOAD_OUTPUT" | grep -o '"Id": "[^"]*' | cut -d'"' -f4) # Wait for data loading to complete echo "Waiting for users data loading to complete..." sleep 10 # Load data into event table echo "Loading data into event table..." EVENT_LOAD_OUTPUT=$(aws redshift-data execute-statement \ --database "$DB_NAME" \ --workgroup-name "$WORKGROUP_NAME" \ --sql "COPY event FROM 's3://redshift-downloads/tickit/allevents_pipe.txt' DELIMITER '|' TIMEFORMAT 'YYYY-MM-DD HH:MI:SS' IGNOREHEADER 1 IAM_ROLE '$ROLE_ARN';" 2>&1) echo "$EVENT_LOAD_OUTPUT" check_error "$EVENT_LOAD_OUTPUT" "aws redshift-data execute-statement (load event)" EVENT_LOAD_QUERY_ID=$(echo "$EVENT_LOAD_OUTPUT" | grep -o '"Id": "[^"]*' | cut -d'"' -f4) # Wait for data loading to complete echo "Waiting for event data loading to complete..." sleep 10 # Load data into sales table echo "Loading data into sales table..." SALES_LOAD_OUTPUT=$(aws redshift-data execute-statement \ --database "$DB_NAME" \ --workgroup-name "$WORKGROUP_NAME" \ --sql "COPY sales FROM 's3://redshift-downloads/tickit/sales_tab.txt' DELIMITER '\t' TIMEFORMAT 'MM/DD/YYYY HH:MI:SS' IGNOREHEADER 1 IAM_ROLE '$ROLE_ARN';" 2>&1) echo "$SALES_LOAD_OUTPUT" check_error "$SALES_LOAD_OUTPUT" "aws redshift-data execute-statement (load sales)" SALES_LOAD_QUERY_ID=$(echo "$SALES_LOAD_OUTPUT" | grep -o '"Id": "[^"]*' | cut -d'"' -f4) # Wait for data loading to complete echo "Waiting for sales data loading to complete..." sleep 30 # Step 6: Run sample queries echo "Running sample queries..." # Query 1: Find top 10 buyers by quantity echo "Running query: Find top 10 buyers by quantity..." QUERY1_OUTPUT=$(aws redshift-data execute-statement \ --database "$DB_NAME" \ --workgroup-name "$WORKGROUP_NAME" \ --sql "SELECT firstname, lastname, total_quantity FROM (SELECT buyerid, sum(qtysold) total_quantity FROM sales GROUP BY buyerid ORDER BY total_quantity desc limit 10) Q, users WHERE Q.buyerid = userid ORDER BY Q.total_quantity desc;" 2>&1) echo "$QUERY1_OUTPUT" check_error "$QUERY1_OUTPUT" "aws redshift-data execute-statement (query 1)" QUERY1_ID=$(echo "$QUERY1_OUTPUT" | grep -o '"Id": "[^"]*' | cut -d'"' -f4) # Wait for query to complete echo "Waiting for query 1 to complete..." sleep 10 # Get query 1 results echo "Getting results for query 1..." QUERY1_STATUS_OUTPUT=$(aws redshift-data describe-statement --id "$QUERY1_ID" 2>&1) echo "$QUERY1_STATUS_OUTPUT" check_error "$QUERY1_STATUS_OUTPUT" "aws redshift-data describe-statement (query 1)" QUERY1_STATUS=$(echo "$QUERY1_STATUS_OUTPUT" | grep -o '"Status": "[^"]*' | cut -d'"' -f4) if [ "$QUERY1_STATUS" == "FINISHED" ]; then QUERY1_RESULTS=$(aws redshift-data get-statement-result --id "$QUERY1_ID" 2>&1) echo "Query 1 Results:" echo "$QUERY1_RESULTS" else echo "Query 1 is not yet complete. Status: $QUERY1_STATUS" echo "Waiting additional time for query to complete..." sleep 20 # Check again QUERY1_STATUS_OUTPUT=$(aws redshift-data describe-statement --id "$QUERY1_ID" 2>&1) QUERY1_STATUS=$(echo "$QUERY1_STATUS_OUTPUT" | grep -o '"Status": "[^"]*' | cut -d'"' -f4) if [ "$QUERY1_STATUS" == "FINISHED" ]; then QUERY1_RESULTS=$(aws redshift-data get-statement-result --id "$QUERY1_ID" 2>&1) echo "Query 1 Results:" echo "$QUERY1_RESULTS" else echo "Query 1 is still not complete. Status: $QUERY1_STATUS" fi fi # Query 2: Find events in the 99.9 percentile in terms of all time total sales echo "Running query: Find events in the 99.9 percentile in terms of all time total sales..." QUERY2_OUTPUT=$(aws redshift-data execute-statement \ --database "$DB_NAME" \ --workgroup-name "$WORKGROUP_NAME" \ --sql "SELECT eventname, total_price FROM (SELECT eventid, total_price, ntile(1000) over(order by total_price desc) as percentile FROM (SELECT eventid, sum(pricepaid) total_price FROM sales GROUP BY eventid)) Q, event E WHERE Q.eventid = E.eventid AND percentile = 1 ORDER BY total_price desc;" 2>&1) echo "$QUERY2_OUTPUT" check_error "$QUERY2_OUTPUT" "aws redshift-data execute-statement (query 2)" QUERY2_ID=$(echo "$QUERY2_OUTPUT" | grep -o '"Id": "[^"]*' | cut -d'"' -f4) # Wait for query to complete echo "Waiting for query 2 to complete..." sleep 10 # Get query 2 results echo "Getting results for query 2..." QUERY2_STATUS_OUTPUT=$(aws redshift-data describe-statement --id "$QUERY2_ID" 2>&1) echo "$QUERY2_STATUS_OUTPUT" check_error "$QUERY2_STATUS_OUTPUT" "aws redshift-data describe-statement (query 2)" QUERY2_STATUS=$(echo "$QUERY2_STATUS_OUTPUT" | grep -o '"Status": "[^"]*' | cut -d'"' -f4) if [ "$QUERY2_STATUS" == "FINISHED" ]; then QUERY2_RESULTS=$(aws redshift-data get-statement-result --id "$QUERY2_ID" 2>&1) echo "Query 2 Results:" echo "$QUERY2_RESULTS" else echo "Query 2 is not yet complete. Status: $QUERY2_STATUS" echo "Waiting additional time for query to complete..." sleep 20 # Check again QUERY2_STATUS_OUTPUT=$(aws redshift-data describe-statement --id "$QUERY2_ID" 2>&1) QUERY2_STATUS=$(echo "$QUERY2_STATUS_OUTPUT" | grep -o '"Status": "[^"]*' | cut -d'"' -f4) if [ "$QUERY2_STATUS" == "FINISHED" ]; then QUERY2_RESULTS=$(aws redshift-data get-statement-result --id "$QUERY2_ID" 2>&1) echo "Query 2 Results:" echo "$QUERY2_RESULTS" else echo "Query 2 is still not complete. Status: $QUERY2_STATUS" fi fi # Summary echo "" echo "===========================================" echo "TUTORIAL SUMMARY" echo "===========================================" echo "You have successfully:" echo "1. Created a Redshift Serverless namespace and workgroup" echo "2. Created an IAM role with S3 access permissions" echo "3. Stored admin credentials securely in AWS Secrets Manager" echo "4. Created tables for sample data" echo "5. Loaded sample data from Amazon S3" echo "6. Run sample queries on the data" echo "" echo "Redshift Serverless Resources:" echo "- Namespace: $NAMESPACE_NAME" echo "- Workgroup: $WORKGROUP_NAME" echo "- Database: $DB_NAME" echo "- Endpoint: $WORKGROUP_ENDPOINT" echo "- Credentials Secret: $SECRET_NAME" echo "" echo "To connect to your Redshift Serverless database using SQL tools:" echo "- Host: $WORKGROUP_ENDPOINT" echo "- Database: $DB_NAME" echo "- Username: $ADMIN_USERNAME" echo "- Password: Retrieve from AWS Secrets Manager secret '$SECRET_NAME'" echo "" echo "To retrieve the password from Secrets Manager (without jq):" echo "aws secretsmanager get-secret-value --secret-id $SECRET_NAME --query 'SecretString' --output text | sed -n 's/.*\"password\":\"\([^\"]*\)\".*/\1/p'" echo "" # Clean up temporary files rm -f redshift-trust-policy.json redshift-s3-policy.json # Clean up resources cleanup_resources echo "Tutorial completed at $(date)"

For a complete list of AWS SDK developer guides and code examples, see Using this service with an AWS SDK. This topic also includes information about getting started and details about previous SDK versions.