diff --git a/tuts/141-aws-savingsplans-gs/README.md b/tuts/141-aws-savingsplans-gs/README.md new file mode 100644 index 0000000..3b67711 --- /dev/null +++ b/tuts/141-aws-savingsplans-gs/README.md @@ -0,0 +1,28 @@ +# Aws Savingsplans Gs + +A read-only script that queries Savingsplans resources and displays information. + +## Running + +```bash +bash aws-savingsplans-gs.sh +``` + +## What it does + +1. Describing savings plans +2. Describing savings plan rates +3. Listing available offerings + +## Resources created + +None — this script is read-only. + +## Cost + +No cost. This script only reads existing resources. + +## Related docs + +- [AWS CLI savingsplans reference](https://docs.aws.amazon.com/cli/latest/reference/savingsplans/index.html) + diff --git a/tuts/141-aws-savingsplans-gs/REVISION-HISTORY.md b/tuts/141-aws-savingsplans-gs/REVISION-HISTORY.md new file mode 100644 index 0000000..a687bc7 --- /dev/null +++ b/tuts/141-aws-savingsplans-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 141-aws-savingsplans-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/141-aws-savingsplans-gs/aws-savingsplans-gs.md b/tuts/141-aws-savingsplans-gs/aws-savingsplans-gs.md new file mode 100644 index 0000000..92d544e --- /dev/null +++ b/tuts/141-aws-savingsplans-gs/aws-savingsplans-gs.md @@ -0,0 +1,19 @@ +# Aws Savingsplans Gs + +## Prerequisites + +1. AWS CLI installed and configured (`aws configure`) +2. Appropriate IAM permissions for the AWS services used + +## Step 1: Describing savings plans + +The script handles this step automatically. See `aws-savingsplans-gs.sh` for the exact CLI commands. + +## Step 2: Describing savings plan rates + +The script handles this step automatically. See `aws-savingsplans-gs.sh` for the exact CLI commands. + +## Step 3: Listing available offerings + +The script handles this step automatically. See `aws-savingsplans-gs.sh` for the exact CLI commands. + diff --git a/tuts/141-aws-savingsplans-gs/aws-savingsplans-gs.sh b/tuts/141-aws-savingsplans-gs/aws-savingsplans-gs.sh new file mode 100644 index 0000000..34e1390 --- /dev/null +++ b/tuts/141-aws-savingsplans-gs/aws-savingsplans-gs.sh @@ -0,0 +1,12 @@ +#!/bin/bash +WORK_DIR=$(mktemp -d); exec > >(tee -a "$WORK_DIR/sp.log") 2>&1 +REGION=us-east-1 # Savings Plans requires us-east-1 +export AWS_DEFAULT_REGION="$REGION"; export AWS_REGION="$REGION"; echo "Region: $REGION" +echo "Step 1: Describing savings plans" +aws savingsplans describe-savings-plans --query 'savingsPlans[:5].{Id:savingsPlanId,Type:savingsPlanType,State:state,Commitment:commitment}' --output table 2>/dev/null || echo " No savings plans found" +echo "Step 2: Describing savings plan rates" +aws savingsplans describe-savings-plans-offering-rates --savings-plan-offering-ids [] 2>/dev/null | head -5 || echo " No offering rates (no active plans)" +echo "Step 3: Listing available offerings" +aws savingsplans describe-savings-plans-offerings --query 'searchResults[:3].{Type:planType,Duration:durationSeconds,Currency:currency}' --output table 2>/dev/null || echo " Cannot list offerings" +echo ""; echo "Tutorial complete. No resources created — read-only." +rm -rf "$WORK_DIR" diff --git a/tuts/142-aws-servicecatalog-gs/README.md b/tuts/142-aws-servicecatalog-gs/README.md new file mode 100644 index 0000000..7ed5da3 --- /dev/null +++ b/tuts/142-aws-servicecatalog-gs/README.md @@ -0,0 +1,36 @@ +# Aws Servicecatalog Gs + +An AWS CLI tutorial that demonstrates Servicecatalog operations. + +## Running + +```bash +bash aws-servicecatalog-gs.sh +``` + +To auto-run with cleanup: + +```bash +echo 'y' | bash aws-servicecatalog-gs.sh +``` + +## What it does + +1. Creating portfolio: $PORTFOLIO +2. Describing portfolio +3. Listing portfolios + +## Resources created + +- Portfolio + +The script prompts you to clean up resources when it finishes. + +## Cost + +Free tier eligible for most operations. Clean up resources after use to avoid charges. + +## Related docs + +- [AWS CLI servicecatalog reference](https://docs.aws.amazon.com/cli/latest/reference/servicecatalog/index.html) + diff --git a/tuts/142-aws-servicecatalog-gs/REVISION-HISTORY.md b/tuts/142-aws-servicecatalog-gs/REVISION-HISTORY.md new file mode 100644 index 0000000..055afcc --- /dev/null +++ b/tuts/142-aws-servicecatalog-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 142-aws-servicecatalog-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/142-aws-servicecatalog-gs/aws-servicecatalog-gs.md b/tuts/142-aws-servicecatalog-gs/aws-servicecatalog-gs.md new file mode 100644 index 0000000..e7fee64 --- /dev/null +++ b/tuts/142-aws-servicecatalog-gs/aws-servicecatalog-gs.md @@ -0,0 +1,23 @@ +# Aws Servicecatalog Gs + +## Prerequisites + +1. AWS CLI installed and configured (`aws configure`) +2. Appropriate IAM permissions for the AWS services used + +## Step 1: Creating portfolio: $PORTFOLIO + +The script handles this step automatically. See `aws-servicecatalog-gs.sh` for the exact CLI commands. + +## Step 2: Describing portfolio + +The script handles this step automatically. See `aws-servicecatalog-gs.sh` for the exact CLI commands. + +## Step 3: Listing portfolios + +The script handles this step automatically. See `aws-servicecatalog-gs.sh` for the exact CLI commands. + +## Cleanup + +The script prompts you to clean up all created resources. If you need to clean up manually, check the script log for the resource names that were created. + diff --git a/tuts/142-aws-servicecatalog-gs/aws-servicecatalog-gs.sh b/tuts/142-aws-servicecatalog-gs/aws-servicecatalog-gs.sh new file mode 100644 index 0000000..01fca07 --- /dev/null +++ b/tuts/142-aws-servicecatalog-gs/aws-servicecatalog-gs.sh @@ -0,0 +1,15 @@ +#!/bin/bash +WORK_DIR=$(mktemp -d); exec > >(tee -a "$WORK_DIR/sc.log") 2>&1 +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null))}; [ -z "$REGION" ] && echo "ERROR: No region" && exit 1; export AWS_DEFAULT_REGION="$REGION"; echo "Region: $REGION" +RANDOM_ID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1); PORTFOLIO="tut-portfolio-${RANDOM_ID}" +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; }; trap 'handle_error $LINENO' ERR +cleanup() { echo ""; echo "Cleaning up..."; [ -n "$PORT_ID" ] && aws servicecatalog delete-portfolio --id "$PORT_ID" 2>/dev/null && echo " Deleted portfolio"; rm -rf "$WORK_DIR"; echo "Done."; } +echo "Step 1: Creating portfolio: $PORTFOLIO" +PORT_ID=$(aws servicecatalog create-portfolio --display-name "$PORTFOLIO" --provider-name "Tutorial" --query 'PortfolioDetail.Id' --output text) +echo " Portfolio ID: $PORT_ID" +echo "Step 2: Describing portfolio" +aws servicecatalog describe-portfolio --id "$PORT_ID" --query 'PortfolioDetail.{Name:DisplayName,Id:Id,Provider:ProviderName,Created:CreatedTime}' --output table +echo "Step 3: Listing portfolios" +aws servicecatalog list-portfolios --query 'PortfolioDetails[?starts_with(DisplayName, `tut-`)].{Name:DisplayName,Id:Id}' --output table +echo ""; echo "Tutorial complete." +echo "Do you want to clean up? (y/n): "; read -r CHOICE; [[ "$CHOICE" =~ ^[Yy]$ ]] && cleanup diff --git a/tuts/150-aws-sso-admin-gs/README.md b/tuts/150-aws-sso-admin-gs/README.md new file mode 100644 index 0000000..aae000e --- /dev/null +++ b/tuts/150-aws-sso-admin-gs/README.md @@ -0,0 +1,28 @@ +# Aws Sso Admin Gs + +A read-only script that queries Sso Admin resources and displays information. + +## Running + +```bash +bash aws-sso-admin-gs.sh +``` + +## What it does + +1. Listing IAM Identity Center instances +2. Listing permission sets +3. Listing accounts for provisioned permission sets + +## Resources created + +None — this script is read-only. + +## Cost + +No cost. This script only reads existing resources. + +## Related docs + +- [AWS CLI sso-admin reference](https://docs.aws.amazon.com/cli/latest/reference/sso-admin/index.html) + diff --git a/tuts/150-aws-sso-admin-gs/REVISION-HISTORY.md b/tuts/150-aws-sso-admin-gs/REVISION-HISTORY.md new file mode 100644 index 0000000..dc7c402 --- /dev/null +++ b/tuts/150-aws-sso-admin-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 150-aws-sso-admin-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/150-aws-sso-admin-gs/aws-sso-admin-gs.md b/tuts/150-aws-sso-admin-gs/aws-sso-admin-gs.md new file mode 100644 index 0000000..b74d712 --- /dev/null +++ b/tuts/150-aws-sso-admin-gs/aws-sso-admin-gs.md @@ -0,0 +1,19 @@ +# Aws Sso Admin Gs + +## Prerequisites + +1. AWS CLI installed and configured (`aws configure`) +2. Appropriate IAM permissions for the AWS services used + +## Step 1: Listing IAM Identity Center instances + +The script handles this step automatically. See `aws-sso-admin-gs.sh` for the exact CLI commands. + +## Step 2: Listing permission sets + +The script handles this step automatically. See `aws-sso-admin-gs.sh` for the exact CLI commands. + +## Step 3: Listing accounts for provisioned permission sets + +The script handles this step automatically. See `aws-sso-admin-gs.sh` for the exact CLI commands. + diff --git a/tuts/150-aws-sso-admin-gs/aws-sso-admin-gs.sh b/tuts/150-aws-sso-admin-gs/aws-sso-admin-gs.sh new file mode 100644 index 0000000..1dc0862 --- /dev/null +++ b/tuts/150-aws-sso-admin-gs/aws-sso-admin-gs.sh @@ -0,0 +1,13 @@ +#!/bin/bash +WORK_DIR=$(mktemp -d); exec > >(tee -a "$WORK_DIR/sso.log") 2>&1 +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null))}; [ -z "$REGION" ] && echo "ERROR: No region" && exit 1; export AWS_DEFAULT_REGION="$REGION"; echo "Region: $REGION" +echo "Step 1: Listing IAM Identity Center instances" +INSTANCE_ARN=$(aws sso-admin list-instances --query 'Instances[0].InstanceArn' --output text 2>/dev/null) +if [ -z "$INSTANCE_ARN" ] || [ "$INSTANCE_ARN" = "None" ]; then echo " No IAM Identity Center instance found. Enable it in the console first."; rm -rf "$WORK_DIR"; exit 0; fi +echo " Instance: $INSTANCE_ARN" +echo "Step 2: Listing permission sets" +aws sso-admin list-permission-sets --instance-arn "$INSTANCE_ARN" --query 'PermissionSets[:5]' --output table 2>/dev/null || echo " No permission sets" +echo "Step 3: Listing accounts for provisioned permission sets" +aws sso-admin list-accounts-for-provisioned-permission-set --instance-arn "$INSTANCE_ARN" --permission-set-arn "$(aws sso-admin list-permission-sets --instance-arn "$INSTANCE_ARN" --query 'PermissionSets[0]' --output text 2>/dev/null)" --query 'AccountIds' --output table 2>/dev/null || echo " No provisioned accounts" +echo ""; echo "Tutorial complete. No resources created — read-only." +rm -rf "$WORK_DIR" diff --git a/tuts/157-cloudformation-stacks/README.md b/tuts/157-cloudformation-stacks/README.md new file mode 100644 index 0000000..4e8c92d --- /dev/null +++ b/tuts/157-cloudformation-stacks/README.md @@ -0,0 +1,38 @@ +# Cloudformation Stacks + +An AWS CLI tutorial that demonstrates Cloudformation operations. + +## Running + +```bash +bash cloudformation-stacks.sh +``` + +To auto-run with cleanup: + +```bash +echo 'y' | bash cloudformation-stacks.sh +``` + +## What it does + +1. Creating a CloudFormation template +2. Creating stack: $STACK_NAME +3. Stack outputs +4. Listing stack resources +5. Stack events + +## Resources created + +- Stack + +The script prompts you to clean up resources when it finishes. + +## Cost + +Free tier eligible for most operations. Clean up resources after use to avoid charges. + +## Related docs + +- [AWS CLI cloudformation reference](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/index.html) + diff --git a/tuts/157-cloudformation-stacks/REVISION-HISTORY.md b/tuts/157-cloudformation-stacks/REVISION-HISTORY.md new file mode 100644 index 0000000..851aec3 --- /dev/null +++ b/tuts/157-cloudformation-stacks/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 157-cloudformation-stacks + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/157-cloudformation-stacks/cloudformation-stacks.md b/tuts/157-cloudformation-stacks/cloudformation-stacks.md new file mode 100644 index 0000000..37c6edd --- /dev/null +++ b/tuts/157-cloudformation-stacks/cloudformation-stacks.md @@ -0,0 +1,31 @@ +# Cloudformation Stacks + +## Prerequisites + +1. AWS CLI installed and configured (`aws configure`) +2. Appropriate IAM permissions for the AWS services used + +## Step 1: Creating a CloudFormation template + +The script handles this step automatically. See `cloudformation-stacks.sh` for the exact CLI commands. + +## Step 2: Creating stack: $STACK_NAME + +The script handles this step automatically. See `cloudformation-stacks.sh` for the exact CLI commands. + +## Step 3: Stack outputs + +The script handles this step automatically. See `cloudformation-stacks.sh` for the exact CLI commands. + +## Step 4: Listing stack resources + +The script handles this step automatically. See `cloudformation-stacks.sh` for the exact CLI commands. + +## Step 5: Stack events + +The script handles this step automatically. See `cloudformation-stacks.sh` for the exact CLI commands. + +## Cleanup + +The script prompts you to clean up all created resources. If you need to clean up manually, check the script log for the resource names that were created. + diff --git a/tuts/157-cloudformation-stacks/cloudformation-stacks.sh b/tuts/157-cloudformation-stacks/cloudformation-stacks.sh new file mode 100644 index 0000000..5272c65 --- /dev/null +++ b/tuts/157-cloudformation-stacks/cloudformation-stacks.sh @@ -0,0 +1,39 @@ +#!/bin/bash +WORK_DIR=$(mktemp -d); exec > >(tee -a "$WORK_DIR/cfn.log") 2>&1 +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null))}; [ -z "$REGION" ] && echo "ERROR: No region" && exit 1; export AWS_DEFAULT_REGION="$REGION"; echo "Region: $REGION" +RANDOM_ID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1); STACK_NAME="tut-stack-${RANDOM_ID}" +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; }; trap 'handle_error $LINENO' ERR +cleanup() { echo ""; echo "Cleaning up..."; aws cloudformation delete-stack --stack-name "$STACK_NAME" 2>/dev/null; aws cloudformation wait stack-delete-complete --stack-name "$STACK_NAME" 2>/dev/null && echo " Stack deleted"; rm -rf "$WORK_DIR"; echo "Done."; } +echo "Step 1: Creating a CloudFormation template" +cat > "$WORK_DIR/template.yaml" << 'EOF' +AWSTemplateFormatVersion: '2010-09-09' +Description: Tutorial stack - creates an SQS queue +Parameters: + QueueName: + Type: String + Default: tutorial-queue +Resources: + TutorialQueue: + Type: AWS::SQS::Queue + Properties: + QueueName: !Ref QueueName + MessageRetentionPeriod: 86400 +Outputs: + QueueUrl: + Value: !Ref TutorialQueue + QueueArn: + Value: !GetAtt TutorialQueue.Arn +EOF +echo " Template created" +echo "Step 2: Creating stack: $STACK_NAME" +aws cloudformation create-stack --stack-name "$STACK_NAME" --template-body "file://$WORK_DIR/template.yaml" --parameters "ParameterKey=QueueName,ParameterValue=cfn-tut-${RANDOM_ID}" > /dev/null +echo " Waiting for stack creation..." +aws cloudformation wait stack-create-complete --stack-name "$STACK_NAME" +echo "Step 3: Stack outputs" +aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query 'Stacks[0].Outputs[].{Key:OutputKey,Value:OutputValue}' --output table +echo "Step 4: Listing stack resources" +aws cloudformation list-stack-resources --stack-name "$STACK_NAME" --query 'StackResourceSummaries[].{Type:ResourceType,LogicalId:LogicalResourceId,Status:ResourceStatus}' --output table +echo "Step 5: Stack events" +aws cloudformation describe-stack-events --stack-name "$STACK_NAME" --query 'StackEvents[:5].{Resource:LogicalResourceId,Status:ResourceStatus,Time:Timestamp}' --output table +echo ""; echo "Tutorial complete." +echo "Do you want to clean up? (y/n): "; read -r CHOICE; [[ "$CHOICE" =~ ^[Yy]$ ]] && cleanup diff --git a/tuts/163-cloudwatch-metrics-math/README.md b/tuts/163-cloudwatch-metrics-math/README.md new file mode 100644 index 0000000..16d16c7 --- /dev/null +++ b/tuts/163-cloudwatch-metrics-math/README.md @@ -0,0 +1,37 @@ +# Cloudwatch Metrics Math + +An AWS CLI tutorial that demonstrates Cloudwatch operations. + +## Running + +```bash +bash cloudwatch-metrics-math.sh +``` + +To auto-run with cleanup: + +```bash +echo 'y' | bash cloudwatch-metrics-math.sh +``` + +## What it does + +1. Publishing high-resolution metrics +2. Getting metric statistics +3. Using metric math (error rate) +4. Listing metrics in namespace + +## Resources created + +- Metric Data + +The script prompts you to clean up resources when it finishes. + +## Cost + +Free tier eligible for most operations. Clean up resources after use to avoid charges. + +## Related docs + +- [AWS CLI cloudwatch reference](https://docs.aws.amazon.com/cli/latest/reference/cloudwatch/index.html) + diff --git a/tuts/163-cloudwatch-metrics-math/REVISION-HISTORY.md b/tuts/163-cloudwatch-metrics-math/REVISION-HISTORY.md new file mode 100644 index 0000000..214b571 --- /dev/null +++ b/tuts/163-cloudwatch-metrics-math/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 163-cloudwatch-metrics-math + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/163-cloudwatch-metrics-math/cloudwatch-metrics-math.md b/tuts/163-cloudwatch-metrics-math/cloudwatch-metrics-math.md new file mode 100644 index 0000000..e85567a --- /dev/null +++ b/tuts/163-cloudwatch-metrics-math/cloudwatch-metrics-math.md @@ -0,0 +1,27 @@ +# Cloudwatch Metrics Math + +## Prerequisites + +1. AWS CLI installed and configured (`aws configure`) +2. Appropriate IAM permissions for the AWS services used + +## Step 1: Publishing high-resolution metrics + +The script handles this step automatically. See `cloudwatch-metrics-math.sh` for the exact CLI commands. + +## Step 2: Getting metric statistics + +The script handles this step automatically. See `cloudwatch-metrics-math.sh` for the exact CLI commands. + +## Step 3: Using metric math (error rate) + +The script handles this step automatically. See `cloudwatch-metrics-math.sh` for the exact CLI commands. + +## Step 4: Listing metrics in namespace + +The script handles this step automatically. See `cloudwatch-metrics-math.sh` for the exact CLI commands. + +## Cleanup + +The script prompts you to clean up all created resources. If you need to clean up manually, check the script log for the resource names that were created. + diff --git a/tuts/163-cloudwatch-metrics-math/cloudwatch-metrics-math.sh b/tuts/163-cloudwatch-metrics-math/cloudwatch-metrics-math.sh new file mode 100644 index 0000000..21dc3d7 --- /dev/null +++ b/tuts/163-cloudwatch-metrics-math/cloudwatch-metrics-math.sh @@ -0,0 +1,19 @@ +#!/bin/bash +WORK_DIR=$(mktemp -d); exec > >(tee -a "$WORK_DIR/cw-math.log") 2>&1 +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null))}; [ -z "$REGION" ] && echo "ERROR: No region" && exit 1; export AWS_DEFAULT_REGION="$REGION"; echo "Region: $REGION" +RANDOM_ID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1); NS="Tutorial/App-${RANDOM_ID}" +cleanup() { echo ""; echo "No cleanup needed — custom metrics expire automatically."; rm -rf "$WORK_DIR"; } +echo "Step 1: Publishing high-resolution metrics" +for i in $(seq 1 10); do + aws cloudwatch put-metric-data --namespace "$NS" --metric-data "[{\"MetricName\":\"Requests\",\"Value\":$((RANDOM % 100 + 50)),\"Unit\":\"Count\",\"StorageResolution\":1},{\"MetricName\":\"Errors\",\"Value\":$((RANDOM % 5)),\"Unit\":\"Count\",\"StorageResolution\":1},{\"MetricName\":\"Latency\",\"Value\":$((RANDOM % 200 + 10)),\"Unit\":\"Milliseconds\"}]" +done +echo " Published 30 data points (10 batches x 3 metrics)" +sleep 3 +echo "Step 2: Getting metric statistics" +aws cloudwatch get-metric-statistics --namespace "$NS" --metric-name Requests --start-time "$(date -u -d '5 minutes ago' +%Y-%m-%dT%H:%M:%SZ)" --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --period 60 --statistics Sum Average Maximum --query 'Datapoints[0].{Sum:Sum,Avg:Average,Max:Maximum}' --output table 2>/dev/null || echo " Metrics not yet available" +echo "Step 3: Using metric math (error rate)" +aws cloudwatch get-metric-data --metric-data-queries '[{"Id":"requests","MetricStat":{"Metric":{"Namespace":"'"$NS"'","MetricName":"Requests"},"Period":60,"Stat":"Sum"},"ReturnData":false},{"Id":"errors","MetricStat":{"Metric":{"Namespace":"'"$NS"'","MetricName":"Errors"},"Period":60,"Stat":"Sum"},"ReturnData":false},{"Id":"error_rate","Expression":"(errors/requests)*100","Label":"Error Rate %","ReturnData":true}]' --start-time "$(date -u -d '5 minutes ago' +%Y-%m-%dT%H:%M:%SZ)" --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --query 'MetricDataResults[0].{Label:Label,Values:Values}' --output table 2>/dev/null || echo " Math expression result pending" +echo "Step 4: Listing metrics in namespace" +aws cloudwatch list-metrics --namespace "$NS" --query 'Metrics[].{Name:MetricName,Dimensions:Dimensions|length(@)}' --output table +echo ""; echo "Tutorial complete." +cleanup