Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to add custom EventSource and lambda triggers via amplify add function, Kinesis support in analytics category #2463

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
f383c94
feat(amplify-category-function): trig base logic
ambientlight Sep 30, 2019
75ef928
fix(amplify-category-function): lint-fix
ambientlight Sep 30, 2019
c9da7da
feat(graphql-dynamodb-transformer): liftnested out
ambientlight Sep 30, 2019
bfe7a44
feat(amplify-category-function): api/storage trigs
ambientlight Sep 30, 2019
a1ba0ed
fix(amplify-category-function): remove sqs from lambda triggers
ambientlight Oct 19, 2019
31db0aa
feat(cli): optional custom question in service-select-prompt
ambientlight Oct 20, 2019
16294f5
fix(cli): fix param rename in comments in copy-batch
ambientlight Oct 21, 2019
9432e3d
feat(amplify-category-analytics): barebone kinesis
ambientlight Oct 21, 2019
14c95a6
feat(amplify-category-analytics): kinesis cognito policies
ambientlight Oct 21, 2019
9516fe6
feat(amplify-category-analytics): kinesis update support
ambientlight Oct 22, 2019
c462608
feat(amplify-category-function): analytics kinesis trigger support
ambientlight Oct 22, 2019
ef4d0dd
Merge branch 'master' into lambda-custom-event-source
ambientlight Oct 23, 2019
e116ca9
fix: lint fix
ambientlight Oct 23, 2019
bc5385d
fix(amplify-category-function): fix non appsync resources, redund prompt
ambientlight Oct 23, 2019
5aee354
fix(amplify-category-analytics): getIAMPolicies for kinesis
ambientlight Oct 23, 2019
0fa8c87
fix(amplify-category-analytics): create flow filter condition in kinesis
ambientlight Oct 23, 2019
c2e5027
feat(amplify-provider-awscloudformation): nested stack outputs in meta
ambientlight Oct 29, 2019
44d596b
fix(amplify-provider-awscloudformation): logicalId nested, nested forall
ambientlight Oct 30, 2019
f1d7c82
fix(graphql-dynamodb-transformer): remove exposed nested outputs in root
ambientlight Nov 2, 2019
d1bb7a1
feat(amplify-provider-awscloudformation): exports support
ambientlight Nov 2, 2019
047fece
fix(amplify-provider-awscloudformation): depends.exports fixes
ambientlight Nov 2, 2019
6415619
feat(amplify-category-function): dynamoDB lambda trigger with exports
ambientlight Nov 2, 2019
48e5a2c
feat(amplify-category-analytics): check auth rules in kinesis
ambientlight Nov 3, 2019
fbbb939
fix(amplify-provider-awscloudformation): cleaner dependsOn exports
ambientlight Nov 3, 2019
21af03b
fix(amplify-category-function): importValue directly for multienv
ambientlight Nov 3, 2019
5579a9c
feat(amplify-category-analytics): kinesis tweaks, console support
ambientlight Nov 18, 2019
2b628e4
feat(amplify-category-analytics): lock single kinesis resource
ambientlight Nov 18, 2019
548293d
feat(amplify-category-function): collect directives, multi-DDB support
ambientlight Nov 18, 2019
c9a4c70
feat(amplify-category-function): lint fix, missed assign, tran-core dep
ambientlight Nov 18, 2019
41ebcb6
feat(amplify-category-api): model-scoped getIAMPolicies
ambientlight Nov 18, 2019
f8788e0
feat(amplify-provider-awscloudformation): remove exports aggregation
ambientlight Nov 18, 2019
e86b49f
fix(amplify-provider-awscloudformation): fix leftover resourceOutput
ambientlight Dec 19, 2019
fee6dcf
Merge branch 'master' into lambda-custom-event-source
ambientlight Jan 9, 2020
7d53c9e
Revert "feat(amplify-category-api): model-scoped getIAMPolicies"
ambientlight Jan 19, 2020
5758a5b
feat(amplify-category-function): trigger dep GraphQLAPIEndpointOutput
ambientlight Jan 19, 2020
b3f5913
fix(amplify-category-api): fix undefined TransformPackage
ambientlight Jan 19, 2020
0f1e2c7
feat(amplify-category-function): appsync @model tables in storage flow
ambientlight Jan 20, 2020
c30dc36
Merge branch 'master' into lambda-custom-event-source
ambientlight Jan 20, 2020
5b3660c
fix(amplify-category-function): fn::sub reference, storage flow
ambientlight Jan 29, 2020
e3ec6ae
Merge branch 'lambda-custom-event-source' of https://github.com/ambie…
ambientlight Jan 29, 2020
d9903c2
Merge branch 'master' into lambda-custom-event-source
ambientlight Jan 29, 2020
b0af83b
feat(amplify-category-function): model permissions lambda envs
ambientlight Jan 29, 2020
452f46f
fix(amplify-category-analytics): typos, use latest api for service meta
ambientlight Feb 1, 2020
77b4b4c
fix(amplify-category-function): remove scripts, update deps
ambientlight Feb 1, 2020
07a2165
fix(amplify-category-function): guard absent res category in meta
ambientlight Feb 6, 2020
e904ce7
fix(amplify-category-function): package.json update
ambientlight Feb 6, 2020
c7226e7
Merge branch 'master' into lambda-custom-event-source
ambientlight Feb 6, 2020
b58bfc8
fix(amplify-category-function): update flow CF params assume Ref envvar
ambientlight Feb 7, 2020
f6d474b
fix(amplify-category-function): triggerEventSourceMappings as array
ambientlight Feb 11, 2020
30744aa
fix(amplify-category-analytics): extend getIAMPolicies for kinesis
ambientlight Feb 17, 2020
1218ff8
fix(amplify-e2e-tests): account for analytics flow update
ambientlight Feb 20, 2020
fdcba7d
feat(amplify-e2e-tests): sample lambda trigger e2e test
ambientlight Feb 23, 2020
1f79657
feat(amplify-e2e-tests): kinesis trigger, name validation, template
ambientlight Feb 23, 2020
68a0b7e
fix(amplify-category-function): fix inf loop in unexisting ddb, tests
ambientlight Feb 24, 2020
3dc454b
feat(amplify-e2e-tests): additional perm tests, fix ddb arn derivation
ambientlight Feb 25, 2020
3fc7e57
Merge https://github.com/aws-amplify/amplify-cli into lambda-custom-e…
ambientlight Feb 25, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/amplify-category-analytics/amplify-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
"add",
"remove",
"push",
"update",
"console",
"help"
],
"commandAliases":{
"configure": "update"
},
"eventHandlers": []
}
4 changes: 4 additions & 0 deletions packages/amplify-category-analytics/commands/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ module.exports = {
name: 'add',
description: `Takes you through a CLI flow to add an ${featureName} resource to your local backend`,
},
{
name: 'update',
description: `Takes you through steps in the CLI to update an ${featureName} resource`,
},
{
name: 'push',
description: `Provisions only ${featureName} cloud resources with the latest local developments`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module.exports = {
const { amplify } = context;
const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-services.json`);
return amplify
.serviceSelectionPrompt(context, category, servicesMetadata)
.serviceSelectionPrompt(context, category, servicesMetadata, 'Select an Analytics provider')
.then(result => {
options = {
service: result.service,
Expand Down
43 changes: 43 additions & 0 deletions packages/amplify-category-analytics/commands/analytics/update.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const subcommand = 'update';
const category = 'analytics';

module.exports = {
name: subcommand,
alias: ['configure'],
run: async context => {
const { amplify } = context;
const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-services.json`);

return amplify
.serviceSelectionPrompt(context, category, servicesMetadata)
.then(result => {
const options = {
service: result.service,
providerPlugin: result.providerName,
};

const providerController = require(`../../provider-utils/${result.providerName}/index`);
if (!providerController) {
context.print.error('Provider not configured for this category');
return;
}

return providerController.updateResource(context, category, result.service, options);
})
.then(resourceName => {
const { print } = context;
print.success(`Successfully updated resource ${resourceName} locally`);
print.info('');
print.success('Some next steps:');
print.info('"amplify push" will build all your local backend resources and provision it in the cloud');
print.info(
'"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud',
);
print.info('');
})
.catch(err => {
context.print.info(err.stack);
context.print.error(`There was an error updating the ${category} resource`);
});
},
};
40 changes: 37 additions & 3 deletions packages/amplify-category-analytics/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,45 @@
const path = require('path');
const inquirer = require('inquirer');
const pinpointHelper = require('./lib/pinpoint-helper');
const kinesisHelper = require('./lib/kinesis-helper');
const { migrate } = require('./provider-utils/awscloudformation/service-walkthroughs/pinpoint-walkthrough');

