Skip to content
This repository was archived by the owner on Sep 8, 2021. It is now read-only.

Add a runtime for general trigger event #61

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
php71.zip
php73.zip
php71g.zip
php73g.zip
22 changes: 20 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,25 +1,43 @@
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

all: php71.zip php73.zip
all: php71.zip php73.zip php71g.zip php73g.zip

php71.zip:
docker run --rm -e http_proxy=${http_proxy} -v $(ROOT_DIR):/opt/layer lambci/lambda:build-provided /opt/layer/build.sh

php73.zip:
docker run --rm -e http_proxy=${http_proxy} -v $(ROOT_DIR):/opt/layer lambci/lambda:build-provided /opt/layer/build-php-remi.sh 3

php71g.zip:
docker run --rm -e GENERAL_EVENT=true -e http_proxy=${http_proxy} -v $(ROOT_DIR):/opt/layer lambci/lambda:build-provided /opt/layer/build.sh

php73g.zip:
docker run --rm -e GENERAL_EVENT=true -e http_proxy=${http_proxy} -v $(ROOT_DIR):/opt/layer lambci/lambda:build-provided /opt/layer/build-php-remi.sh 3

upload71: php71.zip
./upload.sh 7.1

upload73: php73.zip
./upload.sh 7.3

upload71g: php71g.zip
./upload.sh 7.1g

upload73g: php73g.zip
./upload.sh 7.3g

publish71: php71.zip
./publish.sh 7.1

publish73: php73.zip
./publish.sh 7.3

publish71g: php71g.zip
./publish.sh 7.1g

publish73g: php73g.zip
./publish.sh 7.3g

clean:
rm -f php71.zip php73.zip
rm -f php71.zip php73.zip php71g.zip php73g.zip

3 changes: 3 additions & 0 deletions bootstrap.generalenv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

PHP_INI_SCAN_DIR=/opt/etc/php.d/:/var/task/etc/php.d/ /opt/bin/php -c /opt/php.ini -d extension_dir=/opt/lib/php/modules /opt/lib/runtime.php
20 changes: 18 additions & 2 deletions build-php-remi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,21 @@ cp /usr/lib64/libonig.so.5 lib/
mkdir -p lib/php/7.${PHP_MINOR_VERSION}
cp -a /usr/lib64/php/modules lib/php/7.${PHP_MINOR_VERSION}/

zip -r /opt/layer/php7${PHP_MINOR_VERSION}.zip .

