Skip to content

Commit

Permalink
add support for AWS Lambda layers & some deployment hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
d8vjork committed Oct 19, 2023
1 parent 666b0f9 commit c0e3194
Showing 1 changed file with 72 additions and 2 deletions.
74 changes: 72 additions & 2 deletions src/Commands/DeployLocal.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

namespace OpenSoutheners\SidecarLocal\Commands;

use Hammerstone\Sidecar\Clients\LambdaClient;
use Hammerstone\Sidecar\Sidecar;
use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Yaml\Yaml;
use ZipArchive;

class DeployLocal extends Command
{
Expand Down Expand Up @@ -54,7 +56,7 @@ public function handle(): int
return $this->stopDocker($fullPath);
}

if (! $this->writeComposeFile($fullPath, $this->buildYamlServices())) {
if (! $this->writeComposeFile($fullPath, $this->buildYamlServices($fullPath))) {
$this->error('Error writing the docker-compose.yml file.');

return 3;
Expand All @@ -72,14 +74,23 @@ public function handle(): int
/**
* Build function services array to be written by Yaml dumper.
*/
protected function buildYamlServices(): array
protected function buildYamlServices(string $basePath): array
{
/** @var array<\Hammerstone\Sidecar\LambdaFunction> $sidecarFunctions */
$sidecarFunctions = Sidecar::instantiatedFunctions();
$services = [];

foreach ($sidecarFunctions as $lambdaFunction) {
$lambdaFunction->beforeDeployment();

$functionClassName = class_basename(get_class($lambdaFunction));
$functionLayers = $lambdaFunction->layers();
$functionLayersPath = null;

if (count($functionLayers) > 0) {
$functionLayersPath = $this->grabFunctionRequiredLayers($basePath, $functionClassName, $functionLayers);
}

$functionAwsCallName = $lambdaFunction->nameWithPrefix();
$serviceName = Str::snake(Str::remove('-', $functionClassName));

Expand Down Expand Up @@ -108,11 +119,70 @@ protected function buildYamlServices(): array
"traefik.http.services.{$serviceName}.loadbalancer.server.port=8080",
],
];

if ($functionLayersPath) {
$services[$serviceName]['volumes'][] = $functionLayersPath;
}
}

return $services;
}

/**
* Get function required Lambda layers from AWS cloud.
*/
protected function grabFunctionRequiredLayers(string $basePath, string $functionClass, array $arns): string
{
// We need to set environment any value rather than "local"
// to be able to grab layers from AWS cloud.
config(['sidecar.env' => 'deploying']);

$zipArchive = new ZipArchive();

$functionLayerDirectory = "{$basePath}/layers/{$functionClass}";
$this->filesystem->ensureDirectoryExists($functionLayerDirectory);

$progressBar = $this->getOutput()->createProgressBar(count($arns));
$progressBar->start();

foreach ($arns as $arn) {
$layerDirectoryName = Str::of($arn)->afterLast(':layer:')->replaceLast(':', '/');
$layerZipFileName = $layerDirectoryName->afterLast('/')->append('.zip')->value();
$layerDirectoryName = $layerDirectoryName->value();

$layerTmpDirectoryPath = storage_path("tmp/layers/{$layerDirectoryName}");
$this->filesystem->ensureDirectoryExists($layerTmpDirectoryPath);
$layerTmpFilePath = "{$layerTmpDirectoryPath}/{$layerZipFileName}";

if (! $this->filesystem->exists($layerTmpFilePath)) {
$layerData = app(LambdaClient::class)->getLayerVersionByArn(['Arn' => $arn])->toArray();

$layerLocation = data_get($layerData, 'Content.Location');

if (! $layerLocation || ! $this->filesystem->copy($layerLocation, $layerTmpFilePath)) {
$this->warn("Cannot download layer for function '{$functionClass}'.");

continue;
}
}

$zipArchive->open($layerTmpFilePath);
$zipArchive->extractTo($functionLayerDirectory);
$zipArchive->close();

$progressBar->advance();
}

$progressBar->clear();

config(['sidecar.env' => 'local']);

return Str::of($functionLayerDirectory)
->replaceFirst($basePath, '.')
->append(':/opt:ro')
->value();
}

/**
* Write Docker compose file functions as services and base HTTP proxy.
*/
Expand Down

0 comments on commit c0e3194

Please sign in to comment.