Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Release Notes
=============

## 1.9.29
* Event Grid: Bump API version from `2022-06-15` to `2025-02-15`.
* Event Grid: Add `MonitorAlert` endpoint type for event subscriptions with configurable action groups and severity (Sev0–Sev4).
* Event Grid: Add `event_delivery_schema` keyword to configure the event delivery schema (EventGridSchema, CloudEventSchemaV1_0, CustomInputSchema).

## 1.9.28
* Container Apps: Add `resources` operation to the `container` builder to set both CPU and memory together using a `ConsumptionPlanResources` discriminated union. This ensures only valid consumption plan resource combinations can be selected at compile time. The individual `cpu_cores` and `memory` operations remain available for use with dedicated plans.

Expand Down
59 changes: 52 additions & 7 deletions docs/content/api-overview/resources/event-grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ The Event Grid is a simple but powerful builder that links events from Azure ser
|-|-|
| topic_name | The name of the topic that will be created. |
| source | Optional, defaults to the current resource group. The source of the events. See below for the full list of builder configurations that are supported. |
| event_delivery_schema | Optional. Sets the event delivery schema for all subscriptions on this topic. Valid values: `EventGridSchema` (default), `CloudEventSchemaV1_0`, `CustomInputSchema`. |
| add_queue_subscriber | Adds a new storage queue subscriber. Requires the storage account config that will receive the events, the queue name and the list of events to subscribe to. |
| add_webhook_subscriber| Adds a new webhook (HTTP) subscriber. Requires the web app config that will receive the event, associated URI local path and the list of events to subscribe to. Also contains an overload that takes in a Web App name and the full Uri of the webhook. |
| add_eventhub_subscriber| Adds a new event hub subscriber. Requires the event hub builder config that will receive the events and the list of events to subscribe to. |
| add_function_subscriber| Adds a new Azure Functions subscriber. Requires the function app, the handler name and the list of events to subscribe to. |
| add_monitor_alert_subscriber | Adds a new Azure Monitor Alert subscriber. Requires a list of action groups (either `ActionGroupConfig` list or `ResourceId` list), a severity level (`Sev0`–`Sev4`), and the list of events to subscribe to. |

### Supported Sources
Farmer supports the following Event Grid sources using Farmer builders:
Expand All @@ -36,15 +38,58 @@ Farmer supports the following Event Grid sources using Farmer builders:
| [IotHub](iot-hub) | SystemEvents.IotHub |
| [EventHub](eventhub) | SystemEvents.EventHub |

### Suported Destinations
### Supported Destinations

* EventHub (`add_eventhub_subscriber`),
* StorageQueue (`add_queue_subscriber`),
* WebHook (`add_webhook_subscriber`),
* ServiceBus Queue (`add_servicebus_queue_subscriber`),
* ServiceBus Topic (`add_servicebus_topic_subscriber`).
* EventHub (`add_eventhub_subscriber`)
* StorageQueue (`add_queue_subscriber`)
* WebHook (`add_webhook_subscriber`)
* ServiceBus Queue (`add_servicebus_queue_subscriber`)
* ServiceBus Topic (`add_servicebus_topic_subscriber`)
* Azure Monitor Alert (`add_monitor_alert_subscriber`)

#### Examples

The following sample routes Key Vault secret expiry events to Azure Monitor Alerts using the CloudEvent schema:

```fsharp
open Farmer
open Farmer.Builders
open Farmer.Arm.EventGrid

let myKeyVault = keyVault { name "mykeyvault" }

// Reference an existing action group by resource ID
let actionGroupId =
Arm.ActionGroups.actionGroups.resourceId (ResourceName "myActionGroup")

let kvExpiryGrid = eventGrid {
topic_name "kv-expiry-topic"
source myKeyVault
event_delivery_schema CloudEventSchemaV1_0
add_monitor_alert_subscriber
[ actionGroupId ]
Sev3
[ SystemEvents.KeyVault.SecretNearExpiry
SystemEvents.KeyVault.SecretExpired ]
}
```

Alternatively, reference a Farmer-managed action group directly:

```fsharp
let alertGroup = actionGroup {
name "myActionGroup"
short_name "myAG"
}

let kvExpiryGrid = eventGrid {
topic_name "kv-expiry-topic"
source myKeyVault
event_delivery_schema CloudEventSchemaV1_0
add_monitor_alert_subscriber [ alertGroup ] Sev3 [ SystemEvents.KeyVault.SecretNearExpiry ]
}
```

#### Example
The following sample creates a source storage account that emits events on the event grid topic, whilst two destinations are created: an event hub and a storage queue, each listening for different events.

