From 8cbb0a562ca70d136fed346ed5decfd19e557bcf Mon Sep 17 00:00:00 2001 From: EC2 Default User Date: Wed, 3 Nov 2021 22:15:11 +0000 Subject: [PATCH 1/2] adding functionality for ivs notifications --- .../ivs-helpers/IvsSnsSetup.template.ejs | 134 ++++++++++++++++++ .../LambdaFunctions/IvsStatusLambda/index.js | 9 ++ .../ivs-workflow-template.yaml.ejs | 38 +++++ .../service-walkthroughs/ivs-push.js | 51 ++++++- provider-utils/ivs-questions.json | 24 ++++ 5 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 provider-utils/awscloudformation/cloudformation-templates/ivs-helpers/IvsSnsSetup.template.ejs create mode 100644 provider-utils/awscloudformation/cloudformation-templates/ivs-helpers/LambdaFunctions/IvsStatusLambda/index.js diff --git a/provider-utils/awscloudformation/cloudformation-templates/ivs-helpers/IvsSnsSetup.template.ejs b/provider-utils/awscloudformation/cloudformation-templates/ivs-helpers/IvsSnsSetup.template.ejs new file mode 100644 index 00000000..9e1b4082 --- /dev/null +++ b/provider-utils/awscloudformation/cloudformation-templates/ivs-helpers/IvsSnsSetup.template.ejs @@ -0,0 +1,134 @@ +Description: + "IVS notifications sent to SNS and then forwarded to Lambda" + +Parameters: + env: + Type: String + Description: The environment name. e.g. Dev, Test, or Production. + Default: NONE + pS3: + Type: String + Description: Store template and lambda package + AllowedPattern: "[a-zA-Z][a-zA-Z0-9-_]*" + Default: amazonbooth + pSourceFolder: + Type: String + Description: Store template and lambda package + AllowedPattern: "[a-zA-Z][a-zA-Z0-9-_]*" + Default: vod-helpers + pSnsTopicName: + Type: String + Description: Topic Name + Default: default + pFunctionName: + Type: String + Description: Function Name + Default: IvsChannelStatusLambda + pFunctionHash: + Type: String + Description: FunctionHash + Default: default + +Resources: + + IvsNotificationsSNS: + Type: AWS::SNS::Topic + + IvsEventsRule: + Type: AWS::Events::Rule + Properties: + Description: "Event rule for IVS" + EventPattern: + source: + - aws.ivs + detail-type: + - "IVS Stream State Change" + State: ENABLED + Targets: + - Arn: !Ref IvsNotificationsSNS + Id: IvsNotificationsSNS + + rIvsNotificationsSNSPolicy: + Type: 'AWS::SNS::TopicPolicy' + Properties: + Topics: + - !Ref IvsNotificationsSNS + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Sid: "1" + Action: 'sns:Publish' + Resource: !Ref IvsNotificationsSNS + Principal: + AWS: '*' + Condition: + ArnLike: + AWS:SourceArn: !Sub 'arn:aws:*:*:${AWS::AccountId}:*' + - Effect: Allow + Sid: "2" + Action: "sns:Publish" + Principal: + Service : 'events.amazonaws.com' + Resource: !Ref IvsNotificationsSNS + +<% if (props.status.lambda) { -%> + rIvsStatusLambda: + Type: AWS::Lambda::Function + Properties: + FunctionName: !Ref pFunctionName + Description: Invoked on IVS status events + Handler: index.handler + Role: !GetAtt rIvsStatusLambdaRole.Arn + Runtime: nodejs14.x + Timeout: 30 + Code: + S3Bucket: !Ref pS3 + S3Key: !Sub + - ivs-helpers/IvsStatusLambda-${hash}.zip + - { hash: !Ref pFunctionHash } + + rIvsStatusLambdaRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - + Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - sts:AssumeRole + Policies: + - + PolicyName: !Sub "${AWS::AccountId}-ivs-status-processing-role" + PolicyDocument: + Statement: + - + Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:DescribeLogStreams + - logs:PutLogEvents + Resource: + - arn:aws:logs:*:*:* + + rSNSLambdaPermissions: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !Ref rIvsStatusLambda + Action: lambda:InvokeFunction + Principal: sns.amazonaws.com + SourceArn: !Sub arn:aws:sns:${AWS::Region}:${AWS::AccountId}:* + + rSNSLambdaSubscription: + Type: AWS::SNS::Subscription + Properties: + Protocol: lambda + Endpoint: !GetAtt rIvsStatusLambda.Arn + TopicArn: !Ref IvsNotificationsSNS + +<% } -%> \ No newline at end of file diff --git a/provider-utils/awscloudformation/cloudformation-templates/ivs-helpers/LambdaFunctions/IvsStatusLambda/index.js b/provider-utils/awscloudformation/cloudformation-templates/ivs-helpers/LambdaFunctions/IvsStatusLambda/index.js new file mode 100644 index 00000000..3a897256 --- /dev/null +++ b/provider-utils/awscloudformation/cloudformation-templates/ivs-helpers/LambdaFunctions/IvsStatusLambda/index.js @@ -0,0 +1,9 @@ +console.log('Loading function'); + +exports.handler = async (event, context) => { + // console.log('Received event:', JSON.stringify(event, null, 2)); + const message = event.Records[0].Sns.Message; + console.log('From SNS:', message); + console.log('context ', context); + return message; +}; diff --git a/provider-utils/awscloudformation/cloudformation-templates/ivs-workflow-template.yaml.ejs b/provider-utils/awscloudformation/cloudformation-templates/ivs-workflow-template.yaml.ejs index 356b38c2..671fb6b8 100644 --- a/provider-utils/awscloudformation/cloudformation-templates/ivs-workflow-template.yaml.ejs +++ b/provider-utils/awscloudformation/cloudformation-templates/ivs-workflow-template.yaml.ejs @@ -28,6 +28,14 @@ Parameters: Type: String Description: Quality of channel Default: <%= props.channel.channelQuality %> +<% if (props.status.reportStatus) { -%> + pSnsTopicName: + Type: String + Description: Name of the SNS topic for MediaConvert status events + AllowedPattern: "[a-zA-Z][a-zA-Z0-9-_]*" + Default: AmplifyIvsChannelEvents +<% } -%> + Conditions: HasEnvironmentParameter: @@ -50,6 +58,36 @@ Resources: pLatencyMode: !Ref pLatencyMode pQuality: !Ref pQuality + + +<% if (props.status.reportStatus) { -%> + rSnsInvokeLambdaSetup: + Type: AWS::CloudFormation::Stack + Properties: + TemplateURL: !Sub "https://s3.amazonaws.com/${pS3}/${pSourceFolder}/IvsSnsSetup.template" + Parameters: + env: !Ref env + pS3: !Ref pS3 + pSourceFolder: !Ref pSourceFolder + pSnsTopicName: !Ref pSnsTopicName + pFunctionHash: "<%= props.hashes.IvsStatusLambda %>" + pFunctionName: + !If + - HasEnvironmentParameter + - !Join + - '-' + - - !Ref pProjectName + - !Ref env + - 'IvsChannelStatusLambda' + - !Join + - '-' + - - !Ref pProjectName + - 'IvsChannelStatusLambda' + +<% } -%> + + + Outputs: oVideoOutput: Value: !GetAtt rIVSChannel.Outputs.oVideoOutput diff --git a/provider-utils/awscloudformation/service-walkthroughs/ivs-push.js b/provider-utils/awscloudformation/service-walkthroughs/ivs-push.js index 663e0802..7a829e1e 100644 --- a/provider-utils/awscloudformation/service-walkthroughs/ivs-push.js +++ b/provider-utils/awscloudformation/service-walkthroughs/ivs-push.js @@ -76,11 +76,58 @@ async function serviceQuestions(context, options, defaultValuesFilename, resourc value: args.channelLatency ? args.channelLatency : question.channelLatency.default, }); }, - }, + } ]; + + const statusReporting = [ + { + type: question.reportStatus.type, + name: question.reportStatus.key, + message: question.reportStatus.question, + choices: question.reportStatus.options, + default: question.reportStatus.default, + when(answers) { + return headlessMode.autoAnswer({ + context, + answers, + key: question.reportStatus.key, + value: args.reportStatus ? args.reportStatus : question.reportStatus.default, + }); + }, + } + ] + + const statusLambda = [ + { + type: question.reportStatusLambda.type, + name: question.reportStatusLambda.key, + message: question.reportStatusLambda.question, + choices: question.reportStatusLambda.options, + default: question.reportStatusLambda.default, + when(answers) { + return headlessMode.autoAnswer({ + context, + answers, + key: question.reportStatusLambda.key, + value: args.reportStatusLambda ? args.reportStatusLambda : question.reportStatusLambda.default, + }); + }, + } + + ] + const channelQuestions = await inquirer.prompt(createChannel); props.channel = channelQuestions; + const statusQuestions = await inquirer.prompt(statusReporting); + props.status = statusQuestions + + + if(statusQuestions.reportStatus === true){ + const statusQuestionsLambda = await inquirer.prompt(statusLambda); + props.status.lambda = statusQuestionsLambda.reportStatusLambda + } + return props; -} +} \ No newline at end of file diff --git a/provider-utils/ivs-questions.json b/provider-utils/ivs-questions.json index e6ffae73..3871508d 100644 --- a/provider-utils/ivs-questions.json +++ b/provider-utils/ivs-questions.json @@ -46,5 +46,29 @@ ], "default": "LOW", "required": true + }, + "reportStatus" : { + "key": "reportStatus", + "question": "Report status of the channel", + "type": "confirm", + "default": "true", + "required": true, + "options" : [ + { + "value" : "true", + "next" : "reportStatusLambda" + }, + { + "value" : "false", + "next" : "" + } + ] + }, + "reportStatusLambda" : { + "key": "reportStatusLambda", + "question": "Invoke Lambda on channel status event", + "type": "confirm", + "default": "true", + "required": true } } From a2c141dce974bc35af71c10c57ca3cecf0d5b5f5 Mon Sep 17 00:00:00 2001 From: EC2 Default User Date: Wed, 3 Nov 2021 22:41:26 +0000 Subject: [PATCH 2/2] linting the files --- .../service-walkthroughs/ivs-push.js | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/provider-utils/awscloudformation/service-walkthroughs/ivs-push.js b/provider-utils/awscloudformation/service-walkthroughs/ivs-push.js index 7a829e1e..4a2b5198 100644 --- a/provider-utils/awscloudformation/service-walkthroughs/ivs-push.js +++ b/provider-utils/awscloudformation/service-walkthroughs/ivs-push.js @@ -76,10 +76,9 @@ async function serviceQuestions(context, options, defaultValuesFilename, resourc value: args.channelLatency ? args.channelLatency : question.channelLatency.default, }); }, - } + }, ]; - const statusReporting = [ { type: question.reportStatus.type, @@ -95,11 +94,11 @@ async function serviceQuestions(context, options, defaultValuesFilename, resourc value: args.reportStatus ? args.reportStatus : question.reportStatus.default, }); }, - } - ] - - const statusLambda = [ - { + }, + ]; + + const statusLambda = [ + { type: question.reportStatusLambda.type, name: question.reportStatusLambda.key, message: question.reportStatusLambda.question, @@ -110,24 +109,23 @@ async function serviceQuestions(context, options, defaultValuesFilename, resourc context, answers, key: question.reportStatusLambda.key, - value: args.reportStatusLambda ? args.reportStatusLambda : question.reportStatusLambda.default, + value: args.reportStatusLambda + ? args.reportStatusLambda : question.reportStatusLambda.default, }); }, - } - - ] - + }, + ]; + const channelQuestions = await inquirer.prompt(createChannel); props.channel = channelQuestions; const statusQuestions = await inquirer.prompt(statusReporting); - props.status = statusQuestions - - - if(statusQuestions.reportStatus === true){ + props.status = statusQuestions; + + if (statusQuestions.reportStatus === true) { const statusQuestionsLambda = await inquirer.prompt(statusLambda); - props.status.lambda = statusQuestionsLambda.reportStatusLambda + props.status.lambda = statusQuestionsLambda.reportStatusLambda; } - + return props; -} \ No newline at end of file +}