aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.64k stars 3.91k forks source link

[aws-events] Clarify inputTransformer in docs #11210

Open choweiyuan opened 4 years ago

choweiyuan commented 4 years ago

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html#cfn-events-rule-target-inputtransformer

I want to be able to use L2 Construct for InputTransformer

Use Case

Closest I've found is this https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-events.CfnRule.InputTransformerProperty.html

Ideally I want to be able to use Rule https://docs.aws.amazon.com/cdk/api/latest/docs/aws-events-readme.html with InputTransformer instead of Input

Proposed Solution

Other


This is a :rocket: Feature Request

Eu-g-e-nE commented 3 years ago

Agree, very useful feature. Any ETA?

github-actions[bot] commented 2 years ago

This issue has not received any attention in 1 year. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.

tstibbs commented 2 years ago

I believe this is still a worthwhile feature - the lack of attention over the last year doesn't invalidate the feature request.

TheRealAmazonKendra commented 1 year ago

I'm wondering if I'm missing something here because had already been implemented. We've abstracted away the different types of input (Input vs InputPath vs InputTransformer), but you can provide an InputTransformer through the input field using one of the functions here. Does this just need better documentation?

rix0rrr commented 1 year ago

The example is not very well advertised on this page, but it looks like this:

declare const onCommitRule: events.Rule;
declare const topic: sns.Topic;

onCommitRule.addTarget(new targets.SnsTopic(topic, {
  message: events.RuleTargetInput.fromObject(
    {
      DataType: `custom_${events.EventField.fromPath('$.detail-type')}`
    }
  )
}));
peterwoodworth commented 1 year ago

There may be a cleaner way of implementing this. It appears as if the different targets have different ways of being able to provide an inputTransformer. The example Rico posted wouldn't apply for EcsTask for example, which requires this to be configured within its containerOverrides prop. I'm not sure we can uniformly address this in the docs, and we may want to look into a solution that leads to a more consistent experience when configuring this between different types of targets

jabalsad commented 1 year ago

It's also not clear to me how exactly one would use the built in variables as a template, e.g. <aws.events.event.json>? Or how I would combine that with other cdk functions, e.g.

input: events.RuleTargetInput.fromText(`{"message":<aws.events.event.json>, "condition": ` + cdk.Fn.conditionIf(...) + `}`)
terusaku commented 10 months ago

I met similar issue, and addressed by the following way. I hope this is helpful.

Referece docs

https://github.com/aws/aws-cdk/tree/main/packages/aws-cdk-lib/aws-events https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-transform-target-input.html

Sample code

RuleTargetInput Usecase via SNS Topic for AWS Chatbot. I receive Slack Notification from AWS Chatbot, like this

const rule = new aws_events.Rule(...)
rule.addTarget(
  new aws_events_targets.SnsTopic(snsTopic, {
    message: aws_events.RuleTargetInput.fromObject({
      version: '1.0',
      source: 'custom',
      content: {
        textType: 'client-markdown',
        title: `TITLE_TEXT | ${aws_events.EventField.fromPath(
          '$.account'
        )}:${aws_events.EventField.fromPath(
          '$.region'
        )} | ${aws_events.EventField.fromPath(
          '$.detail.eventName'
        )}`,
        description: `DESCRIPTION_TEXT: ${aws_events.EventField.fromPath(
          '$.detail.eventType'
        )}\n${aws_events.EventField.fromPath(
          '$.detail.reason'
        )}\n${aws_events.EventField.fromPath('$.resources[0]')}`,
      },
    }),
  })
);

Pain point

JelsB commented 5 months ago

I ran into the same issue. But like said here, the feature works perfectly fine, it's just a matter of documentation.

I'm wondering if I'm missing something here because had already been implemented. We've abstracted away the different types of input (Input vs InputPath vs InputTransformer), but you can provide an InputTransformer through the input field using one of the functions here. Does this just need better documentation?

This abstraction is pretty neat actually because it automatically creates the inputPath and inputTemplate for you when you specify the message (or input, event, ... ) in the CDK target object. For each unique EventField.fromPath() that you use, it creates an inputPath key-value pair for you and uses that key in the inputTemplate.

For myself, I've made it clearer by mimicking the input transformer in the code:

import * as events from 'aws-cdk-lib/aws-events'
import * as targets from 'aws-cdk-lib/aws-events-targets'
...

