@mavogel/cdk-vscode-server 0.0.63 → 0.0.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/.jsii +127 -38
  2. package/API.md +112 -1
  3. package/CLAUDE.md +121 -4
  4. package/README.md +64 -1
  5. package/examples/auto-stop/main.ts +1 -1
  6. package/examples/custom/main.ts +24 -2
  7. package/examples/custom-install-steps/main.ts +201 -0
  8. package/integ-tests/integ.custom-domain.ts.snapshot/IntegSetupVSCodeOnCustomDomainDefaultTestDeployAssert6982D514.assets.json +2 -2
  9. package/integ-tests/integ.custom-domain.ts.snapshot/IntegSetupVSCodeOnCustomDomainDefaultTestDeployAssert6982D514.template.json +1 -1
  10. package/integ-tests/integ.custom-domain.ts.snapshot/IntegTestStackCustomDomain.assets.json +2 -2
  11. package/integ-tests/integ.custom-domain.ts.snapshot/IntegTestStackCustomDomain.template.json +3 -3
  12. package/integ-tests/integ.custom-domain.ts.snapshot/integ.json +1 -1
  13. package/integ-tests/integ.custom-domain.ts.snapshot/manifest.json +8 -5
  14. package/integ-tests/integ.custom-domain.ts.snapshot/tree.json +1 -1
  15. package/integ-tests/integ.stop-on-idle.ts.snapshot/IntegStopOnIdleFunctionalityDefaultTestDeployAssertEECF3FC0.assets.json +2 -2
  16. package/integ-tests/integ.stop-on-idle.ts.snapshot/IntegStopOnIdleFunctionalityDefaultTestDeployAssertEECF3FC0.template.json +4 -4
  17. package/integ-tests/integ.stop-on-idle.ts.snapshot/IntegTestStackStopOnIdle.assets.json +2 -2
  18. package/integ-tests/integ.stop-on-idle.ts.snapshot/IntegTestStackStopOnIdle.template.json +3 -3
  19. package/integ-tests/integ.stop-on-idle.ts.snapshot/manifest.json +12 -6
  20. package/integ-tests/integ.stop-on-idle.ts.snapshot/tree.json +1 -1
  21. package/integ-tests/integ.ubuntu.ts.snapshot/IntegSetupVSCodeOnUbuntuDefaultTestDeployAssertFF8DF2C5.assets.json +2 -2
  22. package/integ-tests/integ.ubuntu.ts.snapshot/IntegSetupVSCodeOnUbuntuDefaultTestDeployAssertFF8DF2C5.template.json +1 -1
  23. package/integ-tests/integ.ubuntu.ts.snapshot/IntegTestStackUbuntu22.assets.json +2 -2
  24. package/integ-tests/integ.ubuntu.ts.snapshot/IntegTestStackUbuntu22.template.json +3 -3
  25. package/integ-tests/integ.ubuntu.ts.snapshot/integ.json +1 -1
  26. package/integ-tests/integ.ubuntu.ts.snapshot/manifest.json +8 -5
  27. package/integ-tests/integ.ubuntu.ts.snapshot/tree.json +1 -1
  28. package/integ-tests/integ.ubuntu25.ts +69 -0
  29. package/integ-tests/integ.ubuntu25.ts.snapshot/IntegSetupVSCodeOnUbuntu25DefaultTestDeployAssert48DBCF35.assets.json +33 -0
  30. package/integ-tests/integ.ubuntu25.ts.snapshot/IntegSetupVSCodeOnUbuntu25DefaultTestDeployAssert48DBCF35.template.json +337 -0
  31. package/integ-tests/integ.ubuntu25.ts.snapshot/IntegTestStackUbuntu25.assets.json +118 -0
  32. package/integ-tests/integ.ubuntu25.ts.snapshot/IntegTestStackUbuntu25.template.json +2725 -0
  33. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.2819175352ad1ce0dae768e83fc328fb70fb5f10b4a8ff0ccbcb791f02b0716d/index.js +1 -0
  34. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.2f99f38311da357eaaea1284d67c759759324dec4a1cd11621d9c59eea9e81df.lambda/index.js +180 -0
  35. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.530055f7515b3f0a47900f5df37e729ba40ca977b2d07b952bdefa2b8f883f42.bundle/index.js +30676 -0
  36. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.781ab0ab74634cdaf61539ab208ab777829ef07097ac21f95b9e15a3b1eedc1b.lambda/index.js +57 -0
  37. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.7fa1e366ee8a9ded01fc355f704cff92bfd179574e6f9cfee800a3541df1b200/__entrypoint__.js +1 -0
  38. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.7fa1e366ee8a9ded01fc355f704cff92bfd179574e6f9cfee800a3541df1b200/index.js +1 -0
  39. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.9d043014be736e8162bcc7ec5590cc6d2ff24fd0d9c73a5c5d595151c5fdad00/index.js +1 -0
  40. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.bdc104ed9cab1b5b6421713c8155f0b753380595356f710400609664d3635eca/cfn-response.js +1 -0
  41. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.bdc104ed9cab1b5b6421713c8155f0b753380595356f710400609664d3635eca/consts.js +1 -0
  42. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.bdc104ed9cab1b5b6421713c8155f0b753380595356f710400609664d3635eca/framework.js +3 -0
  43. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.bdc104ed9cab1b5b6421713c8155f0b753380595356f710400609664d3635eca/outbound.js +1 -0
  44. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.bdc104ed9cab1b5b6421713c8155f0b753380595356f710400609664d3635eca/util.js +1 -0
  45. package/integ-tests/integ.ubuntu25.ts.snapshot/asset.efac30c7091c58fed492058fa6403c14f7e58aab8cf4fd595d838b8d5eeec2b9/index.js +6017 -0
  46. package/integ-tests/integ.ubuntu25.ts.snapshot/integ.json +23 -0
  47. package/integ-tests/integ.ubuntu25.ts.snapshot/manifest.json +1473 -0
  48. package/integ-tests/integ.ubuntu25.ts.snapshot/tree.json +1 -0
  49. package/lib/idle-monitor/idle-monitor.js +1 -1
  50. package/lib/installer/installer.d.ts +11 -0
  51. package/lib/installer/installer.js +21 -4
  52. package/lib/mappings.js +11 -3
  53. package/lib/vscode-server.d.ts +57 -1
  54. package/lib/vscode-server.js +12 -3
  55. package/package.json +1 -1
