How to link two lambda functions from API gateway - amazon-web-services

I have two lambda functions
Lambda 1:
def save_events(event):
result = []
conn = pymysql.connect(rds_host, user=name, passwd=password,
db=db_name,connect_timeout=30)
with conn.cursor() as cur:
cur.execute("SELECT * FROM bodyparts")
for row in cur:
result.append(list(row))
cur.close()
bodyparts = json.dumps(result)
bodyParts=(bodyparts.replace("\"", "'"))
def lambda_handler(event, context):
save_events(event)
return bodyParts
Lambda 2:
def save_events(event):
result = []
conn = pymysql.connect(rds_host, user=, passwd=, db=, connect_timeout=30)
with conn.cursor(pymysql.cursors.DictCursor) as cur:
cur.execute("select exid,exercise_name,image from exercise where bid = 3")
result = cur.fetchall()
cur.close()
print ("Data from RDS...")
print (result)
workout = json.dumps(result)
workouts=(workout.replace("\"", "'"))
def lambda_handler(event, context):
save_events(event)
return workouts
After the successful execution of lambda 1 it will return list as a json object to the browser using API gateway and now how to invoke the lambda 2 function in API gateway based on the user selection from the output of lambda1 function.
In lambda2 how to pass user selected item as "bid" value in query.
I know the theory part, really stuck with the implementation part as am a beginner to backend development, Any help would be much appreciated

I think that a good option for you is AWS Step Function. If you use Step Functions you can have 2 states with a lambda in each state, the state 1 execute your lambda 1 and pass the result to the second state and execute in it lambda 2. Remember that Step Functions can be called from API Gateway so if you are using API Gateway like endpoint you only need to change the target to Step Functions instead the lambda function. A good way to create all this resources is SAM (Serverless Application Model), using swagger.

Related

AWS Lambda failing to fetch EC2 AZ details

I am trying to create lambda script using Python3.9 which will return total ec2 servers in AWS account, their status & details. Some of my code snippet is -
def lambda_handler(event, context):
client = boto3.client("ec2")
#s3 = boto3.client("s3")
# fetch information about all the instances
status = client.describe_instances()
for i in status["Reservations"]:
instance_details = i["Instances"][0]
if instance_details["State"]["Name"].lower() in ["shutting-down","stopped","stopping","terminated",]:
print("AvailabilityZone: ", instance_details['AvailabilityZone'])
print("\nInstanceId: ", instance_details["InstanceId"])
print("\nInstanceType: ",instance_details['InstanceType'])
On ruunning this code i get error -
If I comment AZ details, code works fine.If I create a new function with only AZ parameter in it, all AZs are returned. Not getting why it fails in above mentioned code.
In python, its always a best practice to use get method to fetch value from list or dict to handle exception.
AvailibilityZone is actually present in Placement dict and not under instance details. You can check the entire response structure from below boto 3 documentation
Reference
def lambda_handler(event, context):
client = boto3.client("ec2")
#s3 = boto3.client("s3")
# fetch information about all the instances
status = client.describe_instances()
for i in status["Reservations"]:
instance_details = i["Instances"][0]
if instance_details["State"]["Name"].lower() in ["shutting-down","stopped","stopping","terminated",]:
print(f"AvailabilityZone: {instance_details.get('Placement', dict()).get('AvailabilityZone')}")
print(f"\nInstanceId: {instance_details.get('InstanceId')}")
print(f"\nInstanceType: {instance_details.get('InstanceType')}")
The problem is that in response of describe_instances availability zone is not in first level of instance dictionary (in your case instance_details). Availability zone is under Placement dictionary, so what you need is
print(f"AvailabilityZone: {instance_details.get('Placement', dict()).get('AvailabilityZone')}")

Can we Integrate AWS lambda with AWS IOT and perform operations in the IOT using this lambda function?

The scenario is like this
I have a microservice which invokes a LAMBDA function whose role will be to delete things from the AWS IOT.
Is there a way I can perform operations in AWS IOT using the lambda function?
Any article, blog regarding this will be a huge help as I'm not able to find any integration document on the web.
I found a way to do several operations in AWS IOT using lambda function by the means of API's.
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iot.html#IoT.Client.delete_thing_group
The above link has description about API's which will help in this case.
A sample lambda function script to delete a thing from the IOT is
import json
import boto3
def lambda_handler(event, context):
thing_name = event['thing_name']
delete_thing(thing_name=thing_name)
def delete_thing(thing_name):
c_iot = boto3.client('iot')
print(" DELETING {}".format(thing_name))
try:
r_principals = c_iot.list_thing_principals(thingName=thing_name)
except Exception as e:
print("ERROR listing thing principals: {}".format(e))
r_principals = {'principals': []}
print("r_principals: {}".format(r_principals))
for arn in r_principals['principals']:
cert_id = arn.split('/')[1]
print(" arn: {} cert_id: {}".format(arn, cert_id))
r_detach_thing = c_iot.detach_thing_principal(thingName=thing_name, principal=arn)
print("DETACH THING: {}".format(r_detach_thing))
r_upd_cert = c_iot.update_certificate(certificateId=cert_id, newStatus='INACTIVE')
print("INACTIVE: {}".format(r_upd_cert))
r_del_cert = c_iot.delete_certificate(certificateId=cert_id, forceDelete=True)
print(" DEL CERT: {}".format(r_del_cert))
r_del_thing = c_iot.delete_thing(thingName=thing_name)
print(" DELETE THING: {}\n".format(r_del_thing))
And the input for this lambda function will be
{
"thing_name": "MyIotThing"
}

