LoginSignup
1
2

More than 5 years have passed since last update.

curlでFTPのファイル送信前後でFTPコマンドを実行する

Posted at

背景

Javaアプリケーションでwarファイルを作ったらデプロイしたいわけです。
しかし、某システムがデプロイに事実上FTP(S)しかまともに出来ない残念仕様なので、FTP(S)で色々やらないといけないわけです。

そしてFTPは色々コマンドが実行できるはずなんですが、困ったことにftpクライアントが入ってない環境なんですね。

代替として目を付けたのがcurlでした。

やり方

なんとcurlは-Q --quoteオプションでファイルを送る前後でFTPの操作ができます。

curl --helpだけ見ると-Q送る前に実行する以外には書いてないんですが、上記のドキュメント通り、FTPコマンドの先頭に-(ハイフン)を付けると送った後に実行するFTPコマンドが書けます。(manコマンド?入ってないですね。。。)
また、FTPコマンド失敗時はそのままだとそこで終了してしまうのですが、*(アスタリスク)を先頭につけると、成否を無視してくれます。

やってみましょう。

ユースケースとしては、一時ファイルとしてアップロードした後、リネームする感じです。
FTPはアップロード時は、アップロード先のファイルを置き換えるのではなく、上書きするようにしてアップロードします。なので、アップロード最中のファイルを見てしまう可能性があります。これが嫌な場合に使います。

例えば以下のようなシェルスクリプトを書きます。
これは引数で取るようにしてますが、Jenkins等なら特定のファイルパスで決め打ちでもよいでしょう。

#!/bin/bash

# usage) bash this.sh FILE FTP_FILEPATH
#   eg.) bash this.sh test.dat /path/to/test.dat

set -ue

UPLOAD_FILEPATH=$1
FTP_FILEPATH=$2

FTP_HOST=ftp.host.dummy
FTP_USER=ftp-user
FTP_PASS=ftp-password

# 一時ファイル
TEMP_FTP_FILEPATH="${FTP_FILEPATH}.temp"


# curl コマンド。--quoteの内容が肝。
curl \
  -v --fail --ftp-ssl \
  -T "${UPLOAD_FILEPATH}" \
  -u "${FTP_USER}:${FTP_PASS}" \
  "ftps://${FTP_HOST}${TEMP_FTP_FILEPATH}" \
  --quote "-*DELE $FTP_FILEPATH" \
  --quote "-RNFR $TEMP_FTP_FILEPATH" \
  --quote "-RNTO $FTP_FILEPATH"

--quoteを複数並べるとその順序で実行してくれるようです。

また、DELEする理由は、RNTOは既に存在する場合に失敗する可能性があったため書いています。
環境によっては置き換えが出来る場合があるので、その場合はDELEの行は不要です。

(おまけ)nssのバージョンによっては失敗する

FTPS接続するときに、TLSの1.2以上でないと接続できないようなサーバの時に遭遇。

手元でcurlコマンドが動くことを確認してから、別の環境で実行したら以下のようなログ(-vオプション付き)が出て、失敗していた。

curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp 
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz 
* About to connect() to xxxxxxxxx.net port 990 (#0)
*   Trying XXX.XXX.XXX.XXX... connected
* Connected to xxxxxxxxx.net (XXX.XXX.XXX.XXX) port 990 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* NSS error -5938
* Closing connection #0
* SSL connect error

手元や他のサーバのcurlではうまくいくのと、接続先はTLSの1.2以上でないとNGというのはわかっていたので、多分バージョンが古くてTLS1.2に対応できてないとかそういうのかな、と考えた。

# cat /etc/redhat-release 
CentOS release 6.6 (Final)

古い。Curlのバージョンを見てみましょう。

# curl --version
curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp 
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz 

古い。NSSを使っているらしいので、NSSのバージョンも見る。

# yum list nss curl
読み込んだプラグイン:fastestmirror
Loading mirror speeds from cached hostfile
 * base: ftp.tsukuba.wide.ad.jp
 * extras: ftp.tsukuba.wide.ad.jp
 * updates: ftp.tsukuba.wide.ad.jp
インストール済みパッケージ
curl.x86_64                                                                       7.19.7-37.el6_5.3                                                                        @anaconda-CentOS-201410241409.x86_64/6.6
nss.x86_64                                                                        3.16.1-14.el6                                                                            @anaconda-CentOS-201410241409.x86_64/6.6
利用可能なパッケージ
curl.x86_64                                                                       7.19.7-53.el6_9                                                                          base                                    
nss.i686                                                                          3.36.0-8.el6                                                                             base                                    
nss.x86_64                                                                        3.36.0-8.el6                                                                             base    

古い。試しにnssだけアップデート。

yum update -y nss

これで動いた。

なんでダメかはよくわからなかったけど、nss tls1.2とか"NSS error -5938"で調べると軒並み「アップデートしなさい」という対応がでてくるので、多分そういうことなんでしょう。(思考放棄)

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2