const eventInputMapping = {
  account: events.EventField.account,
  region: events.EventField.region,
  alarmName: events.EventField.fromPath('$.detail.alarmName'),
  description: events.EventField.fromPath('$.detail.configuration.description'),
  startTime: events.EventField.fromPath('$.detail.state.timestamp'),
  state: events.EventField.fromPath('$.detail.state.value'),
  metric: events.EventField.fromPath('$.detail.configuration.metrics[0].metricStat.metric.name'),
  clusterName: events.EventField.fromPath('$.detail.configuration.metrics[0].metricStat.metric.dimensions.ClusterName'),
  serviceName: events.EventField.fromPath('$.detail.configuration.metrics[0].metricStat.metric.dimensions.ServiceName'),
}

const eventInputTemplate = {
  title: `Service ${eventInputMapping.serviceName} went into ${eventInputMapping.state} state for ${eventInputMapping.metric} ${eventInputMapping.description}.`,
  text: `The ECS scaling alarm ${eventInputMapping.alarmName} got triggered at ${eventInputMapping.startTime}` +
  ` This impacts the scaling of ECS service ${eventInputMapping.serviceName} in ECS cluster ${eventInputMapping.clusterName}. `,
  source_type_name: 'amazon ecs',
  tags: [
    `account-id:${eventInputMapping.account}`,
    `region:${eventInputMapping.region}`,
    `servicename:${eventInputMapping.serviceName}`,
    `clustername:${eventInputMapping.clusterName}`,
  ],
}

new events.Rule(this, 'DefaultEcsMetricsScalingAlarms', {
  ...
  targets: [new targets.ApiDestination(eventsDestination, {
    event: events.RuleTargetInput.fromObject(eventInputTemplate)
  }),
  ],
})

This will result in the following inputPath:

{
  "account": "$.account",
  "detail-alarmName": "$.detail.alarmName",
  "detail-configuration-description": "$.detail.configuration.description",
  "detail-configuration-metrics-0--metricStat-metric-dimensions-ClusterName": "$.detail.configuration.metrics[0].metricStat.metric.dimensions.ClusterName",
  "detail-configuration-metrics-0--metricStat-metric-dimensions-ServiceName": "$.detail.configuration.metrics[0].metricStat.metric.dimensions.ServiceName",
  "detail-configuration-metrics-0--metricStat-metric-name": "$.detail.configuration.metrics[0].metricStat.metric.name",
  "detail-state-timestamp": "$.detail.state.timestamp",
  "detail-state-value": "$.detail.state.value",
  "region": "$.region"
}

and inputTemplate

{
    "title": "Service <detail-configuration-metrics-0--metricStat-metric-dimensions-ServiceName> went into <detail-state-value> state for <detail-configuration-metrics-0--metricStat-metric-name> <detail-configuration-description>.",
    "text": "The ECS scaling alarm <detail-alarmName> got triggered at <detail-state-timestamp> This impacts the scaling of ECS service <detail-configuration-metrics-0--metricStat-metric-dimensions-ServiceName> in ECS cluster <detail-configuration-metrics-0--metricStat-metric-dimensions-ClusterName>. ",
    "source_type_name": "amazon ecs",
    "tags": [
        "account-id:<account>",
        "region:<region>",
        "service:<detail-configuration-metrics-0--metricStat-metric-dimensions-ServiceName>",
        "cluster:<detail-configuration-metrics-0--metricStat-metric-dimensions-ClusterName>"
    ]
}
scarperharper commented 2 months ago

The answers above gave me the answer I was after - just thought I'd add a simpler example. My rule:

new events.Rule(stack, 'rule-name', {
  eventBus: existingEventBus,
  eventPattern: {
    source: [`interesting-source`],
  },
  targets: [
    new targets.ApiDestination(destination, {
      event: events.RuleTargetInput.fromObject({
        person: events.EventField.fromPath('$.detail.person'),
      }),
      headerParameters: {
        'x-api-key': 'secret',
      },
      pathParameterValues: ['what', 'ever'],
      deadLetterQueue: deadLetterQueue,
    }),
  ],
});

Transformed this input:

{
  "version": "0",
  "id": "...",
  "detail-type": "...",
  "source": "service",
  "account": "...",
  "time": "2024-08-02T10:28:09Z",
  "region": "eu-west-1",
  "resources": [],
  "detail": {
    "person": {
      "firstName": "first",
      "lastName": "last"
    }
  }
}

.. into ..

{
  "person": {
    "firstName": "first",
    "lastName": "last"
  }
}
nitsujri commented 2 weeks ago

@terusaku thank you for your example, I searched for hours to figure out how to write this thinking that I could some how generate a simple RuleTargetInputProperties.

The most obvious location lacks solid examples of how to build an inputTemplate.

@peterwoodworth @TheRealAmazonKendra not sure who to write this, there doesn't seem to be easily searchable nor examples of how to use a fromObject to get to input, inputPath, inputTemplate. Any reason we can't match the EvenBridge UI since those are distinct text input boxes/areas and take those 3 as inputs as well?