Ends in
00
hrs
00
mins
00
secs
ENROLL NOW

48 Hour FLASH SALE - 10% OFF ALL PLANS. Use Coupon Code: TD-PLAYCLOUD-0925

Automated Slack Notifications for RI Coverage Across All AWS Regions

Home » Others » Automated Slack Notifications for RI Coverage Across All AWS Regions

Automated Slack Notifications for RI Coverage Across All AWS Regions

Efficient management of cloud resources is essential for maintaining a company’s flexibility and cost-effectiveness. Reserved Instances (RIs) offer significant cost-saving opportunities, but to fully leverage its benefits, consistent monitoring and optimization are key. By automating Slack notifications for RI coverage, businesses can ensure teams stay informed and take timely action to maximize savings. This comprehensive article explores the advantages of integrating automated Slack notifications for RI coverage across all AWS regions, helping teams maintain financial efficiency and operational agility.

Importance of Monitoring RI Coverage

It is crucial to effectively monitor Reserved Instance (RI) coverage for several reasons:

  1. It helps prevent wasted resources. Since RIs represent a financial commitment, diligent monitoring ensures you aren’t paying for unused capacity. This proactive approach not only safeguards your budget but also enhances overall efficiency.
  2. Accurate tracking enables you to maximize savings by identifying when additional RIs are necessary or when existing ones should be adjusted to align with current workloads.
  3. Compliance with regulations often requires a certain level of resource management and reporting.
Tutorials dojo strip

Automated notifications are vital in helping you meet these obligations and ensuring you stay on the right side of regulatory requirements.

Setting up the RI Coverage Notification

