cf-s3-invalidator 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
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: