Skip to content

Commit b0384fe

Browse files
author
Yuriy Bezsonov
committed
WIP
1 parent 8242240 commit b0384fe

24 files changed

Lines changed: 2475 additions & 1716 deletions

.github/renovate.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
extends:
2+
- config:base
3+
schedule:
4+
- "before 6am on monday"
5+
regexManagers:
6+
- fileMatch:
7+
- "^infra/scripts/.*\\.sh$"
8+
matchStrings:
9+
- "NVM_VERSION=\"(?<currentValue>.*?)\""
10+
datasourceTemplate: github-releases
11+
depNameTemplate: nvm-sh/nvm
12+
- fileMatch:
13+
- "^infra/scripts/.*\\.sh$"
14+
matchStrings:
15+
- "MAVEN_VERSION=\"(?<currentValue>.*?)\""
16+
datasourceTemplate: github-releases
17+
depNameTemplate: apache/maven
18+
- fileMatch:
19+
- "^infra/scripts/.*\\.sh$"
20+
matchStrings:
21+
- "KUBECTL_VERSION=\"(?<currentValue>.*?)\""
22+
datasourceTemplate: github-releases
23+
depNameTemplate: kubernetes/kubernetes
24+
- fileMatch:
25+
- "^infra/scripts/.*\\.sh$"
26+
matchStrings:
27+
- "HELM_VERSION=\"(?<currentValue>.*?)\""
28+
datasourceTemplate: github-releases
29+
depNameTemplate: helm/helm
30+
- fileMatch:
31+
- "^infra/scripts/.*\\.sh$"
32+
matchStrings:
33+
- "EKSCTL_VERSION=\"(?<currentValue>.*?)\""
34+
datasourceTemplate: github-releases
35+
depNameTemplate: weaveworks/eksctl
36+
- fileMatch:
37+
- "^infra/scripts/.*\\.sh$"
38+
matchStrings:
39+
- "YQ_VERSION=\"(?<currentValue>.*?)\""
40+
datasourceTemplate: github-releases
41+
depNameTemplate: mikefarah/yq
42+
- fileMatch:
43+
- "^infra/scripts/.*\\.sh$"
44+
matchStrings:
45+
- "DOCKER_COMPOSE_VERSION=\"(?<currentValue>.*?)\""
46+
datasourceTemplate: github-releases
47+
depNameTemplate: docker/compose
48+
49+
- fileMatch:
50+
- "^infra/scripts/.*\\.sh$"
51+
matchStrings:
52+
- "EKS_NODE_VIEWER_VERSION=\"(?<currentValue>.*?)\""
53+
datasourceTemplate: github-releases
54+
depNameTemplate: awslabs/eks-node-viewer
55+
- fileMatch:
56+
- "^infra/scripts/.*\\.sh$"
57+
matchStrings:
58+
- "SOCI_VERSION=\"(?<currentValue>.*?)\""
59+
datasourceTemplate: github-releases
60+
depNameTemplate: awslabs/soci-snapshotter

.kiro/specs/infra/design.md

