configure-s3-website 1.3.0 → 1.4.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.
- data/README.md +102 -3
- data/changelog.md +6 -0
- data/configure-s3-website.gemspec +2 -0
- data/features/cassettes/cucumber_tags/apply-configs-on-cf-dist.yml +169 -0
- data/features/create_cloudfront_dist.feature +27 -1
- data/features/modify_cloudfront_dist.feature +19 -0
- data/features/step_definitions/steps.rb +9 -1
- data/features/support/sample_config_files/apply_configs_on_cf_dist.yml +8 -0
- data/features/support/sample_config_files/create_cf_dist_with_custom_configs.yml +7 -0
- data/features/support/vcr.rb +1 -0
- data/lib/configure-s3-website/cloudfront_client.rb +81 -18
- data/lib/configure-s3-website/config_source/config_source.rb +3 -0
- data/lib/configure-s3-website/config_source/file_config_source.rb +4 -0
- data/lib/configure-s3-website/http_helper.rb +19 -5
- data/lib/configure-s3-website/runner.rb +16 -2
- data/lib/configure-s3-website/version.rb +1 -1
- data/spec/cloudfront_client_spec.rb +71 -0
- metadata +30 -4
data/README.md
CHANGED
@@ -33,6 +33,10 @@ you.
|
|
33
33
|
|
34
34
|
### Deliver your website via CloudFront
|
35
35
|
|
36
|
+
This gem can create new CloudFront distributions and update existing ones.
|
37
|
+
|
38
|
+
#### Creating a new distribution
|
39
|
+
|
36
40
|
`configure-s3-website` can create a CloudFront distribution for you. It will ask
|
37
41
|
you whether you want to deliver your website via the CDN. If you answer yes,
|
38
42
|
`configure-s3-website` will create a CloudFront distribution that has the
|
@@ -55,9 +59,102 @@ configuration file, `configure-s3-website` will not create a new distribution.
|
|
55
59
|
Conversely, if you remove the `cloudfront_distribution_id` key from the file and
|
56
60
|
run `configure-s3-website` again, it will create you a new distribution.
|
57
61
|
|
58
|
-
|
62
|
+
##### Creating a new distribution with custom settings
|
63
|
+
|
64
|
+
If the default settings do not suit you, you can create a new distribution with
|
65
|
+
your settings by adding `cloudfront_distribution_config` values into your config
|
66
|
+
file. For example:
|
67
|
+
|
68
|
+
```yaml
|
69
|
+
cloudfront_distribution_config:
|
70
|
+
default_cache_behavior:
|
71
|
+
min_TTL: 600
|
72
|
+
default_root_object: index.json
|
73
|
+
```
|
74
|
+
|
75
|
+
See the section below for more information about the valid values of the
|
76
|
+
`cloudfront_distribution_config` setting.
|
77
|
+
|
78
|
+
If you want to, you can look at the distribution settings on the management console
|
59
79
|
at <https://console.aws.amazon.com/cloudfront>.
|
60
80
|
|
81
|
+
#### Updating an existing distribution
|
82
|
+
|
83
|
+
You can modify an existing CloudFront distribution by defining the id of the
|
84
|
+
distribution and the configs you wish to override the defaults with.
|
85
|
+
|
86
|
+
Let's say your config file contains the following fragment:
|
87
|
+
|
88
|
+
```yaml
|
89
|
+
cloudfront_distribution_id: AXSAXSSE134
|
90
|
+
cloudfront_distribution_config:
|
91
|
+
default_cache_behavior:
|
92
|
+
min_TTL: 600
|
93
|
+
default_root_object: index.json
|
94
|
+
```
|
95
|
+
|
96
|
+
When you invoke `configure-s3-website`, it will overwrite the default value of
|
97
|
+
*default_cache_behavior's* *min_TTL* as well as the default value of
|
98
|
+
*default_root_object* setting in the [default distribution configs](#default-distribution-configs).
|
99
|
+
|
100
|
+
This gem generates `<DistributionConfig>` of the CloudFront REST API. For
|
101
|
+
reference, see
|
102
|
+
<http://docs.aws.amazon.com/AmazonCloudFront/latest/APIReference/GetConfig.html#GetConfig_Responses>
|
103
|
+
(example) and
|
104
|
+
<https://cloudfront.amazonaws.com/doc/2012-07-01/AmazonCloudFrontCommon.xsd>
|
105
|
+
(XSD). In other words, When you call `configure-s3-website`, it will turn the values of your
|
106
|
+
`cloudfront_distribution_config` into XML, include them in the
|
107
|
+
`<DistributionConfig>` element and send them to the CloudFront REST API.
|
108
|
+
|
109
|
+
The YAML keys in the config file will be turned into CloudFront REST API XML
|
110
|
+
with the same logic as in [configuring redirects](#configuring-redirects).
|
111
|
+
|
112
|
+
Having the distribution settings in the config file is handy, because it allows
|
113
|
+
you to store most (in many cases all) website deployment settings in one file.
|
114
|
+
|
115
|
+
#### Default distribution configs
|
116
|
+
|
117
|
+
Below is the default CloudFront distribution config. It is built based on the
|
118
|
+
API version 2012-07-01 of [DistributionConfig Complex
|
119
|
+
Type](http://docs.aws.amazon.com/AmazonCloudFront/latest/APIReference/DistributionConfigDatatype.html).
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
{
|
123
|
+
'caller_reference' => 'configure-s3-website gem [generated-timestamp]',
|
124
|
+
'default_root_object' => 'index.html',
|
125
|
+
'logging' => {
|
126
|
+
'enabled' => 'false',
|
127
|
+
'include_cookies' => 'false',
|
128
|
+
'bucket' => '',
|
129
|
+
'prefix' => ''
|
130
|
+
},
|
131
|
+
'enabled' => 'true',
|
132
|
+
'comment' => 'Created by the configure-s3-website gem',
|
133
|
+
'aliases' => {
|
134
|
+
'quantity' => '0'
|
135
|
+
},
|
136
|
+
'default_cache_behavior' => {
|
137
|
+
'target_origin_id' => '[generated-string]',
|
138
|
+
'trusted_signers' => {
|
139
|
+
'enabled' => 'false',
|
140
|
+
'quantity' => '0'
|
141
|
+
},
|
142
|
+
'forwarded_values' => {
|
143
|
+
'query_string' => 'true',
|
144
|
+
'cookies' => {
|
145
|
+
'forward' => 'all'
|
146
|
+
}
|
147
|
+
},
|
148
|
+
'viewer_protocol_policy' => 'allow-all',
|
149
|
+
'min_TTL' => '86400'
|
150
|
+
},
|
151
|
+
'cache_behaviors' => {
|
152
|
+
'quantity' => '0'
|
153
|
+
},
|
154
|
+
'price_class' => 'PriceClass_All'
|
155
|
+
}
|
156
|
+
```
|
157
|
+
|
61
158
|
### Specifying a non-standard S3 endpoint
|
62
159
|
|
63
160
|
By default, `configure-s3-website` creates the S3 website into the US Standard
|
@@ -109,8 +206,10 @@ the bucket. In brief, it does the following things:
|
|
109
206
|
3. Make the bucket **readable to the whole world**
|
110
207
|
4. Apply the redirect (a.k.a routing) rules on the bucket website
|
111
208
|
|
112
|
-
|
113
|
-
|
209
|
+
When interacting with CloudFront, `configure-s3-website` uses the [POST
|
210
|
+
Distribution](http://docs.aws.amazon.com/AmazonCloudFront/latest/APIReference/CreateDistribution.html),
|
211
|
+
[GET
|
212
|
+
Distribution](http://docs.aws.amazon.com/AmazonCloudFront/latest/APIReference/GetDistribution.html) and [PUT Distribution Config](http://docs.aws.amazon.com/AmazonCloudFront/latest/APIReference/PutConfig.html) APIs.
|
114
213
|
|
115
214
|
## Development
|
116
215
|
|
data/changelog.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
This project uses [Semantic Versioning](http://semver.org).
|
4
4
|
|
5
|
+
## 1.4.0
|
6
|
+
|
7
|
+
* Allow the user to store his CloudFront settings in the config file
|
8
|
+
* Support updating configs of an existing CloudFront distribution
|
9
|
+
* Support creating of new distros with custom CloudFront configs
|
10
|
+
|
5
11
|
## 1.3.0
|
6
12
|
|
7
13
|
* Create a CloudFront distro if the user wants to deliver his S3 website via the
|
@@ -9,6 +9,8 @@ spec = Gem::Specification.new do |s|
|
|
9
9
|
s.summary = 'Configure your AWS S3 bucket to function as a web site'
|
10
10
|
s.bindir = 'bin'
|
11
11
|
|
12
|
+
s.add_dependency 'deep_merge', '= 1.0.0'
|
13
|
+
|
12
14
|
s.add_development_dependency 'rspec', '~> 2.10.0'
|
13
15
|
s.add_development_dependency 'rspec-expectations', '~> 2.10.0'
|
14
16
|
s.add_development_dependency 'cucumber', '~> 1.2.0'
|
@@ -0,0 +1,169 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: put
|
5
|
+
uri: https://s3.amazonaws.com/website-via-cf/?website
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ! "\n <WebsiteConfiguration xmlns='http://s3.amazonaws.com/doc/2006-03-01/'>\n
|
9
|
+
\ <IndexDocument>\n <Suffix>index.html</Suffix>\n </IndexDocument>\n
|
10
|
+
\ <ErrorDocument>\n <Key>error.html</Key>\n </ErrorDocument>\n
|
11
|
+
\ </WebsiteConfiguration>\n "
|
12
|
+
headers:
|
13
|
+
Date:
|
14
|
+
- Tue, 21 May 2013 12:19:26 UTC
|
15
|
+
Content-Type:
|
16
|
+
- ''
|
17
|
+
Content-Length:
|
18
|
+
- '298'
|
19
|
+
Authorization:
|
20
|
+
- AWS foo:foo
|
21
|
+
response:
|
22
|
+
status:
|
23
|
+
code: 200
|
24
|
+
message: OK
|
25
|
+
headers:
|
26
|
+
X-Amz-Id-2:
|
27
|
+
- GtZ029e+Hum8PqKTmknJf1cB2zfnh4ug71/wVX/uDySx4ETpPfU7YcoSj7nPkUeM
|
28
|
+
X-Amz-Request-Id:
|
29
|
+
- A12EA2F4AEDA0657
|
30
|
+
Date:
|
31
|
+
- Tue, 21 May 2013 12:19:33 GMT
|
32
|
+
Content-Length:
|
33
|
+
- '0'
|
34
|
+
Server:
|
35
|
+
- AmazonS3
|
36
|
+
body:
|
37
|
+
encoding: US-ASCII
|
38
|
+
string: ''
|
39
|
+
http_version:
|
40
|
+
recorded_at: Tue, 21 May 2013 12:19:28 GMT
|
41
|
+
- request:
|
42
|
+
method: put
|
43
|
+
uri: https://s3.amazonaws.com/website-via-cf/?policy
|
44
|
+
body:
|
45
|
+
encoding: US-ASCII
|
46
|
+
string: ! "{\n \"Version\":\"2008-10-17\",\n \"Statement\":[{\n
|
47
|
+
\ \"Sid\":\"PublicReadForGetBucketObjects\",\n \"Effect\":\"Allow\",\n
|
48
|
+
\ \"Principal\": { \"AWS\": \"*\" },\n \"Action\":[\"s3:GetObject\"],\n
|
49
|
+
\ \"Resource\":[\"arn:aws:s3:::website-via-cf/*\"]\n }]\n }"
|
50
|
+
headers:
|
51
|
+
Date:
|
52
|
+
- Tue, 21 May 2013 12:19:28 UTC
|
53
|
+
Content-Type:
|
54
|
+
- ''
|
55
|
+
Content-Length:
|
56
|
+
- '283'
|
57
|
+
Authorization:
|
58
|
+
- AWS foo:foo
|
59
|
+
response:
|
60
|
+
status:
|
61
|
+
code: 204
|
62
|
+
message: No Content
|
63
|
+
headers:
|
64
|
+
X-Amz-Id-2:
|
65
|
+
- qWuZ40Adyj2wa4i/ywb3E5mjypu0HYJpQOuAhBXkQskqf7O3NBVTeZ2vQT2UzspU
|
66
|
+
X-Amz-Request-Id:
|
67
|
+
- E998426FB9B27996
|
68
|
+
Date:
|
69
|
+
- Tue, 21 May 2013 12:19:34 GMT
|
70
|
+
Server:
|
71
|
+
- AmazonS3
|
72
|
+
body:
|
73
|
+
encoding: US-ASCII
|
74
|
+
string: ''
|
75
|
+
http_version:
|
76
|
+
recorded_at: Tue, 21 May 2013 12:19:29 GMT
|
77
|
+
- request:
|
78
|
+
method: get
|
79
|
+
uri: https://cloudfront.amazonaws.com/2012-07-01/distribution/E13NX4HCPUP9BP/config
|
80
|
+
body:
|
81
|
+
encoding: US-ASCII
|
82
|
+
string: ''
|
83
|
+
headers:
|
84
|
+
Date:
|
85
|
+
- Tue, 21 May 2013 12:19:29 UTC
|
86
|
+
Content-Type:
|
87
|
+
- ''
|
88
|
+
Content-Length:
|
89
|
+
- '0'
|
90
|
+
Authorization:
|
91
|
+
- AWS foo:foo
|
92
|
+
response:
|
93
|
+
status:
|
94
|
+
code: 200
|
95
|
+
message: OK
|
96
|
+
headers:
|
97
|
+
X-Amzn-Requestid:
|
98
|
+
- b29153e6-c210-11e2-8f84-efb8518943a7
|
99
|
+
Etag:
|
100
|
+
- E234UVYUVB06TU
|
101
|
+
Content-Type:
|
102
|
+
- text/xml
|
103
|
+
Content-Length:
|
104
|
+
- '1150'
|
105
|
+
Date:
|
106
|
+
- Tue, 21 May 2013 12:19:33 GMT
|
107
|
+
body:
|
108
|
+
encoding: US-ASCII
|
109
|
+
string: ! '<?xml version="1.0"?>
|
110
|
+
|
111
|
+
<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2012-07-01/"><CallerReference>1369126181889</CallerReference><Aliases><Quantity>0</Quantity></Aliases><DefaultRootObject>index.json</DefaultRootObject><Origins><Quantity>1</Quantity><Items><Origin><Id>website-via-cf-S3-origin</Id><DomainName>website-via-cf.s3.amazonaws.com</DomainName><S3OriginConfig><OriginAccessIdentity></OriginAccessIdentity></S3OriginConfig></Origin></Items></Origins><DefaultCacheBehavior><TargetOriginId>website-via-cf-S3-origin</TargetOriginId><ForwardedValues><QueryString>true</QueryString><Cookies><Forward>all</Forward></Cookies></ForwardedValues><TrustedSigners><Enabled>false</Enabled><Quantity>0</Quantity></TrustedSigners><ViewerProtocolPolicy>allow-all</ViewerProtocolPolicy><MinTTL>3600</MinTTL></DefaultCacheBehavior><CacheBehaviors><Quantity>0</Quantity></CacheBehaviors><Comment>Created
|
112
|
+
by the configure-s3-website gem</Comment><Logging><Enabled>false</Enabled><IncludeCookies>false</IncludeCookies><Bucket></Bucket><Prefix></Prefix></Logging><PriceClass>PriceClass_All</PriceClass><Enabled>true</Enabled></DistributionConfig>'
|
113
|
+
http_version:
|
114
|
+
recorded_at: Tue, 21 May 2013 12:19:29 GMT
|
115
|
+
- request:
|
116
|
+
method: put
|
117
|
+
uri: https://cloudfront.amazonaws.com/2012-07-01/distribution/E13NX4HCPUP9BP/config
|
118
|
+
body:
|
119
|
+
encoding: US-ASCII
|
120
|
+
string: ! "\n <DistributionConfig xmlns=\"http://cloudfront.amazonaws.com/doc/2012-07-01/\">\n
|
121
|
+
\ <Origins>\n <Quantity>1</Quantity>\n <Items>\n <Origin>\n
|
122
|
+
\ <Id>website-via-cf-S3-origin</Id>\n <DomainName>website-via-cf.s3.amazonaws.com</DomainName>\n
|
123
|
+
\ <S3OriginConfig>\n <OriginAccessIdentity></OriginAccessIdentity>\n
|
124
|
+
\ </S3OriginConfig>\n </Origin>\n </Items>\n
|
125
|
+
\ </Origins>\n \n<CallerReference>1369126181889</CallerReference>\n<DefaultRootObject>index.json</DefaultRootObject>\n<Logging>\n
|
126
|
+
\ <Enabled>false</Enabled>\n <IncludeCookies>false</IncludeCookies>\n <Bucket></Bucket>\n
|
127
|
+
\ <Prefix></Prefix></Logging>\n<Enabled>true</Enabled>\n<Comment>Updated by
|
128
|
+
the configure-s3-website gem</Comment>\n<Aliases>\n <Quantity>0</Quantity></Aliases>\n<DefaultCacheBehavior>\n
|
129
|
+
\ <TargetOriginId>website-via-cf-S3-origin</TargetOriginId>\n <TrustedSigners>\n
|
130
|
+
\ <Enabled>false</Enabled>\n <Quantity>0</Quantity></TrustedSigners>\n
|
131
|
+
\ <ForwardedValues>\n <QueryString>true</QueryString>\n <Cookies>\n
|
132
|
+
\ <Forward>all</Forward></Cookies></ForwardedValues>\n <ViewerProtocolPolicy>allow-all</ViewerProtocolPolicy>\n
|
133
|
+
\ <MinTTL>3600</MinTTL></DefaultCacheBehavior>\n<CacheBehaviors>\n <Quantity>0</Quantity></CacheBehaviors>\n<PriceClass>PriceClass_All</PriceClass>\n
|
134
|
+
\ </DistributionConfig>\n "
|
135
|
+
headers:
|
136
|
+
Date:
|
137
|
+
- Tue, 21 May 2013 12:19:29 UTC
|
138
|
+
Content-Type:
|
139
|
+
- ''
|
140
|
+
Content-Length:
|
141
|
+
- '1381'
|
142
|
+
Authorization:
|
143
|
+
- AWS foo:foo
|
144
|
+
If-Match:
|
145
|
+
- E234UVYUVB06TU
|
146
|
+
response:
|
147
|
+
status:
|
148
|
+
code: 200
|
149
|
+
message: OK
|
150
|
+
headers:
|
151
|
+
X-Amzn-Requestid:
|
152
|
+
- b2e5dc3f-c210-11e2-83d0-6be74820cf4d
|
153
|
+
Etag:
|
154
|
+
- E257DGI0PKML9Q
|
155
|
+
Content-Type:
|
156
|
+
- text/xml
|
157
|
+
Content-Length:
|
158
|
+
- '1499'
|
159
|
+
Date:
|
160
|
+
- Tue, 21 May 2013 12:19:34 GMT
|
161
|
+
body:
|
162
|
+
encoding: US-ASCII
|
163
|
+
string: ! '<?xml version="1.0"?>
|
164
|
+
|
165
|
+
<Distribution xmlns="http://cloudfront.amazonaws.com/doc/2012-07-01/"><Id>E13NX4HCPUP9BP</Id><Status>InProgress</Status><LastModifiedTime>2013-05-21T12:19:35.353Z</LastModifiedTime><InProgressInvalidationBatches>0</InProgressInvalidationBatches><DomainName>d2u7lu18vsudvw.cloudfront.net</DomainName><ActiveTrustedSigners><Enabled>false</Enabled><Quantity>0</Quantity></ActiveTrustedSigners><DistributionConfig><CallerReference>1369126181889</CallerReference><Aliases><Quantity>0</Quantity></Aliases><DefaultRootObject>index.json</DefaultRootObject><Origins><Quantity>1</Quantity><Items><Origin><Id>website-via-cf-S3-origin</Id><DomainName>website-via-cf.s3.amazonaws.com</DomainName><S3OriginConfig><OriginAccessIdentity></OriginAccessIdentity></S3OriginConfig></Origin></Items></Origins><DefaultCacheBehavior><TargetOriginId>website-via-cf-S3-origin</TargetOriginId><ForwardedValues><QueryString>true</QueryString><Cookies><Forward>all</Forward></Cookies></ForwardedValues><TrustedSigners><Enabled>false</Enabled><Quantity>0</Quantity></TrustedSigners><ViewerProtocolPolicy>allow-all</ViewerProtocolPolicy><MinTTL>3600</MinTTL></DefaultCacheBehavior><CacheBehaviors><Quantity>0</Quantity></CacheBehaviors><Comment>Updated
|
166
|
+
by the configure-s3-website gem</Comment><Logging><Enabled>false</Enabled><IncludeCookies>false</IncludeCookies><Bucket></Bucket><Prefix></Prefix></Logging><PriceClass>PriceClass_All</PriceClass><Enabled>true</Enabled></DistributionConfig></Distribution>'
|
167
|
+
http_version:
|
168
|
+
recorded_at: Tue, 21 May 2013 12:19:30 GMT
|
169
|
+
recorded_with: VCR 2.3.0
|
@@ -1,4 +1,4 @@
|
|
1
|
-
Feature: Create CloudFront distribution
|
1
|
+
Feature: Create a CloudFront distribution
|
2
2
|
|
3
3
|
@create-cf-dist
|
4
4
|
Scenario: The user wants to deliver his website via CloudFront
|
@@ -18,6 +18,31 @@ Feature: Create CloudFront distribution
|
|
18
18
|
Added setting 'cloudfront_distribution_id: E45H2VN49KPDU' into features/support/sample_config_files/create_cf_dist.yml
|
19
19
|
|
20
20
|
"""
|
21
|
+
And the config file should contain the distribution id
|
22
|
+
|
23
|
+
@create-cf-dist
|
24
|
+
Scenario: The user wants create a CloudFront distribution with his own settings
|
25
|
+
Given I answer 'yes' to 'do you want to use CloudFront'
|
26
|
+
When I run the configure-s3-website command with parameters
|
27
|
+
| option | value |
|
28
|
+
| --config-file | features/support/sample_config_files/create_cf_dist_with_custom_configs.yml |
|
29
|
+
Then the output should be
|
30
|
+
"""
|
31
|
+
Bucket website-via-cf now functions as a website
|
32
|
+
Bucket website-via-cf is now readable to the whole world
|
33
|
+
No redirects to configure for website-via-cf bucket
|
34
|
+
Do you want to deliver your website via CloudFront, the CDN of Amazon? [y/N]
|
35
|
+
The distribution E45H2VN49KPDU at d3feoe9t5ufu01.cloudfront.net now delivers the bucket website-via-cf
|
36
|
+
Please allow up to 15 minutes for the distribution to initialise
|
37
|
+
For more information on the distribution, see https://console.aws.amazon.com/cloudfront
|
38
|
+
Added setting 'cloudfront_distribution_id: E45H2VN49KPDU' into features/support/sample_config_files/create_cf_dist_with_custom_configs.yml
|
39
|
+
Applied custom distribution settings:
|
40
|
+
default_cache_behavior:
|
41
|
+
min_TTL: 600
|
42
|
+
default_root_object: index.json
|
43
|
+
|
44
|
+
"""
|
45
|
+
And the config file should contain the distribution id
|
21
46
|
|
22
47
|
@create-cf-dist
|
23
48
|
Scenario: The user wants to deliver his website via CloudFront and see details on the new distribution
|
@@ -149,6 +174,7 @@ Feature: Create CloudFront distribution
|
|
149
174
|
Added setting 'cloudfront_distribution_id: E45H2VN49KPDU' into features/support/sample_config_files/create_cf_dist.yml
|
150
175
|
|
151
176
|
"""
|
177
|
+
And the config file should contain the distribution id
|
152
178
|
|
153
179
|
@bucket-exists
|
154
180
|
Scenario: The user already has CloudFront configured in his configuration file
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Feature: Modify an existing CloudFront distribution
|
2
|
+
|
3
|
+
@apply-configs-on-cf-dist
|
4
|
+
Scenario: The user wants to modify an existing CloudFront distribution
|
5
|
+
When I run the configure-s3-website command with parameters
|
6
|
+
| option | value |
|
7
|
+
| --config-file | features/support/sample_config_files/apply_configs_on_cf_dist.yml |
|
8
|
+
Then the output should be
|
9
|
+
"""
|
10
|
+
Bucket website-via-cf now functions as a website
|
11
|
+
Bucket website-via-cf is now readable to the whole world
|
12
|
+
No redirects to configure for website-via-cf bucket
|
13
|
+
Detected an existing CloudFront distribution (id E13NX4HCPUP9BP) ...
|
14
|
+
Applied custom distribution settings:
|
15
|
+
default_cache_behavior:
|
16
|
+
min_TTL: 3600
|
17
|
+
default_root_object: index.json
|
18
|
+
|
19
|
+
"""
|
@@ -3,7 +3,8 @@ require 'rspec'
|
|
3
3
|
When /^I run the configure-s3-website command with parameters$/ do |table|
|
4
4
|
options, optparse = ConfigureS3Website::CLI.optparse_and_options
|
5
5
|
optparse.parse! args_array_from_cucumber_table(table)
|
6
|
-
@
|
6
|
+
@config_source = options[:config_source]
|
7
|
+
@reset = create_reset_config_file_function @config_source.description
|
7
8
|
@console_output = capture_stdout {
|
8
9
|
ConfigureS3Website::Runner.run(options, stub_stdin)
|
9
10
|
}
|
@@ -21,6 +22,13 @@ Then /^the output should include$/ do |expected_console_output|
|
|
21
22
|
@console_output.should include(expected_console_output)
|
22
23
|
end
|
23
24
|
|
25
|
+
Then /^the config file should contain the distribution id$/ do
|
26
|
+
config_file_path = @config_source.description
|
27
|
+
File.open(config_file_path, 'r').read.should include(
|
28
|
+
"cloudfront_distribution_id: #{@config_source.cloudfront_distribution_id}"
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
24
32
|
def args_array_from_cucumber_table(table)
|
25
33
|
args = []
|
26
34
|
table.hashes.map do |entry|
|
data/features/support/vcr.rb
CHANGED
@@ -3,28 +3,82 @@ require "rexml/xpath"
|
|
3
3
|
|
4
4
|
module ConfigureS3Website
|
5
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
|
+
# Get caller reference and ETag (will be required by the PUT config resource)
|
11
|
+
response = HttpHelper.call_cloudfront_api(
|
12
|
+
path = "/2012-07-01/distribution/#{config_source.cloudfront_distribution_id}/config",
|
13
|
+
method = Net::HTTP::Get,
|
14
|
+
body = '',
|
15
|
+
config_source
|
16
|
+
)
|
17
|
+
etag = response['ETag']
|
18
|
+
caller_reference = REXML::XPath.first(
|
19
|
+
REXML::Document.new(response.body),
|
20
|
+
'/DistributionConfig/CallerReference'
|
21
|
+
).get_text.to_s
|
22
|
+
|
23
|
+
# Call the PUT config resource with the caller reference and ETag
|
24
|
+
custom_distribution_config = config_source.cloudfront_distribution_config || {}
|
25
|
+
custom_distribution_config_with_caller_ref = custom_distribution_config.merge({
|
26
|
+
'caller_reference' => caller_reference,
|
27
|
+
'comment' => 'Updated by the configure-s3-website gem'
|
28
|
+
})
|
29
|
+
HttpHelper.call_cloudfront_api(
|
30
|
+
path = "/2012-07-01/distribution/#{options[:config_source].cloudfront_distribution_id}/config",
|
31
|
+
method = Net::HTTP::Put,
|
32
|
+
body = distribution_config_xml(
|
33
|
+
config_source,
|
34
|
+
custom_distribution_config_with_caller_ref
|
35
|
+
),
|
36
|
+
config_source,
|
37
|
+
headers = { 'If-Match' => etag }
|
38
|
+
)
|
39
|
+
|
40
|
+
# Report
|
41
|
+
unless custom_distribution_config.empty?
|
42
|
+
print_report_on_custom_distribution_config custom_distribution_config
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
6
46
|
def self.create_distribution_if_user_agrees(options, standard_input)
|
7
47
|
puts 'Do you want to deliver your website via CloudFront, the CDN of Amazon? [y/N]'
|
8
48
|
case standard_input.gets.chomp
|
9
|
-
when /(y|Y)/ then
|
49
|
+
when /(y|Y)/ then create_distribution options
|
10
50
|
end
|
11
51
|
end
|
12
52
|
|
13
53
|
private
|
14
54
|
|
15
|
-
def self.
|
55
|
+
def self.create_distribution(options)
|
16
56
|
config_source = options[:config_source]
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
57
|
+
custom_distribution_config = config_source.cloudfront_distribution_config || {}
|
58
|
+
response_xml = REXML::Document.new(
|
59
|
+
HttpHelper.call_cloudfront_api(
|
60
|
+
'/2012-07-01/distribution',
|
61
|
+
Net::HTTP::Post,
|
62
|
+
distribution_config_xml(config_source, custom_distribution_config),
|
63
|
+
config_source
|
64
|
+
).body
|
22
65
|
)
|
23
|
-
response_xml = REXML::Document.new(response.body)
|
24
66
|
dist_id = REXML::XPath.first(response_xml, '/Distribution/Id').get_text
|
25
67
|
print_report_on_new_dist response_xml, dist_id, options
|
26
68
|
config_source.cloudfront_distribution_id = dist_id.to_s
|
27
69
|
puts " Added setting 'cloudfront_distribution_id: #{dist_id}' into #{config_source.description}"
|
70
|
+
unless custom_distribution_config.empty?
|
71
|
+
print_report_on_custom_distribution_config custom_distribution_config
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.print_report_on_custom_distribution_config(custom_distribution_config, left_padding = 4)
|
76
|
+
puts ' Applied custom distribution settings:'
|
77
|
+
puts custom_distribution_config.
|
78
|
+
to_yaml.
|
79
|
+
to_s.
|
80
|
+
gsub("---\n", '').
|
81
|
+
gsub(/^/, padding(left_padding))
|
28
82
|
end
|
29
83
|
|
30
84
|
def self.print_report_on_new_dist(response_xml, dist_id, options)
|
@@ -35,21 +89,19 @@ module ConfigureS3Website
|
|
35
89
|
puts ' For more information on the distribution, see https://console.aws.amazon.com/cloudfront'
|
36
90
|
if options[:verbose]
|
37
91
|
puts ' Below is the response from the CloudFront API:'
|
38
|
-
|
92
|
+
print_verbose_response_from_cloudfront(response_xml)
|
39
93
|
end
|
40
94
|
end
|
41
95
|
|
42
|
-
def self.
|
96
|
+
def self.print_verbose_response_from_cloudfront(response_xml, left_padding = 4)
|
43
97
|
lines = []
|
44
98
|
response_xml.write(lines, 2)
|
45
|
-
padding = ""
|
46
|
-
left_padding.times { padding << " " }
|
47
99
|
puts lines.join().
|
48
|
-
gsub(/^/, "" + padding).
|
100
|
+
gsub(/^/, "" + padding(left_padding)).
|
49
101
|
gsub(/\s$/, "")
|
50
102
|
end
|
51
103
|
|
52
|
-
def self.distribution_config_xml(config_source, custom_cf_settings
|
104
|
+
def self.distribution_config_xml(config_source, custom_cf_settings)
|
53
105
|
%|
|
54
106
|
<DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2012-07-01/">
|
55
107
|
<Origins>
|
@@ -65,14 +117,19 @@ module ConfigureS3Website
|
|
65
117
|
</Items>
|
66
118
|
</Origins>
|
67
119
|
#{
|
68
|
-
|
69
|
-
|
70
|
-
|
120
|
+
require 'deep_merge'
|
121
|
+
settings = default_cloudfront_settings config_source
|
122
|
+
settings.deep_merge! custom_cf_settings
|
123
|
+
XmlHelper.hash_to_api_xml(settings)
|
71
124
|
}
|
72
125
|
</DistributionConfig>
|
73
126
|
|
|
74
127
|
end
|
75
128
|
|
129
|
+
# Changing these default settings probably necessitates a
|
130
|
+
# backward incompatible release.
|
131
|
+
#
|
132
|
+
# If you change these settings, remember to update also the README.md.
|
76
133
|
def self.default_cloudfront_settings(config_source)
|
77
134
|
{
|
78
135
|
'caller_reference' => 'configure-s3-website gem ' + Time.now.to_s,
|
@@ -101,7 +158,7 @@ module ConfigureS3Website
|
|
101
158
|
}
|
102
159
|
},
|
103
160
|
'viewer_protocol_policy' => 'allow-all',
|
104
|
-
'min_TTL' =>
|
161
|
+
'min_TTL' => '86400'
|
105
162
|
},
|
106
163
|
'cache_behaviors' => {
|
107
164
|
'quantity' => '0'
|
@@ -113,5 +170,11 @@ module ConfigureS3Website
|
|
113
170
|
def self.origin_id(config_source)
|
114
171
|
"#{config_source.s3_bucket_name}-S3-origin"
|
115
172
|
end
|
173
|
+
|
174
|
+
def self.padding(amount)
|
175
|
+
padding = ''
|
176
|
+
amount.times { padding << " " }
|
177
|
+
padding
|
178
|
+
end
|
116
179
|
end
|
117
180
|
end
|
@@ -5,21 +5,34 @@ module ConfigureS3Website
|
|
5
5
|
date = Time.now.utc.strftime("%a, %d %b %Y %H:%M:%S %Z")
|
6
6
|
digest = create_s3_digest(path, method, config_source, date)
|
7
7
|
self.call_api(
|
8
|
-
path,
|
8
|
+
path,
|
9
|
+
method,
|
10
|
+
body,
|
11
|
+
config_source,
|
12
|
+
endpoint.hostname,
|
13
|
+
digest,
|
14
|
+
date
|
9
15
|
)
|
10
16
|
end
|
11
17
|
|
12
|
-
def self.call_cloudfront_api(path, method, body, config_source)
|
18
|
+
def self.call_cloudfront_api(path, method, body, config_source, headers = {})
|
13
19
|
date = Time.now.utc.strftime("%a, %d %b %Y %H:%M:%S %Z")
|
14
20
|
digest = create_cloudfront_digest(config_source, date)
|
15
21
|
self.call_api(
|
16
|
-
path,
|
22
|
+
path,
|
23
|
+
method,
|
24
|
+
body,
|
25
|
+
config_source,
|
26
|
+
'cloudfront.amazonaws.com',
|
27
|
+
digest,
|
28
|
+
date,
|
29
|
+
headers
|
17
30
|
)
|
18
31
|
end
|
19
32
|
|
20
33
|
private
|
21
34
|
|
22
|
-
def self.call_api(path, method, body, config_source, hostname, digest, date)
|
35
|
+
def self.call_api(path, method, body, config_source, hostname, digest, date, additional_headers = {})
|
23
36
|
url = "https://#{hostname}#{path}"
|
24
37
|
uri = URI.parse(url)
|
25
38
|
req = method.new(uri.to_s)
|
@@ -28,9 +41,10 @@ module ConfigureS3Website
|
|
28
41
|
'Content-Type' => '',
|
29
42
|
'Content-Length' => body.length.to_s,
|
30
43
|
'Authorization' => "AWS %s:%s" % [config_source.s3_access_key_id, digest]
|
31
|
-
})
|
44
|
+
}.merge(additional_headers))
|
32
45
|
req.body = body
|
33
46
|
http = Net::HTTP.new(uri.host, uri.port)
|
47
|
+
# http.set_debug_output $stderr
|
34
48
|
http.use_ssl = true
|
35
49
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
36
50
|
res = http.request(req)
|
@@ -2,16 +2,30 @@ module ConfigureS3Website
|
|
2
2
|
class Runner
|
3
3
|
def self.run(options, standard_input = STDIN)
|
4
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)
|
5
11
|
unless user_already_has_cf_configured options
|
6
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
|
7
18
|
end
|
8
19
|
end
|
9
20
|
|
10
|
-
private
|
11
|
-
|
12
21
|
def self.user_already_has_cf_configured(options)
|
13
22
|
config_source = options[:config_source]
|
14
23
|
config_source.cloudfront_distribution_id
|
15
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
|
16
30
|
end
|
17
31
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'configure-s3-website'
|
3
|
+
require "rexml/document"
|
4
|
+
require "rexml/xpath"
|
5
|
+
|
6
|
+
describe ConfigureS3Website::CloudFrontClient do
|
7
|
+
context '#distribution_config_xml' do
|
8
|
+
describe 'letting the user to override the default values' do
|
9
|
+
let(:config_source) {
|
10
|
+
mock = double('config_source')
|
11
|
+
mock.stub(:s3_bucket_name).and_return('test-bucket')
|
12
|
+
mock.stub(:s3_endpoint).and_return(nil)
|
13
|
+
mock
|
14
|
+
}
|
15
|
+
|
16
|
+
let(:custom_settings) {
|
17
|
+
{ 'default_cache_behavior' => { 'min_TTL' => '987' } }
|
18
|
+
}
|
19
|
+
|
20
|
+
let(:distribution_config_xml) {
|
21
|
+
REXML::Document.new(
|
22
|
+
ConfigureS3Website::CloudFrontClient.send(
|
23
|
+
:distribution_config_xml,
|
24
|
+
config_source,
|
25
|
+
custom_settings
|
26
|
+
)
|
27
|
+
)
|
28
|
+
}
|
29
|
+
|
30
|
+
it 'allows the user to override default CloudFront settings' do
|
31
|
+
REXML::XPath.first(
|
32
|
+
distribution_config_xml,
|
33
|
+
'/DistributionConfig/DefaultCacheBehavior/MinTTL'
|
34
|
+
).get_text.to_s.should eq('987')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'retains the default values that are not overriden' do
|
38
|
+
REXML::XPath.first(
|
39
|
+
distribution_config_xml,
|
40
|
+
'/DistributionConfig/DefaultCacheBehavior/ViewerProtocolPolicy'
|
41
|
+
).get_text.to_s.should eq('allow-all')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'inferring //Origins/Items/Origin/DomainName' do
|
46
|
+
let(:config_source) {
|
47
|
+
mock = double('config_source')
|
48
|
+
mock.stub(:s3_bucket_name).and_return('test-bucket')
|
49
|
+
mock.stub(:s3_endpoint).and_return('us-west-1')
|
50
|
+
mock
|
51
|
+
}
|
52
|
+
|
53
|
+
let(:distribution_config_xml) {
|
54
|
+
REXML::Document.new(
|
55
|
+
ConfigureS3Website::CloudFrontClient.send(
|
56
|
+
:distribution_config_xml,
|
57
|
+
config_source,
|
58
|
+
custom_distribution_config = {}
|
59
|
+
)
|
60
|
+
)
|
61
|
+
}
|
62
|
+
|
63
|
+
it 'honors the endpoint of the S3 bucket' do
|
64
|
+
REXML::XPath.first(
|
65
|
+
distribution_config_xml,
|
66
|
+
'/DistributionConfig/Origins/Items/Origin/DomainName'
|
67
|
+
).get_text.to_s.should eq('test-bucket.s3-us-west-1.amazonaws.com')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configure-s3-website
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: deep_merge
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.0.0
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: rspec
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,6 +155,7 @@ files:
|
|
139
155
|
- bin/configure-s3-website
|
140
156
|
- changelog.md
|
141
157
|
- configure-s3-website.gemspec
|
158
|
+
- features/cassettes/cucumber_tags/apply-configs-on-cf-dist.yml
|
142
159
|
- features/cassettes/cucumber_tags/bucket-does-not-exist-in-tokyo.yml
|
143
160
|
- features/cassettes/cucumber_tags/bucket-does-not-exist.yml
|
144
161
|
- features/cassettes/cucumber_tags/bucket-exists.yml
|
@@ -147,10 +164,13 @@ files:
|
|
147
164
|
- features/config_file.feature
|
148
165
|
- features/configure_bucket.feature
|
149
166
|
- features/create_cloudfront_dist.feature
|
167
|
+
- features/modify_cloudfront_dist.feature
|
150
168
|
- features/step_definitions/steps.rb
|
151
169
|
- features/support/env.rb
|
170
|
+
- features/support/sample_config_files/apply_configs_on_cf_dist.yml
|
152
171
|
- features/support/sample_config_files/config_with_cloudfront_distribution_id.yml
|
153
172
|
- features/support/sample_config_files/create_cf_dist.yml
|
173
|
+
- features/support/sample_config_files/create_cf_dist_with_custom_configs.yml
|
154
174
|
- features/support/sample_config_files/endpoint_tokyo.yml
|
155
175
|
- features/support/sample_config_files/redirects.yml
|
156
176
|
- features/support/sample_config_files/s3_config_with_existing_bucket.yml
|
@@ -166,6 +186,7 @@ files:
|
|
166
186
|
- lib/configure-s3-website/s3_client.rb
|
167
187
|
- lib/configure-s3-website/version.rb
|
168
188
|
- lib/configure-s3-website/xml_helper.rb
|
189
|
+
- spec/cloudfront_client_spec.rb
|
169
190
|
- spec/config_source/file_config_source_spec.rb
|
170
191
|
- spec/s3_client_spec.rb
|
171
192
|
- spec/sample_files/_config_file.yml
|
@@ -186,7 +207,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
186
207
|
version: '0'
|
187
208
|
segments:
|
188
209
|
- 0
|
189
|
-
hash:
|
210
|
+
hash: 2506779264415997513
|
190
211
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
191
212
|
none: false
|
192
213
|
requirements:
|
@@ -195,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
195
216
|
version: '0'
|
196
217
|
segments:
|
197
218
|
- 0
|
198
|
-
hash:
|
219
|
+
hash: 2506779264415997513
|
199
220
|
requirements: []
|
200
221
|
rubyforge_project:
|
201
222
|
rubygems_version: 1.8.25
|
@@ -203,6 +224,7 @@ signing_key:
|
|
203
224
|
specification_version: 3
|
204
225
|
summary: Configure your AWS S3 bucket to function as a web site
|
205
226
|
test_files:
|
227
|
+
- features/cassettes/cucumber_tags/apply-configs-on-cf-dist.yml
|
206
228
|
- features/cassettes/cucumber_tags/bucket-does-not-exist-in-tokyo.yml
|
207
229
|
- features/cassettes/cucumber_tags/bucket-does-not-exist.yml
|
208
230
|
- features/cassettes/cucumber_tags/bucket-exists.yml
|
@@ -211,15 +233,19 @@ test_files:
|
|
211
233
|
- features/config_file.feature
|
212
234
|
- features/configure_bucket.feature
|
213
235
|
- features/create_cloudfront_dist.feature
|
236
|
+
- features/modify_cloudfront_dist.feature
|
214
237
|
- features/step_definitions/steps.rb
|
215
238
|
- features/support/env.rb
|
239
|
+
- features/support/sample_config_files/apply_configs_on_cf_dist.yml
|
216
240
|
- features/support/sample_config_files/config_with_cloudfront_distribution_id.yml
|
217
241
|
- features/support/sample_config_files/create_cf_dist.yml
|
242
|
+
- features/support/sample_config_files/create_cf_dist_with_custom_configs.yml
|
218
243
|
- features/support/sample_config_files/endpoint_tokyo.yml
|
219
244
|
- features/support/sample_config_files/redirects.yml
|
220
245
|
- features/support/sample_config_files/s3_config_with_existing_bucket.yml
|
221
246
|
- features/support/sample_config_files/s3_config_with_non-existing_bucket.yml
|
222
247
|
- features/support/vcr.rb
|
248
|
+
- spec/cloudfront_client_spec.rb
|
223
249
|
- spec/config_source/file_config_source_spec.rb
|
224
250
|
- spec/s3_client_spec.rb
|
225
251
|
- spec/sample_files/_config_file.yml
|