-
Notifications
You must be signed in to change notification settings - Fork 819
/
storage.ts
192 lines (172 loc) · 6.81 KB
/
storage.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
import { AmplifyStorageSimulator } from 'amplify-storage-simulator';
import * as path from 'path';
import * as fs from 'fs-extra';
import { getAmplifyMeta, addCleanupTask, getMockDataDirectory } from '../utils';
import { ConfigOverrideManager } from '../utils/config-override';
import { invoke } from 'amplify-category-function';
const category = 'function';
const port = 20005; // port for S3
export class StorageTest {
private storageName: string;
private storageSimulator: AmplifyStorageSimulator;
private configOverrideManager: ConfigOverrideManager;
private storageRegion: string;
private bucketName: string;
async start(context) {
// loading s3 resource config form parameters.json
const meta = context.amplify.getProjectDetails().amplifyMeta;
const existingStorage = meta.storage;
this.storageRegion = meta.providers.awscloudformation.Region;
if (existingStorage === undefined || Object.keys(existingStorage).length === 0) {
return context.print.warning('Storage has not yet been added to this project.');
}
let backendPath = context.amplify.pathManager.getBackendDirPath();
const resourceName = Object.keys(existingStorage)[0];
const parametersFilePath = path.join(backendPath, 'storage', resourceName, 'parameters.json');
const localEnvFilePath = context.amplify.pathManager.getLocalEnvFilePath();
const localEnvInfo = context.amplify.readJsonFile(localEnvFilePath);
const storageParams = context.amplify.readJsonFile(parametersFilePath);
this.bucketName = `${storageParams.bucketName}-${localEnvInfo.envName}`;
const route = path.join('/', this.bucketName);
let localDirS3 = this.createLocalStorage(context, `${storageParams.bucketName}`);
try {
addCleanupTask(context, async context => {
await this.stop(context);
});
this.configOverrideManager = ConfigOverrideManager.getInstance(context);
this.storageName = await this.getStorage(context);
const storageConfig = { port, route, localDirS3 };
this.storageSimulator = new AmplifyStorageSimulator(storageConfig);
await this.storageSimulator.start();
console.log('Mock Storage endpoint is running at', this.storageSimulator.url);
await this.generateTestFrontendExports(context);
} catch (e) {
console.error('Failed to start Mock Storage server', e);
}
}
async stop(context) {
await this.storageSimulator.stop();
}
// to fire s3 triggers attached on the bucket
async trigger(context) {
let region = this.storageRegion;
this.storageSimulator.getServer.on('event', (eventObj: any) => {
const meta = context.amplify.getProjectDetails().amplifyMeta;
const existingStorage = meta.storage;
let backendPath = context.amplify.pathManager.getBackendDirPath();
const resourceName = Object.keys(existingStorage)[0];
const CFNFilePath = path.join(backendPath, 'storage', resourceName, 's3-cloudformation-template.json');
const storageParams = context.amplify.readJsonFile(CFNFilePath);
const lambdaConfig =
storageParams.Resources.S3Bucket.Properties.NotificationConfiguration &&
storageParams.Resources.S3Bucket.Properties.NotificationConfiguration.LambdaConfigurations;
//no trigger case
if (lambdaConfig === undefined) {
return;
}
// loop over lambda config to check for trigger based on prefix
let triggerName;
for (let obj of lambdaConfig) {
let prefix_arr = obj.Filter;
if (prefix_arr === undefined) {
let eventName = String(eventObj.Records[0].event.eventName).split(':')[0];
if (eventName === 'ObjectRemoved' || eventName === 'ObjectCreated') {
triggerName = String(obj.Function.Ref)
.split('function')[1]
.split('Arn')[0];
break;
}
} else {
let keyName = String(eventObj.Records[0].s3.object.key);
prefix_arr = obj.Filter.S3Key.Rules;
for (let rules of prefix_arr) {
let node;
if (typeof rules.Value === 'object') {
node = String(Object.values(rules.Value)[0][1][0] + String(region) + ':');
}
if (typeof rules.Value === 'string') {
node = String(rules.Value);
}
// check prefix given is the prefix of keyname in the event object
if (keyName.indexOf(node) === 0) {
triggerName = String(obj.Function.Ref)
.split('function')[1]
.split('Arn')[0];
break;
}
}
}
if (triggerName !== undefined) {
break;
}
}
const srcDir = path.normalize(path.join(backendPath, category, String(triggerName), 'src'));
const event = eventObj;
const invokeOptions = {
packageFolder: srcDir,
fileName: `${srcDir}/index.js`,
handler: 'handler',
event,
};
invoke(invokeOptions);
});
}
private async generateTestFrontendExports(context) {
await this.generateFrontendExports(context, {
endpoint: this.storageSimulator.url,
name: this.storageName,
testMode: true,
});
}
// generate aws-exports.js
private async generateFrontendExports(
context: any,
localStorageDetails?: {
endpoint: string;
name: string;
testMode: boolean;
}
) {
const currentMeta = await getAmplifyMeta(context);
const override = currentMeta.storage || {};
if (localStorageDetails) {
const storageMeta = override[localStorageDetails.name] || { output: {} };
override[localStorageDetails.name] = {
service: 'S3',
...storageMeta,
output: {
BucketName: this.bucketName,
Region: this.storageRegion,
...storageMeta.output,
},
testMode: localStorageDetails.testMode,
lastPushTimeStamp: new Date(),
};
}
this.configOverrideManager.addOverride('storage', override);
await this.configOverrideManager.generateOverriddenFrontendExports(context);
}
private async getStorage(context) {
const currentMeta = await getAmplifyMeta(context);
const { storage: tmp = {} } = currentMeta;
let name = null;
Object.entries(tmp).some((entry: any) => {
if (entry[1].service === 'S3') {
name = entry[0];
return true;
}
});
return name;
}
// create local storage for S3 on disk which is fixes as the test folder
private createLocalStorage(context, resourceName: string) {
const directoryPath = path.join(getMockDataDirectory(context), 'S3'); // get bucket through parameters remove afterwards
fs.ensureDirSync(directoryPath);
const localPath = path.join(directoryPath, resourceName);
fs.ensureDirSync(localPath);
return localPath;
}
get getSimulatorObject() {
return this.storageSimulator;
}
}