snapshot_reload 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rvmrc +48 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +69 -0
- data/LICENSE.txt +22 -0
- data/README.md +114 -0
- data/README.rdoc +19 -0
- data/Rakefile +66 -0
- data/bin/snapshot_reload +70 -0
- data/features/snapshot_live.feature +29 -0
- data/features/snapshot_reload.feature +171 -0
- data/features/step_definitions/snapshot_live_steps.rb +4 -0
- data/features/step_definitions/snapshot_reload_steps.rb +1 -0
- data/features/support/env.rb +17 -0
- data/lib/snapshot_reload.rb +129 -0
- data/lib/snapshot_reload/String.rb +25 -0
- data/lib/snapshot_reload/defaults.rb +18 -0
- data/lib/snapshot_reload/errors.rb +31 -0
- data/lib/snapshot_reload/fetch.rb +161 -0
- data/lib/snapshot_reload/reload.rb +69 -0
- data/lib/snapshot_reload/validate.rb +111 -0
- data/lib/snapshot_reload/version.rb +18 -0
- data/snapshot_reload.gemspec +25 -0
- data/spec/snapshot_reload_spec.rb +109 -0
- data/spec/spec_helper.rb +1 -0
- metadata +178 -0
@@ -0,0 +1,171 @@
|
|
1
|
+
#
|
2
|
+
# +Copyright+:: (c) 2012, Novu, LLC
|
3
|
+
# +License+:: All rights reserverd. For internal and private use only
|
4
|
+
# +Author+:: Tamara Temple <tamara.temple@novu.com>
|
5
|
+
#
|
6
|
+
|
7
|
+
# TODO: consolidate scenarios into outlines to make them DRYer
|
8
|
+
|
9
|
+
Feature: ensure command line options work as expected
|
10
|
+
In order to test the command line options
|
11
|
+
As a tester
|
12
|
+
I want to try out all the options
|
13
|
+
|
14
|
+
Scenario: learn how to use application
|
15
|
+
When I get help for "snapshot_reload"
|
16
|
+
Then the exit status should be 0
|
17
|
+
And the banner should be present
|
18
|
+
And the banner should document that this app takes options
|
19
|
+
And the following options should be documented:
|
20
|
+
|--version|
|
21
|
+
|--log-level LEVEL|
|
22
|
+
|--env ENVIRONMENT|
|
23
|
+
|--source S3SOURCE|
|
24
|
+
|--aws-conf AWS_CONFIG|
|
25
|
+
|--aws-key AWSKEY|
|
26
|
+
|--aws-secret AWSSECRET|
|
27
|
+
And the banner should document that this app's arguments are:
|
28
|
+
|config|which is required|
|
29
|
+
|
30
|
+
Scenario: omit a configuration file
|
31
|
+
When I run `snapshot_reload --log-level debug`
|
32
|
+
Then the output should contain "parse error: 'config' is required"
|
33
|
+
And the banner should be present
|
34
|
+
And the exit status should not be 0
|
35
|
+
|
36
|
+
Scenario: provide non-existant configuration file
|
37
|
+
When I run `snapshot_reload --log-level debug --dry-run config`
|
38
|
+
Then the exit status should be 1
|
39
|
+
And the output should contain "config file does not exist"
|
40
|
+
|
41
|
+
Scenario: provide non-yaml configuration file
|
42
|
+
Given a file named "config.txt" with:
|
43
|
+
"""
|
44
|
+
Hello There!
|
45
|
+
"""
|
46
|
+
When I run `snapshot_reload --dry-run config.txt`
|
47
|
+
Then the exit status should be 2
|
48
|
+
And the output should contain "config.txt is not YAML"
|
49
|
+
|
50
|
+
Scenario: provide existing configuration file and no credential file
|
51
|
+
Given a file named "config.yaml" with:
|
52
|
+
"""
|
53
|
+
qa:
|
54
|
+
adapter: mysql2
|
55
|
+
host: localhost
|
56
|
+
encoding: utf8
|
57
|
+
database: novu_test
|
58
|
+
pool: 5
|
59
|
+
username: novuadmin
|
60
|
+
password:
|
61
|
+
"""
|
62
|
+
When I run `snapshot_reload --log-level debug --dry-run --aws-conf aws_cred --source s3://tam-test-2/db-backups/novu-2012-12-11.sql.gz config.yaml`
|
63
|
+
Then the exit status should be 4
|
64
|
+
And the output should contain "aws_cred does not exist!"
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
Scenario: provide existing configuration file and credential file
|
69
|
+
Given a file named "config.yaml" with:
|
70
|
+
"""
|
71
|
+
qa:
|
72
|
+
adapter: mysql2
|
73
|
+
host: localhost
|
74
|
+
encoding: utf8
|
75
|
+
database: novu_test
|
76
|
+
pool: 5
|
77
|
+
username: novuadmin
|
78
|
+
password:
|
79
|
+
"""
|
80
|
+
Given a file named "aws_cred" with:
|
81
|
+
"""
|
82
|
+
access_key = A1234
|
83
|
+
secret_key = S5678
|
84
|
+
"""
|
85
|
+
When I run `snapshot_reload --log-level debug --dry-run --aws-conf aws_cred --source s3://tam-test-2/db-backups/novu-2012-12-11.sql.gz config.yaml`
|
86
|
+
Then the exit status should be 0
|
87
|
+
|
88
|
+
Scenario: provide existing configuration file with environment "other" and credential file
|
89
|
+
Given a file named "config.yaml" with:
|
90
|
+
"""
|
91
|
+
other:
|
92
|
+
adapter: mysql2
|
93
|
+
host: localhost
|
94
|
+
encoding: utf8
|
95
|
+
database: novu_test
|
96
|
+
pool: 5
|
97
|
+
username: novuadmin
|
98
|
+
password:
|
99
|
+
"""
|
100
|
+
Given a file named "aws_cred" with:
|
101
|
+
"""
|
102
|
+
access_key = A1234
|
103
|
+
secret_key = S5678
|
104
|
+
"""
|
105
|
+
When I run `snapshot_reload --log-level debug --dry-run --aws-conf aws_cred --env other --source s3://tam-test-2/db-backups/novu-2012-12-11.sql.gz config.yaml`
|
106
|
+
Then the exit status should be 0
|
107
|
+
|
108
|
+
Scenario: provide existing configuration file with environment "other" and aws-key but omit awk-secret
|
109
|
+
Given a file named "config.yaml" with:
|
110
|
+
"""
|
111
|
+
other:
|
112
|
+
adapter: mysql2
|
113
|
+
host: localhost
|
114
|
+
encoding: utf8
|
115
|
+
database: novu_test
|
116
|
+
pool: 5
|
117
|
+
username: novuadmin
|
118
|
+
password:
|
119
|
+
"""
|
120
|
+
When I run `snapshot_reload --log-level debug --dry-run --aws-key A1234 --env other --source s3://tam-test-2/db-backups/novu-2012-12-11.sql.gz config.yaml`
|
121
|
+
Then the exit status should be 9
|
122
|
+
And the output should contain "Must provide *both* aws-key and aws-secret"
|
123
|
+
|
124
|
+
Scenario: provide existing configuration file with environment "other" and aws-secret but omit awk-key
|
125
|
+
Given a file named "config.yaml" with:
|
126
|
+
"""
|
127
|
+
other:
|
128
|
+
adapter: mysql2
|
129
|
+
host: localhost
|
130
|
+
encoding: utf8
|
131
|
+
database: novu_test
|
132
|
+
pool: 5
|
133
|
+
username: novuadmin
|
134
|
+
password:
|
135
|
+
"""
|
136
|
+
When I run `snapshot_reload --log-level debug --dry-run --aws-secret S5678 --env other --source s3://tam-test-2/db-backups/novu-2012-12-11.sql.gz config.yaml`
|
137
|
+
Then the exit status should be 9
|
138
|
+
And the output should contain "Must provide *both* aws-key and aws-secret"
|
139
|
+
|
140
|
+
Scenario: provide --verbose switch
|
141
|
+
Given a file named "config.yaml" with:
|
142
|
+
"""
|
143
|
+
qa:
|
144
|
+
adapter: mysql2
|
145
|
+
host: localhost
|
146
|
+
encoding: utf8
|
147
|
+
database: novu_test
|
148
|
+
pool: 5
|
149
|
+
username: novuadmin
|
150
|
+
password:
|
151
|
+
"""
|
152
|
+
Given a file named "aws_cred" with:
|
153
|
+
"""
|
154
|
+
access_key = A1234
|
155
|
+
secret_key = S5678
|
156
|
+
"""
|
157
|
+
When I run `snapshot_reload --log-level debug --dry-run --aws-conf aws_cred --verbose --source s3://tam-test-2/db-backups/novu-2012-12-11.sql.gz config.yaml`
|
158
|
+
Then the exit status should be 0
|
159
|
+
And the output should contain "config: "
|
160
|
+
And the output should contain "env: qa"
|
161
|
+
And the output should contain "host: localhost"
|
162
|
+
And the output should contain "database: novu_test"
|
163
|
+
And the output should contain "username: novuadmin"
|
164
|
+
And the output should contain "password: "
|
165
|
+
And the output should contain "source: "
|
166
|
+
And the output should contain "aws key: A1234"
|
167
|
+
And the output should contain "aws secret: S5678"
|
168
|
+
And the output should contain "dry run: true"
|
169
|
+
And the output should contain "verbose: true"
|
170
|
+
And the output should contain "quiet: false"
|
171
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
# Put your step definitions here
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'aruba/cucumber'
|
2
|
+
require 'methadone/cucumber'
|
3
|
+
|
4
|
+
ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
5
|
+
LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
|
6
|
+
|
7
|
+
Before do
|
8
|
+
# Using "announce" causes massive warnings on 1.9.2
|
9
|
+
@puts = true
|
10
|
+
@original_rubylib = ENV['RUBYLIB']
|
11
|
+
ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
|
12
|
+
@aruba_timeout_seconds = 3600 # need enough time to transfer the large sql file
|
13
|
+
end
|
14
|
+
|
15
|
+
After do
|
16
|
+
ENV['RUBYLIB'] = @original_rubylib
|
17
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
snapshot_reload.rb
|
4
|
+
|
5
|
+
+Copyright:+:: (c) 2012, Novu, LLC
|
6
|
+
+License:+:: All rights reserved. For internatl and private use only.
|
7
|
+
+Author:+:: Tamara Temple <tamara.temple@novu.com>
|
8
|
+
|
9
|
+
=end
|
10
|
+
|
11
|
+
|
12
|
+
require "snapshot_reload/version"
|
13
|
+
require "snapshot_reload/errors"
|
14
|
+
require "snapshot_reload/defaults"
|
15
|
+
require "snapshot_reload/validate"
|
16
|
+
require "snapshot_reload/fetch"
|
17
|
+
require "snapshot_reload/reload"
|
18
|
+
require "snapshot_reload/String"
|
19
|
+
require 'methadone'
|
20
|
+
|
21
|
+
module SnapshotReload
|
22
|
+
class SnapshotReload
|
23
|
+
include Methadone::CLILogging
|
24
|
+
|
25
|
+
# attr_reader :config, :env, :host, :database, :username, :password, :source, :aws_key, :aws_secret, :sql_file
|
26
|
+
|
27
|
+
def initialize(config, options=nil)
|
28
|
+
|
29
|
+
options = Hash.new if options.nil?
|
30
|
+
|
31
|
+
@config = validate_configuration(config)
|
32
|
+
@env = validate_environment(options[:env], @config)
|
33
|
+
|
34
|
+
@host = check_field(@config,@env,'host')
|
35
|
+
@database = check_field(@config,@env,'database')
|
36
|
+
@username = check_field(@config,@env,'username')
|
37
|
+
@password = check_field(@config,@env,'password',false)
|
38
|
+
|
39
|
+
@source = validate_source(options[:source])
|
40
|
+
|
41
|
+
if @source.match('^s3://')
|
42
|
+
aws = validate_aws(options['aws-conf'],
|
43
|
+
options['aws-key'], options['aws-secret'])
|
44
|
+
@aws_key = aws[0]
|
45
|
+
@aws_secret = aws[1]
|
46
|
+
end
|
47
|
+
|
48
|
+
@dry_run = options['dry-run'] ||= false
|
49
|
+
|
50
|
+
@verbose = options[:verbose] ||= false
|
51
|
+
@quiet = options[:quiet] ||= false
|
52
|
+
|
53
|
+
@verbose = false if @quiet
|
54
|
+
|
55
|
+
@sql_file = ''
|
56
|
+
|
57
|
+
if @verbose
|
58
|
+
info("config: #{@config.to_s}")
|
59
|
+
info("env: #{@env.to_s}")
|
60
|
+
info("host: #{@host.to_s}")
|
61
|
+
info("database: #{@database.to_s}")
|
62
|
+
info("username: #{@username.to_s}")
|
63
|
+
info("password: #{@password.to_s}")
|
64
|
+
info("source: #{@source.to_s}")
|
65
|
+
info("aws key: #{@aws_key}")
|
66
|
+
info("aws secret: #{@aws_secret}")
|
67
|
+
info("dry run: #{@dry_run}")
|
68
|
+
info("verbose: #{@verbose}")
|
69
|
+
info("quiet: #{@quiet}")
|
70
|
+
end
|
71
|
+
|
72
|
+
reload # and here all the magic happens!!
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def config
|
77
|
+
@config
|
78
|
+
end
|
79
|
+
|
80
|
+
def env
|
81
|
+
@env
|
82
|
+
end
|
83
|
+
|
84
|
+
def host
|
85
|
+
@host
|
86
|
+
end
|
87
|
+
|
88
|
+
def database
|
89
|
+
@database
|
90
|
+
end
|
91
|
+
|
92
|
+
def username
|
93
|
+
@username
|
94
|
+
end
|
95
|
+
|
96
|
+
def password
|
97
|
+
@password
|
98
|
+
end
|
99
|
+
|
100
|
+
def source
|
101
|
+
@source
|
102
|
+
end
|
103
|
+
|
104
|
+
def aws_key
|
105
|
+
@aws_key
|
106
|
+
end
|
107
|
+
|
108
|
+
def aws_secret
|
109
|
+
@aws_secret
|
110
|
+
end
|
111
|
+
|
112
|
+
def sql_file
|
113
|
+
@sql_file
|
114
|
+
end
|
115
|
+
|
116
|
+
def dry_run?
|
117
|
+
@dry_run
|
118
|
+
end
|
119
|
+
|
120
|
+
def verbose?
|
121
|
+
@verbose
|
122
|
+
end
|
123
|
+
|
124
|
+
def quiet?
|
125
|
+
@quiet
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
String.rb
|
4
|
+
|
5
|
+
+Copyright:+:: (c) 2012, Novu, LLC
|
6
|
+
+License:+:: All rights reserved. For internatl and private use only.
|
7
|
+
+Author:+:: Tamara Temple <tamara.temple@novu.com>
|
8
|
+
|
9
|
+
Additional methods for String and NilClass, cos I want to.
|
10
|
+
Seriously, doesn't "present?" look better that "not nil?" ??
|
11
|
+
|
12
|
+
=end
|
13
|
+
|
14
|
+
|
15
|
+
class String
|
16
|
+
def present?
|
17
|
+
true unless self.nil? or self.empty?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class NilClass
|
22
|
+
def present?
|
23
|
+
true unless self.nil?
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
Defaults used in the SnapshotReload module
|
4
|
+
|
5
|
+
+Copyright:+ (c) 2012 Novu, LLC
|
6
|
+
+License:+ All rights reserved. For internal and private use only
|
7
|
+
+Author:+ Tamara Temple <tamara.temple@novu.com>
|
8
|
+
|
9
|
+
=end
|
10
|
+
|
11
|
+
module SnapshotReload
|
12
|
+
DEFAULT_S3_SOURCE = %q{s3://novu_backups/db_backups/clean-mysqldump.sql.gz}
|
13
|
+
DEFAULT_AWS_CREDS = %q{/opt/novu/.s3cfg}
|
14
|
+
DEFAULT_ENVIRONMENT = %q{qa}
|
15
|
+
|
16
|
+
CHUNK_SIZE = 10 * 1024 * 1024 # chunk size to pull over file from S3
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
errors.rb
|
4
|
+
|
5
|
+
+Copyright:+:: (c) 2012, Novu, LLC
|
6
|
+
+License:+:: All rights reserved. For internatl and private use only.
|
7
|
+
+Author:+:: Tamara Temple <tamara.temple@novu.com>
|
8
|
+
|
9
|
+
Enumerate program exit errors as descriptive constants
|
10
|
+
|
11
|
+
|
12
|
+
=end
|
13
|
+
|
14
|
+
module SnapshotReload
|
15
|
+
|
16
|
+
ENOCONFIG = 1
|
17
|
+
ECONFIGNOTYAML = 2
|
18
|
+
ENOENVINCONFIG = 3
|
19
|
+
ENOCRED = 4
|
20
|
+
ENOFIELD = 5
|
21
|
+
ENOSQLFILE = 6
|
22
|
+
ECMDFAILED = 7
|
23
|
+
EBADS3URI = 8
|
24
|
+
EMISSINGKEYORSECRET = 9
|
25
|
+
ENOWRITE = 10
|
26
|
+
EDROPFAILED = 11
|
27
|
+
ENOBUCKET = 12
|
28
|
+
ENOOBJECT = 13
|
29
|
+
ENOS3FILES = 14
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
fetch.rb
|
4
|
+
|
5
|
+
+Copyright:+:: (c) 2012, Novu, LLC
|
6
|
+
+License:+:: All rights reserved. For internatl and private use only.
|
7
|
+
+Author:+:: Tamara Temple <tamara.temple@novu.com>
|
8
|
+
|
9
|
+
=end
|
10
|
+
|
11
|
+
require 'methadone'
|
12
|
+
require 'fog'
|
13
|
+
|
14
|
+
module SnapshotReload
|
15
|
+
class SnapshotReload
|
16
|
+
|
17
|
+
def fetch_snapshot
|
18
|
+
|
19
|
+
if @source.match('^s3://')
|
20
|
+
@sql_file = s3_fetch
|
21
|
+
else
|
22
|
+
@sql_file = @source
|
23
|
+
end
|
24
|
+
|
25
|
+
unless File.exists?(@sql_file)
|
26
|
+
fatal("#{@sql_file} does not exist!")
|
27
|
+
exit(ENOSQLFILE)
|
28
|
+
end
|
29
|
+
|
30
|
+
info("SQL file: #{@sql_file}") if @verbose
|
31
|
+
|
32
|
+
@sql_file
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
=begin
|
38
|
+
|
39
|
+
Helper methods for fetch_snapshot
|
40
|
+
|
41
|
+
=end
|
42
|
+
|
43
|
+
|
44
|
+
def s3_fetch
|
45
|
+
|
46
|
+
matches = @source.match('^s3://([^/]+)/(.*)$')
|
47
|
+
if matches
|
48
|
+
s3_bucket_name=matches[1]
|
49
|
+
s3_object_name=matches[2]
|
50
|
+
else
|
51
|
+
fatal("#{@source} is not a valid s3 uri (must be s3://bucket/object)")
|
52
|
+
exit(EBADS3URI)
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
warn("Dry run, nothing will be fetched from S3") if @dry_run
|
57
|
+
|
58
|
+
info("Connecting to AWS S3") if @verbose
|
59
|
+
|
60
|
+
connection = Fog::Storage.new(:provider => 'AWS',
|
61
|
+
:aws_access_key_id => @aws_key,
|
62
|
+
:aws_secret_access_key => @aws_secret) unless @dry_run
|
63
|
+
|
64
|
+
|
65
|
+
unless @dry_run
|
66
|
+
|
67
|
+
buckets = connection.directories.select do |dir|
|
68
|
+
debug("Dir: #{dir.key}")
|
69
|
+
dir if dir.key == s3_bucket_name
|
70
|
+
end
|
71
|
+
|
72
|
+
if buckets.nil? or buckets.empty?
|
73
|
+
fatal("no bucket #{s3_bucket_name} found")
|
74
|
+
exit(ENOBUCKET)
|
75
|
+
end
|
76
|
+
|
77
|
+
s3_bucket = buckets.first
|
78
|
+
|
79
|
+
info("S3 Bucket #{s3_bucket.key} found") if @verbose
|
80
|
+
|
81
|
+
if s3_bucket.files.nil?
|
82
|
+
error("No files in S3 bucket #{s3_bucket_name}")
|
83
|
+
exit(ENOS3FILES)
|
84
|
+
end
|
85
|
+
|
86
|
+
files = s3_bucket.files.select do |file|
|
87
|
+
debug("File: #{file.key}")
|
88
|
+
file if file.key == s3_object_name
|
89
|
+
end
|
90
|
+
|
91
|
+
if files.nil? or files.empty?
|
92
|
+
fatal("no object #{s3_object_name} found")
|
93
|
+
exit(ENOOBJECT)
|
94
|
+
end
|
95
|
+
|
96
|
+
s3_object = files.first
|
97
|
+
|
98
|
+
info("S3 Object #{s3_object_name} found in #{s3_bucket_name}") if @verbose
|
99
|
+
|
100
|
+
s3_file = File.basename(s3_object.key)
|
101
|
+
s3_object_content_length = s3_object.content_length
|
102
|
+
|
103
|
+
else # this is just a dry run, make up stuff
|
104
|
+
|
105
|
+
s3_file = File.basename(s3_object_name)
|
106
|
+
s3_object_content_length = 0
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
if File.exists?(s3_file) and
|
111
|
+
not (File.stat(s3_file).file? and File.stat(s3_file).writable?)
|
112
|
+
fatal("#{s3_file} is not writable!")
|
113
|
+
exit(ENOWRITE)
|
114
|
+
end
|
115
|
+
|
116
|
+
info("Writing to file #{s3_file}") if @verbose
|
117
|
+
|
118
|
+
File.open(s3_file,'w') do |file|
|
119
|
+
|
120
|
+
# Calculate number of batches for extremely large files
|
121
|
+
|
122
|
+
batches = s3_object_content_length / CHUNK_SIZE
|
123
|
+
|
124
|
+
(0..batches).each do |batch|
|
125
|
+
start_byte = batch * CHUNK_SIZE
|
126
|
+
end_byte = start_byte + CHUNK_SIZE - 1
|
127
|
+
contents = get_the_object(connection, s3_bucket_name, s3_object_name, start_byte, end_byte)
|
128
|
+
info("Writing #{contents.length} bytes to #{s3_file}") if @verbose
|
129
|
+
file.write(contents)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Now get the remainder
|
133
|
+
start_byte = batches * CHUNK_SIZE
|
134
|
+
end_byte = s3_object_content_length
|
135
|
+
contents = get_the_object(connection, s3_bucket_name, s3_object_name, start_byte, end_byte)
|
136
|
+
info("Writing #{contents.length} bytes to #{s3_file}") if @verbose
|
137
|
+
file.write(contents)
|
138
|
+
|
139
|
+
end # File.open
|
140
|
+
|
141
|
+
s3_file_stat = File.stat(s3_file)
|
142
|
+
info("Wrote #{s3_file_stat.size} bytes to #{s3_file}") if @verbose
|
143
|
+
|
144
|
+
s3_file # return the name of file written
|
145
|
+
|
146
|
+
end # method s3_fetch
|
147
|
+
|
148
|
+
def get_the_object(cnxn, bucket, name, range_start, range_end)
|
149
|
+
|
150
|
+
get_object_options = { 'Range' => "bytes=%d-%d" % [ range_start, range_end ] }
|
151
|
+
info("Getting #{name} from #{bucket}, range #{get_object_options['Range']}") if @verbose
|
152
|
+
return '' if @dry_run
|
153
|
+
response = cnxn.get_object(bucket,name,get_object_options)
|
154
|
+
debug("Response.class: #{response.class}")
|
155
|
+
debug("Response.status: #{response.status}")
|
156
|
+
response.body
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|