Alexa Skill ARN - The remote endpoint could not be called, or the response it returned was invalid - amazon-web-services

I've created a simple Lambda function to call a webpage, this works fine when I test it from the functions page however when trying to create a skill to call this function I end up with a "The remote endpoint could not be called, or the response it returned was invalid." error.
Lambda Function
var http = require('http');
exports.handler = function(event, context) {
console.log('start request to ' + event.url)
http.get(event.url, function(res) {
console.log("Got response: " + res.statusCode);
context.succeed();
}).on('error', function(e) {
console.log("Got error: " + e.message);
context.done(null, 'FAILURE');
});
console.log('end request to ' + event.url);
}
The Test Event code looks like this:
{
"url": "http://mywebsite.co.uk"
}
and I've added a trigger for the "Alexa Skills Kit".
The ARN for this function is showing as:
arn:aws:lambda:us-east-1:052516835015:function:CustomFunction
Alexa Skill (Developer Portal)
I've then created a skill with a simple Intent:
{
"intents": [
{
"intent": "CustomFunction"
}
]
}
and created an Utterance as:
CustomFunction execute my custom function
In the Configuration section for my skill I have selected the "AWS Lambda ARN (Amazon Resource Name)" option and entered the ARN into the box for North America.
In the Test -> Service Simulator section, I've added "execute my custom function" as the Text and this changes the Lambda Request to show:
{
"session": {
"sessionId": "SessionId.a3e8aee0-acae-4de5-85df-XXXXXXXXX",
"application": {
"applicationId": "amzn1.ask.skill.XXXXXXXXX"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.XXXXXXXXX"
},
"new": true
},
"request": {
"type": "IntentRequest",
"requestId": "EdwRequestId.445267bd-2b4a-45ef-8566-XXXXXXXXX",
"locale": "en-GB",
"timestamp": "2016-11-27T22:54:07Z",
"intent": {
"name": "RunWOL",
"slots": {}
}
},
"version": "1.0"
}
but when I run the test I get the following error:
The remote endpoint could not be called, or the response it returned was invalid.
Does anyone have any ideas on why the skill can't connect to the function?
Thanks

The Service Simulator built into the Amazon Alexa Developer Console has known issues. Try copying the JSON generated by the Simulator and pasting it into your lambda function's test event. To access lambda's test events first find the blue 'Test' button. Next to that button select the (Actions Drop down menu) -> (Configure Test Event) -> Paste the provided JSON into the code area -> (Save and Test). Lambda's built in testing features are much more reliable than Alexa's.
If this does not solve the problem lambda's testing event returns a complete stackTrace and error codes. It becomes much easier to trouble shoot when every error isn't "The remote endpoint could not be called, or the response it returned was invalid."
{
"session": {
"sessionId": "SessionId.a3e8aee0-acae-4de5-85df-XXXXXXXXX",
"application": {
"applicationId": "amzn1.ask.skill.XXXXXXXXX"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.XXXXXXXXX"
},
"new": true
},
"request": {
"type": "IntentRequest",
"requestId": "EdwRequestId.445267bd-2b4a-45ef-8566-XXXXXXXXX",
"locale": "en-GB",
"timestamp": "2016-11-27T22:54:07Z",
"intent": {
"name": "RunWOL",
"slots": {}
}
},
"version": "1.0"
}

​While uploading .zip, do not compress the folder into .zip.
Instead, go into the folder, select package.json, index.js and node modules & then compress them and then upload the .zip.

This error message is very broad and may imply a lot of different issues. I was getting this error and in my case it was a timeout issue. How long does that website you are pinging taking to respond? The timeout doesn't seem to be properly documented, see my original question here: Troubleshooting Amazon's Alexa Skill Kit (ASK) Lambda interaction

Related

Spring cloud function routing api gateway null pointer exception

