publish2cloud 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ require 'publish2cloud/railtie.rb' if defined?(Rails) && Rails::VERSION::MAJOR == 3
@@ -0,0 +1,177 @@
1
+ require 'hmac-sha1' # on OS X: sudo gem install ruby-hmac
2
+ require 'net/https'
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'base64'
6
+ require 'right_aws'
7
+
8
+ module Publish2Cloud
9
+
10
+ class Publisher
11
+
12
+ def initialize s3_access, s3_secret, s3_bucket, cf_distribution, max_age = nil
13
+ @s3_access = s3_access
14
+ @s3_secret = s3_secret
15
+ @s3_bucket = s3_bucket
16
+ @cf_distribution = cf_distribution
17
+ @max_age = max_age
18
+ end
19
+
20
+ def run urls
21
+ ensure_s3_bucket_exist
22
+ set_root 'index.html'
23
+
24
+ urls.each {|x|
25
+ uri = URI.parse(x)
26
+ if uri.path == "" or uri.path == "/"
27
+ s3_key = "index.html"
28
+ else
29
+ s3_key = uri.path[1..-1]
30
+ end
31
+ puts "#{x} -> #{s3_key}"
32
+ fetch_and_upload_to_s3 x, s3_key
33
+ invalidate [s3_key]
34
+ }
35
+ end
36
+
37
+ #http://aws.amazon.com/cloudfront/faqs/#How_long_will_Amazon_CloudFront_keep_my_files
38
+ #headers looks like this:
39
+ #{'Cache-Control' => public, max-age=86400', 'Content-Type' => 'text/html; charset=utf-8'}
40
+ #{'Cache-Control' => 'max-age=0, private, must-revalidate', 'Content-Type' => 'text/html; charset=utf-8'}
41
+ def fetch_and_upload_to_s3 url, s3_key
42
+ res = Net::HTTP.get_response URI.parse(url)
43
+
44
+ raise res.code if res.code != '200'
45
+ #puts res.body
46
+
47
+ s3= RightAws::S3.new(@s3_access, @s3_secret, {:logger => Logger.new('log/publish2cloud.log')})
48
+ bucket = s3.bucket(@s3_bucket)
49
+ if @max_age
50
+ headers = {'Cache-Control' => "public, max-age=#{@max_age}", 'Content-Type' => 'text/html; charset=utf-8'}
51
+ else
52
+ headers = {'Content-Type' => 'text/html; charset=utf-8'}
53
+ end
54
+ bucket.put(s3_key, res.body, {}, 'public-read', headers)
55
+
56
+ puts "Uploaded #{s3_key}"
57
+ end
58
+
59
+ def invalidate paths_as_array
60
+ paths = nil
61
+
62
+ if paths_as_array.length > 0
63
+ paths = '<Path>/' + paths_as_array.join('</Path><Path>/') + '</Path>'
64
+ end
65
+
66
+ date = Time.now.utc
67
+ date = date.strftime("%a, %d %b %Y %H:%M:%S %Z")
68
+ digest = HMAC::SHA1.new(@s3_secret)
69
+ digest << date
70
+
71
+ uri = URI.parse('https://cloudfront.amazonaws.com/2010-08-01/distribution/' + @cf_distribution + '/invalidation')
72
+
73
+ if paths != nil
74
+ req = Net::HTTP::Post.new(uri.path)
75
+ else
76
+ req = Net::HTTP::Get.new(uri.path)
77
+ end
78
+
79
+ req.initialize_http_header({
80
+ 'x-amz-date' => date,
81
+ 'Content-Type' => 'text/xml',
82
+ 'Authorization' => "AWS %s:%s" % [@s3_access, Base64.encode64(digest.digest)]
83
+ })
84
+
85
+ if paths != nil
86
+ req.body = "<InvalidationBatch>" + paths + "<CallerReference>ref_#{Time.now.utc.to_i}</CallerReference></InvalidationBatch>"
87
+ end
88
+
89
+ #puts req.body
90
+
91
+ http = Net::HTTP.new(uri.host, uri.port)
92
+ http.use_ssl = true
93
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
94
+ res = http.request(req)
95
+
96
+ # TODO: Check status code and pretty print the output
97
+ # Tip: pipe the output to | xmllint -format - |less for easier reading
98
+ #puts $STDERR res.code
99
+ #puts res.body
100
+ puts "Invalidated #{paths_as_array}"
101
+ return 0
102
+ end
103
+
104
+ def set_root newobj
105
+ date = Time.now.utc
106
+ date = date.strftime("%a, %d %b %Y %H:%M:%S %Z")
107
+ digest = HMAC::SHA1.new(@s3_secret)
108
+ digest << date
109
+
110
+ uri = URI.parse('https://cloudfront.amazonaws.com/2010-08-01/distribution/' + @cf_distribution + '/config')
111
+
112
+ req = Net::HTTP::Get.new(uri.path)
113
+
114
+ req.initialize_http_header({
115
+ 'x-amz-date' => date,
116
+ 'Content-Type' => 'text/xml',
117
+ 'Authorization' => "AWS %s:%s" % [@s3_access, Base64.encode64(digest.digest)]
118
+ })
119
+
120
+ http = Net::HTTP.new(uri.host, uri.port)
121
+ http.use_ssl = true
122
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
123
+ res = http.request(req)
124
+ puts res
125
+ match = /<DefaultRootObject>(.*?)<\/DefaultRootObject>/.match(res.body)
126
+ currentobj = match ? match[1] : nil
127
+
128
+ if newobj == currentobj
129
+ puts "'#{currentobj}' is already the DefaultRootObject"
130
+ return -1
131
+ end
132
+
133
+ etag = res.header['etag']
134
+
135
+ req = Net::HTTP::Put.new(uri.path)
136
+
137
+ req.initialize_http_header({
138
+ 'x-amz-date' => date,
139
+ 'Content-Type' => 'text/xml',
140
+ 'Authorization' => "AWS %s:%s" % [@s3_access, Base64.encode64(digest.digest)],
141
+ 'If-Match' => etag
142
+ })
143
+
144
+ if currentobj == nil
145
+ regex = /<\/DistributionConfig>/
146
+ replace = "<DefaultRootObject>#{newobj}</DefaultRootObject></DistributionConfig>"
147
+ else
148
+ regex = /<DefaultRootObject>(.*?)<\/DefaultRootObject>/
149
+ replace = "<DefaultRootObject>#{newobj}</DefaultRootObject>"
150
+ end
151
+
152
+ req.body = res.body.gsub(regex, replace)
153
+
154
+ http = Net::HTTP.new(uri.host, uri.port)
155
+ http.use_ssl = true
156
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
157
+ res = http.request(req)
158
+
159
+ puts res.code
160
+ puts res.body
161
+ return 0
162
+ end
163
+
164
+ def ensure_s3_bucket_exist
165
+ s3= RightAws::S3.new(@s3_access, @s3_secret, {:logger => Logger.new('log/publish2cloud.log')})
166
+ bucket = s3.bucket(@s3_bucket)
167
+ begin
168
+ bucket.keys
169
+ puts "Bucket '#{@s3_bucket}' exists"
170
+ rescue
171
+ puts "Going to creat '#{@s3_bucket}'"
172
+ RightAws::S3::Bucket.create(s3, @s3_bucket, true, 'public-read')
173
+ end
174
+ end
175
+
176
+ end
177
+ end
@@ -0,0 +1,10 @@
1
+ require 'publish2cloud'
2
+ require 'rails'
3
+
4
+ module Publish2Cloud
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load 'publish2cloud/tasks.rb'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'publish2cloud', 'publish2cloud'))
2
+
3
+ PUBLISH2CLOUD_CONFIG_FILE = Rails.root.join('config', 'publish2cloud.rb')
4
+
5
+ namespace :p2c do
6
+ desc "Publish2Cloud"
7
+ task :push do
8
+
9
+ require PUBLISH2CLOUD_CONFIG_FILE
10
+ p2c = Publish2Cloud::Publisher.new(P2C_S3_ACCESS_KEY_ID,
11
+ P2C_S3_SECRET_ACCESS_KEY,
12
+ P2C_S3_BUCKET,
13
+ P2C_CF_DISTRIBUTION_ID,
14
+ defined?(P2C_MAX_AGE) ? P2C_MAX_AGE : nil)
15
+ p2c.run P2C_URLS
16
+ end
17
+
18
+ desc "Analyze links of a given webpage"
19
+ task :analyze do
20
+ p ARGV
21
+ end
22
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'publish2cloud', 'tasks'))
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: publish2cloud
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Xue Yong Zhi
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-25 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: ruby-hmac
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: right_aws
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: nokogiri
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ description:
64
+ email:
65
+ - yong@intridea.com
66
+ executables: []
67
+
68
+ extensions: []
69
+
70
+ extra_rdoc_files: []
71
+
72
+ files:
73
+ - lib/publish2cloud/publish2cloud.rb
74
+ - lib/publish2cloud/railtie.rb
75
+ - lib/publish2cloud/tasks.rb
76
+ - lib/publish2cloud.rb
77
+ - lib/tasks/publish2cloud.rake
78
+ has_rdoc: true
79
+ homepage:
80
+ licenses: []
81
+
82
+ post_install_message:
83
+ rdoc_options: []
84
+
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ hash: 3
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ requirements: []
106
+
107
+ rubyforge_project:
108
+ rubygems_version: 1.3.7
109
+ signing_key:
110
+ specification_version: 3
111
+ summary: publish2cloud
112
+ test_files: []
113
+