Ends in
00
days
00
hrs
00
mins
00
secs
ENROLL NOW

🎁 Get 20% Off - Christmas Big Sale on All Practice Exams, Video Courses, and eBooks!

Unified Slack Automation for Purging the Cache

Home » AWS » Unified Slack Automation for Purging the Cache

Unified Slack Automation for Purging the Cache

Cached data can sometimes be corrupted, which can lead to performance problems. It can also prevent applications and websites from loading the latest version of their content. That’s why clearing cache is a must, not only does it resolve these issues, it also clears up space. Clearing cache is also a way to protect privacy since cache can hold sensitive information.

About the task

Currently, when purging the cache for both TD Portal and TD Main Site, 4 slack commands have to be used:

For TD Portal:

  • /clear-w3 portal
  • /clear-fastcgi portal

For TD Main Site:

  • /clear-wprocket main
  • /clear-fastcgi main

Using these individual commands can be quite a hassle and can also be time-consuming. To resolve this problem, a new slack command has been created (/clear-cache) that takes in a parameter, which can be either portal (For TD Portal) or main (For TD Main Site).

  • /clear-cache portal
      • Clears cache for W3, then Fast-CGI.
  • /clear-cache main
      • Clears cache for WP-Rocket, then Fast-CGI.
  • Tutorials dojo strip
Unified Slack Automation for Purging the Cache

Architecture Diagram

Implementation steps

Creating Slack Bot

If you already have a Slack Application, you may skip this step.

  • Go to Slack API, then click Create New App.
  • Select From Scratch and provide the necessary details:
      • App Name: Your own app name
      • Workspace: The Slack Workspace where you will put the bot in

Creating the SSM Documents

Before we create the Lambda functions, we must first create the SSM Documents that will be accessed by the Lambda functions. We will be creating 3 documents: TD-PurgeW3, TD-PurgeFastCGI, and TD-PurgeWPRocket.

  • Go to AWS Management Console, then search for AWS Systems Manager.
  • Go to Shared Resources > Documents
  • Click Create document > Command or Session (After inputting the details on each Document, at the bottom right side of the screen: Click Create document)
      • First Document:
          • Name: TD-PurgeW3
          • Document Type: Command
          • Content: JSON, then input the following:
        {
          "schemaVersion": "2.2",
          "description": "Purges NGINX FastCGI cache",
          "parameters": {
            "slackHook": {
              "type": "String",
              "description": "(Required) Slack Web hook."
            },
            "requesterName": {
              "type": "String",
              "description": "(Required) Slack user who purges the cache."
            },
            "targetInstance": {
              "type": "String",
              "description": "(Required) Portal or Main site"
            }
          },
          "mainSteps": [
            {
              "action": "aws:runShellScript",
              "name": "runShellScript",
              "inputs": {
                "runCommand": [
                  "#!/bin/bash",
                  "hook='{{ slackHook }}'",
                  "sudo -u ubuntu -i -- wp w3-total-cache flush all --path=[Put here working directory]",
                  "#Notify Slack Channel",
                  "curl -H \"Content-type: application/json\" -d '{\"text\": \"{{ targetInstance }}: {{ requesterName }} cleared W3 Total Cache\"}' -X POST $hook"
                ]
              }
            }
          ]
        }
        
      • Second Document:
          • Name: TD-PurgeFastCGI
          • Document Type: Command
          • Content: JSON, then input the following:
        {
          "schemaVersion": "2.2",
          "description": "Purges NGINX FastCGI cache",
          "parameters": {
            "slackHook": {
              "type": "String",
              "description": "(Required) Slack Web hook."
            },
            "requesterName": {
              "type": "String",
              "description": "(Required) Slack user who purges the cache."
            },
            "targetInstance": {
              "type": "String",
              "description": "(Required) Portal or Main site"
            }
          },
          "mainSteps": [
            {
              "action": "aws:runShellScript",
              "name": "runShellScript",
              "inputs": {
                "runCommand": [
                  "#!/bin/bash",
                  "hook='{{ slackHook }}'",
                  "Working_Directory=\[Put here working directory]",
                  "if [[ -d \"$Working_Directory\" ]]; then",
                  "dir_size=$(sudo du -sh $Working_Directory | awk '{print $1}')",
                  "echo \"Removing cache...\"",
                  "sudo rm -rf $Working_Directory/*",
                  "#Notify Slack Channel",
                  "curl -H \"Content-type: application/json\" -d '{\"text\": \"{{ targetInstance }}: {{ requesterName }} cleared '$dir_size' of cache\"}' -X POST $hook",
                  "else",
                  "echo \"Cache is empty\"",
                  "fi"
                ]
              }
            }
          ]
        }
        
      • Third Document:
          • Name: TD-PurgeWPRocket
          • Document Type: Command
          • Content: JSON, then input the following:
        {
          "schemaVersion": "2.2",
          "description": "Purges WP Rocket cache",
          "parameters": {
            "slackHook": {
              "type": "String",
              "description": "(Required) Slack Web hook."
            },
            "requesterName": {
              "type": "String",
              "description": "(Required) Slack user who purges the cache."
            },
            "targetInstance": {
              "type": "String",
              "description": "(Required) Portal or Main site"
            }
          },
          "mainSteps": [
            {
              "action": "aws:runShellScript",
              "name": "runShellScript",
              "inputs": {
                "runCommand": [
                  "#!/bin/bash",
                  "hook='{{ slackHook }}'",
                  "Working_Directory=\[Put here working directory]",
                  "if [[ -d \"$Working_Directory\" ]]; then",
                  "dir_size=$(sudo du -sh $Working_Directory | awk '{print $1}')",
                  "echo \"Removing cache...\"",
                  "sudo rm -rf $Working_Directory/*",
                  "#Notify Slack Channel",
                  "curl -H \"Content-type: application/json\" -d '{\"text\": \"{{ targetInstance }}: {{ requesterName }} cleared '$dir_size' of WP Rocket cache\"}' -X POST $hook",
                  "else",
                  "echo \"Cache is empty\"",
                  "fi"
                ]
              }
            }
          ]
        }
        

 