package/CLAUDE.md CHANGED
@@ -88,9 +88,10 @@ Uses Lambda-backed custom resources via CDK Provider construct:
88
88
 
89
89
  1. **Installer** (`src/installer/`)
90
90
  - Runs SSM documents to install VS Code Server
91
- - OS-specific installation for Ubuntu 22/24 and Amazon Linux 2023
91
+ - OS-specific installation for Ubuntu 22/24/25 and Amazon Linux 2023
92
92
  - Returns SUCCESS when installation completes
93
93
  - Custom resource name: `SSMInstallerCustomResource`
94
+ - **Critical**: Must pass `linuxFlavorType` parameter to ensure correct OS-specific SSM document is used
94
95
 
95
96
  2. **SecretRetriever** (`src/secret-retriever/`)
96
97
  - Extracts generated password from Secrets Manager
@@ -130,11 +131,28 @@ enabler.node.addDependency(installerCustomResource);
130
131
  ### AMI Selection (`src/mappings.ts`)
131
132
 
132
133
  Contains SSM parameter paths for:
133
- - Ubuntu 22/24 (ARM + x86_64)
134
+ - Ubuntu 22/24/25 (ARM + x86_64)
134
135
  - Amazon Linux 2023 (ARM + x86_64)
135
136
 
137
+ **Ubuntu Codenames**:
138
+ - Ubuntu 22 = "jammy" (uses ebs-gp2)
139
+ - Ubuntu 24 = "noble" (uses ebs-gp3)
140
+ - Ubuntu 25 = "plucky" (uses ebs-gp3)
141
+
136
142
  Function `getAmiSSMParameterForLinuxArchitectureAndFlavor()` returns region-specific SSM parameter for latest AMI.
137
143
 
144
+ **Verify SSM Parameters** (when adding new OS versions):
145
+ ```bash
146
+ # List available Ubuntu versions
147
+ aws ssm get-parameters-by-path --path "/aws/service/canonical/ubuntu/server/" --recursive --query "Parameters[*].Name" --region us-east-1
148
+
149
+ # Verify specific AMI paths exist
150
+ aws ssm get-parameters --names \
151
+ "/aws/service/canonical/ubuntu/server/plucky/stable/current/amd64/hvm/ebs-gp3/ami-id" \
152
+ "/aws/service/canonical/ubuntu/server/plucky/stable/current/arm64/hvm/ebs-gp3/ami-id" \
153
+ --region us-east-1
154
+ ```
155
+
138
156
  ### Key Props (`src/vscode-server.ts:27-200`)
139
157
 
140
158
  **Instance Configuration**:
@@ -155,6 +173,10 @@ Function `getAmiSSMParameterForLinuxArchitectureAndFlavor()` returns region-spec
155
173
  - `idleCheckIntervalMinutes` - How often to check (default: 5)
156
174
  - `skipStatusChecks` - Skip EC2 status checks before stopping (for testing only)
157
175
 
176
+ **Custom Installation**:
177
+ - `customInstallSteps` - Array of custom shell commands that run after standard installation
178
+ - `repoUrl` - Git repository to clone into home folder during setup
179
+
158
180
  **Extensions**:
159
181
  - `additionalInstanceRolePolicies`, `additionalTags`
160
182
 
@@ -164,6 +186,7 @@ Function `getAmiSSMParameterForLinuxArchitectureAndFlavor()` returns region-spec
164
186
  - All public APIs must be JSII-compatible (no TS-specific types)
165
187
  - Bundled dependencies (like `node-html-parser`) must be in `.projenrc.ts` `bundledDeps`
