🐡
FTPサーバからファイルをgetし、S3にputするシェルスクリプト
背景
アクティブモードに制限されたFTP用のサーバからファイルを取得する際、固定IPでアクセスする必要がありました。
定期的にサーバにファイルを取り込み、使用しているS3に置きに行くための簡易的なEC2サーバを立ち上げ、シェルスクリプトをAmazon EventBridgeで定期的に叩く暫定対応を行いました。
使用したシェルスクリプトファイル例
#!/bin/bash
# $1 = 日付(デフォルトは実行日)
# AWSパラメータストアに接続情報を配置し、そこから取得するようにしています。
get_ftp_config() {
local param_name=$1
aws ssm get-parameter --name "XXXXXXXX/${param_name}" --with-decryption | jq -r '.Parameter.Value'
}
# FTPサーバーの接続設定
FTP_USER=$(get_ftp_config "user")
FTP_PASS=$(get_ftp_config "password")
FTP_HOST=$(get_ftp_config "host")
FTP_PORT=$(get_ftp_config "port")
MY_PUBLIC_IP=$(curl -s ifconfig.me)
S3_BUCKET="s3://XXXXXXXX/"
# 日付オプションがなければ、今日の日付を取得
TARGET_DATE=${1:-$(TZ='Asia/Tokyo' date +%Y%m%d)}
# ダウンロードするファイルのパス
FTP_FILE_PATH="./${TARGET_DATE}_XXXXXXXX.csv"
# ローカルにダウンロードするパス
LOCAL_FILE_PATH="/XXXXXXXX/${TARGET_DATE}.csv"
# S3バケットのパス
S3_BUCKET_PATH="${S3_BUCKET}/XXXXXXXX/${TARGET_DATE}.csv"
# Slackにエラーメッセージを送る関数
send_error_to_slack() {
local webhook_url="https://hooks.slack.com/services/XXXXXXXX"
local payload=$1
curl -X POST -H 'Content-type: application/json' --data "${payload}" "${webhook_url}"
# エラーで終了
exit 1
}
# FTPからファイルをダウンロード
lftp -u $FTP_USER,$FTP_PASS ftp://$FTP_HOST:$FTP_PORT -e "set ftp:passive-mode off;set ftp:port-ipv4 $MY_PUBLIC_IP" <<EOF
get $FTP_FILE_PATH -o $LOCAL_FILE_PATH
bye
EOF
# ファイルをS3にアップロード
if [ -f $LOCAL_FILE_PATH ]; then
FILE_SIZE=$(stat -c%s "$LOCAL_FILE_PATH")
# ファイルサイズが1バイト以下の場合、Slackに通知
if [ $FILE_SIZE -le 1 ]; then
send_error_to_slack "{\"text\": \"$FTP_FILE_PATH のcsvファイルが空です。user: $FTP_USER\"}"
fi
aws s3 cp $LOCAL_FILE_PATH $S3_BUCKET_PATH
# ローカルファイルを削除
rm $LOCAL_FILE_PATH
else
send_error_to_slack "{\"text\": \"$FTP_FILE_PATH のダウンロードに失敗しました。user: $FTP_USER\"}"
fi
Amazon EventBridge設定
- Amazon EventBridge > ルール へ遷移
- ルールを作成ボタンを押下
- ルールの詳細を定義(スケジュールを選択し、続行してルールを作成するを押下)
- スケジュールを定義
- ターゲットを選択
- 今回の場合の設定例
- 今回の場合の設定例
- 入力内容を確認し、ルールの作成を押下
補足
接続先のFTPサーバにファイルがなかった場合や、CSVファイルの中身が空であった場合は、
Slackチャンネルに通知し検知できるようにしています。
定時実行にはcronを利用しようと思ったのですが、AmazonLinux2023で非推奨となっていたので、Amazon EventBridgeを使用しました。
感想
普段シェルスクリプトはあまり書くことがありませんが、特段設定行わず手軽に実装できるので、
次回以降似たような要件があれば利用していければと思います。
Discussion