diff --git a/Libraries/Libraries.sln b/Libraries/Libraries.sln index b2a87e830..c0e00084d 100644 --- a/Libraries/Libraries.sln +++ b/Libraries/Libraries.sln @@ -77,6 +77,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellTests", "test\Pow EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerShellScriptsAsFunctions", "test\TestPowerShellFunctions\PowerShellScriptsAsFunctions\PowerShellScriptsAsFunctions.csproj", "{0AD1E5D6-AC23-47C1-97BF-227007021B6F}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Amazon.Lambda.CloudWatchEvents", "src\Amazon.Lambda.CloudWatchEvents\Amazon.Lambda.CloudWatchEvents.csproj", "{AD96AA48-2E1A-4BBB-9329-E1E484172FE3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -203,6 +205,10 @@ Global {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Debug|Any CPU.Build.0 = Debug|Any CPU {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Release|Any CPU.ActiveCfg = Release|Any CPU {0AD1E5D6-AC23-47C1-97BF-227007021B6F}.Release|Any CPU.Build.0 = Release|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -240,6 +246,7 @@ Global {ADEC039D-0C34-4DA7-802B-6204FFE3F1F5} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} {997B1047-4361-4E6D-9850-F130EC188141} = {1DE4EE60-45BA-4EF7-BE00-B9EB861E4C69} {0AD1E5D6-AC23-47C1-97BF-227007021B6F} = {ADEC039D-0C34-4DA7-802B-6204FFE3F1F5} + {AD96AA48-2E1A-4BBB-9329-E1E484172FE3} = {AAB54E74-20B1-42ED-BC3D-CE9F7BC7FD12} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {503678A4-B8D1-4486-8915-405A3E9CF0EB} diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/Amazon.Lambda.CloudWatchEvents.csproj b/Libraries/src/Amazon.Lambda.CloudWatchEvents/Amazon.Lambda.CloudWatchEvents.csproj new file mode 100644 index 000000000..d60a4a60f --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/Amazon.Lambda.CloudWatchEvents.csproj @@ -0,0 +1,20 @@ + + + + + + netstandard1.3 + 1.6.0 + Amazon Lambda .NET Core support - CloudWatchEvents package. + Amazon.Lambda.CloudWatchEvents + 1.0.0 + Amazon.Lambda.CloudWatchEvents + Amazon.Lambda.CloudWatchEvents + AWS;Amazon;Lambda + + + + + + + diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/CloudWatchEvent.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/CloudWatchEvent.cs new file mode 100644 index 000000000..55968369e --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/CloudWatchEvent.cs @@ -0,0 +1,77 @@ +namespace Amazon.Lambda.CloudWatchEvents +{ + using System; + using System.Collections.Generic; + + /// + /// AWS CloudWatch event + /// The contents of the detail top-level field are different depending on which service generated the event and what the event is. + /// The combination of the source and detail-type fields serves to identify the fields and values found in the detail field. + /// Complete list of events that inherit this interface: https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/EventTypes.html + /// https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/CloudWatchEventsandEventPatterns.html + /// https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/EventTypes.html + /// + public class CloudWatchEvent + { + /// + /// By default, this is set to 0 (zero) in all events. + /// + public string Version { get; set; } + + /// + /// The 12-digit number identifying an AWS account. + /// + public string Account { get; set; } + + /// + /// Identifies the AWS region where the event originated. + /// + public string Region { get; set; } + + /// + /// A JSON object, whose content is at the discretion of the service originating the event. + /// The detail content in the example above is very simple, just two fields. + /// AWS API call events have detail objects with around 50 fields nested several levels deep. + /// + public T Detail { get; set; } + + /// + /// Identifies, in combination with the source field, the fields and values that appear in the detail field. + /// For example, ScheduledEvent will be null + /// For example, ECSEvent could be "ECS Container Instance State Change" or "ECS Task State Change" + /// + public string DetailType { get; set; } + + /// + /// Identifies the service that sourced the event. + /// All events sourced from within AWS begin with "aws." + /// Customer-generated events can have any value here, as long as it doesn't begin with "aws." + /// We recommend the use of Java package-name style reverse domain-name strings. + /// For example, ScheduledEvent will be "aws.events" + /// For example, ECSEvent will be "aws.ecs" + /// + public string Source { get; set; } + + /// + /// The event timestamp, which can be specified by the service originating the event. + /// If the event spans a time interval, the service might choose to report the start time, + /// so this value can be noticeably before the time the event is actually received. + /// + public DateTime Time { get; set; } + + /// + /// A unique value is generated for every event. + /// This can be helpful in tracing events as they move through rules to targets, and are processed. + /// + public string Id { get; set; } + + /// + /// This JSON array contains ARNs that identify resources that are involved in the event. + /// Inclusion of these ARNs is at the discretion of the service. + /// For example, Amazon EC2 instance state-changes include Amazon EC2 instance ARNs, Auto Scaling events + /// include ARNs for both instances and Auto Scaling groups, but API calls with AWS CloudTrail do not + /// include resource ARNs. + /// + public List Resources { get; set; } + } +} diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Attachment.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Attachment.cs new file mode 100644 index 000000000..27074c940 --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Attachment.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + /// + /// An object representing a container instance or task attachment. + /// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Attachment.html + /// + public class Attachment + { + /// + /// Details of the attachment. For elastic network interfaces, this includes the + /// network interface ID, the MAC address, the subnet ID, and the private IPv4 address. + /// + public List> Details { get; set; } + + /// + /// The unique identifier for the attachment. + /// + public string Id { get; set; } + + /// + /// The status of the attachment. Valid values are PRECREATED, CREATED, ATTACHING, + /// ATTACHED, DETACHING, DETACHED, and DELETED. + /// + public string Status { get; set; } + + /// + /// The type of the attachment, such as ElasticNetworkInterface. + /// + public string Type { get; set; } + } +} \ No newline at end of file diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Attribute.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Attribute.cs new file mode 100644 index 000000000..7eae7d505 --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Attribute.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + /// + /// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerInstance.html + /// + public class Attribute + { + /// + /// The attributes set for the container instance, either by the Amazon ECS container agent at instance + /// registration or manually with the PutAttributes operation. + /// + public string Name { get; set; } + } +} diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Container.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Container.cs new file mode 100644 index 000000000..30262f41c --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Container.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + /// + /// A Docker container that is part of a task. + /// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Container.html + /// + public class Container + { + /// + /// The Amazon Resource Name (ARN) of the container. + /// + public string ContainerArn { get; set; } + + /// + /// The exit code returned from the container. + /// + public int ExitCode { get; set; } + + /// + /// The last known status of the container. + /// + public string LastStatus { get; set; } + + /// + /// The name of the container. + /// + public string Name { get; set; } + + /// + /// The ARN of the task. + /// + public string TaskArn { get; set; } + } +} diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ContainerInstance.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ContainerInstance.cs new file mode 100644 index 000000000..beba77bce --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ContainerInstance.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + /// + /// An EC2 instance that is running the Amazon ECS agent and has been registered with a cluster. + /// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerInstance.html + /// + public class ContainerInstance + { + /// + /// This parameter returns true if the agent is connected to Amazon ECS. + /// Registered instances with an agent that may be unhealthy or stopped return false. Instances without + /// a connected agent can't accept placement requests. + /// + public bool AgentConnected { get; set; } + + /// + /// The status of the most recent agent update. If an update has never been requested, this value is NULL. + /// + public string AgentUpdateStatus { get; set; } + + /// + /// The elastic network interfaces associated with the container instance. + /// + public List Attachments { get; set; } + + /// + /// The attributes set for the container instance, either by the Amazon ECS container agent at instance + /// registration or manually with the PutAttributes operation. + /// + public List Attributes { get; set; } + + /// + /// The Amazon Resource Name (ARN) of the container instance. + /// The ARN contains the arn:aws:ecs namespace, followed by the region of the container instance, + /// the AWS account ID of the container instance owner, the container-instance namespace, + /// and then the container instance ID. + /// + public string ContainerInstanceArn { get; set; } + + /// + /// The EC2 instance ID of the container instance. + /// + public string Ec2InstanceId { get; set; } + + /// + /// The number of tasks on the container instance that are in the PENDING status. + /// + public int PendingTasksCount { get; set; } + + /// + /// The Unix time stamp for when the container instance was registered. + /// + public DateTime RegisteredAt { get; set; } + + /// + /// For CPU and memory resource types, this parameter describes the amount of each resource that was available + /// on the container instance when the container agent registered it with Amazon ECS; this value represents + /// the total amount of CPU and memory that can be allocated on this container instance to tasks. + /// For port resource types, this parameter describes the ports that were reserved by the Amazon ECS container + /// agent when it registered the container instance with Amazon ECS. + /// + public List RegisteredResources { get; set; } + + /// + /// For CPU and memory resource types, this parameter describes the remaining CPU and memory that has not + /// already been allocated to tasks and is therefore available for new tasks. + /// For port resource types, this parameter describes the ports that were reserved by the Amazon ECS + /// container agent (at instance registration time) and any task containers that have reserved port mappings + /// on the host (with the host or bridge network mode). + /// Any port that is not specified here is available for new tasks. + /// + public List RemainingResources { get; set; } + + /// + /// The number of tasks on the container instance that are in the RUNNING status. + /// + public int RunningTasksCount { get; set; } + + /// + /// The status of the container instance. + /// The valid values are ACTIVE, INACTIVE, or DRAINING. ACTIVE indicates that the container instance + /// can accept tasks. + /// DRAINING indicates that new tasks are not placed on the container instance and any service tasks + /// running on the container instance are removed if possible. + /// + public string Status { get; set; } + + /// + /// The version counter for the container instance. + /// Every time a container instance experiences a change that triggers a CloudWatch event, + /// the version counter is incremented. If you are replicating your Amazon ECS container instance + /// state with CloudWatch Events, you can compare the version of a container instance reported by + /// the Amazon ECS APIs with the version reported in CloudWatch Events for the container instance + /// (inside the detail object) to verify that the version in your event stream is current. + /// + public long Version { get; set; } + + /// + /// The version information for the Amazon ECS container agent and Docker daemon running on the container instance. + /// + public VersionInfo VersionInfo { get; set; } + + // NOTE: The following properties are not present in the ContainerInstance object documentation but have + // been added here for convenience. + + /// + /// The Amazon Resource Name (ARN) of the cluster that hosts the service. + /// + public string ClusterArn { get; set; } + + /// + /// The Unix time stamp for when the service was last updated. + /// + public DateTime UpdatedAt { get; set; } + } +} \ No newline at end of file diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ContainerOverride.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ContainerOverride.cs new file mode 100644 index 000000000..e4862ec58 --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ContainerOverride.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + /// + /// The overrides that should be sent to a container. + /// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerOverride.html + /// + public class ContainerOverride + { + /// + /// The command to send to the container that overrides the default command from + /// the Docker image or the task definition. You must also specify a container name. + /// + public List Command { get; set; } + + /// + /// The number of cpu units reserved for the container, instead of the default value + /// from the task definition. You must also specify a container name. + /// + public int Cpu { get; set; } + + /// + /// The environment variables to send to the container. You can add new environment variables, + /// which are added to the container at launch, or you can override the existing environment + /// variables from the Docker image or the task definition. You must also specify a container name. + /// + public List> Environment { get; set; } + + /// + /// The hard limit (in MiB) of memory to present to the container, instead of the default value + /// from the task definition. If your container attempts to exceed the memory specified here, + /// the container is killed. You must also specify a container name. + /// + public int Memory { get; set; } + + /// + /// The soft limit (in MiB) of memory to reserve for the container, instead of the default value + /// from the task definition. You must also specify a container name. + /// + public int MemoryReservation { get; set; } + + /// + /// The name of the container that receives the override. + /// This parameter is required if any override is specified. + /// + public string Name { get; set; } + } +} diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ECSContainerInstanceStateChangeEvent.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ECSContainerInstanceStateChangeEvent.cs new file mode 100644 index 000000000..467acefa7 --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ECSContainerInstanceStateChangeEvent.cs @@ -0,0 +1,17 @@ +using System; +using Amazon.Lambda.CloudWatchEvents; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + + /// + /// AWS ECS event + /// http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules.html + /// http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_example-events.html + /// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_cwe_events.html + /// + public class ECSContainerInstanceStateChangeEvent : CloudWatchEvent + { + + } +} diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ECSTaskStateChangeEvent.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ECSTaskStateChangeEvent.cs new file mode 100644 index 000000000..26e526607 --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/ECSTaskStateChangeEvent.cs @@ -0,0 +1,16 @@ +using System; +using Amazon.Lambda.CloudWatchEvents; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + /// + /// /// AWS ECS task state change event + /// http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules.html + /// http://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_example-events.html + /// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_cwe_events.html + /// + public class ECSTaskStateChangeEvent : CloudWatchEvent + { + + } +} \ No newline at end of file diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Resource.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Resource.cs new file mode 100644 index 000000000..c72f1f399 --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Resource.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + using System.Collections.Generic; + + /// + /// Describes the resources available for a container instance. + /// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Resource.html + /// + public class Resource + { + /// + /// The name of the resource, such as CPU, MEMORY, PORTS, PORTS_UDP, or a user-defined resource. + /// + public string Name { get; set; } + + /// + /// The type of the resource, such as INTEGER, DOUBLE, LONG, or STRINGSET. + /// + public string Type { get; set; } + + /// + /// When the integerValue type is set, the value of the resource must be an integer. + /// + public int IntegerValue { get; set; } + + /// + /// When the stringSetValue type is set, the value of the resource must be a string type. + /// + public List StringSetValue { get; set; } + } +} diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Task.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Task.cs new file mode 100644 index 000000000..8503322a0 --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/Task.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + /// + /// Details on a task in a cluster. + /// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Task.html + /// + public class Task + { + /// + /// The elastic network adapter associated with the task if the task uses the awsvpc network mode. + /// + public List Attachments { get; set; } + + /// + /// The ARN of the cluster that hosts the task. + /// + public string ClusterArn { get; set; } + + /// + /// The connectivity status of a task. + /// + public string Connectivity { get; set; } + + /// + /// The Unix time stamp for when the task last went into CONNECTED status. + /// + public DateTime ConnectivityAt { get; set; } + + /// + /// The ARN of the container instances that host the task. + /// + public string ContainerInstanceArn { get; set; } + + /// + /// The containers associated with the task. + /// + public List Containers { get; set; } + + /// + /// The number of CPU units used by the task. It can be expressed as an integer using CPU units, + /// for example 1024, or as a string using vCPUs, for example 1 vCPU or 1 vcpu, in a task definition. + /// String values are converted to an integer indicating the CPU units when the task definition is registered. + /// See https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Task.html for extra info. + /// + public string Cpu { get; set; } + + /// + /// The Unix time stamp for when the task was created (the task entered the PENDING state). + /// + public DateTime CreatedAt { get; set; } + + /// + /// The desired status of the task. For more information, + /// see Task Lifecycle: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_life_cycle.html. + /// + public string DesiredStatus { get; set; } + + /// + /// The Unix time stamp for when the task execution stopped. + /// + public DateTime ExecutionStoppedAt { get; set; } + + /// + /// The name of the task group associated with the task. + /// + public string Group { get; set; } + + /// + /// The health status for the task, which is determined by the health of the essential containers in the task. + /// If all essential containers in the task are reporting as HEALTHY, then the task status also + /// reports as HEALTHY. If any essential containers in the task are reporting as UNHEALTHY or UNKNOWN, + /// then the task status also reports as UNHEALTHY or UNKNOWN, accordingly. + /// See https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Task.html for extra info. + /// + public string HealthStatus { get; set; } + + /// + /// The last known status of the task. For more information, + /// see Task Lifecycle: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_life_cycle.html. + /// + public string LastStatus { get; set; } + + /// + /// The launch type on which your task is running. + /// + public string LaunchType { get; set; } + + /// + /// The amount of memory (in MiB) used by the task. It can be expressed as an integer using MiB, + /// for example 1024, or as a string using GB, for example 1GB or 1 GB, in a task definition. + /// String values are converted to an integer indicating the MiB when the task definition is registered. + /// See https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Task.html for extra info. + /// + public string Memory { get; set; } + + /// + /// One or more container overrides. + /// + public TaskOverride Overrides { get; set; } + + /// + /// The platform version on which your task is running. For more information, + /// see AWS Fargate Platform Versions in the Amazon Elastic Container Service Developer Guide. + /// https://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html + /// + public string PlatformVersion { get; set; } + + /// + /// The Unix time stamp for when the container image pull began. + /// + public DateTime PullStartedAt { get; set; } + + /// + /// The Unix time stamp for when the container image pull completed. + /// + public DateTime PullStoppedAt { get; set; } + + /// + /// The Unix time stamp for when the task started (the task + /// transitioned from the PENDING state to the RUNNING state). + /// + public DateTime StartedAt { get; set; } + + /// + /// The tag specified when a task is started. If the task is started by an Amazon ECS service, + /// then the startedBy parameter contains the deployment ID of the service that starts it. + /// + public string StartedBy { get; set; } + + /// + /// The Unix time stamp for when the task stops (transitions from the RUNNING state to STOPPED). + /// + public DateTime StoppedAt { get; set; } + + /// + /// The Amazon Resource Name (ARN) of the task. + /// + public string TaskArn { get; set; } + + /// + /// The ARN of the task definition that creates the task. + /// + public string TaskDefinitionArn { get; set; } + + /// + /// The version counter for the task. Every time a task experiences a change that triggers a CloudWatch event, + /// the version counter is incremented. If you are replicating your Amazon ECS task state with + /// CloudWatch Events, you can compare the version of a task reported by the Amazon ECS APIs with + /// the version reported in CloudWatch Events for the task (inside the detail object) to verify that + /// the version in your event stream is current. + /// + public long Version { get; set; } + + // NOTE: The UpdatedAt property is not present in the Task object documentation but has been + // added here for convenience. + + /// + /// The Unix time stamp for when the service was last updated. + /// + public DateTime UpdatedAt { get; set; } + } +} \ No newline at end of file diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/TaskOverride.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/TaskOverride.cs new file mode 100644 index 000000000..fb14a5a41 --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/TaskOverride.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + /// + /// The overrides associated with a task. + /// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_TaskOverride.html + /// + public class TaskOverride + { + /// + /// One or more container overrides sent to a task. + /// + public List ContainerOverrides { get; set; } + + /// + /// The Amazon Resource Name (ARN) of the task execution role that the + /// Amazon ECS container agent and the Docker daemon can assume. + /// + public string ExecutionRoleArn { get; set; } + + /// + /// The Amazon Resource Name (ARN) of the IAM role that containers in this task can assume. + /// All containers in this task are granted the permissions that are specified in this role. + /// + public string TaskRoleArn { get; set; } + } +} diff --git a/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/VersionInfo.cs b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/VersionInfo.cs new file mode 100644 index 000000000..6b5b6922d --- /dev/null +++ b/Libraries/src/Amazon.Lambda.CloudWatchEvents/ECSEvents/VersionInfo.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Amazon.Lambda.CloudWatchEvents.ECSEvents +{ + /// + /// The Docker and Amazon ECS container agent version information about a container instance. + /// https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_VersionInfo.html + /// + public class VersionInfo + { + /// + /// The Git commit hash for the Amazon ECS container agent build on the amazon-ecs-agent GitHub repository. + /// + public string AgentHash { get; set; } + /// + /// The version number of the Amazon ECS container agent. + /// + public string AgentVersion { get; set; } + /// + /// The Docker version running on the container instance. + /// + public string DockerVersion { get; set; } + } +} diff --git a/Libraries/src/Amazon.Lambda.Serialization.Json/AwsResolver.cs b/Libraries/src/Amazon.Lambda.Serialization.Json/AwsResolver.cs index e5bb32558..586f485a4 100644 --- a/Libraries/src/Amazon.Lambda.Serialization.Json/AwsResolver.cs +++ b/Libraries/src/Amazon.Lambda.Serialization.Json/AwsResolver.cs @@ -2,6 +2,7 @@ using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; +using System.Reflection; namespace Amazon.Lambda.Serialization.Json { @@ -80,6 +81,18 @@ protected override IList CreateProperties(Type type, MemberSeriali } } } + else if (type.FullName.StartsWith("Amazon.Lambda.CloudWatchEvents.") + && (type.GetTypeInfo().BaseType?.FullName?.StartsWith("Amazon.Lambda.CloudWatchEvents.CloudWatchEvent`", + StringComparison.Ordinal) ?? false)) + { + foreach (JsonProperty property in properties) + { + if (property.PropertyName.Equals("DetailType", StringComparison.Ordinal)) + { + property.PropertyName = "detail-type"; + } + } + } return properties; } diff --git a/Libraries/test/EventsTests/EventTests.cs b/Libraries/test/EventsTests/EventTests.cs index 36b7a7ef8..52edc2d69 100644 --- a/Libraries/test/EventsTests/EventTests.cs +++ b/Libraries/test/EventsTests/EventTests.cs @@ -14,6 +14,8 @@ namespace Amazon.Lambda.Tests using Amazon.Lambda.LexEvents; using Amazon.Lambda.KinesisFirehoseEvents; using Amazon.Lambda.KinesisAnalyticsEvents; + using Amazon.Lambda.CloudWatchLogsEvents; + using Amazon.Lambda.CloudWatchEvents.ECSEvents; using Newtonsoft.Json.Linq; @@ -23,11 +25,11 @@ namespace Amazon.Lambda.Tests using System.Text; using Xunit; using System.Linq; - using Amazon.Lambda.CloudWatchLogsEvents; using Newtonsoft.Json; using JsonSerializer = Amazon.Lambda.Serialization.Json.JsonSerializer; + public class EventTest { [Fact] @@ -181,7 +183,7 @@ public void CognitoTest() private static void Handle(CognitoEvent cognitoEvent) { - foreach(var datasetKVP in cognitoEvent.DatasetRecords) + foreach (var datasetKVP in cognitoEvent.DatasetRecords) { var datasetName = datasetKVP.Key; var datasetRecord = datasetKVP.Value; @@ -351,7 +353,7 @@ public void SQSTest() Assert.Equal("MessageID", record.MessageId); Assert.Equal("MessageReceiptHandle", record.ReceiptHandle); Assert.Equal("Message Body", record.Body); - Assert.Equal("fce0ea8dd236ccb3ed9b37dae260836f", record.Md5OfBody ); + Assert.Equal("fce0ea8dd236ccb3ed9b37dae260836f", record.Md5OfBody); Assert.Equal("582c92c5c5b6ac403040a4f3ab3115c9", record.Md5OfMessageAttributes); Assert.Equal("arn:aws:sqs:us-west-2:123456789012:SQSQueue", record.EventSourceArn); Assert.Equal("aws:sqs", record.EventSource); @@ -617,7 +619,7 @@ public void LexResponse() Assert.Equal("button-text", lexResponse.DialogAction.ResponseCard.GenericAttachments[0].Buttons[0].Text); Assert.Equal("value sent to server on button click", lexResponse.DialogAction.ResponseCard.GenericAttachments[0].Buttons[0].Value); - MemoryStream ms = new MemoryStream(); + MemoryStream ms = new MemoryStream(); serializer.Serialize(lexResponse, ms); ms.Position = 0; var json = new StreamReader(ms).ReadToEnd(); @@ -781,5 +783,104 @@ private string MemoryStreamToBase64String(MemoryStream ms) var data = ms.ToArray(); return Convert.ToBase64String(data); } + + [Fact] + public void ECSContainerInstanceStateChangeEventTest() + { + using (var fileStream = File.OpenRead("ecs-container-state-change-event.json")) + { + var serializer = new JsonSerializer(); + var ecsEvent = serializer.Deserialize(fileStream); + + Assert.Equal(ecsEvent.Version, "0"); + Assert.Equal(ecsEvent.Id, "8952ba83-7be2-4ab5-9c32-6687532d15a2"); + Assert.Equal(ecsEvent.DetailType, "ECS Container Instance State Change"); + Assert.Equal(ecsEvent.Source, "aws.ecs"); + Assert.Equal(ecsEvent.Account, "111122223333"); + Assert.Equal(ecsEvent.Time.ToUniversalTime(), DateTime.Parse("2016-12-06T16:41:06Z").ToUniversalTime()); + Assert.Equal(ecsEvent.Region, "us-east-1"); + Assert.Equal(ecsEvent.Resources.Count, 1); + Assert.Equal(ecsEvent.Resources[0], "arn:aws:ecs:us-east-1:111122223333:container-instance/b54a2a04-046f-4331-9d74-3f6d7f6ca315"); + Assert.IsType(typeof(ContainerInstance), ecsEvent.Detail); + Assert.Equal(ecsEvent.Detail.AgentConnected, true); + Assert.Equal(ecsEvent.Detail.Attributes.Count, 14); + Assert.Equal(ecsEvent.Detail.Attributes[0].Name, "com.amazonaws.ecs.capability.logging-driver.syslog"); + Assert.Equal(ecsEvent.Detail.ClusterArn, "arn:aws:ecs:us-east-1:111122223333:cluster/default"); + Assert.Equal(ecsEvent.Detail.ContainerInstanceArn, "arn:aws:ecs:us-east-1:111122223333:container-instance/b54a2a04-046f-4331-9d74-3f6d7f6ca315"); + Assert.Equal(ecsEvent.Detail.Ec2InstanceId, "i-f3a8506b"); + Assert.Equal(ecsEvent.Detail.RegisteredResources.Count, 4); + Assert.Equal(ecsEvent.Detail.RegisteredResources[0].Name, "CPU"); + Assert.Equal(ecsEvent.Detail.RegisteredResources[0].Type, "INTEGER"); + Assert.Equal(ecsEvent.Detail.RegisteredResources[0].IntegerValue, 2048); + Assert.Equal(ecsEvent.Detail.RegisteredResources[2].StringSetValue[0], "22"); + Assert.Equal(ecsEvent.Detail.RemainingResources.Count, 4); + Assert.Equal(ecsEvent.Detail.RemainingResources[0].Name, "CPU"); + Assert.Equal(ecsEvent.Detail.RemainingResources[0].Type, "INTEGER"); + Assert.Equal(ecsEvent.Detail.RemainingResources[0].IntegerValue, 1988); + Assert.Equal(ecsEvent.Detail.RemainingResources[2].StringSetValue[0], "22"); + Assert.Equal(ecsEvent.Detail.Status, "ACTIVE"); + Assert.Equal(ecsEvent.Detail.Version, 14801); + Assert.Equal(ecsEvent.Detail.VersionInfo.AgentHash, "aebcbca"); + Assert.Equal(ecsEvent.Detail.VersionInfo.AgentVersion, "1.13.0"); + Assert.Equal(ecsEvent.Detail.VersionInfo.DockerVersion, "DockerVersion: 1.11.2"); + Assert.Equal(ecsEvent.Detail.UpdatedAt.ToUniversalTime(), DateTime.Parse("2016-12-06T16:41:06.991Z").ToUniversalTime()); + + Handle(ecsEvent); + } + } + + [Fact] + public void ECSTaskStateChangeEventTest() + { + using (var fileStream = File.OpenRead("ecs-task-state-change-event.json")) + { + var serializer = new JsonSerializer(); + var ecsEvent = serializer.Deserialize(fileStream); + + Assert.Equal(ecsEvent.Version, "0"); + Assert.Equal(ecsEvent.Id, "9bcdac79-b31f-4d3d-9410-fbd727c29fab"); + Assert.Equal(ecsEvent.DetailType, "ECS Task State Change"); + Assert.Equal(ecsEvent.Source, "aws.ecs"); + Assert.Equal(ecsEvent.Account, "111122223333"); + Assert.Equal(ecsEvent.Time.ToUniversalTime(), DateTime.Parse("2016-12-06T16:41:06Z").ToUniversalTime()); + Assert.Equal(ecsEvent.Region, "us-east-1"); + Assert.Equal(ecsEvent.Resources.Count, 1); + Assert.Equal(ecsEvent.Resources[0], "arn:aws:ecs:us-east-1:111122223333:task/b99d40b3-5176-4f71-9a52-9dbd6f1cebef"); + Assert.IsType(typeof(Task), ecsEvent.Detail); + Assert.Equal(ecsEvent.Detail.ClusterArn, "arn:aws:ecs:us-east-1:111122223333:cluster/default"); + Assert.Equal(ecsEvent.Detail.ContainerInstanceArn, "arn:aws:ecs:us-east-1:111122223333:container-instance/b54a2a04-046f-4331-9d74-3f6d7f6ca315"); + Assert.Equal(ecsEvent.Detail.Containers.Count, 1); + Assert.Equal(ecsEvent.Detail.Containers[0].ContainerArn, "arn:aws:ecs:us-east-1:111122223333:container/3305bea1-bd16-4217-803d-3e0482170a17"); + Assert.Equal(ecsEvent.Detail.Containers[0].ExitCode, 0); + Assert.Equal(ecsEvent.Detail.Containers[0].LastStatus, "STOPPED"); + Assert.Equal(ecsEvent.Detail.Containers[0].Name, "xray"); + Assert.Equal(ecsEvent.Detail.Containers[0].TaskArn, "arn:aws:ecs:us-east-1:111122223333:task/b99d40b3-5176-4f71-9a52-9dbd6f1cebef"); + Assert.Equal(ecsEvent.Detail.CreatedAt.ToUniversalTime(), DateTime.Parse("2016-12-06T16:41:05.702Z").ToUniversalTime()); + Assert.Equal(ecsEvent.Detail.DesiredStatus, "RUNNING"); + Assert.Equal(ecsEvent.Detail.Group, "task-group"); + Assert.Equal(ecsEvent.Detail.LastStatus, "RUNNING"); + Assert.Equal(ecsEvent.Detail.Overrides.ContainerOverrides.Count, 1); + Assert.Equal(ecsEvent.Detail.Overrides.ContainerOverrides[0].Name, "xray"); + Assert.Equal(ecsEvent.Detail.StartedAt.ToUniversalTime(), DateTime.Parse("2016-12-06T16:41:06.8Z").ToUniversalTime()); + Assert.Equal(ecsEvent.Detail.StartedBy, "ecs-svc/9223370556150183303"); + Assert.Equal(ecsEvent.Detail.UpdatedAt.ToUniversalTime(), DateTime.Parse("2016-12-06T16:41:06.975Z").ToUniversalTime()); + Assert.Equal(ecsEvent.Detail.TaskArn, "arn:aws:ecs:us-east-1:111122223333:task/b99d40b3-5176-4f71-9a52-9dbd6f1cebef"); + Assert.Equal(ecsEvent.Detail.TaskDefinitionArn, "arn:aws:ecs:us-east-1:111122223333:task-definition/xray:2"); + Assert.Equal(ecsEvent.Detail.Version, 4); + + Handle(ecsEvent); + } + } + + private void Handle(ECSContainerInstanceStateChangeEvent ecsEvent) + { + Console.WriteLine($"[{ecsEvent.Source} {ecsEvent.Time}] {ecsEvent.DetailType}"); + } + + private void Handle(ECSTaskStateChangeEvent ecsEvent) + { + Console.WriteLine($"[{ecsEvent.Source} {ecsEvent.Time}] {ecsEvent.DetailType}"); + } + } } diff --git a/Libraries/test/EventsTests/EventsTests.csproj b/Libraries/test/EventsTests/EventsTests.csproj index 15fe53575..95b98dccf 100644 --- a/Libraries/test/EventsTests/EventsTests.csproj +++ b/Libraries/test/EventsTests/EventsTests.csproj @@ -16,6 +16,8 @@ + + @@ -23,6 +25,7 @@ + diff --git a/Libraries/test/EventsTests/ecs-container-state-change-event.json b/Libraries/test/EventsTests/ecs-container-state-change-event.json new file mode 100644 index 000000000..aaf6365f8 --- /dev/null +++ b/Libraries/test/EventsTests/ecs-container-state-change-event.json @@ -0,0 +1,126 @@ +{ + "version": "0", + "id": "8952ba83-7be2-4ab5-9c32-6687532d15a2", + "detail-type": "ECS Container Instance State Change", + "source": "aws.ecs", + "account": "111122223333", + "time": "2016-12-06T16:41:06Z", + "region": "us-east-1", + "resources": [ + "arn:aws:ecs:us-east-1:111122223333:container-instance/b54a2a04-046f-4331-9d74-3f6d7f6ca315" + ], + "detail": { + "agentConnected": true, + "attributes": [ + { + "name": "com.amazonaws.ecs.capability.logging-driver.syslog" + }, + { + "name": "com.amazonaws.ecs.capability.task-iam-role-network-host" + }, + { + "name": "com.amazonaws.ecs.capability.logging-driver.awslogs" + }, + { + "name": "com.amazonaws.ecs.capability.logging-driver.json-file" + }, + { + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.17" + }, + { + "name": "com.amazonaws.ecs.capability.privileged-container" + }, + { + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18" + }, + { + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19" + }, + { + "name": "com.amazonaws.ecs.capability.ecr-auth" + }, + { + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.20" + }, + { + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.21" + }, + { + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.22" + }, + { + "name": "com.amazonaws.ecs.capability.docker-remote-api.1.23" + }, + { + "name": "com.amazonaws.ecs.capability.task-iam-role" + } + ], + "clusterArn": "arn:aws:ecs:us-east-1:111122223333:cluster/default", + "containerInstanceArn": "arn:aws:ecs:us-east-1:111122223333:container-instance/b54a2a04-046f-4331-9d74-3f6d7f6ca315", + "ec2InstanceId": "i-f3a8506b", + "registeredResources": [ + { + "name": "CPU", + "type": "INTEGER", + "integerValue": 2048 + }, + { + "name": "MEMORY", + "type": "INTEGER", + "integerValue": 3767 + }, + { + "name": "PORTS", + "type": "STRINGSET", + "stringSetValue": [ + "22", + "2376", + "2375", + "51678", + "51679" + ] + }, + { + "name": "PORTS_UDP", + "type": "STRINGSET", + "stringSetValue": [] + } + ], + "remainingResources": [ + { + "name": "CPU", + "type": "INTEGER", + "integerValue": 1988 + }, + { + "name": "MEMORY", + "type": "INTEGER", + "integerValue": 767 + }, + { + "name": "PORTS", + "type": "STRINGSET", + "stringSetValue": [ + "22", + "2376", + "2375", + "51678", + "51679" + ] + }, + { + "name": "PORTS_UDP", + "type": "STRINGSET", + "stringSetValue": [] + } + ], + "status": "ACTIVE", + "version": 14801, + "versionInfo": { + "agentHash": "aebcbca", + "agentVersion": "1.13.0", + "dockerVersion": "DockerVersion: 1.11.2" + }, + "updatedAt": "2016-12-06T16:41:06.991Z" + } +} \ No newline at end of file diff --git a/Libraries/test/EventsTests/ecs-task-state-change-event.json b/Libraries/test/EventsTests/ecs-task-state-change-event.json new file mode 100644 index 000000000..fa36a1ade --- /dev/null +++ b/Libraries/test/EventsTests/ecs-task-state-change-event.json @@ -0,0 +1,42 @@ +{ + "version": "0", + "id": "9bcdac79-b31f-4d3d-9410-fbd727c29fab", + "detail-type": "ECS Task State Change", + "source": "aws.ecs", + "account": "111122223333", + "time": "2016-12-06T16:41:06Z", + "region": "us-east-1", + "resources": [ + "arn:aws:ecs:us-east-1:111122223333:task/b99d40b3-5176-4f71-9a52-9dbd6f1cebef" + ], + "detail": { + "clusterArn": "arn:aws:ecs:us-east-1:111122223333:cluster/default", + "containerInstanceArn": "arn:aws:ecs:us-east-1:111122223333:container-instance/b54a2a04-046f-4331-9d74-3f6d7f6ca315", + "containers": [ + { + "containerArn": "arn:aws:ecs:us-east-1:111122223333:container/3305bea1-bd16-4217-803d-3e0482170a17", + "exitCode": 0, + "lastStatus": "STOPPED", + "name": "xray", + "taskArn": "arn:aws:ecs:us-east-1:111122223333:task/b99d40b3-5176-4f71-9a52-9dbd6f1cebef" + } + ], + "createdAt": "2016-12-06T16:41:05.702Z", + "desiredStatus": "RUNNING", + "group": "task-group", + "lastStatus": "RUNNING", + "overrides": { + "containerOverrides": [ + { + "name": "xray" + } + ] + }, + "startedAt": "2016-12-06T16:41:06.8Z", + "startedBy": "ecs-svc/9223370556150183303", + "updatedAt": "2016-12-06T16:41:06.975Z", + "taskArn": "arn:aws:ecs:us-east-1:111122223333:task/b99d40b3-5176-4f71-9a52-9dbd6f1cebef", + "taskDefinitionArn": "arn:aws:ecs:us-east-1:111122223333:task-definition/xray:2", + "version": 4 + } +} \ No newline at end of file