diff --git a/README.md b/README.md index 6e184a5a..edacb9f7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # claws -A terminal UI for AWS resource management 👮 +A terminal UI for AWS resource management [![CI](https://github.com/clawscli/claws/actions/workflows/ci.yml/badge.svg)](https://github.com/clawscli/claws/actions/workflows/ci.yml) [![Release](https://img.shields.io/github/v/release/clawscli/claws)](https://github.com/clawscli/claws/releases/latest) @@ -8,32 +8,28 @@ A terminal UI for AWS resource management 👮 [![Go Version](https://img.shields.io/badge/Go-1.25+-00ADD8?style=flat&logo=go)](https://go.dev/) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) -![claws demo](demo.gif) - -## Supported Platforms - -| OS | Architecture | -|-----|-------------| -| macOS | Intel, Apple Silicon | -| Linux | x86_64, ARM64 | -| Windows | x86_64 | +![claws demo](docs/images/demo.gif) ## Features - **Interactive TUI** - Navigate AWS resources with vim-style keybindings -- **Mouse support** - Click, scroll, hover for navigation -- **Multi-service support** - EC2, S3, IAM, RDS, Lambda, ECS, and 65+ more services (163 resources total) +- **69 services, 163 resources** - EC2, S3, Lambda, RDS, ECS, and more +- **Multi-profile & Multi-region** - Query multiple accounts/regions in parallel - **Resource actions** - Start/stop instances, delete resources, tail logs -- **Cross-resource navigation** - Jump from VPC to subnets, from Lambda to CloudWatch Logs -- **Profile & region switching** - Switch AWS profiles (`P`) and regions (`R`) on the fly -- **Multi-profile selection** - Select multiple profiles with `P`, parallel fetch across accounts -- **Multi-region selection** - Select multiple regions with `R`, parallel fetch with aggregated results -- **Command mode** - Quick navigation with `:ec2/instances` syntax -- **Tag search** - Browse all tagged resources across regions with `:tags` command -- **Filtering** - Fuzzy search with `/`, tag filtering with `:tag Env=prod` -- **Column sorting** - Sort by any column with `:sort ` command -- **Resource comparison** - Side-by-side diff view with `m` to mark, `d` to compare -- **Pagination** - Handle large datasets with `N` key for next page +- **Cross-resource navigation** - Jump from VPC to subnets, Lambda to CloudWatch +- **Filtering & sorting** - Fuzzy search, tag filtering, column sorting +- **Resource comparison** - Side-by-side diff view +- **6 color themes** - dark, light, nord, dracula, gruvbox, catppuccin + +## Screenshots + +| Resource Browser | Detail View | Actions Menu | +|------------------|-------------|--------------| +| ![browser](docs/images/resource-browser.png) | ![detail](docs/images/detail-view.png) | ![actions](docs/images/actions-menu.png) | + +### Multi-Region & Multi-Account + +![multi-region](docs/images/multi-account-region.png) ## Installation @@ -50,49 +46,9 @@ brew install --cask claws curl -fsSL https://raw.githubusercontent.com/clawscli/claws/main/install.sh | sh ``` -Options: -```bash -# Install specific version -curl -fsSL https://raw.githubusercontent.com/clawscli/claws/main/install.sh | VERSION=v0.1.6 sh - -# Install to custom directory -curl -fsSL https://raw.githubusercontent.com/clawscli/claws/main/install.sh | INSTALL_DIR=/usr/local/bin sh -``` - -> **Security Note:** Piping scripts directly to `sh` is convenient but bypasses inspection. -> For increased security, download and review the script first: -> ```bash -> curl -fsSL https://raw.githubusercontent.com/clawscli/claws/main/install.sh -o install.sh -> less install.sh # Review the script -> sh install.sh -> ``` - ### Download Binary -Download from [GitHub Releases](https://github.com/clawscli/claws/releases/latest): - -```bash -# macOS (Apple Silicon) -curl -Lo claws.tar.gz https://github.com/clawscli/claws/releases/latest/download/claws-darwin-arm64.tar.gz -tar xzf claws.tar.gz && mv claws /usr/local/bin/ - -# macOS (Intel) -curl -Lo claws.tar.gz https://github.com/clawscli/claws/releases/latest/download/claws-darwin-amd64.tar.gz -tar xzf claws.tar.gz && mv claws /usr/local/bin/ - -# Linux (x86_64) -curl -Lo claws.tar.gz https://github.com/clawscli/claws/releases/latest/download/claws-linux-amd64.tar.gz -tar xzf claws.tar.gz && sudo mv claws /usr/local/bin/ - -# Linux (ARM64) -curl -Lo claws.tar.gz https://github.com/clawscli/claws/releases/latest/download/claws-linux-arm64.tar.gz -tar xzf claws.tar.gz && sudo mv claws /usr/local/bin/ - -# Windows (PowerShell) -Invoke-WebRequest -Uri https://github.com/clawscli/claws/releases/latest/download/claws-windows-amd64.zip -OutFile claws.zip -Expand-Archive claws.zip -DestinationPath . -# Add to PATH or move to desired location -``` +Download from [GitHub Releases](https://github.com/clawscli/claws/releases/latest). ### Go Install @@ -100,45 +56,24 @@ Expand-Archive claws.zip -DestinationPath . go install github.com/clawscli/claws/cmd/claws@latest ``` -### From Source - -```bash -git clone https://github.com/clawscli/claws.git -cd claws -go build -o claws ./cmd/claws -``` - ## Quick Start ```bash # Run claws (uses default AWS credentials) claws -# Or with specific profile +# With specific profile claws -p myprofile -# Or with specific region +# With specific region claws -r us-west-2 -# Use environment credentials only (ignore ~/.aws config) -# Useful for EC2 instance profiles, ECS task roles, Lambda, etc. -claws -e - -# Read-only mode (disables destructive actions) -claws --read-only -# or -CLAWS_READ_ONLY=1 claws - -# Enable debug logging to file -claws -l debug.log - # Start directly on a service claws -s ec2 # EC2 instances claws -s rds/snapshots # RDS snapshots -claws -s cfn # CloudFormation (alias) -# Open detail view for specific resource -claws -s ec2 -i i-1234567890abcdef0 +# Read-only mode (disables destructive actions) +claws --read-only ``` ## Key Bindings @@ -146,339 +81,34 @@ claws -s ec2 -i i-1234567890abcdef0 | Key | Action | |-----|--------| | `j` / `k` | Navigate up/down | -| `h` / `l` | Navigate within category (service list) | | `Enter` / `d` | View resource details | | `:` | Command mode (e.g., `:ec2/instances`) | -| `:` + `Enter` | Go to dashboard (home) | -| `~` | Go to dashboard (from service browser) | -| `:services` | Go to service browser | -| `:sort ` | Sort by column (ascending) | -| `:sort desc ` | Sort by column (descending) | -| `:tag ` | Filter by tag (e.g., `:tag Env=prod`) | -| `:tags` | Browse all tagged resources | | `/` | Filter mode (fuzzy search) | -| `Tab` | Next resource type | -| `1-9` | Switch to resource type by number | | `a` | Open actions menu | -| `m` | Mark resource for comparison | -| `d` | Describe (or diff if marked) | -| `c` | Clear filter and mark | -| `N` | Load next page (pagination) | -| `M` | Toggle inline metrics (EC2, RDS, Lambda) | -| `y` | Copy resource ID to clipboard | -| `Y` | Copy resource ARN to clipboard | -| `Ctrl+r` | Refresh (including metrics) | -| `R` | Select AWS region(s) (multi-select supported) | -| `P` | Select AWS profile(s) (multi-select supported) | +| `R` | Select region(s) | +| `P` | Select profile(s) | | `?` | Show help | -| `Esc` | Go back | -| `q` / `Ctrl+c` | Quit | - -### Mouse Support +| `q` | Quit | -| Action | Effect | -|--------|--------| -| Hover | Highlight item under cursor | -| Click | Select item / navigate | -| Scroll wheel | Scroll through lists | -| Click on tabs | Switch resource type | -| Back button | Navigate back (same as Esc) | +See [docs/keybindings.md](docs/keybindings.md) for complete reference. -### Navigation Shortcuts (Context-dependent) +## Documentation -| Key | Action | -|-----|--------| -| `v` | View VPC / Versions | -| `s` | View Subnets / Streams / Stages | -| `g` | View Security Groups | -| `r` | View Route Tables / Roles / Resources | -| `e` | View Events / Executions / Endpoints | -| `l` | View CloudWatch Logs | -| `o` | View Outputs / Operations | -| `i` | View Images / Indexes | - -### Region Selector (`R` key) - -| Key | Action | -|-----|--------| -| `j` / `k` | Navigate up/down | -| `Space` | Toggle region selection | -| `a` | Select all regions | -| `n` | Deselect all regions | -| `/` | Filter regions | -| `Enter` | Apply selection | -| `Esc` | Cancel | - -Selected regions are queried in parallel; resources display with Region column. - -### Profile Selector (`P` key) - -| Key | Action | -|-----|--------| -| `j` / `k` | Navigate up/down | -| `Space` | Toggle profile selection | -| `l` | SSO login for selected profile | -| `L` | Console login for selected profile (`:login`) | -| `/` | Filter profiles | -| `Enter` | Apply selection | -| `Esc` | Cancel | - -Selected profiles are queried in parallel; resources display with Profile and Account columns. - -### Commands - -| Command | Action | -|---------|--------| -| `:q` / `:quit` | Quit | -| `:login [name]` | AWS console login (default: `claws-login` profile) | -| `:ec2/instances` | Navigate to EC2 instances | -| `:sort ` | Sort by column | -| `:tag ` | Filter by tag | -| `:diff ` | Compare current row with named resource | -| `:diff ` | Compare two named resources | -| `:theme ` | Change color theme (saved if persistence enabled) | -| `:autosave on/off` | Enable/disable config autosave (always saved) | - -**Login Details:** -- `:login` runs `aws login --remote` using `claws-login` profile -- `:login myprofile` uses the specified profile name instead -- For SSO profiles, use `P` to open profile selector, then `l` for SSO login - -## Supported Services (69 services, 163 resources) - -### Compute -| Service | Resources | -|---------|-----------| -| EC2 | Instances, Volumes, Security Groups, Elastic IPs, Key Pairs, AMIs, Snapshots, Launch Templates, Capacity Reservations | -| Lambda | Functions | -| ECS | Clusters, Services, Tasks | -| Auto Scaling | Groups, Activities | -| App Runner | Services, Operations | -| Batch | Job Queues, Compute Environments, Jobs, Job Definitions | -| EMR | Clusters, Steps | - -### Storage & Database -| Service | Resources | -|---------|-----------| -| S3 | Buckets | -| S3 Vectors | Buckets, Indexes | -| DynamoDB | Tables | -| RDS | Instances, Snapshots | -| Redshift | Clusters, Snapshots | -| ElastiCache | Clusters | -| OpenSearch | Domains | - -### Data & Analytics -| Service | Resources | -|---------|-----------| -| Glue | Databases, Tables, Crawlers, Jobs, Job Runs | -| Athena | Workgroups, Query Executions | -| Transcribe | Jobs | - -### Containers & ML -| Service | Resources | -|---------|-----------| -| ECR | Repositories, Images | -| Bedrock | Foundation Models, Guardrails, Inference Profiles | -| Bedrock Agent | Agents, Knowledge Bases, Data Sources, Prompts, Flows | -| Bedrock AgentCore | Runtimes, Endpoints, Versions | -| SageMaker | Endpoints, Notebooks, Training Jobs, Models | - -### Networking -| Service | Resources | -|---------|-----------| -| VPC | VPCs, Subnets, Route Tables, Internet Gateways, NAT Gateways, VPC Endpoints, Transit Gateways, TGW Attachments | -| Route 53 | Hosted Zones, Record Sets | -| API Gateway | REST APIs, HTTP APIs, Stages | -| AppSync | GraphQL APIs, Data Sources | -| ELB | Load Balancers, Target Groups, Targets | -| CloudFront | Distributions | -| Direct Connect | Connections, Virtual Interfaces | - -### Security & Identity -| Service | Resources | -|---------|-----------| -| IAM | Users, Roles, Policies, Groups, Instance Profiles | -| KMS | Keys | -| ACM | Certificates | -| Secrets Manager | Secrets | -| SSM | Parameters | -| Cognito | User Pools, Users | -| GuardDuty | Detectors, Findings | -| WAF | Web ACLs | -| Inspector | Findings | -| Security Hub | Findings | -| Firewall Manager | Policies | -| Network Firewall | Firewalls, Firewall Policies, Rule Groups | -| IAM Access Analyzer | Analyzers, Findings | -| Detective | Graphs, Investigations | -| Macie | Classification Jobs, Findings, Buckets | - -### Integration -| Service | Resources | -|---------|-----------| -| SQS | Queues | -| SNS | Topics, Subscriptions | -| EventBridge | Event Buses, Rules | -| Step Functions | State Machines, Executions | -| Kinesis | Streams | -| Transfer Family | Servers, Users | -| DataSync | Tasks, Locations, Task Executions | - -### Management & Monitoring -| Service | Resources | -|---------|-----------| -| CloudFormation | Stacks, Events, Resources, Outputs | -| CloudWatch | Alarms, Log Groups, Log Streams | -| CloudTrail | Trails, Events | -| AWS Config | Rules | -| AWS Health | Events | -| X-Ray | Groups | -| Service Quotas | Services, Quotas | -| CodeBuild | Projects, Builds | -| CodePipeline | Pipelines, Executions | -| AWS Backup | Plans, Vaults, Selections, Protected Resources, Backup Jobs, Copy Jobs, Restore Jobs, Recovery Points | -| Organizations | Accounts, OUs, Policies, Roots | -| License Manager | Configurations, Licenses, Grants | - -### Cost Management -| Service | Resources | -|---------|-----------| -| RI/SP | Reserved Instances, Savings Plans | -| Cost Explorer | Costs, Anomalies, Monitors | -| Compute Optimizer | Summary, Recommendations | -| Trusted Advisor | Recommendations | -| Budgets | Budgets, Notifications | - -## Service Aliases - -Quick shortcuts for common services: - -| Alias | Service | -|-------|---------| -| `cfn`, `cf` | CloudFormation | -| `sg` | EC2 Security Groups | -| `asg` | Auto Scaling | -| `cw` | CloudWatch | -| `logs` | CloudWatch Log Groups | -| `ddb` | DynamoDB | -| `sm` | Secrets Manager | -| `r53` | Route 53 | -| `eb` | EventBridge | -| `sfn` | Step Functions | -| `sq`, `quotas` | Service Quotas | -| `apigw`, `api` | API Gateway | -| `elb`, `alb`, `nlb` | Elastic Load Balancing | -| `redis`, `cache` | ElastiCache | -| `es`, `elasticsearch` | OpenSearch | -| `cdn`, `dist` | CloudFront | -| `gd` | GuardDuty | -| `build`, `cb` | CodeBuild | -| `pipeline`, `cp` | CodePipeline | -| `waf` | WAF | -| `ce`, `cost-explorer` | Cost Explorer | -| `co` | Compute Optimizer | -| `ta` | Trusted Advisor | -| `ri` | Reserved Instances | -| `sp` | Savings Plans | -| `odcr` | Capacity Reservations | -| `tgw` | Transit Gateways | -| `agentcore` | Bedrock AgentCore | -| `kb` | Bedrock Agent Knowledge Bases | -| `agent` | Bedrock Agent Agents | -| `models` | Bedrock Foundation Models | -| `guardrail` | Bedrock Guardrails | - -## Configuration - -claws uses your standard AWS configuration: - -- `~/.aws/credentials` - AWS credentials -- `~/.aws/config` - AWS configuration (region, profile) -- Environment variables: `AWS_PROFILE`, `AWS_REGION`, `AWS_ACCESS_KEY_ID`, etc. - -### Configuration File - -Optional settings can be stored in `~/.config/claws/config.yaml`: - -```yaml -timeouts: - aws_init: 10s # AWS initialization timeout (default: 5s) - multi_region_fetch: 60s # Multi-region parallel fetch timeout (default: 30s) - tag_search: 45s # Tag search timeout (default: 30s) - metrics_load: 30s # CloudWatch metrics load timeout (default: 30s) - log_fetch: 15s # CloudWatch Logs fetch timeout (default: 10s) - -concurrency: - max_fetches: 100 # Max concurrent API fetches (default: 50) - -cloudwatch: - window: 15m # Metrics data window period (default: 15m) - -autosave: - enabled: true # Save region/profile/theme on change (default: false) - -startup: # Applied on launch if present - profiles: # Multiple profiles supported - - production - regions: - - us-east-1 - - us-west-2 - -theme: nord # Preset: dark, light, nord, dracula, gruvbox, catppuccin - -# Or use preset with custom overrides: -# theme: -# preset: dracula -# primary: "#ff79c6" -# danger: "#ff5555" -``` - -**Available Theme Presets:** - -| Preset | Description | -|--------|-------------| -| `dark` | Default dark theme (pink/magenta accents) | -| `light` | For light-background terminals | -| `nord` | Nordic, calm blue palette | -| `dracula` | Popular dark theme (purple/pink) | -| `gruvbox` | Retro, warm earth tones | -| `catppuccin` | Modern pastel (Mocha variant) | - -The config file is **not created automatically**. Create it manually if needed. - -CLI flags (`-p`, `-r`, `-t`, `--autosave`, `--no-autosave`) override config file settings. - -For required IAM permissions, see [docs/iam-permissions.md](docs/iam-permissions.md). - -## Architecture - -claws uses a simple architecture with custom implementations for each service: - -``` -claws/ -├── cmd/claws/ # Entry point -├── internal/ -│ ├── app/ # Main TUI application -│ ├── aws/ # AWS client management + helpers -│ ├── action/ # Action framework -│ ├── dao/ # Data Access Object interface -│ ├── log/ # Structured logging (slog-based) -│ ├── registry/ # Service registry + aliases -│ ├── render/ # Renderer interface -│ ├── ui/ # Theme system -│ └── view/ # View components -└── custom/ # Service implementations (DAO + Renderer + Actions) -``` - -See [docs/architecture.md](docs/architecture.md) for details. +| Document | Description | +|----------|-------------| +| [Key Bindings](docs/keybindings.md) | Complete keyboard shortcuts reference | +| [Supported Services](docs/services.md) | All 69 services and 163 resources | +| [Configuration](docs/configuration.md) | Config file, themes, and options | +| [IAM Permissions](docs/iam-permissions.md) | Required AWS permissions | +| [Architecture](docs/architecture.md) | Internal design and structure | +| [Adding Resources](docs/adding-resources.md) | Guide for contributors | ## Development ### Prerequisites - Go 1.25+ -- [Task](https://taskfile.dev/) (optional, for task runner) +- [Task](https://taskfile.dev/) (optional) ### Commands @@ -486,34 +116,13 @@ See [docs/architecture.md](docs/architecture.md) for details. task build # Build binary task run # Run the application task test # Run tests -task test-cover # Run tests with coverage task lint # Run linters -task fmt # Format code -task clean # Clean build artifacts ``` -### Adding New Resources - -See [docs/adding-resources.md](docs/adding-resources.md) for a guide on adding new AWS resources. - -### Releasing - -Releases are automated via GoReleaser. Tag format controls which platforms are built: - -| Tag | Platforms Built | -|-----|-----------------| -| `v0.1.0` | All (linux/darwin arm64+amd64, windows) | -| `v0.1.0-rc1` | ARM64 only (linux/darwin) | -| `v0.1.0-rc1-amd64` | ARM64 + AMD64 (linux/darwin) | -| `v0.1.0-rc1-win` | ARM64 + Windows | -| `v0.1.0-rc1-all` | All platforms | - -Prereleases (tags containing `-`) skip Homebrew publishing. - ## Tech Stack -- **TUI Framework**: [Bubbletea](https://github.com/charmbracelet/bubbletea) + [Lipgloss](https://github.com/charmbracelet/lipgloss) + [Bubbles](https://github.com/charmbracelet/bubbles) -- **AWS SDK**: [AWS SDK for Go v2](https://github.com/aws/aws-sdk-go-v2) +- **TUI**: [Bubbletea](https://github.com/charmbracelet/bubbletea) + [Lipgloss](https://github.com/charmbracelet/lipgloss) +- **AWS**: [AWS SDK for Go v2](https://github.com/aws/aws-sdk-go-v2) ## License diff --git a/Taskfile.yml b/Taskfile.yml index 8cac713a..c31b5055 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -47,7 +47,7 @@ tasks: - | echo "Waiting for LocalStack to be ready..." for i in $(seq 1 30); do - if curl -s --connect-timeout 2 --max-time 5 http://localhost:4566/_localstack/health 2>/dev/null | grep -q '"s3": "running"'; then + if curl -s --connect-timeout 2 --max-time 5 http://localhost:4566/_localstack/health 2>/dev/null | grep -qE '"s3": "(available|running)"'; then echo "LocalStack started at http://localhost:4566" exit 0 fi @@ -92,7 +92,48 @@ tasks: - ./claws demo:record: - desc: Record demo.gif using VHS + LocalStack (Linux only - --network host required) + desc: Record all demos (gif + screenshots) using VHS + LocalStack + deps: [build, localstack:start, localstack:demo-setup] + preconditions: + - sh: '[ "$(uname -s)" = "Linux" ]' + msg: "demo:record requires Linux (--network host not supported on macOS/Windows)" + cmds: + - task: demo:record:gif + - task: demo:record:themes + - task: demo:record:features + + demo:record:gif: + desc: Record demo.gif only + deps: [build, localstack:start, localstack:demo-setup] + preconditions: + - sh: '[ "$(uname -s)" = "Linux" ]' + msg: "demo:record requires Linux (--network host not supported on macOS/Windows)" + cmds: + - | + docker run --rm --network host \ + -v "$(pwd)":/vhs \ + -v "$(pwd)/scripts/demo-aws-config:/root/.aws:ro" \ + -e AWS_ENDPOINT_URL=http://localhost:4566 \ + -e AWS_EC2_METADATA_DISABLED=true \ + ghcr.io/charmbracelet/vhs docs/tapes/demo.tape + + demo:record:themes: + desc: Record theme screenshots only + deps: [build, localstack:start, localstack:demo-setup] + preconditions: + - sh: '[ "$(uname -s)" = "Linux" ]' + msg: "demo:record requires Linux (--network host not supported on macOS/Windows)" + cmds: + - | + docker run --rm --network host \ + -v "$(pwd)":/vhs \ + -v "$(pwd)/scripts/demo-aws-config:/root/.aws:ro" \ + -e AWS_ENDPOINT_URL=http://localhost:4566 \ + -e AWS_EC2_METADATA_DISABLED=true \ + ghcr.io/charmbracelet/vhs docs/tapes/themes.tape + + demo:record:features: + desc: Record feature screenshots only deps: [build, localstack:start, localstack:demo-setup] preconditions: - sh: '[ "$(uname -s)" = "Linux" ]' @@ -101,12 +142,10 @@ tasks: - | docker run --rm --network host \ -v "$(pwd)":/vhs \ + -v "$(pwd)/scripts/demo-aws-config:/root/.aws:ro" \ -e AWS_ENDPOINT_URL=http://localhost:4566 \ - -e AWS_ACCESS_KEY_ID=test \ - -e AWS_SECRET_ACCESS_KEY=test \ - -e AWS_DEFAULT_REGION=us-east-1 \ -e AWS_EC2_METADATA_DISABLED=true \ - ghcr.io/charmbracelet/vhs:v0.10.0 cassette.tape + ghcr.io/charmbracelet/vhs docs/tapes/features.tape test-localstack: desc: Run integration tests with LocalStack diff --git a/demo.gif b/demo.gif deleted file mode 100644 index 45113d13..00000000 Binary files a/demo.gif and /dev/null differ diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..0951f916 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,121 @@ +# Configuration + +## AWS Credentials + +claws uses your standard AWS configuration: + +- `~/.aws/credentials` - AWS credentials +- `~/.aws/config` - AWS configuration (region, profile) +- Environment variables: `AWS_PROFILE`, `AWS_REGION`, `AWS_ACCESS_KEY_ID`, etc. + +## Configuration File + +Optional settings can be stored in `~/.config/claws/config.yaml`: + +```yaml +timeouts: + aws_init: 10s # AWS initialization timeout (default: 5s) + multi_region_fetch: 60s # Multi-region parallel fetch timeout (default: 30s) + tag_search: 45s # Tag search timeout (default: 30s) + metrics_load: 30s # CloudWatch metrics load timeout (default: 30s) + log_fetch: 15s # CloudWatch Logs fetch timeout (default: 10s) + +concurrency: + max_fetches: 100 # Max concurrent API fetches (default: 50) + +cloudwatch: + window: 15m # Metrics data window period (default: 15m) + +autosave: + enabled: true # Save region/profile/theme on change (default: false) + +startup: # Applied on launch if present + profiles: # Multiple profiles supported + - production + regions: + - us-east-1 + - us-west-2 + +theme: nord # Preset: dark, light, nord, dracula, gruvbox, catppuccin + +# Or use preset with custom overrides: +# theme: +# preset: dracula +# primary: "#ff79c6" +# danger: "#ff5555" +``` + +The config file is **not created automatically**. Create it manually if needed. + +CLI flags (`-p`, `-r`, `-t`, `--autosave`, `--no-autosave`) override config file settings. + +## Themes + +claws includes 6 built-in color themes: + +| Theme | Description | +|-------|-------------| +| `dark` | Default dark theme (pink/magenta accents) | +| `light` | For light-background terminals | +| `nord` | Nordic, calm blue palette | +| `dracula` | Popular dark theme (purple/pink) | +| `gruvbox` | Retro, warm earth tones | +| `catppuccin` | Modern pastel (Mocha variant) | + +### Theme Previews + +| dark | light | nord | +|------|-------|------| +| ![dark](images/theme-dark.png) | ![light](images/theme-light.png) | ![nord](images/theme-nord.png) | + +| dracula | gruvbox | catppuccin | +|---------|---------|------------| +| ![dracula](images/theme-dracula.png) | ![gruvbox](images/theme-gruvbox.png) | ![catppuccin](images/theme-catppuccin.png) | + +### Switching Themes + +```bash +# Via command line +claws -t nord + +# Via command mode (runtime) +:theme dracula +``` + +If autosave is enabled, theme changes are persisted to the config file. + +### Custom Theme Colors + +Override specific colors from a preset: + +```yaml +theme: + preset: dracula + primary: "#ff79c6" + danger: "#ff5555" + success: "#50fa7b" +``` + +## Read-Only Mode + +Disable all destructive actions: + +```bash +# Via flag +claws --read-only + +# Via environment variable +CLAWS_READ_ONLY=1 claws +``` + +## Debug Logging + +Enable debug logging to a file: + +```bash +claws -l debug.log +``` + +## IAM Permissions + +For required IAM permissions, see [iam-permissions.md](iam-permissions.md). diff --git a/docs/images/actions-menu.png b/docs/images/actions-menu.png new file mode 100644 index 00000000..36ebf96d Binary files /dev/null and b/docs/images/actions-menu.png differ diff --git a/docs/images/demo.gif b/docs/images/demo.gif new file mode 100644 index 00000000..37987f59 Binary files /dev/null and b/docs/images/demo.gif differ diff --git a/docs/images/detail-view.png b/docs/images/detail-view.png new file mode 100644 index 00000000..dc12095b Binary files /dev/null and b/docs/images/detail-view.png differ diff --git a/docs/images/multi-account-region.png b/docs/images/multi-account-region.png new file mode 100644 index 00000000..a7ef7b8c Binary files /dev/null and b/docs/images/multi-account-region.png differ diff --git a/docs/images/multi-profile.png b/docs/images/multi-profile.png new file mode 100644 index 00000000..99b1cc36 Binary files /dev/null and b/docs/images/multi-profile.png differ diff --git a/docs/images/multi-region-data.png b/docs/images/multi-region-data.png new file mode 100644 index 00000000..2adc098c Binary files /dev/null and b/docs/images/multi-region-data.png differ diff --git a/docs/images/multi-region.png b/docs/images/multi-region.png new file mode 100644 index 00000000..2021fa6d Binary files /dev/null and b/docs/images/multi-region.png differ diff --git a/docs/images/resource-browser.png b/docs/images/resource-browser.png new file mode 100644 index 00000000..bf4a4a47 Binary files /dev/null and b/docs/images/resource-browser.png differ diff --git a/docs/images/theme-catppuccin.png b/docs/images/theme-catppuccin.png new file mode 100644 index 00000000..45aaa9d0 Binary files /dev/null and b/docs/images/theme-catppuccin.png differ diff --git a/docs/images/theme-dark.png b/docs/images/theme-dark.png new file mode 100644 index 00000000..f5c431ac Binary files /dev/null and b/docs/images/theme-dark.png differ diff --git a/docs/images/theme-dracula.png b/docs/images/theme-dracula.png new file mode 100644 index 00000000..06e93721 Binary files /dev/null and b/docs/images/theme-dracula.png differ diff --git a/docs/images/theme-gruvbox.png b/docs/images/theme-gruvbox.png new file mode 100644 index 00000000..46deae7e Binary files /dev/null and b/docs/images/theme-gruvbox.png differ diff --git a/docs/images/theme-light.png b/docs/images/theme-light.png new file mode 100644 index 00000000..b4c61858 Binary files /dev/null and b/docs/images/theme-light.png differ diff --git a/docs/images/theme-nord.png b/docs/images/theme-nord.png new file mode 100644 index 00000000..86343c39 Binary files /dev/null and b/docs/images/theme-nord.png differ diff --git a/docs/keybindings.md b/docs/keybindings.md new file mode 100644 index 00000000..a4566768 --- /dev/null +++ b/docs/keybindings.md @@ -0,0 +1,116 @@ +# Key Bindings + +Complete reference for all keyboard shortcuts in claws. + +## General Navigation + +| Key | Action | +|-----|--------| +| `j` / `k` | Navigate up/down | +| `h` / `l` | Navigate within category (service list) | +| `Enter` / `d` | View resource details | +| `Esc` | Go back | +| `q` / `Ctrl+c` | Quit | + +## Views & Modes + +| Key | Action | +|-----|--------| +| `:` | Command mode (e.g., `:ec2/instances`) | +| `:` + `Enter` | Go to dashboard (home) | +| `~` | Go to dashboard (from service browser) | +| `:services` | Go to service browser | +| `/` | Filter mode (fuzzy search) | +| `?` | Show help | + +## Resource Browser + +| Key | Action | +|-----|--------| +| `Tab` | Next resource type | +| `1-9` | Switch to resource type by number | +| `a` | Open actions menu | +| `m` | Mark resource for comparison | +| `d` | Describe (or diff if marked) | +| `c` | Clear filter and mark | +| `N` | Load next page (pagination) | +| `M` | Toggle inline metrics (EC2, RDS, Lambda) | +| `y` | Copy resource ID to clipboard | +| `Y` | Copy resource ARN to clipboard | +| `Ctrl+r` | Refresh (including metrics) | + +## Profile & Region + +| Key | Action | +|-----|--------| +| `R` | Select AWS region(s) (multi-select supported) | +| `P` | Select AWS profile(s) (multi-select supported) | + +## Commands + +| Command | Action | +|---------|--------| +| `:q` / `:quit` | Quit | +| `:login [name]` | AWS console login (default: `claws-login` profile) | +| `:ec2/instances` | Navigate to EC2 instances | +| `:sort ` | Sort by column (ascending) | +| `:sort desc ` | Sort by column (descending) | +| `:tag ` | Filter by tag (e.g., `:tag Env=prod`) | +| `:tags` | Browse all tagged resources | +| `:diff ` | Compare current row with named resource | +| `:diff ` | Compare two named resources | +| `:theme ` | Change color theme | +| `:autosave on/off` | Enable/disable config autosave | + +## Mouse Support + +| Action | Effect | +|--------|--------| +| Hover | Highlight item under cursor | +| Click | Select item / navigate | +| Scroll wheel | Scroll through lists | +| Click on tabs | Switch resource type | +| Back button | Navigate back (same as Esc) | + +## Navigation Shortcuts (Context-dependent) + +These shortcuts navigate to related resources based on the current context: + +| Key | Action | +|-----|--------| +| `v` | View VPC / Versions | +| `s` | View Subnets / Streams / Stages | +| `g` | View Security Groups | +| `r` | View Route Tables / Roles / Resources | +| `e` | View Events / Executions / Endpoints | +| `l` | View CloudWatch Logs | +| `o` | View Outputs / Operations | +| `i` | View Images / Indexes | + +## Region Selector (`R` key) + +| Key | Action | +|-----|--------| +| `j` / `k` | Navigate up/down | +| `Space` | Toggle region selection | +| `a` | Select all regions | +| `n` | Deselect all regions | +| `/` | Filter regions | +| `Enter` | Apply selection | +| `Esc` | Cancel | + +Selected regions are queried in parallel; resources display with Region column. + +## Profile Selector (`P` key) + +| Key | Action | +|-----|--------| +| `j` / `k` | Navigate up/down | +| `Space` | Toggle profile selection | +| `l` | SSO login for selected profile | +| `L` | Console login for selected profile (`:login`) | +| `/` | Filter profiles | +| `Enter` | Apply selection | +| `Esc` | Cancel | + +Selected profiles are queried in parallel; resources display with Profile and Account columns. diff --git a/docs/services.md b/docs/services.md new file mode 100644 index 00000000..c37a3552 --- /dev/null +++ b/docs/services.md @@ -0,0 +1,157 @@ +# Supported Services + +claws supports **69 services** with **163 resources**. + +## Compute + +| Service | Resources | +|---------|-----------| +| EC2 | Instances, Volumes, Security Groups, Elastic IPs, Key Pairs, AMIs, Snapshots, Launch Templates, Capacity Reservations | +| Lambda | Functions | +| ECS | Clusters, Services, Tasks | +| Auto Scaling | Groups, Activities | +| App Runner | Services, Operations | +| Batch | Job Queues, Compute Environments, Jobs, Job Definitions | +| EMR | Clusters, Steps | + +## Storage & Database + +| Service | Resources | +|---------|-----------| +| S3 | Buckets | +| S3 Vectors | Buckets, Indexes | +| DynamoDB | Tables | +| RDS | Instances, Snapshots | +| Redshift | Clusters, Snapshots | +| ElastiCache | Clusters | +| OpenSearch | Domains | + +## Data & Analytics + +| Service | Resources | +|---------|-----------| +| Glue | Databases, Tables, Crawlers, Jobs, Job Runs | +| Athena | Workgroups, Query Executions | +| Transcribe | Jobs | + +## Containers & ML + +| Service | Resources | +|---------|-----------| +| ECR | Repositories, Images | +| Bedrock | Foundation Models, Guardrails, Inference Profiles | +| Bedrock Agent | Agents, Knowledge Bases, Data Sources, Prompts, Flows | +| Bedrock AgentCore | Runtimes, Endpoints, Versions | +| SageMaker | Endpoints, Notebooks, Training Jobs, Models | + +## Networking + +| Service | Resources | +|---------|-----------| +| VPC | VPCs, Subnets, Route Tables, Internet Gateways, NAT Gateways, VPC Endpoints, Transit Gateways, TGW Attachments | +| Route 53 | Hosted Zones, Record Sets | +| API Gateway | REST APIs, HTTP APIs, Stages | +| AppSync | GraphQL APIs, Data Sources | +| ELB | Load Balancers, Target Groups, Targets | +| CloudFront | Distributions | +| Direct Connect | Connections, Virtual Interfaces | + +## Security & Identity + +| Service | Resources | +|---------|-----------| +| IAM | Users, Roles, Policies, Groups, Instance Profiles | +| KMS | Keys | +| ACM | Certificates | +| Secrets Manager | Secrets | +| SSM | Parameters | +| Cognito | User Pools, Users | +| GuardDuty | Detectors, Findings | +| WAF | Web ACLs | +| Inspector | Findings | +| Security Hub | Findings | +| Firewall Manager | Policies | +| Network Firewall | Firewalls, Firewall Policies, Rule Groups | +| IAM Access Analyzer | Analyzers, Findings | +| Detective | Graphs, Investigations | +| Macie | Classification Jobs, Findings, Buckets | + +## Integration + +| Service | Resources | +|---------|-----------| +| SQS | Queues | +| SNS | Topics, Subscriptions | +| EventBridge | Event Buses, Rules | +| Step Functions | State Machines, Executions | +| Kinesis | Streams | +| Transfer Family | Servers, Users | +| DataSync | Tasks, Locations, Task Executions | + +## Management & Monitoring + +| Service | Resources | +|---------|-----------| +| CloudFormation | Stacks, Events, Resources, Outputs | +| CloudWatch | Alarms, Log Groups, Log Streams | +| CloudTrail | Trails, Events | +| AWS Config | Rules | +| AWS Health | Events | +| X-Ray | Groups | +| Service Quotas | Services, Quotas | +| CodeBuild | Projects, Builds | +| CodePipeline | Pipelines, Executions | +| AWS Backup | Plans, Vaults, Selections, Protected Resources, Backup Jobs, Copy Jobs, Restore Jobs, Recovery Points | +| Organizations | Accounts, OUs, Policies, Roots | +| License Manager | Configurations, Licenses, Grants | + +## Cost Management + +| Service | Resources | +|---------|-----------| +| RI/SP | Reserved Instances, Savings Plans | +| Cost Explorer | Costs, Anomalies, Monitors | +| Compute Optimizer | Summary, Recommendations | +| Trusted Advisor | Recommendations | +| Budgets | Budgets, Notifications | + +--- + +## Service Aliases + +Quick shortcuts for common services: + +| Alias | Service | +|-------|---------| +| `cfn`, `cf` | CloudFormation | +| `sg` | EC2 Security Groups | +| `asg` | Auto Scaling | +| `cw` | CloudWatch | +| `logs` | CloudWatch Log Groups | +| `ddb` | DynamoDB | +| `sm` | Secrets Manager | +| `r53` | Route 53 | +| `eb` | EventBridge | +| `sfn` | Step Functions | +| `sq`, `quotas` | Service Quotas | +| `apigw`, `api` | API Gateway | +| `elb`, `alb`, `nlb` | Elastic Load Balancing | +| `redis`, `cache` | ElastiCache | +| `es`, `elasticsearch` | OpenSearch | +| `cdn`, `dist` | CloudFront | +| `gd` | GuardDuty | +| `build`, `cb` | CodeBuild | +| `pipeline`, `cp` | CodePipeline | +| `waf` | WAF | +| `ce`, `cost-explorer` | Cost Explorer | +| `co` | Compute Optimizer | +| `ta` | Trusted Advisor | +| `ri` | Reserved Instances | +| `sp` | Savings Plans | +| `odcr` | Capacity Reservations | +| `tgw` | Transit Gateways | +| `agentcore` | Bedrock AgentCore | +| `kb` | Bedrock Agent Knowledge Bases | +| `agent` | Bedrock Agent Agents | +| `models` | Bedrock Foundation Models | +| `guardrail` | Bedrock Guardrails | diff --git a/docs/tapes/README.md b/docs/tapes/README.md new file mode 100644 index 00000000..d569e9f3 --- /dev/null +++ b/docs/tapes/README.md @@ -0,0 +1,52 @@ +# VHS Tape Files + +This directory contains [VHS](https://github.com/charmbracelet/vhs) tape files for generating demo GIFs and screenshots. + +## Tape Files + +| File | Purpose | Output | +|------|---------|--------| +| `demo.tape` | Main demo GIF | `docs/images/demo.gif` | +| `themes.tape` | Theme screenshots | `docs/images/theme-*.png` | +| `features.tape` | Feature screenshots | `docs/images/*.png` | + +## Usage (Recommended) + +Use task commands from project root (requires Docker + Linux): + +```bash +# Record everything (GIF + all screenshots) +task demo:record + +# Record individual items +task demo:record:gif # Main demo GIF only +task demo:record:themes # Theme screenshots only +task demo:record:features # Feature screenshots only +``` + +This automatically: +- Builds the `claws` binary +- Starts LocalStack with demo data +- Runs VHS in Docker with proper environment + +## Manual Usage + +If you have VHS installed locally: + +```bash +# Start LocalStack with demo data first +task localstack:demo-setup +task build + +# Then run VHS from project root +AWS_ENDPOINT_URL=http://localhost:4566 \ +AWS_ACCESS_KEY_ID=test \ +AWS_SECRET_ACCESS_KEY=test \ +vhs docs/tapes/demo.tape +``` + +## Notes + +- `task demo:record` requires Linux (`--network host` for LocalStack access) +- Tapes use LocalStack for demo data (no real AWS credentials needed) +- Adjust `Sleep` durations if rendering is slow diff --git a/cassette.tape b/docs/tapes/demo.tape similarity index 78% rename from cassette.tape rename to docs/tapes/demo.tape index 25be2796..c8cf5ebd 100644 --- a/cassette.tape +++ b/docs/tapes/demo.tape @@ -1,6 +1,9 @@ -Output demo.gif +# Demo recording for claws - run via: task demo:record:gif +# Requires LocalStack running with demo data -Set FontSize 20 +Output docs/images/demo.gif + +Set FontSize 16 Set Width 1920 Set Height 1080 Set TypingSpeed 0.08 @@ -22,7 +25,7 @@ Sleep 1.5s Enter Sleep 2s -Type "/demo" +Type "/public" Sleep 1s Enter Sleep 2s diff --git a/docs/tapes/features.tape b/docs/tapes/features.tape new file mode 100644 index 00000000..cecc590b --- /dev/null +++ b/docs/tapes/features.tape @@ -0,0 +1,70 @@ +# Generate feature screenshots - run via: task demo:record:features +# Requires LocalStack running with demo data + +Set FontSize 16 +Set Width 1920 +Set Height 1080 +Set TypingSpeed 0.05 + +Type "./claws" +Enter +Sleep 2s + +Type ":" +Sleep 0.5s +Type "ec2/instances" +Enter +Sleep 2s +Screenshot docs/images/resource-browser.png + +Type "d" +Sleep 2s +Screenshot docs/images/detail-view.png +Escape +Sleep 1s + +Type "a" +Sleep 1.5s +Screenshot docs/images/actions-menu.png +Escape +Sleep 1s + +Type "R" +Sleep 1s +Screenshot docs/images/multi-region.png +Type "/ap-northeast-1" +Sleep 1s +Enter +Sleep 0.5s +Type " " +Sleep 0.5s +Enter +Sleep 3s +Screenshot docs/images/multi-region-data.png + +Type "P" +Sleep 1s +Screenshot docs/images/multi-profile.png +Type "/dev" +Sleep 1s +Enter +Sleep 0.5s +Type " " +Sleep 0.5s +Enter +Sleep 1s + +Type "R" +Sleep 0.5s +Type "/us-west-2" +Sleep 1s +Enter +Sleep 0.5s +Type " " +Sleep 0.5s +Enter +Sleep 3s +Screenshot docs/images/multi-account-region.png + +Type "q" +Sleep 0.5s diff --git a/docs/tapes/theme-light.tape b/docs/tapes/theme-light.tape new file mode 100644 index 00000000..1449aed6 --- /dev/null +++ b/docs/tapes/theme-light.tape @@ -0,0 +1,20 @@ +Set Theme { "background": "#ffffff", "foreground": "#333333", "black": "#000000", "white": "#ffffff" } +Set FontSize 16 +Set Width 1920 +Set Height 1080 +Set TypingSpeed 0.05s + +Type "./claws -t light" +Enter +Sleep 2s + +Type ":" +Sleep 0.5s +Type "ec2/instances" +Enter +Sleep 2s + +Screenshot docs/images/theme-light.png + +Type "q" +Sleep 0.5s diff --git a/docs/tapes/themes.tape b/docs/tapes/themes.tape new file mode 100644 index 00000000..0bb9c135 --- /dev/null +++ b/docs/tapes/themes.tape @@ -0,0 +1,89 @@ +# Generate theme screenshots - run via: task demo:record:themes +# Requires LocalStack running with demo data + +Set FontSize 16 +Set Width 1920 +Set Height 1080 +Set TypingSpeed 0.05 + +# Theme: dark (default) +Type "./claws -t dark" +Enter +Sleep 2s +Type ":" +Sleep 0.5s +Type "ec2/instances" +Enter +Sleep 2s +Screenshot docs/images/theme-dark.png +Type "q" +Sleep 0.5s + +# Theme: light (white background) +Set Theme { "background": "#ffffff", "foreground": "#333333", "black": "#000000", "white": "#ffffff" } +Type "./claws -t light" +Enter +Sleep 2s +Type ":" +Sleep 0.5s +Type "ec2/instances" +Enter +Sleep 2s +Screenshot docs/images/theme-light.png +Type "q" +Sleep 0.5s + +# Reset to dark background for remaining themes +Set Theme "Builtin Dark" + +# Theme: nord +Type "./claws -t nord" +Enter +Sleep 2s +Type ":" +Sleep 0.5s +Type "ec2/instances" +Enter +Sleep 2s +Screenshot docs/images/theme-nord.png +Type "q" +Sleep 0.5s + +# Theme: dracula +Type "./claws -t dracula" +Enter +Sleep 2s +Type ":" +Sleep 0.5s +Type "ec2/instances" +Enter +Sleep 2s +Screenshot docs/images/theme-dracula.png +Type "q" +Sleep 0.5s + +# Theme: gruvbox +Type "./claws -t gruvbox" +Enter +Sleep 2s +Type ":" +Sleep 0.5s +Type "ec2/instances" +Enter +Sleep 2s +Screenshot docs/images/theme-gruvbox.png +Type "q" +Sleep 0.5s + +# Theme: catppuccin +Type "./claws -t catppuccin" +Enter +Sleep 2s +Type ":" +Sleep 0.5s +Type "ec2/instances" +Enter +Sleep 2s +Screenshot docs/images/theme-catppuccin.png +Type "q" +Sleep 0.5s diff --git a/scripts/demo-aws-config/config b/scripts/demo-aws-config/config new file mode 100644 index 00000000..046a399a --- /dev/null +++ b/scripts/demo-aws-config/config @@ -0,0 +1,11 @@ +[default] +region = us-east-1 +endpoint_url = http://localhost:4566 + +[profile prod] +region = us-east-1 +endpoint_url = http://localhost:4566 + +[profile dev] +region = us-west-2 +endpoint_url = http://localhost:4566 diff --git a/scripts/demo-aws-config/credentials b/scripts/demo-aws-config/credentials new file mode 100644 index 00000000..8637b6f3 --- /dev/null +++ b/scripts/demo-aws-config/credentials @@ -0,0 +1,11 @@ +[default] +aws_access_key_id = 111111111111 +aws_secret_access_key = test + +[prod] +aws_access_key_id = 111111111111 +aws_secret_access_key = test + +[dev] +aws_access_key_id = 222222222222 +aws_secret_access_key = test diff --git a/scripts/localstack-demo-cleanup.sh b/scripts/localstack-demo-cleanup.sh index 5f7cc6d1..9583cad4 100755 --- a/scripts/localstack-demo-cleanup.sh +++ b/scripts/localstack-demo-cleanup.sh @@ -20,129 +20,98 @@ if [[ "${AWS_ENDPOINT_URL:-}" != "http://localhost:4566" ]]; then error "AWS_ENDPOINT_URL must be http://localhost:4566 (got: ${AWS_ENDPOINT_URL:-})" fi -export AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-test}" export AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-test}" -export AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION:-us-east-1}" export AWS_EC2_METADATA_DISABLED=true +ACCOUNTS=("111111111111" "222222222222") +REGIONS=("us-east-1" "us-west-2" "ap-northeast-1") + aws_cmd() { aws --endpoint-url="${AWS_ENDPOINT_URL}" "$@" } -log "=== claws LocalStack Demo Cleanup ===" - -log "Terminating EC2 instances..." -INSTANCES=$(aws_cmd ec2 describe-instances \ - --filters "Name=tag:Project,Values=claws-demo" "Name=instance-state-name,Values=pending,running,stopping,stopped" \ - --query 'Reservations[].Instances[].InstanceId' --output text 2>/dev/null || echo "") -if [[ -n "$INSTANCES" ]]; then - for id in $INSTANCES; do - if aws_cmd ec2 terminate-instances --instance-ids "$id" 2>/dev/null; then - log " Terminating: $id" - else - track_error "Failed to terminate: $id" - fi +cleanup_account_region() { + local account="$1" + local region="$2" + export AWS_ACCESS_KEY_ID="$account" + export AWS_DEFAULT_REGION="$region" + + log "Cleaning $account / $region..." + + local instances=$(aws_cmd ec2 describe-instances \ + --filters "Name=tag:Project,Values=claws-demo" "Name=instance-state-name,Values=pending,running,stopping,stopped" \ + --query 'Reservations[].Instances[].InstanceId' --output text 2>/dev/null || echo "") + if [[ -n "$instances" ]]; then + for id in $instances; do + aws_cmd ec2 terminate-instances --instance-ids "$id" 2>/dev/null && log " Terminated: $id" || track_error "Failed: $id" + done + sleep 2 + fi + + local sgs=$(aws_cmd ec2 describe-security-groups \ + --filters "Name=tag:Project,Values=claws-demo" \ + --query 'SecurityGroups[].GroupId' --output text 2>/dev/null || echo "") + for sg in $sgs; do + aws_cmd ec2 delete-security-group --group-id "$sg" 2>/dev/null && log " Deleted SG: $sg" || track_error "Failed SG: $sg" done - log " Waiting for instances to terminate..." - for i in $(seq 1 30); do - # shellcheck disable=SC2086 # Word splitting intended for multiple IDs - REMAINING=$(aws_cmd ec2 describe-instances \ - --instance-ids $INSTANCES \ - --filters "Name=instance-state-name,Values=pending,running,shutting-down,stopping,stopped" \ - --query 'Reservations[].Instances[].InstanceId' --output text 2>/dev/null || echo "") - if [[ -z "$REMAINING" ]]; then - log " All instances terminated" - break - fi - if [[ $i -eq 30 ]]; then - track_error "Timeout waiting for instances to terminate" + + local subnets=$(aws_cmd ec2 describe-subnets \ + --filters "Name=tag:Project,Values=claws-demo" \ + --query 'Subnets[].SubnetId' --output text 2>/dev/null || echo "") + for subnet in $subnets; do + aws_cmd ec2 delete-subnet --subnet-id "$subnet" 2>/dev/null && log " Deleted subnet: $subnet" || track_error "Failed subnet: $subnet" + done + + local rts=$(aws_cmd ec2 describe-route-tables \ + --filters "Name=tag:Project,Values=claws-demo" \ + --query 'RouteTables[].RouteTableId' --output text 2>/dev/null || echo "") + for rt in $rts; do + local assocs=$(aws_cmd ec2 describe-route-tables --route-table-ids "$rt" \ + --query 'RouteTables[0].Associations[?!Main].RouteTableAssociationId' --output text 2>/dev/null || echo "") + for assoc in $assocs; do + aws_cmd ec2 disassociate-route-table --association-id "$assoc" 2>/dev/null || true + done + aws_cmd ec2 delete-route-table --route-table-id "$rt" 2>/dev/null && log " Deleted RT: $rt" || track_error "Failed RT: $rt" + done + + local igws=$(aws_cmd ec2 describe-internet-gateways \ + --filters "Name=tag:Project,Values=claws-demo" \ + --query 'InternetGateways[].InternetGatewayId' --output text 2>/dev/null || echo "") + for igw in $igws; do + local vpc=$(aws_cmd ec2 describe-internet-gateways --internet-gateway-ids "$igw" \ + --query 'InternetGateways[0].Attachments[0].VpcId' --output text 2>/dev/null || echo "") + if [[ -n "$vpc" && "$vpc" != "None" ]]; then + aws_cmd ec2 detach-internet-gateway --internet-gateway-id "$igw" --vpc-id "$vpc" 2>/dev/null || true fi - sleep 1 + aws_cmd ec2 delete-internet-gateway --internet-gateway-id "$igw" 2>/dev/null && log " Deleted IGW: $igw" || track_error "Failed IGW: $igw" done -fi - -log "Deleting Security Groups..." -SGS=$(aws_cmd ec2 describe-security-groups \ - --filters "Name=tag:Project,Values=claws-demo" \ - --query 'SecurityGroups[].GroupId' --output text 2>/dev/null || echo "") -for sg in $SGS; do - if aws_cmd ec2 delete-security-group --group-id "$sg" 2>/dev/null; then - log " Deleted: $sg" - else - track_error "Failed to delete SG: $sg" - fi -done + + local vpcs=$(aws_cmd ec2 describe-vpcs \ + --filters "Name=tag:Project,Values=claws-demo" \ + --query 'Vpcs[].VpcId' --output text 2>/dev/null || echo "") + for vpc in $vpcs; do + aws_cmd ec2 delete-vpc --vpc-id "$vpc" 2>/dev/null && log " Deleted VPC: $vpc" || track_error "Failed VPC: $vpc" + done +} -log "Deleting Subnets..." -SUBNETS=$(aws_cmd ec2 describe-subnets \ - --filters "Name=tag:Project,Values=claws-demo" \ - --query 'Subnets[].SubnetId' --output text 2>/dev/null || echo "") -for subnet in $SUBNETS; do - if aws_cmd ec2 delete-subnet --subnet-id "$subnet" 2>/dev/null; then - log " Deleted: $subnet" - else - track_error "Failed to delete subnet: $subnet" - fi -done +log "=== claws LocalStack Demo Cleanup ===" -log "Deleting Route Tables..." -RTS=$(aws_cmd ec2 describe-route-tables \ - --filters "Name=tag:Project,Values=claws-demo" \ - --query 'RouteTables[].RouteTableId' --output text 2>/dev/null || echo "") -for rt in $RTS; do - ASSOCS=$(aws_cmd ec2 describe-route-tables --route-table-ids "$rt" \ - --query 'RouteTables[0].Associations[?!Main].RouteTableAssociationId' --output text 2>/dev/null || echo "") - for assoc in $ASSOCS; do - aws_cmd ec2 disassociate-route-table --association-id "$assoc" 2>/dev/null || track_error "Failed to disassociate: $assoc" +for account in "${ACCOUNTS[@]}"; do + for region in "${REGIONS[@]}"; do + cleanup_account_region "$account" "$region" done - if aws_cmd ec2 delete-route-table --route-table-id "$rt" 2>/dev/null; then - log " Deleted: $rt" - else - track_error "Failed to delete RT: $rt" - fi -done - -log "Detaching and deleting Internet Gateways..." -IGWS=$(aws_cmd ec2 describe-internet-gateways \ - --filters "Name=tag:Project,Values=claws-demo" \ - --query 'InternetGateways[].InternetGatewayId' --output text 2>/dev/null || echo "") -for igw in $IGWS; do - VPC=$(aws_cmd ec2 describe-internet-gateways --internet-gateway-ids "$igw" \ - --query 'InternetGateways[0].Attachments[0].VpcId' --output text 2>/dev/null || echo "") - if [[ -n "$VPC" && "$VPC" != "None" ]]; then - aws_cmd ec2 detach-internet-gateway --internet-gateway-id "$igw" --vpc-id "$VPC" 2>/dev/null || track_error "Failed to detach IGW: $igw" - fi - if aws_cmd ec2 delete-internet-gateway --internet-gateway-id "$igw" 2>/dev/null; then - log " Deleted: $igw" - else - track_error "Failed to delete IGW: $igw" - fi done -log "Deleting VPCs..." -VPCS=$(aws_cmd ec2 describe-vpcs \ - --filters "Name=tag:Project,Values=claws-demo" \ - --query 'Vpcs[].VpcId' --output text 2>/dev/null || echo "") -for vpc in $VPCS; do - if aws_cmd ec2 delete-vpc --vpc-id "$vpc" 2>/dev/null; then - log " Deleted: $vpc" - else - track_error "Failed to delete VPC: $vpc" - fi -done +export AWS_ACCESS_KEY_ID="${ACCOUNTS[0]}" +export AWS_DEFAULT_REGION="us-east-1" log "Deleting S3 buckets..." for bucket in claws-demo-assets claws-demo-logs claws-demo-backups; do - if aws_cmd s3 rb "s3://${bucket}" --force 2>/dev/null; then - log " Deleted: $bucket" - else - track_error "Failed to delete bucket: $bucket" - fi + aws_cmd s3 rb "s3://${bucket}" --force 2>/dev/null && log " Deleted: $bucket" || true done if [[ $ERRORS -gt 0 ]]; then warn "=== Cleanup completed with $ERRORS error(s) ===" - exit 1 else log "=== Cleanup complete ===" fi diff --git a/scripts/localstack-demo-setup.sh b/scripts/localstack-demo-setup.sh index fd20e22a..dab295a7 100755 --- a/scripts/localstack-demo-setup.sh +++ b/scripts/localstack-demo-setup.sh @@ -25,17 +25,38 @@ if [[ "${AWS_ENDPOINT_URL:-}" != "http://localhost:4566" ]]; then fi # Set credentials for LocalStack -export AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-test}" export AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-test}" -export AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION:-us-east-1}" export AWS_EC2_METADATA_DISABLED=true +# Account IDs (LocalStack uses AWS_ACCESS_KEY_ID as account ID if 12 digits) +ACCOUNT_PROD="111111111111" +ACCOUNT_DEV="222222222222" + +# Regions to create resources in +REGIONS=("us-east-1" "us-west-2" "ap-northeast-1") + # Common tags DEMO_TAG="Key=Project,Value=claws-demo" DEMO_TAG2="Key=Demo,Value=true" aws_cmd() { - aws --endpoint-url="${AWS_ENDPOINT_URL}" "$@" + local account="${AWS_ACCOUNT_ID:-$ACCOUNT_PROD}" + local region="${AWS_REGION:-us-east-1}" + AWS_ACCESS_KEY_ID="$account" aws --endpoint-url="${AWS_ENDPOINT_URL}" --region "$region" "$@" +} + +aws_cmd_account() { + local account="$1" + shift + local region="${AWS_REGION:-us-east-1}" + AWS_ACCESS_KEY_ID="$account" aws --endpoint-url="${AWS_ENDPOINT_URL}" --region "$region" "$@" +} + +aws_cmd_region() { + local region="$1" + shift + local account="${AWS_ACCOUNT_ID:-$ACCOUNT_PROD}" + AWS_ACCESS_KEY_ID="$account" aws --endpoint-url="${AWS_ENDPOINT_URL}" --region "$region" "$@" } # Wait for LocalStack to be ready @@ -52,28 +73,31 @@ wait_localstack() { } # ============================================ -# VPC A: Production-like setup +# VPC A: Production-like setup (Account: prod, Region: us-east-1) # ============================================ create_vpc_a() { - log "Creating VPC A (prod)..." + log "Creating VPC A (prod) in us-east-1..." + export AWS_ACCOUNT_ID="$ACCOUNT_PROD" + export AWS_REGION="us-east-1" + VPC_A=$(aws_cmd ec2 create-vpc --cidr-block 10.0.0.0/16 --query 'Vpc.VpcId' --output text) - aws_cmd ec2 create-tags --resources "$VPC_A" --tags Key=Name,Value=claws-demo-prod ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$VPC_A" --tags Key=Name,Value=prod-vpc-east Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} - # Internet Gateway IGW_A=$(aws_cmd ec2 create-internet-gateway --query 'InternetGateway.InternetGatewayId' --output text) - aws_cmd ec2 create-tags --resources "$IGW_A" --tags Key=Name,Value=claws-demo-igw-prod ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$IGW_A" --tags Key=Name,Value=prod-igw-east Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} aws_cmd ec2 attach-internet-gateway --vpc-id "$VPC_A" --internet-gateway-id "$IGW_A" - # Public Subnets SUBNET_A1=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_A" --cidr-block 10.0.1.0/24 --availability-zone us-east-1a --query 'Subnet.SubnetId' --output text) - aws_cmd ec2 create-tags --resources "$SUBNET_A1" --tags Key=Name,Value=claws-demo-public-1a ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$SUBNET_A1" --tags Key=Name,Value=prod-public-web-1a Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} SUBNET_A2=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_A" --cidr-block 10.0.2.0/24 --availability-zone us-east-1b --query 'Subnet.SubnetId' --output text) - aws_cmd ec2 create-tags --resources "$SUBNET_A2" --tags Key=Name,Value=claws-demo-public-1b ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$SUBNET_A2" --tags Key=Name,Value=prod-public-web-1b Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} - # Private Subnet SUBNET_A3=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_A" --cidr-block 10.0.10.0/24 --availability-zone us-east-1a --query 'Subnet.SubnetId' --output text) - aws_cmd ec2 create-tags --resources "$SUBNET_A3" --tags Key=Name,Value=claws-demo-private-1a ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$SUBNET_A3" --tags Key=Name,Value=prod-private-db-1a Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} + + SUBNET_A4=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_A" --cidr-block 10.0.11.0/24 --availability-zone us-east-1b --query 'Subnet.SubnetId' --output text) + aws_cmd ec2 create-tags --resources "$SUBNET_A4" --tags Key=Name,Value=prod-private-db-1b Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} # Route Table (public) RTB_A=$(aws_cmd ec2 create-route-table --vpc-id "$VPC_A" --query 'RouteTable.RouteTableId' --output text) @@ -106,87 +130,150 @@ create_vpc_a() { log "Creating EC2 instances in VPC A..." - # Web servers + # Web servers (running) WEB1=$(aws_cmd ec2 run-instances --image-id "$AMI" --instance-type t2.micro --subnet-id "$SUBNET_A1" --security-group-ids "$SG_WEB" --query 'Instances[0].InstanceId' --output text) - aws_cmd ec2 create-tags --resources "$WEB1" --tags Key=Name,Value=claws-demo-web-1 Key=Role,Value=web ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$WEB1" --tags Key=Name,Value=prod-web-1 Key=Role,Value=web Key=Status,Value=active ${DEMO_TAG} ${DEMO_TAG2} WEB2=$(aws_cmd ec2 run-instances --image-id "$AMI" --instance-type t2.micro --subnet-id "$SUBNET_A2" --security-group-ids "$SG_WEB" --query 'Instances[0].InstanceId' --output text) - aws_cmd ec2 create-tags --resources "$WEB2" --tags Key=Name,Value=claws-demo-web-2 Key=Role,Value=web ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$WEB2" --tags Key=Name,Value=prod-web-2 Key=Role,Value=web Key=Status,Value=active ${DEMO_TAG} ${DEMO_TAG2} - # App server + # App server (stopped - maintenance) APP1=$(aws_cmd ec2 run-instances --image-id "$AMI" --instance-type t2.small --subnet-id "$SUBNET_A1" --security-group-ids "$SG_APP" --query 'Instances[0].InstanceId' --output text) - aws_cmd ec2 create-tags --resources "$APP1" --tags Key=Name,Value=claws-demo-app-1 Key=Role,Value=app ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$APP1" --tags Key=Name,Value=prod-app-1 Key=Role,Value=app Key=Status,Value=maintenance ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 stop-instances --instance-ids "$APP1" || true - # DB server + # DB server (running) DB1=$(aws_cmd ec2 run-instances --image-id "$AMI" --instance-type t2.medium --subnet-id "$SUBNET_A3" --security-group-ids "$SG_DB" --query 'Instances[0].InstanceId' --output text) - aws_cmd ec2 create-tags --resources "$DB1" --tags Key=Name,Value=claws-demo-db-1 Key=Role,Value=db ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$DB1" --tags Key=Name,Value=prod-db-1 Key=Role,Value=db Key=Status,Value=active ${DEMO_TAG} ${DEMO_TAG2} log "VPC A created: $VPC_A" } # ============================================ -# VPC B: Dev/Staging setup +# VPC B: Dev Account (Account: dev, Region: us-west-2) # ============================================ create_vpc_b() { - log "Creating VPC B (dev)..." + log "Creating VPC B (dev) in us-west-2..." + export AWS_ACCOUNT_ID="$ACCOUNT_DEV" + export AWS_REGION="us-west-2" + VPC_B=$(aws_cmd ec2 create-vpc --cidr-block 10.1.0.0/16 --query 'Vpc.VpcId' --output text) - aws_cmd ec2 create-tags --resources "$VPC_B" --tags Key=Name,Value=claws-demo-dev ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$VPC_B" --tags Key=Name,Value=dev-vpc-west Key=Env,Value=dev ${DEMO_TAG} ${DEMO_TAG2} - # Internet Gateway IGW_B=$(aws_cmd ec2 create-internet-gateway --query 'InternetGateway.InternetGatewayId' --output text) - aws_cmd ec2 create-tags --resources "$IGW_B" --tags Key=Name,Value=claws-demo-igw-dev ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$IGW_B" --tags Key=Name,Value=dev-igw-west Key=Env,Value=dev ${DEMO_TAG} ${DEMO_TAG2} aws_cmd ec2 attach-internet-gateway --vpc-id "$VPC_B" --internet-gateway-id "$IGW_B" - # Subnets - SUBNET_B1=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_B" --cidr-block 10.1.1.0/24 --availability-zone us-east-1a --query 'Subnet.SubnetId' --output text) - aws_cmd ec2 create-tags --resources "$SUBNET_B1" --tags Key=Name,Value=claws-demo-dev-1a ${DEMO_TAG} ${DEMO_TAG2} - - SUBNET_B2=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_B" --cidr-block 10.1.2.0/24 --availability-zone us-east-1b --query 'Subnet.SubnetId' --output text) - aws_cmd ec2 create-tags --resources "$SUBNET_B2" --tags Key=Name,Value=claws-demo-dev-1b ${DEMO_TAG} ${DEMO_TAG2} + SUBNET_B1=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_B" --cidr-block 10.1.1.0/24 --availability-zone us-west-2a --query 'Subnet.SubnetId' --output text) + aws_cmd ec2 create-tags --resources "$SUBNET_B1" --tags Key=Name,Value=dev-subnet-2a Key=Env,Value=dev ${DEMO_TAG} ${DEMO_TAG2} - SUBNET_B3=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_B" --cidr-block 10.1.3.0/24 --availability-zone us-east-1c --query 'Subnet.SubnetId' --output text) - aws_cmd ec2 create-tags --resources "$SUBNET_B3" --tags Key=Name,Value=claws-demo-dev-1c ${DEMO_TAG} ${DEMO_TAG2} + SUBNET_B2=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_B" --cidr-block 10.1.2.0/24 --availability-zone us-west-2b --query 'Subnet.SubnetId' --output text) + aws_cmd ec2 create-tags --resources "$SUBNET_B2" --tags Key=Name,Value=dev-subnet-2b Key=Env,Value=dev ${DEMO_TAG} ${DEMO_TAG2} - # Route Table RTB_B=$(aws_cmd ec2 create-route-table --vpc-id "$VPC_B" --query 'RouteTable.RouteTableId' --output text) - aws_cmd ec2 create-tags --resources "$RTB_B" --tags Key=Name,Value=claws-demo-rt-dev ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$RTB_B" --tags Key=Name,Value=dev-rt-west Key=Env,Value=dev ${DEMO_TAG} ${DEMO_TAG2} aws_cmd ec2 create-route --route-table-id "$RTB_B" --destination-cidr-block 0.0.0.0/0 --gateway-id "$IGW_B" || true - # Security Groups - SG_DEV=$(aws_cmd ec2 create-security-group --group-name claws-demo-sg-dev --description "Dev all-in-one" --vpc-id "$VPC_B" --query 'GroupId' --output text) - aws_cmd ec2 create-tags --resources "$SG_DEV" --tags Key=Name,Value=claws-demo-sg-dev ${DEMO_TAG} ${DEMO_TAG2} - - SG_STAGING=$(aws_cmd ec2 create-security-group --group-name claws-demo-sg-staging --description "Staging" --vpc-id "$VPC_B" --query 'GroupId' --output text) - aws_cmd ec2 create-tags --resources "$SG_STAGING" --tags Key=Name,Value=claws-demo-sg-staging ${DEMO_TAG} ${DEMO_TAG2} - - SG_BASTION=$(aws_cmd ec2 create-security-group --group-name claws-demo-sg-bastion --description "Bastion host" --vpc-id "$VPC_B" --query 'GroupId' --output text) - aws_cmd ec2 create-tags --resources "$SG_BASTION" --tags Key=Name,Value=claws-demo-sg-bastion ${DEMO_TAG} ${DEMO_TAG2} - aws_cmd ec2 authorize-security-group-ingress --group-id "$SG_BASTION" --protocol tcp --port 22 --cidr 0.0.0.0/0 || true + SG_DEV=$(aws_cmd ec2 create-security-group --group-name dev-sg-all --description "Dev all-in-one" --vpc-id "$VPC_B" --query 'GroupId' --output text) + aws_cmd ec2 create-tags --resources "$SG_DEV" --tags Key=Name,Value=dev-sg-all Key=Env,Value=dev ${DEMO_TAG} ${DEMO_TAG2} - # EC2 Instances AMI="ami-12345678" - log "Creating EC2 instances in VPC B..." + log "Creating EC2 instances in dev account (us-west-2)..." DEV1=$(aws_cmd ec2 run-instances --image-id "$AMI" --instance-type t2.micro --subnet-id "$SUBNET_B1" --security-group-ids "$SG_DEV" --query 'Instances[0].InstanceId' --output text) - aws_cmd ec2 create-tags --resources "$DEV1" --tags Key=Name,Value=claws-demo-dev-server Key=Role,Value=dev ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 create-tags --resources "$DEV1" --tags Key=Name,Value=dev-api-server Key=Env,Value=dev ${DEMO_TAG} ${DEMO_TAG2} - STAGING1=$(aws_cmd ec2 run-instances --image-id "$AMI" --instance-type t2.small --subnet-id "$SUBNET_B2" --security-group-ids "$SG_STAGING" --query 'Instances[0].InstanceId' --output text) - aws_cmd ec2 create-tags --resources "$STAGING1" --tags Key=Name,Value=claws-demo-staging Key=Role,Value=staging ${DEMO_TAG} ${DEMO_TAG2} + DEV2=$(aws_cmd ec2 run-instances --image-id "$AMI" --instance-type t2.small --subnet-id "$SUBNET_B2" --security-group-ids "$SG_DEV" --query 'Instances[0].InstanceId' --output text) + aws_cmd ec2 create-tags --resources "$DEV2" --tags Key=Name,Value=dev-worker Key=Env,Value=dev ${DEMO_TAG} ${DEMO_TAG2} log "VPC B created: $VPC_B" } # ============================================ -# S3 Buckets (for variety in demo) +# VPC C: Prod Account in ap-northeast-1 +# ============================================ +create_vpc_c() { + log "Creating VPC C (prod) in ap-northeast-1..." + export AWS_ACCOUNT_ID="$ACCOUNT_PROD" + export AWS_REGION="ap-northeast-1" + + VPC_C=$(aws_cmd ec2 create-vpc --cidr-block 10.2.0.0/16 --query 'Vpc.VpcId' --output text) + aws_cmd ec2 create-tags --resources "$VPC_C" --tags Key=Name,Value=prod-vpc-tokyo Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} + + IGW_C=$(aws_cmd ec2 create-internet-gateway --query 'InternetGateway.InternetGatewayId' --output text) + aws_cmd ec2 create-tags --resources "$IGW_C" --tags Key=Name,Value=prod-igw-tokyo Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} + aws_cmd ec2 attach-internet-gateway --vpc-id "$VPC_C" --internet-gateway-id "$IGW_C" + + SUBNET_C1=$(aws_cmd ec2 create-subnet --vpc-id "$VPC_C" --cidr-block 10.2.1.0/24 --availability-zone ap-northeast-1a --query 'Subnet.SubnetId' --output text) + aws_cmd ec2 create-tags --resources "$SUBNET_C1" --tags Key=Name,Value=prod-tokyo-1a Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} + + SG_TOKYO=$(aws_cmd ec2 create-security-group --group-name prod-sg-tokyo --description "Tokyo prod" --vpc-id "$VPC_C" --query 'GroupId' --output text) + aws_cmd ec2 create-tags --resources "$SG_TOKYO" --tags Key=Name,Value=prod-sg-tokyo Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} + + AMI="ami-12345678" + + log "Creating EC2 instances in prod account (ap-northeast-1)..." + + TOKYO1=$(aws_cmd ec2 run-instances --image-id "$AMI" --instance-type t2.micro --subnet-id "$SUBNET_C1" --security-group-ids "$SG_TOKYO" --query 'Instances[0].InstanceId' --output text) + aws_cmd ec2 create-tags --resources "$TOKYO1" --tags Key=Name,Value=prod-tokyo-web Key=Env,Value=prod ${DEMO_TAG} ${DEMO_TAG2} + + log "VPC C created: $VPC_C" +} + +# ============================================ +# S3 Buckets # ============================================ create_s3_buckets() { log "Creating S3 buckets..." + export AWS_ACCOUNT_ID="$ACCOUNT_PROD" + export AWS_REGION="us-east-1" aws_cmd s3 mb s3://claws-demo-assets 2>/dev/null || true aws_cmd s3 mb s3://claws-demo-logs 2>/dev/null || true aws_cmd s3 mb s3://claws-demo-backups 2>/dev/null || true } +# ============================================ +# AWS Config for multi-profile demo +# ============================================ +create_aws_config() { + log "Creating AWS config for demo profiles..." + + CONFIG_DIR="$(dirname "$0")/demo-aws-config" + mkdir -p "$CONFIG_DIR" + + cat > "$CONFIG_DIR/config" << 'AWSCONFIG' +[default] +region = us-east-1 +endpoint_url = http://localhost:4566 + +[profile prod] +region = us-east-1 +endpoint_url = http://localhost:4566 + +[profile dev] +region = us-west-2 +endpoint_url = http://localhost:4566 +AWSCONFIG + + cat > "$CONFIG_DIR/credentials" << 'AWSCREDS' +[default] +aws_access_key_id = 111111111111 +aws_secret_access_key = test + +[prod] +aws_access_key_id = 111111111111 +aws_secret_access_key = test + +[dev] +aws_access_key_id = 222222222222 +aws_secret_access_key = test +AWSCREDS + + chmod 600 "$CONFIG_DIR/credentials" + log "AWS config created at: $CONFIG_DIR" +} + # ============================================ # Main # ============================================ @@ -205,19 +292,21 @@ main() { create_vpc_a create_vpc_b + create_vpc_c create_s3_buckets + create_aws_config log "=== Demo setup complete! ===" log "" log "Resources created:" - log " - 2 VPCs (prod, dev)" - log " - 6 Subnets" - log " - 4 Route Tables" - log " - 2 Internet Gateways" - log " - 6 Security Groups" - log " - 6 EC2 Instances" + log " - 3 VPCs (prod us-east-1, dev us-west-2, prod ap-northeast-1)" + log " - 2 Accounts (111111111111=prod, 222222222222=dev)" + log " - 3 Regions (us-east-1, us-west-2, ap-northeast-1)" + log " - 7 EC2 Instances across accounts/regions" log " - 3 S3 Buckets" log "" + log "AWS config created at: scripts/demo-aws-config/" + log "" log "Run claws with:" log " AWS_ENDPOINT_URL=http://localhost:4566 ./claws" }