Skip to content

Commit cb7a9b1

Browse files
committed
make s3 upload work
1 parent 7c7da82 commit cb7a9b1

File tree

5 files changed

+46
-22
lines changed

5 files changed

+46
-22
lines changed

conf/mongodb-consistent-backup.example.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,12 @@ production:
4949
method: none
5050
# remove_uploaded: [true|false] (default: false)
5151
# s3:
52+
# region: [AWS S3 Region] (default: us-east-1)
5253
# access_key: [AWS S3 Access Key]
5354
# secret_key: [AWS S3 Secret Key]
5455
# bucket_name: [AWS S3 Bucket Name]
5556
# bucket_prefix: [prefix] (default: /)
5657
# threads: [1+] (default: 1 per CPU)
58+
# secure: [true|false] (default: true)
59+
# retries: [1+] (default: 5)
60+
# acl: [acl_str] (default: none)

mongodb_consistent_backup/Upload/S3/S3.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,31 @@ def _reduce_method(m):
2424

2525
class S3(Task):
2626
def __init__(self, manager, config, timer, base_dir, backup_dir, **kwargs):
27-
super(Nsca, self).__init__(self.__class__.__name__, manager, config, timer, base_dir, backup_dir, **kwargs)
27+
super(S3, self).__init__(self.__class__.__name__, manager, config, timer, base_dir, backup_dir, **kwargs)
2828
self.remove_uploaded = self.config.upload.remove_uploaded
29-
self.s3_host = self.config.upload.s3.host
29+
self.region = self.config.upload.s3.region
3030
self.bucket_name = self.config.upload.s3.bucket_name
3131
self.bucket_prefix = self.config.upload.s3.bucket_prefix
3232
self.access_key = self.config.upload.s3.access_key
3333
self.secret_key = self.config.upload.s3.secret_key
3434
self.thread_count = self.config.upload.s3.threads
3535
self.chunk_size_mb = self.config.upload.s3.chunk_size_mb
3636
self.chunk_size = self.chunk_size_mb * 1024 * 1024
37+
self.secure = self.config.upload.s3.secure
38+
self.retries = self.config.upload.s3.retries
39+
self.s3_acl = self.config.upload.s3.acl
3740

38-
self.key_prefix = None
41+
self.key_prefix = base_dir
3942
if 'key_prefix' in self.args:
4043
self.key_prefix = key_prefix
4144

4245
self._pool = None
4346
self._multipart = None
4447
self._upload_done = False
45-
if None in (self.access_key, self.secret_key,self.s3_host):
46-
raise "Invalid S3 security key or host detected!"
48+
if None in (self.access_key, self.secret_key, self.region):
49+
raise "Invalid S3 security key or region detected!"
4750
try:
48-
self.s3_conn = S3Session(self.access_key, self.secret_key, self.s3_host)
51+
self.s3_conn = S3Session(self.region, self.access_key, self.secret_key, self.bucket_name)
4952
self.bucket = self.s3_conn.get_bucket(self.bucket_name)
5053
except Exception, e:
5154
raise OperationError(e)
@@ -57,15 +60,18 @@ def run(self):
5760
try:
5861
self.timer.start(self.timer_name)
5962
for file_name in os.listdir(self.backup_dir):
63+
file_path = os.path.join(self.backup_dir, file_name)
64+
# skip mongodb-consistent-backup_META dir
65+
if os.path.isdir(file_path):
66+
continue
67+
file_size = os.stat(file_path).st_size
68+
chunk_count = int(ceil(file_size / float(self.chunk_size)))
69+
6070
if self.bucket_prefix == "/":
6171
key_name = "/%s/%s" % (self.key_prefix, file_name)
6272
else:
6373
key_name = "%s/%s/%s" % (self.bucket_prefix, self.key_prefix, file_name)
6474

