Skip to content

Instantly share code, notes, and snippets.

@leepa
Created December 5, 2018 12:30
Show Gist options
  • Select an option

  • Save leepa/bb4415dd18f95ee39e6ca73f827b986a to your computer and use it in GitHub Desktop.

Select an option

Save leepa/bb4415dd18f95ee39e6ca73f827b986a to your computer and use it in GitHub Desktop.

Revisions

  1. leepa created this gist Dec 5, 2018.
    248 changes: 248 additions & 0 deletions main.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,248 @@
    extern crate lambda_runtime as lambda;

    #[macro_use]
    extern crate log;

    extern crate simple_logger;
    extern crate serde_derive;
    extern crate chrono;

    use lambda::{error::HandlerError, lambda};
    use chrono::{DateTime, Utc};
    use serde_derive::{Deserialize};
    use std::error::Error;
    use std::collections::HashMap;

    #[derive(Deserialize, Debug)]
    struct S3Event {
    #[serde(rename = "Records")]
    #[allow(dead_code)]
    records: Vec<S3EventRecord>,
    }

    #[derive(Deserialize, Debug)]
    struct S3EventRecord {
    #[serde(rename = "eventVersion")]
    #[allow(dead_code)]
    event_version: String,

    #[serde(rename = "eventSource")]
    #[allow(dead_code)]
    event_source: String,

    #[serde(rename = "awsRegion")]
    #[allow(dead_code)]
    aws_region: String,

    #[serde(rename = "eventTime")]
    #[allow(dead_code)]
    event_time: DateTime<Utc>,

    #[serde(rename = "eventName")]
    #[allow(dead_code)]
    event_name: String,

    #[serde(rename = "userIdentity")]
    #[allow(dead_code)]
    user_identity: S3UserIdentity,

    #[serde(rename = "requestParameters")]
    #[allow(dead_code)]
    request_parameters: S3RequestParameters,

    #[serde(rename = "responseElements")]
    #[allow(dead_code)]
    response_elements: HashMap<String, String>,

    #[serde(rename = "s3")]
    #[allow(dead_code)]
    s3: S3Entity,
    }

    #[derive(Deserialize, Debug)]
    struct S3RequestParameters {
    #[serde(rename = "sourceIPAddress")]
    #[allow(dead_code)]
    source_ip_address: String,
    }

    #[derive(Deserialize, Debug)]
    struct S3UserIdentity {
    #[serde(rename = "principalId")]
    #[allow(dead_code)]
    principal_id: String,
    }

    #[derive(Deserialize, Debug)]
    struct S3Entity {
    #[serde(rename = "s3SchemaVersion")]
    #[allow(dead_code)]
    schema_version: String,

    #[serde(rename = "configurationId")]
    #[allow(dead_code)]
    configuration_id: String,

    #[serde(rename = "bucket")]
    #[allow(dead_code)]
    bucket: S3Bucket,

    #[serde(rename = "object")]
    #[allow(dead_code)]
    object: S3Object,
    }

    #[derive(Deserialize, Debug)]
    struct S3Bucket {
    #[serde(rename = "name")]
    #[allow(dead_code)]
    name: String,

    #[serde(rename = "ownerIdentity")]
    #[allow(dead_code)]
    owner_identity: S3UserIdentity,

    #[serde(rename = "arn")]
    #[allow(dead_code)]
    arn: String,
    }

    #[derive(Deserialize, Debug)]
    struct S3Object {
    #[serde(rename = "key")]
    #[allow(dead_code)]
    key: String,

    #[serde(default)]
    #[serde(rename = "size")]
    #[allow(dead_code)]
    size: i64,

    #[serde(default)]
    #[serde(rename = "urlDecodedKey")]
    #[allow(dead_code)]
    url_decoded_key: String,

    #[serde(default)]
    #[serde(rename = "versionId")]
    #[allow(dead_code)]
    version_id: String,

    #[serde(default)]
    #[serde(rename = "eTag")]
    #[allow(dead_code)]
    etag: String,

    #[serde(rename = "sequencer")]
    #[allow(dead_code)]
    sequencer: String,
    }

    fn main() -> Result<(), Box<dyn Error>> {
    simple_logger::init_with_level(log::Level::Debug).unwrap();
    lambda!(handler);

    Ok(())
    }

    fn handler(e: S3Event, _c: lambda::Context) -> Result<String, HandlerError> {
    info!("Logging S3 Event {:?}", e);
    Ok("Foo".to_string())
    }

    #[cfg(test)]
    mod tests {
    use super::*;

    extern crate serde_json;

    #[test]
    fn parse_delete_event() {
    let s3_delete_event = r#"
    {
    "Records": [
    {
    "eventVersion": "2.0",
    "eventSource": "aws:s3",
    "awsRegion": "eu-west-1",
    "eventTime": "1970-01-01T00:00:00.000Z",
    "eventName": "ObjectRemoved:Delete",
    "userIdentity": {
    "principalId": "EXAMPLE"
    },
    "requestParameters": {
    "sourceIPAddress": "127.0.0.1"
    },
    "responseElements": {
    "x-amz-request-id": "EXAMPLE123456789",
    "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
    },
    "s3": {
    "s3SchemaVersion": "1.0",
    "configurationId": "testConfigRule",
    "bucket": {
    "name": "example-bucket",
    "ownerIdentity": {
    "principalId": "EXAMPLE"
    },
    "arn": "arn:aws:s3:::example-bucket"
    },
    "object": {
    "key": "test/key",
    "sequencer": "0A1B2C3D4E5F678901"
    }
    }
    }
    ]
    }
    "#;

    let _deserialized: S3Event = serde_json::from_str(&s3_delete_event).unwrap();
    }

    #[test]
    fn parse_put_event() {
    let s3_put_event = r#"
    {
    "Records": [
    {
    "eventVersion": "2.0",
    "eventSource": "aws:s3",
    "awsRegion": "eu-west-1",
    "eventTime": "1970-01-01T00:00:00.000Z",
    "eventName": "ObjectCreated:Put",
    "userIdentity": {
    "principalId": "EXAMPLE"
    },
    "requestParameters": {
    "sourceIPAddress": "127.0.0.1"
    },
    "responseElements": {
    "x-amz-request-id": "EXAMPLE123456789",
    "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
    },
    "s3": {
    "s3SchemaVersion": "1.0",
    "configurationId": "testConfigRule",
    "bucket": {
    "name": "example-bucket",
    "ownerIdentity": {
    "principalId": "EXAMPLE"
    },
    "arn": "arn:aws:s3:::example-bucket"
    },
    "object": {
    "key": "test/key",
    "size": 1024,
    "eTag": "0123456789abcdef0123456789abcdef",
    "sequencer": "0A1B2C3D4E5F678901"
    }
    }
    }
    ]
    }
    "#;

    let _deserialized: S3Event = serde_json::from_str(&s3_put_event).unwrap();
    }
    }