public HelloStack(Construct parent, string id, IStackProps props) : base(parent, id, props) { var topic = new Topic(this, "HelloCdkTopic", new TopicProps { TopicName = "HelloCdkTopic", DisplayName = "My First Topic From HelloCdk" }); var queue = new Queue(this, "HelloCdkQueue", new QueueProps { QueueName = "HelloCdkQueue" }); topic.AddSubscription(new SqsSubscription(queue, new SqsSubscriptionProps { RawMessageDelivery = true })); var functionType = typeof(HelloCdkConsumerLambda.Function); var function = new Function(this, nameof(HelloCdkConsumerLambda), new FunctionProps { Code = Code.FromAsset($"./src/{nameof(HelloCdkConsumerLambda)}/bin/Release/netcoreapp2.1/publish"), Runtime = Runtime.DOTNET_CORE_2_1, Tracing = Tracing.ACTIVE, Handler = $"{functionType.Assembly.GetName().Name}::{functionType}::{nameof(HelloCdkConsumerLambda.Function.FunctionHandler)}", MemorySize = 256, Timeout = Duration.Seconds(10) }); function.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { Actions = new[] { "sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:GetQueueAttributes", "sqs:ChangeMessageVisibility" }, Resources = new[] { queue.QueueArn } })); _ = new EventSourceMapping(this, $"{nameof(HelloCdkConsumerLambda)}Trigger", new EventSourceMappingProps { EventSourceArn = queue.QueueArn, BatchSize = 10, Enabled = true, Target = function }); }
internal LoadTesterStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { // The code that defines your stack goes here var fn = new Function(this, "loadtester", new FunctionProps { FunctionName = "loadtester", Runtime = Runtime.NODEJS_12_X, Code = Code.FromAsset("src/EdgyRegions/resources/loadtest"), Handler = "index.handler", Timeout = Duration.Minutes(15) }); var poly = new Amazon.CDK.AWS.IAM.PolicyStatement { Effect = Amazon.CDK.AWS.IAM.Effect.ALLOW, }; poly.AddActions(new string[] { "cloudwatch:PutMetricData" }); poly.AddAllResources(); fn.AddToRolePolicy(poly); }
public TheEventbridgeAtmStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { //Producer Lambda var atmProducerLambda = new Function(this, "atmProducerLambda", new FunctionProps { Runtime = Runtime.NODEJS_12_X, Code = Code.FromAsset("lambda-fns/atmProducer"), Handler = "handler.lambdaHandler" }); var eventPolicy = new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Resources = new[] { "*" }, Actions = new[] { "events:PutEvents" } }); atmProducerLambda.AddToRolePolicy(eventPolicy); //Approved Transaction Consumer var atmConsumer1Lambda = new Function(this, "atmConsumer1Lambda", new FunctionProps { Runtime = Runtime.NODEJS_12_X, Code = Code.FromAsset("lambda-fns/atmConsumer"), Handler = "handler.case1Handler" }); var atmConsumer1LambdaRule = new Rule(this, "atmConsumer1LambdaRule", new RuleProps { Description = "Approved transactions", EventPattern = new EventPattern { Source = new[] { "custom.myATMapp" }, DetailType = new[] { "transaction" }, Detail = new Dictionary <string, object> { ["result"] = new[] { "approved" } } } }); atmConsumer1LambdaRule.AddTarget(new LambdaFunction(atmConsumer1Lambda)); //NY Prefix Consumer var atmConsumer2Lambda = new Function(this, "atmConsumer2Lambda", new FunctionProps { Runtime = Runtime.NODEJS_12_X, Code = Code.FromAsset("lambda-fns/atmConsumer"), Handler = "handler.case2Handler" }); var atmConsumer2LambdaRule = new Rule(this, "atmConsumer2LambdaRule", new RuleProps { Description = "Transactions with NY- prefix", EventPattern = new EventPattern { Source = new[] { "custom.myATMapp" }, DetailType = new[] { "transaction" }, Detail = new Dictionary <string, object> { ["location"] = new [] { new Dictionary <string, string> { ["prefix"] = "NY-" } } } } }); atmConsumer2LambdaRule.AddTarget(new LambdaFunction(atmConsumer2Lambda)); //Not Approved Consumer var atmConsumer3Lambda = new Function(this, "atmConsumer3Lambda", new FunctionProps { Runtime = Runtime.NODEJS_12_X, Code = Code.FromAsset("lambda-fns/atmConsumer"), Handler = "handler.case3Handler" }); var atmConsumer3LambdaRule = new Rule(this, "atmConsumer3LambdaRule", new RuleProps { Description = "Not approved transactions", EventPattern = new EventPattern { Source = new[] { "custom.myATMapp" }, DetailType = new[] { "transaction" }, Detail = new Dictionary <string, object> { ["result"] = new[] { new Dictionary <string, object> { ["anything-but"] = "approved" } } } } }); atmConsumer3LambdaRule.AddTarget(new LambdaFunction(atmConsumer3Lambda)); //API Gateway proxy integration // defines an API Gateway REST API resource backed by our "atmProducerLambda" function. new LambdaRestApi(this, "Endpoint", new LambdaRestApiProps { Handler = atmProducerLambda }); }
internal ColdStartSimulatorStack(Construct scope, string id, StackProps props = null) : base(scope, id, props) { var coldStartSimulatorLambdaPolicy = new Amazon.CDK.AWS.IAM.PolicyStatement { Effect = Amazon.CDK.AWS.IAM.Effect.ALLOW }; coldStartSimulatorLambdaPolicy.AddResources("*"); coldStartSimulatorLambdaPolicy.AddActions("lambda:*"); coldStartSimulatorLambdaPolicy.AddActions("xray:*"); var coldStartSimulatorSetupFunction = new Function(this, "coldstartsimulator-setup", new FunctionProps { FunctionName = "coldstartsimulator-setup", Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("../lambdas/coldstartsimulator/bin/Release/netcoreapp3.1/publish"), Handler = "ColdStartSimulator::ColdStartSimulator.StepFunctionTasks::Setup", Timeout = Duration.Seconds(31), MemorySize = 512 }); var coldStartSimulatorInvokeLambdaFunction = new Function(this, "coldstartsimulator-invokelambda", new FunctionProps { FunctionName = "coldstartsimulator-invokelambda", Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("../lambdas/coldstartsimulator/bin/Release/netcoreapp3.1/publish"), Handler = "ColdStartSimulator::ColdStartSimulator.StepFunctionTasks::InvokeLambda", Timeout = Duration.Seconds(31), MemorySize = 512 }); coldStartSimulatorInvokeLambdaFunction.AddToRolePolicy(coldStartSimulatorLambdaPolicy); var coldStartSimulatorTouchLambdaFunction = new Function(this, "coldstartsimulator-touchlambda", new FunctionProps { FunctionName = "coldstartsimulator-touchlambda", Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("../lambdas/coldstartsimulator/bin/Release/netcoreapp3.1/publish"), Handler = "ColdStartSimulator::ColdStartSimulator.StepFunctionTasks::TouchLambda", Timeout = Duration.Seconds(31), MemorySize = 512 }); coldStartSimulatorTouchLambdaFunction.AddToRolePolicy(coldStartSimulatorLambdaPolicy); var metricS3Bucket = new Bucket(this, "metric-bucket", new BucketProps { BucketName = "coldstart-metric-bucket", }); var coldStartSimulatorCollectMetricsFunction = new Function(this, "coldstartsimulator-collectmetrics", new FunctionProps { FunctionName = "coldstartsimulator-collectmetrics", Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("../lambdas/coldstartsimulator/bin/Release/netcoreapp3.1/publish"), Handler = "ColdStartSimulator::ColdStartSimulator.StepFunctionTasks::CollectMetrics", Timeout = Duration.Seconds(31), MemorySize = 512 }); metricS3Bucket.GrantPut(coldStartSimulatorCollectMetricsFunction); coldStartSimulatorCollectMetricsFunction.AddEnvironment("MetricS3BucketName", metricS3Bucket.BucketName); coldStartSimulatorCollectMetricsFunction.AddToRolePolicy(coldStartSimulatorLambdaPolicy); var setup = new LambdaInvoke(this, "Setup", new LambdaInvokeProps { LambdaFunction = coldStartSimulatorSetupFunction, OutputPath = "$.Payload" }); var touch = new LambdaInvoke(this, "Touch", new LambdaInvokeProps { LambdaFunction = coldStartSimulatorTouchLambdaFunction, OutputPath = "$.Payload" }); var invoke = new LambdaInvoke(this, "Invoke", new LambdaInvokeProps { LambdaFunction = coldStartSimulatorInvokeLambdaFunction, OutputPath = "$.Payload" }); var collectMetrics = new LambdaInvoke(this, "Collect Metrics", new LambdaInvokeProps { LambdaFunction = coldStartSimulatorCollectMetricsFunction, OutputPath = "$.Payload" }); var wait3Seconds = new Wait(this, "Wait 3 seconds", new WaitProps { Time = WaitTime.Duration(Duration.Seconds(3)) }); var wait30Seconds = new Wait(this, "Wait 30 seconds", new WaitProps { Time = WaitTime.Duration(Duration.Seconds(30)) }); var invokeAgainChoice = new Choice(this, "Invoke again?"); invokeAgainChoice.When(Condition.BooleanEquals("$.Continue", true), touch); invokeAgainChoice.Otherwise(wait30Seconds); wait30Seconds .Next(collectMetrics); var definition = setup .Next(touch) .Next(wait3Seconds) .Next(invoke) .Next(invokeAgainChoice); new StateMachine(this, "ColdStartSimulatorStateMachine", new StateMachineProps { Definition = definition, Timeout = Duration.Minutes(10) }); }
internal TranscriptionStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { var inputBucket = new Bucket(this, "Input"); var outputBucket = new Bucket(this, "Output"); var languageCode = this.Node.TryGetContext("LanguageCode")?.ToString(); if (string.IsNullOrEmpty(languageCode)) { languageCode = "en-us"; } var startJobFunction = new Function(this, "StartJobFunction", new FunctionProps { Tracing = Tracing.ACTIVE, Runtime = Runtime.DOTNET_CORE_2_1, Timeout = Duration.Seconds(30), MemorySize = 256, Environment = new Dictionary <string, string>() { { "TRANSCRIBE_OUTPUT_BUCKET", outputBucket.BucketName }, { "TRANSCRIBE_LANGUAGE_CODE", languageCode } }, FunctionName = "StartTranscriptionJob", Code = Code.FromAsset("./assets/StartTranscriptionJob.zip"), Handler = "StartTranscriptionJob::StartTranscriptionJob.Function::FunctionHandler", Events = new[] { new S3EventSource(inputBucket, new S3EventSourceProps { Events = new [] { EventType.OBJECT_CREATED } }) } }); startJobFunction.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { Actions = new[] { "transcribe:StartTranscriptionJob" }, Effect = Effect.ALLOW, Resources = new[] { "*" } })); // this is passed onto Transcribe so it can write to the output bucket startJobFunction.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { Actions = new[] { "s3:Put*" }, Effect = Effect.ALLOW, Resources = new[] { outputBucket.ArnForObjects("*") } })); inputBucket.GrantRead(startJobFunction); var notificationTopic = new Topic(this, "TranscriptionNotificationTopic", new TopicProps { TopicName = "TranscriptionCompletedTopic", }); var subscriberEmail = this.Node.TryGetContext("SubscriberEmail")?.ToString(); if (!string.IsNullOrEmpty(subscriberEmail)) { notificationTopic.AddSubscription(new EmailSubscription(subscriberEmail)); } var notifyCompletionFunction = new Function(this, "NotifyCompleteFunction", new FunctionProps { Tracing = Tracing.ACTIVE, Runtime = Runtime.DOTNET_CORE_2_1, Timeout = Duration.Seconds(30), MemorySize = 256, Environment = new Dictionary <string, string>() { { "TRANSCRIBE_TOPIC_ARN", notificationTopic.TopicArn } }, FunctionName = "NotifyTranscriptionJobComplete", Code = Code.FromAsset("./assets/NotifyTranscriptionJobComplete.zip"), Handler = "NotifyTranscriptionJobComplete::NotifyTranscriptionJobComplete.Function::FunctionHandler", Events = new[] { new S3EventSource(outputBucket, new S3EventSourceProps { Events = new [] { EventType.OBJECT_CREATED } }) } }); notifyCompletionFunction.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { Actions = new[] { "sns:Publish" }, Effect = Effect.ALLOW, Resources = new[] { notificationTopic.TopicArn } })); notifyCompletionFunction.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { // this permission is needed so that when the user clicks the presigned url // that the Lambda generates, S3 will permit access to the object content and // not otherwise return an access-denied error Actions = new[] { "s3:GetObject" }, Effect = Effect.ALLOW, Resources = new[] { outputBucket.ArnForObjects("*") } })); outputBucket.GrantWrite(notifyCompletionFunction); // emit the name of the input bucket so we know where to upload content! new CfnOutput(this, "InputBucket", new CfnOutputProps { Value = inputBucket.BucketName }); }
internal MackerelAlertLampStack(Construct scope, string id, MackerelAlertLampProps props) : base(scope, id, props) { System.Console.Out.WriteLine(string.Join(",", props.ThingCerts)); // MackerelのEventBridge通知チャンネル先のパートナーイベントソース名 // リソース名に使用するのでここで構築しておく。 var eventSourceName = $"aws.partner/mackerel.io/{props.OrganizationName}/{props.EventName}"; var thingPolicy = new Amazon.CDK.AWS.IoT.CfnPolicy(this, "MackerelAlertLampThingPoilcy", new Amazon.CDK.AWS.IoT.CfnPolicyProps() { PolicyName = "MackerelAlertLampThingPoilcy", PolicyDocument = new Dictionary <string, object> { ["Version"] = "2012-10-17", ["Statement"] = new object[] { new Dictionary <string, object> { ["Effect"] = "Allow", ["Action"] = new string[] { "iot:*", "greengrass:*", }, ["Resource"] = new string[] { "*" }, } } } }); // IDなどに使うために証明書のARNを加工しておく。 var certs = props.ThingCerts .Select(x => new { Arn = x, Hash = Utils.ToHash(x), }).ToList(); var certAttaches = certs.Select(x => { var attach = new CfnPolicyPrincipalAttachment(this, "MackerelAlertLampCertAttach-" + x.Hash, new CfnPolicyPrincipalAttachmentProps() { PolicyName = thingPolicy.PolicyName, Principal = x.Arn, }); attach.AddDependsOn(thingPolicy); return(attach); }).ToList(); var things = certs.Select(x => new { CertArn = x.Arn, Thing = new CfnThing(this, "MackerelAlertLampThing-" + x.Hash, new CfnThingProps() { ThingName = "MackerelAlertLamp-" + x.Hash, }) }).ToList(); var thingAttaches = things.Select(x => { var attach = new CfnThingPrincipalAttachment(this, x.Thing.ThingName + "Attach", new CfnThingPrincipalAttachmentProps() { ThingName = x.Thing.ThingName, Principal = x.CertArn, }); attach.AddDependsOn(x.Thing); return(attach); }).ToList(); var cloudReceiveAlertFunction = new Function(this, "CloudReceiveAlert", new FunctionProps() { Runtime = Runtime.PYTHON_3_7, Code = Code.FromAsset("handlers/cloud"), Handler = "ReceiveAlert.handler", Environment = new Dictionary <string, string>() { ["MACKEREL_ALERT_TOPIC"] = eventSourceName, }, }); cloudReceiveAlertFunction.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps() { Actions = new string[] { "iot:Publish", }, Resources = new string[] { "*", }, })); var ggLambda = new Function(this, "DeviceReceiveAlert", new FunctionProps() { Runtime = Runtime.PYTHON_3_7, Code = Code.FromAsset("handlers/device"), Handler = "ReceiveAlert.handler", }); var ggLambdaVersion = ggLambda.AddVersion("v1"); var ggLambdaAlias = new Alias(this, "DeviceReceiveAlertAlias", new AliasProps() { AliasName = "v" + ggLambdaVersion.Version, Version = ggLambdaVersion, }); var toggleGpio = new Function(this, "DeviceToggleGpio", new FunctionProps() { Runtime = Runtime.PYTHON_3_7, Code = Code.FromAsset("handlers/device"), Handler = "ToggleGpio.handler", }); var toggleGpioVersion = toggleGpio.AddVersion("v1"); var toggleGpioAlias = new Alias(this, "DeviceToggleGpioAlias", new AliasProps() { AliasName = "v" + toggleGpioVersion.Version, Version = toggleGpioVersion, }); var ggCoreId = 0; var ggCore = new CfnCoreDefinition(this, "MackerelAlertLampCore", new CfnCoreDefinitionProps() { Name = "MackerelAlertLampCore", InitialVersion = new CfnCoreDefinition.CoreDefinitionVersionProperty() { Cores = things.Select(x => new CfnCoreDefinition.CoreProperty() { Id = (++ggCoreId).ToString(), CertificateArn = x.CertArn, // XXX ARN参照できないの? //ThingArn = x.Thing.GetAtt("Arn").Reference.ToString(), //ThingArn = x.Thing.GetAtt("resource.arn").Reference.ToString(), ThingArn = $"arn:aws:iot:{this.Region}:{this.Account}:thing/{x.Thing.ThingName}", }).ToArray(), } }); things.ForEach(x => { ggCore.AddDependsOn(x.Thing); }); var gpioRw = new CfnResourceDefinition.ResourceInstanceProperty() { Id = "gpio-rw", Name = "RaspberryPiGpioRw", ResourceDataContainer = new CfnResourceDefinition.ResourceDataContainerProperty() { LocalDeviceResourceData = new CfnResourceDefinition.LocalDeviceResourceDataProperty() { SourcePath = "/dev/gpiomem", GroupOwnerSetting = new CfnResourceDefinition.GroupOwnerSettingProperty() { AutoAddGroupOwner = true, }, } }, }; var ggResource = new CfnResourceDefinition(this, "MackerelAlertLampResource", new CfnResourceDefinitionProps() { Name = "MackerelAlertLampResource", InitialVersion = new CfnResourceDefinition.ResourceDefinitionVersionProperty() { Resources = new CfnResourceDefinition.ResourceInstanceProperty[] { gpioRw, } }, }); var ggFunction = new CfnFunctionDefinition(this, "MackerelAlertLampFunction", new CfnFunctionDefinitionProps() { Name = "MackerelAlertLampFunction", InitialVersion = new CfnFunctionDefinition.FunctionDefinitionVersionProperty() { Functions = new CfnFunctionDefinition.FunctionProperty[] { new CfnFunctionDefinition.FunctionProperty() { Id = ggLambda.FunctionName + "-" + ggLambdaAlias.AliasName, FunctionArn = ggLambdaAlias.FunctionArn, FunctionConfiguration = new CfnFunctionDefinition.FunctionConfigurationProperty() { // MemorySize と Timeout は必須である様子 MemorySize = 65535, Timeout = 10, // 秒 }, }, new CfnFunctionDefinition.FunctionProperty() { Id = toggleGpio.FunctionName + "-" + toggleGpioAlias.AliasName, FunctionArn = toggleGpioAlias.FunctionArn, FunctionConfiguration = new CfnFunctionDefinition.FunctionConfigurationProperty() { // MemorySize と Timeout は必須である様子 MemorySize = 65535, Timeout = 10, // 秒 }, }, }, }, }); // https://docs.aws.amazon.com/ja_jp/greengrass/latest/developerguide/raspberrypi-gpio-connector.html var gpioConnector = new CfnConnectorDefinition.ConnectorProperty() { Id = "gpio-connector", ConnectorArn = $"arn:aws:greengrass:{this.Region}::/connectors/RaspberryPiGPIO/versions/1", Parameters = new Dictionary <string, object>() { ["GpioMem-ResourceId"] = gpioRw.Id, //["InputGpios"] = "5,6U,7D", //["InputPollPeriod"] = 50, // 10, 9, 11番は配置連続しているのでとりあえずそれを使う ["OutputGpios"] = "9L,10L,11L", } }; var ggConnector = new CfnConnectorDefinition(this, "MackerelAlertLampConnector", new CfnConnectorDefinitionProps() { Name = "MackerelAlertLampConnector", InitialVersion = new CfnConnectorDefinition.ConnectorDefinitionVersionProperty() { Connectors = new CfnConnectorDefinition.ConnectorProperty[] { gpioConnector, }, } }); var ggSubscriptions = new CfnSubscriptionDefinition.SubscriptionProperty[] { // ReceiveAlert Cloud to Device new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "mackerel-alert-to-device", Source = "cloud", Target = ggLambdaAlias.FunctionArn, Subject = eventSourceName, }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "mackerel-alert-gpio-write-11", Source = ggLambdaAlias.FunctionArn, Target = gpioConnector.ConnectorArn, Subject = "gpio/+/11/write", }, // XXX Currently, when you create a subscription that uses the Raspberry Pi GPIO connector, you must specify a value for at least one of the + wildcards in the topic. new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-read", Source = "cloud", Target = gpioConnector.ConnectorArn, Subject = "gpio/+/9/read", }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-write", Source = "cloud", Target = gpioConnector.ConnectorArn, Subject = "gpio/+/9/write", }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-state", Source = gpioConnector.ConnectorArn, Target = "cloud", Subject = "gpio/+/9/state", }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-error", Source = gpioConnector.ConnectorArn, Target = "cloud", Subject = "gpio/+/error", }, // new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-read-10", Source = "cloud", Target = gpioConnector.ConnectorArn, Subject = "gpio/+/10/read", }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-write-10", Source = "cloud", Target = gpioConnector.ConnectorArn, Subject = "gpio/+/10/write", }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-state-10", Source = gpioConnector.ConnectorArn, Target = "cloud", Subject = "gpio/+/10/state", }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-read-11", Source = toggleGpioAlias.FunctionArn, Target = gpioConnector.ConnectorArn, Subject = "gpio/+/11/read", }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-write-11", Source = toggleGpioAlias.FunctionArn, Target = gpioConnector.ConnectorArn, Subject = "gpio/+/11/write", }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-state-11", Source = gpioConnector.ConnectorArn, Target = "cloud", Subject = "gpio/+/11/state", }, new CfnSubscriptionDefinition.SubscriptionProperty() { Id = "gpio-test", Source = "cloud", Target = toggleGpioAlias.FunctionArn, Subject = "gpio/test", }, }; var ggSubscription = new CfnSubscriptionDefinition(this, "MackerelAlertLampSubscription", new CfnSubscriptionDefinitionProps() { Name = "MackerelAlertLampSubscription", InitialVersion = new CfnSubscriptionDefinition.SubscriptionDefinitionVersionProperty() { Subscriptions = ggSubscriptions, }, }); var ggGroup = new Amazon.CDK.AWS.Greengrass.CfnGroup(this, "MackerelAlertLampGroup", new Amazon.CDK.AWS.Greengrass.CfnGroupProps() { Name = "MackerelAlertLamp", // XXX 引数にする RoleArn = "arn:aws:iam::854403262515:role/service-role/Greengrass_ServiceRole", }); var ggVersionHash = Utils.ToHash(string.Join("-", ggCore.AttrLatestVersionArn, ggFunction.AttrLatestVersionArn, ggResource.AttrLatestVersionArn, ggConnector.AttrLatestVersionArn, ggSubscription.AttrLatestVersionArn)); var ggLatestVersion = new CfnGroupVersion(this, "MackerelAlertLampGroupVersion-" + ggVersionHash, new CfnGroupVersionProps() { GroupId = ggGroup.AttrId, CoreDefinitionVersionArn = ggCore.AttrLatestVersionArn, FunctionDefinitionVersionArn = ggFunction.AttrLatestVersionArn, ResourceDefinitionVersionArn = ggResource.AttrLatestVersionArn, ConnectorDefinitionVersionArn = ggConnector.AttrLatestVersionArn, SubscriptionDefinitionVersionArn = ggSubscription.AttrLatestVersionArn, }); ggLatestVersion.AddDependsOn(ggGroup); ggLatestVersion.AddDependsOn(ggCore); ggLatestVersion.AddDependsOn(ggResource); ggLatestVersion.AddDependsOn(ggFunction); ggLatestVersion.AddDependsOn(ggConnector); ggLatestVersion.AddDependsOn(ggSubscription); var mackerelAlertBus = new EventBus(this, "mackerel-alert-bus", new EventBusProps() { EventSourceName = eventSourceName, }); var mackerelAlertRule = new Rule(this, "mackerel-alert-rule", new RuleProps() { EventBus = mackerelAlertBus, EventPattern = new EventPattern() { Account = new string[] { this.Account, }, }, Targets = new IRuleTarget[] { new LambdaFunction(cloudReceiveAlertFunction), }, }); }
/// <summary> /// Constructor. /// </summary> /// <param name="scope"></param> /// <param name="id"></param> /// <param name="props"></param> public LogAggregator(Construct scope, string id, LogAggregatorProps props) : base(scope, id) { // The Kinesis stream that will receive all lambda logs. var kinesisStream = new Amazon.CDK.AWS.Kinesis.Stream(this, "Stream", props.KinesisStreamProps); // Forward all records from kinesis to the log shipper. props.LogShipper.AddEventSource(new KinesisEventSource(kinesisStream, new KinesisEventSourceProps { BatchSize = props.KinesisBatchSize, MaxBatchingWindow = props.KinesisMaxBatchingWindow, StartingPosition = StartingPosition.TRIM_HORIZON, })); // Create a role (containing a policy) that can be assumed by CloudWatch logs to put records in Kinesis. var statement = new PolicyStatement(); statement.AddActions(new[] { "kinesis:PutRecords", "kinesis:PutRecord" }); statement.AddResources(new[] { kinesisStream.StreamArn }); var cloudWatchLogsToKinesisRole = new Role(this, "CloudWatchLogsToKinesis", new RoleProps { AssumedBy = new ServicePrincipal("logs.amazonaws.com") }); cloudWatchLogsToKinesisRole.AttachInlinePolicy(new Policy(this, "CanPutRecordsInKinesis", new PolicyProps { Statements = new[] { statement } })); // This CloudWatch rule will trigger whenever a new LogGroup is created. This assumes // that CloudTrail is enabled. var createLogGroupEventRule = new Rule(this, "CreateLogGroupEvent", new RuleProps { Description = "Fires whenever CloudTrail detects that a log group is created", EventPattern = new EventPattern { Source = new[] { "aws.logs" }, DetailType = new[] { "AWS API Call via CloudTrail" }, Detail = new Dictionary <string, object> { { "eventSource", new string[] { "logs.amazonaws.com" } }, { "eventName", new string[] { "CreateLogGroup" } }, } } }); if (props.CloudWatchLogRetentionInDays.HasValue) { var setLogGroupExpirationLambda = new Function(this, "SetLogGroupExpiration", new FunctionProps { Runtime = Runtime.NODEJS_10_X, Handler = "index.handler", Description = $"Sets the log retention policy to {props.CloudWatchLogRetentionInDays} days when a log group is created.", MemorySize = 128, Environment = new Dictionary <string, string> { { "retention_days", props.CloudWatchLogRetentionInDays.Value.ToString() }, { "prefix", props.LogGroupsPrefix }, }, Code = Code.FromInline(EmbeddedResourceReader.Read("Resources.SetExpiry.js")) }); // This lambda must be able to change the logs retention policy. setLogGroupExpirationLambda.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Actions = new[] { "logs:PutRetentionPolicy" }, Resources = new[] { "*" }, })); // This lambda should be invoked automatically when a log group is created. createLogGroupEventRule.AddTarget(new LambdaFunction(setLogGroupExpirationLambda)); } var excludedLogGroups = props.LogShipper == null ? "" : $"/aws/lambda/{props.LogShipper.FunctionName}"; // This function will be invoked whenever a CloudWatch log group is created. It will // subscribe the log group to our Kinesis Data Stream so that all logs end up in the // DataStream. var subscribeLogGroupsToKinesisLambda = new Function(this, "SubscribeLogGroupsToKinesis", new FunctionProps { Runtime = Runtime.NODEJS_10_X, Handler = "index.handler", Description = "Subscribe logs to the Kinesis stream", MemorySize = 128, Environment = new Dictionary <string, string> { { "arn", kinesisStream.StreamArn }, { "role_arn", cloudWatchLogsToKinesisRole.RoleArn }, { "prefix", props.LogGroupsPrefix }, { "excluded_log_groups", excludedLogGroups }, { "filter_pattern", props.CloudWatchLogsFilterPattern.ToString() }, }, Code = Code.FromInline(EmbeddedResourceReader.Read("Resources.SubscribeLogGroupsToKinesis.js")) }); subscribeLogGroupsToKinesisLambda.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Actions = new [] { "logs:PutSubscriptionFilter" }, Resources = new[] { "*" }, })); subscribeLogGroupsToKinesisLambda.AddToRolePolicy(new PolicyStatement(new PolicyStatementProps { Effect = Effect.ALLOW, Actions = new[] { "iam:PassRole" }, Resources = new[] { "*" }, })); createLogGroupEventRule.AddTarget(new LambdaFunction(subscribeLogGroupsToKinesisLambda)); }
internal StepFunctionDemoStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { Bucket stepFunctionDemoBucket = new Bucket(this, "StepFunctionDemoBucket", new BucketProps { Encryption = BucketEncryption.S3_MANAGED, RemovalPolicy = RemovalPolicy.RETAIN }); Table stepFunctionDemoTable = new Table(this, "StepFunctionDemoTable", new TableProps { BillingMode = BillingMode.PROVISIONED, PartitionKey = new Amazon.CDK.AWS.DynamoDB.Attribute { Name = "Id", Type = AttributeType.STRING }, RemovalPolicy = RemovalPolicy.DESTROY }); //Step Function invoking Lambda function Function invokeOddEvenStepFunction = new Function(this, "InvokeOddEvenStepFunction", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::InvokeOddEvenStepFunction", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Lambda Function that invokes the Demo Step Function", }); //Function to calculate Odd or Even Function oddOrEvenFunction = new Function(this, "OddOrEvenFunction", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::OddOrEvenFunction", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Lambda Function that calculates odd or even", }); //Demo Lambda to perform Process 1 Function process1Function = new Function(this, "Process1Function", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process1Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs process1", }); Function processAFunction = new Function(this, "ProcessAFunction", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process1Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs process1", }); //Demo Lambda to perform Process 2 Function process2Function = new Function(this, "Process2Function", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process2Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs process2", }); //Demo Lambda to perform Process 1 Function process11Function = new Function(this, "Process11Function", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process11Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs job process1", }); //Demo Lambda to perform Process 2 Function process12Function = new Function(this, "Process12Function", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::Process12Function", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that runs job process2", }); Function taskTokenExecutorFunction = new Function(this, "TaskTokenExecutorFunction", new FunctionProps { Runtime = Runtime.DOTNET_CORE_3_1, Code = Code.FromAsset("src/Demo.Services.Lambda/bin/Release/netcoreapp3.1/Demo.Services.Lambda.zip"), Handler = "Demo.Services.Lambda::Demo.Services.Lambda.Functions::TaskTokenExecutor", Timeout = Duration.Minutes(5), MemorySize = 512, Description = "Demo Lambda Function that executes Task Token Step", Environment = new Dictionary <string, string>() { ["STEP_FUNCTION_DEMO_BUCKET"] = stepFunctionDemoBucket.BucketName } }); stepFunctionDemoBucket.GrantReadWrite(taskTokenExecutorFunction); var oddEvenFunction = new Task(this, "OddEvenFunction", new TaskProps { Task = new InvokeFunction(oddOrEvenFunction.LatestVersion) }); var process1 = new Task(this, "Process1", new TaskProps { Task = new InvokeFunction(process1Function.LatestVersion) }); var processA = new Task(this, "ProcessA", new TaskProps { Task = new InvokeFunction(processAFunction.LatestVersion) }); var process2 = new Task(this, "Process2", new TaskProps { Task = new InvokeFunction(process2Function.LatestVersion) }); var process11 = new Task(this, "Process11", new TaskProps { Task = new InvokeFunction(process11Function.LatestVersion), ResultPath = "$.Resolved" }); var process12 = new Task(this, "Process12", new TaskProps { Task = new InvokeFunction(process12Function.LatestVersion) }); var taskTokenExecutor = new Task(this, "TaskTokenExecutor", new TaskProps { Task = new RunLambdaTask(taskTokenExecutorFunction.LatestVersion, new RunLambdaTaskProps() { IntegrationPattern = ServiceIntegrationPattern.WAIT_FOR_TASK_TOKEN, Payload = TaskInput.FromContextAt("$$.Task.Token") }), Parameters = new Dictionary <string, object> { ["Payload"] = new Dictionary <string, object> { ["TaskToken.$"] = "$$.Task.Token", ["State.$"] = "$" } } }); //Choice to go to Process 1 or Process 2 based on input number is odd or even. var isEven = new Choice(this, "Is the number Even?"); var isResolvedOrOverriden = new Choice(this, "Is Resolved Or Overriden?"); //var chain1 = Chain.Start(oddEvenFunction) // .Next(isEven // .When( // Condition.StringEquals("$.Result", "Even"), // Chain.Start(process1) // .Next(process11) // .Next(isResolvedOrOverriden // .When( // Condition.Or( // new[] // { // Condition.BooleanEquals("$.Resolved", true), // Condition.BooleanEquals("$.Override", true) // }), process12) // .Otherwise(process2))) // .When(Condition.StringEquals("$.Result", "Odd"), process2)); var chain1 = Chain.Start(oddEvenFunction) .Next(isEven .When( Condition.StringEquals("$.Result", "Even"), Chain.Start(process1) .Next(taskTokenExecutor) .Next(isResolvedOrOverriden .When( Condition.Or( new[] { Condition.BooleanEquals("$.Resolved", true), Condition.BooleanEquals("$.Override", true) }), process12) .Otherwise(process2))) .When(Condition.StringEquals("$.Result", "Odd"), process2)); //State Machine var stateMachine = new StateMachine(this, "JobDemoStateMachine", new StateMachineProps { StateMachineName = "JobDemoStateMachine", Timeout = Duration.Minutes(5), Definition = chain1 }); stateMachine.Role?.AddManagedPolicy(ManagedPolicy.FromManagedPolicyArn(this, "DynamoDBFullAccessForStepFunction", "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess")); stateMachine.Role?.AddManagedPolicy(ManagedPolicy.FromManagedPolicyArn(this, "LambdaFullAccessForStepFunction", "arn:aws:iam::aws:policy/AWSLambdaFullAccess")); var demofargateTask1 = new FargateTaskDefinition(this, "demoECSTask1Definition", new FargateTaskDefinitionProps { MemoryLimitMiB = 4096, Cpu = 2048 }); var demofargateTask2 = new FargateTaskDefinition(this, "demoECSTask2Definition", new FargateTaskDefinitionProps { MemoryLimitMiB = 4096, Cpu = 2048 }); stepFunctionDemoBucket.GrantReadWrite(demofargateTask2.TaskRole); IVpc publicVpc = Vpc.FromLookup(this, "PublicVPC", new VpcLookupOptions { Tags = new Dictionary <string, string> { ["Paces:VpcType"] = "Public" } }); var cluster = Cluster.FromClusterAttributes(this, "PublicCluster", new ClusterAttributes { ClusterName = "OHC-PACES", Vpc = publicVpc, SecurityGroups = new[] { SecurityGroup.FromSecurityGroupId(this, "SecurityGroup", "sg-0a1bab8166d8fb715") } }); var container1 = demofargateTask1.AddContainer("app", new ContainerDefinitionOptions { Image = ContainerImage.FromAsset(".", new AssetImageProps { File = "Dockerfile" }), Logging = LogDriver.AwsLogs(new AwsLogDriverProps { LogGroup = new LogGroup(this, "demoECSTask1LogGroup", new LogGroupProps { LogGroupName = "/ecs/demoECSTask1-" + RandomString.Generate(10, StackId), }), StreamPrefix = "logs" }), }); var container2 = demofargateTask2.AddContainer("app", new ContainerDefinitionOptions { Image = ContainerImage.FromAsset(".", new AssetImageProps { File = "Dockerfile.1" }), Environment = new Dictionary <string, string> { ["STEP_FUNCTION_DEMO_BUCKET"] = stepFunctionDemoBucket.BucketName }, Logging = LogDriver.AwsLogs(new AwsLogDriverProps { LogGroup = new LogGroup(this, "demoECSTask2LogGroup", new LogGroupProps { LogGroupName = $"/ecs/demoECSTask2-{RandomString.Generate(10, StackId)}", }), StreamPrefix = "logs" }) }); Rule rule = new Rule(this, "DemoJobRule", new RuleProps { Schedule = Schedule.Cron(new CronOptions { Day = "*", Hour = "*", Minute = "1", Month = "*", Year = "*" }), Description = "Runs demo job fargate task", Targets = new IRuleTarget[] { new EcsTask( new EcsTaskProps { Cluster = cluster, TaskDefinition = demofargateTask2, SubnetSelection = new SubnetSelection { OnePerAz = true } }) } }); //var ecsTask1 = new Task(this, "ecsTask1", new TaskProps //{ // InputPath = "$", // Task = new CustomTask(new RunEcsFargateTaskProps // { // Cluster = Cluster.FromClusterAttributes(this, "PublicCluster", new ClusterAttributes // { // ClusterName = "OHC-PACES", // Vpc = publicVpc, // SecurityGroups = new[] { SecurityGroup.FromSecurityGroupId(this, "SecurityGroup", "sg-0a1bab8166d8fb715") } // }), // TaskDefinition = fargateTask1, // ContainerOverrides = new[] // { // new ContainerOverride // { // ContainerDefinition = container, // Command = new []{"$.Data"} // }, // } // }) //}); var ecsTask1 = new Task(this, "EcsTask1", new TaskProps { InputPath = "$", Task = new RunEcsFargateTask(new RunEcsFargateTaskProps { Cluster = cluster, TaskDefinition = demofargateTask1, //ContainerOverrides = new[] //{ // new ContainerOverride // { // ContainerDefinition = container, // // }, //} }), Parameters = new Dictionary <string, object> { ["Overrides"] = new Dictionary <string, object> { ["ContainerOverrides"] = new Dictionary <string, string>[] { new Dictionary <string, string> { ["Name"] = "app", ["Command.$"] = "$.ECSPayload" } } } } }); var chain2 = Chain.Start(processA).Next(ecsTask1); var stateMachineWithTask = new StateMachine(this, "JobDemoStateMachine-1", new StateMachineProps { StateMachineName = "JobDemoStateMachine-1", Timeout = Duration.Minutes(15), Definition = chain2, Role = Role.FromRoleArn(this, "StateMachineWithTaskRole", "arn:aws:iam::342600918501:role/service-role/PacesEdi274DefaultStateMachineRole") }); //All Policies // 1. Invoke function policies invokeOddEvenStepFunction.Role?.AddManagedPolicy(ManagedPolicy.FromManagedPolicyArn(this, "InvokeLambdaPolicy", "arn:aws:iam::aws:policy/AWSLambdaFullAccess")); var policyStatement = new PolicyStatement { Sid = "CanInvokeStepFunctions", Effect = Effect.ALLOW }; policyStatement.AddActions(new[] { "states:StartExecution" }); invokeOddEvenStepFunction.AddToRolePolicy(policyStatement); policyStatement.AddResources(stateMachine.StateMachineArn); invokeOddEvenStepFunction.AddEnvironment(Functions.StateMachineArnKey, stateMachine.StateMachineArn); process12Function.AddEnvironment(Functions.StepFunctionDemoBucketKey, stepFunctionDemoBucket.BucketName); stepFunctionDemoBucket.GrantReadWrite(process12Function); var policyStatementDemofargateTask2 = new PolicyStatement { Sid = "CanNotifyStepFunction", Effect = Effect.ALLOW }; policyStatementDemofargateTask2.AddActions(new[] { "states:SendTask*" }); demofargateTask2.AddToExecutionRolePolicy(policyStatementDemofargateTask2); demofargateTask2.AddToTaskRolePolicy(policyStatementDemofargateTask2); policyStatementDemofargateTask2.AddAllResources(); }