```fsharp
Expand Down
51 changes: 49 additions & 2 deletions src/Farmer/Arm/EventGrid.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ module Farmer.Arm.EventGrid
open Farmer
open EventGrid

let systemTopics = ResourceType("Microsoft.EventGrid/systemTopics", "2022-06-15")
let systemTopics = ResourceType("Microsoft.EventGrid/systemTopics", "2025-02-15")

let eventSubscriptions =
ResourceType("Microsoft.EventGrid/systemTopics/eventSubscriptions", "2022-06-15")
ResourceType("Microsoft.EventGrid/systemTopics/eventSubscriptions", "2025-02-15")

type TopicType =
| TopicType of ResourceType * topic: string
Expand Down Expand Up @@ -54,6 +54,37 @@ type AzureFunctionEndpointType = {
PreferredBatchSizeInKilobytes: uint
}

type MonitorAlertSeverity =
| Sev0
| Sev1
| Sev2
| Sev3
| Sev4

member this.ArmValue =
match this with
| Sev0 -> "Sev0"
| Sev1 -> "Sev1"
| Sev2 -> "Sev2"
| Sev3 -> "Sev3"
| Sev4 -> "Sev4"

type MonitorAlertEndpointType = {
ActionGroups: ResourceId list
Severity: MonitorAlertSeverity
}

type EventDeliverySchema =
| EventGridSchema
| CloudEventSchemaV1_0
| CustomInputSchema

member this.ArmValue =
match this with
| EventGridSchema -> "EventGridSchema"
| CloudEventSchemaV1_0 -> "CloudEventSchemaV1_0"
| CustomInputSchema -> "CustomInputSchema"

type ServiceBusEndpointType =
| Queue of Queue: ServiceBusQueueEndpointType
| Topic of Topic: ServiceBusTopicEndpointType
Expand All @@ -64,6 +95,7 @@ type EndpointType =
| StorageQueue of queue: ResourceName
| ServiceBus of bus: ServiceBusEndpointType
| AzureFunction of AzureFunctionEndpointType
| MonitorAlert of MonitorAlertEndpointType

type Topic = {
Name: ResourceName
Expand Down Expand Up @@ -96,6 +128,7 @@ type Subscription<'T> = {
Destination: ResourceName
DestinationEndpoint: EndpointType
Events: EventGridEvent<'T> list
EventDeliverySchema: EventDeliverySchema option
} with

interface IArmResource with
Expand All @@ -114,6 +147,7 @@ type Subscription<'T> = {
| WebHook _ -> None
| ServiceBus(Queue { Queue = queue; Bus = bus }) -> Some(ServiceBus.queues.resourceId (bus, queue))
| ServiceBus(Topic { Topic = topic; Bus = bus }) -> Some(ServiceBus.topics.resourceId (bus, topic))
| MonitorAlert _ -> None

{|
eventSubscriptions.Create(
Expand Down Expand Up @@ -169,11 +203,24 @@ type Subscription<'T> = {
queueName = topic.Value
|}
|}
| MonitorAlert alert ->
{|
endpointType = "MonitorAlert"
properties = {|
actionGroups = [
for ag in alert.ActionGroups do
ag.Eval()
]
severity = alert.Severity.ArmValue
|}
|}
|> box
filter = {|
includedEventTypes = [
for event in this.Events do
event.Value
]
|}
eventDeliverySchema = this.EventDeliverySchema |> Option.map _.ArmValue |> Option.toObj
|}
|}
48 changes: 48 additions & 0 deletions src/Farmer/Builders/Builders.EventGrid.fs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ type EventGridConfig<'T> = {
Endpoint: EndpointType
SystemEvents: EventGridEvent<'T> list
|} list
EventDeliverySchema: EventDeliverySchema option
Tags: Map<string, string>
} with

Expand All @@ -213,6 +214,7 @@ type EventGridConfig<'T> = {
Destination = sub.Destination
DestinationEndpoint = sub.Endpoint
Events = sub.SystemEvents
EventDeliverySchema = this.EventDeliverySchema
}
]

Expand All @@ -221,6 +223,7 @@ type EventGridBuilder() =
TopicName = state.TopicName
Source = source, topic
Subscriptions = []
EventDeliverySchema = None
Tags = Map.empty
}

Expand All @@ -243,6 +246,7 @@ type EventGridBuilder() =
TopicName = ResourceName.Empty
Source = ResourceName("[resourceGroup().name]"), Topics.ResourceGroup
Subscriptions = []
EventDeliverySchema = None
Tags = Map.empty
}

Expand Down Expand Up @@ -373,6 +377,50 @@ type EventGridBuilder() =
let name = sprintf $"%s{bus.Name.Value}-servicebus-topic"
EventGridBuilder.AddSub(state, name, topic.Name, endpoint, events)

[<CustomOperation "event_delivery_schema">]
member _.EventDeliverySchema(state: EventGridConfig<'T>, schema: EventDeliverySchema) = {
state with
EventDeliverySchema = Some schema
}

[<CustomOperation "add_monitor_alert_subscriber">]
member _.AddMonitorAlertSubscription
(
state: EventGridConfig<'T>,
actionGroups: ActionGroupConfig list,
severity: MonitorAlertSeverity,
events: EventGridEvent<_> list
) =
let ids =
actionGroups
|> List.map (fun ag -> Arm.ActionGroups.actionGroups.resourceId ag.Name)

let endpoint =
MonitorAlert {
ActionGroups = ids
Severity = severity
}

let destination = actionGroups |> List.head |> (fun ag -> ag.Name)
EventGridBuilder.AddSub(state, destination.Value + "-monitor-alert", destination, endpoint, events)

[<CustomOperation "add_monitor_alert_subscriber">]
member _.AddMonitorAlertSubscription
(
state: EventGridConfig<'T>,
actionGroupIds: ResourceId list,
severity: MonitorAlertSeverity,
events: EventGridEvent<_> list
) =
let endpoint =
MonitorAlert {
ActionGroups = actionGroupIds
Severity = severity
}

let destination = actionGroupIds |> List.head |> (fun id -> id.Name)
EventGridBuilder.AddSub(state, destination.Value + "-monitor-alert", destination, endpoint, events)

[<CustomOperation "add_tags">]
member _.Tags(state: EventGridConfig<'T>, pairs) = {
state with
Expand Down
Loading