Lines changed: 148 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,28 @@ infra/
2222
│ │ │ ├── Eks.java
2323
│ │ │ ├── Database.java
2424
│ │ │ ├── CodeBuild.java
25+
│ │ │ ├── Lambda.java
2526
│ │ │ └── Roles.java
26-
│ │ ├── stacks/
27-
│ │ │ └── WorkshopStack.java
28-
│ │ └── WorkshopApp.java # Main CDK application
27+
│ │ ├── WorkshopStack.java # Main stack
28+
│ │ └── WorkshopApp.java # Main CDK application
29+
│ ├── src/main/resources/
30+
│ │ └── ec2-userdata.sh # Minimal UserData script (embedded in CDK)
2931
│ ├── pom.xml
3032
│ └── cdk.json
3133
├── workshop-template.yaml # Generated unified CloudFormation template
3234
├── scripts/
33-
│ ├── workshops/ # Workshop-specific orchestration scripts
34-
│ │ ├── ide.sh
35-
│ │ ├── java-on-aws.sh
36-
│ │ ├── java-on-eks.sh
37-
│ │ ├── java-ai-agents.sh
38-
│ │ └── java-spring-ai-agents.sh
39-
│ ├── setup/ # Modular setup scripts
40-
│ │ ├── base.sh
41-
│ │ ├── eks.sh
42-
│ │ ├── app.sh
43-
│ │ ├── monitoring.sh
44-
│ │ └── ai-agents.sh
35+
│ ├── ide/ # Modular IDE and workshop scripts
36+
│ │ ├── vscode.sh # VS Code installation and configuration
37+
│ │ ├── base.sh # Base development tools
38+
│ │ ├── java-on-aws.sh # Java-on-AWS workshop setup
39+
│ │ ├── java-on-eks.sh # Java-on-EKS workshop setup
40+
│ │ └── java-ai-agents.sh # Java AI Agents workshop setup
4541
│ ├── lib/ # Common utilities
4642
│ │ ├── common.sh
4743
│ │ └── wait-for-resources.sh
48-
│ ├── deploy/ # Deployment utilities
49-
│ ├── test/ # Testing scripts
44+
│ ├── cfn/ # CloudFormation utilities
45+
│ │ ├── generate.sh
46+
│ │ └── sync.sh
5047
│ └── cleanup/ # Cleanup scripts
5148
└── package.json # Build automation
5249
```
@@ -56,35 +53,30 @@ infra/
5653
### CDK Components
5754

5855
#### WorkshopStack
59-
The main CDK stack that conditionally creates resources based on workshop type:
56+
The main CDK stack that conditionally creates resources based on template type:
6057

6158
```java
6259
public class WorkshopStack extends Stack {
6360
public WorkshopStack(final Construct scope, final String id, final StackProps props) {
6461
super(scope, id, props);
6562

66-
String workshopType = System.getenv("WORKSHOP_TYPE");
67-
if (workshopType == null) {
68-
workshopType = "ide"; // default
63+
String templateType = System.getenv("TEMPLATE_TYPE");
64+
if (templateType == null) {
65+
templateType = "base"; // default
6966
}
7067

7168
// Core infrastructure (always created)
72-
var roles = new Roles(this, "Roles");
7369
var vpc = new Vpc(this, "Vpc");
74-
var ide = new Ide(this, "Ide", vpc.getVpc(), roles);
70+
var ide = new Ide(this, "Ide", vpc.getVpc());
7571

76-
// Conditional resources based on workshop type
77-
if (!"ide".equals(workshopType) && !"java-ai-agents".equals(workshopType)) {
78-
new Eks(this, "Eks", vpc.getVpc(), roles);
72+
// Custom roles only for non-base templates
73+
if (!"base".equals(templateType)) {
74+
var roles = new Roles(this, "Roles");
7975
}
8076

81-
if (!"ide".equals(workshopType)) {
82-
new Database(this, "Database", vpc.getVpc());
83-
}
84-
85-
// CodeBuild for workshop setup
77+
// CodeBuild for service-linked role creation
8678
new CodeBuild(this, "CodeBuild",
87-
Map.of("STACK_NAME", Aws.STACK_NAME, "WORKSHOP_TYPE", workshopType));
79+
Map.of("STACK_NAME", Aws.STACK_NAME, "TEMPLATE_TYPE", templateType));
8880
}
8981
}
9082
```
@@ -95,7 +87,7 @@ public class WorkshopStack extends Stack {
9587
**Ide**: Creates VS Code IDE environment with necessary permissions
9688
**Eks**: Creates EKS cluster with AutoMode
9789
**Database**: Configures RDS instances and database schemas
98-
**CodeBuild**: Creates CodeBuild project for workshop setup automation
90+
**CodeBuild**: Creates CodeBuild project for AWS service-linked role creation
9991
**Roles**: Creates IAM roles and policies for workshop resources
10092

10193
### Lambda Function Architecture
@@ -128,60 +120,148 @@ Instead of multiple Lambda functions, the new design uses:
128120
| `unicornstore-db-setup-lambda` | **Setup Scripts** | N/A | N/A | Moved to workshop setup scripts |
129121

130122
#### External Resource Approach
131-
The new design uses **external files** for all complex scripts and code, loaded via CDK for better maintainability while preserving CloudFormation template compatibility through inline code generation. This approach eliminates hard-to-maintain inline code blocks.
123+
The new design uses **external files** for all complex scripts and code, loaded via CDK for better maintainability while preserving CloudFormation template compatibility through inline code generation. This approach eliminates hard-to-maintain inline code blocks and provides a **reusable Lambda construct** for consistent function creation.
132124

133125
#### External Resource Organization
134126
```
135127
infra/cdk/src/main/resources/
136-
├── launcher.py # EC2 instance launching with multi-AZ/instance-type failover
137-
└── bootstrap.sh # EC2 User Data bootstrap script with CloudWatch logging
128+
├── lambda/
129+
│ ├── ec2-launcher.py # EC2 instance launching with multi-AZ/instance-type failover
130+
│ ├── codebuild-start.py # CodeBuild project starter for workshop setup
131+
│ └── codebuild-report.py # CodeBuild completion reporter via EventBridge
132+
└── ec2-userdata.sh # Minimal UserData script (2.4KB) with CloudWatch logging
133+
```
134+
135+
#### Reusable Lambda Construct
136+
```java
137+
public class Lambda extends Construct {
138+
public Lambda(final Construct scope, final String id, final LambdaProps props) {
139+
super(scope, id);
140+
141+
Function.Builder.create(this, "Function")
142+
.runtime(Runtime.PYTHON_3_13)
143+
.handler("index.lambda_handler")
144+
.code(Code.fromInline(loadFile(props.getSourceFile())))
145+
.timeout(props.getTimeout())
146+
.functionName(props.getFunctionName())
147+
.role(props.getRole())
148+
.build();
149+
}
150+
}
138151
```
139152

140153
#### Usage in IDE Construct
141154
```java
142-
// Create instance launcher Lambda loading from external file
143-
var instanceLauncherFunction = Function.Builder.create(this, "IdeInstanceLauncherFunction")
144-
.runtime(Runtime.PYTHON_3_13)
145-
.handler("index.lambda_handler")
146-
.code(Code.fromInline(loadFile("/launcher.py")))
147-
.timeout(Duration.minutes(5))
148-
.functionName(instanceName + "-launcher")
149-
.role(props.getLambdaRole())
150-
.build();
155+
// Create EC2 launcher Lambda using reusable construct
156+
var launcherLambda = new Lambda(this, "LauncherLambda",
157+
Lambda.LambdaProps.builder()
158+
.sourceFile("/lambda/ec2-launcher.py")
159+
.functionName(instanceName + "-launcher")
160+
.timeout(Duration.minutes(5))
161+
.role(props.getLambdaRole())
162+
.build());
151163

152164
// Create User Data from external script with variable substitution
153165
var userData = UserData.forLinux();
154-
String bootstrapScript = loadFile("/bootstrap.sh")
166+
String bootstrapScript = loadFile("/ec2-userdata.sh")
155167
.replace("${stackName}", Aws.STACK_NAME)
156168
.replace("${awsRegion}", Aws.REGION)
157169
.replace("${idePassword}", ideSecretsManagerPassword.secretValueFromJson("password").unsafeUnwrap());
158170
userData.addCommands(bootstrapScript.split("\n"));
159-
160-
// Helper method for loading files
161-
private String loadFile(String filePath) {
162-
try {
163-
return Files.readString(Path.of(getClass().getResource(filePath).getPath()));
164-
} catch (IOException e) {
165-
throw new RuntimeException("Failed to load file " + filePath, e);
166-
}
167-
}
168171
```
169172

170173
### Script Organization
171174

172-
#### Convention-Based Script Discovery
173-
Scripts are organized using a naming convention where the script name matches the stack name:
174-
- `ide.sh` → executed for ide workshop type
175-
- `java-on-aws.sh` → executed for java-on-aws workshop type
176-
- `java-on-eks.sh` → executed for java-on-eks workshop type
177-
178-
#### Modular Setup Scripts
179-
Common functionality is extracted into reusable modules:
180-
- `base.sh`: Common tools and AWS CLI configuration
181-
- `eks.sh`: EKS cluster configuration and kubectl setup
182-
- `app.sh`: Application deployment and configuration
183-
- `monitoring.sh`: Observability stack setup
184-
- `ai-agents.sh`: AI-specific setup for agent workshops
175+
#### Minimal UserData Architecture
176+
The new architecture uses minimal UserData (2.4KB) that downloads and executes a full bootstrap script, avoiding AWS UserData size limits:
177+
178+
```
179+
infra/cdk/src/main/resources/
180+
└── ec2-userdata.sh # Minimal UserData script (2.4KB)
181+
182+
infra/scripts/ide/
183+
├── bootstrap.sh # Full bootstrap script (3.8KB)
184+
├── vscode.sh # VS Code installation and configuration
185+
├── base.sh # Base development tools (foundational for all workshops)
186+
├── java-on-aws.sh # calls base.sh + EKS/DB setup
187+
├── java-on-eks.sh # calls base.sh + EKS setup
188+
└── java-ai-agents.sh # calls base.sh + AI setup
189+
```
190+
191+
#### Bootstrap Flow
192+
```
193+
ec2-userdata.sh → bootstrap.sh → vscode.sh → {workshop}.sh
194+
```
195+
196+
Where:
197+
- `ec2-userdata.sh`: Minimal UserData script that downloads and runs bootstrap.sh with fallback URLs
198+
- `bootstrap.sh`: Full system setup, CloudWatch, environment variables, git clone, calls vscode.sh and template script
199+
- `vscode.sh`: Complete VS Code IDE setup (code-server, Caddy, configuration)
200+
- `base.sh`: Base development tools (for base template type)
201+
- Future template scripts will be added to `/ide` folder as needed
202+
203+
#### Configuration
204+
- **Template Type**: Configurable via `TEMPLATE_TYPE` environment variable (defaults to `base`)
205+
- **Git Branch**: Defined in code as `"main"`
206+
- **VS Code Version**: Uses latest version by default
207+
208+
#### Environment Variables
209+
**Input (CDK reads):**
210+
- `TEMPLATE_TYPE` - determines template type (defaults to "base")
211+
212+
**Output (CDK passes to scripts):**
213+
- `STACK_NAME` - AWS stack name
214+
- `TEMPLATE_TYPE` - template type
215+
- `GIT_BRANCH` - git branch (hardcoded to "main")
216+
217+
#### Tool Version Management
218+
The system uses a hybrid approach for tool versions:
219+
220+
**Pinned Versions (Renovate Managed):**
221+
- Java: 25 (default, installs 8,17,21,25)
222+
- Node.js: 20 (LTS)
223+
- Maven: 3.9.11
224+
- kubectl: 1.34.2
225+
- Helm: 3.19.3 (v3.x for chart compatibility)
226+
- eksctl: 0.220.0
227+
- eks-node-viewer: 0.7.4
228+
- Docker Compose: 2.40.2
229+
- SOCI: 0.12.0
230+
- yq: 4.49.2
231+
232+
**Latest Versions (Auto-updating):**
233+
- VS Code: latest
234+
- AWS SAM CLI: latest
235+
- Session Manager Plugin: latest
236+
- AWS CLI: latest
237+
- CDK: latest (npm global)
238+
- Artillery: latest (npm global)
239+
- k9s: latest (webinstall.dev)
240+
- e1s: latest (GitHub script)
241+
242+
**System Packages (Repository Latest):**
243+
- jq, Docker, git, Caddy: latest available in package repositories
244+
245+
#### Script Architecture
246+
Scripts are organized with helper functions and consistent error handling:
247+
248+
**Bootstrap Script (`ide-bootstrap.sh`):**
249+
- Standardized on `dnf` package manager
250+
- Added error handling for critical operations (AWS CLI, git clone, CloudFront)
251+
- Improved logging and comments
252+
253+
**VS Code Script (`vscode.sh`):**
254+
- Helper functions eliminate repetitive `sudo -u ec2-user` patterns
255+
- `setup_user_file()` function for clean file creation
256+
- `run_as_user()` function for user command execution
257+
- Uses latest VS Code version by default
258+
259+
**IDE Script (`ide.sh`):**
260+
- Function-based organization by tool category
261+
- Comprehensive logging with timestamps (`log_info()`)
262+
- Error handling and download verification (`handle_error()`, `download_and_verify()`)
263+
- Consistent output handling and cleanup
264+
- Removed redundant operations (multiple `java -version` calls)
185265

186266
### Build Automation
187267

0 commit comments

Comments
 (0)