cf-s3-invalidator 0.3.6 → 0.3.7
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
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Invalidator for AWS S3-based Cloudfront distributions
|
2
2
|
|
3
|
+
[]
|
4
|
+
|
5
|
+
(http://travis-ci.org/laurilehmijoki/cf-s3-invalidator)
|
3
6
|
If your Amazon Web Services Cloudfront distribution is based on AWS S3, then
|
4
7
|
this library may be useful to you.
|
5
8
|
|
@@ -14,13 +17,12 @@ calls on them the invalidation REST API of Cloudfront.
|
|
14
17
|
|
15
18
|
You can specify the configuration as CLI parameters:
|
16
19
|
|
17
|
-
`cf-s3-inv --key <AWS-KEY> --secret <AWS-SECRET> --
|
20
|
+
`cf-s3-inv --key <AWS-KEY> --secret <AWS-SECRET> --distribution <CLOUDFRONT-DISTRIBUTION-ID>`
|
18
21
|
|
19
22
|
Or you can store them into the file *_cf_s3_invalidator.yml*:
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
s3_bucket: your.bucket.com
|
24
|
+
aws_key: YOUR_AWS_ACCESS_KEY_ID
|
25
|
+
aws_secret: YOUR_AWS_SECRET_ACCESS_KEY
|
24
26
|
cloudfront_distribution_id: YOUR_CLOUDFRONT_DISTRIBUTION_ID
|
25
27
|
|
26
28
|
Then you can just run:
|
@@ -29,9 +31,6 @@ Then you can just run:
|
|
29
31
|
|
30
32
|
## Development
|
31
33
|
|
32
|
-
[]
|
33
|
-
(http://travis-ci.org/laurilehmijoki/cf-s3-invalidator)
|
34
|
-
|
35
34
|
Run tests:
|
36
35
|
|
37
36
|
`rake test`
|
data/bin/cf-s3-inv
CHANGED
@@ -9,7 +9,7 @@ unless Kernel.respond_to?(:require_relative)
|
|
9
9
|
end
|
10
10
|
require 'optparse'
|
11
11
|
require 'yaml'
|
12
|
-
require_relative '../lib/
|
12
|
+
require_relative '../lib/cloudfront_client'
|
13
13
|
require_relative '../lib/s3_loader'
|
14
14
|
|
15
15
|
class UI
|
@@ -46,14 +46,28 @@ class UI
|
|
46
46
|
class FileOptionParser
|
47
47
|
def parse
|
48
48
|
yml = YAML.load_file(get_conf_file_path)
|
49
|
+
validate_keys(yml)
|
49
50
|
{
|
50
|
-
|
51
|
-
:
|
52
|
-
:
|
51
|
+
# For backward compatibility, support s3_key and s3_secret
|
52
|
+
:key => yml['s3_key'] ? yml['s3_key'] : yml['aws_key'],
|
53
|
+
:secret => yml['s3_secret'] ? yml['s3_secret'] : yml['aws_secret'],
|
53
54
|
:distribution => yml['cloudfront_distribution_id']
|
54
55
|
}
|
55
56
|
end
|
56
57
|
|
58
|
+
def validate_keys(config)
|
59
|
+
def test_keys(alternative_config_keys, error_message, config)
|
60
|
+
valid = config.keys.any? { |key| alternative_config_keys.include? key }
|
61
|
+
raise error_message.red unless valid
|
62
|
+
end
|
63
|
+
test_keys(["s3_key", "aws_key"],
|
64
|
+
"AWS key missing in the configuration file", config)
|
65
|
+
test_keys(["s3_secret", "aws_secret"],
|
66
|
+
"AWS secret missing in the configuration file", config)
|
67
|
+
test_keys(["cloudfront_distribution_id"],
|
68
|
+
"Cloudfront distribution id missing in the configuration file", config)
|
69
|
+
end
|
70
|
+
|
57
71
|
def print_help
|
58
72
|
puts "Add the rows below into file '#{get_conf_file_name}' and then run the program without arguments"
|
59
73
|
puts ""
|
@@ -77,7 +91,6 @@ class UI
|
|
77
91
|
sample = <<-EOF
|
78
92
|
s3_key: YOUR_AWS_S3_ACCESS_KEY_ID
|
79
93
|
s3_secret: YOUR_AWS_S3_SECRET_ACCESS_KEY
|
80
|
-
s3_bucket: your.bucket.com
|
81
94
|
cloudfront_distribution_id: YOUR_CLOUDFRONT_DISTRIBUTION_ID
|
82
95
|
EOF
|
83
96
|
end
|
@@ -100,10 +113,6 @@ class UI
|
|
100
113
|
"Amazon Web Services API secret key") do |val|
|
101
114
|
options[:secret] = val
|
102
115
|
end
|
103
|
-
opts.on("-b", "--bucket BUCKET NAME",
|
104
|
-
"S3 bucket name") do |val|
|
105
|
-
options[:bucket] = val
|
106
|
-
end
|
107
116
|
opts.on("-d", "--distribution CLOUDFRONT ID",
|
108
117
|
"Cloudfront distribution id") do |val|
|
109
118
|
options[:distribution] = val
|
@@ -123,11 +132,31 @@ class UI
|
|
123
132
|
end
|
124
133
|
end
|
125
134
|
|
126
|
-
|
135
|
+
class Orchestrator
|
136
|
+
def initialize
|
137
|
+
@options = UI.new.parse_or_print_help
|
138
|
+
@cf = CloudfrontClient.new(
|
139
|
+
@options[:key], @options[:secret], @options[:distribution])
|
140
|
+
end
|
141
|
+
|
142
|
+
def resolve_s3_bucket_name
|
143
|
+
@s3_bucket_name = @cf.get_s3_bucket_name
|
144
|
+
if @s3_bucket_name
|
145
|
+
puts "Resolving S3 bucket name... Got #{@s3_bucket_name.yellow}"
|
146
|
+
else
|
147
|
+
puts
|
148
|
+
"The Cloudfront distribution is not based on an S3 bucket".red
|
149
|
+
exit
|
150
|
+
end
|
151
|
+
end
|
127
152
|
|
128
|
-
|
129
|
-
|
153
|
+
def invalidate_cf_dist
|
154
|
+
s3_object_keys = S3Loader.new(
|
155
|
+
@options[:key], @options[:secret]).list_keys(@s3_bucket_name)
|
156
|
+
@cf.invalidate(s3_object_keys)
|
157
|
+
end
|
158
|
+
end
|
130
159
|
|
131
|
-
|
132
|
-
|
133
|
-
|
160
|
+
orchestrator = Orchestrator.new
|
161
|
+
orchestrator.resolve_s3_bucket_name
|
162
|
+
orchestrator.invalidate_cf_dist
|
data/cf-s3-invalidator.gemspec
CHANGED
@@ -5,22 +5,34 @@ Feature: cloudfront-s3-invalidator without AWS credentials
|
|
5
5
|
I want to run cf-s3-inv and see that it tells me I have no valid credentials
|
6
6
|
|
7
7
|
Scenario: Run cf-s3-inv with the configuration file that has invalid AWS access key
|
8
|
+
Given a file named "_cf_s3_invalidator.yml" with:
|
9
|
+
"""
|
10
|
+
aws_key: YOUR_AWS_ACCESS_KEY_ID
|
11
|
+
aws_secret: YOUR_AWS_SECRET_ACCESS_KEY
|
12
|
+
cloudfront_distribution_id: CF_ID
|
13
|
+
"""
|
14
|
+
When I run `cf-s3-inv`
|
15
|
+
Then the output should contain:
|
16
|
+
"""
|
17
|
+
The security token included in the request is invalid
|
18
|
+
"""
|
19
|
+
|
20
|
+
Scenario: Run cf-s3-inv with the configuration file that has invalid S3 access key
|
8
21
|
Given a file named "_cf_s3_invalidator.yml" with:
|
9
22
|
"""
|
10
23
|
s3_key: YOUR_AWS_S3_ACCESS_KEY_ID
|
11
24
|
s3_secret: YOUR_AWS_S3_SECRET_ACCESS_KEY
|
12
|
-
s3_bucket: your.bucket.com
|
13
25
|
cloudfront_distribution_id: CF_ID
|
14
26
|
"""
|
15
27
|
When I run `cf-s3-inv`
|
16
28
|
Then the output should contain:
|
17
29
|
"""
|
18
|
-
The
|
30
|
+
The security token included in the request is invalid
|
19
31
|
"""
|
20
32
|
|
21
33
|
Scenario: Run cf-s3-inv with CLI arguments containing invalid AWS access key
|
22
|
-
When I run `cf-s3-inv --key
|
34
|
+
When I run `cf-s3-inv --key invalidawskey --secret invalidawssecret --distribution some-dist`
|
23
35
|
Then the output should contain:
|
24
36
|
"""
|
25
|
-
The
|
37
|
+
The security token included in the request is invalid
|
26
38
|
"""
|
@@ -0,0 +1,41 @@
|
|
1
|
+
Feature: configuration file
|
2
|
+
In order to easily specify AWS credentials and Cloudfront distribution name
|
3
|
+
As a geek
|
4
|
+
I want to use a configuration file
|
5
|
+
|
6
|
+
Scenario: Missing key
|
7
|
+
Given a file named "_cf_s3_invalidator.yml" with:
|
8
|
+
"""
|
9
|
+
s3_secret: YOUR_AWS_S3_SECRET_ACCESS_KEY
|
10
|
+
cloudfront_distribution_id: CF_ID
|
11
|
+
"""
|
12
|
+
When I run `cf-s3-inv`
|
13
|
+
Then the output should contain:
|
14
|
+
"""
|
15
|
+
AWS key missing in the configuration file
|
16
|
+
"""
|
17
|
+
|
18
|
+
Scenario: Missing secret
|
19
|
+
Given a file named "_cf_s3_invalidator.yml" with:
|
20
|
+
"""
|
21
|
+
aws_key: AWS_KEY
|
22
|
+
cloudfront_distribution_id: CF_ID
|
23
|
+
"""
|
24
|
+
When I run `cf-s3-inv`
|
25
|
+
Then the output should contain:
|
26
|
+
"""
|
27
|
+
AWS secret missing in the configuration file
|
28
|
+
"""
|
29
|
+
|
30
|
+
Scenario: Missing Cloudfront distribution id
|
31
|
+
Given a file named "_cf_s3_invalidator.yml" with:
|
32
|
+
"""
|
33
|
+
aws_key: AWS_KEY
|
34
|
+
aws_secret: AWS_SECRET
|
35
|
+
"""
|
36
|
+
When I run `cf-s3-inv`
|
37
|
+
Then the output should contain:
|
38
|
+
"""
|
39
|
+
Cloudfront distribution id missing in the configuration file
|
40
|
+
"""
|
41
|
+
|
@@ -5,9 +5,7 @@ require 'net/https'
|
|
5
5
|
require 'base64'
|
6
6
|
require 'colored'
|
7
7
|
|
8
|
-
|
9
|
-
# Confabulus @ http://blog.confabulus.com/2011/05/13/cloudfront-invalidation-from-ruby
|
10
|
-
class CloudfrontInvalidator
|
8
|
+
class CloudfrontClient
|
11
9
|
def initialize(aws_account, aws_secret, distribution)
|
12
10
|
@aws_account = aws_account
|
13
11
|
@aws_secret = aws_secret
|
@@ -16,18 +14,7 @@ class CloudfrontInvalidator
|
|
16
14
|
|
17
15
|
def invalidate(items)
|
18
16
|
items = to_cf_keys(items)
|
19
|
-
|
20
|
-
digest = Base64.encode64(
|
21
|
-
OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), @aws_secret, date)).strip
|
22
|
-
uri = URI.parse(
|
23
|
-
"https://cloudfront.amazonaws.com/2012-05-05/distribution/#{@distribution}/invalidation")
|
24
|
-
req = Net::HTTP::Post.new(uri.path)
|
25
|
-
req.initialize_http_header({
|
26
|
-
'x-amz-date' => date,
|
27
|
-
'Content-Type' => 'text/xml',
|
28
|
-
'Authorization' => "AWS %s:%s" % [@aws_account, digest]
|
29
|
-
})
|
30
|
-
req.body = %|
|
17
|
+
body = %|
|
31
18
|
<InvalidationBatch>
|
32
19
|
<Paths>
|
33
20
|
<Quantity>#{items.length}</Quantity>
|
@@ -38,25 +25,58 @@ class CloudfrontInvalidator
|
|
38
25
|
<CallerReference>#{Time.now.utc.to_i}</CallerReference>
|
39
26
|
</InvalidationBatch>
|
40
27
|
|
|
28
|
+
res = sign_and_call(
|
29
|
+
"https://cloudfront.amazonaws.com/2012-05-05/distribution/#{@distribution}/invalidation",
|
30
|
+
Net::HTTP::Post,
|
31
|
+
body)
|
32
|
+
print_invalidation_result(res, items)
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_s3_bucket_name
|
36
|
+
res = sign_and_call(
|
37
|
+
"https://cloudfront.amazonaws.com/2012-05-05/distribution/#{@distribution}",
|
38
|
+
Net::HTTP::Get)
|
39
|
+
matches =
|
40
|
+
res.body.scan(/<DomainName>([\w|\.]+)\.s3\.amazonaws\.com<\/DomainName>/)
|
41
|
+
if matches.empty?
|
42
|
+
nil
|
43
|
+
else
|
44
|
+
s3_bucket_name = matches.first.first
|
45
|
+
s3_bucket_name
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def sign_and_call(url, method, body = nil)
|
52
|
+
date = Time.now.strftime("%a, %d %b %Y %H:%M:%S %Z")
|
53
|
+
digest = Base64.encode64(
|
54
|
+
OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), @aws_secret, date)).strip
|
55
|
+
uri = URI.parse(url)
|
56
|
+
req = method.new(uri.path)
|
57
|
+
req.initialize_http_header({
|
58
|
+
'x-amz-date' => date,
|
59
|
+
'Content-Type' => 'text/xml',
|
60
|
+
'Authorization' => "AWS %s:%s" % [@aws_account, digest]
|
61
|
+
})
|
62
|
+
req.body = body unless body == nil
|
41
63
|
http = Net::HTTP.new(uri.host, uri.port)
|
42
64
|
http.use_ssl = true
|
43
65
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
44
66
|
res = http.request(req)
|
45
|
-
|
67
|
+
if res.code.to_i.between? 200, 299
|
68
|
+
res
|
69
|
+
else
|
70
|
+
raise "AWS API call failed. Reason:".red + "\n" + res.body
|
71
|
+
end
|
46
72
|
end
|
47
73
|
|
48
|
-
def
|
49
|
-
|
50
|
-
puts "Invalidating Cloudfront items".cyan
|
74
|
+
def print_invalidation_result(http_response, items)
|
75
|
+
puts "Invalidating Cloudfront items..."
|
51
76
|
items.each do |item|
|
52
|
-
puts " #{item}".
|
53
|
-
end
|
54
|
-
if success
|
55
|
-
puts "succeeded".green
|
56
|
-
else
|
57
|
-
puts "FAILED, reason:".red
|
58
|
-
puts http_response.body
|
77
|
+
puts " #{item}".yellow
|
59
78
|
end
|
79
|
+
puts "succeeded".green
|
60
80
|
end
|
61
81
|
|
62
82
|
def to_cf_keys(s3_keys)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cf-s3-invalidator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 7
|
10
|
+
version: 0.3.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Lauri Lehmijoki
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-07-
|
18
|
+
date: 2012-07-06 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: aws-sdk
|
@@ -112,8 +112,9 @@ files:
|
|
112
112
|
- cf-s3-invalidator.gemspec
|
113
113
|
- features/cloudfront-s3-invalidator-help.feature
|
114
114
|
- features/cloudfront-s3-invalidator-no-credentials.feature
|
115
|
+
- features/configuration-file.feature
|
115
116
|
- features/support/env.rb
|
116
|
-
- lib/
|
117
|
+
- lib/cloudfront_client.rb
|
117
118
|
- lib/s3_loader.rb
|
118
119
|
homepage: https://github.com/laurilehmijoki/cf-s3-invalidator
|
119
120
|
licenses:
|