How code AWS Lambda to report back to pipline about job done? - aws-lambda

Edit: changed lambda function and logs output, problem reminas :/
Have following lambda function as step in codepipeline:
import boto3
import json
import sys
import os
import pymysql
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
DB_HOST = os.environ['DB_HOST']
DB_USER = os.environ['DB_USER']
DB_PASS = os.environ['DB_PASS'],
DB_PORT = int(os.environ['DB_PORT'])
codepipeline = boto3.client('codepipeline')
cursorType = pymysql.cursors.DictCursor
try:
connection = pymysql.connect(
host=DB_HOST,
user=DB_USER,
password=DB_PASS,
port=DB_PORT,
)
except pymysql.MySQLError as err:
logger.error("Error: Could not connect to MySql db")
logger.error(err)
sys.exit()
logger.info("Success: Connected to MySql db")
def lambda_handler(event, context):
cursor = connection.cursor()
try:
logger.info("Dropping db...")
cursor.execute(f"drop database {DB_NAME}")
logger.info("Creating db...")
cursor.execute(f"create database {DB_NAME}")
logger.info("Db created")
connection.close()
logger.info('Conection closed')
job_id = event['CodePipeline.job']['id']
logger.info("Job id `{job_id}`")
response = codepipeline.put_job_success_result(jobId=job_id)
logger.info(response)
except Exception as err:
logger.error(err)
response = codepipeline.put_job_failure_result(
jobId=job_id, failureDetails={'message': message, 'type': 'JobFailed'}
)
return {
"statusCode": 200,
}
Function log from function run:
START RequestId: 02e2f7cb-817d-4e49-90db-5b4cae5c9336 Version: $LATEST
[INFO] 2020-09-23T07:38:34.515Z Found credentials in environment variables.
[INFO] 2020-09-23T07:38:34.598Z Success: Connected to MySql db
{'CodePipeline.job': {'id': '9a8b13ea-d4f8-4aea-8481-60db0b7b5b5d... snip}
Dropping db
Creating db
Db created
Conection closed
[INFO] 2020-09-23T07:38:34.732Z 02e2f7cb-817d-4e49-90db-5b4cae5c9336 Job id 9a8b13ea-d4f8-4aea-8481-60db0b7b5b5d
successfuly done
END RequestId: 02e2f7cb-817d-4e49-90db-5b4cae5c9336
REPORT RequestId: 02e2f7cb-817d-4e49-90db-5b4cae5c9336 Duration: 60060.17 ms Billed Duration: 60000 ms Memory Size: 128 MB Max Memory Used: 76 MB Init Duration: 426.53 ms
2020-09-23T07:39:34.660Z 02e2f7cb-817d-4e49-90db-5b4cae5c9336 Task timed out after 60.06 seconds
[INFO] 2020-09-23T07:39:35.55Z Found credentials in environment variables.
[INFO] 2020-09-23T07:39:35.94Z Success: Connected to MySql db
START RequestId: 02e2f7cb-817d-4e49-90db-5b4cae5c9336 Version: $LATEST
{'CodePipeline.job': {'id': '9a8b13ea-d4f8-4aea-8481-60db0b7b5b5d',... snip}
Dropping db
Creating db
Db created
Conection closed
[INFO] 2020-09-23T07:41:39.974Z 02e2f7cb-817d-4e49-90db-5b4cae5c9336 Job id 9a8b13ea-d4f8-4aea-8481-60db0b7b5b5d
successfuly done
END RequestId: 02e2f7cb-817d-4e49-90db-5b4cae5c9336
REPORT RequestId: 02e2f7cb-817d-4e49-90db-5b4cae5c9336 Duration: 60060.32 ms Billed Duration: 60000 ms Memory Size: 128 MB Max Memory Used: 30 MB
2020-09-23T07:42:39.925Z 02e2f7cb-817d-4e49-90db-5b4cae5c9336 Task timed out after 60.06 seconds
How can I "force" lambda to report back to codepipeline that job is done either ok or not instead of just running in some kind of loop?
Lambda IAM role has policy attached like below:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:Describe*",
"ssm:Get*",
"ssm:List*",
"kms:Decrypt",
"ssm:GetParametersByPath",
"ec2:DescribeNetworkInterfaces",
"ec2:CreateNetworkInterface",
"ec2:DeleteNetworkInterface",
"ec2:DescribeInstances",
"ec2:AttachNetworkInterface",
"codepipeline:PutJobSuccessResult",
"codepipeline:PutJobFailureResult"
],
"Resource": "*"
}
]
}
Help please as I can't find reason why lambda is not "letting know" back to pipeline about job status.

