サーバのバックアップをPythonでDropboxに保存した話

個人で利用しているサーバのバックアップを一応外部にとりたいな・・・と、思い立ち、とりあえずDropboxに保存するようにした話です。

なぜDropboxに?

サーバ外に保存しておきたいと思ったときに、どこに保存しておくか?と考えたときに思い浮かんだのは以下の3箇所でした。

  • AWS S3
  • 自宅PC
  • Dropbox

バックアップ完了時にデータを保存したかったので外部から内部アクセスを許可していない自宅PCは一旦却下。そして無料枠が残っていた+API触ってみておこうと思いからDropboxに保存することにしました。

準備

DropboxにAPIを利用してアクセスする場合、アクセストークンを事前に取得しておく必要がありました。

  1. DropboxのMy appsにアクセス
  2. 「Create app」を押す
  3. 「Create a new app on the Dropbox Platform」画面で設定を入力する
    • Choose an API:Dropbox APIを選択(個人アカウントなので必然こちらでした)
    • Choose the type of access you need:App folderを選択(この選択をすると、APIアクセスのデフォルトルートが “/Dropbox/アプリ/アプリ名”になります。
    • Name your app:好きな名前

  4. 作成に成功すると設定画面に遷移
  5. 画面上の「Generate」ボタンを押す
  6. ボタンが表示されていたところに、「アクセストークン」が表示されるのでテキストを保存
  7. SDKのインストール
    $ pip install dropbox
    

これで、Dropboxにアクセスするための準備は完了。

ファイルコピーのためのスクリプト

バックアップ用のファイルを作成するところは割愛して、、コピーする方法はこんな感じ。
(*) バックアップは、”/Dropbox/アプリ/(Dropboxアプリ名)/(サーバ名)”フォルダの下に保存することとします。

以下はスクリプト。

import os
import dropbox

DROPBOX_ACCESS_TOKEN = '(準備で取得したアクセストークン)'
SERVER_NAME = '(バックアップサーバ名)'

def make_dropbox_backup_folder(dbx, server):
    '''サーバのバックアップ保存フォルダを探してない場合はフォルダを作成する.'''
    try:
        is_exits = False
        for entry in dbx.files_list_folder('').entries:
            if (entry.name == server):
                is_exits = True
                break

        if (is_exits == False):
            # サーバフォルダが見つからないので作成
            dbx.files_create_folder('/' + server)

    except:
        print("Error. Make Backup Folder")
        return False

    return True

def upload_file(dbx, server, file):
    '''ファイルアップロード.'''
    name = os.path.basename(file)
    remote = '/' + server + '/' + name

    with open(file, 'rb') as f:
         dbx.files_upload(f.read(), remote)


if (__name__ == "__main__"):
    dbx = dropbox.Dropbox(DROPBOX_ACCESS_TOKEN)
    if (make_dropbox_backup_folder(dbx, SERVER_NAME) == False):
        print('Error. create server folder')
    else:
        upload_backup(dbx, SERVER_NAME, 'daily.tar.gz')

TIPS

dropboxのAPIでは、単純にファイルの存在を確認するメソッドがありません。
このため、サーバ名のフォルダがある場合はそのままアップロード、無い場合(初回)は作成するという処理を作る時に
1. とりあえず作っちゃって存在する場合はエラーさせる
2. ちゃんと検索して確認する
の2方法があります。上記スクリプトでは、(2)の方式を使っていて、

        for entry in dbx.files_list_folder('').entries:
            if (entry.name == server):
                is_exits = True
                break

この部分で検索+確認をしています。
(*)検索するときに、’.’ではなく”を使うみたい。