Class: BoringBackup::Stores::S3
- Defined in:
- lib/boring_backup/stores/s3.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#access_key_id ⇒ Object
Returns the value of attribute access_key_id.
-
#bucket ⇒ Object
Returns the value of attribute bucket.
-
#endpoint ⇒ Object
Returns the value of attribute endpoint.
-
#part_size ⇒ Object
Returns the value of attribute part_size.
-
#region ⇒ Object
Returns the value of attribute region.
-
#secret_access_key ⇒ Object
Returns the value of attribute secret_access_key.
- #storage_class ⇒ Object
-
#thread_count ⇒ Object
Returns the value of attribute thread_count.
Instance Method Summary collapse
-
#backup!(key, stream) ⇒ Object
Prefer Aws::S3::TransferManager for streaming uploads if available.
- #cleanup!(key) ⇒ Object
- #default_storage_class ⇒ Object
- #description ⇒ Object
-
#initialize ⇒ S3
constructor
A new instance of S3.
- #name ⇒ Object
- #storage_classes ⇒ Object
- #validate! ⇒ Object
Constructor Details
#initialize ⇒ S3
Returns a new instance of S3.
8 9 10 11 12 13 14 15 |
# File 'lib/boring_backup/stores/s3.rb', line 8 def initialize @region = ENV["AWS_REGION"] @access_key_id = ENV["AWS_ACCESS_KEY_ID"] @secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"] @part_size = ENV.fetch("BB_S3_PART_SIZE", 8 * 1024 * 1024).to_i @thread_count = ENV.fetch("BB_S3_THREAD_COUNT", 2).to_i @storage_class = ENV.fetch("BB_S3_STORAGE_CLASS", default_storage_class) end |
Instance Attribute Details
#access_key_id ⇒ Object
Returns the value of attribute access_key_id.
5 6 7 |
# File 'lib/boring_backup/stores/s3.rb', line 5 def access_key_id @access_key_id end |
#bucket ⇒ Object
Returns the value of attribute bucket.
5 6 7 |
# File 'lib/boring_backup/stores/s3.rb', line 5 def bucket @bucket end |
#endpoint ⇒ Object
Returns the value of attribute endpoint.
5 6 7 |
# File 'lib/boring_backup/stores/s3.rb', line 5 def endpoint @endpoint end |
#part_size ⇒ Object
Returns the value of attribute part_size.
5 6 7 |
# File 'lib/boring_backup/stores/s3.rb', line 5 def part_size @part_size end |
#region ⇒ Object
Returns the value of attribute region.
5 6 7 |
# File 'lib/boring_backup/stores/s3.rb', line 5 def region @region end |
#secret_access_key ⇒ Object
Returns the value of attribute secret_access_key.
5 6 7 |
# File 'lib/boring_backup/stores/s3.rb', line 5 def secret_access_key @secret_access_key end |
#storage_class ⇒ Object
17 18 19 20 21 |
# File 'lib/boring_backup/stores/s3.rb', line 17 def storage_class value = @storage_class.to_s.strip.downcase value.empty? ? nil : value.to_sym end |
#thread_count ⇒ Object
Returns the value of attribute thread_count.
5 6 7 |
# File 'lib/boring_backup/stores/s3.rb', line 5 def thread_count @thread_count end |
Instance Method Details
#backup!(key, stream) ⇒ Object
Prefer Aws::S3::TransferManager for streaming uploads if available. Aws::S3::Resource.upload_stream is deprecated in newer versions
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/boring_backup/stores/s3.rb', line 49 def backup!(key, stream) started = Process.clock_gettime(Process::CLOCK_MONOTONIC) bytes = 0 validate! upload_attempted = true if defined?(Aws::S3::TransferManager) manager = Aws::S3::TransferManager.new(client: s3_client) manager.upload_stream(bucket:, key: key, **) do |s3_stream| bytes = IO.copy_stream(stream, s3_stream) end else object = Aws::S3::Resource.new(client: s3_client).bucket(bucket).object(key) object.upload_stream(**) do |s3_stream| bytes = IO.copy_stream(stream, s3_stream) end end duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started if config.min_size && bytes < config.min_size.to_i raise BoringBackup::DumpTooSmallError, "backup too small: #{BoringBackup.utils.human_size(bytes)} < min_size (#{BoringBackup.utils.human_size(config.min_size)})" end Result.new(success: true, store: name, bytes:, key:, duration:) rescue => e duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started cleanup!(key) if upload_attempted Result.new(success: false, error: e, store: name, bytes:, key:, duration:) end |
#cleanup!(key) ⇒ Object
100 101 102 103 104 |
# File 'lib/boring_backup/stores/s3.rb', line 100 def cleanup!(key) s3_client.delete_object(bucket:, key:) rescue => e warn "Failed to clean up partial upload #{key}: #{e.}" end |
#default_storage_class ⇒ Object
23 |
# File 'lib/boring_backup/stores/s3.rb', line 23 def default_storage_class = :standard_ia |
#description ⇒ Object
43 44 45 |
# File 'lib/boring_backup/stores/s3.rb', line 43 def description [bucket.to_s.empty? ? "no bucket" : "#{name}://#{bucket}", region].compact.join(" ") end |
#name ⇒ Object
41 |
# File 'lib/boring_backup/stores/s3.rb', line 41 def name = :s3 |
#storage_classes ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/boring_backup/stores/s3.rb', line 25 def storage_classes %i[ standard standard_ia onezone_ia intelligent_tiering glacier_ir glacier deep_archive reduced_redundancy express_onezone outposts snow ] end |
#validate! ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/boring_backup/stores/s3.rb', line 86 def validate! raise BoringBackup::ConfigurationError, "bucket is not configured" if bucket.to_s.empty? if access_key_id.to_s.empty? != secret_access_key.to_s.empty? raise BoringBackup::ConfigurationError, "access_key_id and secret_access_key must both be set, or both left blank to use the default AWS credential chain" end if storage_class && !storage_classes.include?(storage_class) raise BoringBackup::ConfigurationError, "unknown storage class: #{storage_class.inspect} (expected one of: #{storage_classes.map(&:inspect).join(", ")}, or nil to use the bucket default)" end end |