Skip to content

Commit

Permalink
feat: Add notification example using Telegram
Browse files Browse the repository at this point in the history
Closes: #583
Signed-off-by: William Lam <wlam@vmware.com>
  • Loading branch information
William Lam committed Sep 14, 2021
1 parent 34df8e1 commit 86a059f
Show file tree
Hide file tree
Showing 11 changed files with 442 additions and 2 deletions.
12 changes: 10 additions & 2 deletions docs/site/examples-knative.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,16 @@ examples:
links:
- language: powershell
url: "/tree/master/examples/knative/powershell/kn-ps-slack-vsphere-alarm"
- title: Email Notification

- title: Telegram Notification
usecases:
- item: automation
- item: integration
- item: notification
id: kn-pcli-telegram-function
description: Function to send a Telegram notification triggered by a vMotion of VM.
links:
- language: powercli
url: "/tree/master/examples/knative/powercli/kn-pcli-telegram"
---

A complete and updated list of ready to use functions curated by the VMware Event Broker community is listed below.
Expand Down
5 changes: 5 additions & 0 deletions examples/knative/powercli/kn-pcli-telegram/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM projects.registry.vmware.com/veba/ce-pcli-base:1.3

COPY handler.ps1 handler.ps1

CMD ["pwsh","./server.ps1"]
149 changes: 149 additions & 0 deletions examples/knative/powercli/kn-pcli-telegram/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# kn-pcli-telegram
Example Knative PowerCLI function for sending a [Telegram](https://telegram.org/) message when a VM is migrated and optionally filter by its location in a vSphere Resource Pool.

![](screenshots/screenshots-01.png)

# Step 1 - Build


Create the container image locally to test your function logic.

```
export TAG=<version>
docker build -t <docker-username>/kn-pcli-telegram:${TAG} .
```

# Step 2 - Test

Verify the container image works by executing it locally.

Change into the `test` directory
```console
cd test
```

Update the following variable names within the `docker-test-env-variable` file

* TELEGRAM_BOT_API_KEY - Telegram Bot API key
* TELEGRAM_GROUP_CHAT_ID - Telegram Group Chat ID
* VCENTER_RESOURCE_POOL_FILTER - Name of vSphere Resource Pool to filter for and only send Telegram if migrated VM is located in RP
* VCENTER_SERVER - IP Address or FQDN of the vCenter Server to connect to check for parent vSphere Resource Pool
* VCENTER_USERNAME - vCenter account with permission to check for parent vSphere Resource Pool
* VCENTER_PASSWORD - vCenter credentials to account with permission to check for parent vSphere Resource Pool
* VCENTER_CERTIFCATE_ACTION - Set-PowerCLIConfiguration Action to configure when connection fails due to certificate error, default is Fail. (Possible values: Fail, Ignore or Warn)

Start the container image by running the following command:

```console
docker run -e FUNCTION_DEBUG=true -e PORT=8080 --env-file docker-test-env-variable -it --rm -p 8080:8080 <docker-username>/kn-pcli-telegram:${TAG}
```

In a separate terminal, run either `send-cloudevent-test.ps1` (PowerShell Script) or `send-cloudevent-test.sh` (Bash Script) to simulate a CloudEvent payload being sent to the local container image

```console
Testing Function ...
See docker container console for output

# Output from docker container console
08/11/2021 14:45:44 - PowerShell HTTP server start listening on 'http://*:8080/'
08/11/2021 14:45:44 - Processing Init

08/11/2021 14:45:44 - Configuring PowerCLI Configuration Settings

08/11/2021 14:45:45 - Connecting to vCenter Server vcsa.primp-industries.local

08/11/2021 14:46:15 - Successfully connected to vcsa.primp-industries.local

08/11/2021 14:46:15 - Init Processing Completed

08/11/2021 14:47:33 - DEBUG: K8s Secrets:
{"TELEGRAM_BOT_API_KEY": "XXXXXX","TELEGRAM_GROUP_CHAT_ID": "XXXXXX","VCENTER_RESOURCE_POOL_FILTER": "Customer-A","VCENTER_SERVER": "vcsa.primp-industries.local","VCENTER_USERNAME" : "administrator@vsphere.local","VCENTER_PASSWORD" : "XXXXXX","VCENTER_CERTIFICATE_ACTION" : "Ignore"}

08/11/2021 14:47:33 - DEBUG: CloudEventData

Name Value
---- -----
FullFormattedMessage Virtual machine TestVM-01 was migrated from host 192.168.30.101, vsanDatastore in …
Dvs
Net
UserName VSPHERE.LOCAL\Administrator
Datacenter {Name, Datacenter}
CreatedTime 08/10/2021 18:20:24
ChainId 5636613
SourceHost {Name, Host}
SourceDatacenter {Name, Datacenter}
ComputeResource {Name, ComputeResource}
Ds {Name, Datastore}
Template False
SourceDatastore {Name, Datastore}
Key 5636626
ChangeTag
Vm {Name, Vm}
Host {Name, Host}



08/11/2021 14:47:33 - Creating VM MoReF
08/11/2021 14:47:33 - Retreiving parent Resource Pool
08/11/2021 14:47:33 - Sending message to Telegram ...
08/11/2021 14:47:33 - DEBUG: Telegram URL:
https://api.telegram.org/botXXXXXX/sendMessage

08/11/2021 14:47:33 - DEBUG: Telegram Message:
TestVM-01 has been successfully migrated at 08/10/2021 18:20:24

08/11/2021 14:47:34 - Successfully sent Telegram message ...
```

# Step 3 - Deploy

> **Note:** The following steps assume a working Knative environment using the
`default` Rabbit `broker`. The Knative `service` and `trigger` will be installed in the
`vmware-functions` Kubernetes namespace, assuming that the `broker` is also available there.

Push your container image to an accessible registry such as Docker once you're done developing and testing your function logic.

```console
docker push <docker-username>/kn-pcli-telegram:${TAG}
```

Update the `telegram_secret.json` file with the required Telegram and vCenter Server configurations and then create the kubernetes secret which can then be accessed from within the function by using the environment variable named called `TELEGRAM_SECRET`.

```console
# create secret

kubectl -n vmware-functions create secret generic telegram-secret --from-file=TELEGRAM_SECRET=telegram_secret.json

# update label for secret to show up in VEBA UI
kubectl -n vmware-functions label secret telegram-secret app=veba-ui
```

Edit the `function.yaml` file with the name of the container image from Step 1 if you made any changes. If not, the default VMware container image will suffice. By default, the function deployment will filter on the `VmMigratedEvent` vCenter Server Event. If you wish to change this, update the `subject` field within `function.yaml` to the desired event type.


Deploy the function to the VMware Event Broker Appliance (VEBA).

```console
# deploy function

kubectl -n vmware-functions apply -f function.yaml
```

For testing purposes, the `function.yaml` contains the following annotations, which will ensure the Knative Service Pod will always run **exactly** one instance for debugging purposes. Functions deployed through through the VMware Event Broker Appliance UI defaults to scale to 0, which means the pods will only run when it is triggered by an vCenter Event.

```yaml
annotations:
autoscaling.knative.dev/maxScale: "1"
autoscaling.knative.dev/minScale: "1"
```
# Step 4 - Undeploy
```console
# undeploy function

kubectl -n vmware-functions delete -f function.yaml

# delete secret
kubectl -n vmware-functions delete secret telegram-secret
```
38 changes: 38 additions & 0 deletions examples/knative/powercli/kn-pcli-telegram/function.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: kn-pcli-telegram
labels:
app: veba-ui
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/maxScale: "1"
autoscaling.knative.dev/minScale: "1"
spec:
containers:
- image: projects.registry.vmware.com/veba/kn-pcli-telegram:1.0
envFrom:
- secretRef:
name: telegram-secret
env:
- name: FUNCTION_DEBUG
value: "false"
---
apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
name: veba-pcli-telegram-trigger
labels:
app: veba-ui
spec:
broker: default
filter:
attributes:
subject: VmMigratedEvent
subscriber:
ref:
apiVersion: serving.knative.dev/v1
kind: Service
name: kn-pcli-telegram
134 changes: 134 additions & 0 deletions examples/knative/powercli/kn-pcli-telegram/handler.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
Function Process-Init {
[CmdletBinding()]
param()
Write-Host "$(Get-Date) - Processing Init`n"

try {
$jsonSecrets = ${env:TELEGRAM_SECRET} | ConvertFrom-Json
} catch {
throw "`nK8s secrets `$env:TELEGRAM_SECRET does not look to be defined"
}

# Extract all telegram secrets for ease of use in function
$VCENTER_SERVER = ${jsonSecrets}.VCENTER_SERVER
$VCENTER_USERNAME = ${jsonSecrets}.VCENTER_USERNAME
$VCENTER_PASSWORD = ${jsonSecrets}.VCENTER_PASSWORD
$VCENTER_CERTIFICATE_ACTION = ${jsonSecrets}.VCENTER_CERTIFICATE_ACTION

# Configure TLS 1.2/1.3 support as this is required for latest vSphere release
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls13

Write-Host "$(Get-Date) - Configuring PowerCLI Configuration Settings`n"
Set-PowerCLIConfiguration -InvalidCertificateAction:${VCENTER_CERTIFICATE_ACTION} -ParticipateInCeip:$true -Confirm:$false

Write-Host "$(Get-Date) - Connecting to vCenter Server $VCENTER_SERVER`n"

try {
Connect-VIServer -Server $VCENTER_SERVER -User $VCENTER_USERNAME -Password $VCENTER_PASSWORD
} catch {
Write-Error "$(Get-Date) - Failed to connect to vCenter Server"
throw $_
}

Write-Host "$(Get-Date) - Successfully connected to $VCENTER_SERVER`n"

Write-Host "$(Get-Date) - Init Processing Completed`n"
}

Function Process-Shutdown {
[CmdletBinding()]
param()
Write-Host "$(Get-Date) - Processing Shutdown`n"

Write-Host "$(Get-Date) - Disconnecting from vCenter Server`n"

try {
Disconnect-VIServer * -Confirm:$false
} catch {
Write-Error "$(Get-Date) - Failed to Disconnect from vCenter Server"
}

Write-Host "$(Get-Date) - Shutdown Processing Completed`n"
}

Function Process-Handler {
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=$true)][CloudNative.CloudEvents.CloudEvent]$CloudEvent
)