const category = 'analytics';

function console(context) {
pinpointHelper.console(context);
async function console(context) {
const hasKinesisResource = kinesisHelper.hasResource(context);
const hasPinpointResource = pinpointHelper.hasResource(context);

let selectedResource;
if (hasKinesisResource && hasPinpointResource) {
const question = {
name: 'resource',
message: 'Select resource',
type: 'list',
choices: ['kinesis', 'pinpoint'],
required: true,
};

const result = await inquirer.prompt(question);
selectedResource = result.resource;
} else if (hasKinesisResource) {
selectedResource = 'kinesis';
} else if (hasPinpointResource) {
selectedResource = 'pinpoint';
} else {
context.print.error('Neither analytics nor notifications is enabled in the cloud.');
attilah marked this conversation as resolved.
Show resolved Hide resolved
}

switch (selectedResource) {
case 'kinesis':
kinesisHelper.console(context);
break;
case 'pinpoint':
pinpointHelper.console(context);
break;
default:
break;
}
}

async function getPermissionPolicies(context, resourceOpsMapping) {
Expand All @@ -22,7 +56,7 @@ async function getPermissionPolicies(context, resourceOpsMapping) {
context,
amplifyMeta[category][resourceName].service,
resourceName,
resourceOpsMapping[resourceName]
resourceOpsMapping[resourceName],
);
permissionPolicies.push(policy);
resourceAttributes.push({ resourceName, attributes, category });
Expand Down
1 change: 1 addition & 0 deletions packages/amplify-category-analytics/lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ module.exports = {
CategoryName: 'analytics',
NotificationsCategoryName: 'notifications',
PinpointName: 'Pinpoint',
KinesisName: 'Kinesis',
};
54 changes: 54 additions & 0 deletions packages/amplify-category-analytics/lib/kinesis-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const open = require('open');
const constants = require('./constants');

function console(context) {
const amplifyMeta = context.amplify.getProjectMeta();
const { envName } = context.amplify.getEnvInfo();
const region = context.amplify.getEnvDetails()[envName].awscloudformation.Region;

const kinesisApp = scanCategoryMetaForKinesis(amplifyMeta[constants.CategoryName]);
if (kinesisApp) {
const { Id } = kinesisApp;
const consoleUrl = `https://${region}.console.aws.amazon.com/kinesis/home?region=${region}#/streams/details?streamName=${Id}&tab=details`;
open(consoleUrl, { wait: false });
} else {
context.print.error('Kinesis is not enabled in the cloud.');
}
}

function scanCategoryMetaForKinesis(categoryMeta) {
// single kinesis resource for now
let result;
if (categoryMeta) {
const services = Object.keys(categoryMeta);
for (let i = 0; i < services.length; i++) {
const serviceMeta = categoryMeta[services[i]];
if (serviceMeta.service === constants.KinesisName && serviceMeta.output && serviceMeta.output.kinesisStreamId) {
result = {
Id: serviceMeta.output.kinesisStreamId,
};
if (serviceMeta.output.Name) {
result.Name = serviceMeta.output.Name;
} else if (serviceMeta.output.appName) {
result.Name = serviceMeta.output.appName;
}

if (serviceMeta.output.Region) {
result.Region = serviceMeta.output.Region;
}
break;
}
}
}
return result;
}

function hasResource(context) {
const amplifyMeta = context.amplify.getProjectMeta();
return scanCategoryMetaForKinesis(amplifyMeta[constants.CategoryName]) !== undefined;
}

module.exports = {
console,
hasResource,
};
11 changes: 11 additions & 0 deletions packages/amplify-category-analytics/lib/pinpoint-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ function scanCategoryMetaForPinpoint(categoryMeta) {
return result;
}

function hasResource(context) {
const amplifyMeta = context.amplify.getProjectMeta();
let pinpointApp = scanCategoryMetaForPinpoint(amplifyMeta[constants.CategoryName]);
if (!pinpointApp) {
pinpointApp = scanCategoryMetaForPinpoint(amplifyMeta[constants.NotificationsCategoryName]);
}

return pinpointApp !== undefined;
}

module.exports = {
hasResource,
console,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Pinpoint resource stack creation using Amplify CLI",
"Parameters": {
"env": {
"Type": "String"
},
"kinesisStreamName": {
"Type": "String"
},
"kinesisStreamShardCount": {
"Type": "Number",
"Default": 1
},
"authPolicyName": {
"Type": "String"
},
"unauthPolicyName": {
"Type": "String"
},
"authRoleName": {
"Type": "String"
},
"unauthRoleName": {
"Type": "String"
}
},
"Conditions": {
"ShouldNotCreateEnvResources": {
"Fn::Equals": [
{ "Ref": "env" },
"NONE"
]
}
},
"Resources": {
"KinesisStream": {
"Type": "AWS::Kinesis::Stream",
"Properties": {
"Name": {
"Fn::Join": [
"-",
[
{ "Ref": "kinesisStreamName" },
{ "Ref": "env"}
]
]
},
"ShardCount": { "Ref": "kinesisStreamShardCount" }
}
},
"CognitoUnauthPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": {"Ref": "unauthPolicyName" },
"Roles": [
{"Ref": "unauthRoleName" }
],
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"kinesis:PutRecord",
"kinesis:PutRecords"
],
"Resource": {
"Fn::GetAtt": ["KinesisStream", "Arn"]
}
}]
}
}
},
"CognitoAuthPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": {"Ref": "authPolicyName" },
"Roles": [
{"Ref": "authRoleName" }
],
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"kinesis:PutRecord",
"kinesis:PutRecords"
],
"Resource": {
"Fn::GetAtt": ["KinesisStream", "Arn"]
}
}]
}
}
}
},
"Outputs": {
"kinesisStreamArn": {
"Value": {"Fn::GetAtt": ["KinesisStream", "Arn"] }
},
"kinesisStreamId": {
"Value": {"Ref": "KinesisStream" }
},
"kinesisStreamShardCount": {
"Value": {"Ref": "kinesisStreamShardCount" }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const uuid = require('uuid');

const getAllDefaults = project => {
const appName = project.projectConfig.projectName.toLowerCase();
const [shortId] = uuid().split('-');

const authRoleName = {
Ref: 'AuthRoleName',
};

const unauthRoleName = {
Ref: 'UnauthRoleName',
};

const defaults = {
kinesisStreamName: `${appName}Kinesis`,
kinesisStreamShardCount: 1,
authRoleName,
unauthRoleName,
authPolicyName: `kinesis_amplify_${shortId}`,
unauthPolicyName: `kinesis_amplify_${shortId}`,
};

return defaults;
};

module.exports = {
getAllDefaults,
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ function addResource(context, category, service) {
return addWalkthrough(context, defaultValuesFilename, serviceMetadata);
}

function updateResource(context, category, service) {
const serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service];
const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata;
const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`;
const { updateWalkthrough } = require(serviceWalkthroughSrc);

if (!updateWalkthrough) {
context.print.error('Update functionality not available for this service');
process.exit(0);
}

return updateWalkthrough(context, defaultValuesFilename, serviceMetadata);
}

function getPermissionPolicies(context, service, resourceName, crudOptions) {
const serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service];
const { serviceWalkthroughFilename } = serviceMetadata;
Expand All @@ -22,4 +36,4 @@ function getPermissionPolicies(context, service, resourceName, crudOptions) {
return getIAMPolicies(resourceName, crudOptions);
}

module.exports = { addResource, getPermissionPolicies };
module.exports = { addResource, getPermissionPolicies, updateResource };
Loading