diff --git a/README.md b/README.md index 8053c75..a906109 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,12 @@ # Delibird +Delibird is a URL shortening system with various features such as measurement, password protection, and redirects with digital signatures, in addition to simple redirection. + +This application supports custom domains, enabling domain-specific management pages and user management, and can be implemented with a fully serverless architecture using AWS Lambda. + +It allows you to deploy your own shortened link service with full access to all features, delivering far superior cost performance compared to existing cloud-based shortening services. + +Delibird + ## Requirements @@ -51,4 +59,4 @@ make plan-{environment name} ```bash make apply-{environment name} -``` \ No newline at end of file +``` diff --git a/lambda/build.sh b/lambda/build.sh new file mode 100644 index 0000000..01048be --- /dev/null +++ b/lambda/build.sh @@ -0,0 +1,98 @@ +#!/bin/bash +set -e + +# このスクリプトのディレクトリを取得 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# LAMBDA_NAMEが指定されていればそれを使用、なければエラー +if [ -n "${LAMBDA_NAME}" ]; then + LAMBDA_NAME="${LAMBDA_NAME}" +else + echo "Error: LAMBDA_NAME environment variable is not set." >&2 + exit 1 +fi +LAMBDA_DIR="${SCRIPT_DIR}/${LAMBDA_NAME}" + +# BUILD_OUTPUT_DIRが指定されていればそれを使用、なければエラー +if [ -n "${BUILD_OUTPUT_DIR}" ]; then + BUILD_DIR="${BUILD_OUTPUT_DIR}/${LAMBDA_NAME}" +else + echo "Error: BUILD_OUTPUT_DIR environment variable is not set." >&2 + exit 1 +fi + +echo "Building Fuction: ${LAMBDA_NAME}..." +echo "Output directory: ${BUILD_DIR}" + +# 既存のbuildディレクトリをクリーンアップ +rm -rf "${BUILD_DIR}" +mkdir -p "${BUILD_DIR}" + +# requirements.txtから依存関係をインストール +if [ -f "${LAMBDA_DIR}/requirements.txt" ]; then + echo "Installing dependencies from requirements.txt..." + # Lambdaを/var/taskにマウントして、buildディレクトリを/delibird/outputにマウント + # /delibird/outputを通して、buildディレクトリにパッケージをインストール + docker run --rm \ + -v "${LAMBDA_DIR}":/var/task \ + -v "${BUILD_DIR}":/delibird/output \ + public.ecr.aws/sam/build-python3.13:latest-arm64 \ + pip install -r "requirements.txt" -t "/delibird/output" --upgrade +else + echo "Error: No requirements.txt found" >&2 + exit 1 +fi + +# カスタムコード(ddb, utilなど)をコピー +echo "Copying custom code..." + +# 除外するファイル/ディレクトリのパターン +EXCLUDE_PATTERNS=("__pycache__" "*.pyc" "*.pyo" "*.sh" "*.md" ".git" ".gitignore" "*.txt") + +copied_count=0 +for item in "${LAMBDA_DIR}"/*; do + if [ ! -e "$item" ]; then + continue # ファイルが存在しない場合はスキップ + fi + + item_name=$(basename "$item") + should_exclude=false + + # 除外パターンにマッチするかチェック + for pattern in "${EXCLUDE_PATTERNS[@]}"; do + # shellcheck disable=SC2254 + case "$item_name" in + $pattern) + should_exclude=true + break + ;; + esac + done + + if [ "$should_exclude" = false ]; then + echo "Copying: $item_name" + cp -r "$item" "${BUILD_DIR}/" + ((copied_count++)) + else + echo "Skipping: $item_name" + fi +done + +# コピーされたファイルがあるか確認 +if [ "$copied_count" -eq 0 ]; then + echo "Error: No custom code was copied to ${BUILD_DIR}" >&2 + exit 1 +fi + +echo "Function ${LAMBDA_NAME} build completed successfully." + +# ビルド成果物の内容を表示 +echo "" +echo "Build output contents:" +echo "----------------------" +echo "Python packages:" +ls -lh "${BUILD_DIR}" | head -20 +echo "" +echo "Total size:" +du -sh "${BUILD_DIR}" + diff --git a/lambda/layers/common/build.sh b/lambda/layers/common/build.sh index 1c98738..8762fca 100755 --- a/lambda/layers/common/build.sh +++ b/lambda/layers/common/build.sh @@ -24,7 +24,13 @@ mkdir -p "${PYTHON_DIR}" # requirements.txtから依存関係をインストール if [ -f "${LAYER_DIR}/python/requirements.txt" ]; then echo "Installing dependencies from requirements.txt..." - pip install -r "${LAYER_DIR}/python/requirements.txt" -t "${PYTHON_DIR}" --upgrade + # Lambdaを/var/taskにマウントして、buildディレクトリを/delibird/outputにマウント + # /delibird/outputを通して、buildディレクトリにパッケージをインストール + docker run --rm \ + -v "${LAYER_DIR}/python":/var/task \ + -v "${PYTHON_DIR}":/delibird/output \ + public.ecr.aws/sam/build-python3.13:latest-arm64 \ + pip install -r "requirements.txt" -t "/delibird/output" --upgrade else echo "Error: No requirements.txt found" >&2 exit 1 diff --git a/modules/aws_lambda/function.tf b/modules/aws_lambda/function.tf index b11baa6..ccce1d9 100644 --- a/modules/aws_lambda/function.tf +++ b/modules/aws_lambda/function.tf @@ -1,13 +1,53 @@ +# Lambda Layerのソースディレクトリとビルド出力先 +locals { + lambda_dir = "${path.root}/../../lambda" +} + +# build functions +resource "null_resource" "build_redirect_request" { + triggers = { + files = sha256(join("", [ + for f in fileset("${local.lambda_dir}/redirect_request", "**/*") : + filesha256("${local.lambda_dir}/redirect_request/${f}") + ])) + build_script = filesha256("${local.lambda_dir}/build.sh") + } + + provisioner "local-exec" { + command = "chmod +x ${local.lambda_dir}/build.sh && LAMBDA_NAME=redirect_request BUILD_OUTPUT_DIR=${path.root}/.build ${local.lambda_dir}/build.sh" + working_dir = path.root + } +} + +resource "null_resource" "build_admin_portal" { + triggers = { + files = sha256(join("", [ + for f in fileset("${local.lambda_dir}/admin_portal", "**/*") : + filesha256("${local.lambda_dir}/admin_portal/${f}") + ])) + build_script = filesha256("${local.lambda_dir}/build.sh") + } + + provisioner "local-exec" { + command = "chmod +x ${local.lambda_dir}/build.sh && LAMBDA_NAME=admin_portal BUILD_OUTPUT_DIR=${path.root}/.build ${local.lambda_dir}/build.sh" + working_dir = path.root + } +} + data "archive_file" "redirect_request" { type = "zip" - source_dir = "${path.root}/../../lambda/redirect_request" + source_dir = "${path.root}/.build/redirect_request" output_path = "${path.root}/.build/redirect_request.zip" + + depends_on = [null_resource.build_redirect_request] } data "archive_file" "admin_portal" { type = "zip" - source_dir = "${path.root}/../../lambda/admin_portal" + source_dir = "${path.root}/.build/admin_portal" output_path = "${path.root}/.build/admin_portal.zip" + + depends_on = [null_resource.build_admin_portal] } resource "aws_lambda_function" "redirect_request" {