cloudify 0.0.3
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/.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
|