166
188
  - Lambda functions use esbuild bundling configured via Projen (auto-discovered in `src/**/*.lambda.ts`)
189
+ - **@example JSDoc blocks must NOT use code fences** (```) - JSII will fail with "must be code only, no code block fences allowed"
167
190
 
168
191
  ## CDK-nag Integration
169
192
 
@@ -183,6 +206,8 @@ Located in `integ-tests/`, using `@aws-cdk/integ-tests-alpha` framework.
183
206
 
184
207
  **Test Files**:
185
208
  - `integ.ubuntu.ts` - Basic Ubuntu 22 deployment + login test
209
+ - `integ.ubuntu24.ts` - Ubuntu 24 deployment + login test
210
+ - `integ.ubuntu25.ts` - Ubuntu 25 deployment + login test
186
211
  - `integ.al2023.ts` - Amazon Linux 2023 deployment
187
212
  - `integ.custom-domain.ts` - Custom domain + ACM certificate
188
213
  - `integ.stop-on-idle.ts` - **4-phase auto-stop workflow test**
@@ -219,11 +244,50 @@ Projen automatically discovers Lambda functions matching `src/**/*.lambda.ts` pa
219
244
  3. Run `npx projen` - auto-discovers and creates bundle task
220
245
  4. Import in construct: `import { MyFeatureFunction } from './my-feature/my-feature-function'`
221
246
 
247
+ ### Adding Custom Installation Steps
248
+
249
+ Custom steps are appended to SSM document `mainSteps` array in `createSSMDocument()`:
250
+
251
+ 1. **Define interface** (if needed) in `src/vscode-server.ts`:
252
+ ```typescript
253
+ export interface CustomInstallStep {
254
+ readonly name: string;
255
+ readonly commands: string[];
256
+ }
257
+ ```
258
+
259
+ 2. **Add prop** to `VSCodeServerProps` with JSDoc documentation (no code fences!)
260
+
261
+ 3. **Pass to Installer** in both Ubuntu and Amazon Linux paths:
262
+ ```typescript
263
+ installer = Installer.ubuntu({
264
+ // ... other options
265
+ customInstallSteps: customInstallSteps,
266
+ })._bind(this);
267
+ ```
268
+
269
+ 4. **Update `createSSMDocument()`** in `src/installer/installer.ts` to accept and use custom steps:
270
+ ```typescript
271
+ ...(customInstallSteps?.map((step) => ({
272
+ action: 'aws:runShellScript' as const,
273
+ name: step.name,
274
+ inputs: {
275
+ runCommand: step.commands,
276
+ },
277
+ })) ?? []),
278
+ ```
279
+
280
+ 5. **Write unit tests** in `test/vscode-server.test.ts` covering normal usage, without steps, and empty array
281
+
282
+ 6. **Update documentation** in README.md with practical examples and add to `examples/` directory
283
+
222
284
  ### Modifying VSCodeServer Props
223
285
 
224
286
  1. Edit `src/vscode-server.ts` - update `VSCodeServerProps` interface
225
- 2. Run `npx projen build` - regenerates JSII artifacts + API docs
226
- 3. Update README.md with usage examples
287
+ 2. If adding new types/interfaces, export them from `src/vscode-server.ts`
288
+ 3. Run `npx projen build` - regenerates JSII artifacts + API docs
289
+ 4. Update README.md with usage examples and feature section
290
+ 5. Add example usage in `examples/` directory
227
291
 
228
292
  ### Testing Changes
229
293
 
@@ -231,6 +295,59 @@ Projen automatically discovers Lambda functions matching `src/**/*.lambda.ts` pa
231
295
  2. Build validation: `npx projen build` (includes awslint checks)
232
296
  3. Integration test: `npm run integ-test` (full deployment test)
233
297
 
298
+ ### Adding Support for a New Ubuntu Version
299
+
300
+ When Ubuntu releases a new version (e.g., Ubuntu 26):
301
+
302
+ 1. **Add AMI mappings** in `src/mappings.ts`:
303
+ ```typescript
304
+ [
305
+ 'arm-ubuntu26',
306
+ '/aws/service/canonical/ubuntu/server/CODENAME/stable/current/arm64/hvm/ebs-gp3/ami-id',
307
+ ],
308
+ [
309
+ 'amd64-ubuntu26',
310
+ '/aws/service/canonical/ubuntu/server/CODENAME/stable/current/amd64/hvm/ebs-gp3/ami-id',
311
+ ],
312
+ ```
313
+ Replace `CODENAME` with Ubuntu's codename (verify via AWS SSM Parameter Store)
314
+
315
+ 2. **Add enum value** in `src/vscode-server.ts`:
316
+ ```typescript
317
+ export enum LinuxFlavorType {
318
+ // ...
319
+ UBUNTU_26 = 'ubuntu26',
320
+ }
321
+ ```
322
+
323
+ 3. **Update Installer** in `src/installer/installer.ts`:
324
+ - Add `LinuxFlavorType.UBUNTU_26` to the Ubuntu switch case in `createSSMDocument()` (line ~657)
325
+ - Update installer calls in `src/vscode-server.ts` to include new case (line ~930)
326
+
327
+ 4. **Pass linuxFlavorType** in `src/vscode-server.ts`:
328
+ ```typescript
329
+ installer = Installer.ubuntu({
330
+ // ... other options
331
+ linuxFlavorType: instanceOperatingSystem, // Critical!
332
+ })._bind(this);
333
+ ```
334
+
335
+ 5. **Create integration test**: Copy `integ-tests/integ.ubuntu25.ts` to `integ.ubuntu26.ts` and update OS version
336
+
337
+ 6. **Update documentation**:
338
+ - Update README.md examples with inline comments showing all supported versions
339
+ - Examples in `examples/` directory (optional - can keep as Ubuntu 24)
340
+
341
+ 7. **Verify and build**:
342
+ ```bash
343
+ # Verify SSM parameters exist
344
+ aws ssm get-parameters-by-path --path "/aws/service/canonical/ubuntu/server/CODENAME/" --recursive --region us-east-1
345
+
346
+ # Build and test
347
+ npx projen build
348
+ npm run integ-test
349
+ ```
350
+
234
351
  ## Race Condition Prevention (Auto-Stop)
235
352
 
236
353
  **Issue**: IdleMonitor EventBridge rule triggers immediately on stack creation, potentially stopping instance during installation (observed: instance stopped 72 seconds after installer started).
package/README.md CHANGED
@@ -24,6 +24,7 @@ we implement new features. Therefore make sure you use an exact version in your
24
24
  - [Pre-populate with Git Repository](#pre-populate-with-git-repository)
25
25
  - [Custom Domain Configuration](#custom-domain-configuration)
26
26
  - [Auto-Stop Configuration](#auto-stop-configuration)
27
+ - [Custom Installation Steps](#custom-installation-steps)
27
28
  - [Solution Design](#solution-design)
28
29
  - [Inspiration](#inspiration)
29
30
 
@@ -34,6 +35,7 @@ we implement new features. Therefore make sure you use an exact version in your
34
35
  - 🤹‍♂️ **Pre-installed packages**: Besides the [vscode](https://code.visualstudio.com/) server, other tools and software packages such as `git`, `docker`, `awscli` `nodejs` and `python` are pre-installed on the EC2 instance.
35
36
  - 🌐 **Custom Domain Support**: Use your own domain name with automatic ACM certificate creation and Route53 DNS configuration, or bring your existing certificate.
36
37
  - 💰 **Auto-Stop**: Automatically stop EC2 instances after inactivity with Elastic IP retention - save up to 75% on costs for development environments.
38
+ - 🔧 **Custom Install Steps**: Extend the standard installation with your own shell commands to install workshop-specific tools, configure environments, or run setup scripts.
37
39
  - 🏗️ **Extensibility**: Pass in properties to the construct, which start with `additional*`. They allow you to extend the configuration to your needs. There are more to come...
38
40
 
39
41
  ## Usage
@@ -69,7 +71,7 @@ export class MyStack extends Stack {
69
71
  instanceVolumeSize: 8,
70
72
  instanceClass: ec2.InstanceClass.M7G,
71
73
  instanceSize: ec2.InstanceSize.LARGE,
72
- instanceOperatingSystem: LinuxFlavorType.UBUNTU_22,
74
+ instanceOperatingSystem: LinuxFlavorType.UBUNTU_24,
73
75
  instanceCpuArchitecture: LinuxArchitectureType.ARM,
74
76
 
75
77
  // 👇🏽 or if you want to give the InstanceRole more permissions
@@ -261,6 +263,67 @@ Run integration tests with:
261
263
  npm run integ-test
262
264
  ```
263
265
 
266
+ ### Custom Installation Steps
267
+
268
+ Extend the standard VS Code Server installation with your own custom shell commands - perfect for installing workshop-specific tools, configuring development environments, or running setup scripts:
269
+
270
+ ```ts
271
+ new VSCodeServer(this, 'vscode', {
272
+ // Add custom installation steps that run after standard setup
273
+ customInstallSteps: [
274
+ {
275
+ name: 'InstallWorkshopTools',
276
+ commands: [
277
+ '#!/bin/bash',
278
+ 'echo "Installing workshop-specific tools"',
279
+
280
+ // Install additional software
281
+ 'curl -fsSL https://get.docker.com | sh',
282
+ 'usermod -aG docker ubuntu',
283
+
284
+ // Configure environment
285
+ 'echo "export WORKSHOP_ENV=production" >> /home/ubuntu/.bashrc',
286
+ ],
287
+ },
288
+ {
289
+ name: 'CloneStarterCode',
290
+ commands: [
291
+ '#!/bin/bash',
292
+ 'cd /home/ubuntu',
293
+ 'git clone https://github.com/my-org/workshop-starter.git',
294
+ 'chown -R ubuntu:ubuntu workshop-starter',
295
+ ],
296
+ },
297
+ ],
298
+ });
299
+ ```
300
+
301
+ **Key Features:**
302
+ - **Execute After Standard Setup**: Custom steps run after VS Code Server installation completes
303
+ - **Multiple Steps**: Add as many installation steps as needed, executed in order
304
+ - **Full Shell Access**: Run any shell commands with root privileges
305
+ - **Workshop-Friendly**: Pre-install tools, configure environments, or download starter code
306
+
307
+ **Common Use Cases:**
308
+ - Install additional development tools (Docker, kubectl, terraform)
309
+ - Configure workshop-specific environments and credentials
310
+ - Clone starter code repositories with specific permissions
311
+ - Set up databases or services required for training
312
+ - Download and prepare datasets or assets
313
+ - Configure IDE extensions or settings
314
+
315
+ **Supported Operating Systems:**
316
+ - Ubuntu 22/24/25
317
+ - Amazon Linux 2023
318
+
319
+ **Requirements:**
320
+ - Commands execute with root privileges during instance initialization
321
+ - Use absolute paths or ensure proper working directory context
322
+ - Consider idempotency if instance might be restarted
323
+ - Commands run synchronously in the order specified
324
+
325
+ For complete examples, see [examples/custom-install-steps/main.ts](./examples/custom-install-steps/main.ts).
326
+
264
327
  ## Solution Design
265
328
 
266
329
  <details>
@@ -37,7 +37,7 @@ export class AutoStopExampleStack extends Stack {
37
37
  instanceClass: ec2.InstanceClass.M7G,
38
38
  instanceSize: ec2.InstanceSize.XLARGE,
39
39
  instanceVolumeSize: 40,
40
- instanceOperatingSystem: LinuxFlavorType.UBUNTU_22,
40
+ instanceOperatingSystem: LinuxFlavorType.UBUNTU_24,
41
41
  instanceCpuArchitecture: LinuxArchitectureType.ARM,
42
42
 
43
43
  // 🔥 Auto-Stop Configuration
@@ -17,7 +17,7 @@ export class MyStack extends Stack {
17
17
  instanceVolumeSize: 8,
18
18
  instanceClass: ec2.InstanceClass.M7G,
19
19
  instanceSize: ec2.InstanceSize.LARGE,
20
- instanceOperatingSystem: LinuxFlavorType.UBUNTU_22,
20
+ instanceOperatingSystem: LinuxFlavorType.UBUNTU_24, // Supports UBUNTU_22, UBUNTU_24, UBUNTU_25, AMAZON_LINUX_2023
21
21
  instanceCpuArchitecture: LinuxArchitectureType.ARM,
22
22
 
23
23
  // 👇🏽 or if you want to give the InstanceRole more permissions
@@ -31,7 +31,29 @@ export class MyStack extends Stack {
31
31
  `arn:aws:codebuild:*:${Stack.of(this).account}:*/*`,
32
32
  ],
33
33
  }),
34
- ]
34
+ ],
35
+
36
+ // 👇🏽 Add custom installation steps to extend the standard setup
37
+ customInstallSteps: [
38
+ {
39
+ name: 'InstallCodeBuildTools',
40
+ commands: [
41
+ '#!/bin/bash',
42
+ 'echo "Installing CodeBuild-related tools..."',
43
+ // Install AWS CodeBuild local agent for testing
44
+ 'docker pull public.ecr.aws/codebuild/local-builds:latest',
45
+ // Create helper script
46
+ 'cat > /usr/local/bin/codebuild-local << EOF',
47
+ '#!/bin/bash',
48
+ 'docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock \\',
49
+ ' -e "IMAGE_NAME=public.ecr.aws/codebuild/local-builds:latest" \\',
50
+ ' public.ecr.aws/codebuild/local-builds:latest',
51
+ 'EOF',
52
+ 'chmod +x /usr/local/bin/codebuild-local',
53
+ 'echo "CodeBuild tools installed successfully"',
54
+ ],
55
+ },
56
+ ],
35
57
 