To create an advanced automated Slack notifications for RI coverage, follow these steps:

  1. Create a AWS Lambda Function:
    • Open your web browser and go to the AWS Lambda console to get started.Automated Slack Notifications for RI Coverage Across All AWS Regions
    • Ensure that you operate in the Ohio region (us-east-2) or any region you prefer to align with your resource requirements.
    • Click theCreate functionbutton to initiate the function setup process.Automated Slack Notifications for RI Coverage Across All AWS Regions
    • SelectAuthor from scratchto build your function from zero, then add a “Function Name”.
    • ChoosePython 3.12as the runtime environment, which is ideal for our coding needs.Automated Slack Notifications for RI Coverage Across All AWS Regions
    • Copy and paste the provided Python code into the code editor below. Review and customize it as necessary to suit your specific requirements.

      import boto3
      import datetime
      import json
      import os
      import urllib3
      from calendar import month_name
      
      # Set AWS Cost Explorer as client
      ce = boto3.client('ce')
      
      # Set list of service and regions
      services = ['Amazon Elastic Compute Cloud - Compute', 'Amazon Relational Database Service']
      daterange = ['DAILY', 'MONTHLY']
      
      # Slack webhook URL
      slack_webhook_url = os.environ['SLACK_WEBHOOK_URL']
      
      # Calculate dates                                            
      today =  datetime.date.today() # to simulate aspecific date of a month choose a month(1-12), a day. Use this format for, today = datetime.date.today().replace(month=3, day=1) 
                                                                   
      yesterday = today - datetime.timedelta(days=1)
      start_date_daily = yesterday.strftime('%Y-%m-%d')
      end_date_daily = today.strftime('%Y-%m-%d')
      
      def lambda_handler(event, context):
          
          print(json.dumps(event)) # for testing purposes to see the event that triggers the lambda in json
          for service in services:
              for range in daterange:
                  if range == 'DAILY':
                      get_ri_coverage_daily(ce, start_date_daily, end_date_daily, service, range)
                  elif range == 'MONTHLY':
                      # Adjust start date calculation
                      if today.day == 1:  # If today is the first day of the month
                          start_date_monthly = yesterday.replace(day=1).strftime('%Y-%m-%d')    #the start day is prev month's first day
                          end_date_monthly = yesterday.strftime('%Y-%m-%d') # yesterday which means the last date of the prev month
                      else: 
                          start_date_monthly = today.replace(day=1).strftime('%Y-%m-%d')  # Start of current month
                          end_date_monthly = today.strftime('%Y-%m-%d')  # End date
                      get_ri_coverage_monthly(ce, start_date_monthly, end_date_monthly, service, range)
      
      def get_ri_coverage_daily(ce, start, end, service, range):
          try:
              filter = {
                  'Dimensions': {
                      'Key': 'SERVICE',
                      'Values': [service]
                  }
              }
      
              response = ce.get_reservation_coverage(
                  TimePeriod={'Start': start, 'End': end},
                  GroupBy=[
                      {'Type': 'DIMENSION', 'Key': 'INSTANCE_TYPE'},
                      {'Type': 'DIMENSION', 'Key': 'REGION'}
                  ],
                  Filter=filter
              )
              print(f"{service} {range}")
              print(json.dumps(response))
              
              message = format_daily_message(service, range, start, end, response)
      
              # Send Slack notification
              send_slack_notification(message)
      
          except Exception as e:
              print(f"Error retrieving Reservation Coverage for {service} - DAILY: {str(e)}")
      
      def get_ri_coverage_monthly(ce, start, end, service, range):
          try:
              filter = {
                  'Dimensions': {
                      'Key': 'SERVICE',
                      'Values': [service]
                  }
              }
      
              response = ce.get_reservation_coverage(
                  TimePeriod={'Start': start, 'End': end},
                  GroupBy=[
                      {'Type': 'DIMENSION', 'Key': 'REGION'}
                  ],
                  Filter=filter
              )
              print(f"{service} {range}")
              print(json.dumps(response))
              
                      # Convert start and end dates to datetime objects
              start = datetime.datetime.strptime(start, '%Y-%m-%d')
              end= datetime.datetime.strptime(end, '%Y-%m-%d')
      
              message = format_monthly_message(service, range, start, end, response)
      
              # Send Slack notification
              send_slack_notification(message)
      
          except Exception as e:
              print(f"Error retrieving Reservation Coverage for {service} - MONTHLY: {str(e)}")
      
      def format_daily_message(service, range, start, end, response):
          message = f"*{':large_blue_square:' if 'Amazon Relational Database Service' in service else ':large_orange_square:'}"
          message += f"{'Amazon RDS' if 'Amazon Relational Database Service' in service else 'Amazon EC2'}"
          message += f" RI Coverage Report {range.upper()}- {start}*\n\n"
          message += f"```"  #this ecapsulates the message in a code snippet
      
          for coverage in response.get('CoveragesByTime', []):
              for group in coverage.get('Groups', []):
                  attributes = group.get('Attributes', {})
                  instance_type = attributes.get('instanceType')
                  region = attributes.get('region', 'Unknown Region')
                  coverage_hours = group.get('Coverage', {}).get('CoverageHours', {})
                  on_demand_hours = round(float(coverage_hours.get('OnDemandHours')), 2)
                  reserved_hours = round(float(coverage_hours.get('ReservedHours')), 2)
                  total_running_hours = round(float(coverage_hours.get('TotalRunningHours')), 2)
                  coverage_hours_percentage = round(float(coverage_hours.get('CoverageHoursPercentage')), 2)
      
                  message += f"\n• {instance_type} in {region}\n"
                  message += f"    - On-Demand Hours: {on_demand_hours}\n"
                  message += f"    - Reserved Hours: {reserved_hours}\n"
                  message += f"    - Total Running Hours: {total_running_hours}\n"
                  message += f"    - Coverage Hours Percentage: {coverage_hours_percentage}%\n"
      
              # Extract total coverage information
              total_coverage = coverage.get('Total', {}).get('CoverageHours', {})
              total_on_demand_hours = round(float(total_coverage.get('OnDemandHours', 0)), 2)
              total_reserved_hours = round(float(total_coverage.get('ReservedHours', 0)), 2)
              total_running_hours = round(float(total_coverage.get('TotalRunningHours', 0)), 2)
              total_coverage_percentage = round(float(total_coverage.get('CoverageHoursPercentage', 0)), 2)
      
              # Include total coverage in the message
              message += "\n*Total Coverage*\n"
              message += f"    - Total On-Demand Hours: {total_on_demand_hours}\n"
              message += f"    - Total Reserved Hours: {total_reserved_hours}\n"
              message += f"    - Total Running Hours: {total_running_hours}\n"
              message += f"    - Total Coverage Hours Percentage: {total_coverage_percentage}%\n"
      
          message += f"```" #this ecapsulates the message in a code snippet
          return message
      
      def format_monthly_message(service, range, start, end, response):
          message = f"*{':large_blue_square:' if 'Amazon Relational Database Service' in service else ':large_orange_square:'}"
          message += f"{'Amazon RDS' if 'Amazon Relational Database Service' in service else 'Amazon EC2'}"
          message += f" RI Coverage Report {range.upper()}- {start.strftime('%B')}*\n\n"
      
          progress_bar_length = 60  # Length of the progress bar, adjust as needed
      
          for coverage in response.get('CoveragesByTime', []):
              for group in coverage.get('Groups', []):
                  region = group.get('Attributes', {}).get('region')
                  coverage_hours_percentage = round(float(group.get('Coverage', {}).get('CoverageHours', {}).get('CoverageHoursPercentage', 0)),2)
                  
                  progress_bar_fill = int(coverage_hours_percentage / 100 * progress_bar_length)
                  progress_bar =  '|' * progress_bar_fill  + ' ' * max(0, ( progress_bar_length - progress_bar_fill))
      
                  message += f"Region: *{region}*\n"
                  message += f"Actual Coverage: *|{progress_bar}|* ({coverage_hours_percentage}%)\n\n"
      
          return message
      
      
      def send_slack_notification(message):
          http = urllib3.PoolManager()
          data = {'text': message}
          encoded_data = json.dumps(data).encode('utf-8')
      
          try:
              response = http.request('POST', slack_webhook_url, body=encoded_data, headers={'Content-Type': 'application/json'})
              print(response.status)
          except Exception as e:
              print(f"Error sending Slack notification: {e}")
      
    • Set the timeout for your Lambda function to 10 seconds. This ensures your function has sufficient time to execute without timing out prematurely.Automated Slack Notifications for RI Coverage Across All AWS Regions
    • Create an inline policy. Then, attach the required permission to your Lambda function to enable access to AWS services. Navigate to “Configuration” and then “Permissions,” and click on the execution role name.

      {
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "ce:GetReservationCoverage",
                  "Resource": "*"
              }
          ]
      }
      

      Automated Slack Notifications for RI Coverage Across All AWS Regions

    • Set up the environment variables, including variables for Instance ID and Slack channel.Automated Slack Notifications for RI Coverage Across All AWS Regions
  2. Amazon EventBridge Events Configuration:
    • Navigate to the AWS Management Console and open the EventBridge console.Automated Slack Notifications for RI Coverage Across All AWS Regions
    • In the left sidebar, chooseRulesto view and manage your existing CloudWatch rules. Automated Slack Notifications for RI Coverage Across All AWS Regions
    • Click theCreate rulebutton to initiate the rule configuration process.
    • Specify the schedule for triggering your rule.Automated Slack Notifications for RI Coverage Across All AWS Regions
    • In theTargetssection, select your Lambda function as the target for this rule. This establishes the connection between the event schedule and your function. Automated Slack Notifications for RI Coverage Across All AWS Regions
    • After reviewing your settings, click theSavebutton to create the rule.
    • Finally, test the setup to ensure the rule triggers your Lambda function as expected. You can monitor the function’s logs in the Lambda console to confirm it executes correctly. Automated Slack Notifications for RI Coverage Across All AWS Regions

