Skip to content

Commit 4354992

Browse files
authored
feat: add destroy.sh script for easy deletion (#1366)
Thank you!
1 parent d462844 commit 4354992

File tree

5 files changed

+561
-0
lines changed

5 files changed

+561
-0
lines changed

destroy.sh

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Set Node.js memory limit
6+
export NODE_OPTIONS="--max-old-space-size=800"
7+
8+
echo "----------------------------"
9+
echo " _____ _ _ "
10+
echo " / ____| | | | | "
11+
echo "| | __ ___ _ __ | | | | "
12+
echo "| | |_ |/ _ \ '_ \| | | | "
13+
echo "| |__| | __/ | | | |__| | "
14+
echo " \_____|\___|_| |_|\____/ "
15+
echo " DESTROY STACKS "
16+
echo "----------------------------"
17+
18+
# Process command arguments
19+
env_name_provided=false
20+
while [[ $# -gt 0 ]]; do
21+
case "$1" in
22+
-c|--cdk-context)
23+
cdk_context_path="$2"
24+
shift 2
25+
;;
26+
-p|--parameter-file)
27+
parameter_file_path="$2"
28+
shift 2
29+
;;
30+
-e|--env)
31+
env_name="$2"
32+
env_name_provided=true
33+
shift 2
34+
;;
35+
-y|--yes)
36+
skip_confirmation=true
37+
shift
38+
;;
39+
-h|--help)
40+
echo "-c, --cdk-context ... Path to the cdk.json file"
41+
echo "-p, --parameter-file ... Path to the parameter.ts file"
42+
echo "-e, --env ... Environment name (e.g., dev, prod)"
43+
echo "-y, --yes ... Skip confirmation prompt"
44+
echo "-h, --help ... Show this message"
45+
exit 0
46+
;;
47+
*)
48+
echo "Unknown option: $1"
49+
exit 1
50+
;;
51+
esac
52+
done
53+
54+
# Check if the file exists
55+
if [[ -n "$cdk_context_path" && ! -f "$cdk_context_path" ]]; then
56+
echo "Error: CDK context file not found: $cdk_context_path"
57+
exit 1
58+
fi
59+
60+
if [[ -n "$parameter_file_path" && ! -f "$parameter_file_path" ]]; then
61+
echo "Error: Parameter file not found: $parameter_file_path"
62+
exit 1
63+
fi
64+
65+
pushd /tmp
66+
67+
# Delete the repository in /tmp if it exists
68+
rm -rf generative-ai-use-cases
69+
70+
# Clone GenU
71+
git clone https://github.com/aws-samples/generative-ai-use-cases
72+
73+
pushd generative-ai-use-cases
74+
75+
# Install npm packages
76+
npm ci
77+
78+
# If cdk.json is specified, use it
79+
if [[ -n "$cdk_context_path" ]]; then
80+
echo "Using provided cdk.json from $cdk_context_path"
81+
cp -f $cdk_context_path packages/cdk/cdk.json
82+
fi
83+
84+
# If parameter.ts is specified, use it
85+
if [[ -n "$parameter_file_path" ]]; then
86+
echo "Using provided parameter.ts from $parameter_file_path"
87+
cp -f $parameter_file_path packages/cdk/parameter.ts
88+
fi
89+
90+
# Determine environment name if not specified
91+
if [[ "$env_name_provided" == false ]]; then
92+
# Get all GenU stacks (sorted alphabetically for deterministic behavior)
93+
STACK_NAMES=$(aws cloudformation list-stacks \
94+
--stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE \
95+
--query 'sort_by(StackSummaries[?starts_with(StackName, `GenerativeAiUseCasesStack`)], &StackName)[].StackName' \
96+
--output text)
97+
98+
# Count number of stacks
99+
STACK_COUNT=$(echo "$STACK_NAMES" | awk 'NF' | wc -w)
100+
101+
if [[ $STACK_COUNT -eq 0 ]]; then
102+
echo "Error: No GenU stacks found in this account"
103+
exit 1
104+
elif [[ $STACK_COUNT -gt 1 ]]; then
105+
# Multiple stacks - require explicit environment
106+
echo ""
107+
echo "╔════════════════════════════════════════════════════════════════╗"
108+
echo "║ ⚠️ ERROR: Multiple GenU environments detected ║"
109+
echo "╚════════════════════════════════════════════════════════════════╝"
110+
echo ""
111+
echo "Found $STACK_COUNT GenU deployments in this account:"
112+
echo ""
113+
114+
# Display all environments
115+
IFS=$'\t' read -ra STACK_ARRAY <<< "$STACK_NAMES"
116+
for stack in "${STACK_ARRAY[@]}"; do
117+
env="${stack#GenerativeAiUseCasesStack}"
118+
echo "${env:-default} (Stack: $stack)"
119+
done
120+
121+
echo ""
122+
echo "To prevent accidental deletion, you must explicitly specify"
123+
echo "which environment to destroy using the -e flag:"
124+
echo ""
125+
echo " ./destroy.sh -e <environment-name>"
126+
echo ""
127+
echo "Examples:"
128+
for stack in "${STACK_ARRAY[@]}"; do
129+
env="${stack#GenerativeAiUseCasesStack}"
130+
if [[ -z "$env" ]]; then
131+
echo " ./destroy.sh -e \"\""
132+
else
133+
echo " ./destroy.sh -e $env"
134+
fi
135+
done
136+
echo ""
137+
exit 1
138+
else
139+
# Single stack - auto-select
140+
STACK_NAME=$(echo "$STACK_NAMES" | awk '{print $1}')
141+
env_name="${STACK_NAME#GenerativeAiUseCasesStack}"
142+
echo "Detected environment from stack: ${env_name:-default}"
143+
fi
144+
fi
145+
146+
# If environment is specified, update parameter.ts
147+
if [[ -n "$env_name" && -z "$parameter_file_path" ]]; then
148+
echo "Using parameter.ts for environment: $env_name"
149+
150+
# Get stack outputs to populate parameter.ts
151+
STACK_NAME="GenerativeAiUseCasesStack${env_name}"
152+
153+
if aws cloudformation describe-stacks --stack-name "$STACK_NAME" &>/dev/null; then
154+
echo "Extracting configuration from stack: $STACK_NAME"
155+
156+
# Helper function to extract CloudFormation output values
157+
function extract_value {
158+
echo $1 | jq -r ".Stacks[0].Outputs[] | select(.OutputKey==\"$2\") | .OutputValue"
159+
}
160+
161+
# Get stack outputs
162+
stack_output=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --output json)
163+
164+
# Extract all configuration values
165+
MODEL_REGION=$(extract_value "$stack_output" ModelRegion)
166+
MODEL_IDS=$(extract_value "$stack_output" ModelIds)
167+
IMAGE_MODEL_IDS=$(extract_value "$stack_output" ImageGenerateModelIds)
168+
VIDEO_MODEL_IDS=$(extract_value "$stack_output" VideoGenerateModelIds)
169+
SPEECH_MODEL_IDS=$(extract_value "$stack_output" SpeechToSpeechModelIds)
170+
ENDPOINT_NAMES=$(extract_value "$stack_output" EndpointNames)
171+
RAG_ENABLED=$(extract_value "$stack_output" RagEnabled)
172+
RAG_KB_ENABLED=$(extract_value "$stack_output" RagKnowledgeBaseEnabled)
173+
AGENT_ENABLED=$(extract_value "$stack_output" AgentEnabled)
174+
SELF_SIGNUP=$(extract_value "$stack_output" SelfSignUpEnabled)
175+
SAML_ENABLED=$(extract_value "$stack_output" SamlAuthEnabled)
176+
SAML_DOMAIN=$(extract_value "$stack_output" SamlCognitoDomainName)
177+
SAML_PROVIDER=$(extract_value "$stack_output" SamlCognitoFederatedIdentityProviderName)
178+
AGENTS=$(extract_value "$stack_output" Agents | base64 -d 2>/dev/null || echo "[]")
179+
INLINE_AGENTS=$(extract_value "$stack_output" InlineAgents)
180+
USE_CASE_BUILDER=$(extract_value "$stack_output" UseCaseBuilderEnabled)
181+
HIDDEN_USE_CASES=$(extract_value "$stack_output" HiddenUseCases)
182+
FLOWS=$(extract_value "$stack_output" Flows | base64 -d 2>/dev/null || echo "[]")
183+
MCP_ENABLED=$(extract_value "$stack_output" McpEnabled)
184+
AGENT_CORE_ENABLED=$(extract_value "$stack_output" AgentCoreEnabled)
185+
AGENT_BUILDER_ENABLED=$(extract_value "$stack_output" AgentCoreAgentBuilderEnabled)
186+
AGENT_CORE_EXTERNAL=$(extract_value "$stack_output" AgentCoreExternalRuntimes)
187+
188+
# Update parameter.ts
189+
export env_name MODEL_REGION MODEL_IDS IMAGE_MODEL_IDS VIDEO_MODEL_IDS SPEECH_MODEL_IDS ENDPOINT_NAMES
190+
export RAG_ENABLED RAG_KB_ENABLED AGENT_ENABLED SELF_SIGNUP SAML_ENABLED SAML_DOMAIN SAML_PROVIDER
191+
export AGENTS INLINE_AGENTS FLOWS MCP_ENABLED USE_CASE_BUILDER HIDDEN_USE_CASES
192+
export AGENT_CORE_ENABLED AGENT_BUILDER_ENABLED AGENT_CORE_EXTERNAL
193+
194+
node <<'NODESCRIPT'
195+
const fs = require('fs');
196+
let content = fs.readFileSync('packages/cdk/parameter.ts', 'utf8');
197+
198+
const filterInferenceProfileArn = (models) => {
199+
return models.map(({ inferenceProfileArn, ...rest }) => rest);
200+
};
201+
202+
const envParams = {
203+
modelRegion: process.env.MODEL_REGION,
204+
modelIds: filterInferenceProfileArn(JSON.parse(process.env.MODEL_IDS)),
205+
imageGenerationModelIds: filterInferenceProfileArn(JSON.parse(process.env.IMAGE_MODEL_IDS)),
206+
videoGenerationModelIds: filterInferenceProfileArn(JSON.parse(process.env.VIDEO_MODEL_IDS)),
207+
speechToSpeechModelIds: filterInferenceProfileArn(JSON.parse(process.env.SPEECH_MODEL_IDS)),
208+
endpointNames: filterInferenceProfileArn(JSON.parse(process.env.ENDPOINT_NAMES)),
209+
ragEnabled: process.env.RAG_ENABLED === 'true',
210+
ragKnowledgeBaseEnabled: process.env.RAG_KB_ENABLED === 'true',
211+
agentEnabled: process.env.AGENT_ENABLED === 'true',
212+
selfSignUpEnabled: process.env.SELF_SIGNUP === 'true',
213+
samlAuthEnabled: process.env.SAML_ENABLED === 'true',
214+
samlCognitoDomainName: process.env.SAML_DOMAIN,
215+
samlCognitoFederatedIdentityProviderName: process.env.SAML_PROVIDER,
216+
agents: JSON.parse(process.env.AGENTS),
217+
inlineAgents: process.env.INLINE_AGENTS === 'true',
218+
flows: JSON.parse(process.env.FLOWS),
219+
mcpEnabled: process.env.MCP_ENABLED === 'true',
220+
useCaseBuilderEnabled: process.env.USE_CASE_BUILDER === 'true',
221+
hiddenUseCases: JSON.parse(process.env.HIDDEN_USE_CASES),
222+
createGenericAgentCoreRuntime: process.env.AGENT_CORE_ENABLED === 'true',
223+
agentBuilderEnabled: process.env.AGENT_BUILDER_ENABLED === 'true',
224+
agentCoreExternalRuntimes: JSON.parse(process.env.AGENT_CORE_EXTERNAL)
225+
};
226+
227+
const envParamsStr = JSON.stringify(envParams, null, 2);
228+
const regex = new RegExp(`${process.env.env_name}:\\s*\\{[\\s\\S]*?\\n \\}`, 'm');
229+
content = content.replace(regex, `${process.env.env_name}: ${envParamsStr}`);
230+
231+
fs.writeFileSync('packages/cdk/parameter.ts', content);
232+
NODESCRIPT
233+
234+
echo "Updated parameter.ts with stack configuration"
235+
fi
236+
fi
237+
238+
# List target stacks
239+
echo ""
240+
echo "Target stacks to be deleted:"
241+
if [[ -n "$env_name" ]]; then
242+
npx -w packages/cdk cdk ls -c env="$env_name"
243+
else
244+
npx -w packages/cdk cdk ls
245+
fi
246+
echo ""
247+
248+
# Confirmation prompt
249+
if [[ "$skip_confirmation" != true ]]; then
250+
echo "WARNING: This will permanently delete all GenU stacks and resources."
251+
if [[ -n "$env_name" ]]; then
252+
echo "Environment: $env_name"
253+
else
254+
echo "Environment: default"
255+
fi
256+
echo "This action cannot be undone."
257+
echo ""
258+
read -p "Are you sure you want to continue? (yes/no): " confirmation
259+
260+
if [[ "$confirmation" != "yes" ]]; then
261+
echo "Destroy operation cancelled."
262+
exit 0
263+
fi
264+
fi
265+
266+
# Build destroy command
267+
destroy_cmd="npm run cdk:destroy -- --force"
268+
269+
# Pass environment via context flag if specified
270+
if [[ -n "$env_name" ]]; then
271+
destroy_cmd="$destroy_cmd -c env=$env_name"
272+
fi
273+
274+
# Execute destroy
275+
$destroy_cmd
276+
277+
echo "*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"
278+
echo "GenU has been successfully destroyed"
279+
echo "*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"

