0

I am working with AWS Lambda Function and want to integrate them with Dynamo-db to keep the track of my cloudwatch data matrix into it in order to keep track of alerts for sending messages if alerts are sent or not to record in DB.

The function is perfectly fine if I don't use Dynamo-DB, below is the code with Dynamo-db. I never used DynamoDB but just started.

Code:

import json
import os
import boto3
from datetime import datetime, timedelta
from boto3.dynamodb.conditions import Key
from botocore.exceptions import ClientError

def lambda_handler(event, context):
    fsx = boto3.client('fsx')
    cloudwatch = boto3.client('cloudwatch') 
    ses = boto3.client('ses')
    region_name = os.environ['AWS_REGION']
    dynamodb = boto3.resource('dynamodb', region_name=region_name)
    now = datetime.utcnow()
    start_time = (now - timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%SZ')
    end_time = now.strftime('%Y-%m-%dT%H:%M:%SZ')
    table =  []
    result = []
    next_token = None
    while True:
        if next_token:
            response = fsx.describe_file_systems(NextToken=next_token)
        else:
            response = fsx.describe_file_systems()
        for filesystem in response.get('FileSystems'):
            filesystem_id = filesystem.get('FileSystemId')
            table.append(filesystem_id)
        next_token = response.get('NextToken')
        if not next_token:
            break
    try:
        # Create the DynamoDB table if it does not exist
        table = dynamodb.create_table(
            TableName='FsxNMonitorFsx',
            KeySchema=[
                {
                    'AttributeName': 'filesystem_id',
                    'KeyType': 'HASH' #Partition key
                }
            ],
            AttributeDefinitions=[
                {
                    'attributeName': 'filesystem_id',
                    'AttributeType': 'S'
                },
                {
                    'attributeName': 'alert_sent',
                    'attributeType': 'BOOL'
                }
            ],
            ProvisionedThroughput={
                'ReadCapacityUnits': 10,
                'WriteCapacityUnits': 10
            }
        )
        # Wait for the table to be created
        table.meta.client.get_waiter('table_exists').wait(TableName='FsxNMonitorFsx')
    except ClientError as e:
        if e.response['Error']['Code'] != 'ResourceInUseException':
            raise
    # Code to retrieve metric data and check if alert needs to be sent
    for filesystem_id in table:
        response = cloudwatch.get_metric_data(
            MetricDataQueries=[
                {
                    'Id': 'm1',
                    'MetricStat': {
                        'Metric': {
                            'Namespace': 'AWS/FSx',
                            'MetricName': 'StorageCapacity',
                            'Dimensions': [
                                {
                                    'Name': 'FileSystemId',
                                    'Value': filesystem_id
                                },
                                {
                                    'Name': 'StorageTier',
                                    'Value': 'SSD'
                                },
                                {
                                    'Name': 'DataType',
                                    'Value': 'All'
                                }
                            ]
                        },
                        'Period': 60,
                        'Stat': 'Sum'
                    },
                    'ReturnData': True
                },
                {
                    'Id': 'm2',
                    'MetricStat': {
                        'Metric': {
                            'Namespace': 'AWS/FSx',
                            'MetricName': 'StorageUsed',
                            'Dimensions': [
                                {
                                    'Name': 'FileSystemId',
                                    'Value': filesystem_id
                                },
                                {
                                    'Name': 'StorageTier',
                                    'Value': 'SSD'
                                },
                                {
                                    'Name': 'DataType',
                                    'Value': 'All'
                                }
                            ]
                        },
                        'Period': 60,
                        'Stat': 'Sum'
                    },
                    'ReturnData': True
                }
            ],
            StartTime=start_time,
            EndTime=end_time
        )
        storage_capacity = response['MetricDataResults'][0]['Values']
        storage_used = response['MetricDataResults'][1]['Values']
        if storage_capacity:
            storage_capacity = storage_capacity[0]
        else:
            storage_capacity = None
        if storage_used:
            storage_used = storage_used[0]
        else:
            storage_used = None
        if storage_capacity and storage_used:
            percent_used = (storage_used / storage_capacity) * 100
        else:
            percent_used = None
        response = dynamodb.get_item(
            TableName='FsxNMonitorFsx',
            Key={'filesystem_id': {'S': filesystem_id}}
        )
        if 'Item' in response:
            alert_sent = response['Item']['alert_sent']['BOOL']
        else:
            alert_sent = False
        # Send alert if storage usage exceeds threshold and no alert has been sent yet
        if percent_used > 80 and not alert_sent:
            email_body = "... some code..."

            ses.send_email(
                Source='[email protected]'',
                Destination={
                    'ToAddresses': ['[email protected]'],
                },
                Message={
                    'Subject': {
                        'Data': email_subject
                    },
                    'Body': {
                        'Html': {
                            'Data': email_body
                        }
                    }
                }
            )
            # Update FsxNMonitorFsx in DynamoDB
            dynamodb.update_item(
                TableName='FsxNMonitorFsx',
                Key={'filesystem_id': {'S': filesystem_id}},
                UpdateExpression='SET alert_sent = :val',
                ExpressionAttributeValues={':val': {'BOOL': True}}
            )
    return {
        'statusCode': 200,
        'body': json.dumps('Email sent!')
    }

Error :

Response
{
  "errorMessage": "Parameter validation failed:\nMissing required parameter in AttributeDefinitions[0]: \"AttributeName\"\nUnknown parameter in AttributeDefinitions[0]: \"attributeName\", must be one of: AttributeName, AttributeType\nMissing required parameter in AttributeDefinitions[1]: \"AttributeName\"\nMissing required parameter in AttributeDefinitions[1]: \"AttributeType\"\nUnknown parameter in AttributeDefinitions[1]: \"attributeName\", must be one of: AttributeName, AttributeType\nUnknown parameter in AttributeDefinitions[1]: \"attributeType\", must be one of: AttributeName, AttributeType",
  "errorType": "ParamValidationError",
  "requestId": "54de7194-f8e8-4a9f-91d6-0f77575de775",


Function Logs
START RequestId: 54de7194-f8e8-4a9f-91d6-0f77575de775 Version: $LATEST
[ERROR] ParamValidationError: Parameter validation failed:
Missing required parameter in AttributeDefinitions[0]: "AttributeName"
Unknown parameter in AttributeDefinitions[0]: "attributeName", must be one of: AttributeName, AttributeType
Missing required parameter in AttributeDefinitions[1]: "AttributeName"
Missing required parameter in AttributeDefinitions[1]: "AttributeType"
Unknown parameter in AttributeDefinitions[1]: "attributeName", must be one of: AttributeName, AttributeType
Unknown parameter in AttributeDefinitions[1]: "attributeType", must be one of: AttributeName, AttributeType

Edit:

In the below section i just changed the 'filesystem_id' to the filesystem_id and another one is all lowercae attribute to first letter upper-cae like Attribute.

        {
            'AttributeName': filesystem_id,
            'KeyType': 'HASH' #Partition key
        }
    ],
    AttributeDefinitions=[
        {
            'AttributeName': filesystem_id,
            'AttributeType': 'S'
        },
        {
            'attributeName': 'alert_sent',
            'attributeType': 'BOOL'
        }
    ],
    ProvisionedThroughput={
        'ReadCapacityUnits': 10,
        'WriteCapacityUnits': 10
    }

Now the New Error:

Response
{
  "errorMessage": "An error occurred (ValidationException) when calling the CreateTable operation: 1 validation error detected: Value 'BOOL' at 'attributeDefinitions.2.member.attributeType' failed to satisfy constraint: Member must satisfy enum value set: [B, N, S]",
  "errorType": "ClientError",

Can someone please help on this.

4
  • have you tried changing the lowercase attributeName props in the AttributeDefinitions to AttributeName? Commented Jan 27, 2023 at 6:54
  • @fodma1 I have tried that but same error, I have changed the 'filesystem_id' to the filesystem_id and that error gone but now givving Bool error like n error occurred (ValidationException) when calling the CreateTable operation: 1 validation error detected: Value 'BOOL' at 'attributeDefinitions.2.member.attributeType' failed to satisfy constraint: Member must satisfy enum value set: [B, N, S]", Commented Jan 27, 2023 at 7:06
  • but now givving Bool error like... → it will be better to update question with actual code and actual errors Commented Jan 27, 2023 at 8:32
  • @rzlvmp, this is actual code itself, I will edit the question with the change and new Error? Commented Jan 27, 2023 at 8:59

1 Answer 1

1

All problems clearly described in error message:

  1. The problematic part is AttributeDefinitions
  2. Allowed key names are !A!ttribute(Name or Type) but not !a!ttribute(Name or Type). And you improved only first element of AttributeDefinitions after editing the question.
  3. AttributeType should be S, N or B. Not BOOL

AttributeType (string) -- [REQUIRED]
The data type for the attribute, where:

S - the attribute is of type String
N - the attribute is of type Number
B - the attribute is of type Binary

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks rzlvmp, looks that error gone an now another [ERROR] ClientError: An error occurred (ValidationException) when calling the CreateTable operation: One or more parameter values were invalid: Number of attributes in KeySchema does not exactly match number of attributes defined in AttributeDefinitions
And check error again: here is no AttributeName': 'alert_sent' inside KeySchema
Yes, i Change that to the KeyType': 'RANGE' and that resolved it but looks like get-item do not iterate over bools

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.