# Decode CloudEvent
try {
$cloudEventData = $cloudEvent | Read-CloudEventJsonData -Depth 10
} catch {
throw "`nPayload must be JSON encoded"
}

try {
$jsonSecrets = ${env:TELEGRAM_SECRET} | ConvertFrom-Json
} catch {
throw "`nK8s secrets `$env:TELEGRAM_SECRET does not look to be defined"
}

if(${env:FUNCTION_DEBUG} -eq "true") {
Write-Host "$(Get-Date) - DEBUG: K8s Secrets:`n${env:TELEGRAM_SECRET}`n"

Write-Host "$(Get-Date) - DEBUG: CloudEventData`n $(${cloudEventData} | Out-String)`n"
}

$sendTelegram = $true

# Ignore ResourcePool filter if not provided
if(${jsonSecrets}.VCENTER_RESOURCE_POOL_FILTER -ne $NULL) {

try {
Write-Host "$(Get-Date) - Creating VM MoReF"

# Construct VM Object given the MoRef ID from CloudEvent
$moRef = New-Object VMware.Vim.ManagedObjectReference
$moRef.Type = "VirtualMachine"
$moRef.Value = ${cloudEventData}.Vm.Vm.Value

$vm = Get-View $moRef
} catch {
throw "`Unable to construct VM Object using MoRef ID: $(${cloudEventData}.Vm.Vm.Value)"
}

# Retrieve the parent ResourcePool and only request the Name property
try {
Write-Host "$(Get-Date) - Retreiving parent Resource Pool"
$rp = Get-View $vm.ResourcePool -Property Name
} catch {
throw "`Unable to retrieve parent Resource Pool"
}

# Check whether RP name matches filter, do not send telegram message if it does not match
if($rp.name -ne ${jsonSecrets}.VCENTER_RESOURCE_POOL_FILTER) {
$sendTelegram = $false
}

}