Setting up Lambda Functions

We will be creating 2 Lambda functions. The first one (TD-ClearAllCache) accepts a synchronous call from Slack and then returns an acknowledgment response to Slack. The second one (TD-ClearCacheLogic) accepts an asynchronous call from the first lambda function and then sends a response to Slack through the use of the ssm.send_command().

  • On the AWS Management Console, search for Lambda.
  • Click the Create function, then supply the necessary information:
      • Function name:  TD-ClearAllCache
      • Runtime: Python 3.11
      • Existing role: td-invoke-purge-fastcgi-cache-role
  • Go to the Configuration tab and activate the Function URL (This is only for TD-ClearAllCache).
      • Auth type: None
  • Create another Lambda function with this information:
      • Function name:  TD-ClearCacheLogic
      • Runtime: Python 3.11
      • Existing role: td-invoke-purge-fastcgi-cache-role
  • For both Lambda functions, go to Configuration > Environment variables:
      • For TD-ClearAllCache:
        • SIGNING_KEY: You can get this from your Slack Application
        • SLACK_HOOK: Webhook URL from Slack
        • SLACK_CHANNEL: Slack channel where you will test/use the command
      • For TD-ClearCacheLogic:
        • PORTAL_INSTANCE_ID: Instance ID
        • MAIN_INSTANCE_ID: Instance ID
        • SSM_PURGE_FASTCGI: TD-PurgeFastCGI
        • SSM_PURGE_W3: TD-Purge-W3
        • SSM_PURGE_WPRocket: TD-PurgeWPRocket
  • For both Lambda functions, go to Configuration > General configuration:
      • For TD-ClearAllCache: Change Timeout to 10 sec
      • For TD-ClearCacheLogic: Change Timeout to 30 sec
  • Use the following code for the respective Lambda functions:
      • For TD-ClearAllCache:
        import json
        import boto3
        import base64
        import os
        import hashlib
        import hmac
        
        lambda_client = boto3.client('lambda')
        
        #Set up constants
        SLACK_CHANNEL = os.environ["SLACK_CHANNEL"]
        SIGNING_KEY   = os.environ["SIGNING_KEY"]
        SLACK_HOOK    = os.environ["SLACK_HOOK"]
        
        
        def lambda_handler(event, context):
            
            #Parse event data
            slack_signature = event['headers']["x-slack-signature"]
            slack_timestamp = event['headers']['x-slack-request-timestamp']
            slack_payload   = event['body']
            payload         = parse_slack_payload(slack_payload)
            from_channel    = payload["channel_name"]
            
            #Check if request originates from valid source
            from_valid_source =  verify_source(signing_key=SIGNING_KEY.encode('utf-8'),
                                              timestamp=slack_timestamp,
                                              body=base64.b64decode(slack_payload).decode('utf-8'),
                                              slack_signature=slack_signature,
                                              from_channel=from_channel
                                              )
            
            
            if from_valid_source:
                new_payload = {
                    'body': {
                        'target_instance': payload['text'],
                        'requester': payload["user_name"],
                        'hook': SLACK_HOOK
                    }
                }
                
                try:
                    lambda_client.invoke(FunctionName='TD-ClearCacheLogic',
                                                    InvocationType='Event',
                                                    Payload=json.dumps(new_payload)
                                                    )
                  
                    return f'Request Authorized \nRequest Id: {context.aws_request_id}'
                
                except Exception as e:
                    return f'{e}'
                    
            else:
                return "You're not authorized to do this operation"
            
            
        def parse_slack_payload(data):
            # decode the data using the b64decode function
            decoded_data_raw = base64.b64decode(data).decode('utf-8').split('&')
            decoded_data_formatted={key:value for key, value in [i.split("=") for i in decoded_data_raw]}
            return decoded_data_formatted
                
            
        def verify_source(signing_key, timestamp, body, slack_signature, from_channel):
            
            basetring = f'v0:{timestamp}:{body}'
            hmac_digest = hmac.new(key=signing_key,
                                  msg=basetring.encode('utf-8'),
                                  digestmod=hashlib.sha256).hexdigest()
                                   
            if hmac.compare_digest(slack_signature, f'v0={hmac_digest}') and SLACK_CHANNEL == from_channel:
                return True    
        
      • For TD-ClearCacheLogic:
        import boto3
        from botocore.config import Config
        import os
        import time
        
        #Set up constants
        PORTAL_INSTANCE_ID   = os.environ["PORTAL_INSTANCE_ID"]
        MAIN_INSTANCE_ID = os.environ["MAIN_INSTANCE_ID"]
        SSM_PURGE_FASTCGI = os.environ["SSM_PURGE_FASTCGI"]
        SSM_PURGE_W3 = os.environ["SSM_PURGE_W3"]
        SSM_PURGE_WPRocket = os.environ["SSM_PURGE_WPRocket"]
        
        
        def lambda_handler(event, context):
            payload = event["body"]
            hook = payload['hook']
            requester = payload['requester']
            target_instance = payload['target_instance']
            
            purge_cache(hook, requester, target_instance)
            
            return
            
            
        def purge_cache(hook, requester, target_instance):
            
            target_instances = {
                'portal': { 
                    'instance_id': PORTAL_INSTANCE_ID,
                    'region': [put here the region where your instance is located e.g 'us-east-1']
                    },
                'main': { 
                    'instance_id': MAIN_INSTANCE_ID,
                    'region': [put here the region where your instance is located e.g 'us-east-1']
                    }
            }
            
            instance_ssm_documents = {
                'portal':{
                    'w3': SSM_PURGE_W3,
                    'fastcgi': SSM_PURGE_FASTCGI
                },
                'main': {
                    'wprocket': SSM_PURGE_WPRocket,
                    'fastcgi': SSM_PURGE_FASTCGI
                }
            }
            
            for target_document in instance_ssm_documents[target_instance].values():
                target_instance_id = target_instances[target_instance]['instance_id']
                target_region   = target_instances[target_instance]['region']
            
                print(target_instance_id, target_region, target_document)
                
                ssm = boto3.client('ssm', config=Config(region_name = target_region))
                response = ssm.send_command(
                InstanceIds=[
                    target_instance_id,
                    ],
                    DocumentName=target_document,
                    Parameters={
                        'slackHook': [hook],
                        'requesterName': [requester],
                        'targetInstance': [ target_instance.upper() ]
                        },
                    TimeoutSeconds=30
                )
                print(response)
                time.sleep(6)
                
        

