@gugananuvem/aws-local-simulator 1.0.35 → 1.0.39

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 (149) hide show
  1. package/README.md +662 -658
  2. package/package.json +10 -3
  3. package/src/config/default-config.js +71 -0
  4. package/src/config/env-loader.js +4 -2
  5. package/src/middleware/authorization.js +271 -0
  6. package/src/middleware/cloudtrail-logger.js +333 -0
  7. package/src/middleware/error-handler.js +138 -0
  8. package/src/middleware/index.js +79 -0
  9. package/src/middleware/policy-enforcement.js +407 -0
  10. package/src/server.js +74 -4
  11. package/src/services/acm/index.js +66 -0
  12. package/src/services/acm/models/certificate.js +202 -0
  13. package/src/services/acm/server.js +224 -0
  14. package/src/services/acm/simulator.js +293 -0
  15. package/src/services/alb/index.js +104 -0
  16. package/src/services/alb/models/loadBalancer.js +88 -0
  17. package/src/services/alb/models/targetGroup.js +128 -0
  18. package/src/services/alb/server.js +160 -0
  19. package/src/services/alb/simulator.js +262 -0
  20. package/src/services/apigateway/index.js +22 -0
  21. package/src/services/apigateway/server.js +247 -35
  22. package/src/services/apigateway/simulator.js +780 -26
  23. package/src/services/asg/index.js +100 -0
  24. package/src/services/asg/models/autoScalingGroup.js +110 -0
  25. package/src/services/asg/models/launchTemplate.js +41 -0
  26. package/src/services/asg/models/scalingPolicy.js +51 -0
  27. package/src/services/asg/server.js +236 -0
  28. package/src/services/asg/simulator.js +410 -0
  29. package/src/services/aurora/cluster-manager.js +731 -0
  30. package/src/services/aurora/data-api.js +514 -0
  31. package/src/services/aurora/db-engine.js +270 -0
  32. package/src/services/aurora/index.js +159 -0
  33. package/src/services/aurora/rds-api.js +189 -0
  34. package/src/services/aurora/server.js +213 -0
  35. package/src/services/aurora/sql-translator.js +334 -0
  36. package/src/services/cloudformation/index.js +2 -2
  37. package/src/services/cloudformation/server.js +1 -0
  38. package/src/services/cloudfront/cache-engine.js +225 -0
  39. package/src/services/cloudfront/geo-restrictions.js +377 -0
  40. package/src/services/cloudfront/index.js +220 -0
  41. package/src/services/cloudfront/models/behavior.js +158 -0
  42. package/src/services/cloudfront/models/distribution.js +284 -0
  43. package/src/services/cloudfront/models/index.js +99 -0
  44. package/src/services/cloudfront/models/invalidation.js +109 -0
  45. package/src/services/cloudfront/models/origin.js +155 -0
  46. package/src/services/cloudfront/origin-router.js +552 -0
  47. package/src/services/cloudfront/origin-validator.js +398 -0
  48. package/src/services/cloudfront/server.js +512 -0
  49. package/src/services/cloudfront/signed-url-generator.js +377 -0
  50. package/src/services/cloudfront/simulator.js +425 -0
  51. package/src/services/cloudfront/store.js +326 -0
  52. package/src/services/cloudshell/env-builder.js +27 -0
  53. package/src/services/cloudshell/index.js +48 -0
  54. package/src/services/cloudshell/routes.js +60 -0
  55. package/src/services/cloudshell/session-manager.js +226 -0
  56. package/src/services/cloudshell/static/.gitkeep +0 -0
  57. package/src/services/cloudshell/static/index.html +406 -0
  58. package/src/services/cloudshell/websocket-handler.js +107 -0
  59. package/src/services/cloudtrail/index.js +2 -3
  60. package/src/services/cloudtrail/server.js +68 -0
  61. package/src/services/cognito/server.js +4 -1
  62. package/src/services/dynamodb/server.js +4 -1
  63. package/src/services/dynamodb/simulator.js +2 -1
  64. package/src/services/ec2/index.js +101 -0
  65. package/src/services/ec2/instanceServer.js +311 -0
  66. package/src/services/ec2/models/ami.js +39 -0
  67. package/src/services/ec2/models/instance.js +98 -0
  68. package/src/services/ec2/models/networkInterface.js +74 -0
  69. package/src/services/ec2/models/securityGroup.js +71 -0
  70. package/src/services/ec2/server.js +350 -0
  71. package/src/services/ec2/simulator.js +436 -0
  72. package/src/services/eventbridge/server.js +36 -0
  73. package/src/services/eventbridge/simulator.js +230 -45
  74. package/src/services/iam/index.js +65 -0
  75. package/src/services/iam/middleware.js +99 -0
  76. package/src/services/iam/server.js +331 -0
  77. package/src/services/iam/simulator.js +1432 -0
  78. package/src/services/index.js +28 -0
  79. package/src/services/kinesis-analytics/index.js +105 -0
  80. package/src/services/kinesis-analytics/models/application.js +325 -0
  81. package/src/services/kinesis-analytics/models/index.js +12 -0
  82. package/src/services/kinesis-analytics/server.js +250 -0
  83. package/src/services/kinesis-analytics/simulator.js +407 -0
  84. package/src/services/kinesis-analytics/store.js +176 -0
  85. package/src/services/kinesis-data-streams/index.js +106 -0
  86. package/src/services/kinesis-data-streams/models/index.js +12 -0
  87. package/src/services/kinesis-data-streams/models/record.js +70 -0
  88. package/src/services/kinesis-data-streams/models/stream.js +280 -0
  89. package/src/services/kinesis-data-streams/server.js +255 -0
  90. package/src/services/kinesis-data-streams/simulator.js +514 -0
  91. package/src/services/kinesis-data-streams/store.js +163 -0
  92. package/src/services/kinesis-firehose/index.js +106 -0
  93. package/src/services/kinesis-firehose/models/delivery-stream.js +265 -0
  94. package/src/services/kinesis-firehose/models/index.js +10 -0
  95. package/src/services/kinesis-firehose/server.js +215 -0
  96. package/src/services/kinesis-firehose/simulator.js +388 -0
  97. package/src/services/kinesis-firehose/store.js +163 -0
  98. package/src/services/kms/server.js +4 -1
  99. package/src/services/lambda/index.js +26 -0
  100. package/src/services/lambda/server.js +12 -1
  101. package/src/services/lambda/simulator.js +4 -0
  102. package/src/services/opensearch/index.js +105 -0
  103. package/src/services/opensearch/models/document.js +115 -0
  104. package/src/services/opensearch/models/index.js +73 -0
  105. package/src/services/opensearch/server.js +310 -0
  106. package/src/services/opensearch/simulator.js +605 -0
  107. package/src/services/opensearch/store.js +162 -0
  108. package/src/services/organizations/control-tower-simulator.js +321 -0
  109. package/src/services/organizations/control-tower-store.js +182 -0
  110. package/src/services/organizations/iam-integration.js +413 -0
  111. package/src/services/organizations/index.js +172 -0
  112. package/src/services/organizations/models/index.js +13 -0
  113. package/src/services/organizations/models/invitation.js +48 -0
  114. package/src/services/organizations/models/organization.js +566 -0
  115. package/src/services/organizations/models/role.js +244 -0
  116. package/src/services/organizations/models/scp.js +131 -0
  117. package/src/services/organizations/server.js +736 -0
  118. package/src/services/organizations/simulator.js +593 -0
  119. package/src/services/organizations/store.js +235 -0
  120. package/src/services/organizations/vpc-integration.js +453 -0
  121. package/src/services/route53/index.js +67 -0
  122. package/src/services/route53/models/healthCheck.js +101 -0
  123. package/src/services/route53/models/hostedZone.js +37 -0
  124. package/src/services/route53/models/resourceRecord.js +106 -0
  125. package/src/services/route53/server.js +841 -0
  126. package/src/services/route53/simulator.js +350 -0
  127. package/src/services/s3/index.js +62 -0
  128. package/src/services/s3/presigned-url-generator.js +337 -0
  129. package/src/services/s3/server.js +231 -0
  130. package/src/services/s3/simulator.js +551 -4
  131. package/src/services/sns/index.js +31 -0
  132. package/src/services/sns/server.js +9 -0
  133. package/src/services/sqs/index.js +38 -0
  134. package/src/services/sqs/server.js +57 -4
  135. package/src/services/sqs/simulator.js +423 -33
  136. package/src/services/sts/simulator.js +209 -17
  137. package/src/services/vpc/README.md +459 -0
  138. package/src/services/vpc/ec2ResponseFormatter.js +431 -0
  139. package/src/services/vpc/index.js +90 -0
  140. package/src/services/vpc/models/internetGateway.js +71 -0
  141. package/src/services/vpc/models/routeTable.js +160 -0
  142. package/src/services/vpc/models/subnet.js +48 -0
  143. package/src/services/vpc/models/vpc.js +37 -0
  144. package/src/services/vpc/models/vpcEndpoint.js +100 -0
  145. package/src/services/vpc/models/vpcGateway.js +134 -0
  146. package/src/services/vpc/server.js +836 -0
  147. package/src/services/vpc/simulator.js +613 -0
  148. package/src/utils/policy-cache.js +215 -0
  149. package/aws-config +0 -154
