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
+ [![Build Status](https://secure.travis-ci.org/laurilehmijoki/cf-s3-invalidator.png)]
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> --bucket <S3-BUCKET-NAME> --distribution <CLOUDFRONT-DISTRIBUTION-ID>`
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
- s3_key: YOUR_AWS_S3_ACCESS_KEY_ID
22
- s3_secret: YOUR_AWS_S3_SECRET_ACCESS_KEY
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
- [![Build Status](https://secure.travis-ci.org/laurilehmijoki/cf-s3-invalidator.png)]
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/cloudfront_invalidator'
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
- :key => yml['s3_key'],
51
- :secret => yml['s3_secret'],
52
- :bucket => yml['s3_bucket'],
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
- options = UI.new.parse_or_print_help
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
- s3_object_keys = S3Loader.new(
129
- options[:key], options[:secret]).list_keys(options[:bucket])
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
- invalidator = CloudfrontInvalidator.new(
132
- options[:key], options[:secret], options[:distribution])
133
- invalidator.invalidate(s3_object_keys)
160
+ orchestrator = Orchestrator.new
161
+ orchestrator.resolve_s3_bucket_name
162
+ orchestrator.invalidate_cf_dist
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'cf-s3-invalidator'
3
- s.version = '0.3.6'
3
+ s.version = '0.3.7'
4
4
  s.license = 'MIT'
5
5
  s.summary = 'A tool for invalidating AWS S3-based Cloudfront distributions'
6
6
  s.description =
@@ -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 AWS Access Key Id you provided does not exist in our records. (AWS::S3::Errors::InvalidAccessKeyId)
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 invalid-aws-key --secret invalid-aws-secret --bucket some-bucket --distribution some-dist`
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 AWS Access Key Id you provided does not exist in our records. (AWS::S3::Errors::InvalidAccessKeyId)
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
- # Adapted from:
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
- date = Time.now.strftime("%a, %d %b %Y %H:%M:%S %Z")
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
- print_operation_result(res, items)
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 print_operation_result(http_response, items)
49
- success = http_response.code == '201'
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}".blue
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: 31
4
+ hash: 29
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 6
10
- version: 0.3.6
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-05 00:00:00 Z
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/cloudfront_invalidator.rb
117
+ - lib/cloudfront_client.rb
117
118
  - lib/s3_loader.rb
118
119
  homepage: https://github.com/laurilehmijoki/cf-s3-invalidator
119
120
  licenses: