AWS Lambda Function Issue with Slack Webhook - python-3.x

I'm using the AWS lambda function to send alerts to our slack channel. But, due to some unknown issue, I'm not getting slack alert and not even getting any kind of error message from the AWS lambda function. Logs represent that the function ran successfully without any error but I do not receipt any alert
code:
import json, sys, csv, os
import requests
def lambda_handler(event, context):
def Send2Slack(message):
if __name__ == '__main__':
print('inside slack function')
url = "webhook_URL"
title = (f"New Incoming Message")
slack_data = {
"username": "abc",
"channel" : "xyz",
"attachments": [
{
"color": "#ECB22E",
"fields": [
{
"title": title,
"value": message,
"short": "false",
}
]
}
]
}
byte_length = str(sys.getsizeof(slack_data))
headers = {'Content-Type': "application/json", 'Content-Length': byte_length}
response = requests.post(url, data=json.dumps(slack_data), headers=headers)
if response.status_code != 200:
raise Exception(response.status_code, response.text)
output = "Hello Slack "
Send2Slack(output)
Please let me know where I'm doing wrong and help me fix this issue.

I'm able to answer this issue.
def Send2Slack(message):
if __name__ == '__main__':
Once I removed if __name__ == '__main__': from send2slack function the it worked.
Otherwise, I was not able to get into the function.
Thanks for all your help.

Related

How to write pytest for Websocket Client endpoint

I used WebsocketApp to create a python Websocket client(synch) which interacts with Websocket server.
Now, I am interested in integrating the Websocket client in end to end test.
I tried to write a Pytest for Websocket client, but because I am a beginner with Pytest, so I blocked and I do not know how should I continue it.
this is my code:
import json
import websocket
no_message = 0
count = 1
def on_error(ws, error):
print(error)
def on_close(ws, close_status_code, close_msg):
print("############## closed ###############")
def on_message(ws, message):
try:
if message is not None:
print("RESPONSE FROM SERVER.......", message)
global no_message
no_message += 1
if no_message >= count:
ws.close()
if message is None:
ws.close()
except:
print("error")
ws.on_error()
def on_open(ws):
global count
message = {
"session_id": "String",
"destination": "127.0.0.1",
"count": count,
"command": "LIVE_PING",
}
count = message.get("count")
ws.send(json.dumps(message))
if __name__ == "__main__":
websocket.enableTrace(True)
host = "ws://127.0.0.1:8000/"
ws = websocket.WebSocketApp(
host,
on_open=on_open,
on_message=on_message,
on_error=on_error,
on_close=on_close,
)
ws.run_forever()
and this my pytest for:
import json
import unittest.mock as mock
import websocket
class Testws():
def test_on_close(self):
print("Close")
def test_on_error(self):
print('ERROR')
def test_on_message(self, message):
assert message == 'RESPONSE FROM SERVER....... {"session_id":"String","sample":0,"elapsed":15}'
def test_on_open(self, ws):
fake_message = {
"session_id": "String",
"destination": "127.0.0.1",
"count": 2,
"command": "LIVE_PING",
}
ws.send(json.dumps(fake_message))
c = Testws()
host = "ws://127.0.0.1:8000/"
ws = websocket.WebSocketApp(host, on_open=c.test_on_open, on_message=c.test_on_message, )
ws.run_forever()
I tried also using Monkeypatching, but I am confused and do not think it is the right way
import json
import websocket
from wsClient import synch_ws_client as cl
from websocket import WebSocketApp
def test_synch_ws_client(monkeypatch):
def mock_on_message():
print('RESPONSE FROM SERVER....... {"session_id":"String","sample":0,"elapsed":2}')
def mock_on_error():
print('Error')
def mock_on_close():
print('############## closed ###############')
def mock_on_open(ws):
fake_massage = {
"session_id": "String",
"destination": "127.0.0.1",
"count": 1,
"command": "LIVE_PING"
}
ws.send(json.dumps(fake_massage))
monkeypatch.setattr(WebSocketApp, 'on_message', mock_on_message)
monkeypatch.setattr(WebSocketApp, 'on_close', mock_on_close)
monkeypatch.setattr(WebSocketApp, 'on_error', mock_on_error)
monkeypatch.setattr(WebSocketApp, 'on_open', mock_on_open)
assert cl.on_message() == 'RESPONSE FROM SERVER....... {"session_id":"String","sample":0,"elapsed":2}'
I do not know, how can I check for example the test_on_open and test_on_message modules are call successfully.

