Search code examples
typescriptamazon-web-servicesaws-lambdaamazon-snsaws-cdk

AWS CDK: Sending and SMS message once a lambda function detects changes in URL


I have a CDK app that uses a lambda function to check for changes to the content of a website. I want that SMS to be sent to a mobile number if the change is detected.

In my AWS CDK project, I created my stack, that builds the lambda function and the SNS

file: lib/lambda_query_website_aws_cdk-stack.ts

import * as cdk from '@aws-cdk/core';
import events = require('@aws-cdk/aws-events');
import targets = require('@aws-cdk/aws-events-targets');
import lambda = require('@aws-cdk/aws-lambda');
import * as sns from '@aws-cdk/aws-sns';
import * as subscriptions from '@aws-cdk/aws-sns-subscriptions';



import fs = require('fs')


export class LambdaQueryWebsiteAwsCdkStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const lambdaFn = new lambda.Function(this, 'Singleton', {
      code: new lambda.InlineCode(fs.readFileSync('lambda-handler.py', { encoding: 'utf-8' })),
      handler: 'index.main',
      timeout: cdk.Duration.seconds(300),
      runtime: lambda.Runtime.PYTHON_3_6,
      environment: {
        'PREV_RESPONSE': ''
      }

    });

    // Runs every 30 minutes from 6:00 to 23:00
    // See https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html
    const rule = new events.Rule(this, 'Rule', {
      schedule: events.Schedule.expression('cron(0/30 6-23 * * ? *)')
    });
    
    rule.addTarget(new targets.LambdaFunction(lambdaFn));

    // Create an SNS Topic.
    // The producer or publisher is the lambda function ??
    //The subscriber or consumer is the sms phone number +15551231234
    const myTopic = new sns.Topic(this, 'MyTopic');
    myTopic.addSubscription(new subscriptions.SmsSubscription('+15551231234'));

  }
}

Here is the lambda function

file lambda-handler.py

import os
import urllib.request

url= "https://mywebsite.com"

def main(event, context):
    print("I'm running!")
    response = urllib.request.urlopen(url)
    response_text = response.read()
    html = response_text.decode('utf-8')

    if os.getenv('PREV_RESPONSE',default="HTML_BODY") != html:
        print("There was a change on the web site")
        os.environ['PREV_RESPONSE'] = HTML
        # TODO:
        # Send the SMS notifying about the change

How do I make the SNS service know that the message needs to be sent?

BR


Solution

  • Try something like this

    export class LambdaQueryWebsiteAwsCdkStack extends cdk.Stack {
        constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
          super(scope, id, props);
      
          const myTopic = new sns.Topic(this, 'MyTopic');
          myTopic.addSubscription(new subscriptions.SmsSubscription('+15551231234'));
    
          const lambdaFn = new lambda.Function(this, 'Singleton', {
            code: new lambda.InlineCode(fs.readFileSync('lambda-handler.py', { encoding: 'utf-8' })),
            handler: 'index.main',
            timeout: cdk.Duration.seconds(300),
            runtime: lambda.Runtime.PYTHON_3_6,
            environment: {
              'PREV_RESPONSE': '',
              'SNS_TOPIC_ARN': myTopic.topicArn  // Include topic ARN as environment variable
            }
          });
          
          myTopic.grantPublish(lambdaFn.role)  // Grant lambda function permission to publish to topic
      
          // Runs every 30 minutes from 6:00 to 23:00
          // See https://docs.aws.amazon.com/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html
          const rule = new events.Rule(this, 'Rule', {
            schedule: events.Schedule.expression('cron(0/30 6-23 * * ? *)')
          });
    
          rule.addTarget(new targets.LambdaFunction(lambdaFn));
        }
      }
    

    And in your python function

    import os
    import boto3
    import urllib.request
    
    url= "https://mywebsite.com"
    client = boto3.client("sns")
    
    SNS_TOPIC_ARN = os.getenv("SNS_TOPIC_ARN")
    
    def main(event, context):
        print("I'm running!")
        response = urllib.request.urlopen(url)
        response_text = response.read()
        html = response_text.decode('utf-8')
    
        if os.getenv('PREV_RESPONSE',default="HTML_BODY") != html:
            os.environ['PREV_RESPONSE'] = html
    
            response = client.publish(
                TopicArn=SNS_TOPIC_ARN,
                Message='There was a change on the web site',
                Subject='Some change!'
            )