36
58
  // and more... 💡
37
59
  });
@@ -0,0 +1,201 @@
1
+ import { App, Stack, StackProps } from 'aws-cdk-lib';
2
+ import * as ec2 from 'aws-cdk-lib/aws-ec2';
3
+ import { Construct } from 'constructs';
4
+ import {
5
+ CustomInstallStep,
6
+ LinuxArchitectureType,
7
+ LinuxFlavorType,
8
+ VSCodeServer,
9
+ } from '../../src/index';
10
+
11
+ /**
12
+ * Example: VS Code Server with Custom Installation Steps
13
+ *
14
+ * This example demonstrates how to extend the standard VS Code Server installation
15
+ * with custom shell commands. Perfect for:
16
+ * - Installing workshop-specific tools
17
+ * - Configuring development environments
18
+ * - Running setup scripts
19
+ * - Preparing datasets or assets
20
+ * - Setting up databases or services
21
+ *
22
+ * All custom steps execute with root privileges after the standard installation completes.
23
+ */
24
+ export class CustomInstallStepsExampleStack extends Stack {
25
+ constructor(scope: Construct, id: string, props: StackProps = {}) {
26
+ super(scope, id, props);
27
+
28
+ // Define custom installation steps
29
+ const customSteps: CustomInstallStep[] = [
30
+ // Step 1: Install additional development tools
31
+ {
32
+ name: 'InstallDevelopmentTools',
33
+ commands: [
34
+ '#!/bin/bash',
35
+ 'set -e', // Exit on error
36
+ 'echo "Installing development tools..."',
37
+
38
+ // Install Docker (if not already installed)
39
+ 'if ! command -v docker &> /dev/null; then',
40
+ ' curl -fsSL https://get.docker.com | sh',
41
+ ' usermod -aG docker ubuntu',
42
+ ' systemctl enable docker',
43
+ ' systemctl start docker',
44
+ 'fi',
45
+
46
+ // Install kubectl
47
+ 'curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/arm64/kubectl"',
48
+ 'install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl',
49
+ 'rm kubectl',
50
+
51
+ // Install terraform
52
+ 'wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg',
53
+ 'echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hashicorp.list',
54
+ 'apt-get update && apt-get install -y terraform',
55
+
56
+ 'echo "Development tools installed successfully"',
57
+ ],
58
+ },
59
+
60
+ // Step 2: Configure workshop environment
61
+ {
62
+ name: 'ConfigureWorkshopEnvironment',
63
+ commands: [
64
+ '#!/bin/bash',
65
+ 'set -e',
66
+ 'echo "Configuring workshop environment..."',
67
+
68
+ // Set environment variables
69
+ 'cat >> /home/ubuntu/.bashrc << EOF',
70
+ '',
71
+ '# Workshop environment variables',
72
+ 'export WORKSHOP_NAME="AWS CDK Workshop"',
73
+ 'export WORKSHOP_VERSION="2.0"',
74
+ 'export AWS_REGION="${AWS::Region}"',
75
+ 'export AWS_ACCOUNT_ID="${AWS::AccountId}"',
76
+ '',
77
+ '# Custom aliases',
78
+ 'alias k="kubectl"',
79
+ 'alias tf="terraform"',
80
+ 'alias ll="ls -la"',
81
+ 'EOF',
82
+
83
+ // Create workshop directories
84
+ 'mkdir -p /home/ubuntu/workshop',
85
+ 'mkdir -p /home/ubuntu/workshop/code',
86
+ 'mkdir -p /home/ubuntu/workshop/data',
87
+
88
+ // Set proper ownership
89
+ 'chown -R ubuntu:ubuntu /home/ubuntu/workshop',
90
+ 'chown ubuntu:ubuntu /home/ubuntu/.bashrc',
91
+
92
+ 'echo "Workshop environment configured successfully"',
93
+ ],
94
+ },
95
+
96
+ // Step 3: Clone and prepare workshop starter code
97
+ {
98
+ name: 'PrepareWorkshopCode',
99
+ commands: [
100
+ '#!/bin/bash',
101
+ 'set -e',
102
+ 'echo "Preparing workshop starter code..."',
103
+
104
+ // Clone workshop repository
105
+ 'cd /home/ubuntu/workshop/code',
106
+ 'git clone https://github.com/aws-samples/aws-cdk-examples.git',
107
+
108
+ // Download sample datasets
109
+ 'cd /home/ubuntu/workshop/data',
110
+ 'curl -o sample-data.json https://raw.githubusercontent.com/aws-samples/aws-cdk-examples/main/package.json',
111
+
112
+ // Create a README for participants
113
+ 'cat > /home/ubuntu/workshop/README.md << EOF',
114
+ '# Welcome to the AWS CDK Workshop!',
115
+ '',
116
+ '## Getting Started',
117
+ '',
118
+ '1. Navigate to the code directory: `cd ~/workshop/code`',
119
+ '2. Explore the examples: `ls -la aws-cdk-examples`',
120
+ '3. Run your first CDK app',
121
+ '',
122
+ '## Resources',
123
+ '',
124
+ '- AWS CDK Documentation: https://docs.aws.amazon.com/cdk',
125
+ '- Workshop Guide: [TBD]',
126
+ '',
127
+ '## Installed Tools',
128
+ '',
129
+ '- Node.js $(node --version)',
130
+ '- Python $(python3 --version)',
131
+ '- Docker $(docker --version)',
132
+ '- kubectl $(kubectl version --client --short 2>/dev/null || echo "installed")',
133
+ '- Terraform $(terraform version | head -n1)',
134
+ 'EOF',
135
+
136
+ // Set ownership
137
+ 'chown -R ubuntu:ubuntu /home/ubuntu/workshop',
138
+
139
+ 'echo "Workshop code prepared successfully"',
140
+ ],
141
+ },
142
+
143
+ // Step 4: Install VS Code extensions
144
+ {
145
+ name: 'InstallVSCodeExtensions',
146
+ commands: [
147
+ '#!/bin/bash',
148
+ 'set -e',
149
+ 'echo "Installing VS Code extensions..."',
150
+
151
+ // Switch to ubuntu user to install extensions
152
+ 'sudo -u ubuntu bash << EOF',
153
+ 'export HOME=/home/ubuntu',
154
+
155
+ // Wait for code-server to be ready
156
+ 'sleep 5',
157
+
158
+ // Install useful extensions (examples - adjust based on your needs)
159
+ '# Note: Extension installation via CLI requires code-server to be running',
160
+ '# These would typically be installed through the VS Code UI after first login',
161
+
162
+ 'echo "VS Code extensions configured successfully"',
163
+ 'EOF',
164
+ ],
165
+ },
166
+ ];
167
+
168
+ // Create VS Code Server with custom installation steps
169
+ new VSCodeServer(this, 'vscode-custom-install', {
170
+ // Instance configuration
171
+ instanceClass: ec2.InstanceClass.M7G,
172
+ instanceSize: ec2.InstanceSize.XLARGE,
173
+ instanceVolumeSize: 50, // Larger volume for additional tools
174
+ instanceOperatingSystem: LinuxFlavorType.UBUNTU_24, // Supports UBUNTU_22, UBUNTU_24, UBUNTU_25, AMAZON_LINUX_2023
175
+ instanceCpuArchitecture: LinuxArchitectureType.ARM,
176
+
177
+ // VS Code configuration
178
+ homeFolder: '/workshop',
179
+ vscodeUser: 'ubuntu',
180
+
181
+ // 🔧 Custom installation steps
182
+ customInstallSteps: customSteps,
183
+
184
+ // Additional configuration
185
+ additionalTags: {
186
+ Workshop: 'AWS-CDK-Workshop',
187
+ Environment: 'Training',
188
+ CustomInstallSteps: 'Enabled',
189
+ },
190
+ });
191
+ }
192
+ }
193
+
194
+ const env = {
195
+ account: process.env.CDK_DEFAULT_ACCOUNT || '123456789012',
196
+ region: process.env.CDK_DEFAULT_REGION || 'eu-west-1',
197
+ };
198
+
199
+ const app = new App();
200
+ new CustomInstallStepsExampleStack(app, 'vscode-custom-install-example', { env });
201
+ app.synth();
@@ -14,7 +14,7 @@
14
14
  }