docs/en/DESTROY_ON_CLOUDSHELL.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Destroy Method Using AWS CloudShell (When It's Difficult to Prepare Your Own Environment)
2+
3+
## Overview
4+
5+
When deleting GenU, deletion is normally performed based on the deployed environment and configuration files. However, if you don't have these files due to one-click deployment or test deployments, you can quickly delete using this script.
6+
7+
## Launch CloudShell
8+
9+
Launch [CloudShell](https://console.aws.amazon.com/cloudshell/home).
10+
11+
If you have the `cdk.json` or `parameter.ts` used during deployment, select "Upload file" from the "Actions" dropdown list at the top right of the CloudShell terminal to upload the files.
12+
13+
## Download `destroy.sh` and Grant Execution Permission
14+
15+
Execute the following commands in CloudShell to download the `destroy.sh` script.
16+
After downloading, grant execution permission to `destroy.sh`.
17+
18+
```bash
19+
wget https://raw.githubusercontent.com/aws-samples/generative-ai-use-cases/refs/heads/main/destroy.sh -O destroy.sh
20+
chmod +x destroy.sh
21+
```
22+
23+
## Execute `destroy.sh`
24+
25+
`destroy.sh` supports the following options.
26+
27+
```bash
28+
-c, --cdk-context ... Path to the cdk.json file
29+
-p, --parameter-file ... Path to the parameter.ts file
30+
-e, --env ... Environment name (e.g., dev, prod)
31+
-y, --yes ... Skip confirmation prompt
32+
-h, --help ... Show this message
33+
```
34+
35+
If `cdk.json` or `parameter.ts` is not specified, parameters will be estimated from the deployed GenU-related stacks and `cdk.json` will be created. The parameter estimation method follows `setup-env.sh` and estimates through the following steps:
36+
37+
1. Search for deployed `GenerativeAiUseCasesStack*`
38+
2. Retrieve configuration information from CloudFormation outputs
39+
3. Automatically generate minimal cdk.json
40+
4. Destroy all related stacks
41+
42+
### Destroy Examples
43+
44+
Execute destroy.sh with the following commands.
45+
46+
#### 1. Auto-detect and Destroy
47+
48+
Automatically restores configuration from the deployed stack and destroys it. Use this method if you don't have configuration files.
49+
50+
```bash
51+
./destroy.sh
52+
```
53+
54+
If you have separate environments, set `--env`:
55+
56+
```bash
57+
./destroy.sh --env dev
58+
```
59+
60+
A confirmation prompt will be displayed. Enter `yes` to execute the destruction. If you want to skip confirmation and execute, run as follows:
61+
62+
```bash
63+
./destroy.sh --env dev --yes
64+
```
65+
66+
#### 2. Destroy Using Customized cdk.json
67+
68+
If you have the cdk.json used during deployment:
69+
70+
```bash
71+
./destroy.sh --cdk-context ~/cdk.json
72+
```
73+
74+
#### 3. Destroy Using Customized parameter.ts
75+
76+
If you have the parameter.ts used during deployment:
77+
78+
```bash
79+
./destroy.sh --parameter-file ~/parameter.ts
80+
```
81+
82+
#### 4. Destroy with parameter.ts and Environment Specification
83+
84+
```bash
85+
./destroy.sh --parameter-file ~/parameter.ts --env prod
86+
```
87+
88+
### Important Notes
89+
90+
- Destroy operations cannot be undone
91+
- A confirmation prompt is always displayed before destruction (unless using the `--yes` option)
92+
- All related resources (S3 buckets, DynamoDB tables, Lambda functions, etc.) will be deleted
93+
- If you need data backups, please obtain them before destruction

0 commit comments

Comments
 (0)