How to prettify Oracle Cloud Infrastructure notifications with Microsoft Power Automate?

Oracle Notification Subscription is a powerful cloud-native tool to export your Oracle Topics outside the OCI console. It allows you to deliver live Oracle topics notifications in your emails, Slack channels, or even custom HTTP webhooks in a matter of clicks or terraform resources.

However, once you start setting up an Oracle Notification Subscription into Slack, for example, you might face some unexpected difficulties, as shown in Figure 1 below (or maybe a prettified JSON with line breaks). This is because, unfortunately, the Slack notifications cannot be easily customized and are very often confusing for users.

In this post, I will show you how can you turn Slack Oracle Notification Subscriptions with a raw JSON sent in a Slack channel (Figure 1) into a well-formatted Slack message with Microsoft Power Automate (Figure 2).

Figure 1: A raw OCI slack notification

Figure 2: The same notification after being formatted by a PowerAutomate flow

On this journey, you will need to bypass 2 constraints of the Oracle Cloud console:

  1. Subscriptions Custom HTTPs URLs do not support URL parameters. If you have front-end dev reflexes, you might try to encode the URL in ASCII. But unfortunately, that won’t help either. This first constraint doesn’t go along well with webhook services that do require URL parameters, like Microsoft Power Automate - but is not impossible!

  2. Custom URL subscriptions need confirmation: when you first declare an HTTPS Custom URL subscription, the OCI console will require you to confirm the subscription by sending an HTTP GET request to an URL sent to your custom URL. This constraint does not go well with terraforming your compartments and especially the URL confirmation part: even if you can easily terraform topics and subscriptions (Figure 3), you still need to confirm the Custom HTTP URL.

Figure 3: Topic subscription confirmation

How to subscribe an Oracle Topic to a Microsoft Power Automate webhook?

First, let’s create a blank Power Automate flow and add an “HTTP Request” trigger like below (Figure 4):

Figure 4: Power Automate flow HTTP request listener

After creating an HTTP request listener in your Power Automate flow, your webhook will look like this:

https://prod-xxx.westeurope.logic.azure.com/workflows/xxxxxxxxxxxxxxxx/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=v5Exxxxxxxxxxxxxxxxxxxx

This webhook has 4 static URL parameters (api-version, sp, sv and sig) that are required. Without them, the Power Automate will reject your HTTP calls. Therefore, the subscription of this URL to an OCI topic will fail (since OCI is not compatible with URI parameters).

One way to bypass this is to have an Oracle API Gateway endpoint setup:

  • The Notification subscription will be configured with the API Gateway endpoint and will therefore send the notification payload to the API Gateway.

  • The API Gateway endpoint will serve as a reverse proxy and will transfer the Oracle Notification payload to the Power Automate flow.

  • The 4 static URL parameters will be appended by the API Gateway before making the call to Power Automate.

Now you might ask yourself: “What does the API Gateway configuration look like?”

Here step-by-step guide:

First, create a gateway as in Figure 5:

Figure 5: API Gateway creation

Then create a deployment, choose a name and set the path to “/” (Figure 6):

Figure 6: API Gateway deployment creation

Then configure a route (Figure 7) :

Path should be ”/”

Methods: POST

Type: HTTP

URL: the webhook url without the URL parameters

Figure 7: API Gateway Deployment Route configuration

Then you will need to hit “Hide Route Request Policies” and append the 4 static URL parameters to “Query Parameter Transformations” (Figure 8):

Note: for the “sp” parameter, make sure that the value is not ASCII encoded and is plain text like in the screen capture: “/triggers/manual/run” for instance.

Figure 8: API Gateway Deployment Route additional parameters configuration

Note:

  • If you go for a private API Gateway, make sure to have a NAT or Internet Gateway that will allow the API Gateway to reach the Power Automate endpoint

  • You will need to adjust the API Gateway subnet to include “Oracle Services” ingress on port 443.

And “Voilà” , you can now try out the Oracle API Gateway URL with postman for instance: just send a POST request to the Power Automate HTTP Request listener (Figure 9).

Depending on what you chose to send, you should get a nice HTTP 202 or a sign that Power Automate received and understood your request. If you get a timeout, double-check your Oracle NSG/Security List.

Figure 9: Postman test of the API Gateway

Validate Topic Subscription with Power Automate

Now we need to tackle the first issue: create a subscription that you don’t need to validate by hand.

You can handle this directly in Power Automate.

The doc states that the validation URL is sent to your http endpoint with a specific HTTP Header: X-OCI-NS-ConfirmationURL. The value is this header is the confirmation URL. You can also find the confirmation URL in the body:

{
"ConfirmationURL":"<exampleConfirmationURL>"
}

We can rely on the fact that only the confirmation call will contain the X-OCI-NS-ConfirmationURL header in order to treat it differently with a “Control Condition” in PowerAutomate. Check out Figure 10 for details about how to catch this call.

Figure 10: Treating confirmation with a control condition sending this call to a dedicated branch of the flow

Treating OCI alerts

Now you are almost there: the branch that is not treating subscription confirmations, will enable you to treat the OCI alerts.

As shown in Figure 11, you will need to do 2 things:

  1. First, you will need to parse the JSON body.

The schema will look like this:

{
    "type": "object",
     "properties": {
        "dedupeKey": {
           "type": "string"
        },
        "title": {
           "type": "string"
        },
        "body": {
            "type": "string"
        },
        "type": 
            "type": "string"
        },
        "severity": {
            "type": "string"
        },
        "timestampEpochMillis": {
             "type": "integer"
        },
        "timestamp": {
            "type": "string"
        },
        "alarmMetaData": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "status": {
                       "type": "string"
                    },
                    "severity": {
                        "type": "string"
                    },
                    "namespace": {
                        "type": "string"
                    },
                    "query": {
                        "type": "string"
                    },
                    "totalMetricsFiring": {
                        "type": "integer"
                    },
                    "dimensions": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "lbHostId": {
                                    "type": "string"
                                },
                                "backendSetName": {
                                    "type": "string"
                                },
                                "resourceId": {
                                    "type": "string"
                                },
                                "availabilityDomain": {
                                    "type": "string"
                                },
                                "region": {
                                    "type": "string"
                                },
                                "lbComponent": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                },
                "required": [
                    "id",
                    "status",
                    "severity",
                    "namespace",
                    "query",
                    "totalMetricsFiring",
                   "dimensions"
                ]
            }
        },
        "version": {
          "type": "number"
        }
    }
}

Figure 11: Reading OCI alerts and sending them to slack

2. Send a customized message to Slack.

You will need to create an OCI Notification slack app: https://api.slack.com/messaging/webhooks

From there, get your webhook URL that you can use like on the images above and below to send messages to Slack.

Figure 12: Example of Slack message

Final words

And that’s it, you now have clean OCI notifications in Slack.

In this post, we went together through how to get it done manually in the OCI console. However, you can easily scale this to all your tenancies or compartments with terraforming: once the setting is done in a compartment, you can export the terraform stack for the OCI console and deploy it elsewhere.

 

How do you prettify your OCI notifications? Is it with Power Automate or with some other solution? Let us know in the comments below!

 

Author: Alexandre Gillet, Cloud Operation Manager @ Discngine