65-
file_path = os.path.join(self.backup_dir, file_name)
66-
file_size = os.stat(file_path).st_size
67-
chunk_count = int(ceil(file_size / float(self.chunk_size)))
68-
6975
logging.info("Starting multipart AWS S3 upload to key: %s%s using %i threads, %imb chunks, %i retries" % (
7076
self.bucket_name,
7177
key_name,
@@ -82,9 +88,9 @@ def run(self):
8288
part_num = i + 1
8389
self._pool.apply_async(S3UploadThread(
8490
self.bucket_name,
91+
self.region,
8592
self.access_key,
8693
self.secret_key,
87-
self.s3_host,
8894
self._multipart.id,
8995
part_num,
9096
file_path,
@@ -99,7 +105,8 @@ def run(self):
99105
if len(self._multipart.get_all_parts()) == chunk_count:
100106
self._multipart.complete_upload()
101107
key = self.bucket.get_key(key_name)
102-
key.set_acl(self.s3_acl)
108+
if self.s3_acl:
109+
key.set_acl(self.s3_acl)
103110
self._upload_done = True
104111

105112
if self.remove_uploaded:

mongodb_consistent_backup/Upload/S3/S3Session.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,26 @@
22

33
import boto
44
import boto.s3
5+
from boto.s3.connection import OrdinaryCallingFormat, SubdomainCallingFormat
56

67
from mongodb_consistent_backup.Errors import OperationError
78

89
class S3Session:
9-
def __init__(self, access_key, secret_key, s3_host='s3.amazonaws.com', secure=True, num_retries=5, socket_timeout=15):
10+
def __init__(self, region, access_key, secret_key, bucket_name, secure=True, num_retries=5, socket_timeout=15):
11+
self.region = region
1012
self.access_key = access_key
1113
self.secret_key = secret_key
12-
self.s3_host = s3_host
1314
self.secure = secure
1415
self.num_retries = num_retries
1516
self.socket_timeout = socket_timeout
1617

18+
# monkey patch for bucket_name with dots
19+
# https://github.com/boto/boto/issues/2836
20+
if self.secure and '.' in bucket_name:
21+
self.calling_format = OrdinaryCallingFormat()
22+
else:
23+
self.calling_format = SubdomainCallingFormat()
24+
1725
for section in boto.config.sections():
1826
boto.config.remove_section(section)
1927
boto.config.add_section('Boto')
@@ -33,11 +41,12 @@ def connect(self):
3341
if not self._conn:
3442
try:
3543
logging.debug("Connecting to AWS S3 with Access Key: %s" % self.access_key)
36-
self._conn = boto.s3.S3Connection(
37-
self.access_key,
38-
self.secret_key,
39-
host=self.s3_host,
40-
is_secure=self.secure
44+
self._conn = boto.s3.connect_to_region(
45+
self.region,
46+
aws_access_key_id=self.access_key,
47+
aws_secret_access_key=self.secret_key,
48+
is_secure=self.secure,
49+
calling_format=self.calling_format
4150
)
4251
logging.debug("Successfully connected to AWS S3 with Access Key: %s" % self.access_key)
4352
except Exception, e:

mongodb_consistent_backup/Upload/S3/S3UploadThread.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66

77

88
class S3UploadThread:
9-
def __init__(self, bucket_name, access_key, secret_key, s3_host, multipart_id, part_num, file_name, offset,
9+
def __init__(self, bucket_name, region, access_key, secret_key, multipart_id, part_num, file_name, offset,
1010
byte_count, retries=5, secure=True):
1111
self.bucket_name = bucket_name
12+
self.region = region
1213
self.access_key = access_key
1314
self.secret_key = secret_key
14-
self.s3_host = s3_host
1515
self.multipart_id = multipart_id
1616
self.part_num = part_num
1717
self.file_name = file_name
@@ -21,7 +21,7 @@ def __init__(self, bucket_name, access_key, secret_key, s3_host, multipart_id, p
2121
self.secure = secure
2222

2323
try:
24-
self.s3_conn = S3Session(self.access_key, self.secret_key, self.s3_host, self.secure, self.retries)
24+
self.s3_conn = S3Session(self.region, self.access_key, self.secret_key, self.bucket_name, self.secure, self.retries)
2525
self.bucket = self.s3_conn.get_bucket(self.bucket_name)
2626
except Exception, e:
2727
logging.fatal("Could not get AWS S3 connection to bucket %s! Error: %s" % (self.bucket_name, e))
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
from S3 import S3
22

33
def config(parser):
4+
parser.add_argument("--upload.s3.region", dest="upload.s3.region", help="S3 Uploader AWS region to connect to (default: us-east-1)", default="us-east-1", type=str)
45
parser.add_argument("--upload.s3.access_key", dest="upload.s3.access_key", help="S3 Uploader AWS Access Key (required for S3 upload)", type=str)
56
parser.add_argument("--upload.s3.secret_key", dest="upload.s3.secret_key", help="S3 Uploader AWS Secret Key (required for S3 upload)", type=str)
67
parser.add_argument("--upload.s3.bucket_name", dest="upload.s3.bucket_name", help="S3 Uploader destination bucket name", type=str)
78
parser.add_argument("--upload.s3.bucket_prefix", dest="upload.s3.bucket_prefix", help="S3 Uploader destination bucket path prefix", type=str)
89
parser.add_argument("--upload.s3.threads", dest="upload.s3.threads", help="S3 Uploader upload worker threads (default: 4)", default=4, type=int)
910
parser.add_argument("--upload.s3.chunk_size_mb", dest="upload.s3.chunk_size_mb", help="S3 Uploader upload chunk size, in megabytes (default: 50)", default=50, type=int)
11+
parser.add_argument("--upload.s3.secure", dest="upload.s3.secure", help="S3 Uploader connect over SSL (default: true)", default=True, action="store_false")
12+
parser.add_argument("--upload.s3.retries", dest="upload.s3.retries", help="S3 Uploader retry times (default: 5)", default=5, type=int)
13+
parser.add_argument("--upload.s3.acl", dest="upload.s3.acl", help="S3 Uploader ACL associated with objects (default: none)", default=None, type=str)
1014
return parser

0 commit comments

Comments
 (0)