CodeシリーズとLambdaを利用したデータファイルの自動登録


背景

サービスを提供している場合、マスタデータの登録ってついてまわりますよね
この作業ってトイルに分類されるものだと思っています
自動化できる部分は自動化したいものです

幸いなことに、AWS環境には、CodePipelineやLambdaと自動化への環境は整えられています
細かい作り込みは必要となりましたが、自動化そのものは実現できましたので、ご参考になりましたら

実装関係

使ったサービスやコマンド

  • CodePipeline
  • CodeCommit
  • CodeBuild
  • git
  • SSM(ParameterStore)
  • S3
  • Lambda

CodeCommit

ポイントは1つだけです
出力アーティファクト形式に「完全クローン」を選択してください

CodeBuild

細かい技術の組み合わせとなっています
ポイントとそれに関する説明をしていきます

登録用データファイルの作成

git archiveコマンドでgitで管理しているファイルをzip形式で出力できます
git diffコマンドで特定のCommit間のファイルを特定できます
この2つのコマンドで、前回CommitとHEADの間のファイルをzipファイルに出力できます

buildspec.yml.sh
git archive [ブランチ] `git diff --name-only ${PRE_COMMIT} HEAD --diff-filter=AM` -o ${FILENAME} --worktree-attributes

PRE_COMMITはSSMのパラメータストアに保持するようにしました
下のコマンドで取得しています

buildspec.yml.sh
PRE_COMMIT=$(aws ssm get-parameter --name [パラメータストア名] | jq ".Parameter.Value" | sed -e "s/\"//g")

apiの戻り値のJSONからjqでパラメータストアの値を取得し、sedコマンドでダブルコーテーションを除去しています

--worktree-attributes は、.gitattributesに記載したgit archiveに含めたくないファイルを反映してくれるオプションです

dot.gitattributes
buildspec.yml export-ignore
script/ export-ignore

後は、ファイルをS3に上げて

buildspec.yml.sh
aws s3 cp ${FILENAME} s3://${S3_BUCKET}/${S3_KEY}

最新のcommit番号をパラメータストアに更新し直して、Codeシリーズのタスクは完了です
なお、--overwriteオプションがないとエラーになります

buildspec.yml.sh
- NOW_COMMIT=$(git rev-parse HEAD)
- aws ssm put-parameter --name [パラメータストア名] --value ${NOW_COMMIT} --overwrite

対象のファイルがなかったら

commitするのはデータファイルばかりではないので、登録対象のファイルがない場合もあります
マスタデータの登録を行うLambdaでの対応も出来ますが、無駄にS3にファイルを上げたりLambdaを実行したりするのは嫌だったので、
CodeBuildのbuildspec.ymlにまつわるexitいろいろ を参考に下のshellファイルで処理を止めるようにしました
Dai@FastLabel さん、ありがとうございます

count_target_file.sh
#!/bin/sh
CNT=$(git diff --name-only ${PRE_COMMIT} HEAD --diff-filter=AM -- data | wc -l)
echo $CNT
if [ $CNT -eq 0 ]; then
  exit 1
fi

対象となるマスターファイルはdataディレクトリに置く運用になっています
commitされたファイルをdataディレクトリのものに絞って、その件数が0かどうかで判定するようにしました

Lambdaの起動

後は、S3のPUTイベントで、Lambdaを起動して、LambdaでDynamoDBに登録すれば完了です
Lambdaの処理内容は、Qiitaを読むレベルの方には蛇足になりますので、2点だけ述べておきます

エイリアスを付与したLambdaを実行

開発、ステージング、本番と環境を別に設けているケースがほとんどだと思います
環境ごとに同じLambdaを用意するのは無駄なコストになりますので、devやstg、prdといったエイリアスをつけて
環境を識別するようにしました

lambda.py
Stage = context.invoked_function_arn.split(":")[-1]

unzip先はディレクトリ

S3にアップロードしたファイルはzipファイルなので当然解凍しますが、解凍先のパラメータをファイルと思い込んでいまして、無駄に時間を費やしました
下のpythonコードの最後の行のunzip_dirのところですね
同じ轍を踏みませんように

lambda.py
   with zipfile.ZipFile(zip_file, "r") as z:
        for f_name in z.namelist():
            if f_name.endswith(".csv") or f_name.endswith(".json"):
                z.extract(f_name, unzip_dir)

終わりに

まだ本格的な運用が始まっていないこと、私がshellをあまり書いたことがないことから、不具合やもっと効率の良い書き方もあると思います
ですが、現時点ではやりたかったことを実現できましたので、Qiitaでシェアすることにしました

皆様のトイル撲滅の一助になりましたら