🐡

FTPサーバからファイルをgetし、S3にputするシェルスクリプト

2024/06/27に公開

背景

アクティブモードに制限された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を使用しました。
https://docs.aws.amazon.com/ja_jp/linux/al2023/ug/deprecated-al2023.html

感想

普段シェルスクリプトはあまり書くことがありませんが、特段設定行わず手軽に実装できるので、
次回以降似たような要件があれば利用していければと思います。

Goals Tech Blog

Discussion