$telegramMessage = "$(${cloudEventData}.Vm.Name) has been successfully migrated at $(${cloudEventData}.CreatedTime)"

if($sendTelegram) {
Write-Host "$(Get-Date) - Sending message to Telegram ..."
$ProgressPreference = "SilentlyContinue"

$telegramUrl = "https://api.telegram.org/bot$(${jsonSecrets}.TELEGRAM_BOT_API_KEY)/sendMessage"

if(${env:FUNCTION_DEBUG} -eq "true") {
Write-Host "$(Get-Date) - DEBUG: Telegram URL:`n`t${telegramUrl}`n"

Write-Host "$(Get-Date) - DEBUG: Telegram Message:`n`t${telegramMessage}`n"
}

try {
Invoke-WebRequest -Method POST -Uri $telegramUrl -ContentType "application/json;charset=utf-8" -Body (ConvertTo-Json -Compress -InputObject @{chat_id="$(${jsonSecrets}.TELEGRAM_GROUP_CHAT_ID)";text=$telegramMessage})
} catch {
throw "$(Get-Date) - Failed to send SMS: $($_)"
}

Write-Host "$(Get-Date) - Successfully sent Telegram message ..."
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"TELEGRAM_BOT_API_KEY": "FILL-ME-IN",
"TELEGRAM_GROUP_CHAT_ID": "FILL-ME-IN",
"VCENTER_RESOURCE_POOL_FILTER": "FILL-ME-IN-OR-REMOVE-THIS-LINE",
"VCENTER_SERVER": "FILL-ME-IN",
"VCENTER_USERNAME" : "FILL-ME-IN",
"VCENTER_PASSWORD" : "FILL-ME-IN",
"VCENTER_CERTIFICATE_ACTION" : "Fail"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TELEGRAM_SECRET={"TELEGRAM_BOT_API_KEY": "FILL-ME-IN","TELEGRAM_GROUP_CHAT_ID": "FILL-ME-IN","VCENTER_RESOURCE_POOL_FILTER": "FILL-ME-IN-OR-REMOVE-THIS-LINE","VCENTER_SERVER": "FILL-ME-IN","VCENTER_USERNAME" : "FILL-ME-IN","VCENTER_PASSWORD" : "FILL-ME-IN","VCENTER_CERTIFICATE_ACTION" : "Fail"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

$headers = @{
"Content-Type" = "application/json";
"ce-specversion" = "1.0";
"ce-id" = "41289fef-0727-46f7-b1a9-b8145972c734";
"ce-source" = "https://vcenter.local/sdk";
"ce-type" = "com.vmware.event.router/event";
"ce-subject" = "VmMigratedEvent";
}

$body = Get-Content -Raw -Path "./test-payload.json"

Write-Host "Testing Function ..."
Invoke-WebRequest -Uri http://localhost:8080 -Method POST -Headers $headers -Body $body

Write-host "See docker container console for output"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

echo "Testing Function ..."
curl -i -vvv -d@test-payload.json \
-H "Content-Type: application/json" \
-H 'ce-specversion: 1.0' \
-H 'ce-id: 41289fef-0727-46f7-b1a9-b8145972c734' \
-H 'ce-source: https://vcenter.local/sdk' \
-H 'ce-type: com.vmware.event.router/event' \
-H 'ce-subject: VmMigratedEvent' \
-X POST localhost:8080

echo "See docker container console for output"
Loading

0 comments on commit 86a059f

Please sign in to comment.