Connecting the Slack Slash Command to the Lambda function using the Function URL

  • Go to TD-ClearAllCache and copy the Function URL.
  • Go to your Slack Application, then go to Slash Commands.
  • Click Create New Command, then input the necessary details:
      • Command: /clear-cache
      • Request URL: The Function URL goes here
      • Short Description: Put here what your slash command is supposed to do
      • Usage Hint: Here you can put the parameters that the command needs in order to work
  • Double-check the Preview of Autocomplete Entry, then click Save.

Using the Slash Command

  • Go to the channel where you will test the Slash Command.
  • Type /clear-cache portal | main
      • [portal | main] are the parameters to choose from. Whether to clear TD Portal or TD Main Site.
  • This should be the output for /clear-cache portal:

  • This should be the output for /clear-cache main:
Free AWS Courses

Unified Slack Automation for Purging the Cache

Rollback Plan

Deleting Slack App:

  • Go to Slack API > Your Apps > then click the name of your app in App Name

Unified Slack Automation for Purging the Cache

  • Scroll down, then click Delete App

Unified Slack Automation for Purging the Cache

Deleting Lambda Functions:

  • Go to either TD-ClearAllCache or TD-ClearCacheLogic
  • Click the Actions dropdown box, then click the Delete function

Unified Slack Automation for Purging the Cache

