I wrote a bash script similar to this one: Download an already uploaded Lambda function
Everything is fine with all lambda functions that have been deployed via SAM template files. However, when I retrieve the deployment package of a lambda function (application) that has been deployed via the web UI of AWS, all I get is the index.js file in the deployment package of that function.
Anyway, it is possible to generate a SAM yaml file that describes the architecture of the given lambda application by selecting it over the Lambda Management Console via Actions > Export Function > Download AWS SAM file. Consequently, there should be a possibility to do this via aws-cli or is that not possible at all?
You can get function configuration with awscli https://docs.aws.amazon.com/cli/latest/reference/lambda/get-function-configuration.html and the response will contain a Code section with a link to the function package https://docs.aws.amazon.com/lambda/latest/dg/API_FunctionCodeLocation.html
Also, you can create a CloudFormation stack from the existing infrastructure with CloudFormer https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-using-cloudformer.html
Having a CloudFormation template you can get the resource description. https://docs.aws.amazon.com/cli/latest/reference/cloudformation/describe-stack-resources.html with the link to the function source code on S3.
See more on this in https://stackoverflow.com/a/55764927/6628583
This is a clue, not a complete answer, sorry. There should be, but there is not yet, an aws-cli to get this SAM content. The URI in the browser is obtuse with some obscure network calls, e.g.
https://us-west-2.console.aws.amazon.com/p/log/1/lambda/1/OP/&k0=feevc&m0=1&d0=%7B%22s_fid%22:%2233SNIPPEDC66-34SNIPPED7FE5B%22%7D&p0=exportSAM&cb=1595621538378&proxy-rid=7c6a6a31SNIPPEDf1a400b457cc
There seems to be no easy way to construct that URI to GET the exportSAM download.
The browser lambda.js is not much help, e.g.
var A = Object(p.connect)((function(e) {
return {
blueprint: Object(v.b)(e).query.exportBp,
integrationConfigs: h.c.getNodes(e),
downloadMessages: h.c.getDownloadMessages(e),
isOpen: !!Object(v.b)(e).query.exportModal,
exporting: h.c.getExporting(e)
}
}
), (function(e) {
return {
downloadSam: function(t) {
return e((n = t,
{
type: b.f.EXPORT_BLUEPRINT_TO_FLOURISH,
blueprintName: n
}));
var n
},
close: function() {
return e(Object(m.c)({
query: {
exportModal: void 0,
exportBp: void 0
}
}, {
persistQuery: !0
}))
}
}
}
), (function(e, t, n) {
return S(S(S(S({}, n), e), t), {}, {
downloadSam: function() {
return t.downloadSam(e.blueprint)
}
})
}
Related
So i'm trying to use S3 to upload some profiles images and then be able to call them by a URL, and for this i wanted to create a Nuxt plugin to add all the related functions to it
but for now i'm trying to keep it simple
plugins/s3.js
import S3 from 'aws-sdk/clients/s3'
export default defineNuxtPlugin(nuxtApp => {
return {
provide: { S3 },
};
});
by doing this i'm getting issues with vite that are saying that global is not define, so i found that i could add some vite config inside my nuxt.config.ts and i did it
nuxt.config.ts
vite: {
define: {
'global': {}
}
},
but by doing that i'm having some conflict at /node_modules/nuxt/dist/pages/runtime/router.mjs:65:4
so there is a solution by adding "window" but if i added i'm getting another error on production saying " TypeError: t is not a constructor" and that's all :)
what would be the best approach to fix this issue? i just want to be able to upload files and call them
I have following AWS CDK backed solution:
Static S3 based webpage which communicates with
API Gateway which then sends data to
AWS lambda.
The problem is that S3 page needs to be aware of API gateway endpoint URL.
Obviously this is not achievable within the same CDK stack. So I have defined two stacks:
Backend (API gateway + lambda)
Frontend (S3 based static webpage)
They are linked as dependant in CDK code:
const app = new cdk.App();
const backStack = new BackendStack(app, 'Stack-back', {...});
new FrontendStack(app, 'Stack-front', {...}).addDependency(backStack, "API URL from backend is needed");
I try to share URL as follows.
Code from backend stack definition:
const api = new apiGW.RestApi(this, 'MyAPI', {
restApiName: 'My API',
description: 'This service provides interface towards web app',
defaultCorsPreflightOptions: {
allowOrigins: apiGW.Cors.ALL_ORIGINS,
}
});
api.root.addMethod("POST", lambdaIntegration);
new CfnOutput(this, 'ApiUrlRef', {
value: api.url,
description: 'API Gateway URL',
exportName: 'ApiUrl',
});
Code from frontend stack definition:
const apiUrl = Fn.importValue('ApiUrl');
Unfortunately, instead of URL I get token (${Token[TOKEN.256]}). At the same time, I see URL is resolved in CDK generated files:
./cdk.out/Stack-back.template.json:
"ApiUrlRef": {
"Description": "API Gateway URL",
"Value": {
"Fn::Join": [
"",
[
"https://",
{
"Ref": "MyAPI7DAA778AA"
},
".execute-api.us-west-1.",
{
"Ref": "AWS::URLSuffix"
},
"/",
{
"Ref": "MyAPIDeploymentStageprodA7777A7A"
},
"/"
]
]
},
"Export": {
"Name": "ApiUrl"
}
}
},
What I'm doing wrong?
UPD:
After advice of fedonev to pass data as props, situation did not changed much. Now url looks like that:
"https://${Token[TOKEN.225]}.execute-api.us-west-1.${Token[AWS.URLSuffix.3]}/${Token[TOKEN.244]}/"
I think important part I missed (which was also pointed by
Milan Gatyas) is how I create HTML with URL of gateway.
In my frontend-stack.ts, I use template file. After template is filled, I store it in S3:
const filledTemplatePath: string = path.join(processedWebFileDir,'index.html');
const webTemplate: string = fs.readFileSync(filledTemplatePath, 'utf8')
const Handlebars = require("handlebars")
let template = Handlebars.compile(webTemplate)
const adjustedHtml: string = template({ apiGwEndpoint: apiUrl.toString() })
fs.writeFileSync(filledTemplatePath, adjustedHtml)
// bucket
const bucket: S3.Bucket = new S3.Bucket(this, "WebsiteBucket",
{
bucketName: 'frontend',
websiteIndexDocument: 'index.html',
websiteErrorDocument: 'error.html',
publicReadAccess: true,
})
new S3Deploy.BucketDeployment(this, 'DeployWebsite', {
sources: [S3Deploy.Source.asset(processedWebFileDir)],
destinationBucket: bucket,
});
(I'm new to TS and web, please don't judge much :) )
Am I correct that S3 is populated on synth, deploy does not change anything and this is why I get tokens in html?
Will be grateful for a link or explanation so that I could understand the process better, there are so much new information to me that some parts are still quite foggy.
As #fedonev mentioned, the tokens are just placeholder values in the TypeScript application. CDK app replaces tokens with intrinsic functions when the CloudFormation template is produced.
However, your use case is different. You try to know the information inside the CDK app which is available only at synthesis time, and you can't use the intrinsic function to resolve the URL while being in CDK app to write to file.
If possible you can utilize the custom domain for the API Gateway. Then you can work with beforehand known custom domain in your static file and assign the custom domain to the API Gateway in your CDK App.
[Edit: rewrote the answer to reflect updates to the OP]
Am I correct that S3 is populated on synth, deploy does not change anything and this is why I get tokens in html?
Yes. The API URL will resolve only at deploy-time. You are trying to consume it at synth-time when you write to the template file. At synth-time, CDK represents not-yet-available values as Tokens like ${Token[TOKEN.256]}, the CDK's clever way of handling such deferred values.
What I'm doing wrong?
You need to defer the consumption of API URL until its value is resolved (= until the API is deployed). In most cases, passing constructs as props between stacks is the right approach. But not in your case: you want to inject the URL into the template file. As usual with AWS, you have many options:
Split the stacks into separate apps, deployed separately. Deploy BackendStack. Hardcode the url into FrontendStack. Quick and dirty.
Instead of S3, use Amplify front-end hosting, which can expose the URL to your template as an environment variable. Beginner friendly, has CDK support.
Add a CustomResource construct, which would be backed by a Lambda that writes the URL to the template file as part of the deploy lifecycle. This solution is elegant but not newbie-friendly.
Use a Pipeline to inject the URL variable as a build step during deploy. Another advanced approach.
So I have a very simple aws-lambda-tools-defaults.json in my project:
{
"profile": "default",
"region": "us-east-2",
"configuration": "Release",
"framework": "netcoreapp3.1",
"function-runtime": "dotnetcore3.1",
"function-memory-size": 256,
"function-timeout": 30,
"function-handler": "LaCarte.RestaurantAdmin.EventHandlers::LaCarte.RestaurantAdmin.EventHandlers.Function::FunctionHandler"
}
It works, I can test my lambda code locally which is great. But I want to be able to test multiple lambdas, not just one. Does anyone else know how to change the JSON so that I can run multiple lambdas in the mock tool?
Thanks in advance,
Simply remove the function-handler attribute from your aws-lambda-tools-defaults.json file and add a template attribute referencing your serverless.template (the AWS CloudFormation template used to deploy your lambda functions to your AWS cloud environment)
{
...
"template": "serverless.template"
...
}
Then, you can test you lambda function locally for example with The AWS .NET Mock Lambda Test Tool. So now you'll see the Function dropdown List has changed from listing the lambda function name you specified in your function-handler
to the list of lambda functions declared in your serverless.template file, and then you can test them all locally! :)
You can find more info in this discussion
Answering after a long time, but might help someone else. To deploy and test multiple lambdas from visual studio, you have to implement serverless.template. Check AWS SAM documentation.
You can start with this one - https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/lambda-build-test-severless-app.html
I've created a lambda function called add in my aws environment, I am trying to build a cdk application that would generate a new API Gateway and then invoke add.
I am following the tutorial on https://cdkworkshop.com/20-typescript/30-hello-cdk/300-apigw.html and I noticed all the examples I came across online seem to write their code in a similar form to following:
const hello = new lambda.Function(this, 'HelloHandler', {
runtime: lambda.Runtime.NODEJS_10_X, // execution environment
code: lambda.Code.fromAsset('lambda'), // code loaded from "lambda" directory
handler: 'hello.handler' // file is "hello", function is "handler"
});
const api = new apiGateWay.LambdaRestApi(this, 'api', {
handler: hello
})
Above example directly creates a new lambda function name with HelloHanlder in it. I want to reference my previously created function add, and not add any new lambda function to the stack, something along the lines of:
const api = new apiGateWay.LambdaRestApi(this, 'api', {
handler: "add"
})
Is this possible to fix?
Option 1: Using existing Lambda from function Arn
const hello = lambda.Function.fromFunctionArn(
this,
"hello-lambda",
"arn:aws:lambda:us-east-1:111222233333:function:hello-lambda"
);
new apigw.LambdaRestApi(this, "Endpoint", {
handler: hello,
});
Option 2: You can import existing lambda into a new CloudFormation stack and export the Arn and import into CDK
Example of import a DynamoDb, Lambda is no different
Exporting Arn as stack output
Importing stack into CDK and using it.
I have a function in my Alexa skill's lambda function that I am trying to do a unit test for using the aws-lambda-mock-context node package. The method I am trying to test includes a call to DynamoDB to check if an item exists in my table.
At the moment, my test immediately fails with CredentialsError: Missing credentials in config. Following this blog, I tried to manually enter my Amazon IAM credentials into a .aws/credentials file. Testing with the credentials leads to the test running for 30+ seconds before timing out, with no success or fail result from DynamoDB. I am not sure where to go from here.
The function I am looking to unit test looks like this:
helper.prototype.checkForItem = function(alexa) {
var registration_id = 123;
var params = {
TableName: 'registrations',
Key: {
id: {"N" : registration_id}
}
};
return this.getItemFromDB(params).then(function(data) {
//...
}
And the call to DynamoDB:
helper.prototype.getItemFromDB = function(params) {
return new Promise(function(fulfill, reject) {
dynamoDB.getItem(params, function(err, data) {
if (err == null) {
console.log("fulfilled");
fulfill(data);
}
else {
console.log("error recieving data " + err);
reject(null);
}
});
});
}
You can use SAM Local to test you lambda:
AWS SAM is a fast and easy way of deploying your serverless
applications, allowing you to write simple templates to describe your
functions and their event sources (Amazon API Gateway, Amazon S3,
Kinesis, and so on). Based on AWS SAM, SAM Local is an AWS CLI tool
that provides an environment for you to develop, test, and analyze
your serverless applications locally before uploading them to the
Lambda runtime. Whether you're developing on Linux, Mac, or Microsoft
Windows, you can use SAM Local to create a local testing environment
that simulates the AWS runtime environment. Doing so helps you address
issues such as performance. Working with SAM Local also allows faster,
iterative development of your Lambda function code because there is no
need to redeploy your application package to the AWS Lambda runtime.
For more information, see Building a Simple Application Using SAM
Local.
if you want to do unit testing you can mock dynamo db endpoint using any mocking library like nock, also you can check fiddler request/ response what your app is making to dynamo db endpoint and then accordingly you can troubleshoot.