From Teams integration with AWS lambda + Postgres & Tulip – Michael Ellerbeck
Microsoft teams has a pretty nifty way of opening access to posting messages. This can be configured like this
After generating a webhook url, let’s store it in SSM since it is credentials for writing to a channel. For this first go ahead I’m going to store it as json with multiple key pairs, it might be better to store them separately, but this will work for now.
The general look is
{"team_test1": "https://sample.webhook.office.com/webhookb2/blahblah","team_test2": "https://sample.webhook.office.com/webhookb2/blahblah"}
Let’s call the paramater
/dev/teamsintegration/channels
Next, creating the lambda
So it grabs the possible channels from SSM and loads into key pairs for use later (the channel_name paramater)
import
sys
import
logging
import
os
import
json
import
urllib3
import
boto3
logger
=
logging.getLogger()
logger.setLevel(logging.DEBUG)
runtime_region
=
os.environ[
'AWS_REGION'
]
http
=
urllib3.PoolManager()
session
=
boto3.Session(region_name
=
runtime_region)
ssm
=
session.client(
'ssm'
)
channels
=
ssm.get_parameter(Name
=
'/dev/teamsintegration/channels'
, WithDecryption
=
True
)[
'Parameter'
][
'Value'
]
channels
=
json.loads(channels)
def
send_teams(webhook_url:
str
, content:
str
, title:
str
, color:
str
=
"000000"
)
-
>
int
:
msg
=
{
"@context"
:
"https://schema.org/extensions"
,
"@type"
:
"MessageCard"
,
"themeColor"
: color,
"title"
: title,
"text"
: content
}
encoded_msg
=
json.dumps(msg).encode(
'utf-8'
)
http.request(
'POST'
, webhook_url, body
=
encoded_msg)
def
lambda_handler(event, context):
content
=
event[
"content"
]
title
=
event[
"title"
]
color
=
event[
"color"
]
channel_name
=
event[
"channel_name"
]
webhook_url
=
channels[channel_name]
try
:
print
(event)
send_teams(webhook_url, content, title,color)
return
{
'statusCode'
:
200
,
'body'
: json.dumps(title)
}
except
Exception as error:
raise
In order for the lambda to access the SSM parameter create a quick inline policy
{
"Statement": [
{
"Action": "ssm:DescribeParameters",
"Effect": "Allow",
"Resource": "*",
"Sid": "VisualEditor0"
},
{
"Action": "ssm:GetParameter",
"Effect": "Allow",
"Resource": "arn:aws:ssm:us-east-1:accountid:parameter/dev/teamsintegration/channels",
"Sid": "VisualEditor1"
}
],
"Version": "2012-10-17"
}
Ok, lets test this function out. Configure a test event like this
{
"content": "some content",
"title": "a title that is really cool",
"color": "ff0400",
"channel_name1": "team_test1"
}
Assuming that all worked you should get
To use this from Tulip my favorite method is My new favorite way to trigger lambdas from Tulip – Michael Ellerbeck
Grant your rds-lambda-role permission to execute the lambda.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "lambda:InvokeFunction",
"Effect": "Allow",
"Resource": "arn:aws:lambda:us-east-1:943667677541:function:your-function-name-here",
"Sid": "VisualEditor2"
}
]
}
Wrap it in a postgres function
CREATE
OR
REPLACE
FUNCTION
public
.send_teams_msg(content text, title text, color text, channel_name text)
RETURNS
integer
LANGUAGE plpgsql
AS
$
function
$
declare
rows_affected
int
;
create_json TEXT;
response TEXT;
err_context text;
begin
RAISE INFO
'Started'
;
-- Create Json
select
into
create_json row_to_json(t)
from
(
select
content,
title,
color,
channel_name
) t;
SELECT
into
response payload
FROM
aws_lambda.invoke(aws_commons.create_lambda_function_arn(
'your-function-name-here'
,
'us-east-1'
),
create_json::json,
'RequestResponse'
);
RAISE INFO
'response:%'
,response;
-- parse the response
select
into
response response::json->
'response'
;
-- remove qutoes
select
into
response
replace
(response,
'"'
,
''
);
if response =
'sent'
then
return
1;
else
return
0;
END
IF;
end
;
$
function
$
;
Call it like this
1 select public.send_teams_msg('some content','the title', 'ff0400','team_test1')
Then create a connector function
Then of course you can use it in an app like this
Of course, no solution is really complete until automated so let’s Terraform this up.
So this is a somewhat incomplete .tf