@@ -0,0 +1,100 @@
1
+ /**
2
+ * ASG Service - Ponto de entrada
3
+ */
4
+
5
+ const ASGServer = require('./server');
6
+ const ASGSimulator = require('./simulator');
7
+
8
+ class ASGService {
9
+ constructor(config) {
10
+ this.config = config;
11
+ this.name = 'asg';
12
+ this.port = config.ports.asg || 4022;
13
+ this.server = null;
14
+ this.simulator = null;
15
+ this.isRunning = false;
16
+ }
17
+
18
+ async initialize() {
19
+ const logger = require('../../utils/logger');
20
+ logger.debug(`Inicializando ASG Service na porta ${this.port}...`);
21
+
22
+ this.simulator = new ASGSimulator(this.config.asg || {});
23
+ await this.simulator.initialize();
24
+
25
+ this.server = new ASGServer(this.port, this.config);
26
+ this.server.simulator = this.simulator;
27
+
28
+ await this.server.initialize();
29
+
30
+ logger.debug('ASG Service inicializado');
31
+ }
32
+
33
+ injectDependencies(ec2Service, albService) {
34
+ // Injetar dependências para que o ASG possa criar/terminar instâncias
35
+ this.simulator.injectDependencies(ec2Service, albService);
36
+ }
37
+
38
+ async start() {
39
+ const logger = require('../../utils/logger');
40
+
41
+ if (this.isRunning) {
42
+ logger.warn('ASG Service já está em execução');
43
+ return;
44
+ }
45
+
46
+ try {
47
+ await this.server.start();
48
+ this.isRunning = true;
49
+ logger.info('ASG Service iniciado com sucesso');
50
+ } catch (error) {
51
+ logger.error(`Erro ao iniciar ASG Service: ${error.message}`);
52
+ throw error;
53
+ }
54
+ }
55
+
56
+ async stop() {
57
+ const logger = require('../../utils/logger');
58
+
59
+ if (!this.isRunning) {
60
+ logger.warn('ASG Service não está em execução');
61
+ return;
62
+ }
63
+
64
+ try {
65
+ await this.server.stop();
66
+ this.isRunning = false;
67
+ logger.info('ASG Service parado com sucesso');
68
+ } catch (error) {
69
+ logger.error(`Erro ao parar ASG Service: ${error.message}`);
70
+ throw error;
71
+ }
72
+ }
73
+
74
+ getSimulator() {
75
+ return this.simulator;
76
+ }
77
+
78
+ getStatus() {
79
+ const resources = this.simulator.getAllResources();
80
+ const totalInstances = resources.autoScalingGroups.reduce(
81
+ (sum, asg) => sum + asg.Instances.length,
82
+ 0
83
+ );
84
+
85
+ return {
86
+ name: this.name,
87
+ running: this.isRunning,
88
+ port: this.port,
89
+ endpoint: `http://localhost:${this.port}`,
90
+ resources: {
91
+ autoScalingGroupsCount: resources.autoScalingGroups.length,
92
+ launchTemplatesCount: resources.launchTemplates.length,
93
+ scalingPoliciesCount: resources.scalingPolicies.length,
94
+ totalInstances: totalInstances
95
+ }
96
+ };
97
+ }
98
+ }
99
+
100
+ module.exports = ASGService;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Auto Scaling Group Model
3
+ */
4
+
5
+ const { v4: uuid } = require('uuid');
6
+
7
+ class AutoScalingGroup {
8
+ constructor(name, launchTemplate, config = {}) {
9
+ this.AutoScalingGroupName = name;
10
+ this.AutoScalingGroupARN = `arn:aws:autoscaling:us-east-1:123456789012:autoScalingGroup:${uuid()}:autoScalingGroupName/${name}`;
11
+
12
+ // Launch Configuration
13
+ this.LaunchTemplate = launchTemplate;
14
+
15
+ // Capacity
16
+ this.MinSize = config.minSize || 1;
17
+ this.MaxSize = config.maxSize || 5;
18
+ this.DesiredCapacity = config.desiredCapacity || this.MinSize;
19
+ this.Instances = []; // Array de instanceIds gerenciados por esse ASG
20
+
21
+ // Subnets
22
+ this.VPCZoneIdentifier = config.vpcZoneIdentifier || [];
23
+ this.AvailabilityZones = config.availabilityZones || ['us-east-1a'];
24
+
25
+ // Target Groups (para ALB)
26
+ this.TargetGroupARNs = config.targetGroupARNs || [];
27
+ this.LoadBalancerNames = config.loadBalancerNames || [];
28
+
29
+ // Policies
30
+ this.HealthCheckType = config.healthCheckType || 'ELB';
31
+ this.HealthCheckGracePeriod = config.healthCheckGracePeriod || 300;
32
+
33
+ // Tags
34
+ this.Tags = config.tags || [];
35
+
36
+ // Scaling & Lifecycle
37
+ this.SuspendedProcesses = [];
38
+ this.EnabledMetrics = config.enabledMetrics || ['GroupInServiceInstances', 'GroupTerminatingInstances'];
39
+ this.CreationTime = new Date();
40
+ this.Status = 'Active';
41
+
42
+ // Internal tracking
43
+ this.lastScalingTime = new Date();
44
+ this.scalingPolicies = [];
45
+ }
46
+
47
+ toJSON() {
48
+ return {
49
+ AutoScalingGroupName: this.AutoScalingGroupName,
50
+ AutoScalingGroupARN: this.AutoScalingGroupARN,
51
+ LaunchTemplate: this.LaunchTemplate.toJSON(),
52
+ MinSize: this.MinSize,
53
+ MaxSize: this.MaxSize,
54
+ DesiredCapacity: this.DesiredCapacity,
55
+ Instances: this.Instances.map(inst => ({
56
+ InstanceId: inst.InstanceId,
57
+ InstanceType: inst.InstanceType,
58
+ AvailabilityZone: inst.AvailabilityZone,
59
+ LifecycleState: inst.LifecycleState,
60
+ HealthStatus: inst.HealthStatus
61
+ })),
62
+ VPCZoneIdentifier: this.VPCZoneIdentifier,
63
+ AvailabilityZones: this.AvailabilityZones,
64
+ TargetGroupARNs: this.TargetGroupARNs,
65
+ LoadBalancerNames: this.LoadBalancerNames,
66
+ HealthCheckType: this.HealthCheckType,
67
+ HealthCheckGracePeriod: this.HealthCheckGracePeriod,
68
+ Tags: this.Tags,
69
+ EnabledMetrics: this.EnabledMetrics,
70
+ CreationTime: this.CreationTime,
71
+ Status: this.Status
72
+ };
73
+ }
74
+
75
+ addInstance(instance) {
76
+ this.Instances.push({
77
+ InstanceId: instance.InstanceId,
78
+ InstanceType: instance.InstanceType,
79
+ AvailabilityZone: this.AvailabilityZones[0],
80
+ LifecycleState: 'InService',
81
+ HealthStatus: 'Healthy'
82
+ });
83
+ }
84
+
85
+ removeInstance(instanceId) {
86
+ this.Instances = this.Instances.filter(inst => inst.InstanceId !== instanceId);
87
+ }
88
+
89
+ getInstanceCount() {
90
+ return this.Instances.length;
91
+ }
92
+
93
+ canScaleUp() {
94
+ return this.getInstanceCount() < this.MaxSize;
95
+ }
96
+
97
+ canScaleDown() {
98
+ return this.getInstanceCount() > this.MinSize;
99
+ }
100
+
101
+ isBelowDesiredCapacity() {
102
+ return this.getInstanceCount() < this.DesiredCapacity;
103
+ }
104
+
105
+ isAboveDesiredCapacity() {
106
+ return this.getInstanceCount() > this.DesiredCapacity;
107
+ }
108
+ }
109
+
110
+ module.exports = AutoScalingGroup;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Launch Template Model - Template de configuração para ASG
3
+ */
4
+
5
+ const { v4: uuid } = require('uuid');
6
+
7
+ class LaunchTemplate {
8
+ constructor(name, imageId, instanceType, config = {}) {
9
+ this.LaunchTemplateId = uuid();
10
+ this.LaunchTemplateName = name;
11
+ this.ImageId = imageId;
12
+ this.InstanceType = instanceType;
13
+ this.KeyName = config.keyName || null;
14
+ this.SecurityGroupIds = config.securityGroupIds || [];
15
+ this.UserData = config.userData || null;
16
+ this.IamInstanceProfile = config.iamInstanceProfile || null;
17
+ this.Monitoring = config.monitoring || { Enabled: false };
18
+ this.TagSpecifications = config.tagSpecifications || [];
19
+ this.CreationTime = new Date();
20
+ this.VersionNumber = 1;
21
+ }
22
+
23
+ toJSON() {
24
+ return {
25
+ LaunchTemplateId: this.LaunchTemplateId,
26
+ LaunchTemplateName: this.LaunchTemplateName,
27
+ ImageId: this.ImageId,
28
+ InstanceType: this.InstanceType,
29
+ KeyName: this.KeyName,
30
+ SecurityGroupIds: this.SecurityGroupIds,
31
+ UserData: this.UserData,
32
+ IamInstanceProfile: this.IamInstanceProfile,
33
+ Monitoring: this.Monitoring,
34
+ TagSpecifications: this.TagSpecifications,
35
+ CreationTime: this.CreationTime,
36
+ VersionNumber: this.VersionNumber
37
+ };
38
+ }
39
+ }
40
+
41
+ module.exports = LaunchTemplate;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Scaling Policy Model - Política de escalamento automático
3
+ */
4
+
5
+ const { v4: uuid } = require('uuid');
6
+
7
+ class ScalingPolicy {
8
+ constructor(name, asgName, policyType, config = {}) {
9
+ this.PolicyName = name;
10
+ this.AutoScalingGroupName = asgName;
11
+ this.PolicyARN = `arn:aws:autoscaling:us-east-1:123456789012:scalingPolicy:${uuid()}:autoScalingGroupName/${asgName}:policyName/${name}`;
12
+ this.PolicyType = policyType; // 'TargetTrackingScaling', 'StepScaling', 'SimpleScaling'
13
+
14
+ // Target Tracking
15
+ this.TargetValue = config.targetValue || null;
16
+ this.PredefinedMetricSpecification = config.predefinedMetricSpecification || {
17
+ PredefinedMetricType: 'ASGAverageCPUUtilization'
18
+ };
19
+ this.ScaleOutCooldown = config.scaleOutCooldown || 300;
20
+ this.ScaleInCooldown = config.scaleInCooldown || 300;
21
+
22
+ // Step Scaling
23
+ this.AdjustmentType = config.adjustmentType || 'ChangeInCapacity';
24
+ this.MetricAggregationType = config.metricAggregationType || 'Average';
25
+ this.StepAdjustments = config.stepAdjustments || [];
26
+
27
+ // Common
28
+ this.Enabled = config.enabled !== false;
29
+ this.CreationTime = new Date();
30
+ }
31
+
32
+ toJSON() {
33
+ return {
34
+ PolicyName: this.PolicyName,
35
+ AutoScalingGroupName: this.AutoScalingGroupName,
36
+ PolicyARN: this.PolicyARN,
37
+ PolicyType: this.PolicyType,
38
+ TargetValue: this.TargetValue,
39
+ PredefinedMetricSpecification: this.PredefinedMetricSpecification,
40
+ ScaleOutCooldown: this.ScaleOutCooldown,
41
+ ScaleInCooldown: this.ScaleInCooldown,
42
+ AdjustmentType: this.AdjustmentType,
43
+ MetricAggregationType: this.MetricAggregationType,
44
+ StepAdjustments: this.StepAdjustments,
45
+ Enabled: this.Enabled,
46
+ CreationTime: this.CreationTime
47
+ };
48
+ }
49
+ }
50
+
51
+ module.exports = ScalingPolicy;
@@ -0,0 +1,236 @@
1
+ /**
2
+ * ASG Server - API REST para Auto Scaling Group
3
+ */
4
+
5
+ const express = require('express');
6
+ const logger = require('../../utils/logger');
7
+
8
+ class ASGServer {
9
+ constructor(port, config) {
10
+ this.port = port;
11
+ this.config = config;
12
+ this.app = express();
13
+ this.simulator = null;
14
+ }
15
+
16
+ setupMiddlewares() {
17
+ this.app.use(express.json());
18
+ this.app.use((req, res, next) => {
19
+ logger.debug(`ASG Request: ${req.method} ${req.path}`);
20
+ next();
21
+ });
22
+ }
23
+
24
+ async initialize() {
25
+ logger.debug(`Inicializando ASG Server na porta ${this.port}`);
26
+ this.setupMiddlewares();
27
+ this.setupRoutes();
28
+ }
29
+
30
+ setupRoutes() {
31
+ // ========== Launch Template ==========
32
+
33
+ // Create Launch Template
34
+ this.app.post('/__admin/asg/launch-templates/create', (req, res) => {
35
+ try {
36
+ const { Name, ImageId, InstanceType, ...config } = req.body;
37
+ if (!Name || !ImageId || !InstanceType) {
38
+ return res.status(400).json({ error: 'Name, ImageId, and InstanceType are required' });
39
+ }
40
+
41
+ const lt = this.simulator.createLaunchTemplate(Name, ImageId, InstanceType, config);
42
+ res.json({ LaunchTemplate: lt.toJSON() });
43
+ } catch (error) {
44
+ res.status(400).json({ error: error.message });
45
+ }
46
+ });
47
+
48
+ // Describe Launch Templates
49
+ this.app.get('/__admin/asg/launch-templates', (req, res) => {
50
+ try {
51
+ const lts = this.simulator.describeLaunchTemplates();
52
+ res.json({ LaunchTemplates: lts.map(lt => lt.toJSON()) });
53
+ } catch (error) {
54
+ res.status(400).json({ error: error.message });
55
+ }
56
+ });
57
+
58
+ // Get Launch Template
59
+ this.app.get('/__admin/asg/launch-templates/:templateId', (req, res) => {
60
+ try {
61
+ const lt = this.simulator.getLaunchTemplate(req.params.templateId);
62
+ res.json({ LaunchTemplate: lt.toJSON() });
63
+ } catch (error) {
64
+ res.status(404).json({ error: error.message });
65
+ }
66
+ });
67
+
68
+ // Delete Launch Template
69
+ this.app.delete('/__admin/asg/launch-templates/:templateId', (req, res) => {
70
+ try {
71
+ this.simulator.deleteLaunchTemplate(req.params.templateId);
72
+ res.json({ success: true });
73
+ } catch (error) {
74
+ res.status(400).json({ error: error.message });
75
+ }
76
+ });
77
+
78
+ // ========== Auto Scaling Group ==========
79
+
80
+ // Create Auto Scaling Group
81
+ this.app.post('/__admin/asg/auto-scaling-groups/create', (req, res) => {
82
+ try {
83
+ const { AutoScalingGroupName, LaunchTemplateId, ...config } = req.body;
84
+ if (!AutoScalingGroupName || !LaunchTemplateId) {
85
+ return res.status(400).json({
86
+ error: 'AutoScalingGroupName and LaunchTemplateId are required'
87
+ });
88
+ }
89
+
90
+ const asg = this.simulator.createAutoScalingGroup(AutoScalingGroupName, LaunchTemplateId, config);
91
+ res.json({ AutoScalingGroup: asg.toJSON() });
92
+ } catch (error) {
93
+ res.status(400).json({ error: error.message });
94
+ }
95
+ });
96
+
97
+ // Describe Auto Scaling Groups
98
+ this.app.get('/__admin/asg/auto-scaling-groups', (req, res) => {
99
+ try {
100
+ const asgs = this.simulator.describeAutoScalingGroups();
101
+ res.json({ AutoScalingGroups: asgs.map(asg => asg.toJSON()) });
102
+ } catch (error) {
103
+ res.status(400).json({ error: error.message });
104
+ }
105
+ });
106
+
107
+ // Get Auto Scaling Group
108
+ this.app.get('/__admin/asg/auto-scaling-groups/:name', (req, res) => {
109
+ try {
110
+ const asg = this.simulator.getAutoScalingGroup(req.params.name);
111
+ res.json({ AutoScalingGroup: asg.toJSON() });
112
+ } catch (error) {
113
+ res.status(404).json({ error: error.message });
114
+ }
115
+ });
116
+
117
+ // Delete Auto Scaling Group
118
+ this.app.delete('/__admin/asg/auto-scaling-groups/:name', (req, res) => {
119
+ try {
120
+ const forceDelete = req.query.forceDelete === 'true';
121
+ this.simulator.deleteAutoScalingGroup(req.params.name, forceDelete);
122
+ res.json({ success: true });
123
+ } catch (error) {
124
+ res.status(400).json({ error: error.message });
125
+ }
126
+ });
127
+
128
+ // ========== Scaling Operations ==========
129
+
130
+ // Set Desired Capacity
131
+ this.app.put('/__admin/asg/auto-scaling-groups/:name/desired-capacity', (req, res) => {
132
+ try {
133
+ const { DesiredCapacity } = req.body;
134
+ if (DesiredCapacity === undefined) {
135
+ return res.status(400).json({ error: 'DesiredCapacity is required' });
136
+ }
137
+
138
+ const asg = this.simulator.setDesiredCapacity(req.params.name, DesiredCapacity);
139
+ res.json({ AutoScalingGroup: asg.toJSON() });
140
+ } catch (error) {
141
+ res.status(400).json({ error: error.message });
142
+ }
143
+ });
144
+
145
+ // ========== Scaling Policies ==========
146
+
147
+ // Attach Scaling Policy
148
+ this.app.post('/__admin/asg/auto-scaling-groups/:name/scaling-policies', (req, res) => {
149
+ try {
150
+ const { PolicyName, PolicyType, ...config } = req.body;
151
+ if (!PolicyName || !PolicyType) {
152
+ return res.status(400).json({ error: 'PolicyName and PolicyType are required' });
153
+ }
154
+
155
+ const policy = this.simulator.attachScalingPolicy(req.params.name, PolicyName, PolicyType, config);
156
+ res.json({ ScalingPolicy: policy.toJSON() });
157
+ } catch (error) {
158
+ res.status(400).json({ error: error.message });
159
+ }
160
+ });
161
+
162
+ // Describe Scaling Policies
163
+ this.app.get('/__admin/asg/auto-scaling-groups/:name/scaling-policies', (req, res) => {
164
+ try {
165
+ const policies = this.simulator.describeScalingPolicies(req.params.name);
166
+ res.json({ ScalingPolicies: policies.map(p => p.toJSON()) });
167
+ } catch (error) {
168
+ res.status(400).json({ error: error.message });
169
+ }
170
+ });
171
+
172
+ // Detach Scaling Policy
173
+ this.app.delete('/__admin/asg/auto-scaling-groups/:name/scaling-policies/:policyName', (req, res) => {
174
+ try {
175
+ this.simulator.detachScalingPolicy(req.params.name, req.params.policyName);
176
+ res.json({ success: true });
177
+ } catch (error) {
178
+ res.status(400).json({ error: error.message });
179
+ }
180
+ });
181
+
182
+ // Evaluate Scaling Policies (manual trigger)
183
+ this.app.post('/__admin/asg/auto-scaling-groups/:name/evaluate-policies', (req, res) => {
184
+ try {
185
+ this.simulator.evaluateScalingPolicies(req.params.name);
186
+ const asg = this.simulator.getAutoScalingGroup(req.params.name);
187
+ res.json({ AutoScalingGroup: asg.toJSON() });
188
+ } catch (error) {
189
+ res.status(400).json({ error: error.message });
190
+ }
191
+ });
192
+
193
+ // ========== Health & Admin ==========
194
+
195
+ // Health Check
196
+ this.app.get('/__admin/asg/health', (req, res) => {
197
+ res.json({ status: 'ok', service: 'asg' });
198
+ });
199
+
200
+ // Get All Resources
201
+ this.app.get('/__admin/asg/resources', (req, res) => {
202
+ try {
203
+ const resources = this.simulator.getAllResources();
204
+ res.json({
205
+ autoScalingGroups: resources.autoScalingGroups.map(a => a.toJSON()),
206
+ launchTemplates: resources.launchTemplates.map(lt => lt.toJSON()),
207
+ scalingPolicies: resources.scalingPolicies.map(p => p.toJSON())
208
+ });
209
+ } catch (error) {
210
+ res.status(400).json({ error: error.message });
211
+ }
212
+ });
213
+ }
214
+
215
+ async start() {
216
+ return new Promise((resolve) => {
217
+ this.server = this.app.listen(this.port, () => {
218
+ logger.info(`ASG Server running on http://localhost:${this.port}`);
219
+ resolve();
220
+ });
221
+ });
222
+ }
223
+
224
+ async stop() {
225
+ if (this.server) {
226
+ return new Promise((resolve) => {
227
+ this.server.close(() => {
228
+ logger.info('ASG Server stopped');
229
+ resolve();
230
+ });
231
+ });
232
+ }
233
+ }
234
+ }
235
+
236
+ module.exports = ASGServer;