Unified Slack Automation for Purging the Cache

  • Then, repeat the steps for the other function.

Get 20% Off – Christmas Big Sale on All Practice Exams, Video Courses, and eBooks!

Tutorials Dojo portal

Learn AWS with our PlayCloud Hands-On Labs

Tutorials Dojo Exam Study Guide eBooks

tutorials dojo study guide eBook

FREE AWS Exam Readiness Digital Courses

FREE AWS, Azure, GCP Practice Test Samplers

Subscribe to our YouTube Channel

Tutorials Dojo YouTube Channel

Follow Us On Linkedin

Recent Posts

Written by: Alain Torno

Alain Andrei Torno is an AWS Certified Cloud Practitioner and an intern at Tutorials Dojo. He is the Backend Lead and Web Development Co-Head at AWS Cloud Club - PUP Manila. Currently, he is an undergraduate at Polytechnic University of the Philippines taking up Bachelors Degree in Information Technology.

AWS, Azure, and GCP Certifications are consistently among the top-paying IT certifications in the world, considering that most companies have now shifted to the cloud. Earn over $150,000 per year with an AWS, Azure, or GCP certification!

Follow us on LinkedIn, YouTube, Facebook, or join our Slack study group. More importantly, answer as many practice exams as you can to help increase your chances of passing your certification exams on your first try!

View Our AWS, Azure, and GCP Exam Reviewers Check out our FREE courses

Our Community

~98%
passing rate
Around 95-98% of our students pass the AWS Certification exams after training with our courses.
200k+
students
Over 200k enrollees choose Tutorials Dojo in preparing for their AWS Certification exams.
~4.8
ratings
Our courses are highly rated by our enrollees from all over the world.

What our students say about us?