@friggframework/devtools 2.0.0--canary.461.3d6d8ad.0 → 2.0.0--canary.461.5100cd8.0
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.
|
@@ -309,6 +309,17 @@ class MigrationBuilder extends InfrastructureBuilder {
|
|
|
309
309
|
|
|
310
310
|
console.log(' ✓ Added S3_BUCKET_NAME, DB_MIGRATION_QUEUE_URL, and DB_TYPE environment variables');
|
|
311
311
|
|
|
312
|
+
// Add worker function name to router environment (for Lambda invocation)
|
|
313
|
+
// Router needs this to invoke worker for database state checks
|
|
314
|
+
if (!result.functions.dbMigrationRouter.environment) {
|
|
315
|
+
result.functions.dbMigrationRouter.environment = {};
|
|
316
|
+
}
|
|
317
|
+
result.functions.dbMigrationRouter.environment.WORKER_FUNCTION_NAME = {
|
|
318
|
+
Ref: 'DbMigrationWorkerLambdaFunction',
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
console.log(' ✓ Added WORKER_FUNCTION_NAME environment variable to router');
|
|
322
|
+
|
|
312
323
|
// Add IAM permissions for SQS
|
|
313
324
|
result.iamStatements.push({
|
|
314
325
|
Effect: 'Allow',
|
|
@@ -354,6 +365,16 @@ class MigrationBuilder extends InfrastructureBuilder {
|
|
|
354
365
|
|
|
355
366
|
console.log(' ✓ Added S3 IAM permissions for migration status tracking');
|
|
356
367
|
|
|
368
|
+
// Add IAM permission for router to invoke worker Lambda
|
|
369
|
+
// Router invokes worker for database state checks (keeps router lightweight)
|
|
370
|
+
result.iamStatements.push({
|
|
371
|
+
Effect: 'Allow',
|
|
372
|
+
Action: ['lambda:InvokeFunction'],
|
|
373
|
+
Resource: { 'Fn::GetAtt': ['DbMigrationWorkerLambdaFunction', 'Arn'] },
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
console.log(' ✓ Added Lambda invocation permissions for router → worker');
|
|
377
|
+
|
|
357
378
|
console.log(`[${this.name}] ✅ Migration infrastructure configuration completed`);
|
|
358
379
|
return result;
|
|
359
380
|
}
|
|
@@ -90,7 +90,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
90
90
|
if (appDefinition.vpc?.subnets?.management) ignoredOptions.push('vpc.subnets.management');
|
|
91
91
|
if (appDefinition.vpc?.natGateway?.management) ignoredOptions.push('vpc.natGateway.management');
|
|
92
92
|
if (appDefinition.vpc?.shareAcrossStages !== undefined) ignoredOptions.push('vpc.shareAcrossStages');
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
if (ignoredOptions.length > 0) {
|
|
95
95
|
console.log(` ⚠️ managementMode='managed' ignoring: ${ignoredOptions.join(', ')}`);
|
|
96
96
|
}
|
|
@@ -134,13 +134,13 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
134
134
|
if (globalMode === 'managed') {
|
|
135
135
|
// Warn about ignored granular options
|
|
136
136
|
this.warnIgnoredOptions(appDefinition);
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
// Clear granular options to prevent conflicts
|
|
139
139
|
delete appDefinition.vpc.management;
|
|
140
140
|
if (appDefinition.vpc.subnets) delete appDefinition.vpc.subnets.management;
|
|
141
141
|
if (appDefinition.vpc.natGateway) delete appDefinition.vpc.natGateway.management;
|
|
142
142
|
delete appDefinition.vpc.shareAcrossStages;
|
|
143
|
-
|
|
143
|
+
|
|
144
144
|
// Set management based on isolation strategy
|
|
145
145
|
if (vpcIsolation === 'isolated') {
|
|
146
146
|
management = 'create-new';
|
|
@@ -158,7 +158,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
158
158
|
// Legacy shareAcrossStages support (backwards compatibility)
|
|
159
159
|
management = appDefinition.vpc.shareAcrossStages ? 'discover' : 'create-new';
|
|
160
160
|
console.log(` VPC Sharing: ${appDefinition.vpc.shareAcrossStages ? 'shared' : 'isolated'} (translated to ${management})`);
|
|
161
|
-
|
|
161
|
+
|
|
162
162
|
if (!appDefinition.vpc.shareAcrossStages && !appDefinition.vpc.natGateway?.management) {
|
|
163
163
|
appDefinition.vpc.natGateway = appDefinition.vpc.natGateway || {};
|
|
164
164
|
appDefinition.vpc.natGateway.management = 'createAndManage';
|
|
@@ -167,7 +167,7 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
167
167
|
} else {
|
|
168
168
|
management = management || 'discover';
|
|
169
169
|
}
|
|
170
|
-
|
|
170
|
+
|
|
171
171
|
console.log(` VPC Management Mode: ${management}`);
|
|
172
172
|
|
|
173
173
|
// Handle self-healing if enabled
|
|
@@ -463,8 +463,8 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
463
463
|
|
|
464
464
|
const subnetVpcId = vpcManagement === 'create-new' ? { Ref: 'FriggVPC' } : result.vpcId;
|
|
465
465
|
|
|
466
|
-
// Generate CIDRs
|
|
467
|
-
const cidrs = this.generateSubnetCidrs(vpcManagement);
|
|
466
|
+
// Generate CIDRs - pass discovered resources to avoid conflicts
|
|
467
|
+
const cidrs = this.generateSubnetCidrs(vpcManagement, discoveredResources);
|
|
468
468
|
|
|
469
469
|
// Private Subnet 1
|
|
470
470
|
result.resources.FriggPrivateSubnet1 = {
|
|
@@ -597,8 +597,9 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
597
597
|
|
|
598
598
|
/**
|
|
599
599
|
* Generate subnet CIDR blocks
|
|
600
|
+
* Finds available CIDRs that don't conflict with existing subnets
|
|
600
601
|
*/
|
|
601
|
-
generateSubnetCidrs(vpcManagement) {
|
|
602
|
+
generateSubnetCidrs(vpcManagement, discoveredResources) {
|
|
602
603
|
if (vpcManagement === 'create-new') {
|
|
603
604
|
// Use CloudFormation Fn::Cidr for dynamic generation
|
|
604
605
|
return {
|
|
@@ -608,13 +609,47 @@ class VpcBuilder extends InfrastructureBuilder {
|
|
|
608
609
|
public2: { 'Fn::Select': [3, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }] },
|
|
609
610
|
};
|
|
610
611
|
} else {
|
|
611
|
-
//
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
612
|
+
// Find available CIDRs for existing VPC by checking existing subnets
|
|
613
|
+
const existingCidrs = new Set();
|
|
614
|
+
|
|
615
|
+
// Collect all existing subnet CIDRs
|
|
616
|
+
if (discoveredResources?.subnets) {
|
|
617
|
+
for (const subnet of discoveredResources.subnets) {
|
|
618
|
+
if (subnet.CidrBlock) {
|
|
619
|
+
existingCidrs.add(subnet.CidrBlock);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
console.log(` Found ${existingCidrs.size} existing subnet CIDRs in VPC`);
|
|
625
|
+
|
|
626
|
+
// Generate candidates in the default VPC range (172.31.0.0/16)
|
|
627
|
+
// Private subnets: 240-249, Public subnets: 250-255
|
|
628
|
+
const findAvailableCidr = (startOctet, endOctet) => {
|
|
629
|
+
for (let octet = startOctet; octet <= endOctet; octet++) {
|
|
630
|
+
const candidate = `172.31.${octet}.0/24`;
|
|
631
|
+
if (!existingCidrs.has(candidate)) {
|
|
632
|
+
existingCidrs.add(candidate); // Mark as used immediately
|
|
633
|
+
return candidate;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
// Fallback if range exhausted
|
|
637
|
+
return `172.31.${startOctet}.0/24`;
|
|
617
638
|
};
|
|
639
|
+
|
|
640
|
+
const privateRange = { start: 240, end: 249 };
|
|
641
|
+
const publicRange = { start: 250, end: 255 };
|
|
642
|
+
|
|
643
|
+
const cidrs = {
|
|
644
|
+
private1: findAvailableCidr(privateRange.start, privateRange.end),
|
|
645
|
+
private2: findAvailableCidr(privateRange.start, privateRange.end),
|
|
646
|
+
public1: findAvailableCidr(publicRange.start, publicRange.end),
|
|
647
|
+
public2: findAvailableCidr(publicRange.start, publicRange.end),
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
console.log(` Using available CIDRs: ${Object.values(cidrs).join(', ')}`);
|
|
651
|
+
|
|
652
|
+
return cidrs;
|
|
618
653
|
}
|
|
619
654
|
}
|
|
620
655
|
|
|
@@ -840,7 +840,7 @@ describe('VpcBuilder', () => {
|
|
|
840
840
|
// Should create new isolated VPC
|
|
841
841
|
expect(result.vpcId).toEqual({ Ref: 'FriggVPC' });
|
|
842
842
|
expect(result.resources.FriggVPC).toBeDefined();
|
|
843
|
-
|
|
843
|
+
|
|
844
844
|
// Subnets should use CloudFormation Fn::Cidr
|
|
845
845
|
expect(result.resources.FriggPrivateSubnet1.Properties.CidrBlock).toEqual({
|
|
846
846
|
'Fn::Select': [0, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
|
|
@@ -875,7 +875,7 @@ describe('VpcBuilder', () => {
|
|
|
875
875
|
// Should discover existing VPC
|
|
876
876
|
expect(result.vpcId).toBe('vpc-existing');
|
|
877
877
|
expect(result.resources.FriggVPC).toBeUndefined();
|
|
878
|
-
|
|
878
|
+
|
|
879
879
|
// Should create new stage-specific subnets
|
|
880
880
|
expect(result.resources.FriggPrivateSubnet1).toBeDefined();
|
|
881
881
|
|
|
@@ -983,6 +983,93 @@ describe('VpcBuilder', () => {
|
|
|
983
983
|
});
|
|
984
984
|
});
|
|
985
985
|
|
|
986
|
+
describe('generateSubnetCidrs()', () => {
|
|
987
|
+
it('should use CloudFormation Fn::Cidr for create-new mode', () => {
|
|
988
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('create-new', {});
|
|
989
|
+
|
|
990
|
+
expect(cidrs.private1).toEqual({
|
|
991
|
+
'Fn::Select': [0, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
|
|
992
|
+
});
|
|
993
|
+
expect(cidrs.private2).toEqual({
|
|
994
|
+
'Fn::Select': [1, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
|
|
995
|
+
});
|
|
996
|
+
expect(cidrs.public1).toEqual({
|
|
997
|
+
'Fn::Select': [2, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
|
|
998
|
+
});
|
|
999
|
+
expect(cidrs.public2).toEqual({
|
|
1000
|
+
'Fn::Select': [3, { 'Fn::Cidr': ['10.0.0.0/16', 4, 8] }]
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
it('should use default static CIDRs when no existing subnets in VPC', () => {
|
|
1005
|
+
const discoveredResources = {
|
|
1006
|
+
subnets: []
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
|
|
1010
|
+
|
|
1011
|
+
expect(cidrs.private1).toBe('172.31.240.0/24');
|
|
1012
|
+
expect(cidrs.private2).toBe('172.31.241.0/24');
|
|
1013
|
+
expect(cidrs.public1).toBe('172.31.250.0/24');
|
|
1014
|
+
expect(cidrs.public2).toBe('172.31.251.0/24');
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
it('should avoid CIDR conflicts with existing subnets', () => {
|
|
1018
|
+
const discoveredResources = {
|
|
1019
|
+
subnets: [
|
|
1020
|
+
{ CidrBlock: '172.31.240.0/24' }, // Conflicts with default private1
|
|
1021
|
+
{ CidrBlock: '172.31.241.0/24' }, // Conflicts with default private2
|
|
1022
|
+
{ CidrBlock: '172.31.0.0/20' }, // Default VPC subnet
|
|
1023
|
+
{ CidrBlock: '172.31.16.0/20' }, // Default VPC subnet
|
|
1024
|
+
]
|
|
1025
|
+
};
|
|
1026
|
+
|
|
1027
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
|
|
1028
|
+
|
|
1029
|
+
// Should skip 240 and 241 (already taken), use 242-243 for private, 250-251 for public
|
|
1030
|
+
expect(cidrs.private1).toBe('172.31.242.0/24');
|
|
1031
|
+
expect(cidrs.private2).toBe('172.31.243.0/24');
|
|
1032
|
+
expect(cidrs.public1).toBe('172.31.250.0/24'); // Public range starts at 250
|
|
1033
|
+
expect(cidrs.public2).toBe('172.31.251.0/24');
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
it('should find first available CIDR blocks when some in range are taken', () => {
|
|
1037
|
+
const discoveredResources = {
|
|
1038
|
+
subnets: [
|
|
1039
|
+
{ CidrBlock: '172.31.240.0/24' },
|
|
1040
|
+
{ CidrBlock: '172.31.242.0/24' },
|
|
1041
|
+
{ CidrBlock: '172.31.244.0/24' },
|
|
1042
|
+
]
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
|
|
1046
|
+
|
|
1047
|
+
// Should use 241, 243 for private (filling gaps), 250, 251 for public
|
|
1048
|
+
expect(cidrs.private1).toBe('172.31.241.0/24');
|
|
1049
|
+
expect(cidrs.private2).toBe('172.31.243.0/24');
|
|
1050
|
+
expect(cidrs.public1).toBe('172.31.250.0/24'); // Public range starts at 250
|
|
1051
|
+
expect(cidrs.public2).toBe('172.31.251.0/24');
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
it('should handle missing discoveredResources gracefully', () => {
|
|
1055
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', null);
|
|
1056
|
+
|
|
1057
|
+
// Should fallback to default CIDRs
|
|
1058
|
+
expect(cidrs.private1).toBe('172.31.240.0/24');
|
|
1059
|
+
expect(cidrs.private2).toBe('172.31.241.0/24');
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
it('should handle discoveredResources without subnets array', () => {
|
|
1063
|
+
const discoveredResources = { vpcId: 'vpc-123' };
|
|
1064
|
+
|
|
1065
|
+
const cidrs = vpcBuilder.generateSubnetCidrs('discover', discoveredResources);
|
|
1066
|
+
|
|
1067
|
+
// Should fallback to default CIDRs
|
|
1068
|
+
expect(cidrs.private1).toBe('172.31.240.0/24');
|
|
1069
|
+
expect(cidrs.private2).toBe('172.31.241.0/24');
|
|
1070
|
+
});
|
|
1071
|
+
});
|
|
1072
|
+
|
|
986
1073
|
describe('Outputs', () => {
|
|
987
1074
|
it.skip('should generate VPC ID output', async () => {
|
|
988
1075
|
const appDefinition = {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.461.
|
|
4
|
+
"version": "2.0.0--canary.461.5100cd8.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-ec2": "^3.835.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.835.0",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"@babel/eslint-parser": "^7.18.9",
|
|
12
12
|
"@babel/parser": "^7.25.3",
|
|
13
13
|
"@babel/traverse": "^7.25.3",
|
|
14
|
-
"@friggframework/schemas": "2.0.0--canary.461.
|
|
15
|
-
"@friggframework/test": "2.0.0--canary.461.
|
|
14
|
+
"@friggframework/schemas": "2.0.0--canary.461.5100cd8.0",
|
|
15
|
+
"@friggframework/test": "2.0.0--canary.461.5100cd8.0",
|
|
16
16
|
"@hapi/boom": "^10.0.1",
|
|
17
17
|
"@inquirer/prompts": "^5.3.8",
|
|
18
18
|
"axios": "^1.7.2",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"serverless-http": "^2.7.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@friggframework/eslint-config": "2.0.0--canary.461.
|
|
38
|
-
"@friggframework/prettier-config": "2.0.0--canary.461.
|
|
37
|
+
"@friggframework/eslint-config": "2.0.0--canary.461.5100cd8.0",
|
|
38
|
+
"@friggframework/prettier-config": "2.0.0--canary.461.5100cd8.0",
|
|
39
39
|
"aws-sdk-client-mock": "^4.1.0",
|
|
40
40
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
41
41
|
"jest": "^30.1.3",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "5100cd81ceb3fe903e128b5f9530e09cb3e89495"
|
|
74
74
|
}
|