cloudify 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE.txt +20 -0
- data/README.md +48 -0
- data/Rakefile +6 -0
- data/cloudify.gemspec +27 -0
- data/lib/cloudify.rb +11 -0
- data/lib/cloudify/cloudify.rb +26 -0
- data/lib/cloudify/config.rb +63 -0
- data/lib/cloudify/railtie.rb +9 -0
- data/lib/cloudify/storage.rb +72 -0
- data/lib/cloudify/version.rb +3 -0
- data/lib/generators/cloudify/install/install_generator.rb +20 -0
- data/lib/generators/cloudify/install_generator.rb +23 -0
- data/lib/generators/cloudify/templates/cloudify.rake +3 -0
- data/lib/generators/cloudify/templates/cloudify.rb +31 -0
- data/lib/tasks/deploy.rake +8 -0
- data/spec/cloudify_spec.rb +194 -0
- data/spec/fixtures/cloudify.yml +23 -0
- data/spec/spec_helper.rb +12 -0
- data/test/install_generator_test.rb +13 -0
- data/test/test_helper.rb +5 -0
- metadata +127 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm ruby-1.9.2@global
|
data/Gemfile
ADDED
data/MIT-LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Tractical, http://tractical.com/
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Cloudify
|
2
|
+
|
3
|
+
Synchronises files between your Rails application and your favorite CDN provider.
|
4
|
+
|
5
|
+
Currently supported providers:
|
6
|
+
|
7
|
+
* Amazon s3
|
8
|
+
* Rackspace Cloud Files
|
9
|
+
* Google Storage
|
10
|
+
|
11
|
+
## Installation instructions
|
12
|
+
The first thing you should do is install the gem.
|
13
|
+
|
14
|
+
gem install cloudify
|
15
|
+
|
16
|
+
Now, to tell the gem your configuration options you need to do it through the initializer. The gem offers a rails generator to create this initializer which includes documentation on how to use it and what parameters are needed for each of the services currently supported.
|
17
|
+
|
18
|
+
The generator creates the file [https://github.com/tractical/cloudify/blob/master/lib/generators/cloudify/templates/cloudify.rb](example) and you run it like this:
|
19
|
+
|
20
|
+
rails generate cloudify:install
|
21
|
+
|
22
|
+
### Sync assets
|
23
|
+
|
24
|
+
When you're ready to send your files to the cloud all you have to do is to run the following rake task:
|
25
|
+
|
26
|
+
rake cloudify:sync
|
27
|
+
|
28
|
+
If everything goes well you will see an output similar to this:
|
29
|
+
|
30
|
+
*** Syncing with aws ***
|
31
|
+
Uploading new and changed files
|
32
|
+
U public/hello.png (b55b17cc47783139c3f5dee0f3a90ce7)
|
33
|
+
Done
|
34
|
+
|
35
|
+
If you have config.force_deletion_sync set to true, you would get an output like this:
|
36
|
+
|
37
|
+
*** Syncing with aws ***
|
38
|
+
Deleting remote files that no longer exist locally
|
39
|
+
D Screen shot 2011-11-03 at 12.47.03 PM.png
|
40
|
+
D delete_me.png
|
41
|
+
...
|
42
|
+
Done
|
43
|
+
|
44
|
+
And that's it.
|
45
|
+
|
46
|
+
## Questions?
|
47
|
+
|
48
|
+
If you have any questions, please feel free to contact us on Twitter: [Tractical](http://twitter.com/tractical), [Amed Rodriguez](http://twitter.com/amedse), [Javier Saldaña](http://twitter.com/javiersaldana), [Daniel Roux](http://twitter.com/danroux).
|
data/Rakefile
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
# Use Rakefile for tasks that operate on the plugin’s source files, such as special testing or documentation.
|
2
|
+
# These must be run from the plugin’s directory.
|
3
|
+
|
4
|
+
# rakes = Dir["#{File.dirname(__FILE__)}/lib/tasks/*.rake"]
|
5
|
+
# rakes.sort.each { |ext| load ext; puts ext }
|
6
|
+
Bundler::GemHelper.install_tasks
|
data/cloudify.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cloudify/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "cloudify"
|
7
|
+
s.version = Cloudify::VERSION
|
8
|
+
s.authors = ["Amed Rodriguez", "Javier Saldana", "Daniel Roux"]
|
9
|
+
s.email = ["amed@tractical.com", "javier@tractical.com", "daniel@tractical.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Sync assets hosts}
|
12
|
+
s.description = %q{Sync your assets hosts to Amazon, Google & Rackspace services}
|
13
|
+
|
14
|
+
s.rubyforge_project = "cloudify"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "rspec-rails", "2.7.0"
|
22
|
+
s.add_development_dependency "mocha", "0.10.0"
|
23
|
+
s.add_development_dependency "ruby-debug19"
|
24
|
+
|
25
|
+
s.add_dependency "fog", "1.0.0"
|
26
|
+
|
27
|
+
end
|
data/lib/cloudify.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'fog'
|
2
|
+
require 'active_model'
|
3
|
+
require 'erb'
|
4
|
+
require "cloudify/cloudify"
|
5
|
+
require 'cloudify/config'
|
6
|
+
require 'cloudify/storage'
|
7
|
+
|
8
|
+
module Cloudify
|
9
|
+
require 'cloudify/railtie' if defined?(Rails)
|
10
|
+
end
|
11
|
+
# require 'cloudify/engine' if defined?(Rails)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Cloudify
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def config
|
6
|
+
@config ||= Config.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def configure(&proc)
|
10
|
+
yield @config ||= Config.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def storage
|
14
|
+
@storage ||= Storage.new(config.credentials, config.options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def sync
|
18
|
+
config.validate
|
19
|
+
if config && config.valid?
|
20
|
+
storage.sync
|
21
|
+
else
|
22
|
+
"Cloudify: Something went wrong"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Cloudify
|
2
|
+
class Config
|
3
|
+
include ActiveModel::Validations
|
4
|
+
DYNAMIC_SERVICES = [:provider,
|
5
|
+
:google_storage_secret_access_key, :google_storage_access_key_id,
|
6
|
+
:aws_secret_access_key, :aws_access_key_id,
|
7
|
+
:rackspace_username, :rackspace_api_key, :rackspace_european_cloud,
|
8
|
+
:rackspace_auth_url, :rackspace_servicenet, :rackspace_cdn_ssl,
|
9
|
+
:ninefold_storage_token,:ninefold_storage_secret,
|
10
|
+
:endpoint, :region, :host, :path, :port, :scheme, :persistent]
|
11
|
+
|
12
|
+
class Invalid < StandardError; end
|
13
|
+
|
14
|
+
attr_accessor :provider, :force_deletion_sync, :credentials, :assets_directory, :config_path
|
15
|
+
|
16
|
+
validates_presence_of :assets_directory
|
17
|
+
validates_presence_of :google_storage_access_key_id, :google_storage_secret_access_key, :if => Proc.new { |con| con.provider == "google" }
|
18
|
+
validates_presence_of :aws_access_key_id, :aws_secret_access_key, :if => Proc.new { |con| con.provider == "aws" }
|
19
|
+
validates_presence_of :rackspace_api_key, :rackspace_username, :if => Proc.new { |con| con.provider == "rackspace" }
|
20
|
+
validates_presence_of :ninefold_storage_token, :ninefold_storage_secret, :if => Proc.new { |con| con.provider == "ninefold" }
|
21
|
+
validates_inclusion_of :force_deletion_sync, :in => [true, false]
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
self.force_deletion_sync = false
|
25
|
+
self.credentials = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def force_deletion_sync?
|
29
|
+
self.force_deletion_sync == true
|
30
|
+
end
|
31
|
+
|
32
|
+
def initializer_exists?
|
33
|
+
path = File.join(config_path, "initializers", "cloud_storage_sync.rb")
|
34
|
+
File.exists? path
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate
|
38
|
+
unless ["aws", "google", "rackspace", "ninefold"].include?(provider)
|
39
|
+
raise ArgumentError.new("#{provider} is not a recognized storage provider")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def requires(*attrs)
|
44
|
+
attrs.each do |key|
|
45
|
+
raise ArgumentError.new("#{provider.capitalize} requires #{attrs.join(', ')} in configuration files") if self.send(key).nil?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def options
|
50
|
+
{ :assets_directory => assets_directory, :force_deletion_sync => force_deletion_sync }
|
51
|
+
end
|
52
|
+
|
53
|
+
DYNAMIC_SERVICES.each do |key|
|
54
|
+
variable = :"@#{key}"
|
55
|
+
define_method :"#{key}=" do |value|
|
56
|
+
self.credentials.merge!(key => value)
|
57
|
+
instance_variable_set variable, value
|
58
|
+
end
|
59
|
+
|
60
|
+
class_eval "def #{key}; @#{key}; end\n"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Cloudify
|
2
|
+
class Storage
|
3
|
+
|
4
|
+
class BucketNotFound < StandardError; end
|
5
|
+
|
6
|
+
attr_accessor :credentials, :options
|
7
|
+
|
8
|
+
def initialize(credentials, options)
|
9
|
+
self.credentials = credentials
|
10
|
+
self.options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def connection
|
14
|
+
@connection ||= Fog::Storage.new(credentials)
|
15
|
+
end
|
16
|
+
|
17
|
+
def bucket
|
18
|
+
@bucket ||= connection.directories.get(options[:assets_directory])
|
19
|
+
raise BucketNotFound.new("Directory '#{options[:assets_directory]}' not found") unless @bucket
|
20
|
+
@bucket
|
21
|
+
end
|
22
|
+
|
23
|
+
def force_deletion_sync?
|
24
|
+
options[:force_deletion_sync] == true
|
25
|
+
end
|
26
|
+
|
27
|
+
def local_files
|
28
|
+
@local_files ||= Dir.glob("#{Rails.root.to_s}/public/**/*").map{ |f| Digest::MD5.hexdigest(File.read(f)) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def remote_files
|
32
|
+
@remote_files ||= bucket.files.map{ |f| f.etag }
|
33
|
+
end
|
34
|
+
|
35
|
+
def upload_new_and_changed_files
|
36
|
+
STDERR.puts "Uploading new and changed files"
|
37
|
+
Dir.glob("public/**/*").each do |file|
|
38
|
+
if File.file?(file)
|
39
|
+
remote_file = file.gsub("public/", "")
|
40
|
+
begin
|
41
|
+
obj = bucket.files.get(remote_file)
|
42
|
+
rescue
|
43
|
+
obj = nil
|
44
|
+
end
|
45
|
+
if !obj || (obj.etag != Digest::MD5.hexdigest(File.read(file)))
|
46
|
+
STDERR.print "U " + file
|
47
|
+
f = bucket.files.create(:key => remote_file, :body => File.open(file), :public => true)
|
48
|
+
STDERR.puts " (" + f.etag + ")"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete_unsynced_remote_files
|
55
|
+
STDERR.puts "Deleting remote files that no longer exist locally"
|
56
|
+
files_to_delete = (local_files | remote_files) - (local_files & remote_files)
|
57
|
+
bucket.files.each do |f|
|
58
|
+
if files_to_delete.include?(f.etag)
|
59
|
+
STDERR.puts "D #{f.key}"
|
60
|
+
f.destroy
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def sync
|
66
|
+
upload_new_and_changed_files
|
67
|
+
delete_unsynced_remote_files if options[:force_deletion_sync] == true
|
68
|
+
STDERR.puts "Done"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rails'
|
2
|
+
if ::Rails.version >= "3.1"
|
3
|
+
module Cloudify
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
5
|
+
desc "This generator installs the files needed for Cloudify configuration"
|
6
|
+
class_option :use_yml, :type => :boolean, :default => false, :desc => "Use YML file instead of Rails Initializer"
|
7
|
+
source_root File.expand_path(File.join(File.dirname(__FILE__), '../templates'))
|
8
|
+
|
9
|
+
def app_name
|
10
|
+
@app_name ||= Rails.application.is_a?(Rails::Application) && Rails.application.class.name.sub(/::Application$/, "").downcase
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate_initializer
|
14
|
+
unless options[:use_yml]
|
15
|
+
template "cloudify.rb", "config/initializers/cloudify.rb"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
module Cloudify
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
desc "Install a config/cloudify.yml and the rake task enhancer"
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
8
|
+
end
|
9
|
+
|
10
|
+
def app_name
|
11
|
+
@app_name ||= Rails.application.is_a?(Rails::Application) &&
|
12
|
+
Rails.application.class.name.sub(/::Application$/, "").downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate_config
|
16
|
+
template "cloudify.yml", "config/cloudify.yml"
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_rake_task
|
20
|
+
template "cloudify.rake", "lib/tasks/cloudify.rake"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Cloudify.configure do |config|
|
2
|
+
## Cloudify supports the following providers: aws, google, ninefold and rackspace
|
3
|
+
## For more information on which parameters are required for each provider, visit http://fog.io/1.0.0/storage/
|
4
|
+
## Provider examples:
|
5
|
+
|
6
|
+
# config.provider = aws
|
7
|
+
# config.aws_access_key_id = AWS_SECRET_ACCESS_KEY
|
8
|
+
# config.aws_secret_access_key = AWS_ACCESS_KEY_ID
|
9
|
+
# all other configuration attributes are: endpoint, region, host, path, port, scheme, persistent
|
10
|
+
|
11
|
+
# config.provider = rackspace
|
12
|
+
# config.rackspace_username = RACKSPACE_USERNAME
|
13
|
+
# config.rackspace_api_key = RACKSPACE_API_KEY
|
14
|
+
## If you work with the European cloud from Rackspace uncomment the following
|
15
|
+
# config.rackspace_european_cloud = true
|
16
|
+
# all other configuration attributes are: rackspace_auth_url, rackspace_servicenet, rackspace_cdn_ssl, persistent
|
17
|
+
|
18
|
+
# config.provider = google
|
19
|
+
# config.google_storage_access_key_id = GOOGLE_STORAGE_ACCESS_KEY_ID
|
20
|
+
# config.google_storage_secret_access_key = GOOGLE_STORAGE_SECRET_ACCESS_KEY
|
21
|
+
# all other configuration attributes are: host, port, scheme, persistent
|
22
|
+
|
23
|
+
config.aws_access_key_id = 'AWS_SECRET_ACCESS_KEY'
|
24
|
+
config.aws_secret_access_key = 'AWS_ACCESS_KEY_ID'
|
25
|
+
|
26
|
+
# 'assets_directory' aka bucket in aws, container in rackspace, etc.
|
27
|
+
config.assets_directory = 'ASSETS_DIRECTORY'
|
28
|
+
|
29
|
+
# Change this to true if you want to delete files that don't exist locally anymore.
|
30
|
+
config.force_deletion_sync = false
|
31
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Cloudify::Config do
|
4
|
+
it "should have each DYNAMIC_SERVICES accessor for configuration" do
|
5
|
+
Cloudify::Config::DYNAMIC_SERVICES.each do |service_config|
|
6
|
+
should respond_to(service_config)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Cloudify do
|
12
|
+
before(:each) do
|
13
|
+
@config = Cloudify.config
|
14
|
+
end
|
15
|
+
|
16
|
+
context "invalid configuration" do
|
17
|
+
context "missing required files" do
|
18
|
+
it "should not be valid when google" do
|
19
|
+
@config.provider = "google"
|
20
|
+
@config.should_not be_valid
|
21
|
+
@config.errors[:google_storage_access_key_id].should_not be_empty
|
22
|
+
@config.errors[:google_storage_secret_access_key].should_not be_empty
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should not be valid when aws" do
|
26
|
+
@config.provider = "aws"
|
27
|
+
@config.should_not be_valid
|
28
|
+
@config.errors[:aws_secret_access_key].should_not be_empty
|
29
|
+
@config.errors[:aws_access_key_id].should_not be_empty
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not be valid when rackspace" do
|
33
|
+
@config.provider = "rackspace"
|
34
|
+
@config.should_not be_valid
|
35
|
+
@config.errors[:rackspace_username].should_not be_empty
|
36
|
+
@config.errors[:rackspace_api_key].should_not be_empty
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not be valid when ninefold" do
|
40
|
+
@config.provider = "ninefold"
|
41
|
+
@config.should_not be_valid
|
42
|
+
@config.errors[:ninefold_storage_token].should_not be_empty
|
43
|
+
@config.errors[:ninefold_storage_secret].should_not be_empty
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe Cloudify, 'with #configure(initializer)' do
|
50
|
+
before(:all) do
|
51
|
+
Cloudify.configure do |config|
|
52
|
+
config.provider = "aws"
|
53
|
+
config.aws_secret_access_key = "111222333444"
|
54
|
+
config.aws_access_key_id = "qwerty1234567890"
|
55
|
+
config.assets_directory = "app_test"
|
56
|
+
end
|
57
|
+
|
58
|
+
@config = Cloudify.config
|
59
|
+
|
60
|
+
Fog.mock!
|
61
|
+
# create a connection
|
62
|
+
connection = Fog::Storage.new(@config.credentials)
|
63
|
+
# First, a place to contain the glorious details
|
64
|
+
connection.directories.create(
|
65
|
+
:key => @config.options[:assets_directory],
|
66
|
+
:public => true
|
67
|
+
)
|
68
|
+
|
69
|
+
@storage = Cloudify.storage
|
70
|
+
end
|
71
|
+
|
72
|
+
it "loads aws configuration" do
|
73
|
+
@storage.credentials.should eq(@config.credentials)
|
74
|
+
@storage.credentials[:provider].should == "aws"
|
75
|
+
@storage.credentials[:aws_secret_access_key].should == "111222333444"
|
76
|
+
@storage.credentials[:aws_access_key_id].should == "qwerty1234567890"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "loads buckets" do
|
80
|
+
@storage.bucket.should_not be_nil
|
81
|
+
end
|
82
|
+
|
83
|
+
it "syncs to aws" do
|
84
|
+
expect{ Cloudify.sync }.should_not raise_error
|
85
|
+
end
|
86
|
+
|
87
|
+
context "Connect to each service supported" do
|
88
|
+
before(:each) do
|
89
|
+
@config.credentials.clear
|
90
|
+
end
|
91
|
+
|
92
|
+
it "syncs to google" do
|
93
|
+
Cloudify.configure do |config|
|
94
|
+
config.provider = "google"
|
95
|
+
config.google_storage_access_key_id = "somegooglekey"
|
96
|
+
config.google_storage_secret_access_key = "secret_access_key"
|
97
|
+
config.persistent = true
|
98
|
+
end
|
99
|
+
|
100
|
+
expect{ @connection = create_connection }.not_to raise_error
|
101
|
+
@connection.should be_a_kind_of Fog::Storage::Google::Mock
|
102
|
+
end
|
103
|
+
|
104
|
+
it "syncs to aws" do
|
105
|
+
Cloudify.configure do |config|
|
106
|
+
config.provider = "aws"
|
107
|
+
config.aws_access_key_id = "api_key"
|
108
|
+
config.aws_secret_access_key = "username"
|
109
|
+
end
|
110
|
+
|
111
|
+
expect{ @connection = create_connection }.not_to raise_error
|
112
|
+
@connection.should be_a_kind_of Fog::Storage::AWS::Mock
|
113
|
+
end
|
114
|
+
|
115
|
+
it "syncs to rackspace" do
|
116
|
+
Cloudify.configure do |config|
|
117
|
+
config.provider = "rackspace"
|
118
|
+
config.rackspace_username = "username"
|
119
|
+
config.rackspace_api_key = "api_key"
|
120
|
+
end
|
121
|
+
|
122
|
+
expect{ @connection = create_connection }.to raise_error(Fog::Errors::MockNotImplemented, "Contributions welcome!")
|
123
|
+
end
|
124
|
+
|
125
|
+
it "syncs to ninefold" do
|
126
|
+
Cloudify.configure do |config|
|
127
|
+
config.provider = "ninefold"
|
128
|
+
config.ninefold_storage_token = "token_key"
|
129
|
+
config.ninefold_storage_secret = "secret"
|
130
|
+
end
|
131
|
+
|
132
|
+
expect{ @connection = create_connection }.to raise_error(Fog::Errors::MockNotImplemented, "Contributions welcome!")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe Cloudify::Storage do
|
138
|
+
YML_FILE_PATH = File.join(File.dirname(__FILE__), 'fixtures', "cloudify.yml")
|
139
|
+
YML_FILE = File.read(YML_FILE_PATH)
|
140
|
+
YML_DIGEST = Digest::MD5.hexdigest(YML_FILE)
|
141
|
+
|
142
|
+
before do
|
143
|
+
config = mock(Cloudify::Config)
|
144
|
+
config.stub(:credentials).and_return(:provider =>"aws",
|
145
|
+
:aws_secret_access_key =>"111222333444",
|
146
|
+
:aws_access_key_id =>"qwerty1234567890")
|
147
|
+
|
148
|
+
config.stub(:options).and_return(:assets_directory => "app_test",
|
149
|
+
:force_deletion_sync => false)
|
150
|
+
|
151
|
+
Cloudify.stub(:config).and_return(config)
|
152
|
+
@config = Cloudify.config
|
153
|
+
|
154
|
+
Fog.mock!
|
155
|
+
# create a connection
|
156
|
+
connection = Fog::Storage.new(@config.credentials)
|
157
|
+
# First, a place to contain the glorious details
|
158
|
+
connection.directories.create(
|
159
|
+
:key => @config.options[:assets_directory],
|
160
|
+
:public => true
|
161
|
+
)
|
162
|
+
|
163
|
+
@storage = Cloudify::Storage.new(@config.credentials, @config.options)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "Uploads a new file and then deletes it" do
|
167
|
+
@storage.stub(:local_files).and_return([YML_DIGEST])
|
168
|
+
Dir.stub(:glob).and_return([YML_FILE_PATH])
|
169
|
+
@storage.local_files.length.should == 1
|
170
|
+
@storage.bucket.files.length.should == 0
|
171
|
+
@storage.sync
|
172
|
+
@storage.bucket.files.reload
|
173
|
+
@storage.bucket.files.length.should == 1
|
174
|
+
Dir.stub(:glob).and_return([])
|
175
|
+
@storage.stub(:local_files).and_return([])
|
176
|
+
@storage.stub(:remote_files).and_return([YML_DIGEST])
|
177
|
+
@storage.sync
|
178
|
+
@storage.bucket.files.reload
|
179
|
+
@storage.bucket.files.length.should == 1
|
180
|
+
@storage.options[:force_deletion_sync] = true
|
181
|
+
Fog::Storage::AWS::File.any_instance.should_receive(:etag).and_return(YML_DIGEST)
|
182
|
+
@storage.sync
|
183
|
+
@storage.bucket.files.reload
|
184
|
+
@storage.bucket.files.length.should == 0
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def create_connection
|
189
|
+
connection = Fog::Storage.new(@config.credentials)
|
190
|
+
# First, a place to contain the glorious details
|
191
|
+
connection.directories.create(:key => @config.options[:assets_directory],
|
192
|
+
:public => true)
|
193
|
+
connection
|
194
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
## Provider examples:
|
2
|
+
|
3
|
+
# provider: rackspace
|
4
|
+
# rackspace_username: RACKSPACE_USERNAME
|
5
|
+
# rackspace_api_key: RACKSPACE_API_KEY
|
6
|
+
## If you work with the European cloud from Rackspace uncomment the following
|
7
|
+
# rackspace_european_cloud: true
|
8
|
+
|
9
|
+
# provider: google
|
10
|
+
# google_storage_access_key_id: GOOGLE_STORAGE_ACCESS_KEY_ID
|
11
|
+
# google_storage_secret_access_key: GOOGLE_STORAGE_SECRET_ACCESS_KEY
|
12
|
+
|
13
|
+
## CloudStorageSync supports the following providers: aws, google, ninefold and rackspace
|
14
|
+
## For more information on which parameters are required for each provider, visit http://fog.io/1.0.0/storage/
|
15
|
+
|
16
|
+
defaults: &defaults
|
17
|
+
provider: "aws"
|
18
|
+
aws_secret_access_key: "111222333444"
|
19
|
+
aws_access_key_id: "qwerty1234567890"
|
20
|
+
|
21
|
+
test:
|
22
|
+
<<: *defaults
|
23
|
+
assets_directory: "app_test"
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class InstallGeneratorTest < Rails::Generators::TestCase
|
4
|
+
tests Cloudify::InstallGenerator
|
5
|
+
destination File.expand_path("../tmp", File.dirname(__FILE__))
|
6
|
+
setup :prepare_destination
|
7
|
+
setup :run_generator
|
8
|
+
|
9
|
+
test "Assert all files are properly created" do
|
10
|
+
assert_file "lib/tasks/cloudify.rake"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloudify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Amed Rodriguez
|
9
|
+
- Javier Saldana
|
10
|
+
- Daniel Roux
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2011-11-11 00:00:00.000000000Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec-rails
|
18
|
+
requirement: &2152934620 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - =
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.7.0
|
24
|
+
type: :development
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: *2152934620
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mocha
|
29
|
+
requirement: &2152934020 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - =
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.10.0
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: *2152934020
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: ruby-debug19
|
40
|
+
requirement: &2152926500 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
type: :development
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *2152926500
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: fog
|
51
|
+
requirement: &2152925700 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - =
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 1.0.0
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: *2152925700
|
60
|
+
description: Sync your assets hosts to Amazon, Google & Rackspace services
|
61
|
+
email:
|
62
|
+
- amed@tractical.com
|
63
|
+
- javier@tractical.com
|
64
|
+
- daniel@tractical.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- .rvmrc
|
71
|
+
- Gemfile
|
72
|
+
- MIT-LICENSE.txt
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- cloudify.gemspec
|
76
|
+
- lib/cloudify.rb
|
77
|
+
- lib/cloudify/cloudify.rb
|
78
|
+
- lib/cloudify/config.rb
|
79
|
+
- lib/cloudify/railtie.rb
|
80
|
+
- lib/cloudify/storage.rb
|
81
|
+
- lib/cloudify/version.rb
|
82
|
+
- lib/generators/cloudify/install/install_generator.rb
|
83
|
+
- lib/generators/cloudify/install_generator.rb
|
84
|
+
- lib/generators/cloudify/templates/cloudify.rake
|
85
|
+
- lib/generators/cloudify/templates/cloudify.rb
|
86
|
+
- lib/tasks/deploy.rake
|
87
|
+
- spec/cloudify_spec.rb
|
88
|
+
- spec/fixtures/cloudify.yml
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
- test/install_generator_test.rb
|
91
|
+
- test/test_helper.rb
|
92
|
+
homepage: ''
|
93
|
+
licenses: []
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
segments:
|
105
|
+
- 0
|
106
|
+
hash: 2432946652788188517
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ! '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
segments:
|
114
|
+
- 0
|
115
|
+
hash: 2432946652788188517
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project: cloudify
|
118
|
+
rubygems_version: 1.8.10
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: Sync assets hosts
|
122
|
+
test_files:
|
123
|
+
- spec/cloudify_spec.rb
|
124
|
+
- spec/fixtures/cloudify.yml
|
125
|
+
- spec/spec_helper.rb
|
126
|
+
- test/install_generator_test.rb
|
127
|
+
- test/test_helper.rb
|