@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.
- package/README.md +662 -658
- package/package.json +10 -3
- package/src/config/default-config.js +71 -0
- package/src/config/env-loader.js +4 -2
- package/src/middleware/authorization.js +271 -0
- package/src/middleware/cloudtrail-logger.js +333 -0
- package/src/middleware/error-handler.js +138 -0
- package/src/middleware/index.js +79 -0
- package/src/middleware/policy-enforcement.js +407 -0
- package/src/server.js +74 -4
- package/src/services/acm/index.js +66 -0
- package/src/services/acm/models/certificate.js +202 -0
- package/src/services/acm/server.js +224 -0
- package/src/services/acm/simulator.js +293 -0
- package/src/services/alb/index.js +104 -0
- package/src/services/alb/models/loadBalancer.js +88 -0
- package/src/services/alb/models/targetGroup.js +128 -0
- package/src/services/alb/server.js +160 -0
- package/src/services/alb/simulator.js +262 -0
- package/src/services/apigateway/index.js +22 -0
- package/src/services/apigateway/server.js +247 -35
- package/src/services/apigateway/simulator.js +780 -26
- package/src/services/asg/index.js +100 -0
- package/src/services/asg/models/autoScalingGroup.js +110 -0
- package/src/services/asg/models/launchTemplate.js +41 -0
- package/src/services/asg/models/scalingPolicy.js +51 -0
- package/src/services/asg/server.js +236 -0
- package/src/services/asg/simulator.js +410 -0
- package/src/services/aurora/cluster-manager.js +731 -0
- package/src/services/aurora/data-api.js +514 -0
- package/src/services/aurora/db-engine.js +270 -0
- package/src/services/aurora/index.js +159 -0
- package/src/services/aurora/rds-api.js +189 -0
- package/src/services/aurora/server.js +213 -0
- package/src/services/aurora/sql-translator.js +334 -0
- package/src/services/cloudformation/index.js +2 -2
- package/src/services/cloudformation/server.js +1 -0
- package/src/services/cloudfront/cache-engine.js +225 -0
- package/src/services/cloudfront/geo-restrictions.js +377 -0
- package/src/services/cloudfront/index.js +220 -0
- package/src/services/cloudfront/models/behavior.js +158 -0
- package/src/services/cloudfront/models/distribution.js +284 -0
- package/src/services/cloudfront/models/index.js +99 -0
- package/src/services/cloudfront/models/invalidation.js +109 -0
- package/src/services/cloudfront/models/origin.js +155 -0
- package/src/services/cloudfront/origin-router.js +552 -0
- package/src/services/cloudfront/origin-validator.js +398 -0
- package/src/services/cloudfront/server.js +512 -0
- package/src/services/cloudfront/signed-url-generator.js +377 -0
- package/src/services/cloudfront/simulator.js +425 -0
- package/src/services/cloudfront/store.js +326 -0
- package/src/services/cloudshell/env-builder.js +27 -0
- package/src/services/cloudshell/index.js +48 -0
- package/src/services/cloudshell/routes.js +60 -0
- package/src/services/cloudshell/session-manager.js +226 -0
- package/src/services/cloudshell/static/.gitkeep +0 -0
- package/src/services/cloudshell/static/index.html +406 -0
- package/src/services/cloudshell/websocket-handler.js +107 -0
- package/src/services/cloudtrail/index.js +2 -3
- package/src/services/cloudtrail/server.js +68 -0
- package/src/services/cognito/server.js +4 -1
- package/src/services/dynamodb/server.js +4 -1
- package/src/services/dynamodb/simulator.js +2 -1
- package/src/services/ec2/index.js +101 -0
- package/src/services/ec2/instanceServer.js +311 -0
- package/src/services/ec2/models/ami.js +39 -0
- package/src/services/ec2/models/instance.js +98 -0
- package/src/services/ec2/models/networkInterface.js +74 -0
- package/src/services/ec2/models/securityGroup.js +71 -0
- package/src/services/ec2/server.js +350 -0
- package/src/services/ec2/simulator.js +436 -0
- package/src/services/eventbridge/server.js +36 -0
- package/src/services/eventbridge/simulator.js +230 -45
- package/src/services/iam/index.js +65 -0
- package/src/services/iam/middleware.js +99 -0
- package/src/services/iam/server.js +331 -0
- package/src/services/iam/simulator.js +1432 -0
- package/src/services/index.js +28 -0
- package/src/services/kinesis-analytics/index.js +105 -0
- package/src/services/kinesis-analytics/models/application.js +325 -0
- package/src/services/kinesis-analytics/models/index.js +12 -0
- package/src/services/kinesis-analytics/server.js +250 -0
- package/src/services/kinesis-analytics/simulator.js +407 -0
- package/src/services/kinesis-analytics/store.js +176 -0
- package/src/services/kinesis-data-streams/index.js +106 -0
- package/src/services/kinesis-data-streams/models/index.js +12 -0
- package/src/services/kinesis-data-streams/models/record.js +70 -0
- package/src/services/kinesis-data-streams/models/stream.js +280 -0
- package/src/services/kinesis-data-streams/server.js +255 -0
- package/src/services/kinesis-data-streams/simulator.js +514 -0
- package/src/services/kinesis-data-streams/store.js +163 -0
- package/src/services/kinesis-firehose/index.js +106 -0
- package/src/services/kinesis-firehose/models/delivery-stream.js +265 -0
- package/src/services/kinesis-firehose/models/index.js +10 -0
- package/src/services/kinesis-firehose/server.js +215 -0
- package/src/services/kinesis-firehose/simulator.js +388 -0
- package/src/services/kinesis-firehose/store.js +163 -0
- package/src/services/kms/server.js +4 -1
- package/src/services/lambda/index.js +26 -0
- package/src/services/lambda/server.js +12 -1
- package/src/services/lambda/simulator.js +4 -0
- package/src/services/opensearch/index.js +105 -0
- package/src/services/opensearch/models/document.js +115 -0
- package/src/services/opensearch/models/index.js +73 -0
- package/src/services/opensearch/server.js +310 -0
- package/src/services/opensearch/simulator.js +605 -0
- package/src/services/opensearch/store.js +162 -0
- package/src/services/organizations/control-tower-simulator.js +321 -0
- package/src/services/organizations/control-tower-store.js +182 -0
- package/src/services/organizations/iam-integration.js +413 -0
- package/src/services/organizations/index.js +172 -0
- package/src/services/organizations/models/index.js +13 -0
- package/src/services/organizations/models/invitation.js +48 -0
- package/src/services/organizations/models/organization.js +566 -0
- package/src/services/organizations/models/role.js +244 -0
- package/src/services/organizations/models/scp.js +131 -0
- package/src/services/organizations/server.js +736 -0
- package/src/services/organizations/simulator.js +593 -0
- package/src/services/organizations/store.js +235 -0
- package/src/services/organizations/vpc-integration.js +453 -0
- package/src/services/route53/index.js +67 -0
- package/src/services/route53/models/healthCheck.js +101 -0
- package/src/services/route53/models/hostedZone.js +37 -0
- package/src/services/route53/models/resourceRecord.js +106 -0
- package/src/services/route53/server.js +841 -0
- package/src/services/route53/simulator.js +350 -0
- package/src/services/s3/index.js +62 -0
- package/src/services/s3/presigned-url-generator.js +337 -0
- package/src/services/s3/server.js +231 -0
- package/src/services/s3/simulator.js +551 -4
- package/src/services/sns/index.js +31 -0
- package/src/services/sns/server.js +9 -0
- package/src/services/sqs/index.js +38 -0
- package/src/services/sqs/server.js +57 -4
- package/src/services/sqs/simulator.js +423 -33
- package/src/services/sts/simulator.js +209 -17
- package/src/services/vpc/README.md +459 -0
- package/src/services/vpc/ec2ResponseFormatter.js +431 -0
- package/src/services/vpc/index.js +90 -0
- package/src/services/vpc/models/internetGateway.js +71 -0
- package/src/services/vpc/models/routeTable.js +160 -0
- package/src/services/vpc/models/subnet.js +48 -0
- package/src/services/vpc/models/vpc.js +37 -0
- package/src/services/vpc/models/vpcEndpoint.js +100 -0
- package/src/services/vpc/models/vpcGateway.js +134 -0
- package/src/services/vpc/server.js +836 -0
- package/src/services/vpc/simulator.js +613 -0
- package/src/utils/policy-cache.js +215 -0
- package/aws-config +0 -154
|
@@ -0,0 +1,836 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VPC Server
|
|
3
|
+
* Gerencia o servidor HTTP e as rotas do VPC
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const express = require('express');
|
|
7
|
+
const logger = require('../../utils/logger');
|
|
8
|
+
const EC2ResponseFormatter = require('./ec2ResponseFormatter');
|
|
9
|
+
|
|
10
|
+
class VPCServer {
|
|
11
|
+
constructor(port, config) {
|
|
12
|
+
this.port = port;
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.app = express();
|
|
15
|
+
this.simulator = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setupMiddlewares() {
|
|
19
|
+
this.app.use(express.json());
|
|
20
|
+
this.app.use(express.urlencoded({ extended: true }));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async initialize() {
|
|
24
|
+
logger.debug(`Inicializando VPC Server na porta ${this.port}`);
|
|
25
|
+
this.setupMiddlewares();
|
|
26
|
+
this.setupRoutes();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setupRoutes() {
|
|
30
|
+
// ========== VPC Routes ==========
|
|
31
|
+
|
|
32
|
+
// Criar VPC
|
|
33
|
+
this.app.post('/__admin/vpcs/create', (req, res) => {
|
|
34
|
+
try {
|
|
35
|
+
const { CidrBlock, Tags, EnableDnsHostnames, EnableDnsSupport } = req.body;
|
|
36
|
+
|
|
37
|
+
if (!CidrBlock) {
|
|
38
|
+
return res.status(400).json({ error: 'CidrBlock is required' });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const vpc = this.simulator.createVPC(CidrBlock, Tags || [], {
|
|
42
|
+
EnableDnsHostnames,
|
|
43
|
+
EnableDnsSupport
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
res.json({ Vpc: vpc.toJSON() });
|
|
47
|
+
} catch (error) {
|
|
48
|
+
logger.error(`Error creating VPC: ${error.message}`);
|
|
49
|
+
res.status(400).json({ error: error.message });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Listar VPCs
|
|
54
|
+
this.app.get('/__admin/vpcs', (req, res) => {
|
|
55
|
+
try {
|
|
56
|
+
const filters = {};
|
|
57
|
+
if (req.query.vpcIds) {
|
|
58
|
+
filters.vpcIds = Array.isArray(req.query.vpcIds)
|
|
59
|
+
? req.query.vpcIds
|
|
60
|
+
: [req.query.vpcIds];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const vpcs = this.simulator.describeVPCs(filters);
|
|
64
|
+
res.json({ Vpcs: vpcs.map(v => v.toJSON()) });
|
|
65
|
+
} catch (error) {
|
|
66
|
+
logger.error(`Error listing VPCs: ${error.message}`);
|
|
67
|
+
res.status(400).json({ error: error.message });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Obter VPC específico
|
|
72
|
+
this.app.get('/__admin/vpcs/:vpcId', (req, res) => {
|
|
73
|
+
try {
|
|
74
|
+
const vpc = this.simulator.getVPC(req.params.vpcId);
|
|
75
|
+
res.json({ Vpc: vpc.toJSON() });
|
|
76
|
+
} catch (error) {
|
|
77
|
+
logger.error(`Error getting VPC: ${error.message}`);
|
|
78
|
+
res.status(404).json({ error: error.message });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Deletar VPC
|
|
83
|
+
this.app.delete('/__admin/vpcs/:vpcId', (req, res) => {
|
|
84
|
+
try {
|
|
85
|
+
this.simulator.deleteVPC(req.params.vpcId);
|
|
86
|
+
res.json({ success: true });
|
|
87
|
+
} catch (error) {
|
|
88
|
+
logger.error(`Error deleting VPC: ${error.message}`);
|
|
89
|
+
res.status(400).json({ error: error.message });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Modificar atributos VPC
|
|
94
|
+
this.app.post('/__admin/vpcs/:vpcId/attributes', (req, res) => {
|
|
95
|
+
try {
|
|
96
|
+
const { attribute, value } = req.body;
|
|
97
|
+
|
|
98
|
+
if (!attribute) {
|
|
99
|
+
return res.status(400).json({ error: 'Attribute is required' });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const vpc = this.simulator.modifyVPCAttribute(req.params.vpcId, attribute, value);
|
|
103
|
+
res.json({ Vpc: vpc.toJSON() });
|
|
104
|
+
} catch (error) {
|
|
105
|
+
logger.error(`Error modifying VPC attribute: ${error.message}`);
|
|
106
|
+
res.status(400).json({ error: error.message });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// ========== Subnet Routes ==========
|
|
111
|
+
|
|
112
|
+
// Criar Subnet
|
|
113
|
+
this.app.post('/__admin/subnets/create', (req, res) => {
|
|
114
|
+
try {
|
|
115
|
+
const { VpcId, CidrBlock, AvailabilityZone, Tags, MapPublicIpOnLaunch } = req.body;
|
|
116
|
+
|
|
117
|
+
if (!VpcId || !CidrBlock || !AvailabilityZone) {
|
|
118
|
+
return res
|
|
119
|
+
.status(400)
|
|
120
|
+
.json({ error: 'VpcId, CidrBlock and AvailabilityZone are required' });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const subnet = this.simulator.createSubnet(
|
|
124
|
+
VpcId,
|
|
125
|
+
CidrBlock,
|
|
126
|
+
AvailabilityZone,
|
|
127
|
+
Tags || [],
|
|
128
|
+
{ MapPublicIpOnLaunch }
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
res.json({ Subnet: subnet.toJSON() });
|
|
132
|
+
} catch (error) {
|
|
133
|
+
logger.error(`Error creating Subnet: ${error.message}`);
|
|
134
|
+
res.status(400).json({ error: error.message });
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Listar Subnets
|
|
139
|
+
this.app.get('/__admin/subnets', (req, res) => {
|
|
140
|
+
try {
|
|
141
|
+
const filters = {};
|
|
142
|
+
if (req.query.vpcIds) {
|
|
143
|
+
filters.vpcIds = Array.isArray(req.query.vpcIds)
|
|
144
|
+
? req.query.vpcIds
|
|
145
|
+
: [req.query.vpcIds];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const subnets = this.simulator.describeSubnets(filters);
|
|
149
|
+
res.json({ Subnets: subnets.map(s => s.toJSON()) });
|
|
150
|
+
} catch (error) {
|
|
151
|
+
logger.error(`Error listing Subnets: ${error.message}`);
|
|
152
|
+
res.status(400).json({ error: error.message });
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Obter Subnet
|
|
157
|
+
this.app.get('/__admin/subnets/:subnetId', (req, res) => {
|
|
158
|
+
try {
|
|
159
|
+
const subnet = this.simulator.getSubnet(req.params.subnetId);
|
|
160
|
+
res.json({ Subnet: subnet.toJSON() });
|
|
161
|
+
} catch (error) {
|
|
162
|
+
logger.error(`Error getting Subnet: ${error.message}`);
|
|
163
|
+
res.status(404).json({ error: error.message });
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Deletar Subnet
|
|
168
|
+
this.app.delete('/__admin/subnets/:subnetId', (req, res) => {
|
|
169
|
+
try {
|
|
170
|
+
this.simulator.deleteSubnet(req.params.subnetId);
|
|
171
|
+
res.json({ success: true });
|
|
172
|
+
} catch (error) {
|
|
173
|
+
logger.error(`Error deleting Subnet: ${error.message}`);
|
|
174
|
+
res.status(400).json({ error: error.message });
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// ========== Route Table Routes ==========
|
|
179
|
+
|
|
180
|
+
// Criar Route Table
|
|
181
|
+
this.app.post('/__admin/route-tables/create', (req, res) => {
|
|
182
|
+
try {
|
|
183
|
+
const { VpcId, Tags } = req.body;
|
|
184
|
+
|
|
185
|
+
if (!VpcId) {
|
|
186
|
+
return res.status(400).json({ error: 'VpcId is required' });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const routeTable = this.simulator.createRouteTable(VpcId, Tags || []);
|
|
190
|
+
res.json({ RouteTable: routeTable.toJSON() });
|
|
191
|
+
} catch (error) {
|
|
192
|
+
logger.error(`Error creating Route Table: ${error.message}`);
|
|
193
|
+
res.status(400).json({ error: error.message });
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Listar Route Tables
|
|
198
|
+
this.app.get('/__admin/route-tables', (req, res) => {
|
|
199
|
+
try {
|
|
200
|
+
const filters = {};
|
|
201
|
+
if (req.query.vpcIds) {
|
|
202
|
+
filters.vpcIds = Array.isArray(req.query.vpcIds)
|
|
203
|
+
? req.query.vpcIds
|
|
204
|
+
: [req.query.vpcIds];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const routeTables = this.simulator.describeRouteTables(filters);
|
|
208
|
+
res.json({ RouteTables: routeTables.map(rt => rt.toJSON()) });
|
|
209
|
+
} catch (error) {
|
|
210
|
+
logger.error(`Error listing Route Tables: ${error.message}`);
|
|
211
|
+
res.status(400).json({ error: error.message });
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Obter Route Table
|
|
216
|
+
this.app.get('/__admin/route-tables/:rtId', (req, res) => {
|
|
217
|
+
try {
|
|
218
|
+
const routeTable = this.simulator.getRouteTable(req.params.rtId);
|
|
219
|
+
res.json({ RouteTable: routeTable.toJSON() });
|
|
220
|
+
} catch (error) {
|
|
221
|
+
logger.error(`Error getting Route Table: ${error.message}`);
|
|
222
|
+
res.status(404).json({ error: error.message });
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Deletar Route Table
|
|
227
|
+
this.app.delete('/__admin/route-tables/:rtId', (req, res) => {
|
|
228
|
+
try {
|
|
229
|
+
this.simulator.deleteRouteTable(req.params.rtId);
|
|
230
|
+
res.json({ success: true });
|
|
231
|
+
} catch (error) {
|
|
232
|
+
logger.error(`Error deleting Route Table: ${error.message}`);
|
|
233
|
+
res.status(400).json({ error: error.message });
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Adicionar Rota
|
|
238
|
+
this.app.post('/__admin/route-tables/:rtId/routes', (req, res) => {
|
|
239
|
+
try {
|
|
240
|
+
const { DestinationCidrBlock, Target, TargetType } = req.body;
|
|
241
|
+
|
|
242
|
+
if (!DestinationCidrBlock || !Target) {
|
|
243
|
+
return res
|
|
244
|
+
.status(400)
|
|
245
|
+
.json({ error: 'DestinationCidrBlock and Target are required' });
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const route = this.simulator.addRoute(
|
|
249
|
+
req.params.rtId,
|
|
250
|
+
DestinationCidrBlock,
|
|
251
|
+
Target,
|
|
252
|
+
TargetType || 'igw'
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
res.json({ Route: route.toJSON() });
|
|
256
|
+
} catch (error) {
|
|
257
|
+
logger.error(`Error adding route: ${error.message}`);
|
|
258
|
+
res.status(400).json({ error: error.message });
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Remover Rota
|
|
263
|
+
this.app.delete('/__admin/route-tables/:rtId/routes/:cidr', (req, res) => {
|
|
264
|
+
try {
|
|
265
|
+
const cidr = decodeURIComponent(req.params.cidr);
|
|
266
|
+
this.simulator.removeRoute(req.params.rtId, cidr);
|
|
267
|
+
res.json({ success: true });
|
|
268
|
+
} catch (error) {
|
|
269
|
+
logger.error(`Error removing route: ${error.message}`);
|
|
270
|
+
res.status(400).json({ error: error.message });
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Associar Route Table com Subnet
|
|
275
|
+
this.app.post('/__admin/route-tables/:rtId/associations', (req, res) => {
|
|
276
|
+
try {
|
|
277
|
+
const { SubnetId } = req.body;
|
|
278
|
+
|
|
279
|
+
if (!SubnetId) {
|
|
280
|
+
return res.status(400).json({ error: 'SubnetId is required' });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const association = this.simulator.associateRouteTable(req.params.rtId, SubnetId);
|
|
284
|
+
res.json({ Association: association.toJSON() });
|
|
285
|
+
} catch (error) {
|
|
286
|
+
logger.error(`Error associating route table: ${error.message}`);
|
|
287
|
+
res.status(400).json({ error: error.message });
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// Desassociar Route Table
|
|
292
|
+
this.app.delete('/__admin/route-tables/:rtId/associations/:subnetId', (req, res) => {
|
|
293
|
+
try {
|
|
294
|
+
this.simulator.disassociateRouteTable(req.params.rtId, req.params.subnetId);
|
|
295
|
+
res.json({ success: true });
|
|
296
|
+
} catch (error) {
|
|
297
|
+
logger.error(`Error disassociating route table: ${error.message}`);
|
|
298
|
+
res.status(400).json({ error: error.message });
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// ========== Internet Gateway Routes ==========
|
|
303
|
+
|
|
304
|
+
// Criar Internet Gateway
|
|
305
|
+
this.app.post('/__admin/internet-gateways/create', (req, res) => {
|
|
306
|
+
try {
|
|
307
|
+
const { Tags } = req.body;
|
|
308
|
+
const igw = this.simulator.createInternetGateway(Tags || []);
|
|
309
|
+
res.json({ InternetGateway: igw.toJSON() });
|
|
310
|
+
} catch (error) {
|
|
311
|
+
logger.error(`Error creating IGW: ${error.message}`);
|
|
312
|
+
res.status(400).json({ error: error.message });
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Listar Internet Gateways
|
|
317
|
+
this.app.get('/__admin/internet-gateways', (req, res) => {
|
|
318
|
+
try {
|
|
319
|
+
const igws = this.simulator.describeInternetGateways();
|
|
320
|
+
res.json({ InternetGateways: igws.map(igw => igw.toJSON()) });
|
|
321
|
+
} catch (error) {
|
|
322
|
+
logger.error(`Error listing IGWs: ${error.message}`);
|
|
323
|
+
res.status(400).json({ error: error.message });
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// Obter Internet Gateway
|
|
328
|
+
this.app.get('/__admin/internet-gateways/:igwId', (req, res) => {
|
|
329
|
+
try {
|
|
330
|
+
const igw = this.simulator.getInternetGateway(req.params.igwId);
|
|
331
|
+
res.json({ InternetGateway: igw.toJSON() });
|
|
332
|
+
} catch (error) {
|
|
333
|
+
logger.error(`Error getting IGW: ${error.message}`);
|
|
334
|
+
res.status(404).json({ error: error.message });
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Anexar IGW
|
|
339
|
+
this.app.post('/__admin/internet-gateways/:igwId/attach', (req, res) => {
|
|
340
|
+
try {
|
|
341
|
+
const { VpcId } = req.body;
|
|
342
|
+
|
|
343
|
+
if (!VpcId) {
|
|
344
|
+
return res.status(400).json({ error: 'VpcId is required' });
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const attachment = this.simulator.attachInternetGateway(req.params.igwId, VpcId);
|
|
348
|
+
res.json({ Attachment: attachment.toJSON() });
|
|
349
|
+
} catch (error) {
|
|
350
|
+
logger.error(`Error attaching IGW: ${error.message}`);
|
|
351
|
+
res.status(400).json({ error: error.message });
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// Desanexar IGW
|
|
356
|
+
this.app.post('/__admin/internet-gateways/:igwId/detach', (req, res) => {
|
|
357
|
+
try {
|
|
358
|
+
const { VpcId } = req.body;
|
|
359
|
+
|
|
360
|
+
if (!VpcId) {
|
|
361
|
+
return res.status(400).json({ error: 'VpcId is required' });
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
this.simulator.detachInternetGateway(req.params.igwId, VpcId);
|
|
365
|
+
res.json({ success: true });
|
|
366
|
+
} catch (error) {
|
|
367
|
+
logger.error(`Error detaching IGW: ${error.message}`);
|
|
368
|
+
res.status(400).json({ error: error.message });
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// Deletar IGW
|
|
373
|
+
this.app.delete('/__admin/internet-gateways/:igwId', (req, res) => {
|
|
374
|
+
try {
|
|
375
|
+
this.simulator.deleteInternetGateway(req.params.igwId);
|
|
376
|
+
res.json({ success: true });
|
|
377
|
+
} catch (error) {
|
|
378
|
+
logger.error(`Error deleting IGW: ${error.message}`);
|
|
379
|
+
res.status(400).json({ error: error.message });
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// ========== VPC Endpoint Routes ==========
|
|
384
|
+
|
|
385
|
+
// Criar VPC Endpoint
|
|
386
|
+
this.app.post('/__admin/vpc-endpoints/create', (req, res) => {
|
|
387
|
+
try {
|
|
388
|
+
const { VpcId, ServiceName, VpcEndpointType, RouteTableIds, SubnetIds } = req.body;
|
|
389
|
+
|
|
390
|
+
if (!VpcId || !ServiceName) {
|
|
391
|
+
return res.status(400).json({ error: 'VpcId and ServiceName are required' });
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const endpoint = this.simulator.createVPCEndpoint(VpcId, ServiceName, {
|
|
395
|
+
VpcEndpointType,
|
|
396
|
+
RouteTableIds,
|
|
397
|
+
SubnetIds
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
res.json({ VpcEndpoint: endpoint.toJSON() });
|
|
401
|
+
} catch (error) {
|
|
402
|
+
logger.error(`Error creating VPC Endpoint: ${error.message}`);
|
|
403
|
+
res.status(400).json({ error: error.message });
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Listar VPC Endpoints
|
|
408
|
+
this.app.get('/__admin/vpc-endpoints', (req, res) => {
|
|
409
|
+
try {
|
|
410
|
+
const filters = {};
|
|
411
|
+
if (req.query.vpcIds) {
|
|
412
|
+
filters.vpcIds = Array.isArray(req.query.vpcIds)
|
|
413
|
+
? req.query.vpcIds
|
|
414
|
+
: [req.query.vpcIds];
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const endpoints = this.simulator.describeVPCEndpoints(filters);
|
|
418
|
+
res.json({ VpcEndpoints: endpoints.map(e => e.toJSON()) });
|
|
419
|
+
} catch (error) {
|
|
420
|
+
logger.error(`Error listing VPC Endpoints: ${error.message}`);
|
|
421
|
+
res.status(400).json({ error: error.message });
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// Obter VPC Endpoint
|
|
426
|
+
this.app.get('/__admin/vpc-endpoints/:epId', (req, res) => {
|
|
427
|
+
try {
|
|
428
|
+
const endpoint = this.simulator.getVPCEndpoint(req.params.epId);
|
|
429
|
+
res.json({ VpcEndpoint: endpoint.toJSON() });
|
|
430
|
+
} catch (error) {
|
|
431
|
+
logger.error(`Error getting VPC Endpoint: ${error.message}`);
|
|
432
|
+
res.status(404).json({ error: error.message });
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// Modificar VPC Endpoint
|
|
437
|
+
this.app.post('/__admin/vpc-endpoints/:epId/modify', (req, res) => {
|
|
438
|
+
try {
|
|
439
|
+
const changes = req.body;
|
|
440
|
+
const endpoint = this.simulator.modifyVPCEndpoint(req.params.epId, changes);
|
|
441
|
+
res.json({ VpcEndpoint: endpoint.toJSON() });
|
|
442
|
+
} catch (error) {
|
|
443
|
+
logger.error(`Error modifying VPC Endpoint: ${error.message}`);
|
|
444
|
+
res.status(400).json({ error: error.message });
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Deletar VPC Endpoint
|
|
449
|
+
this.app.delete('/__admin/vpc-endpoints/:epId', (req, res) => {
|
|
450
|
+
try {
|
|
451
|
+
this.simulator.deleteVPCEndpoint(req.params.epId);
|
|
452
|
+
res.json({ success: true });
|
|
453
|
+
} catch (error) {
|
|
454
|
+
logger.error(`Error deleting VPC Endpoint: ${error.message}`);
|
|
455
|
+
res.status(400).json({ error: error.message });
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
// ========== Health Check ==========
|
|
460
|
+
|
|
461
|
+
this.app.get('/__admin/health', (req, res) => {
|
|
462
|
+
res.json({ status: 'ok', service: 'vpc' });
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Listar todos os recursos
|
|
466
|
+
this.app.get('/__admin/resources', (req, res) => {
|
|
467
|
+
try {
|
|
468
|
+
const resources = this.simulator.getAllResources();
|
|
469
|
+
res.json({
|
|
470
|
+
vpcs: resources.vpcs.map(v => v.toJSON()),
|
|
471
|
+
subnets: resources.subnets.map(s => s.toJSON()),
|
|
472
|
+
routeTables: resources.routeTables.map(rt => rt.toJSON()),
|
|
473
|
+
internetGateways: resources.internetGateways.map(igw => igw.toJSON()),
|
|
474
|
+
vpcEndpoints: resources.vpcEndpoints.map(e => e.toJSON()),
|
|
475
|
+
natGateways: resources.natGateways.map(ng => ng.toJSON())
|
|
476
|
+
});
|
|
477
|
+
} catch (error) {
|
|
478
|
+
logger.error(`Error fetching resources: ${error.message}`);
|
|
479
|
+
res.status(400).json({ error: error.message });
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// ========== EC2 Query Protocol Internal Routes ==========
|
|
484
|
+
// (Kept for backward compatibility with REST API)
|
|
485
|
+
// These routes are now also handled by the catch-all POST / handler above
|
|
486
|
+
|
|
487
|
+
// DeleteRouteTable
|
|
488
|
+
this.app.post('/__internal/delete-route-table', (req, res) => {
|
|
489
|
+
try {
|
|
490
|
+
const routeTableId = req.body.RouteTableId;
|
|
491
|
+
if (!routeTableId) {
|
|
492
|
+
throw new Error('RouteTableId is required');
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
this.simulator.deleteRouteTable(routeTableId);
|
|
496
|
+
const xmlResponse = EC2ResponseFormatter.formatDeleteRouteTableResponse();
|
|
497
|
+
res.set('Content-Type', 'text/xml');
|
|
498
|
+
res.send(xmlResponse);
|
|
499
|
+
} catch (error) {
|
|
500
|
+
logger.error(`Error deleting Route Table: ${error.message}`);
|
|
501
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
502
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// Catch-all POST / for EC2 Query Protocol (AWS CLI)
|
|
507
|
+
this.app.post('/', (req, res) => {
|
|
508
|
+
try {
|
|
509
|
+
const action = req.body?.Action || '';
|
|
510
|
+
logger.debug(`EC2 Query Protocol Action: ${action}`);
|
|
511
|
+
|
|
512
|
+
// Mapear ações EC2 para handlers
|
|
513
|
+
switch (action) {
|
|
514
|
+
case 'DescribeVpcs':
|
|
515
|
+
return this._handleDescribeVpcs(req, res);
|
|
516
|
+
case 'CreateVpc':
|
|
517
|
+
return this._handleCreateVpc(req, res);
|
|
518
|
+
case 'DeleteVpc':
|
|
519
|
+
return this._handleDeleteVpc(req, res);
|
|
520
|
+
case 'DescribeSubnets':
|
|
521
|
+
return this._handleDescribeSubnets(req, res);
|
|
522
|
+
case 'CreateSubnet':
|
|
523
|
+
return this._handleCreateSubnet(req, res);
|
|
524
|
+
case 'DeleteSubnet':
|
|
525
|
+
return this._handleDeleteSubnet(req, res);
|
|
526
|
+
case 'DescribeInternetGateways':
|
|
527
|
+
return this._handleDescribeIgws(req, res);
|
|
528
|
+
case 'CreateInternetGateway':
|
|
529
|
+
return this._handleCreateIgw(req, res);
|
|
530
|
+
case 'AttachInternetGateway':
|
|
531
|
+
return this._handleAttachIgw(req, res);
|
|
532
|
+
case 'DetachInternetGateway':
|
|
533
|
+
return this._handleDetachIgw(req, res);
|
|
534
|
+
case 'DeleteInternetGateway':
|
|
535
|
+
return this._handleDeleteIgw(req, res);
|
|
536
|
+
case 'DescribeRouteTables':
|
|
537
|
+
return this._handleDescribeRouteTables(req, res);
|
|
538
|
+
case 'CreateRouteTable':
|
|
539
|
+
return this._handleCreateRouteTable(req, res);
|
|
540
|
+
case 'CreateRoute':
|
|
541
|
+
return this._handleCreateRoute(req, res);
|
|
542
|
+
case 'DeleteRouteTable':
|
|
543
|
+
return this._handleDeleteRouteTable(req, res);
|
|
544
|
+
default:
|
|
545
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse(
|
|
546
|
+
'InvalidAction',
|
|
547
|
+
`Unknown Action: ${action}`
|
|
548
|
+
);
|
|
549
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
550
|
+
}
|
|
551
|
+
} catch (error) {
|
|
552
|
+
logger.error(`Error handling EC2 Query: ${error.message}`);
|
|
553
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
554
|
+
res.status(500).set('Content-Type', 'text/xml').send(xmlError);
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// EC2 Query Protocol handlers
|
|
560
|
+
_handleDescribeVpcs(req, res) {
|
|
561
|
+
try {
|
|
562
|
+
const vpcs = this.simulator.describeVPCs();
|
|
563
|
+
const xmlResponse = EC2ResponseFormatter.formatDescribeVpcsResponse(
|
|
564
|
+
vpcs.map(vpc => vpc.toJSON())
|
|
565
|
+
);
|
|
566
|
+
res.set('Content-Type', 'text/xml');
|
|
567
|
+
res.send(xmlResponse);
|
|
568
|
+
} catch (error) {
|
|
569
|
+
logger.error(`Error describing VPCs: ${error.message}`);
|
|
570
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
571
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
_handleCreateVpc(req, res) {
|
|
576
|
+
try {
|
|
577
|
+
const cidrBlock = req.body.CidrBlock;
|
|
578
|
+
if (!cidrBlock) {
|
|
579
|
+
throw new Error('CidrBlock is required');
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const vpc = this.simulator.createVPC(cidrBlock);
|
|
583
|
+
const xmlResponse = EC2ResponseFormatter.formatCreateVpcResponse(vpc.toJSON());
|
|
584
|
+
res.set('Content-Type', 'text/xml');
|
|
585
|
+
res.send(xmlResponse);
|
|
586
|
+
} catch (error) {
|
|
587
|
+
logger.error(`Error creating VPC: ${error.message}`);
|
|
588
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
589
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
_handleDeleteVpc(req, res) {
|
|
594
|
+
try {
|
|
595
|
+
const vpcId = req.body.VpcId;
|
|
596
|
+
if (!vpcId) {
|
|
597
|
+
throw new Error('VpcId is required');
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
this.simulator.deleteVPC(vpcId);
|
|
601
|
+
const xmlResponse = EC2ResponseFormatter.formatDeleteVpcResponse();
|
|
602
|
+
res.set('Content-Type', 'text/xml');
|
|
603
|
+
res.send(xmlResponse);
|
|
604
|
+
} catch (error) {
|
|
605
|
+
logger.error(`Error deleting VPC: ${error.message}`);
|
|
606
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
607
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
_handleDescribeSubnets(req, res) {
|
|
612
|
+
try {
|
|
613
|
+
const subnets = this.simulator.describeSubnets();
|
|
614
|
+
const xmlResponse = EC2ResponseFormatter.formatDescribeSubnetsResponse(
|
|
615
|
+
subnets.map(subnet => subnet.toJSON())
|
|
616
|
+
);
|
|
617
|
+
res.set('Content-Type', 'text/xml');
|
|
618
|
+
res.send(xmlResponse);
|
|
619
|
+
} catch (error) {
|
|
620
|
+
logger.error(`Error describing Subnets: ${error.message}`);
|
|
621
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
622
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
_handleCreateSubnet(req, res) {
|
|
627
|
+
try {
|
|
628
|
+
const { VpcId, CidrBlock, AvailabilityZone } = req.body;
|
|
629
|
+
if (!VpcId || !CidrBlock || !AvailabilityZone) {
|
|
630
|
+
throw new Error('VpcId, CidrBlock and AvailabilityZone are required');
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const subnet = this.simulator.createSubnet(VpcId, CidrBlock, AvailabilityZone);
|
|
634
|
+
const xmlResponse = EC2ResponseFormatter.formatCreateSubnetResponse(subnet.toJSON());
|
|
635
|
+
res.set('Content-Type', 'text/xml');
|
|
636
|
+
res.send(xmlResponse);
|
|
637
|
+
} catch (error) {
|
|
638
|
+
logger.error(`Error creating Subnet: ${error.message}`);
|
|
639
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
640
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
_handleDeleteSubnet(req, res) {
|
|
645
|
+
try {
|
|
646
|
+
const subnetId = req.body.SubnetId;
|
|
647
|
+
if (!subnetId) {
|
|
648
|
+
throw new Error('SubnetId is required');
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
this.simulator.deleteSubnet(subnetId);
|
|
652
|
+
const xmlResponse = EC2ResponseFormatter.formatDeleteSubnetResponse();
|
|
653
|
+
res.set('Content-Type', 'text/xml');
|
|
654
|
+
res.send(xmlResponse);
|
|
655
|
+
} catch (error) {
|
|
656
|
+
logger.error(`Error deleting Subnet: ${error.message}`);
|
|
657
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
658
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
_handleDescribeIgws(req, res) {
|
|
663
|
+
try {
|
|
664
|
+
const igws = this.simulator.describeInternetGateways();
|
|
665
|
+
const xmlResponse = EC2ResponseFormatter.formatDescribeIgwResponse(
|
|
666
|
+
igws.map(igw => igw.toJSON())
|
|
667
|
+
);
|
|
668
|
+
res.set('Content-Type', 'text/xml');
|
|
669
|
+
res.send(xmlResponse);
|
|
670
|
+
} catch (error) {
|
|
671
|
+
logger.error(`Error describing IGWs: ${error.message}`);
|
|
672
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
673
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
_handleCreateIgw(req, res) {
|
|
678
|
+
try {
|
|
679
|
+
const igw = this.simulator.createInternetGateway();
|
|
680
|
+
const xmlResponse = EC2ResponseFormatter.formatCreateIgwResponse(igw.toJSON());
|
|
681
|
+
res.set('Content-Type', 'text/xml');
|
|
682
|
+
res.send(xmlResponse);
|
|
683
|
+
} catch (error) {
|
|
684
|
+
logger.error(`Error creating IGW: ${error.message}`);
|
|
685
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
686
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
_handleAttachIgw(req, res) {
|
|
691
|
+
try {
|
|
692
|
+
const { InternetGatewayId, VpcId } = req.body;
|
|
693
|
+
if (!InternetGatewayId || !VpcId) {
|
|
694
|
+
throw new Error('InternetGatewayId and VpcId are required');
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
this.simulator.attachInternetGateway(InternetGatewayId, VpcId);
|
|
698
|
+
const xmlResponse = EC2ResponseFormatter.formatAttachIgwResponse();
|
|
699
|
+
res.set('Content-Type', 'text/xml');
|
|
700
|
+
res.send(xmlResponse);
|
|
701
|
+
} catch (error) {
|
|
702
|
+
logger.error(`Error attaching IGW: ${error.message}`);
|
|
703
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
704
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
_handleDetachIgw(req, res) {
|
|
709
|
+
try {
|
|
710
|
+
const { InternetGatewayId, VpcId } = req.body;
|
|
711
|
+
if (!InternetGatewayId || !VpcId) {
|
|
712
|
+
throw new Error('InternetGatewayId and VpcId are required');
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
this.simulator.detachInternetGateway(InternetGatewayId, VpcId);
|
|
716
|
+
const xmlResponse = EC2ResponseFormatter.formatDetachIgwResponse();
|
|
717
|
+
res.set('Content-Type', 'text/xml');
|
|
718
|
+
res.send(xmlResponse);
|
|
719
|
+
} catch (error) {
|
|
720
|
+
logger.error(`Error detaching IGW: ${error.message}`);
|
|
721
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
722
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
_handleDeleteIgw(req, res) {
|
|
727
|
+
try {
|
|
728
|
+
const internetGatewayId = req.body.InternetGatewayId;
|
|
729
|
+
if (!internetGatewayId) {
|
|
730
|
+
throw new Error('InternetGatewayId is required');
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
this.simulator.deleteInternetGateway(internetGatewayId);
|
|
734
|
+
const xmlResponse = EC2ResponseFormatter.formatDeleteIgwResponse();
|
|
735
|
+
res.set('Content-Type', 'text/xml');
|
|
736
|
+
res.send(xmlResponse);
|
|
737
|
+
} catch (error) {
|
|
738
|
+
logger.error(`Error deleting IGW: ${error.message}`);
|
|
739
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
740
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
_handleDescribeRouteTables(req, res) {
|
|
745
|
+
try {
|
|
746
|
+
const routeTables = this.simulator.describeRouteTables();
|
|
747
|
+
const xmlResponse = EC2ResponseFormatter.formatDescribeRouteTablesResponse(
|
|
748
|
+
routeTables.map(rt => rt.toJSON())
|
|
749
|
+
);
|
|
750
|
+
res.set('Content-Type', 'text/xml');
|
|
751
|
+
res.send(xmlResponse);
|
|
752
|
+
} catch (error) {
|
|
753
|
+
logger.error(`Error describing Route Tables: ${error.message}`);
|
|
754
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
755
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
_handleCreateRouteTable(req, res) {
|
|
760
|
+
try {
|
|
761
|
+
const vpcId = req.body.VpcId;
|
|
762
|
+
if (!vpcId) {
|
|
763
|
+
throw new Error('VpcId is required');
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const routeTable = this.simulator.createRouteTable(vpcId);
|
|
767
|
+
const xmlResponse = EC2ResponseFormatter.formatCreateRouteTableResponse(
|
|
768
|
+
routeTable.toJSON()
|
|
769
|
+
);
|
|
770
|
+
res.set('Content-Type', 'text/xml');
|
|
771
|
+
res.send(xmlResponse);
|
|
772
|
+
} catch (error) {
|
|
773
|
+
logger.error(`Error creating Route Table: ${error.message}`);
|
|
774
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
775
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
_handleCreateRoute(req, res) {
|
|
780
|
+
try {
|
|
781
|
+
const { RouteTableId, DestinationCidrBlock, GatewayId } = req.body;
|
|
782
|
+
if (!RouteTableId || !DestinationCidrBlock || !GatewayId) {
|
|
783
|
+
throw new Error('RouteTableId, DestinationCidrBlock and GatewayId are required');
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
this.simulator.addRoute(RouteTableId, DestinationCidrBlock, GatewayId);
|
|
787
|
+
const xmlResponse = EC2ResponseFormatter.formatCreateRouteResponse();
|
|
788
|
+
res.set('Content-Type', 'text/xml');
|
|
789
|
+
res.send(xmlResponse);
|
|
790
|
+
} catch (error) {
|
|
791
|
+
logger.error(`Error creating Route: ${error.message}`);
|
|
792
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
793
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
_handleDeleteRouteTable(req, res) {
|
|
798
|
+
try {
|
|
799
|
+
const routeTableId = req.body.RouteTableId;
|
|
800
|
+
if (!routeTableId) {
|
|
801
|
+
throw new Error('RouteTableId is required');
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
this.simulator.deleteRouteTable(routeTableId);
|
|
805
|
+
const xmlResponse = EC2ResponseFormatter.formatDeleteRouteTableResponse();
|
|
806
|
+
res.set('Content-Type', 'text/xml');
|
|
807
|
+
res.send(xmlResponse);
|
|
808
|
+
} catch (error) {
|
|
809
|
+
logger.error(`Error deleting Route Table: ${error.message}`);
|
|
810
|
+
const xmlError = EC2ResponseFormatter.formatErrorResponse('InternalError', error.message);
|
|
811
|
+
res.status(400).set('Content-Type', 'text/xml').send(xmlError);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
async start() {
|
|
816
|
+
return new Promise((resolve) => {
|
|
817
|
+
this.server = this.app.listen(this.port, () => {
|
|
818
|
+
logger.info(`VPC Server running on http://localhost:${this.port}`);
|
|
819
|
+
resolve();
|
|
820
|
+
});
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
async stop() {
|
|
825
|
+
if (this.server) {
|
|
826
|
+
return new Promise((resolve) => {
|
|
827
|
+
this.server.close(() => {
|
|
828
|
+
logger.info('VPC Server stopped');
|
|
829
|
+
resolve();
|
|
830
|
+
});
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
module.exports = VPCServer;
|