15
15
  }
16
16
  },
17
- "c0c8c31a0be065be2df21bb20ec386bf72819c1e19f79e9fc09c29712e67a4a0": {
17
+ "4191278decec94a8cb032ef5af5b2424a3d6f3a20772116b870ecb754d98bb76": {
18
18
  "displayName": "IntegSetupVSCodeOnCustomDomainDefaultTestDeployAssert6982D514 Template",
19
19
  "source": {
20
20
  "path": "IntegSetupVSCodeOnCustomDomainDefaultTestDeployAssert6982D514.template.json",
@@ -23,7 +23,7 @@
23
23
  "destinations": {
24
24
  "current_account-current_region": {
25
25
  "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
26
- "objectKey": "c0c8c31a0be065be2df21bb20ec386bf72819c1e19f79e9fc09c29712e67a4a0.json",
26
+ "objectKey": "4191278decec94a8cb032ef5af5b2424a3d6f3a20772116b870ecb754d98bb76.json",
27
27
  "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
28
28
  }
29
29
  }
@@ -41,7 +41,7 @@
41
41
  }
42
42
  },
43
43
  "flattenResponse": "false",
44
- "salt": "1762251890627"
44
+ "salt": "1762256639191"
45
45
  },
46
46
  "UpdateReplacePolicy": "Delete",