Automated Slack Notifications for RI Coverage Across All AWS Regions

Note: Please be aware that there is typically a two-day delay in cost management reporting. Therefore, the report sent by your Lambda function will reflect data from the last two days.

Conclusion

Automating Slack notifications for Reserved Instance (RI) coverage across all AWS regions is more than just a convenience; it’s a strategic approach to resource management that can lead to significant cost savings and operational efficiencies. Following the steps outlined in this article, you can create a comprehensive monitoring system that empowers your team to make informed decisions.

As cloud environments become increasingly complex, staying ahead of your resources is essential. Embracing automation enhances your visibility into RI utilization and fosters a culture of proactive management. With the proper setup and ongoing optimization, your organization can navigate the intricacies of AWS effectively, ensuring that you maximize both performance and cost efficiency.

48 Hour FLASH SALE – 10% OFF ALL PLANS. Use Coupon Code: TD-PLAYCLOUD-0925

Tutorials Dojo portal

Founder Spotlight: Jon Bonso

jon bonso

AWS Exam Readiness Courses

Enroll Now – Our Google Cloud Certification Exam Reviewers

Tutorials Dojo Exam Study Guide eBooks

tutorials dojo study guide eBook

FREE AWS Exam Readiness Digital Courses

Subscribe to our YouTube Channel

Tutorials Dojo YouTube Channel

FREE AWS, Azure, GCP Practice Test Samplers

Recent Posts

Written by: Nikee Tomas

Nikee is a dedicated Web Developer at Tutorials Dojo. She has a strong passion for cloud computing and contributes to the tech community as an AWS Community Builder. She is continuously striving to enhance her knowledge and expertise in the field.

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?