mss-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +9 -0
- data/LICENSE.txt +0 -0
- data/README.md +192 -0
- data/bin/mss-rb +178 -0
- data/ca-bundle.crt +3554 -0
- data/lib/mss/core/async_handle.rb +89 -0
- data/lib/mss/core/cacheable.rb +76 -0
- data/lib/mss/core/client.rb +786 -0
- data/lib/mss/core/collection/simple.rb +81 -0
- data/lib/mss/core/collection/with_limit_and_next_token.rb +70 -0
- data/lib/mss/core/collection/with_next_token.rb +96 -0
- data/lib/mss/core/collection.rb +262 -0
- data/lib/mss/core/configuration.rb +527 -0
- data/lib/mss/core/credential_providers.rb +653 -0
- data/lib/mss/core/data.rb +251 -0
- data/lib/mss/core/deprecations.rb +83 -0
- data/lib/mss/core/endpoints.rb +36 -0
- data/lib/mss/core/http/connection_pool.rb +374 -0
- data/lib/mss/core/http/curb_handler.rb +150 -0
- data/lib/mss/core/http/handler.rb +88 -0
- data/lib/mss/core/http/net_http_handler.rb +144 -0
- data/lib/mss/core/http/patch.rb +98 -0
- data/lib/mss/core/http/request.rb +258 -0
- data/lib/mss/core/http/response.rb +80 -0
- data/lib/mss/core/indifferent_hash.rb +87 -0
- data/lib/mss/core/inflection.rb +55 -0
- data/lib/mss/core/ini_parser.rb +41 -0
- data/lib/mss/core/json_client.rb +46 -0
- data/lib/mss/core/json_parser.rb +75 -0
- data/lib/mss/core/json_request_builder.rb +34 -0
- data/lib/mss/core/json_response_parser.rb +78 -0
- data/lib/mss/core/lazy_error_classes.rb +107 -0
- data/lib/mss/core/log_formatter.rb +426 -0
- data/lib/mss/core/managed_file.rb +31 -0
- data/lib/mss/core/meta_utils.rb +44 -0
- data/lib/mss/core/model.rb +61 -0
- data/lib/mss/core/naming.rb +29 -0
- data/lib/mss/core/option_grammar.rb +737 -0
- data/lib/mss/core/options/json_serializer.rb +81 -0
- data/lib/mss/core/options/validator.rb +154 -0
- data/lib/mss/core/options/xml_serializer.rb +117 -0
- data/lib/mss/core/page_result.rb +74 -0
- data/lib/mss/core/policy.rb +938 -0
- data/lib/mss/core/query_client.rb +40 -0
- data/lib/mss/core/query_error_parser.rb +23 -0
- data/lib/mss/core/query_request_builder.rb +46 -0
- data/lib/mss/core/query_response_parser.rb +34 -0
- data/lib/mss/core/region.rb +84 -0
- data/lib/mss/core/region_collection.rb +79 -0
- data/lib/mss/core/resource.rb +412 -0
- data/lib/mss/core/resource_cache.rb +39 -0
- data/lib/mss/core/response.rb +214 -0
- data/lib/mss/core/response_cache.rb +49 -0
- data/lib/mss/core/rest_error_parser.rb +23 -0
- data/lib/mss/core/rest_json_client.rb +39 -0
- data/lib/mss/core/rest_request_builder.rb +153 -0
- data/lib/mss/core/rest_response_parser.rb +65 -0
- data/lib/mss/core/rest_xml_client.rb +46 -0
- data/lib/mss/core/service_interface.rb +82 -0
- data/lib/mss/core/signers/base.rb +45 -0
- data/lib/mss/core/signers/cloud_front.rb +55 -0
- data/lib/mss/core/signers/s3.rb +158 -0
- data/lib/mss/core/signers/version_2.rb +71 -0
- data/lib/mss/core/signers/version_3.rb +85 -0
- data/lib/mss/core/signers/version_3_https.rb +60 -0
- data/lib/mss/core/signers/version_4/chunk_signed_stream.rb +190 -0
- data/lib/mss/core/signers/version_4.rb +227 -0
- data/lib/mss/core/uri_escape.rb +43 -0
- data/lib/mss/core/xml/frame.rb +245 -0
- data/lib/mss/core/xml/frame_stack.rb +84 -0
- data/lib/mss/core/xml/grammar.rb +306 -0
- data/lib/mss/core/xml/parser.rb +69 -0
- data/lib/mss/core/xml/root_frame.rb +64 -0
- data/lib/mss/core/xml/sax_handlers/libxml.rb +46 -0
- data/lib/mss/core/xml/sax_handlers/nokogiri.rb +55 -0
- data/lib/mss/core/xml/sax_handlers/ox.rb +40 -0
- data/lib/mss/core/xml/sax_handlers/rexml.rb +46 -0
- data/lib/mss/core/xml/stub.rb +122 -0
- data/lib/mss/core.rb +602 -0
- data/lib/mss/errors.rb +161 -0
- data/lib/mss/rails.rb +194 -0
- data/lib/mss/s3/access_control_list.rb +262 -0
- data/lib/mss/s3/acl_object.rb +263 -0
- data/lib/mss/s3/acl_options.rb +200 -0
- data/lib/mss/s3/bucket.rb +757 -0
- data/lib/mss/s3/bucket_collection.rb +161 -0
- data/lib/mss/s3/bucket_lifecycle_configuration.rb +472 -0
- data/lib/mss/s3/bucket_region_cache.rb +51 -0
- data/lib/mss/s3/bucket_tag_collection.rb +110 -0
- data/lib/mss/s3/bucket_version_collection.rb +78 -0
- data/lib/mss/s3/cipher_io.rb +119 -0
- data/lib/mss/s3/client/xml.rb +265 -0
- data/lib/mss/s3/client.rb +2076 -0
- data/lib/mss/s3/config.rb +60 -0
- data/lib/mss/s3/cors_rule.rb +107 -0
- data/lib/mss/s3/cors_rule_collection.rb +193 -0
- data/lib/mss/s3/data_options.rb +190 -0
- data/lib/mss/s3/encryption_utils.rb +145 -0
- data/lib/mss/s3/errors.rb +93 -0
- data/lib/mss/s3/multipart_upload.rb +353 -0
- data/lib/mss/s3/multipart_upload_collection.rb +75 -0
- data/lib/mss/s3/object_collection.rb +355 -0
- data/lib/mss/s3/object_metadata.rb +102 -0
- data/lib/mss/s3/object_upload_collection.rb +76 -0
- data/lib/mss/s3/object_version.rb +153 -0
- data/lib/mss/s3/object_version_collection.rb +88 -0
- data/lib/mss/s3/paginated_collection.rb +74 -0
- data/lib/mss/s3/policy.rb +73 -0
- data/lib/mss/s3/prefix_and_delimiter_collection.rb +46 -0
- data/lib/mss/s3/prefixed_collection.rb +84 -0
- data/lib/mss/s3/presign_v4.rb +135 -0
- data/lib/mss/s3/presigned_post.rb +574 -0
- data/lib/mss/s3/region_detection.rb +75 -0
- data/lib/mss/s3/request.rb +61 -0
- data/lib/mss/s3/s3_object.rb +1795 -0
- data/lib/mss/s3/tree/branch_node.rb +67 -0
- data/lib/mss/s3/tree/child_collection.rb +103 -0
- data/lib/mss/s3/tree/leaf_node.rb +93 -0
- data/lib/mss/s3/tree/node.rb +21 -0
- data/lib/mss/s3/tree/parent.rb +86 -0
- data/lib/mss/s3/tree.rb +115 -0
- data/lib/mss/s3/uploaded_part.rb +81 -0
- data/lib/mss/s3/uploaded_part_collection.rb +83 -0
- data/lib/mss/s3/website_configuration.rb +101 -0
- data/lib/mss/s3.rb +161 -0
- data/lib/mss/version.rb +16 -0
- data/lib/mss-sdk.rb +2 -0
- data/lib/mss.rb +14 -0
- data/rails/init.rb +14 -0
- metadata +201 -0
@@ -0,0 +1,161 @@
|
|
1
|
+
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# or in the "license" file accompanying this file. This file is
|
9
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
10
|
+
# ANY KIND, either express or implied. See the License for the specific
|
11
|
+
# language governing permissions and limitations under the License.
|
12
|
+
|
13
|
+
module MSS
|
14
|
+
class S3
|
15
|
+
|
16
|
+
# Represents a collection of buckets.
|
17
|
+
#
|
18
|
+
# You can use this to create a bucket:
|
19
|
+
#
|
20
|
+
# s3.buckets.create("mybucket")
|
21
|
+
#
|
22
|
+
# You can get a handle for a specific bucket with indifferent
|
23
|
+
# access:
|
24
|
+
#
|
25
|
+
# bucket = s3.buckets[:mybucket]
|
26
|
+
# bucket = s3.buckets['mybucket']
|
27
|
+
#
|
28
|
+
# You can also use it to find out which buckets are in your account:
|
29
|
+
#
|
30
|
+
# s3.buckets.collect(&:name)
|
31
|
+
# #=> ['bucket1', 'bucket2', ...]
|
32
|
+
#
|
33
|
+
class BucketCollection
|
34
|
+
|
35
|
+
include Core::Model
|
36
|
+
include Enumerable
|
37
|
+
|
38
|
+
# Creates and returns a new Bucket. For example:
|
39
|
+
#
|
40
|
+
# @note If your bucket name contains one or more periods and it
|
41
|
+
# is hosted in a non-US region, you should make requests
|
42
|
+
# against the bucket using the S3 endpoint specific to the
|
43
|
+
# region in which your bucket resides. For example:
|
44
|
+
#
|
45
|
+
# s3 = MSS::S3.new(:region => "eu-west-1")
|
46
|
+
# bucket = s3.buckets.create("my.eu.bucket")
|
47
|
+
#
|
48
|
+
# For a full list of endpoints and regions, see
|
49
|
+
# Regions and Endpoints} in the Amazon Web Services General
|
50
|
+
# Reference.
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
#
|
54
|
+
# bucket = s3.buckets.create('my-bucket')
|
55
|
+
# bucket.name #=> "my-bucket"
|
56
|
+
# bucket.exists? #=> true
|
57
|
+
#
|
58
|
+
# @param [String] bucket_name
|
59
|
+
#
|
60
|
+
# @param [Hash] options
|
61
|
+
#
|
62
|
+
# @option options [String] :location_constraint (nil) The
|
63
|
+
# location where the bucket should be created. Defaults to
|
64
|
+
# the classic US region; however, if you configure a regional
|
65
|
+
# endpoint for Amazon S3 this option will default to the
|
66
|
+
# appropriate location constraint for the endpoint. For
|
67
|
+
# example:
|
68
|
+
#
|
69
|
+
# s3 = MSS::S3.new(:region => "us-west-1")
|
70
|
+
# bucket = s3.buckets.create("my-us-west-bucket")
|
71
|
+
# bucket.location_constraint # => "us-west-1"
|
72
|
+
#
|
73
|
+
# @option options [Symbol,String] :acl (:private) Sets the ACL of the
|
74
|
+
# bucket you are creating. Valid Values include:
|
75
|
+
# * `:private`
|
76
|
+
# * `:public_read`
|
77
|
+
# * `:public_read_write`
|
78
|
+
# * `:authenticated_read`
|
79
|
+
# * `:log_delivery_write`
|
80
|
+
#
|
81
|
+
# @option options [String] :grant_read
|
82
|
+
# @option options [String] :grant_write
|
83
|
+
# @option options [String] :grant_read_acp
|
84
|
+
# @option options [String] :grant_write_acp
|
85
|
+
# @option options [String] :grant_full_control
|
86
|
+
#
|
87
|
+
# @return [Bucket]
|
88
|
+
#
|
89
|
+
def create bucket_name, options = {}
|
90
|
+
|
91
|
+
# convert the symbolized-canned acl into the string version
|
92
|
+
if acl = options[:acl]
|
93
|
+
# options[:acl] = acl.to_s.tr('_', '-')
|
94
|
+
options[:acl] = 'private'
|
95
|
+
end
|
96
|
+
|
97
|
+
# auto set the location constraint for the user if it is not
|
98
|
+
# passed in and the endpoint is not the us-standard region. don't
|
99
|
+
# override the location constraint though, even it is wrong,
|
100
|
+
unless
|
101
|
+
config.s3_endpoint == 's3.amazonmss.com' or
|
102
|
+
options[:location_constraint]
|
103
|
+
then
|
104
|
+
constraint = guess_constraint
|
105
|
+
options[:location_constraint] = constraint if constraint
|
106
|
+
end
|
107
|
+
|
108
|
+
client.create_bucket(options.merge(:bucket_name => bucket_name))
|
109
|
+
bucket_named(bucket_name)
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the Bucket with the given name.
|
114
|
+
#
|
115
|
+
# Makes no requests. The returned bucket object can
|
116
|
+
# be used to make requets for the bucket and its objects.
|
117
|
+
#
|
118
|
+
# @example
|
119
|
+
#
|
120
|
+
# bucket = s3.buckets[:mybucket],
|
121
|
+
# bucket = s3.buckets['mybucket'],
|
122
|
+
#
|
123
|
+
# @param [String] bucket_name
|
124
|
+
# @return [Bucket]
|
125
|
+
def [] bucket_name
|
126
|
+
bucket_named(bucket_name)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Iterates the buckets in this collection.
|
130
|
+
#
|
131
|
+
# @example
|
132
|
+
#
|
133
|
+
# s3.buckets.each do |bucket|
|
134
|
+
# puts bucket.name
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# @return [nil]
|
138
|
+
def each &block
|
139
|
+
response = client.list_buckets
|
140
|
+
response.buckets.each do |b|
|
141
|
+
yield(bucket_named(b.name, response.owner))
|
142
|
+
end
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def bucket_named name, owner = nil
|
149
|
+
S3::Bucket.new(name.to_s, :owner => owner, :config => config)
|
150
|
+
end
|
151
|
+
|
152
|
+
def guess_constraint
|
153
|
+
case config.s3_endpoint
|
154
|
+
when 's3-eu-west-1.amazonmss.com' then 'EU'
|
155
|
+
when /^s3[.-](.*)\.amazonmss\.com/ then $1
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,472 @@
|
|
1
|
+
# Copyright 2011-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"). You
|
4
|
+
# may not use this file except in compliance with the License. A copy of
|
5
|
+
# the License is located at
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# or in the "license" file accompanying this file. This file is
|
9
|
+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
10
|
+
# ANY KIND, either express or implied. See the License for the specific
|
11
|
+
# language governing permissions and limitations under the License.
|
12
|
+
|
13
|
+
require 'nokogiri'
|
14
|
+
|
15
|
+
module MSS
|
16
|
+
class S3
|
17
|
+
|
18
|
+
# A lifecycle configuration specify {Rule rules} that manage the way
|
19
|
+
# Amazon S3 stores objects. The rules apply to objects whose keys match
|
20
|
+
# the rule's prefix.
|
21
|
+
#
|
22
|
+
# ## Rules
|
23
|
+
#
|
24
|
+
# A rule is comprised primarily of an id, prefix and set of
|
25
|
+
# configuration options. Configuration options on the rules can specify:
|
26
|
+
#
|
27
|
+
# * When to expire an object
|
28
|
+
# * When to transition an object to Glacier
|
29
|
+
# * Whether the rule is enabled or disabled
|
30
|
+
#
|
31
|
+
# See {Rule} for more information on all of the attributes and methods
|
32
|
+
# available for rules.
|
33
|
+
#
|
34
|
+
# ## Expiring Objects
|
35
|
+
#
|
36
|
+
# You can add a rule to a bucket lifecycle configuration using {#add_rule}
|
37
|
+
# inside of an {#update} block that will expire an object after a given
|
38
|
+
# number of days:
|
39
|
+
#
|
40
|
+
# # delete backups after they are 1 year old
|
41
|
+
# bucket.lifecycle_configuration.update do
|
42
|
+
# add_rule('backups/', :expiration_time => 365)
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# You can also define the rule to expire objects at a specific date:
|
46
|
+
#
|
47
|
+
# # delete backups on January 1st of next year
|
48
|
+
# bucket.lifecycle_configuration.update do
|
49
|
+
# date = Date.new(Time.now.year + 1, 01, 01)
|
50
|
+
# add_rule('backups/', :expiration_time => date)
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# ## Transitioning Objects to Glacier
|
54
|
+
#
|
55
|
+
# You can add a rule to a bucket lifecycle configuration using {#add_rule}
|
56
|
+
# inside of an {#update} block that will transition objects to Glacier
|
57
|
+
# after a given number of days:
|
58
|
+
#
|
59
|
+
# # move backups to Glacier after 3 days
|
60
|
+
# bucket.lifecycle_configuration.update do
|
61
|
+
# add_rule('backups/', :glacier_transition_time => 3)
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# You can also define the rule to transition objects at a specific date:
|
65
|
+
#
|
66
|
+
# # transition all backups on January 1st of next year
|
67
|
+
# bucket.lifecycle_configuration.update do
|
68
|
+
# date = Date.new(Time.now.year + 1, 01, 01)
|
69
|
+
# add_rule('backups/', :glacier_transition_time => date)
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# ## Replacing Rules
|
73
|
+
#
|
74
|
+
# If you prefer to completely replace a lifecycle configuration, call
|
75
|
+
# {#add_rule} inside a {#replace} block instead of an `#update` block:
|
76
|
+
#
|
77
|
+
# # replace all existing rules with the following
|
78
|
+
# bucket.lifecycle_configuration.replace do
|
79
|
+
# add_rule('backups/', :glacier_transition_time => 10)
|
80
|
+
# add_rule('temp/', :expiration_time => 30)
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# ## Removing Rules
|
84
|
+
#
|
85
|
+
# You can delete specific rules with {#remove_rule}.
|
86
|
+
#
|
87
|
+
# # delete all disabled rules
|
88
|
+
# bucket.lifecycle_configuration.update do
|
89
|
+
# rules.each do |rule|
|
90
|
+
# remove_rule(rule) if rule.disabled?
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# You can also remove all rules in a single call with {#clear}:
|
95
|
+
#
|
96
|
+
# # remove all rules from this lifecycle configuration
|
97
|
+
# bucket.lifecycle_configuration.clear
|
98
|
+
#
|
99
|
+
# ## Editing Existing Rules
|
100
|
+
#
|
101
|
+
# You can also make changes to existing rules.
|
102
|
+
#
|
103
|
+
# # change the expiration days to 10 for EVERY rule
|
104
|
+
# bucket.lifecycle_configuration.update do
|
105
|
+
# rules.each do |rule|
|
106
|
+
# rule.expiration_time = 10
|
107
|
+
# end
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# Please be aware, if you add, remove or edit rules outside of an
|
111
|
+
# {#update} or {#replace} block, then you must call `#update` yourself
|
112
|
+
# or the changes will not be persisted.
|
113
|
+
#
|
114
|
+
class BucketLifecycleConfiguration
|
115
|
+
|
116
|
+
# @api private
|
117
|
+
def initialize bucket, options = {}
|
118
|
+
@bucket = bucket
|
119
|
+
@rules = parse_xml(options[:xml]) if options[:xml]
|
120
|
+
@rules = [] if options[:empty] == true
|
121
|
+
end
|
122
|
+
|
123
|
+
# @return [Bucket] Returns the bucket this lifecycle configuration
|
124
|
+
# belongs to.
|
125
|
+
attr_reader :bucket
|
126
|
+
|
127
|
+
# @return [Array<Hash>] Returns an array of rules.
|
128
|
+
def rules
|
129
|
+
@rules ||= begin
|
130
|
+
begin
|
131
|
+
opts = { :bucket_name => bucket.name }
|
132
|
+
response = bucket.client.get_bucket_lifecycle_configuration(opts)
|
133
|
+
parse_xml(response.http_response.body)
|
134
|
+
rescue Errors::NoSuchLifecycleConfiguration
|
135
|
+
[]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# @overload add_rule(prefix, options = {})
|
141
|
+
# @param [String] prefix objects whose keys begin with this prefix
|
142
|
+
# will be affected by the rule.
|
143
|
+
#
|
144
|
+
# @option options [String] :id A unique ID for this rule. If an ID
|
145
|
+
# is not provided, one will be generated.
|
146
|
+
#
|
147
|
+
# @option options [Boolean] :disabled (false) By default, all rules
|
148
|
+
# will have the status of enabled. You can override this default
|
149
|
+
# by passing `:disabled` => true.
|
150
|
+
#
|
151
|
+
# @option options [Date, Integer] :expiration_time (nil) Indicates
|
152
|
+
# the lifetime for objects matching the given prefix.
|
153
|
+
#
|
154
|
+
# @option options [Date, Integer] :glacier_transition_time (nil)
|
155
|
+
# Indicates the time before objects matching the given prefix will
|
156
|
+
# be transitioned into the Amazon Glacier storage tier.
|
157
|
+
#
|
158
|
+
# @return [Rule] Returns the rule that was added, as a {Rule} object.
|
159
|
+
def add_rule prefix, expiration_time = nil, options = {}
|
160
|
+
if Hash === expiration_time
|
161
|
+
options = expiration_time
|
162
|
+
else
|
163
|
+
options[:expiration_time] = expiration_time
|
164
|
+
end
|
165
|
+
|
166
|
+
id = options[:id] || SecureRandom.uuid
|
167
|
+
opts = {
|
168
|
+
:status => options[:disabled] == true ? 'Disabled' : 'Enabled',
|
169
|
+
:expiration_time => options[:expiration_time],
|
170
|
+
:glacier_transition_time => options[:glacier_transition_time],
|
171
|
+
:noncurrent_version_transition_days => options[:noncurrent_version_transition_days],
|
172
|
+
:noncurrent_version_expiration_days => options[:noncurrent_version_expiration_days]
|
173
|
+
}
|
174
|
+
rule = Rule.new(self, id, prefix, opts)
|
175
|
+
self.rules << rule
|
176
|
+
rule
|
177
|
+
end
|
178
|
+
|
179
|
+
# Removes a single rule. You can pass a rule id or a {Rule}
|
180
|
+
# object.
|
181
|
+
#
|
182
|
+
# # remove a single rule by its ID
|
183
|
+
# bucket.lifecycle_configuration.update do
|
184
|
+
# remove_rule('rule-id')
|
185
|
+
# end
|
186
|
+
#
|
187
|
+
# # remove all disabled rules
|
188
|
+
# bucket.lifecycle_configuration.update do
|
189
|
+
# rules.each do |rule|
|
190
|
+
# remove_rule(rule) if rule.disabled?
|
191
|
+
# end
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# If you call #remove_rule outside an update block
|
195
|
+
# you need to call #update to save the changes.
|
196
|
+
#
|
197
|
+
# @param [Rule,String] rule_or_rule_id
|
198
|
+
#
|
199
|
+
# @return [nil]
|
200
|
+
#
|
201
|
+
def remove_rule rule_or_rule_id
|
202
|
+
rule_id = rule_or_rule_id
|
203
|
+
if rule_id.nil?
|
204
|
+
raise ArgumentError, "expected a rule or rule id, got nil"
|
205
|
+
end
|
206
|
+
rule_id = rule_id.id unless rule_id.is_a?(String)
|
207
|
+
@rules = rules.select{|r| r.id != rule_id }
|
208
|
+
nil
|
209
|
+
end
|
210
|
+
|
211
|
+
# Saves changes made to this lifecycle configuration.
|
212
|
+
#
|
213
|
+
# # set the number of days before expiration for all rules to 10
|
214
|
+
# config = bucket.lifecycle_configuration
|
215
|
+
# config.rules.each do |rule|
|
216
|
+
# rule.expiration_time = 10
|
217
|
+
# end
|
218
|
+
# config.update
|
219
|
+
#
|
220
|
+
# You can call #update with a block. Changes are persisted at the
|
221
|
+
# end of the block.
|
222
|
+
#
|
223
|
+
# # shorter version of the example above
|
224
|
+
# bucket.lifecycle_configuration.update do
|
225
|
+
# rules.each {|rule| rule.expiration_time = 10 }
|
226
|
+
# end
|
227
|
+
#
|
228
|
+
# A block method for updating a BucketLifecycleConfiguration.
|
229
|
+
# All modifications made inside the block are persisted at the end of
|
230
|
+
# the block.
|
231
|
+
#
|
232
|
+
# # 1 request
|
233
|
+
# bucket.lifecycle_configuration.update do
|
234
|
+
# add_rule 'prefix/a', 10
|
235
|
+
# add_rule 'prefix/b', 5
|
236
|
+
# end
|
237
|
+
#
|
238
|
+
# # 2 requests
|
239
|
+
# bucket.lifecycle_configuration.add_rule 'prefix/a', 10
|
240
|
+
# bucket.lifecycle_configuration.add_rule 'prefix/b', 5
|
241
|
+
#
|
242
|
+
# @return [nil]
|
243
|
+
#
|
244
|
+
def update arg = {}, &block
|
245
|
+
begin
|
246
|
+
@batching = true
|
247
|
+
instance_exec(arg, &block) if block_given?
|
248
|
+
persist(true)
|
249
|
+
ensure
|
250
|
+
@batching = false
|
251
|
+
end
|
252
|
+
nil
|
253
|
+
end
|
254
|
+
|
255
|
+
# Yields to the given block. Before yielding, the current
|
256
|
+
# rules will be blanked out. This allows you to provide all
|
257
|
+
# new rules.
|
258
|
+
#
|
259
|
+
# When the block is complete, a single call will be made to save
|
260
|
+
# the new rules.
|
261
|
+
#
|
262
|
+
# bucket.lifecycle_configuration.rules.size #=> 3
|
263
|
+
#
|
264
|
+
# # replace the existing 3 rules with a single rule
|
265
|
+
# bucket.lifecycle_configuration.replace
|
266
|
+
# add_rule 'temp/', 10
|
267
|
+
# end
|
268
|
+
#
|
269
|
+
# bucket.lifecycle_configuration.rules.size #=> 1
|
270
|
+
def replace &block
|
271
|
+
@rules = []
|
272
|
+
update(&block)
|
273
|
+
end
|
274
|
+
|
275
|
+
def clear
|
276
|
+
@rules = []
|
277
|
+
bucket.lifecycle_configuration = nil
|
278
|
+
end
|
279
|
+
alias_method :remove, :clear
|
280
|
+
|
281
|
+
# @return [String] Returns an xml string representation of this
|
282
|
+
# bucket lifecycle configuration.
|
283
|
+
def to_xml
|
284
|
+
Nokogiri::XML::Builder.new do |xml|
|
285
|
+
xml.LifecycleConfiguration do
|
286
|
+
rules.each do |rule|
|
287
|
+
xml.Rule do
|
288
|
+
xml.ID rule.id
|
289
|
+
xml.Prefix rule.prefix
|
290
|
+
xml.Status rule.status
|
291
|
+
xml.Expiration do
|
292
|
+
if Integer === rule.expiration_time
|
293
|
+
xml.Days rule.expiration_time
|
294
|
+
else
|
295
|
+
date = rule.expiration_time.to_s
|
296
|
+
xml.Date "#{date}T00:00:00Z"
|
297
|
+
end
|
298
|
+
end if rule.expiration_time
|
299
|
+
xml.Transition do
|
300
|
+
xml.StorageClass 'GLACIER'
|
301
|
+
if Integer === rule.glacier_transition_time
|
302
|
+
xml.Days rule.glacier_transition_time
|
303
|
+
else
|
304
|
+
date = rule.glacier_transition_time.to_s
|
305
|
+
xml.Date "#{date}T00:00:00Z"
|
306
|
+
end
|
307
|
+
end if rule.glacier_transition_time
|
308
|
+
xml.NoncurrentVersionTransition do
|
309
|
+
xml.StorageClass 'GLACIER'
|
310
|
+
xml.NoncurrentDays rule.noncurrent_version_transition_days
|
311
|
+
end if rule.noncurrent_version_transition_days
|
312
|
+
xml.NoncurrentVersionExpiration do
|
313
|
+
xml.NoncurrentDays rule.noncurrent_version_expiration_days
|
314
|
+
end if rule.noncurrent_version_expiration_days
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end.doc.root.to_xml
|
319
|
+
end
|
320
|
+
|
321
|
+
protected
|
322
|
+
def persist force = false
|
323
|
+
unless @batching and force == false
|
324
|
+
if rules.empty?
|
325
|
+
bucket.lifecycle_configuration = nil
|
326
|
+
else
|
327
|
+
bucket.lifecycle_configuration = self
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
# Represents a single rule from an Amazon S3 bucket lifecycle
|
333
|
+
# configuration.
|
334
|
+
#
|
335
|
+
# # delete all objects with the prefix 'temporary/' after 10 days
|
336
|
+
# bucket.lifecycle_configuration.add_rule 'temporary/', 10
|
337
|
+
#
|
338
|
+
# # remove the rule created above
|
339
|
+
# bucket.lifecycle_configuration.remove_rule 'temporary/'
|
340
|
+
#
|
341
|
+
#
|
342
|
+
class Rule
|
343
|
+
|
344
|
+
# @api private
|
345
|
+
def initialize configuration, id, prefix, expiration_time = nil, status = nil
|
346
|
+
@configuration = configuration
|
347
|
+
@id = id
|
348
|
+
@prefix = prefix
|
349
|
+
|
350
|
+
if Hash === expiration_time
|
351
|
+
options = expiration_time
|
352
|
+
options.each do |key, value|
|
353
|
+
send("#{key}=", value) if respond_to?("#{key}=")
|
354
|
+
end
|
355
|
+
else
|
356
|
+
self.expiration_time = expiration_time
|
357
|
+
self.status = status
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
# @return [BucketLifecycleConfiguration]
|
362
|
+
attr_reader :configuration
|
363
|
+
|
364
|
+
# @return [String]
|
365
|
+
attr_reader :id
|
366
|
+
|
367
|
+
# @return [String]
|
368
|
+
attr_accessor :prefix
|
369
|
+
|
370
|
+
# @return [Date] the date the objects will expire
|
371
|
+
# @return [Integer] if the value is an integer, returns the number
|
372
|
+
# of days before the object will expire.
|
373
|
+
attr_reader :expiration_time
|
374
|
+
|
375
|
+
# Converts any time values to Date objects
|
376
|
+
def expiration_time=(value)
|
377
|
+
@expiration_time = convert_time_value(value)
|
378
|
+
end
|
379
|
+
|
380
|
+
alias expiration_days expiration_time
|
381
|
+
alias expiration_days= expiration_time=
|
382
|
+
|
383
|
+
# @return [Date] the date the objects will be
|
384
|
+
# transitioned into the Amazon Glacier storage tier.
|
385
|
+
# @return [Integer] if the value is an integer, returns the number
|
386
|
+
# of days before the object is transitioned into the Amazon Glacier
|
387
|
+
# storage tier.
|
388
|
+
attr_reader :glacier_transition_time
|
389
|
+
|
390
|
+
# Converts any time values to Date objects
|
391
|
+
def glacier_transition_time=(value)
|
392
|
+
@glacier_transition_time = convert_time_value(value)
|
393
|
+
end
|
394
|
+
|
395
|
+
# @return [Integer]
|
396
|
+
attr_accessor :noncurrent_version_transition_days
|
397
|
+
|
398
|
+
# @return [Integer]
|
399
|
+
attr_accessor :noncurrent_version_expiration_days
|
400
|
+
|
401
|
+
# @return [String] Returns the rule status, 'Enabled' or 'Disabled'
|
402
|
+
attr_accessor :status
|
403
|
+
|
404
|
+
def enabled?
|
405
|
+
status == 'Enabled'
|
406
|
+
end
|
407
|
+
|
408
|
+
def enable!
|
409
|
+
self.status = 'Enabled'
|
410
|
+
end
|
411
|
+
|
412
|
+
def disabled?
|
413
|
+
status == 'Disabled'
|
414
|
+
end
|
415
|
+
|
416
|
+
def disabled!
|
417
|
+
self.status = 'Disabled'
|
418
|
+
end
|
419
|
+
|
420
|
+
# @api private
|
421
|
+
def eql? other
|
422
|
+
other.is_a?(Rule) and
|
423
|
+
other.configuration.bucket == configuration.bucket and
|
424
|
+
other.id == id and
|
425
|
+
other.prefix == prefix and
|
426
|
+
other.expiration_time == expiration_time and
|
427
|
+
other.glacier_transition_time == glacier_transition_time and
|
428
|
+
other.status == status and
|
429
|
+
other.noncurrent_version_transition_days == noncurrent_version_transition_days and
|
430
|
+
other.noncurrent_version_expiration_days == noncurrent_version_expiration_days
|
431
|
+
end
|
432
|
+
alias_method :==, :eql?
|
433
|
+
|
434
|
+
private
|
435
|
+
|
436
|
+
# If an integer, returns the integer as days, otherwise
|
437
|
+
# converts any time-like values into Date objects
|
438
|
+
# @return [Integer] if the value is an integer
|
439
|
+
# @return [Date] if the value is a time-like object
|
440
|
+
# @return [nil] if the value is nil
|
441
|
+
def convert_time_value(value)
|
442
|
+
return nil if value.nil?
|
443
|
+
return value if value.is_a?(Integer)
|
444
|
+
Date.parse(value.to_s)
|
445
|
+
end
|
446
|
+
|
447
|
+
end
|
448
|
+
|
449
|
+
protected
|
450
|
+
|
451
|
+
def parse_xml xml
|
452
|
+
Client::XML::GetBucketLifecycleConfiguration.parse(xml).rules.map do |r|
|
453
|
+
opts = { :status => r[:status] }
|
454
|
+
|
455
|
+
if r[:expiration]
|
456
|
+
opts[:expiration_time] =
|
457
|
+
r[:expiration][:days] || r[:expiration][:date]
|
458
|
+
end
|
459
|
+
|
460
|
+
if r[:transition]
|
461
|
+
opts[:glacier_transition_time] =
|
462
|
+
r[:transition][:days] || r[:transition][:date]
|
463
|
+
end
|
464
|
+
|
465
|
+
Rule.new(self, r[:id], r[:prefix], opts)
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
end
|
470
|
+
|
471
|
+
end
|
472
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module MSS
|
4
|
+
class S3
|
5
|
+
class BucketRegionCache
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@regions = {}
|
9
|
+
@mutex = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](bucket_name)
|
13
|
+
@mutex.synchronize do
|
14
|
+
@regions[bucket_name]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(bucket_name, region_name)
|
19
|
+
@mutex.synchronize do
|
20
|
+
@regions[bucket_name] = region_name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(bucket_name)
|
25
|
+
@mutex.synchronize do
|
26
|
+
@regions[bucket_name] = region_name
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update!(bucket_regions)
|
31
|
+
@mutex.synchronize do
|
32
|
+
@regions.update!(bucket_regions)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def clear
|
37
|
+
@mutex.synchronize do
|
38
|
+
@regions = {}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_hash
|
43
|
+
@mutex.synchronize do
|
44
|
+
@regions.dup
|
45
|
+
end
|
46
|
+
end
|
47
|
+
alias to_h to_hash
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|