configure-s3-website-ng 3.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/.gitignore +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +2 -0
- data/LICENSE +19 -0
- data/README.md +280 -0
- data/Rakefile +11 -0
- data/bin/configure-s3-website +12 -0
- data/changelog.md +157 -0
- data/configure-s3-website.gemspec +23 -0
- data/lib/configure-s3-website/cli.rb +43 -0
- data/lib/configure-s3-website/cloudfront_client.rb +172 -0
- data/lib/configure-s3-website/config_source/config_source.rb +30 -0
- data/lib/configure-s3-website/config_source/file_config_source.rb +87 -0
- data/lib/configure-s3-website/endpoint_helper.rb +26 -0
- data/lib/configure-s3-website/http_helper.rb +74 -0
- data/lib/configure-s3-website/runner.rb +31 -0
- data/lib/configure-s3-website/s3_client.rb +129 -0
- data/lib/configure-s3-website/version.rb +3 -0
- data/lib/configure-s3-website/xml_helper.rb +15 -0
- data/lib/configure-s3-website.rb +10 -0
- data/spec/cloudfront_client_spec.rb +138 -0
- data/spec/config_source/file_config_source_spec.rb +68 -0
- data/spec/s3_client_spec.rb +162 -0
- data/spec/sample_files/_config_file.yml +3 -0
- data/spec/sample_files/_config_file_EU.yml +4 -0
- data/spec/sample_files/_config_file_no_credentials.yml +1 -0
- data/spec/sample_files/_config_file_oregon.yml +4 -0
- data/spec/sample_files/_config_file_with_eruby.yml +3 -0
- data/spec/sample_files/_custom_index_and_error_docs.yml +5 -0
- data/spec/sample_files/_custom_index_and_error_docs_with_routing_rules.yml +12 -0
- data/spec/xml_helper_spec.rb +39 -0
- metadata +145 -0
@@ -0,0 +1,172 @@
|
|
1
|
+
require "aws-sdk"
|
2
|
+
require 'deep_merge'
|
3
|
+
|
4
|
+
module ConfigureS3Website
|
5
|
+
class CloudFrontClient
|
6
|
+
def self.apply_distribution_config(options)
|
7
|
+
config_source = options[:config_source]
|
8
|
+
puts "Detected an existing CloudFront distribution (id #{config_source.cloudfront_distribution_id}) ..."
|
9
|
+
|
10
|
+
live_config = cloudfront(config_source).get_distribution({
|
11
|
+
id: options[:config_source].cloudfront_distribution_id
|
12
|
+
})
|
13
|
+
|
14
|
+
custom_distribution_config = config_source.cloudfront_distribution_config || {}
|
15
|
+
if custom_distribution_config.empty?
|
16
|
+
return
|
17
|
+
end
|
18
|
+
live_distribution_config = live_config.distribution.distribution_config.to_hash
|
19
|
+
custom_distribution_config_with_caller_ref = live_distribution_config.deep_merge!(
|
20
|
+
deep_symbolize(custom_distribution_config.merge({
|
21
|
+
caller_reference: live_config.distribution.distribution_config.caller_reference,
|
22
|
+
comment: 'Updated by the configure-s3-website gem'
|
23
|
+
})),
|
24
|
+
ConfigureS3Website::deep_merge_options
|
25
|
+
)
|
26
|
+
cloudfront(config_source).update_distribution({
|
27
|
+
distribution_config: custom_distribution_config_with_caller_ref,
|
28
|
+
id: options[:config_source].cloudfront_distribution_id,
|
29
|
+
if_match: live_config.etag
|
30
|
+
})
|
31
|
+
|
32
|
+
print_report_on_custom_distribution_config custom_distribution_config_with_caller_ref
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.create_distribution_if_user_agrees(options, standard_input)
|
36
|
+
if options['autocreate-cloudfront-dist'] and options[:headless]
|
37
|
+
puts 'Creating a CloudFront distribution for your S3 website ...'
|
38
|
+
create_distribution options
|
39
|
+
elsif options[:headless]
|
40
|
+
# Do nothing
|
41
|
+
else
|
42
|
+
puts 'Do you want to deliver your website via CloudFront, Amazon’s CDN service? [y/N]'
|
43
|
+
case standard_input.gets.chomp
|
44
|
+
when /(y|Y)/ then create_distribution options
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def self.cloudfront(config_source)
|
52
|
+
Aws::CloudFront::Client.new(
|
53
|
+
region: 'us-east-1',
|
54
|
+
access_key_id: config_source.s3_access_key_id,
|
55
|
+
secret_access_key: config_source.s3_secret_access_key
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.create_distribution(options)
|
60
|
+
config_source = options[:config_source]
|
61
|
+
custom_distribution_config = config_source.cloudfront_distribution_config || {}
|
62
|
+
distribution = cloudfront(config_source).create_distribution(
|
63
|
+
deep_symbolize new_distribution_config(config_source, custom_distribution_config)
|
64
|
+
).distribution
|
65
|
+
dist_id = distribution.id
|
66
|
+
print_report_on_new_dist distribution, dist_id, options, config_source
|
67
|
+
config_source.cloudfront_distribution_id = dist_id.to_s
|
68
|
+
puts " Added setting 'cloudfront_distribution_id: #{dist_id}' into #{config_source.description}"
|
69
|
+
unless custom_distribution_config.empty?
|
70
|
+
print_report_on_custom_distribution_config custom_distribution_config
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.print_report_on_custom_distribution_config(custom_distribution_config, left_padding = 4)
|
75
|
+
puts ' Applied custom distribution settings:'
|
76
|
+
puts custom_distribution_config.
|
77
|
+
to_yaml.
|
78
|
+
to_s.
|
79
|
+
gsub("---\n", '').
|
80
|
+
gsub(/^/, padding(left_padding))
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.print_report_on_new_dist(distribution, dist_id, options, config_source)
|
84
|
+
config_source = options[:config_source]
|
85
|
+
puts " The distribution #{dist_id} at #{distribution.domain_name} now delivers the origin #{distribution.distribution_config.origins.items[0].domain_name}"
|
86
|
+
puts ' Please allow up to 15 minutes for the distribution to initialise'
|
87
|
+
puts ' For more information on the distribution, see https://console.aws.amazon.com/cloudfront'
|
88
|
+
if options[:verbose]
|
89
|
+
puts ' Below is the response from the CloudFront API:'
|
90
|
+
puts distribution
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.new_distribution_config(config_source, custom_cf_settings)
|
95
|
+
{
|
96
|
+
'distribution_config' => {
|
97
|
+
'caller_reference' => 'configure-s3-website gem ' + Time.now.to_s,
|
98
|
+
'default_root_object' => 'index.html',
|
99
|
+
'origins' => {
|
100
|
+
'quantity' => 1,
|
101
|
+
'items' => [
|
102
|
+
{
|
103
|
+
'id' => (origin_id config_source),
|
104
|
+
'domain_name' => "#{config_source.s3_bucket_name}.#{EndpointHelper.s3_website_hostname(config_source.s3_endpoint)}",
|
105
|
+
'custom_origin_config' => {
|
106
|
+
'http_port' => 80,
|
107
|
+
'https_port' => 443,
|
108
|
+
'origin_protocol_policy' => 'http-only'
|
109
|
+
}
|
110
|
+
}
|
111
|
+
]
|
112
|
+
},
|
113
|
+
'logging' => {
|
114
|
+
'enabled' => 'false',
|
115
|
+
'include_cookies' => 'false',
|
116
|
+
'bucket' => '',
|
117
|
+
'prefix' => ''
|
118
|
+
},
|
119
|
+
'enabled' => 'true',
|
120
|
+
'comment' => 'Created by the configure-s3-website gem',
|
121
|
+
'aliases' => {
|
122
|
+
'quantity' => '0'
|
123
|
+
},
|
124
|
+
'default_cache_behavior' => {
|
125
|
+
'target_origin_id' => (origin_id config_source),
|
126
|
+
'trusted_signers' => {
|
127
|
+
'enabled' => 'false',
|
128
|
+
'quantity' => '0'
|
129
|
+
},
|
130
|
+
'forwarded_values' => {
|
131
|
+
'query_string' => 'true',
|
132
|
+
'cookies' => {
|
133
|
+
'forward' => 'all'
|
134
|
+
}
|
135
|
+
},
|
136
|
+
'viewer_protocol_policy' => 'allow-all',
|
137
|
+
'min_ttl' => '86400'
|
138
|
+
},
|
139
|
+
'cache_behaviors' => {
|
140
|
+
'quantity' => '0'
|
141
|
+
},
|
142
|
+
'price_class' => 'PriceClass_All'
|
143
|
+
}.deep_merge!(custom_cf_settings, ConfigureS3Website::deep_merge_options)
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.origin_id(config_source)
|
148
|
+
"#{config_source.s3_bucket_name}-S3-origin"
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.padding(amount)
|
152
|
+
padding = ''
|
153
|
+
amount.times { padding << " " }
|
154
|
+
padding
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.deep_symbolize(value)
|
158
|
+
if value.is_a? Hash
|
159
|
+
Hash[value.map { |k,v| [k.to_sym, deep_symbolize(v)] }]
|
160
|
+
elsif value.is_a? Array
|
161
|
+
value.map { |v| deep_symbolize(v) }
|
162
|
+
else
|
163
|
+
value
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
def self.deep_merge_options
|
168
|
+
{
|
169
|
+
:merge_hash_arrays => true
|
170
|
+
}
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ConfigureS3Website
|
2
|
+
class ConfigSource
|
3
|
+
def description
|
4
|
+
end
|
5
|
+
|
6
|
+
def s3_access_key_id
|
7
|
+
end
|
8
|
+
|
9
|
+
def s3_secret_access_key
|
10
|
+
end
|
11
|
+
|
12
|
+
def s3_bucket_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def s3_endpoint
|
16
|
+
end
|
17
|
+
|
18
|
+
def routing_rules
|
19
|
+
end
|
20
|
+
|
21
|
+
def cloudfront_distribution_config
|
22
|
+
end
|
23
|
+
|
24
|
+
def cloudfront_distribution_id
|
25
|
+
end
|
26
|
+
|
27
|
+
def cloudfront_distribution_id=(dist_id)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module ConfigureS3Website
|
5
|
+
class FileConfigSource < ConfigSource
|
6
|
+
def initialize(yaml_file_path)
|
7
|
+
@yaml_file_path = yaml_file_path
|
8
|
+
@config = FileConfigSource.parse_config yaml_file_path
|
9
|
+
end
|
10
|
+
|
11
|
+
def description
|
12
|
+
@yaml_file_path
|
13
|
+
end
|
14
|
+
|
15
|
+
def s3_access_key_id
|
16
|
+
@config['s3_id']
|
17
|
+
end
|
18
|
+
|
19
|
+
def s3_secret_access_key
|
20
|
+
@config['s3_secret']
|
21
|
+
end
|
22
|
+
|
23
|
+
def profile
|
24
|
+
@config['profile']
|
25
|
+
end
|
26
|
+
|
27
|
+
def s3_bucket_name
|
28
|
+
@config['s3_bucket']
|
29
|
+
end
|
30
|
+
|
31
|
+
def s3_endpoint
|
32
|
+
endpoint = @config['s3_endpoint'] || 'us-east-1'
|
33
|
+
if endpoint == 'EU'
|
34
|
+
'eu-west-1'
|
35
|
+
else
|
36
|
+
endpoint
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def routing_rules
|
41
|
+
@config['routing_rules']
|
42
|
+
end
|
43
|
+
|
44
|
+
def index_document
|
45
|
+
@config['index_document']
|
46
|
+
end
|
47
|
+
|
48
|
+
def error_document
|
49
|
+
@config['error_document']
|
50
|
+
end
|
51
|
+
|
52
|
+
def cloudfront_distribution_config
|
53
|
+
@config['cloudfront_distribution_config']
|
54
|
+
end
|
55
|
+
|
56
|
+
def cloudfront_distribution_id
|
57
|
+
@config['cloudfront_distribution_id']
|
58
|
+
end
|
59
|
+
|
60
|
+
def cloudfront_distribution_id=(dist_id)
|
61
|
+
@config['cloudfront_distribution_id'] = dist_id
|
62
|
+
file_contents = File.open(@yaml_file_path).read
|
63
|
+
File.open(@yaml_file_path, 'w') do |file|
|
64
|
+
result = file_contents.gsub(
|
65
|
+
/(s3_bucket:.*$)/,
|
66
|
+
"\\1\ncloudfront_distribution_id: #{dist_id}"
|
67
|
+
)
|
68
|
+
file.write result
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def self.parse_config(yaml_file_path)
|
75
|
+
config = YAML.load(ERB.new(File.read(yaml_file_path)).result)
|
76
|
+
validate_config(config, yaml_file_path)
|
77
|
+
config
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.validate_config(config, yaml_file_path)
|
81
|
+
# make sure the bucket name is configured at a minimum
|
82
|
+
if not config.keys.include?'s3_bucket'
|
83
|
+
raise "File #{yaml_file_path} does not contain the required key 's3_bucket'"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ConfigureS3Website
|
2
|
+
class EndpointHelper
|
3
|
+
def self.s3_website_hostname(region)
|
4
|
+
if old_regions.include?(region)
|
5
|
+
"s3-website-#{region}.amazonaws.com"
|
6
|
+
else
|
7
|
+
"s3-website.#{region}.amazonaws.com"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def self.old_regions
|
14
|
+
[
|
15
|
+
'us-east-1',
|
16
|
+
'us-west-1',
|
17
|
+
'us-west-2',
|
18
|
+
'ap-southeast-1',
|
19
|
+
'ap-southeast-2',
|
20
|
+
'ap-northeast-1',
|
21
|
+
'eu-west-1',
|
22
|
+
'sa-east-1'
|
23
|
+
]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module ConfigureS3Website
|
2
|
+
class HttpHelper
|
3
|
+
def self.call_cloudfront_api(path, method, body, config_source, headers = {})
|
4
|
+
date = Time.now.utc.strftime("%a, %d %b %Y %H:%M:%S %Z")
|
5
|
+
digest = create_cloudfront_digest(config_source, date)
|
6
|
+
self.call_api(
|
7
|
+
path,
|
8
|
+
method,
|
9
|
+
body,
|
10
|
+
config_source,
|
11
|
+
'cloudfront.amazonaws.com',
|
12
|
+
digest,
|
13
|
+
date,
|
14
|
+
headers
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def self.call_api(path, method, body, config_source, hostname, digest, date, additional_headers = {})
|
21
|
+
url = "https://#{hostname}#{path}"
|
22
|
+
uri = URI.parse(url)
|
23
|
+
req = method.new(uri.to_s)
|
24
|
+
req.initialize_http_header({
|
25
|
+
'Date' => date,
|
26
|
+
'Content-Type' => '',
|
27
|
+
'Content-Length' => body.length.to_s,
|
28
|
+
'Authorization' => "AWS %s:%s" % [config_source.s3_access_key_id, digest]
|
29
|
+
}.merge(additional_headers))
|
30
|
+
req.body = body
|
31
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
32
|
+
# http.set_debug_output $stderr
|
33
|
+
http.use_ssl = true
|
34
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
35
|
+
res = http.request(req)
|
36
|
+
if res.code.to_i.between? 200, 299
|
37
|
+
res
|
38
|
+
else
|
39
|
+
raise ConfigureS3Website::ErrorParser.create_error res.body
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.create_cloudfront_digest(config_source, date)
|
44
|
+
digest = Base64.encode64(
|
45
|
+
OpenSSL::HMAC.digest(
|
46
|
+
OpenSSL::Digest.new('sha1'),
|
47
|
+
config_source.s3_secret_access_key,
|
48
|
+
date
|
49
|
+
)
|
50
|
+
).strip
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
module ConfigureS3Website
|
58
|
+
class ErrorParser
|
59
|
+
def self.create_error(amazon_error_xml)
|
60
|
+
error_code = amazon_error_xml.delete('\n').match(/<Code>(.*?)<\/Code>/)[1]
|
61
|
+
begin
|
62
|
+
Object.const_get("#{error_code}Error").new
|
63
|
+
rescue NameError
|
64
|
+
GenericError.new(amazon_error_xml)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class GenericError < StandardError
|
71
|
+
def initialize(error_message)
|
72
|
+
super("AWS API call failed:\n#{error_message}")
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ConfigureS3Website
|
2
|
+
class Runner
|
3
|
+
def self.run(options, standard_input = STDIN)
|
4
|
+
S3Client.configure_website options
|
5
|
+
maybe_create_or_update_cloudfront options, standard_input
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def self.maybe_create_or_update_cloudfront(options, standard_input)
|
11
|
+
unless user_already_has_cf_configured options
|
12
|
+
CloudFrontClient.create_distribution_if_user_agrees options, standard_input
|
13
|
+
return
|
14
|
+
end
|
15
|
+
if user_already_has_cf_configured(options) and user_has_custom_cf_dist_config(options)
|
16
|
+
CloudFrontClient.apply_distribution_config options
|
17
|
+
return
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.user_already_has_cf_configured(options)
|
22
|
+
config_source = options[:config_source]
|
23
|
+
config_source.cloudfront_distribution_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.user_has_custom_cf_dist_config(options)
|
27
|
+
config_source = options[:config_source]
|
28
|
+
config_source.cloudfront_distribution_config
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
require 'digest/sha1'
|
4
|
+
require 'digest/md5'
|
5
|
+
require 'net/https'
|
6
|
+
require 'aws-sdk'
|
7
|
+
|
8
|
+
module ConfigureS3Website
|
9
|
+
class S3Client
|
10
|
+
def self.configure_website(options)
|
11
|
+
config_source = options[:config_source]
|
12
|
+
begin
|
13
|
+
enable_website_configuration(config_source)
|
14
|
+
make_bucket_readable_to_everyone(config_source)
|
15
|
+
rescue Aws::S3::Errors::NoSuchBucket
|
16
|
+
create_bucket(config_source)
|
17
|
+
retry
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def self.s3(config_source)
|
24
|
+
if config_source.s3_access_key_id
|
25
|
+
Aws::S3::Client.new(
|
26
|
+
region: config_source.s3_endpoint,
|
27
|
+
access_key_id: config_source.s3_access_key_id,
|
28
|
+
secret_access_key: config_source.s3_secret_access_key
|
29
|
+
)
|
30
|
+
elsif config_source.profile
|
31
|
+
Aws::S3::Client.new(
|
32
|
+
region: config_source.s3_endpoint,
|
33
|
+
profile: config_source.profile,
|
34
|
+
)
|
35
|
+
else
|
36
|
+
Aws::S3::Client.new(
|
37
|
+
region: config_source.s3_endpoint,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.enable_website_configuration(config_source)
|
43
|
+
routing_rules =
|
44
|
+
if config_source.routing_rules && config_source.routing_rules.is_a?(Array)
|
45
|
+
config_source.routing_rules.map { |rule|
|
46
|
+
Hash[
|
47
|
+
rule.map { |rule_key, rule_value|
|
48
|
+
[
|
49
|
+
rule_key.to_sym,
|
50
|
+
Hash[ # Assume that each rule value is a Hash
|
51
|
+
rule_value.map { |redirect_rule_key, redirect_rule_value|
|
52
|
+
[
|
53
|
+
redirect_rule_key.to_sym,
|
54
|
+
redirect_rule_key == "http_redirect_code" || redirect_rule_key == "http_error_code_returned_equals" ?
|
55
|
+
redirect_rule_value.to_s
|
56
|
+
#redirect_rule_value.to_s # Permit numeric redirect values in the YAML config file. (The S3 API does not allow numeric redirect values, hence this block of code.)
|
57
|
+
:
|
58
|
+
redirect_rule_value
|
59
|
+
]
|
60
|
+
}
|
61
|
+
]
|
62
|
+
]
|
63
|
+
}
|
64
|
+
]
|
65
|
+
}
|
66
|
+
else
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
s3(config_source).put_bucket_website({
|
70
|
+
bucket: config_source.s3_bucket_name,
|
71
|
+
website_configuration: {
|
72
|
+
index_document: {
|
73
|
+
suffix: config_source.index_document || "index.html"
|
74
|
+
},
|
75
|
+
error_document: {
|
76
|
+
key: config_source.error_document || "error.html"
|
77
|
+
},
|
78
|
+
routing_rules: routing_rules
|
79
|
+
}
|
80
|
+
})
|
81
|
+
puts "Bucket #{config_source.s3_bucket_name} now functions as a website"
|
82
|
+
if routing_rules && routing_rules.any?
|
83
|
+
puts "#{routing_rules.size} redirects configured for #{config_source.s3_bucket_name} bucket"
|
84
|
+
else
|
85
|
+
puts "No redirects to configure for #{config_source.s3_bucket_name} bucket"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.make_bucket_readable_to_everyone(config_source)
|
90
|
+
s3(config_source).delete_public_access_block({
|
91
|
+
bucket: config_source.s3_bucket_name
|
92
|
+
})
|
93
|
+
s3(config_source).put_bucket_policy({
|
94
|
+
bucket: config_source.s3_bucket_name,
|
95
|
+
policy: %|{
|
96
|
+
"Version":"2008-10-17",
|
97
|
+
"Statement":[{
|
98
|
+
"Sid":"PublicReadForGetBucketObjects",
|
99
|
+
"Effect":"Allow",
|
100
|
+
"Principal": { "AWS": "*" },
|
101
|
+
"Action":["s3:GetObject"],
|
102
|
+
"Resource":["arn:aws:s3:::#{config_source.s3_bucket_name}/*"]
|
103
|
+
}]
|
104
|
+
}|
|
105
|
+
})
|
106
|
+
puts "Bucket #{config_source.s3_bucket_name} is now readable to the whole world"
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.create_bucket(config_source)
|
110
|
+
s3(config_source).create_bucket({
|
111
|
+
bucket: config_source.s3_bucket_name,
|
112
|
+
create_bucket_configuration:
|
113
|
+
if config_source.s3_endpoint && config_source.s3_endpoint != 'us-east-1'
|
114
|
+
{
|
115
|
+
location_constraint: config_source.s3_endpoint
|
116
|
+
}
|
117
|
+
else
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
})
|
121
|
+
puts "Created bucket %s in the %s Region" %
|
122
|
+
[
|
123
|
+
config_source.s3_bucket_name,
|
124
|
+
config_source.s3_endpoint
|
125
|
+
]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ConfigureS3Website
|
2
|
+
class XmlHelper
|
3
|
+
def self.hash_to_api_xml(hash={}, indent=0)
|
4
|
+
"".tap do |body|
|
5
|
+
hash.each do |key, value|
|
6
|
+
key_name = key.sub(/^[a-z\d]*/) { $&.capitalize }.gsub(/(?:_|(\/))([a-z\d]*)/) { $2.capitalize }
|
7
|
+
value = value.is_a?(Hash) ? self.hash_to_api_xml(value, indent+1) : value
|
8
|
+
body << "\n"
|
9
|
+
body << " " * indent * 2 # 2-space indentation formatting for xml
|
10
|
+
body << "<#{key_name}>#{value}</#{key_name}>"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'configure-s3-website/version'
|
2
|
+
require 'configure-s3-website/s3_client'
|
3
|
+
require 'configure-s3-website/cloudfront_client'
|
4
|
+
require 'configure-s3-website/xml_helper'
|
5
|
+
require 'configure-s3-website/http_helper'
|
6
|
+
require 'configure-s3-website/endpoint_helper'
|
7
|
+
require 'configure-s3-website/runner'
|
8
|
+
require 'configure-s3-website/cli'
|
9
|
+
require 'configure-s3-website/config_source/config_source'
|
10
|
+
require 'configure-s3-website/config_source/file_config_source'
|