I have a problem with routing using API Gateway headers. I am using org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest as a handler request. I have two functions, they work locally. They work if I set environment variable.
If I use API Gateway headers (spring.cloud.function.definition:lowercase), I get:
{
"errorMessage": "java.lang.NullPointerException",
"errorType": "java.lang.NullPointerException",
"stackTrace": [
"org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateMessage(AWSLambdaUtils.java:123)",
"org.springframework.cloud.function.adapter.aws.FunctionInvoker.handleRequest(FunctionInvoker.java:105)",
"java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
"java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)",
"java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)",
"java.base/java.lang.reflect.Method.invoke(Unknown Source)"
]
}
Example code reproducing the issue is here: https://github.com/cygi/cloudexample
POM is based on samples from Spring Cloud Function codebase (example code (https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-aws-routing). Spring Cloud Function version is 3.2.1 (sample had a SNAPSHOT version, that uses JAVA 11, which is not available in AWS Lambda, at least without docker).
Reverting to Spring Cloud Function 3.1.6 has resolved the problem.
Test event for AWS Lambda:
{
"body": "foo",
"httpMethod": "POST",
"isBase64Encoded": false,
"headers": {
"spring.cloud.function.definition": "uppercase"
}
}
Result on 3.2.2
{
"statusCode": 417,
"headers": null,
"body": "Failed to establish route, since neither were provided: 'spring.cloud.function.definition' as Message header or as application property or 'spring.cloud.function.routing-expression' as application property."
}
Result on 3.1.6
{
"isBase64Encoded": false,
"headers": {
"id": "758c1873-9377-25af-5ca2-84f55710ff2a",
"contentType": "application/json",
"timestamp": "1644500775689"
},
"body": "\"bbbb\"",
"statusCode": 200
}

Where is the GCP Cloud Scheduler HTTP body?

I am trying to work with a cron job on GCP Cloud Scheduler. I am using the HTTP target with the "GET" method.
I am trying to post messages to a discord channel but first need to GET the body my server webhook sends back to me. The CRON job runs successfully but I cannot find the body of what the webhook returned on the GCP Cloud Scheduler. I have checked the logs as well, it does not contain the body. Here is what the log has:
{
"insertId": "a06j1cfzy21xe",
"jsonPayload": {
"targetType": "HTTP",
"jobName": "projects/website-274422/locations/us-central1/jobs/discord_sec_bot",
"url": "https://discordapp.com/api/webhooks/<redacted>/<redacted>",
"#type": "type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished"
},
"httpRequest": {
"status": 200
},
"resource": {
"type": "cloud_scheduler_job",
"labels": {
"project_id": "website-274422",
"job_id": "discord_sec_bot",
"location": "us-central1"
}
},
"timestamp": "2020-08-10T21:42:13.290867117Z",
"severity": "INFO",
"logName": "projects/website-274422/logs/cloudscheduler.googleapis.com%2Fexecutions",
"receiveTimestamp": "2020-08-10T21:42:13.290867117Z"
}
Could anyone tell me where I could find what my GET request received?
Although it's not mentioned directly in the documentation I don't think it's possible to see this. I am not sure what do you want to do, however if you need any information to pass to the logs you can use response status. I have done quick test on my cloud function, which was randomly sending response status from 200 to 204.
For each job I get 2 different log items. In the 2nd one there is following field with random status:
httpRequest: {
status: 201
}
According this is only chance to see anything returned by the endpoint to logs. You can use this status to code some information.

How do you properly format the syntax in an AWS System Manager Document using downloadContent sourceInfo StringMap

My goal is to have an AWS System Manager Document download a script from S3 and then run that script on the selected EC2 instance. In this case, it will be a Linux OS.
According to AWS documentation for aws:downloadContent the sourceInfo Input is of type StringMap.
The example code looks like this:
{
"schemaVersion": "2.2",
"description": "aws:downloadContent",
"parameters": {
"sourceType": {
"description": "(Required) The download source.",
"type": "String"
},
"sourceInfo": {
"description": "(Required) The information required to retrieve the content from the required source.",
"type": "StringMap"
}
},
"mainSteps": [
{
"action": "aws:downloadContent",
"name": "downloadContent",
"inputs": {
"sourceType":"{{ sourceType }}",
"sourceInfo":"{{ sourceInfo }}"
}
}
]
}
This code assumes you will run this document by hand (console or CLI) and then enter the sourceInfo in the parameter. When running this document by hand, anything entered in the parameter (an S3 URL) isn't accepted. However, I'm not trying to run this by hand, but rather programmatically and I want to hard code the S3 URL into sourceInfo in mainSteps.
AWS does give an example of syntax that looks like this:
{
"path": "https://s3.amazonaws.com/aws-executecommand-test/powershell/helloPowershell.ps1"
}
I've coded the document action in mainSteps like this:
{
"action": "aws:downloadContent",
"name": "downloadContent",
"inputs": {
"sourceType": "S3",
"sourceInfo":
{
"path": "https://s3.amazonaws.com/bucketname/folder1/folder2/script.sh"
},
"destinationPath": "/tmp"
}
},
However, it doesn't seem to work and I receive this error:
invalid format in plugin properties map[sourceInfo:map[path:https://s3.amazonaws.com/bucketname/folder1/folder2/script.sh] sourceType:S3];
error json: cannot unmarshal object into Go struct field DownloadContentPlugin.sourceInfo of type string
Note: I have seen this post that references how to format it for Windows. I did try it, didn't work and doesn't seem relevant to my Linux needs.
So my questions are:
Do you need a parameter for sourceInfo of type StringMap - something that won't be used within the aws:downloadContent {{ sourceInfo }} mainSteps?
How do you properly format the aws:downloadContent action sourceInfo StringMap in mainSteps?
Thank you for your effort in advance.
I had similar issue as I did not want anyone to type the stuff when running. So I added a default to the download content
"sourceInfo": {
"description": "(Required) Blah.",
"type": "StringMap",
"displayType": "textarea",
"default": {
"path": "https://mybucket-public.s3-us-west-2.amazonaws.com/automation.sh"
}
}

Actionable Message post to Azure Functions or Azure Logic Apps

If I want my Actionable Message to send a HttpPOST to an Azure Function or Azure logic app, how do I get this working?
I have tried the following two senario's with out any luck:
Azure function with Azure Active Directory Authentication. When I call it, I get the following response:
{
"innerErrorCode":"ProviderException",
"innerErrorMessage":null,
"authenticationUrl":null,
"displayMessage":"The action could not be completed."
}
This target URL is registered in the Actionable Email Developer Dashboard.
The function is not even triggered, so the error is coming from
/actions/userid/messages/.../executeAction
call.
Azure function with no authentication, I get the following response:
{
"innerErrorCode":"InvalidTargetUrlException",
"innerErrorMessage":null,
"authenticationUrl":null,
"displayMessage":"Target URL
'https://mysite.azurewebsites.net/api/ActionableMessage' is not allowed."
}
Thanks
Can you share the actionable message json which you are using to send mail?
you need to have a entry in potential action as a input along with followed action e.g. a options multi select represented as:
{
"#type": "ActionCard",
"name": "SelectResource",
"inputs": [
{
"#type": "MultichoiceInput",
"id": "<id_which_will_be_used_for_fetching_value>",
"isRequired": true,
"title": "Pick an option",
"style": "expanded",
"choices": $6
}
],
"actions": [
{
"#type": "HttpPOST",
"name": "Select one of the resource for booking",
"target": "your_azure_function_url",
"body": "{{<id_of_the_input>.value}}" //will be received in function
}
]
}

How to get the name of the stage in an AWS Lambda function linked to API Gateway

I have the following Lambda function configured in AWS Lambda :
var AWS = require('aws-sdk');
var DOC = require('dynamodb-doc');
var dynamo = new DOC.DynamoDB();
exports.handler = function(event, context) {
var item = { id: 123,
foo: "bar"};
var cb = function(err, data) {
if(err) {
console.log(err);
context.fail('unable to update hit at this time' + err);
} else {
console.log(data);
context.done(null, data);
}
};
// This doesn't work. How do I get current stage ?
tableName = 'my_dynamo_table_' + stage;
dynamo.putItem({TableName:tableName, Item:item}, cb);
};
Everything works as expected (I insert an item in DynamoDB every time I call it).
I would like the dynamo table name to depend on the stage in which the lambda is deployed.
My table would be:
my_dynamo_table_staging for stage staging
my_dynamo_table_prod for stage prod
However, how do I get the name of the current stage inside the lambda ?
Edit: My Lambda is invoked by HTTP via an endpoint defined with API Gateway
If you have checked "Lambda Proxy Integration" in your Method Integration Request on API Gateway, you should receive the stage from API Gateway, as well as any stageVariable you have configured.
Here's an example of an event object from a Lambda function invoked by API Gateway configured with "Lambda Proxy Integration":
{
"resource": "/resourceName",
"path": "/resourceName",
"httpMethod": "POST",
"headers": {
"header1": "value1",
"header2": "value2"
},
"queryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"accountId": "123",
"resourceId": "abc",
"stage": "dev",
"requestId": "456",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"apiKey": null,
"sourceIp": "1.1.1.1",
"accessKey": null,
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "agent",
"user": null
},
"resourcePath": "/resourceName",
"httpMethod": "POST",
"apiId": "abc123"
},
"body": "body here",
"isBase64Encoded": false
}
I managed it after much fiddling. Here is a walkthrough:
I assume that you have API Gateway and Lambda configured. If not, here's a good guide. You need part-1 and part-2. You can skip the end of part-2 by clicking the newly introduced button "Enable CORS" in API Gateway
Go to API Gateway.
Click here:
Click here:
Then expand Body Mapping Templates, enter application/json as content type, click the add button, then select mapping template, click edit
And paste the following content in "Mapping Template":
{
"body" : $input.json('$'),
"headers": {
#foreach($param in $input.params().header.keySet())
"$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext),#end
#end
},
"stage" : "$context.stage"
}
Then click the button "Deploy API" (this is important for changes in API Gateway to take effect)
You can test by changing the Lambda function to this:
var AWS = require('aws-sdk');
var DOC = require('dynamodb-doc');
var dynamo = new DOC.DynamoDB();
exports.handler = function(event, context) {
var currentStage = event['stage'];
if (true || !currentStage) { // Used for debugging
context.fail('Cannot find currentStage.' + ' stage is:'+currentStage);
return;
}
// ...
}
Then call your endpoint. You should have a HTTP 200 response, with the following response body:
{"errorMessage":"Cannot find currentStage. stage is:development"}
Important note:
If you have a Body Mapping Template that is too simple, like this: {"stage" : "$context.stage"}, this will override the params in the request. That's why body and headers keys are present in the Body Mapping Template. If they are not, your Lambda has not access to it.
For those who use the serverless framework it's already implemented and they can access to event.stage without any additional configurations.
See this issue for more information.
You can get it from event variable. I logged my event object and got this.
{ ...
"resource": "/test"
"stageVariables": {
"Alias": "beta"
}
}