さくらのVPSのバックアップファイルをGoolge Driveに自動転送するスクリプトを作りました。容量オーバーにならないように古いファイルを削除する処理も組み込みました。
スクリプト
■ remoteBackup.py
#!/usr/bin/python # coding: UTF-8 import os, time, re import gDriveAccess def backup_files(filename_pattern_str, from_days): today = time.localtime() today_epoch_delta = time.mktime(today) from_day_epoch_delta = today_epoch_delta - from_days*24*60*60 src_dir = os.getcwd() files = os.listdir(src_dir) ret_files = [] for file in files: file_upd_time = os.path.getmtime(file) filename = os.path.basename(file) if file_upd_time <= from_day_epoch_delta: continue if re.search(filename_pattern_str, filename): ret_files.append(filename) return ret_files #------------------------------------------------------------------------------ # Connect to Google Drive #------------------------------------------------------------------------------ drive_service = gDriveAccess.build_service() #------------------------------------------------------------------------------ # Delete old backup files in Google Drive #------------------------------------------------------------------------------ query = "title contains 'www'" #'contains' means 'start with' query += " and mimeType = 'application/x-tar-gz'" query += " and modifiedDate <'" + gDriveAccess.threshold_date_str(2) + "'" files = gDriveAccess.retrieve_files(drive_service, query) for item in files: print "delete file = %s, %s, %s" % (item["title"], item["id"], item["modifiedDate"]) gDriveAccess.delete_file(drive_service, item["id"]) #------------------------------------------------------------------------------ # Transfer backup files to Google Drive #------------------------------------------------------------------------------ files = backup_files("gz$", 1) for filename in files: print "backup file = %s" % filename gDriveAccess.upload_file(drive_service, filename, 'application/x-tar-gz')
処理内容
- Google Driveに接続
- Google Driveにある古いバックアップファイルを削除
- 当日分のバックアップファイルをGoogle Driveに転送
■ gDriveAccess.py
Google Driveに簡単にアクセスするためのモジュールです。
#!/usr/bin/python # coding: UTF-8 import httplib2 from oauth2client.client import OAuth2WebServerFlow from apiclient.discovery import build from apiclient.http import MediaFileUpload from apiclient import errors import gDriveCredential import logging logging.basicConfig() CLIENT_ID = '********.apps.googleusercontent.com' CLIENT_SECRET = '****************' OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive' REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob' def first_authorize(): flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE, REDIRECT_URI) authorize_url = flow.step1_get_authorize_url() print 'Go to the following link in your browser: ' + authorize_url code = raw_input('Enter verification code: ').strip() credentials = flow.step2_exchange(code) gDriveCredential.store_credentials(credentials) return credentials def build_service(): logging.getLogger().setLevel(getattr(logging, 'ERROR')) try: credentials = gDriveCredential.get_stored_credentials() if credentials is None or credentials.invalid: credentials = first_authorize() except Exception, e: credentials = first_authorize() # Connect to Google Drive http = httplib2.Http() http = credentials.authorize(http) drive_service = build('drive', 'v2', http=http) return drive_service def upload_file(service, filename, file_mimetype): logging.getLogger().setLevel(getattr(logging, 'ERROR')) try: credentials = gDriveCredential.get_stored_credentials() if credentials is None or credentials.invalid: credentials = first_authorize() except Exception, e: credentials = first_authorize() # Upload a file media_body = MediaFileUpload(filename, mimetype=file_mimetype, resumable=True) body = { 'title': filename, 'description': 'sakuraVPS', 'mimeType': file_mimetype } file = service.files().insert(body=body, media_body=media_body).execute() def retrieve_files(service, query): """Retrieve a list of File resources. Args: service: Drive API service instance. Returns: List of File resources. """ result = [] page_token = None while True: try: param = {} if page_token: param['pageToken'] = page_token param['q'] = query # print "param = ", param files = service.files().list(**param).execute() result.extend(files['items']) page_token = files.get('nextPageToken') if not page_token: break except errors.HttpError, error: print 'An error occurred: %s' % error break return result def delete_file(service, file_id): """Permanently delete a file, skipping the trash. Args: service: Drive API service instance. file_id: ID of the file to delete. """ try: service.files().delete(fileId=file_id).execute() except errors.HttpError, error: print 'An error occurred: %s' % error def threshold_date_str(days_before): import time today = time.localtime() today_epoch_delta = time.mktime(today) return_day_epoch_delta = today_epoch_delta - days_before*24*60*60 return time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(return_day_epoch_delta))
事前設定
次の変数に、https://code.google.com/apis/consoleで作成したOAuth 2.0 client の値を設定して使用します。
- CLIENT_ID
- CLIENT_SECRET
■ gDriveCredential.py
認証情報を保存して再利用するためのモジュールです。
import httplib2 import oauth2client.client CREDENTIAL_FILE = 'jsonCredential.txt' def storeJsonCredential(jsonStr): f = open(CREDENTIAL_FILE, 'w') f.write(jsonStr) f.close() def readJsonCredential(): f = open(CREDENTIAL_FILE) json_credential = f.read() f.close() return json_credential def get_stored_credentials(): """Retrieved stored credentials for the provided user ID. Args: user_id: User's ID. Returns: Stored oauth2client.client.OAuth2Credentials if found, None otherwise. Raises: NotImplemented: This function has not been implemented. """ json_credential = readJsonCredential() return oauth2client.client.Credentials.new_from_json(json_credential) def store_credentials(credentials): """Store OAuth 2.0 credentials in the application's database. This function stores the provided OAuth 2.0 credentials using the user ID as key. Args: user_id: User's ID. credentials: OAuth 2.0 credentials to store. Raises: NotImplemented: This function has not been implemented. """ json_credential = credentials.to_json() storeJsonCredential(json_credential)
使い方
上記のスクリプトをバックアップファイルのあるディレクトリに保存して、remoteBackup.pyを実行します。
前提条件
バックアップファイルは、毎日次のようなファイル名で保存されることを想定しています。
-rwxr-xr-x 1 root root 1172599580 1月 24 03:11 2013 wwwbackup-2013-01-24.tar.gz -rwxr-xr-x 1 root root 1172592143 1月 25 03:11 2013 wwwbackup-2013-01-25.tar.gz -rwxr-xr-x 1 root root 1173426517 1月 26 03:11 2013 wwwbackup-2013-01-26.tar.gz -rwxr-xr-x 1 root root 1177605759 1月 27 03:11 2013 wwwbackup-2013-01-27.tar.gz -rwxr-xr-x 1 root root 1178057670 1月 28 03:11 2013 wwwbackup-2013-01-28.tar.gz -rwxr-xr-x 1 root root 1178319271 1月 29 03:11 2013 wwwbackup-2013-01-29.tar.gz -rwxr-xr-x 1 root root 1178883881 1月 30 03:12 2013 wwwbackup-2013-01-30.tar.gz
注意事項
1回目の実行時は手動でアクセス認証する必要があります。(cf. pythonでGoogle Driveにファイル転送)
その時、認証情報が次のファイルに保存されます。
- jsonCredential.txt
2回目以降の実行は、保存された認証情報を使用するので自動でファイル転送・削除処理が行われます。
Google Drive内のファイルへのアクセス
Googleのドキュメント
ファイル検索
remoteBackup.pyで、削除するファイルを選択するために検索フィルターを設定しています。
query = "title contains 'www'"
“Search for Files”にファイル検索時に使えるキーワードが記述されています。しかし、曖昧検索に関する詳細な記述がなく、containsキーワードがそれっぽいですが、試してみたところ、containsキーワードは先頭一致のようです。
関連記事
- 2013/01/24 Google Drive APIのクイックスタート
- 2013/01/27 pythonでファイル入出力
- 2013/01/28 pythonでGoogle Driveにファイル転送
- 2013/01/31 pythonで日付によるファイルの選別