Lambda Function working, but cannot work with API Gateway

I have a working Lambda function when I test it using a test event:
{
"num1_in": 51.5,
"num2_in": -0.097
}
import json
import Function_and_Data_List
#Parse out query string parameters
def lambda_handler(event, context):
num1_in = event['num1_in']
num2_in = event['num2_in']
coord = {'num1': num1_in, 'num2': num2_in}
output = func1(Function_and_Data_List.listdata, coord)
return {
"Output": output
}
However, when I use API gateway to create a REST API I keep getting errors. My method for the REST API are:
1.) Build REST API
2.) Actions -> Create Resource
3.) Actions -> Create Method -> GET
4.) Integration type is Lambda Function, Use Lambda Proxy Integration
5.) Deploy
What am I missing for getting this API to work?
If you use lambda proxy integration, your playload will be in the body. You seem also having incorrect return format.
Therefore, I would recommend trying out the following version of your code:
import json
import Function_and_Data_List
#Parse out query string parameters
def lambda_handler(event, context):
print(event)
body = json.loads(event['body'])
num1_in = body['num1_in']
num2_in = body['num2_in']
coord = {'num1': num1_in, 'num2': num2_in}
output = func1(Function_and_Data_List.listdata, coord)
return {
"statusCode": 200,
"body": json.dumps(output)
}
In the above I also added print(event) so that in the CloudWatch Logs you can inspect the event object which should help debug the issue.

Control AWS Lambda source IP

I have a simple Lambda function the its job is to make HTTP GET to a certain server.
I need to run many copies (hundreds) of the function at the same time and I want to have a distinct source IP address for each HTTP GET coming from each Lambda.
My questions:
How do I make sure that each 'copy' of the Lambda function will have its own IP address?
How do I use boto API invoke call in order to tell AWS that I need N concurrent copies of my Lambda? I am looking here but I can not find the argument that sets the number of concurrent copies.
Thanks
Avishay
As for question #2 I am using the following code in order to invoke N concurrent copies of the Lambda function.
import boto3, json
from concurrent.futures import ThreadPoolExecutor
N = 5
unique_ips = set()
lambda_client = boto3.client('lambda', region_name='us-west-2')
def _lambda_caller(idx):
test_event = dict(idx=idx)
res = lambda_client.invoke(
FunctionName='SimpleHTTPGetter',
InvocationType='RequestResponse',
Payload=json.dumps(test_event),
)
data = json.loads(res['Payload']._raw_stream.data)
print('Thread {} is done'.format(idx))
unique_ips.add(data['body'])
with ThreadPoolExecutor(max_workers=N) as executor:
for i in range(0,N):
future = executor.submit(_lambda_caller,i)
executor.shutdown()
print('Done')
My Lambda code (short version)
import json
import socket
def lambda_handler(event, context):
print('-- HTTP Client started')
hostname = socket.gethostname()
ip = socket.gethostbyname(hostname)
print('My IP address is {}:'.format(ip))
return {
"statusCode": 200,
"body": ip
}
You need to create a VPC, Make sure you attach a subnet that allows internet access. And then attach a security policy to your lambda.
Step by Step here:
https://medium.com/#philippholly/aws-lambda-enable-outgoing-internet-access-within-vpc-8dd250e11e12

How to deploy breast cancer prediction endpoint created by AWS Sagemaker using Lambda and API gateway?

I am trying to deploy the existing breast cancer prediction model on Amazon Sagemanker using AWS Lambda and API gateway. I have followed the official documentation from the below url.
https://aws.amazon.com/blogs/machine-learning/call-an-amazon-sagemaker-model-endpoint-using-amazon-api-gateway-and-aws-lambda/
I am getting a type error at "predicted_label".
result = json.loads(response['Body'].read().decode())
print(result)
pred = int(result['predictions'][0]['predicted_label'])
predicted_label = 'M' if pred == 1 else 'B'
return predicted_label
please let me know if someone could resolve this issue. Thank you.
By printing the result type by print(type(result)) you can see its a dictionary. now you can see the key name is "score" instead of "predicted_label" that you are giving to pred. Hence replace it with
pred = int(result['predictions'][0]['score'])
I think this solves your problem.
here is my lambda function:
import os
import io
import boto3
import json
import csv
# grab environment variables
ENDPOINT_NAME = os.environ['ENDPOINT_NAME']
runtime= boto3.client('runtime.sagemaker')
def lambda_handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
data = json.loads(json.dumps(event))
payload = data['data']
print(payload)
response = runtime.invoke_endpoint(EndpointName=ENDPOINT_NAME,
ContentType='text/csv',
Body=payload)
#print(response)
print(type(response))
for key,value in response.items():
print(key,value)
result = json.loads(response['Body'].read().decode())
print(type(result))
print(result['predictions'])
pred = int(result['predictions'][0]['score'])
print(pred)
predicted_label = 'M' if pred == 1 else 'B'
return predicted_label