-
Notifications
You must be signed in to change notification settings - Fork 816
/
index.ts
186 lines (156 loc) · 6.6 KB
/
index.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
import { $TSAny, $TSContext, $TSObject, stateManager } from 'amplify-cli-core';
import { printer } from 'amplify-prompts';
import {
validateAddStorageRequest,
validateImportStorageRequest,
validateRemoveStorageRequest,
validateUpdateStorageRequest,
} from 'amplify-util-headless-input';
import * as path from 'path';
import sequential from 'promise-sequential';
import { updateConfigOnEnvInit } from './provider-utils/awscloudformation';
import {
headlessAddStorage,
headlessImportStorage,
headlessRemoveStorage,
headlessUpdateStorage,
} from './provider-utils/awscloudformation/storage-configuration-helpers';
import { categoryName } from './constants';
export { categoryName as category } from './constants';
export async function add(context: $TSContext, providerName: string, service: string) {
const options = {
service,
providerPlugin: providerName,
};
const providerController = await import(`./provider-utils/${providerName}`);
if (!providerController) {
printer.error('Provider not configured for this category');
return;
}
return providerController.addResource(context, categoryName, service, options);
}
export async function console(context: $TSContext) {
printer.info(`to be implemented: ${categoryName} console`);
}
export async function migrate(context: $TSContext) {
const { projectPath, amplifyMeta } = context.migrationInfo;
const migrateResourcePromises: Promise<$TSAny>[] = [];
const categoryResources = amplifyMeta?.[categoryName] || {};
for (const resourceName of Object.keys(categoryResources)) {
try {
const providerController = await import(`./provider-utils/${amplifyMeta[categoryName][resourceName].providerPlugin}`);
if (providerController) {
migrateResourcePromises.push(
await providerController.migrateResource(context, projectPath, amplifyMeta[categoryName][resourceName].service, resourceName),
);
} else {
printer.error(`Provider not configured for ${categoryName}: ${resourceName}`);
}
} catch (e) {
printer.warn(`Could not run migration for ${categoryName}: ${resourceName}`);
throw e;
}
}
await Promise.all(migrateResourcePromises);
}
export async function getPermissionPolicies(context: $TSContext, resourceOpsMapping: $TSAny) {
const amplifyMeta = stateManager.getMeta();
const permissionPolicies: $TSAny[] = [];
const resourceAttributes: $TSAny[] = [];
for (const resourceName of Object.keys(resourceOpsMapping)) {
try {
const providerPlugin =
'providerPlugin' in resourceOpsMapping[resourceName]
? resourceOpsMapping[resourceName].providerPlugin
: amplifyMeta[categoryName][resourceName].providerPlugin;
const service =
'service' in resourceOpsMapping[resourceName]
? resourceOpsMapping[resourceName].service
: amplifyMeta[categoryName][resourceName].service;
if (providerPlugin) {
const providerController = await import(`./provider-utils/${providerPlugin}`);
const { policy, attributes } = await providerController.getPermissionPolicies(
service,
resourceName,
resourceOpsMapping[resourceName],
);
if (Array.isArray(policy)) {
permissionPolicies.push(...policy);
} else {
permissionPolicies.push(policy);
}
resourceAttributes.push({ resourceName, attributes, category: categoryName });
} else {
printer.error(`Provider not configured for ${categoryName}: ${resourceName}`);
}
} catch (e) {
printer.warn(`Could not get policies for ${categoryName}: ${resourceName}`);
throw e;
}
}
return { permissionPolicies, resourceAttributes };
}
export async function executeAmplifyCommand(context: $TSContext) {
let commandPath = path.normalize(path.join(__dirname, 'commands'));
if (context.input.command === 'help') {
commandPath = path.join(commandPath, categoryName);
} else {
commandPath = path.join(commandPath, categoryName, context.input.command);
}
const commandModule = await import(commandPath);
await commandModule.run(context);
}
export const executeAmplifyHeadlessCommand = async (context: $TSContext, headlessPayload: string) => {
switch (context.input.command) {
case 'add':
await headlessAddStorage(context, await validateAddStorageRequest(headlessPayload));
break;
case 'update':
await headlessUpdateStorage(context, await validateUpdateStorageRequest(headlessPayload));
break;
case 'remove':
await headlessRemoveStorage(context, await validateRemoveStorageRequest(headlessPayload));
break;
case 'import':
await headlessImportStorage(context, await validateImportStorageRequest(headlessPayload));
break;
default:
printer.error(`Headless mode for ${context.input.command} storage is not implemented yet`);
}
};
export async function handleAmplifyEvent(context: $TSContext, args: $TSAny) {
printer.info(`${categoryName} handleAmplifyEvent to be implemented`);
printer.info(`Received event args ${args}`);
}
export async function initEnv(context: $TSContext) {
const { resourcesToBeSynced, allResources } = await context.amplify.getResourceStatus(categoryName);
const isPulling = context.input.command === 'pull' || (context.input.command === 'env' && context.input.subCommands[0] === 'pull');
let toBeSynced: $TSObject[] = [];
if (resourcesToBeSynced && resourcesToBeSynced.length > 0) {
toBeSynced = resourcesToBeSynced.filter((b: $TSObject) => b.category === categoryName);
}
toBeSynced
.filter(storageResource => storageResource.sync === 'unlink')
.forEach(storageResource => {
context.amplify.removeResourceParameters(context, categoryName, storageResource.resourceName);
});
let tasks: $TSAny[] = [];
// For pull change detection for import sees a difference, to avoid duplicate tasks we don't
// add the syncable resources, as allResources covers it, otherwise it is required for env add
// to populate the output value and such, these sync resources have the 'refresh' sync value.
if (!isPulling) {
tasks = tasks.concat(toBeSynced);
}
// check if this initialization is happening on a pull
if (isPulling && allResources.length > 0) {
tasks.push(...allResources);
}
const storageTasks = tasks.map(storageResource => {
const { resourceName, service } = storageResource;
return async () => {
const config = await updateConfigOnEnvInit(context, categoryName, resourceName, service);
context.amplify.saveEnvResourceParameters(context, categoryName, resourceName, config);
};
});
await sequential(storageTasks);
}