How to delete a node taint using Python's Kubernetes library

Set the stain like this:
v3.patch_node('nodename',
{"spec": {"taints": [{"effect": "NoSchedule", "key": "test", "value": "1",'tolerationSeconds': '300'}]}}```
however.
How to remove tains?
This was pretty non-intuitive to me, but here's how I accomplished this.
def taint_node(context, node_name):
kube_client = setup_kube_client(context)
taint_patch = {"spec": {"taints": [{"effect": "NoSchedule", "key": "test", "value": "True"}]}}
return kube_client.patch_node(node_name, taint_patch)
def untaint_node(context, node_name):
kube_client = setup_kube_client(context)
remove_taint_patch = {"spec": {"taints": []}}
return kube_client.patch_node(node_name, remove_taint_patch)
That worked for me, but it removes ALL taints, which is maybe not what you want to do.
I tried the following:
def untaint_node(context, node_name):
kube_client = setup_kube_client(context)
remove_taint_patch = {"spec": {"taints": [{"effect": "NoSchedule-", "key": "test", "value": "True"}]}}
return kube_client.patch_node(node_name, remove_taint_patch)
but encountered server side validation preventing it (because the effect isn't in the collection of supported values):
kubernetes.client.exceptions.ApiException: (422)
Reason: Unprocessable Entity
HTTP response headers: HTTPHeaderDict({'Audit-Id': 'bfbad6e1-f37c-4090-898b-b2b9c5500425', 'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'X-Kubernetes-Pf-Flowschema-Uid': '7c028f53-f0a4-46bd-b400-68641158da78', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'ef92e801-ce03-4abb-a607-20921bf82547', 'Date': 'Sat, 18 Sep 2021 02:45:37 GMT', 'Content-Length': '759'})
HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Node \"aks-agentpool-33938206-vmss000000\" is invalid: metadata.taints[0].effect: Unsupported value: \"NoSchedule-\": supported values: \"NoSchedule\", \"PreferNoSchedule\", \"NoExecute\"","reason":"Invalid","details":{"name":"aks-agentpool-33938206-vmss000000","kind":"Node","causes":[{"reason":"FieldValueNotSupported","message":"Unsupported value: \"NoSchedule-\": supported values: \"NoSchedule\", \"PreferNoSchedule\", \"NoExecute\"","field":"metadata.taints[0].effect"},{"reason":"FieldValueNotSupported","message":"Unsupported value: \"NoSchedule-\": supported values: \"NoSchedule\", \"PreferNoSchedule\", \"NoExecute\"","field":"metadata.taints[0].effect"}]},"code":422}
Finally, if you need to remove a specific taint, you can always shell out to kubectl (though that's kinda cheating, huh?):
def untaint_node_with_cmd(context, node_name):
cmd_env = os.environ.copy()
child = subprocess.Popen(['kubectl', 'taint', 'nodes', node_name, 'test=True:NoSchedule-', '--context', context], env=cmd_env)
exit_code = child.wait()
return exit_code
Sadly, it doesn't look like this issue has gotten much love in the k8s python client repo. https://github.com/kubernetes-client/python/issues/161
One more better way to untainted a particular taint. By doing this way other taints will not get removed.only a particular taint will ve untainted.
def untaint_node(context, node_name, taint_key):
Kube_client = setup_kube_client(context)
node = Kube_client.list_nodes(field_selector={"metadata.name" : node_name}).items[0]
taints = node.spec.taints
filtered_taints = list(filter(lambda x: x.key != taint_key, taints))
body = {"spec": {"taints": filtered_taints}}
return kube_client.patch_node(node_name, body)
There's nothing special, standard update or patch call on the Node object.
Client libraries are used to interact with kubeapiserver. Therefore, kubeapiserver checks body of the request, no need to have custom removing taint in Python client library.
I think you can do it by calling
v3.patch_node('cn-shanghai.10.10.10.249',
{"spec": {"taints": [{"effect": "NoSchedule-", "key": "test", "value": "1","tolerationSeconds": "300"}]}}
An example can be found in python-client examples repository.
from kubernetes import client, config
def main():
config.load_kube_config()
api_instance = client.CoreV1Api()
body = {
"metadata": {
"labels": {
"foo": "bar",
"baz": None}
}
}
# Listing the cluster nodes
node_list = api_instance.list_node()
print("%s\t\t%s" % ("NAME", "LABELS"))
# Patching the node labels
for node in node_list.items:
api_response = api_instance.patch_node(node.metadata.name, body)
print("%s\t%s" % (node.metadata.name, node.metadata.labels))
if __name__ == '__main__':
main()
Reference: https://github.com/kubernetes-client/python/blob/c3f1a1c61efc608a4fe7f103ed103582c77bc30a/examples/node_labels.py

Can't get the UploadURL from Microsoft Graph in Upload Session

I have been trying to implement the following procedure with python
https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_createuploadsession?view=odsp-graph-online#create-an-upload-session
I have been trying to get the upload URL part
Please note that I already got the access token and created the required client Id and secret
def getUploadUrl(filename="test.txt"):
global token
if (not token):
with open('token.json', 'r') as f:
token = json.load(f)
if (token["expires_at"] < time.time()):
refreshToken()
location = "/me/drive/root:/FolderA/" + filename + ":/createUploadSession"
client = OAuth2Session(client_id=client_id,
redirect_uri=REDIRECT_URI, token=token)
headers = {'Content-Type': 'application/json'}
json_file = {
"item": {"#odata.type": "microsoft.graph.driveItemUploadableProperties",
"#microsoft.graph.conflictBehavior": "replace",
"name": filename
}
}
json_string = json.dumps(json_file, indent=4)
r = client.post(BaseUrl + location,
data=json_string, headers=headers)
print(r.status_code)
print(r.text)
upload_url = ""
if(r.status_code == 200):
upload_url = r.json()['uploadUrl']
return upload_url, r
else:
return "", ""
I keep getting the following Error response though
{
"error": {
"code": "invalidRequest",
"message": "Invalid request",
"innerError": {
"request-id": "7893d0aa-fcdb-46bc-b0b6-58fd90c4cb46",
"date": "2020-03-21T17:15:13"
}
}
What I ended up doing till now is just removing
#odata.type": "microsoft.graph.driveItemUploadableProperties from the JSON payload.
Try to reload later, maybe it was the service bug.

Error on testing AWS Lambda handler function: Data format for event and context parameters

I have the following code from a blog which gets the bitcoin price for today. I could access this Lambda function from the AWS Lex console and test the bot to get the price for today.
"""
Lexbot Lambda handler.
"""
from urllib.request import Request, urlopen
import json
def get_bitcoin_price(date):
print('get_bitcoin_price, date = ' + str(date))
request = Request('https://rest.coinapi.io/v1/ohlcv/BITSTAMP_SPOT_BTC_USD/latest?period_id=1DAY&limit=1&time_start={}'.format(date))
request.add_header('X-CoinAPI-Key', 'E4107FA4-A508-448A-XXX')
response = json.loads(urlopen(request).read())
return response[0]['price_close']
def lambda_handler(event, context):
print('received request: ' + str(event))
date_input = event['currentIntent']['slots']['Date']
btc_price = get_bitcoin_price(date_input)
response = {
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled",
"message": {
"contentType": "SSML",
"content": "Bitcoin's price was {price} dollars".format(price=btc_price)
},
}
}
print('result = ' + str(response))
return response
But when I test the function from the AWS Lex console, I get the following error:
Response:
{
"errorMessage": "'currentIntent'",
"errorType": "KeyError",
"stackTrace": [
[
"/var/task/lambda_function.py",
18,
"lambda_handler",
"date_input = event['currentIntent']['slots']['Date']"
]
]
}
Request ID:
"2488187a-2b76-47ba-b884-b8aae7e7a25d"
Function Logs:
START RequestId: 2488187a-2b76-47ba-b884-b8aae7e7a25d Version: $LATEST
received request: {'Date': 'Feb 22'}
'currentIntent': KeyError
Traceback (most recent call last):
File "/var/task/lambda_function.py", line 18, in lambda_handler
date_input = event['currentIntent']['slots']['Date']
KeyError: 'currentIntent'
How do I test the function in the AWS Lambda console? 'lambda_handler' function, what format would be the 'event' and 'context' be? Also, what would be the 'context' here?
What should I pass as 'event' and 'context' in my case?
Your code is failing because the event object is filled in with {'Date': 'Feb 22'} but your code expects much more than this. Therefore, it fails when you try to parse this JSON by trying to access currentIntent:
date_input = event['currentIntent']['slots']['Date']
You cannot pass any context to your Lambda when testing from the console as it is automatically populated by AWS. Also, the context is only used in very specific occasions, so I would not worry about it for now.
You can, however, pass the event as argument and there are many ways to do it. The simplest way to do it manually is to go to AWS's Lambda Console, click on Test and, if you haven't configured any Test Event yet, the following screen will pop up
Now, on the dropdown, you can select your event and AWS will fill it in for you, like this:
You can now customise the event the way you want it.
Once you save it and click on Test, the event object will be populated with the provided JSON.
Another option is to check Sample Events Published By Event Sources, so you can simply grab any JSON event you'd like and tailor it accordingly.
I have grabbed the Lex Sample Event for you, which looks like this:
{
"messageVersion": "1.0",
"invocationSource": "FulfillmentCodeHook or DialogCodeHook",
"userId": "user-id specified in the POST request to Amazon Lex.",
"sessionAttributes": {
"key1": "value1",
"key2": "value2",
},
"bot": {
"name": "bot-name",
"alias": "bot-alias",
"version": "bot-version"
},
"outputDialogMode": "Text or Voice, based on ContentType request header in runtime API request",
"currentIntent": {
"name": "intent-name",
"slots": {
"slot-name": "value",
"slot-name": "value",
"slot-name": "value"
},
"confirmationStatus": "None, Confirmed, or Denied
(intent confirmation, if configured)"
}
}
Use that as your event and you'll be able to test it accordingly.

Parsing child nodes of JSON response in SOAP UI using groovy json slurper

I am getting a JSON response from an webservice like below . I want to parse all childs of results node using Groovy Json slurper and assert the value is correct.
{
"status": "Healthy",
"results": [
{
"name": "Microservice one",
"status": "Healthy",
"description": "Url check MSOneURI success : status(OK)"
},
{
"name": "Microservice two",
"status": "Healthy",
"description": "Url check MSTwoURI success : status(OK)"
},
{
"name": "Microservice three",
"status": "Healthy",
"description": "Url check MSThreeURI success : status(OK)"
},
{
"name": "Microservice four",
"status": "Healthy",
"description": "Url check MSFourURI success : status(OK)"
},
{
"name": "Microservice five",
"status": "Healthy",
"description": "Url check MSFiveURI success : status(OK)"
}
]
}
This is what I have done - this works .
//imports
import groovy.json.JsonSlurper
import groovy.json.*
//grab the response
def ResponseMessage = messageExchange.response.responseContent
// trim starting and ending double quotes
def TrimResponse =ResponseMessage.replaceAll('^\"|\"$','').replaceAll('/\\/','')
//define a JsonSlurper
def jsonSlurper = new JsonSlurper().parseText(TrimResponse)
//verify the response to be validated isn't empty
assert !(jsonSlurper.isEmpty())
//verify the Json response Shows Correct Values
assert jsonSlurper.status == "Healthy"
def ActualMsNames = jsonSlurper.results*.name.toString()
def ActualMsStatus = jsonSlurper.results*.status.toString()
def ActualMsDescription = jsonSlurper.results*.description.toString()
def ExpectedMsNames = "[Microservice one,Microservice two,Microservice three,Microservice four,Microservice five]"
def ExpectedMsStatus = "[Healthy, Healthy, Healthy, Healthy, Healthy]"
def ExpectedMsDescription = "[Url check MSOneURI success : status(OK),Url check MSTwoURI success : status(OK),Url check MSThreeURI success : status(OK),Url check MSFourURI success : status(OK),Url check MSFiveURI success : status(OK)]"
assert ActualMsNames==ExpectedMsNames
assert ActualMsStatus==ExpectedMsStatus
assert ActualMsDescription==ExpectedMsDescription
But I want to make it better using some kind of for loop which will parse each collection one at a time and assert the value of "name", "status" and "descriptions" at once for each child
Is that possible?
Yes, that's certainly possible.
Without knowing more about your actual data it's not possible to give a perfect example, but you could do something like:
jsonSlurper.results?.eachWithIndex { result, i ->
assert result.name == expectedNames[i]
assert result.status == expectedStatus[i] // or just "Healthy" if that's the only one
assert result.description == expectedDescriptions[i]
}
where expectedWhatever is a list of expected result fields. If your expected results really are based on index like in your example, then you could even calculate them within the loop, but I'm guessing that's not the case for real data.

Resources