@webda/aws 2.0.0-beta.2 → 2.0.1
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/lib/deployers/cloudformation.d.ts +2 -2
- package/lib/deployers/cloudformation.js +672 -693
- package/lib/deployers/cloudformation.js.map +1 -1
- package/lib/deployers/cloudformation.spec.js +428 -477
- package/lib/deployers/cloudformation.spec.js.map +1 -1
- package/lib/deployers/index.js +282 -342
- package/lib/deployers/index.js.map +1 -1
- package/lib/deployers/index.spec.d.ts +1 -1
- package/lib/deployers/index.spec.js +445 -510
- package/lib/deployers/index.spec.js.map +1 -1
- package/lib/deployers/lambda-entrypoint.js +4 -16
- package/lib/deployers/lambda-entrypoint.js.map +1 -1
- package/lib/deployers/lambdapackager.js +13 -52
- package/lib/deployers/lambdapackager.js.map +1 -1
- package/lib/deployers/lambdapackager.spec.js +25 -61
- package/lib/deployers/lambdapackager.spec.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -17
- package/lib/index.js.map +1 -1
- package/lib/index.spec.d.ts +1 -1
- package/lib/index.spec.js +28 -75
- package/lib/index.spec.js.map +1 -1
- package/lib/services/aws-mixin.d.ts +2 -0
- package/lib/services/aws-mixin.js +2 -7
- package/lib/services/aws-mixin.js.map +1 -1
- package/lib/services/cloudwatchlogger.d.ts +4 -2
- package/lib/services/cloudwatchlogger.js +63 -103
- package/lib/services/cloudwatchlogger.js.map +1 -1
- package/lib/services/cloudwatchlogger.spec.js +57 -100
- package/lib/services/cloudwatchlogger.spec.js.map +1 -1
- package/lib/services/dynamodb.d.ts +5 -3
- package/lib/services/dynamodb.js +458 -498
- package/lib/services/dynamodb.js.map +1 -1
- package/lib/services/dynamodb.spec.d.ts +2 -2
- package/lib/services/dynamodb.spec.js +231 -302
- package/lib/services/dynamodb.spec.js.map +1 -1
- package/lib/services/index.d.ts +9 -9
- package/lib/services/index.js +8 -24
- package/lib/services/index.js.map +1 -1
- package/lib/services/lambdacaller.d.ts +3 -1
- package/lib/services/lambdacaller.js +16 -29
- package/lib/services/lambdacaller.js.map +1 -1
- package/lib/services/lambdacaller.spec.js +43 -81
- package/lib/services/lambdacaller.spec.js.map +1 -1
- package/lib/services/lambdaserver.d.ts +1 -8
- package/lib/services/lambdaserver.js +168 -206
- package/lib/services/lambdaserver.js.map +1 -1
- package/lib/services/lambdaserver.spec.js +266 -354
- package/lib/services/lambdaserver.spec.js.map +1 -1
- package/lib/services/route53.js +112 -137
- package/lib/services/route53.js.map +1 -1
- package/lib/services/route53.spec.js +56 -92
- package/lib/services/route53.spec.js.map +1 -1
- package/lib/services/s3binary.d.ts +6 -2
- package/lib/services/s3binary.js +189 -251
- package/lib/services/s3binary.js.map +1 -1
- package/lib/services/s3binary.spec.js +185 -254
- package/lib/services/s3binary.spec.js.map +1 -1
- package/lib/services/secretsmanager.d.ts +2 -0
- package/lib/services/secretsmanager.js +32 -56
- package/lib/services/secretsmanager.js.map +1 -1
- package/lib/services/secretsmanager.spec.js +50 -93
- package/lib/services/secretsmanager.spec.js.map +1 -1
- package/lib/services/sqsqueue.d.ts +6 -8
- package/lib/services/sqsqueue.js +70 -98
- package/lib/services/sqsqueue.js.map +1 -1
- package/lib/services/sqsqueue.spec.js +95 -145
- package/lib/services/sqsqueue.spec.js.map +1 -1
- package/lib/shell.js +19 -38
- package/lib/shell.js.map +1 -1
- package/package.json +12 -9
- package/webda.module.json +48 -0
package/lib/deployers/index.js
CHANGED
|
@@ -1,70 +1,32 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
1
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
2
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
3
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
6
|
};
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
40
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
-
};
|
|
43
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
-
exports.AWSDeployer = void 0;
|
|
45
|
-
const client_acm_1 = require("@aws-sdk/client-acm");
|
|
46
|
-
const client_ec2_1 = require("@aws-sdk/client-ec2");
|
|
47
|
-
const client_route_53_1 = require("@aws-sdk/client-route-53");
|
|
48
|
-
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
49
|
-
const client_sts_1 = require("@aws-sdk/client-sts");
|
|
50
|
-
const core_1 = require("@webda/core");
|
|
51
|
-
const shell_1 = require("@webda/shell");
|
|
52
|
-
const bluebird = __importStar(require("bluebird"));
|
|
53
|
-
const crypto = __importStar(require("crypto"));
|
|
54
|
-
const fs = __importStar(require("fs"));
|
|
55
|
-
const glob = __importStar(require("glob"));
|
|
56
|
-
const iam_policy_optimizer_1 = __importDefault(require("iam-policy-optimizer"));
|
|
57
|
-
const mime = __importStar(require("mime-types"));
|
|
58
|
-
const path = __importStar(require("path"));
|
|
59
|
-
const uuid_1 = require("uuid");
|
|
60
|
-
const route53_1 = require("../services/route53");
|
|
7
|
+
import { ACM } from "@aws-sdk/client-acm";
|
|
8
|
+
import { EC2 } from "@aws-sdk/client-ec2";
|
|
9
|
+
import { Route53 } from "@aws-sdk/client-route-53";
|
|
10
|
+
import { NotFound, S3 } from "@aws-sdk/client-s3";
|
|
11
|
+
import { STS } from "@aws-sdk/client-sts";
|
|
12
|
+
import { Cache, WaitFor, WaitLinearDelay, WebdaError } from "@webda/core";
|
|
13
|
+
import { Deployer } from "@webda/shell";
|
|
14
|
+
import bluebird from "bluebird";
|
|
15
|
+
import * as crypto from "crypto";
|
|
16
|
+
import * as fs from "fs";
|
|
17
|
+
import glob from "glob";
|
|
18
|
+
import IamPolicyOptimizer from "iam-policy-optimizer";
|
|
19
|
+
import * as mime from "mime-types";
|
|
20
|
+
import * as path from "path";
|
|
21
|
+
import { v4 as uuidv4 } from "uuid";
|
|
22
|
+
import { Route53Service } from "../services/route53.js";
|
|
61
23
|
/**
|
|
62
24
|
* Abstract AWS Deployer
|
|
63
25
|
*
|
|
64
26
|
* It includes some basic utilities methods to be used by
|
|
65
27
|
* final deployers
|
|
66
28
|
*/
|
|
67
|
-
class AWSDeployer extends
|
|
29
|
+
export class AWSDeployer extends Deployer {
|
|
68
30
|
constructor(manager, resources) {
|
|
69
31
|
super(manager, resources);
|
|
70
32
|
this.resources.accessKeyId = this.resources.accessKeyId || process.env["AWS_ACCESS_KEY_ID"];
|
|
@@ -86,51 +48,47 @@ class AWSDeployer extends shell_1.Deployer {
|
|
|
86
48
|
/**
|
|
87
49
|
* Return the current AWS Identity used
|
|
88
50
|
*/
|
|
89
|
-
getAWSIdentity() {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
endpoint: this.resources.endpoints.STS
|
|
93
|
-
});
|
|
94
|
-
return sts.getCallerIdentity({});
|
|
51
|
+
async getAWSIdentity() {
|
|
52
|
+
let sts = new STS({
|
|
53
|
+
endpoint: this.resources.endpoints.STS
|
|
95
54
|
});
|
|
55
|
+
return sts.getCallerIdentity({});
|
|
96
56
|
}
|
|
97
57
|
/**
|
|
98
58
|
* Return the default VPC for the current region
|
|
99
59
|
*/
|
|
100
|
-
getDefaultVpc() {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
endpoint: this.resources.endpoints.EC2
|
|
109
|
-
});
|
|
110
|
-
let res = yield ec2.describeVpcs({});
|
|
111
|
-
for (let i in res.Vpcs) {
|
|
112
|
-
if (res.Vpcs[i].IsDefault) {
|
|
113
|
-
defaultVpc.Id = res.Vpcs[i].VpcId;
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (defaultVpc.Id === "") {
|
|
118
|
-
return undefined;
|
|
119
|
-
}
|
|
120
|
-
vpcFilter = {
|
|
121
|
-
Filters: [
|
|
122
|
-
{
|
|
123
|
-
Name: "vpc-id",
|
|
124
|
-
Values: [defaultVpc.Id]
|
|
125
|
-
}
|
|
126
|
-
]
|
|
127
|
-
};
|
|
128
|
-
let res2 = yield ec2.describeSubnets(vpcFilter);
|
|
129
|
-
for (let i in res2.Subnets) {
|
|
130
|
-
defaultVpc.Subnets.push(res2.Subnets[i]);
|
|
131
|
-
}
|
|
132
|
-
return defaultVpc;
|
|
60
|
+
async getDefaultVpc() {
|
|
61
|
+
let defaultVpc = {
|
|
62
|
+
Id: "",
|
|
63
|
+
Subnets: []
|
|
64
|
+
};
|
|
65
|
+
let vpcFilter;
|
|
66
|
+
let ec2 = new EC2({
|
|
67
|
+
endpoint: this.resources.endpoints.EC2
|
|
133
68
|
});
|
|
69
|
+
let res = await ec2.describeVpcs({});
|
|
70
|
+
for (let i in res.Vpcs) {
|
|
71
|
+
if (res.Vpcs[i].IsDefault) {
|
|
72
|
+
defaultVpc.Id = res.Vpcs[i].VpcId;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (defaultVpc.Id === "") {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
vpcFilter = {
|
|
80
|
+
Filters: [
|
|
81
|
+
{
|
|
82
|
+
Name: "vpc-id",
|
|
83
|
+
Values: [defaultVpc.Id]
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
};
|
|
87
|
+
let res2 = await ec2.describeSubnets(vpcFilter);
|
|
88
|
+
for (let i in res2.Subnets) {
|
|
89
|
+
defaultVpc.Subnets.push(res2.Subnets[i]);
|
|
90
|
+
}
|
|
91
|
+
return defaultVpc;
|
|
134
92
|
}
|
|
135
93
|
/**
|
|
136
94
|
* Generate a MD5 in hex
|
|
@@ -163,44 +121,40 @@ class AWSDeployer extends shell_1.Deployer {
|
|
|
163
121
|
* @param domain to get certificate for
|
|
164
122
|
* @param region
|
|
165
123
|
*/
|
|
166
|
-
getCertificate(domain, region = undefined) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
region
|
|
174
|
-
});
|
|
175
|
-
let params = {};
|
|
176
|
-
let res;
|
|
177
|
-
let certificate;
|
|
178
|
-
do {
|
|
179
|
-
res = yield acm.listCertificates(params);
|
|
180
|
-
certificate = res.CertificateSummaryList.filter(cert => cert.DomainName === domain).pop();
|
|
181
|
-
params.NextToken = res.NextToken;
|
|
182
|
-
} while (!certificate && res.NextToken);
|
|
183
|
-
// We did not find the certificate need to create one
|
|
184
|
-
if (!certificate) {
|
|
185
|
-
let zone = yield this.getZoneForDomainName(domain);
|
|
186
|
-
if (!zone) {
|
|
187
|
-
throw new core_1.WebdaError("ROUTE53_NOTFOUND", "Cannot create certificate as Route53 Zone was not found");
|
|
188
|
-
}
|
|
189
|
-
this.logger.log("INFO", "Creating a certificate for", domain);
|
|
190
|
-
certificate = yield this.doCreateCertificate(domain, zone);
|
|
191
|
-
}
|
|
192
|
-
return certificate;
|
|
124
|
+
async getCertificate(domain, region = undefined) {
|
|
125
|
+
if (domain.endsWith(".")) {
|
|
126
|
+
domain = domain.substring(0, domain.length - 1);
|
|
127
|
+
}
|
|
128
|
+
let acm = new ACM({
|
|
129
|
+
endpoint: this.resources.endpoints.ACM,
|
|
130
|
+
region
|
|
193
131
|
});
|
|
132
|
+
let params = {};
|
|
133
|
+
let res;
|
|
134
|
+
let certificate;
|
|
135
|
+
do {
|
|
136
|
+
res = await acm.listCertificates(params);
|
|
137
|
+
certificate = res.CertificateSummaryList.filter(cert => cert.DomainName === domain).pop();
|
|
138
|
+
params.NextToken = res.NextToken;
|
|
139
|
+
} while (!certificate && res.NextToken);
|
|
140
|
+
// We did not find the certificate need to create one
|
|
141
|
+
if (!certificate) {
|
|
142
|
+
let zone = await this.getZoneForDomainName(domain);
|
|
143
|
+
if (!zone) {
|
|
144
|
+
throw new WebdaError("ROUTE53_NOTFOUND", "Cannot create certificate as Route53 Zone was not found");
|
|
145
|
+
}
|
|
146
|
+
this.logger.log("INFO", "Creating a certificate for", domain);
|
|
147
|
+
certificate = await this.doCreateCertificate(domain, zone);
|
|
148
|
+
}
|
|
149
|
+
return certificate;
|
|
194
150
|
}
|
|
195
151
|
/**
|
|
196
152
|
* Get the closest zone to the domain
|
|
197
153
|
*
|
|
198
154
|
* @param domain to get zone for
|
|
199
155
|
*/
|
|
200
|
-
getZoneForDomainName(domain) {
|
|
201
|
-
return
|
|
202
|
-
return route53_1.Route53Service.getZoneForDomainName(domain);
|
|
203
|
-
});
|
|
156
|
+
async getZoneForDomainName(domain) {
|
|
157
|
+
return Route53Service.getZoneForDomainName(domain);
|
|
204
158
|
}
|
|
205
159
|
/**
|
|
206
160
|
* Transform a tag map into a tag array
|
|
@@ -266,10 +220,8 @@ class AWSDeployer extends shell_1.Deployer {
|
|
|
266
220
|
.map(tag => `${encodeURIComponent(tag.Key)}=${encodeURIComponent(tag.Value)}`)
|
|
267
221
|
.join("&");
|
|
268
222
|
}
|
|
269
|
-
waitFor(callback, retries, title, delay) {
|
|
270
|
-
return
|
|
271
|
-
return (0, core_1.WaitFor)(callback, retries, title, this.logger, (0, core_1.WaitLinearDelay)(delay));
|
|
272
|
-
});
|
|
223
|
+
async waitFor(callback, retries, title, delay) {
|
|
224
|
+
return WaitFor(callback, retries, title, this.logger, WaitLinearDelay(delay));
|
|
273
225
|
}
|
|
274
226
|
/**
|
|
275
227
|
* Create a certificate for a domain
|
|
@@ -278,60 +230,58 @@ class AWSDeployer extends shell_1.Deployer {
|
|
|
278
230
|
* @param domain to create the certificate for
|
|
279
231
|
* @param zone
|
|
280
232
|
*/
|
|
281
|
-
doCreateCertificate(domain, zone) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
233
|
+
async doCreateCertificate(domain, zone) {
|
|
234
|
+
let acm = new ACM({
|
|
235
|
+
endpoint: this.resources.endpoints.S3
|
|
236
|
+
});
|
|
237
|
+
if (domain.endsWith(".")) {
|
|
238
|
+
domain = domain.substring(0, domain.length - 1);
|
|
239
|
+
}
|
|
240
|
+
let params = {
|
|
241
|
+
DomainName: domain,
|
|
242
|
+
DomainValidationOptions: [
|
|
243
|
+
{
|
|
244
|
+
DomainName: domain,
|
|
245
|
+
ValidationDomain: domain
|
|
246
|
+
}
|
|
247
|
+
],
|
|
248
|
+
ValidationMethod: "DNS",
|
|
249
|
+
IdempotencyToken: "Webda_" + this.md5(domain).substring(0, 26)
|
|
250
|
+
};
|
|
251
|
+
let certificate = await acm.requestCertificate(params);
|
|
252
|
+
let cert = await this.waitFor(async (resolve) => {
|
|
253
|
+
let res = await acm.describeCertificate({ CertificateArn: certificate.CertificateArn });
|
|
254
|
+
if (res.Certificate.DomainValidationOptions && res.Certificate.DomainValidationOptions[0].ResourceRecord) {
|
|
255
|
+
resolve(res.Certificate);
|
|
256
|
+
return true;
|
|
288
257
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
258
|
+
return false;
|
|
259
|
+
}, 5, "Waiting for certificate challenge", 10000);
|
|
260
|
+
if (cert === undefined || cert.Status === "FAILED") {
|
|
261
|
+
throw new WebdaError("ACM_VALIDATION_FAILED", "Certificate validation has failed");
|
|
262
|
+
}
|
|
263
|
+
if (cert.Status === "PENDING_VALIDATION") {
|
|
264
|
+
// On create need to wait
|
|
265
|
+
let record = cert.DomainValidationOptions[0].ResourceRecord;
|
|
266
|
+
this.logger.log("INFO", "Need to validate certificate", cert.CertificateArn);
|
|
267
|
+
await this.createDNSEntry(record.Name, "CNAME", record.Value, zone);
|
|
268
|
+
// Waiting for certificate validation
|
|
269
|
+
cert = await this.waitFor(async (resolve, reject) => {
|
|
270
|
+
let res = await acm.describeCertificate({
|
|
271
|
+
CertificateArn: cert.CertificateArn
|
|
272
|
+
});
|
|
273
|
+
if (res.Certificate.Status === "ISSUED") {
|
|
304
274
|
resolve(res.Certificate);
|
|
305
275
|
return true;
|
|
306
276
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
this.logger.log("INFO", "Need to validate certificate", cert.CertificateArn);
|
|
316
|
-
yield this.createDNSEntry(record.Name, "CNAME", record.Value, zone);
|
|
317
|
-
// Waiting for certificate validation
|
|
318
|
-
cert = yield this.waitFor((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
319
|
-
let res = yield acm.describeCertificate({
|
|
320
|
-
CertificateArn: cert.CertificateArn
|
|
321
|
-
});
|
|
322
|
-
if (res.Certificate.Status === "ISSUED") {
|
|
323
|
-
resolve(res.Certificate);
|
|
324
|
-
return true;
|
|
325
|
-
}
|
|
326
|
-
if (res.Certificate.Status !== "PENDING_VALIDATION") {
|
|
327
|
-
reject(res.Certificate);
|
|
328
|
-
return true;
|
|
329
|
-
}
|
|
330
|
-
}), 10, "Waiting for certificate validation", 60000);
|
|
331
|
-
}
|
|
332
|
-
//
|
|
333
|
-
return cert;
|
|
334
|
-
});
|
|
277
|
+
if (res.Certificate.Status !== "PENDING_VALIDATION") {
|
|
278
|
+
reject(res.Certificate);
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
}, 10, "Waiting for certificate validation", 60000);
|
|
282
|
+
}
|
|
283
|
+
//
|
|
284
|
+
return cert;
|
|
335
285
|
}
|
|
336
286
|
/**
|
|
337
287
|
* Create DNS entry
|
|
@@ -341,42 +291,40 @@ class AWSDeployer extends shell_1.Deployer {
|
|
|
341
291
|
* @param value the value of the record
|
|
342
292
|
* @param targetZone
|
|
343
293
|
*/
|
|
344
|
-
createDNSEntry(domain, type, value, targetZone = undefined) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
Type: type
|
|
374
|
-
}
|
|
294
|
+
async createDNSEntry(domain, type, value, targetZone = undefined) {
|
|
295
|
+
this.logger.log("INFO", `Creating DNS entry ${domain} ${type} ${value}`);
|
|
296
|
+
let r53 = new Route53({
|
|
297
|
+
endpoint: this.resources.endpoints.S3
|
|
298
|
+
});
|
|
299
|
+
if (!domain.endsWith(".")) {
|
|
300
|
+
domain = domain + ".";
|
|
301
|
+
}
|
|
302
|
+
if (!targetZone) {
|
|
303
|
+
targetZone = await this.getZoneForDomainName(domain);
|
|
304
|
+
}
|
|
305
|
+
if (!targetZone) {
|
|
306
|
+
throw Error("Domain is not handled on AWS");
|
|
307
|
+
}
|
|
308
|
+
await r53.changeResourceRecordSets({
|
|
309
|
+
HostedZoneId: targetZone.Id,
|
|
310
|
+
ChangeBatch: {
|
|
311
|
+
Changes: [
|
|
312
|
+
{
|
|
313
|
+
Action: "UPSERT",
|
|
314
|
+
ResourceRecordSet: {
|
|
315
|
+
Name: domain,
|
|
316
|
+
ResourceRecords: [
|
|
317
|
+
{
|
|
318
|
+
Value: value
|
|
319
|
+
}
|
|
320
|
+
],
|
|
321
|
+
TTL: 360,
|
|
322
|
+
Type: type
|
|
375
323
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
324
|
+
}
|
|
325
|
+
],
|
|
326
|
+
Comment: "webda-automated-deploiement"
|
|
327
|
+
}
|
|
380
328
|
});
|
|
381
329
|
}
|
|
382
330
|
getARNPolicy(accountId, region) {
|
|
@@ -396,70 +344,67 @@ class AWSDeployer extends shell_1.Deployer {
|
|
|
396
344
|
* Allowing you to write some specific Service or Bean that
|
|
397
345
|
* requires specific AWS permissions
|
|
398
346
|
*/
|
|
399
|
-
getPolicyDocument(additionalStatements = []) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
statements.push(res);
|
|
414
|
-
}
|
|
347
|
+
async getPolicyDocument(additionalStatements = []) {
|
|
348
|
+
let me = await this.getAWSIdentity();
|
|
349
|
+
let services = this.manager.getWebda().getServices();
|
|
350
|
+
let statements = [];
|
|
351
|
+
// Build policy
|
|
352
|
+
for (let i in services) {
|
|
353
|
+
if ("getARNPolicy" in services[i]) {
|
|
354
|
+
// Update to match recuring policy - might need to split if policy too big
|
|
355
|
+
let res = services[i].getARNPolicy(me.Account, this.getRegion());
|
|
356
|
+
if (Array.isArray(res)) {
|
|
357
|
+
statements.push(...res);
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
statements.push(res);
|
|
415
361
|
}
|
|
416
362
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
363
|
+
}
|
|
364
|
+
statements.push(...this.getARNPolicy(me.Account, this.getRegion()));
|
|
365
|
+
let policyDocument = {
|
|
366
|
+
Version: "2012-10-17",
|
|
367
|
+
Statement: [...statements, ...additionalStatements]
|
|
368
|
+
};
|
|
369
|
+
// @ts-ignore
|
|
370
|
+
return IamPolicyOptimizer.default?.reducePolicyObject(policyDocument);
|
|
424
371
|
}
|
|
425
372
|
/**
|
|
426
373
|
* Create a bucket if it does not exist
|
|
427
374
|
*
|
|
428
375
|
* @param bucket to create
|
|
429
376
|
*/
|
|
430
|
-
createBucket(Bucket) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
377
|
+
async createBucket(Bucket) {
|
|
378
|
+
let s3 = new S3({
|
|
379
|
+
endpoint: this.resources.endpoints.S3,
|
|
380
|
+
forcePathStyle: this.resources.endpoints.S3 !== undefined
|
|
381
|
+
});
|
|
382
|
+
try {
|
|
383
|
+
await s3.headBucket({
|
|
384
|
+
Bucket
|
|
435
385
|
});
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
386
|
+
}
|
|
387
|
+
catch (err) {
|
|
388
|
+
if (err.name === "Forbidden") {
|
|
389
|
+
this.logger.log("ERROR", "S3 bucket already exists in another account or you do not have permissions on it");
|
|
440
390
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
391
|
+
else if (err instanceof NotFound) {
|
|
392
|
+
this.logger.log("INFO", "\tCreating S3 Bucket", Bucket);
|
|
393
|
+
// Setup www permission on it
|
|
394
|
+
await s3.createBucket({
|
|
395
|
+
Bucket: Bucket
|
|
396
|
+
});
|
|
397
|
+
let Tags = this.getDefaultTags([]);
|
|
398
|
+
if (Tags.length) {
|
|
399
|
+
await s3.putBucketTagging({
|
|
400
|
+
Bucket,
|
|
401
|
+
Tagging: {
|
|
402
|
+
TagSet: Tags
|
|
403
|
+
}
|
|
450
404
|
});
|
|
451
|
-
let Tags = this.getDefaultTags([]);
|
|
452
|
-
if (Tags.length) {
|
|
453
|
-
yield s3.putBucketTagging({
|
|
454
|
-
Bucket,
|
|
455
|
-
Tagging: {
|
|
456
|
-
TagSet: Tags
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
405
|
}
|
|
461
406
|
}
|
|
462
|
-
}
|
|
407
|
+
}
|
|
463
408
|
}
|
|
464
409
|
/**
|
|
465
410
|
* Send a full folder (recursive) on bucket
|
|
@@ -468,14 +413,12 @@ class AWSDeployer extends shell_1.Deployer {
|
|
|
468
413
|
* @param folder path to local folder to send
|
|
469
414
|
* @param prefix prefix on the bucket
|
|
470
415
|
*/
|
|
471
|
-
putFolderOnBucket(bucket, folder, prefix = "") {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
files.map(f => ({ key: `${prefix}${path.relative(absFolder, f).replace(/\\/g, "/")}`, src: f })));
|
|
478
|
-
});
|
|
416
|
+
async putFolderOnBucket(bucket, folder, prefix = "") {
|
|
417
|
+
let absFolder = path.resolve(folder);
|
|
418
|
+
let files = glob.sync(`${absFolder}/**/*`);
|
|
419
|
+
await this.putFilesOnBucket(bucket,
|
|
420
|
+
// Replace \ by / for Windows system
|
|
421
|
+
files.map(f => ({ key: `${prefix}${path.relative(absFolder, f).replace(/\\/g, "/")}`, src: f })));
|
|
479
422
|
}
|
|
480
423
|
/**
|
|
481
424
|
* Find the common prefix between two strings
|
|
@@ -511,88 +454,85 @@ class AWSDeployer extends shell_1.Deployer {
|
|
|
511
454
|
* @param bucket to send bucket
|
|
512
455
|
* @param files to send
|
|
513
456
|
*/
|
|
514
|
-
putFilesOnBucket(bucket, files) {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
457
|
+
async putFilesOnBucket(bucket, files) {
|
|
458
|
+
let s3 = new S3({
|
|
459
|
+
endpoint: this.resources.endpoints.S3,
|
|
460
|
+
forcePathStyle: this.resources.endpoints.S3 !== undefined
|
|
461
|
+
});
|
|
462
|
+
if (!files.length) {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
files.forEach(f => {
|
|
466
|
+
if (f.src === undefined) {
|
|
467
|
+
throw Error("Should have src and key defined");
|
|
522
468
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
469
|
+
else if (!f.key) {
|
|
470
|
+
f.key = path.relative(process.cwd(), f.src);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
// Create the bucket
|
|
474
|
+
await this.createBucket(bucket);
|
|
475
|
+
// Retrieve current files to only upload the one we do not have
|
|
476
|
+
let currentFiles = {};
|
|
477
|
+
let Prefix = files.reduce((prev, cur) => this.commonPrefix(prev, cur.key), files[0].key);
|
|
478
|
+
let Params = {
|
|
479
|
+
Bucket: bucket,
|
|
480
|
+
Prefix,
|
|
481
|
+
MaxKeys: 1000,
|
|
482
|
+
ContinuationToken: undefined
|
|
483
|
+
};
|
|
484
|
+
do {
|
|
485
|
+
let res = await s3.listObjectsV2(Params);
|
|
486
|
+
res.Contents.forEach(obj => {
|
|
487
|
+
currentFiles[obj.Key] = obj;
|
|
530
488
|
});
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
currentFiles[obj.Key] = obj;
|
|
546
|
-
});
|
|
547
|
-
Params.ContinuationToken = res.NextContinuationToken;
|
|
548
|
-
} while (Params.ContinuationToken);
|
|
549
|
-
// Should implement multithread here - cleaning too
|
|
550
|
-
let uuid = (0, uuid_1.v4)();
|
|
551
|
-
let fullSize = 0;
|
|
552
|
-
files = files.filter(info => {
|
|
553
|
-
if (typeof info.src === "string") {
|
|
554
|
-
let s3obj = currentFiles[info.key];
|
|
555
|
-
let stat = fs.statSync(info.src);
|
|
556
|
-
if (s3obj && stat.size === s3obj.Size) {
|
|
557
|
-
let md5 = `"${this.hash(fs.readFileSync(info.src).toString(), "md5", "hex")}"`;
|
|
558
|
-
if (md5 === s3obj.ETag) {
|
|
559
|
-
this.logger.log("TRACE", "Skipping upload of", info.src, "file with same hash already on bucket");
|
|
560
|
-
return false;
|
|
561
|
-
}
|
|
489
|
+
Params.ContinuationToken = res.NextContinuationToken;
|
|
490
|
+
} while (Params.ContinuationToken);
|
|
491
|
+
// Should implement multithread here - cleaning too
|
|
492
|
+
let uuid = uuidv4();
|
|
493
|
+
let fullSize = 0;
|
|
494
|
+
files = files.filter(info => {
|
|
495
|
+
if (typeof info.src === "string") {
|
|
496
|
+
let s3obj = currentFiles[info.key];
|
|
497
|
+
let stat = fs.statSync(info.src);
|
|
498
|
+
if (s3obj && stat.size === s3obj.Size) {
|
|
499
|
+
let md5 = `"${this.hash(fs.readFileSync(info.src).toString(), "md5", "hex")}"`;
|
|
500
|
+
if (md5 === s3obj.ETag) {
|
|
501
|
+
this.logger.log("TRACE", "Skipping upload of", info.src, "file with same hash already on bucket");
|
|
502
|
+
return false;
|
|
562
503
|
}
|
|
563
|
-
fullSize += stat.size;
|
|
564
504
|
}
|
|
565
|
-
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
yield bluebird.map(files, (info) => __awaiter(this, void 0, void 0, function* () {
|
|
569
|
-
// Need to have mimetype to serve the content correctly
|
|
570
|
-
let mimetype = info.mimetype || mime.contentType(path.extname(info.key)) || "application/octet-stream";
|
|
571
|
-
// use of upload and get size length
|
|
572
|
-
yield s3.putObject({
|
|
573
|
-
Bucket: bucket,
|
|
574
|
-
Body: typeof info.src === "string" ? fs.createReadStream(info.src) : info.src,
|
|
575
|
-
Key: info.key,
|
|
576
|
-
ContentType: mimetype,
|
|
577
|
-
Tagging: this.getDefaultTagsAsS3Tagging()
|
|
578
|
-
});
|
|
579
|
-
this.logger.logProgressIncrement(1, uuid);
|
|
580
|
-
this.logger.log("INFO", "Uploaded", typeof info.src === "string" ? info.src : "<dynamicContent>", "to", `s3://${bucket}/${info.key}`, "(" + mimetype + ")");
|
|
581
|
-
}), { concurrency: 5 });
|
|
505
|
+
fullSize += stat.size;
|
|
506
|
+
}
|
|
507
|
+
return true;
|
|
582
508
|
});
|
|
509
|
+
this.logger.logProgressStart(uuid, files.length, "Uploading to S3 bucket " + bucket);
|
|
510
|
+
await bluebird.map(files, async (info) => {
|
|
511
|
+
// Need to have mimetype to serve the content correctly
|
|
512
|
+
let mimetype = info.mimetype || mime.contentType(path.extname(info.key)) || "application/octet-stream";
|
|
513
|
+
// use of upload and get size length
|
|
514
|
+
await s3.putObject({
|
|
515
|
+
Bucket: bucket,
|
|
516
|
+
Body: typeof info.src === "string" ? fs.createReadStream(info.src) : info.src,
|
|
517
|
+
Key: info.key,
|
|
518
|
+
ContentType: mimetype,
|
|
519
|
+
Tagging: this.getDefaultTagsAsS3Tagging()
|
|
520
|
+
});
|
|
521
|
+
this.logger.logProgressIncrement(1, uuid);
|
|
522
|
+
this.logger.log("INFO", "Uploaded", typeof info.src === "string" ? info.src : "<dynamicContent>", "to", `s3://${bucket}/${info.key}`, "(" + mimetype + ")");
|
|
523
|
+
}, { concurrency: 5 });
|
|
583
524
|
}
|
|
584
525
|
}
|
|
585
526
|
__decorate([
|
|
586
|
-
|
|
527
|
+
Cache()
|
|
587
528
|
], AWSDeployer.prototype, "getAWSIdentity", null);
|
|
588
529
|
__decorate([
|
|
589
|
-
|
|
530
|
+
Cache()
|
|
590
531
|
], AWSDeployer.prototype, "getDefaultVpc", null);
|
|
591
532
|
__decorate([
|
|
592
|
-
|
|
533
|
+
Cache()
|
|
593
534
|
], AWSDeployer.prototype, "getZoneForDomainName", null);
|
|
594
535
|
__decorate([
|
|
595
|
-
|
|
536
|
+
Cache()
|
|
596
537
|
], AWSDeployer.prototype, "getPolicyDocument", null);
|
|
597
|
-
exports.AWSDeployer = AWSDeployer;
|
|
598
538
|
//# sourceMappingURL=index.js.map
|