@gugananuvem/aws-local-simulator 1.0.34 → 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 (150) hide show
  1. package/README.md +662 -658
  2. package/package.json +11 -4
  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/handler-loader.js +50 -5
  100. package/src/services/lambda/index.js +26 -0
  101. package/src/services/lambda/server.js +18 -12
  102. package/src/services/lambda/simulator.js +73 -17
  103. package/src/services/opensearch/index.js +105 -0
  104. package/src/services/opensearch/models/document.js +115 -0
  105. package/src/services/opensearch/models/index.js +73 -0
  106. package/src/services/opensearch/server.js +310 -0
  107. package/src/services/opensearch/simulator.js +605 -0
  108. package/src/services/opensearch/store.js +162 -0
  109. package/src/services/organizations/control-tower-simulator.js +321 -0
  110. package/src/services/organizations/control-tower-store.js +182 -0
  111. package/src/services/organizations/iam-integration.js +413 -0
  112. package/src/services/organizations/index.js +172 -0
  113. package/src/services/organizations/models/index.js +13 -0
  114. package/src/services/organizations/models/invitation.js +48 -0
  115. package/src/services/organizations/models/organization.js +566 -0
  116. package/src/services/organizations/models/role.js +244 -0
  117. package/src/services/organizations/models/scp.js +131 -0
  118. package/src/services/organizations/server.js +736 -0
  119. package/src/services/organizations/simulator.js +593 -0
  120. package/src/services/organizations/store.js +235 -0
  121. package/src/services/organizations/vpc-integration.js +453 -0
  122. package/src/services/route53/index.js +67 -0
  123. package/src/services/route53/models/healthCheck.js +101 -0
  124. package/src/services/route53/models/hostedZone.js +37 -0
  125. package/src/services/route53/models/resourceRecord.js +106 -0
  126. package/src/services/route53/server.js +841 -0
  127. package/src/services/route53/simulator.js +350 -0
  128. package/src/services/s3/index.js +62 -0
  129. package/src/services/s3/presigned-url-generator.js +337 -0
  130. package/src/services/s3/server.js +231 -0
  131. package/src/services/s3/simulator.js +551 -4
  132. package/src/services/sns/index.js +31 -0
  133. package/src/services/sns/server.js +9 -0
  134. package/src/services/sqs/index.js +38 -0
  135. package/src/services/sqs/server.js +57 -4
  136. package/src/services/sqs/simulator.js +423 -33
  137. package/src/services/sts/simulator.js +209 -17
  138. package/src/services/vpc/README.md +459 -0
  139. package/src/services/vpc/ec2ResponseFormatter.js +431 -0
  140. package/src/services/vpc/index.js +90 -0
  141. package/src/services/vpc/models/internetGateway.js +71 -0
  142. package/src/services/vpc/models/routeTable.js +160 -0
  143. package/src/services/vpc/models/subnet.js +48 -0
  144. package/src/services/vpc/models/vpc.js +37 -0
  145. package/src/services/vpc/models/vpcEndpoint.js +100 -0
  146. package/src/services/vpc/models/vpcGateway.js +134 -0
  147. package/src/services/vpc/server.js +836 -0
  148. package/src/services/vpc/simulator.js +613 -0
  149. package/src/utils/policy-cache.js +215 -0
  150. 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;