さくらの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で日付によるファイルの選別