So either create codepipline vpc endpoint or move lambda to private network... case solved :).

Related

AWS sam local start api with lambda written in java and packaged as docker image

I have implemented the lambda function using java (taken from the docs actually).
package trial;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.Map;
public class Handler implements RequestHandler<Map<String,Object>, String>{
Gson gson = new GsonBuilder().setPrettyPrinting().create();
#Override
public String handleRequest(Map<String,Object> event, Context context)
{
LambdaLogger logger = context.getLogger();
String response = "200 OK";
// log execution details
logger.log("ENVIRONMENT VARIABLES: " + gson.toJson(System.getenv()));
logger.log("CONTEXT: " + gson.toJson(context));
// process event
logger.log("EVENT: " + gson.toJson(event));
logger.log("EVENT TYPE: " + event.getClass().toString());
return response;
}
}
Then I packed it in a docker image:
FROM public.ecr.aws/lambda/java:11
COPY lib/* ${LAMBDA_TASK_ROOT}/lib/
CMD [ "trial.Handler::handleRequest" ]
Then, using AWS CDK I want to use this image as lambda handler:
const repo = aws.aws_ecr.Repository.fromRepositoryArn(
construct, "repoId", "arn:aws:ecr:eu-west-1:***ACCOUNTID***:repository/repo"
)
const lambda1 = new aws.aws_lambda.DockerImageFunction(construct, "HelloFunction", {
code: aws.aws_lambda.DockerImageCode.fromEcr(repo),
})
const api = new aws.aws_apigateway.LambdaRestApi(construct, 'sample-api', {
handler: lambda1
})
I can deploy this lambda to AWS and everything works as expected.
But it doesn't work when I want to test it using AWS SAM local.
sam local start-api -t cdk.out/HelloCdkStack.template.json --warm-containers EAGER
I get an error:
"resourceId": "123456",
"resourcePath": "/{proxy+}",
"stage": "prod"
},
"resource": "/{proxy+}",
"version": "1.0"
}EVENT TYPE: class java.util.LinkedHashMapEND RequestId: 9a7201d8-7b4b-486e-9208-2da9a8972347
REPORT RequestId: 9a7201d8-7b4b-486e-9208-2da9a8972347 Duration: 9.99 ms Billed Duration: 10 ms Memory Size: 128 MB Max Memory Used: 128 MB
Invalid lambda response received: Lambda returned <class 'str'> instead of dict
2022-12-23 01:30:24 127.0.0.1 - - [23/Dec/2022 01:30:24] "GET /favicon.ico HTTP/1.1" 502 -
** UPDATE, solved
The Handler must return Object for unknown reason.
return Map.of(
"statusCode", 200,
"body", "test response",
"headers", Map.of(
"Content-Type", "application/json"
)
);

aws lambda put-metric-data timeout

I need to get some data from an RDS and push it as a cloudwatch metric.
I created a lambda in AWS that is associated to a VPC which has internet access. But the pushing of the metric times out.
Trying to debug this I do a dns resolution and that works properly.
Any ideas?
this is the code:
print('Loading function')
try:
conn = pymysql.connect(host="kmydb.something.eu-west-1.rds.amazonaws.com", user="myuser", passwd="mypass", db="mydb", connect_timeout=5)
print("SUCCESS: Connection to RDS MySQL instance succeeded")
item_count = 0
with conn.cursor() as cur:
print("Executing SQL command")
cur.execute("select count(*) from something")
for row in cur:
item_count = row[0]
print("DONE: Executing SQL command -> Rows: {}".format(item_count) )
conn.commit()
print("DEBUG: Going to push now.")
hostName = "something.something.com"
ipAddress = socket.gethostbyname(hostName)
print("IP address of the host name {} is: {}".format(hostName, ipAddress))
if pushToCloudwatch(item_count):
print("DEBUG: Pushed sucessfull.")
else:
print("ERROR: Pushed NOT sucessfull.")
except pymysql.MySQLError as e:
print("ERROR: Unexpected error: Could not connect to MySQL instance.")
print("error: {}".format(e))
sys.exit()
def pushToCloudwatch(channels):
print("ERROR: Creating client.")
client = boto3.client('cloudwatch',region_name="us-west-1")
print("ERROR: client created... pushing.")
response = client.put_metric_data(
Namespace='INFRA-VOICE',
MetricData=[
{
'MetricName': 'CurrentP',
'Dimensions': [
{
'Name': 'INFRA',
'Value': 'CurrentP'
},
],
'Value': 0,
'Unit': 'Count'
}
]
)
print("ERROR: Response received.")
print( "Response: {}".format(response) )
return True
So the point is, you MUST:
Put your lambda in a PRIVATE SUBNET (in your existing VPC), event if you have to create it.
Create a NatGateway ON THE PUBLIC Subnet.
Then on the private subnet, you need to add a route to the route table pointing 0.0.0.0/0 to the NatGateway (which is on the public vpc)
The the NatGateway will get your traffic and NAT it to the internet via its own Internet Gateway (igw)
something like this:
This helped me a lot:
Amazon AWS NAT Gatway not working, EC2 doesn't register in ECS Cluster
Solved.

AWS Lambda function for oracle password rotation

Hi I am using lambda function for oracle password rotation and am getting the below error once every grants provided:
START RequestId: f515ffc3-56d4-4301-96a5-426ab14c68a2 Version: $LATEST
[INFO] 2020-05-14T13:54:14.9Z f515ffc3-56d4-4301-96a5-426ab14c68a2 {'RequestType': 'Create', 'ServiceToken': 'arn:aws:lambda:eu-west-1:661211433270:function:oracle-rds-dbsetup-lambda', 'ResponseURL': 'https://cloudformation-custom-resource-response-euwest1.s3-eu-west-1.amazonaws.com/arn%3Aaws%3Acloudformation%3Aeu-west-1%3A661211433270%3Astack/oracle/24520dd0-95e8-11ea-b1d1-0609694b6370%7CRDSDBSetup%7Cff43fa14-be13-4a66-95e5-ee0b82a44993?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20200514T135412Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7200&X-Amz-Credential=AKIAJ7MCS7PVEUOADEEA%2F20200514%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=20bb8ba39f88fb14efb623b9047e89a628eb9c881c67b4d035995d9859918bb9', 'StackId': 'arn:aws:cloudformation:eu-west-1:661211433270:stack/oracle/24520dd0-95e8-11ea-b1d1-0609694b6370', 'RequestId': 'ff43fa14-be13-4a66-95e5-ee0b82a44993', 'LogicalResourceId': 'RDSDBSetup', 'ResourceType': 'Custom::DBSetup', 'ResourceProperties': {'ServiceToken': 'arn:aws:lambda:eu-west-1:661211433270:function:oracle-rds-dbsetup-lambda', 'MasterSecretArn': 'arn:aws:secretsmanager:eu-west-1:661211433270:secret:rds/app/master4-h4UyCN', 'AppUserGrants': ['CREATE SESSION', 'CONNECT', 'RESOURCE', 'DBA'], 'AppSecretArn': 'arn:aws:secretsmanager:eu-west-1:661211433270:secret:rds/app/application4-3XnzKs'}}
[INFO] 2020-05-14T13:54:14.50Z f515ffc3-56d4-4301-96a5-426ab14c68a2 Found credentials in environment variables.
[INFO] 2020-05-14T13:54:15.455Z f515ffc3-56d4-4301-96a5-426ab14c68a2 User created: testappdbuser
[INFO] 2020-05-14T13:54:15.459Z f515ffc3-56d4-4301-96a5-426ab14c68a2 Granted: CREATE SESSION
[INFO] 2020-05-14T13:54:15.470Z f515ffc3-56d4-4301-96a5-426ab14c68a2 Granted: CONNECT
[INFO] 2020-05-14T13:54:15.475Z f515ffc3-56d4-4301-96a5-426ab14c68a2 Granted: RESOURCE
[INFO] 2020-05-14T13:54:15.479Z f515ffc3-56d4-4301-96a5-426ab14c68a2 Granted: DBA
[INFO] 2020-05-14T13:54:15.480Z f515ffc3-56d4-4301-96a5-426ab14c68a2 Successfully created user testappdbuser in Oracle Server DB for secret arn arn:aws:secretsmanager:eu-west-1:661211433270:secret:rds/app/application4-3XnzKs.
https://cloudformation-custom-resource-response-euwest1.s3-eu-west-1.amazonaws.com/arn%3Aaws%3Acloudformation%3Aeu-west-1%3A661211433270%3Astack/oracle/24520dd0-95e8-11ea-b1d1-0609694b6370%7CRDSDBSetup%7Cff43fa14-be13-4a66-95e5-ee0b82a44993?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20200514T135412Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7200&X-Amz-Credential=AKIAJ7MCS7PVEUOADEEA%2F20200514%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=20bb8ba39f88fb14efb623b9047e89a628eb9c881c67b4d035995d9859918bb9
Response body:
{
"Status": "SUCCESS",
"Reason": "See the details in CloudWatch Log Stream: 2020/05/14/[$LATEST]c85275eb57604aebb929853d877306c7",
"PhysicalResourceId": "2020/05/14/[$LATEST]c85275eb57604aebb929853d877306c7",
"StackId": "arn:aws:cloudformation:eu-west-1:661211433270:stack/oracle/24520dd0-95e8-11ea-b1d1-0609694b6370",
"RequestId": "ff43fa14-be13-4a66-95e5-ee0b82a44993",
"LogicalResourceId": "RDSDBSetup",
"NoEcho": false,
"Data": {}
}
send(..) failed executing requests.put(..): HTTPSConnectionPool(host='cloudformation-custom-resource-response-euwest1.s3-eu-west-1.amazonaws.com', port=443): Max retries exceeded with url: /arn%3Aaws%3Acloudformation%3Aeu-west-1%3A661211433270%3Astack/oracle/24520dd0-95e8-11ea-b1d1-0609694b6370%7CRDSDBSetup%7Cff43fa14-be13-4a66-95e5-ee0b82a44993?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20200514T135412Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7200&X-Amz-Credential=AKIAJ7MCS7PVEUOADEEA%2F20200514%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-**Signature=20bb8ba39f88fb14efb623b9047e89a628eb9c881c67b4d035995d9859918bb9 (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fec35bc8610>: Failed to establish a new connection: [Errno 110] Connection timed out'))**
END RequestId: f515ffc3-56d4-4301-96a5-426ab14c68a2
Is your Lambda function in a VPC without a NAT gateway? Looks like it doesn't have an outbound internet connection since it doesn't have an IP address.
Try removing the Lambda from the VPC if you don't need to access VPC private resources.
Otherwise, it also looks like you need to access RDS from within the Lambda, so in that case, you should add a NAT gateway to your VPC.
Some useful resources:
AWS Lambda: How to setup a NAT gateway for a lambda function with VPC access
https://aws.amazon.com/premiumsupport/knowledge-center/internet-access-lambda-function/

AWS Lambda returning internal server error for no reason

I have an AWS Lambda function which results in {"message":"Internal Server Error"} when I run it. Using the CloudWatch Logs and print statements I can confirm that the code executes without errors until it returns. This is my code:
def lambda_handler(event, context):
table_name = "<redacted>"
bucket_name = "<redacted>"
session = boto3.Session(
aws_access_key_id="<redacted>",
aws_secret_access_key="<redacted>",
)
if "body" in event and event["body"]:
req_json = json.loads(event["body"])
uuids = process(req_json, table_name, bucket_name,
session, ("127.0.0.1", 8000), "site/")
print("success", uuids) # this code still executes sucessfully
return http_response(200, "Success", uuids)
else:
return http_response(400, "No request body")
There is no timeout either, as this code runs within ~10s and my timeout is set to 2 minutes. I have no clue why I'm getting no proper http response. If anyone can tell me why or has an Idea what the issue could be, I'd be very grateful.
I dont have your http_response method. but the code below works in lambda.
import json
def lambda_handler(event, context):
if "body" in event and event["body"]:
req_json = json.loads(event["body"])
print("success") # this code still executes sucessfully
return {
'statusCode': 200,
'body': json.dumps(req_json)
}
else:
return {
'statusCode': 400,
'body': json.dumps({'message': 'No request body'})
}
Also I have noticed that you are adding AWS credentials to the lambda code directly. You could instead use IAM role for lambda and assign the required permission to the role.
https://aws.amazon.com/blogs/security/how-to-create-an-aws-iam-policy-to-grant-aws-lambda-access-to-an-amazon-dynamodb-table/

I'm having trouble fetching data from elastic Search domain

I am trying to fetch data from my ES domain to use in my Alexa skill lambda function. I used the following code template from https://github.com/elastic/elasticsearch-js:
const { Client } = require('#elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' })
// promise API
const result = await client.search({
index: 'my-index',
body: { foo: 'bar' }
})
This is the error I'm getting in my lambda function:
Response:
{
"errorMessage": "Response Error",
"errorType": "ResponseError",
"stackTrace": [
"IncomingMessage.response.on (/var/task/node_modules/#elastic/elasticsearch/lib/Transport.js:290:25)",
"emitNone (events.js:111:20)",
"IncomingMessage.emit (events.js:208:7)",
"endReadableNT (_stream_readable.js:1064:12)",
"_combinedTickCallback (internal/process/next_tick.js:138:11)",
"process._tickDomainCallback (internal/process/next_tick.js:218:9)"
]
}
Request ID:
"8d9b248a-c0dc-4b1c-bcb2-d54e267c28c7"
Function Logs:
START RequestId: 8d9b248a-c0dc-4b1c-bcb2-d54e267c28c7
Version: $LATEST
2019-04-09T19:48:46.107Z 8d9b248a-c0dc-4b1c-bcb2-d54e267c28c7
{"errorMessage":"Response Error","errorType":"ResponseError","stackTrace":["IncomingMessage.response.on (/var/task/node_modules/#elastic/elasticsearch/lib/Transport.js:290:25)","emitNone (events.js:111:20)","IncomingMessage.emit (events.js:208:7)","endReadableNT (_stream_readable.js:1064:12)","_combinedTickCallback (internal/process/next_tick.js:138:11)","process._tickDomainCallback (internal/process/next_tick.js:218:9)"]}
END RequestId: 8d9b248a-c0dc-4b1c-bcb2-d54e267c28c7
REPORT RequestId: 8d9b248a-c0dc-4b1c-bcb2-d54e267c28c7
Duration: 1159.14 ms
Billed Duration: 1200 ms
Memory Size: 128 MB
Max Memory Used: 70 MB
You have to respect to search format
https://www.elastic.co/guide/en/elasticsearch/reference/2.3/search.html

Resources