TARGET_NAME=php7${PHP_MINOR_VERSION}
if [ "${GENERAL_EVENT}" = "true" ]; then
TARGET_NAME=${TARGET_NAME}g

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
./composer.phar global require aws/aws-sdk-php
./composer.phar global clear-cache
cp -a /root/.composer lib/composer
cp /opt/layer/php.ini.generalenv php.ini
mv lib/php/7.${PHP_MINOR_VERSION}/* lib/php/
rmdir lib/php/7.${PHP_MINOR_VERSION}
cp /opt/layer/bootstrap.generalenv bootstrap
cp /opt/layer/lib/*.php lib/
fi

zip -r /opt/layer/${TARGET_NAME}.zip .
19 changes: 18 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,21 @@ cp /usr/lib64/libpq.so.5 lib/

cp -a /usr/lib64/php lib/

zip -r /opt/layer/php71.zip .
TARGET_NAME=php71
if [ "${GENERAL_EVENT}" = "true" ]; then
TARGET_NAME=${TARGET_NAME}g

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"
./composer.phar global require aws/aws-sdk-php
./composer.phar global clear-cache
cp -a /root/.composer lib/composer
cp /opt/layer/php.ini.generalenv php.ini
mv lib/php/7.1/* lib/php/
rmdir lib/php/7.1
cp /opt/layer/bootstrap.generalenv bootstrap
cp /opt/layer/lib/*.php lib/
fi

zip -r /opt/layer/${TARGET_NAME}.zip .
38 changes: 38 additions & 0 deletions lib/LambdaContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

class LambdaContext
{
private $deadlineMs;
private $awsRequestd;
private $invokedFunctionArn;
private $logGroupName;
private $logStreamName;
private $functionName;
private $memoryLimitInMb;
private $functionVersion;
private $identity;
private $clientContext;

public function __get($name)
{
return $this->$name;
}

public function __construct($request)
{
$this->deadlineMs = (int)$request['Lambda-Runtime-Deadline-Ms'];
$this->awsRequestId = $request['Lambda-Runtime-Aws-Request-Id'];
$this->invokedFunctionArn = $request['Lambda-Runtime-Invoked-Function-Arn'];
$this->logGroupName = getenv('AWS_LAMBDA_LOG_GROUP_NAME');
$this->logStreamName = getenv('AWS_LAMBDA_LOG_STREAM_NAME');
$this->functionName = getenv("AWS_LAMBDA_FUNCTION_NAME");
$this->memoryLimitInMb = getenv('AWS_LAMBDA_FUNCTION_MEMORY_SIZE');
$this->functionVersion = getenv('AWS_LAMBDA_FUNCTION_VERSION');
if (isset($request['Lambda-Runtime-Cognito-Identity'])) {
$this->identity = json_decode($request['Lambda-Runtime-Cognito-Identity']);
}
if (isset($request['Lambda-Runtime-Client-Context'])) {
$this->clientContext = json_decode($request['Lambda-Runtime-Client-Context']);
}
}
}
96 changes: 96 additions & 0 deletions lib/LambdaErrors.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

namespace LambdaErrors;

class InvocationError extends \Exception
{
}

class LambdaError extends \Exception
{
protected $errorClass;
protected $errorType;
protected $errorMessage;
protected $stackTrace;

public function __construct(\Throwable $originalError, $classification = 'Function')
{
$this->errorClass = get_class($originalError);
$this->errorType = "{$classification}<{$this->errorClass}>";
$file = $originalError->getFile();
$line = $originalError->getLine();
$message = $originalError->getMessage();
$this->errorMessage = "{$file}({$line}): {$message}";
$this->stackTrace = $this->_sanitize_stacktrace($originalError->getTraceAsString());
parent::__construct($this->errorMessage);
}

public function toLambdaResponse()
{
return [
'errorMessage' => $this->errorMessage,
'errorType' => $this->errorType,
'stackTrace' => $this->stackTrace,
];
}

public function runtimeErrorType()
{
$classification = 'Function<UserException>';
if ($this->_allowedError()) {
$classification = $this->errorType;
}
return $classification;
}

private function _sanitize_stacktrace($stacktrace)
{
$ret = [];
$safeTrace = true;
foreach (array_slice(explode(PHP_EOL, $stacktrace), 0, 100) as $trace) {
if ($safeTrace) {
[$no, $file] = explode(' ', $trace);
if (preg_match('@^/opt/lib/@', $file) === 1) {
$safeTrace = false;
} else {
$ret[] = $trace;
}
}
}
return $ret;
}

private function _allowedError()
{
return $this->_standardError();
}

private function _standardError()
{
return true; // @Todo: To determine standard exception classes.
}
}

class LambdaHandlerError extends LambdaError
{
}

class LambdaHandlerCriticalException extends LambdaError
{
}

class LambdaRuntimeError extends LambdaError
{
public function __construct($originalError)
{
parent::__construct($originalError, 'Runtime');
}
}

class LambdaRuntimeInitError extends LambdaError
{
public function __construct($originalError)
{
parent::__construct($originalError, 'Init');
}
}
46 changes: 46 additions & 0 deletions lib/LambdaHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

class LambdaHandler
{
private $handlerFileName;
private $handlerMethodName;
private $handlerClass;

public function __get($name)
{
if (in_array($name, ['handlerFileName', 'handlerMethodName'])) {
return $this->$name;
} else {
throw new Exception("Cannot access private property {$name}");
}
}

public function __construct($envHandler)
{
$handlerSplit = explode('.', $envHandler);
if (count($handlerSplit) == 2) {
[$this->handlerFileName, $this->handlerMethodName] = $handlerSplit;
} elseif (count($handlerSplit) == 3) {
[$this->handlerFileName, $this->handlerClass, $this->handlerMethodName] = $handlerSplit;
} else {
throw new Exception("Invalid handler {$handlerSplit}, must be of form FILENAME.METHOD or FILENAME.CLASS.METHOD where FILENAME corresponds with an existing PHP source file FILENAME.php, CLASS is an optional module/class namespace and METHOD is a callable method. If using CLASS, METHOD must be a static method.");
}
}

public function callHandler($request, $context)
{
try {
if ($this->handlerClass) {
$fun = "{$this->handlerClass}::{$this->handlerMethodName}";
} else {
$fun = $this->handlerMethodName;
}
$response = call_user_func($fun, $request, $context);
return LambdaMarshaller::marshallResponse($response);
} catch (Error $e) {
throw new LambdaErrors\LambdaHandlerCriticalException($e);
} catch (Exception $e) {
throw new LambdaErrors\LambdaHandlerError($e);
}
}
}
14 changes: 14 additions & 0 deletions lib/LambdaLogger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

class LambdaLogger
{
const STDERR = 'php://stderr';

public static function logError(LambdaErrors\LambdaError $error, $message)
{
if (isset($message)) {
file_put_contents(self::STDERR, $message);
}
file_put_contents(self::STDERR, json_encode($error->toLambdaResponse(), JSON_PRETTY_PRINT));
}
}
31 changes: 31 additions & 0 deletions lib/LambdaMarshaller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

class LambdaMarshaller
{
# By default, JSON-parses the raw request body. This can be overwritten
# by users who know what they are doing.
public static function marshallRequest($rawRequest)
{
$contentType = $rawRequest->getHeader('Content-Type')[0];
if ($contentType == 'application/json') {
return json_decode($rawRequest->getBody()->getContents());
} else {
return $rawRequest->getBody()->getContents(); # return it unaltered
}
}

# By default, just runs #to_json on the method's response value.
# This can be overwritten by users who know what they are doing.
# The response is an array of response, content-type.
# If returned without a content-type, it is assumed to be application/json
# Finally, StringIO/IO is used to signal a response that shouldn't be
# formatted as JSON, and should get a different content-type header.
public static function marshallResponse($methodResponse)
{
if (is_resource($methodResponse) && get_resource_type($methodResponse) == 'stream') {
return [$methodResponse, 'application/unknown'];
} else {
return [json_encode($methodResponse, true), 'application/json'];
}
}
}
Loading