47
47
  "DeletionPolicy": "Delete"
@@ -113,7 +113,7 @@
113
113
  }
114
114
  }
115
115
  },
116
- "0d21ebe148c0168a894b38d8db4c34b6ac5b9a016612b7493c323c5d1dc23b7d": {
116
+ "7d89a55db29091c7bd6a0da54d0e29cfc725f77b6fcdde3eb3e136b774b01d04": {
117
117
  "displayName": "IntegTestStackCustomDomain Template",
118
118
  "source": {
119
119
  "path": "IntegTestStackCustomDomain.template.json",
@@ -122,7 +122,7 @@
122
122
  "destinations": {
123
123
  "current_account-current_region": {
124
124
  "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
125
- "objectKey": "0d21ebe148c0168a894b38d8db4c34b6ac5b9a016612b7493c323c5d1dc23b7d.json",
125
+ "objectKey": "7d89a55db29091c7bd6a0da54d0e29cfc725f77b6fcdde3eb3e136b774b01d04.json",
126
126
  "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
127
127
  }
128
128
  }
@@ -1418,7 +1418,7 @@
1418
1418
  "Ref": "IntegVSCodeServerserverinstanceInstanceProfile6130979E"
1419
1419
  },
1420
1420
  "ImageId": {
1421
- "Ref": "SsmParameterValueawsservicecanonicalubuntuserverjammystablecurrentarm64hvmebsgp2amiidC96584B6F00A464EAD1953AFF4B05118Parameter"
1421
+ "Ref": "SsmParameterValueawsservicecanonicalubuntuservernoblestablecurrentarm64hvmebsgp3amiidC96584B6F00A464EAD1953AFF4B05118Parameter"
1422
1422
  },
1423
1423
  "InstanceType": "m7g.xlarge",
1424
1424
  "LaunchTemplate": {
@@ -2998,9 +2998,9 @@
2998
2998
  }
2999
2999
  },
3000
3000
  "Parameters": {
3001
- "SsmParameterValueawsservicecanonicalubuntuserverjammystablecurrentarm64hvmebsgp2amiidC96584B6F00A464EAD1953AFF4B05118Parameter": {
3001
+ "SsmParameterValueawsservicecanonicalubuntuservernoblestablecurrentarm64hvmebsgp3amiidC96584B6F00A464EAD1953AFF4B05118Parameter": {
3002
3002
  "Type": "AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>",
3003
- "Default": "/aws/service/canonical/ubuntu/server/jammy/stable/current/arm64/hvm/ebs-gp2/ami-id"
3003
+ "Default": "/aws/service/canonical/ubuntu/server/noble/stable/current/arm64/hvm/ebs-gp3/ami-id"
3004
3004
  },
3005
3005
  "BootstrapVersion": {
3006
3006
  "Type": "AWS::SSM::Parameter::Value<String>",
@@ -6,7 +6,7 @@
6
6
  "IntegTestStackCustomDomain"
7
7
  ],
8
8
  "regions": [
9
- "${Token[AWS.Region.8]}"
9
+ "${Token[AWS.Region.6]}"
10
10
  ],
11
11
  "cdkCommandOptions": {
12
12
  "destroy": {
@@ -18,7 +18,7 @@
18
18
  "validateOnSynth": false,
19
19
  "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
20
20
  "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
21
- "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/0d21ebe148c0168a894b38d8db4c34b6ac5b9a016612b7493c323c5d1dc23b7d.json",
21
+ "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/7d89a55db29091c7bd6a0da54d0e29cfc725f77b6fcdde3eb3e136b774b01d04.json",
22
22
  "requiresBootstrapStackVersion": 6,
23
23
  "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
24
24
  "additionalDependencies": [
@@ -902,7 +902,10 @@
902
902
  "/IntegTestStackCustomDomain/IntegVSCodeServer/server-instance/Resource": [
903
903
  {
904
904
  "type": "aws:cdk:logicalId",
905
- "data": "IntegVSCodeServerserverinstance0A3D62D7"
905
+ "data": "IntegVSCodeServerserverinstance0A3D62D7",
906
+ "trace": [
907
+ "!!DESTRUCTIVE_CHANGES: WILL_REPLACE"
908
+ ]
906
909
  }
907
910
  ],
908
911
  "/IntegTestStackCustomDomain/IntegVSCodeServer/server-instance/LaunchTemplate": [
@@ -1356,10 +1359,10 @@
1356
1359
  "data": "AWS679f53fac002430cb0da5b7982bd22872D164C4C"
1357
1360
  }
1358
1361
  ],
1359
- "/IntegTestStackCustomDomain/SsmParameterValue:--aws--service--canonical--ubuntu--server--jammy--stable--current--arm64--hvm--ebs-gp2--ami-id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter": [
1362
+ "/IntegTestStackCustomDomain/SsmParameterValue:--aws--service--canonical--ubuntu--server--noble--stable--current--arm64--hvm--ebs-gp3--ami-id:C96584B6-F00A-464E-AD19-53AFF4B05118.Parameter": [
1360
1363
  {
1361
1364
  "type": "aws:cdk:logicalId",
1362
- "data": "SsmParameterValueawsservicecanonicalubuntuserverjammystablecurrentarm64hvmebsgp2amiidC96584B6F00A464EAD1953AFF4B05118Parameter"
1365
+ "data": "SsmParameterValueawsservicecanonicalubuntuservernoblestablecurrentarm64hvmebsgp3amiidC96584B6F00A464EAD1953AFF4B05118Parameter"
1363
1366
  }
1364
1367
  ],
1365
1368
  "/IntegTestStackCustomDomain/AWSCloudFrontPartitionHostedZoneIdMap": [
@@ -1576,7 +1579,7 @@
1576
1579
  "validateOnSynth": false,
1577
1580
  "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
1578
1581
  "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
1579
- "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/c0c8c31a0be065be2df21bb20ec386bf72819c1e19f79e9fc09c29712e67a4a0.json",
1582
+ "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/4191278decec94a8cb032ef5af5b2424a3d6f3a20772116b870ecb754d98bb76.json",
1580
1583
  "requiresBootstrapStackVersion": 6,
1581
1584
  "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
1582
1585
  "additionalDependencies": [