ruby_deployer 0.1.0

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 ADDED
@@ -0,0 +1,5 @@
1
+ Deployfile
2
+ .DS_Store
3
+ tags
4
+ tmp/
5
+ config/
data/.rvmrc ADDED
@@ -0,0 +1,5 @@
1
+ rvm use 1.9.3@ruby-deployer --create
2
+
3
+ if ! command -v bundle ; then
4
+ gem install bundler
5
+ fi
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,41 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ruby_deployer (0.0.1)
5
+ fog
6
+ rake
7
+ thor
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ builder (3.1.3)
13
+ excon (0.16.4)
14
+ fog (1.6.0)
15
+ builder
16
+ excon (~> 0.14)
17
+ formatador (~> 0.2.0)
18
+ mime-types
19
+ multi_json (~> 1.0)
20
+ net-scp (~> 1.0.4)
21
+ net-ssh (>= 2.1.3)
22
+ nokogiri (~> 1.5.0)
23
+ ruby-hmac
24
+ formatador (0.2.3)
25
+ jruby-pageant (1.1.1)
26
+ mime-types (1.19)
27
+ multi_json (1.3.6)
28
+ net-scp (1.0.4)
29
+ net-ssh (>= 1.99.1)
30
+ net-ssh (2.6.0)
31
+ jruby-pageant (>= 1.1.1)
32
+ nokogiri (1.5.5)
33
+ rake (0.9.2.2)
34
+ ruby-hmac (0.4.0)
35
+ thor (0.16.0)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ ruby_deployer!
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # Ruby Deployer
2
+
3
+ A simple tool with a simple name that helps put deployments into the
4
+ hands of developers instead of manual deployment tinkers.
5
+
6
+ ## Philosophy
7
+
8
+ This tool has a philosophy that drives its developement.
9
+
10
+ * Deploy artifacts, not source revisions.
11
+ * Automate creation, provisioning and decommissioning of machines on top
12
+ of a virtualized machine.
13
+ * Simple, understandable DSL that is similar in style and function to
14
+ rake.
15
+ * Servers that contain only runtime environments.
16
+ * Reproducable production environments on a local machine.
17
+
18
+ ## Sample Code
19
+
20
+ Deployfile
21
+
22
+ ```ruby
23
+ artifact :webapp do
24
+ before do
25
+ sh 'bundle install --deployment'
26
+ rake 'assets:precompile'
27
+ end
28
+ exclude ['db']
29
+ end
30
+
31
+ artifact :db do
32
+ before do
33
+ sh 'bundle install --deployment'
34
+ end
35
+ include ['db', 'vendor'] # We need vendor for the vendered gems
36
+ end
37
+
38
+ provision do
39
+ # By default, cookbooks are discovered in ./cookbooks
40
+ # cookbooks ['cookbooks']
41
+ instance 'haproxy'
42
+ instance 'application_master'
43
+ instance 'application', count: 4
44
+ instance 'database_master'
45
+ instance 'database'
46
+ instance 'resque', count: 2
47
+ end
48
+
49
+ deploy do
50
+ push :webapp => ['application_master', 'application', 'resque']
51
+ push :db => ['database_master', 'database']
52
+ end
53
+
54
+ verify do
55
+ rake "deploy:verify[#{environment}]"
56
+ end
57
+ ```
58
+
59
+ Minimal Deployfile
60
+
61
+ ```ruby
62
+ artifact :webapp
63
+
64
+ provision do
65
+ instance 'application_master'
66
+ end
67
+
68
+ deploy :webapp => ['application_master']
69
+ ```
data/Rakefile ADDED
File without changes
data/bin/ruby-deployer ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'thor'
5
+ require_relative '../lib/ruby_deployer'
6
+
7
+ RubyDeployer::Runner.start ARGV
@@ -0,0 +1,31 @@
1
+ require_relative 'file_system_repository'
2
+ require_relative 'general_dsl'
3
+
4
+ module RubyDeployer
5
+ class ArtifactDSL
6
+ include GeneralDSL
7
+
8
+ attr_reader :excludes
9
+
10
+ def initialize options
11
+ @repository = (options[:repository] or FileSystemRepository).new
12
+ end
13
+
14
+ def before(&block)
15
+ @before_block = block
16
+ end
17
+
18
+ def exclude excludes
19
+ @excludes = excludes.map { |exclude| "\\*#{exclude}" }
20
+ end
21
+
22
+ def execute(&block)
23
+ instance_eval &block
24
+ end
25
+
26
+ def publish file
27
+ instance_eval &@before_block if @before_block
28
+ @repository.publish file
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ module RubyDeployer
2
+ class Builder
3
+ def initialize deploy_file
4
+ @deploy_file = deploy_file
5
+ end
6
+
7
+ def start
8
+ puts 'Building...'
9
+ @deploy_file.artifacts.each do |name, artifact|
10
+ file = package name, artifact
11
+ artifact.publish File.open(file)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def package name, artifact
18
+ puts "Creating package #{package_name(name)}..."
19
+ file_location = File.join('tmp', package_name(name))
20
+ `mkdir -p tmp`
21
+ `zip -r #{file_location} . -x #{artifact.excludes.join(' ')}`
22
+ file_location
23
+ end
24
+
25
+ def package_name name
26
+ "#{name}-#{Time.now.to_i}.zip"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,44 @@
1
+ require_relative 'artifact_dsl'
2
+ require_relative 'provision_dsl'
3
+ require_relative 'deployment_dsl'
4
+
5
+ module RubyDeployer
6
+ class DeployFile
7
+ attr_reader :artifacts, :instances, :deployments
8
+
9
+ def initialize file
10
+ @file = file
11
+ @artifacts = Hash.new
12
+ @instances = []
13
+ @deployments = {}
14
+ end
15
+
16
+ def artifact(name, options={}, &block)
17
+ artifact_dsl = ArtifactDSL.new(options)
18
+ artifact_dsl.execute(&block) if block_given?
19
+ @artifacts[name] = artifact_dsl
20
+ end
21
+
22
+ def provision(options={}, &block)
23
+ provision_dsl = ProvisionDSL.new(options)
24
+ provision_dsl.execute(&block) if block_given?
25
+ @instances = provision_dsl.instances
26
+ end
27
+
28
+ def deploy(&block)
29
+ deployment_dsl = DeploymentDSL.new
30
+ deployment_dsl.execute(&block) if block_given?
31
+ @deployments = deployment_dsl.deployments
32
+ end
33
+
34
+ def evaluate
35
+ eval(contents, binding)
36
+ end
37
+
38
+ private
39
+
40
+ def contents
41
+ File.read @file
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,51 @@
1
+ module RubyDeployer
2
+ class Deployer
3
+ def initialize deploy_file, artifact, environment, artifact_repository
4
+ @deploy_file = deploy_file
5
+ @artifact = artifact
6
+ @environment = environment
7
+ @artifact_repository = artifact_repository
8
+ end
9
+
10
+ def start
11
+ destinations = @deploy_file.deployments[@artifact.to_sym]
12
+ targets = servers destinations
13
+ targets.each do |target|
14
+ target.scp(@artifact_repository.get_latest, '/home/ubuntu')
15
+ end
16
+ end
17
+
18
+ def servers(destinations)
19
+ destinations.map do |destination|
20
+ server = connection.servers.all.detect do |s|
21
+ s.state == 'running' and
22
+ s.tags.include? "#{@environment}_#{destination}"
23
+ end
24
+ server.private_key_path = File.join('config', 'aws_key')
25
+ server
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def connection
32
+ @connection ||= Fog::Compute.new({
33
+ provider: 'AWS',
34
+ aws_access_key_id: config['AWS_ACCESS_KEY_ID'],
35
+ aws_secret_access_key: config['AWS_SECRET_ACCESS_KEY']
36
+ })
37
+ end
38
+
39
+ def config
40
+ @config ||= begin
41
+ load_config_error unless File.exists?(File.join('config', 'fog.yml'))
42
+ YAML.load_file File.join('config', 'fog.yml')
43
+ end
44
+ end
45
+
46
+ def load_config_error
47
+ log('Cannot load config/fog.yml')
48
+ raise StandardError.new('Cannot load config/fog.yml')
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,19 @@
1
+ module RubyDeployer
2
+ class DeploymentDSL
3
+ attr_reader :deployments
4
+
5
+ def initialize
6
+ @deployments = {}
7
+ end
8
+
9
+ def push(options)
10
+ options.each do |artifact, destinations|
11
+ @deployments[artifact] = destinations
12
+ end
13
+ end
14
+
15
+ def execute(&block)
16
+ instance_eval &block
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ module RubyDeployer
2
+ class ExecutionFailureError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,16 @@
1
+ module RubyDeployer
2
+ class FileSystemRepository
3
+ def initialize
4
+ @location = File.expand_path('~/.rubydeployer/artifacts')
5
+ `mkdir -p #{@location}`
6
+ end
7
+
8
+ def publish file
9
+ FileUtils.copy file, @location
10
+ end
11
+
12
+ def get_latest
13
+ Dir.glob(File.join(@location, '*.zip')).last
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'execution_failure_error'
2
+
3
+ module RubyDeployer
4
+ module GeneralDSL
5
+ def sh cmd, options={}
6
+ result = `#{cmd}`
7
+ if $?.exitstatus > 0
8
+ raise ExecutionFailureError.new(cmd) unless options[:skip_on_fail]
9
+ end
10
+ log result
11
+ end
12
+
13
+ def rake cmd, options={}
14
+ result = `bundle exec rake #{cmd}`
15
+ if $?.exitstatus > 0
16
+ raise ExecutionFailureError.new(cmd) unless options[:skip_on_fail]
17
+ end
18
+ log result
19
+ end
20
+
21
+ def log message
22
+ puts message
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'general_dsl'
2
+ require 'fog'
3
+
4
+ module RubyDeployer
5
+ class Instance
6
+ include GeneralDSL
7
+
8
+ attr_reader :name, :options
9
+
10
+ def initialize name, options
11
+ @name = name
12
+ @options = options
13
+ end
14
+
15
+ def build connection, environment
16
+ connection.servers.bootstrap(
17
+ private_key_path: File.join('config', 'aws_key'),
18
+ public_key_path: File.join('config', 'aws_key.pub'),
19
+ username: 'ubuntu',
20
+ tags: ["#{environment}_#{name}"]
21
+ )
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'instance'
2
+
3
+ module RubyDeployer
4
+ class ProvisionDSL
5
+ attr_reader :instances
6
+
7
+ def initialize options
8
+ @instances = []
9
+ end
10
+
11
+ def instance(name, options={}, &block)
12
+ @instances << Instance.new(name, options)
13
+ end
14
+
15
+ def execute(&block)
16
+ instance_eval &block
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ module RubyDeployer
2
+ class Provisioner
3
+ def initialize deploy_file, environment
4
+ @deploy_file = deploy_file
5
+ @environment = environment
6
+ end
7
+
8
+ def start
9
+ puts 'Provisioning...'
10
+ @deploy_file.instances.each { |instance| instance.build(connection, @environment) }
11
+ end
12
+
13
+ private
14
+
15
+ def connection
16
+ @connection ||= Fog::Compute.new({
17
+ provider: 'AWS',
18
+ aws_access_key_id: config['AWS_ACCESS_KEY_ID'],
19
+ aws_secret_access_key: config['AWS_SECRET_ACCESS_KEY']
20
+ })
21
+ end
22
+
23
+ def config
24
+ @config ||= begin
25
+ load_config_error unless File.exists?(File.join('config', 'fog.yml'))
26
+ YAML.load_file File.join('config', 'fog.yml')
27
+ end
28
+ end
29
+
30
+ def load_config_error
31
+ log('Cannot load config/fog.yml')
32
+ raise StandardError.new('Cannot load config/fog.yml')
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,57 @@
1
+ require_relative 'deploy_file'
2
+ require_relative 'builder'
3
+ require_relative 'provisioner'
4
+ require_relative 'deployer'
5
+ require_relative 'unprovisioner'
6
+
7
+ def requirements
8
+ unless File.exists? './Deployfile'
9
+ puts 'Cannot find a Deployfile'
10
+ exit 1
11
+ end
12
+ unless File.exists? 'config/fog.yml'
13
+ puts 'Cannot find a config/fog.yml file'
14
+ exit 1
15
+ end
16
+ unless File.exists? 'config/aws_key'
17
+ puts 'Cannot find a config/aws_key ssh key'
18
+ exit 1
19
+ end
20
+ end
21
+
22
+ module RubyDeployer
23
+ class Runner < Thor
24
+ desc "build", "build artifacts using the Deployfile"
25
+ def build
26
+ requirements
27
+ deploy_file = DeployFile.new(File.open('./Deployfile'))
28
+ deploy_file.evaluate
29
+ Builder.new(deploy_file).start
30
+ end
31
+
32
+ desc 'provision ENVIRONMENT_NAME', 'provision servers described in the Deployfile'
33
+ def provision(environment)
34
+ requirements
35
+ deploy_file = DeployFile.new(File.open('./Deployfile'))
36
+ deploy_file.evaluate
37
+ Provisioner.new(deploy_file, environment).start
38
+ end
39
+
40
+ desc 'deploy ARTIFACT ENVIRONMENT_NAME', 'deploy the latest artifact to the specified environment'
41
+ def deploy(artifact, environment)
42
+ requirements
43
+ deploy_file = DeployFile.new(File.open('./Deployfile'))
44
+ repository = FileSystemRepository.new
45
+ deploy_file.evaluate
46
+ Deployer.new(deploy_file, artifact, environment, repository).start
47
+ end
48
+
49
+ desc 'unprovision ENVIRONMENT_NAME', 'decommission the servers for a specified environment'
50
+ def unprovision(environment)
51
+ requirements
52
+ deploy_file = DeployFile.new(File.open('./Deployfile'))
53
+ deploy_file.evaluate
54
+ Unprovisioner.new(deploy_file, environment).start
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,41 @@
1
+ module RubyDeployer
2
+ class Unprovisioner
3
+ def initialize deploy_file, environment
4
+ @deploy_file = deploy_file
5
+ @environment = environment
6
+ end
7
+
8
+ def start
9
+ puts 'Unprovisioning...'
10
+ servers.each { |server| server.destroy }
11
+ end
12
+
13
+ private
14
+
15
+ def servers
16
+ connection.servers.select do |server|
17
+ server.tags.keys.any? { |tag| tag =~ /#{@environment}/ }
18
+ end
19
+ end
20
+
21
+ def connection
22
+ @connection ||= Fog::Compute.new({
23
+ provider: 'AWS',
24
+ aws_access_key_id: config['AWS_ACCESS_KEY_ID'],
25
+ aws_secret_access_key: config['AWS_SECRET_ACCESS_KEY']
26
+ })
27
+ end
28
+
29
+ def config
30
+ @config ||= begin
31
+ load_config_error unless File.exists?(File.join('config', 'fog.yml'))
32
+ YAML.load_file File.join('config', 'fog.yml')
33
+ end
34
+ end
35
+
36
+ def load_config_error
37
+ log('Cannot load config/fog.yml')
38
+ raise StandardError.new('Cannot load config/fog.yml')
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module RubyDeployer
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'ruby_deployer/version'
2
+ require_relative 'ruby_deployer/runner'
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/ruby_deployer/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Derek Hammer"]
6
+ gem.email = ["derek.r.hammer@gmail.com"]
7
+ gem.description = %q{Ruby deployer helps you deploy your web applications}
8
+ gem.summary = %q{Ruby deployer helps you deploy your web applications}
9
+ gem.homepage = ""
10
+ gem.files = `git ls-files`.split($\)
11
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
12
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
13
+ gem.name = "ruby_deployer"
14
+ gem.require_paths = ["lib"]
15
+ gem.version = RubyDeployer::VERSION
16
+
17
+ gem.add_dependency 'thor'
18
+ gem.add_dependency 'rake'
19
+ gem.add_dependency 'fog'
20
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_deployer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Derek Hammer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: fog
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Ruby deployer helps you deploy your web applications
63
+ email:
64
+ - derek.r.hammer@gmail.com
65
+ executables:
66
+ - ruby-deployer
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - .gitignore
71
+ - .rvmrc
72
+ - Gemfile
73
+ - Gemfile.lock
74
+ - README.md
75
+ - Rakefile
76
+ - bin/ruby-deployer
77
+ - lib/ruby_deployer.rb
78
+ - lib/ruby_deployer/artifact_dsl.rb
79
+ - lib/ruby_deployer/builder.rb
80
+ - lib/ruby_deployer/deploy_file.rb
81
+ - lib/ruby_deployer/deployer.rb
82
+ - lib/ruby_deployer/deployment_dsl.rb
83
+ - lib/ruby_deployer/execution_failure_error.rb
84
+ - lib/ruby_deployer/file_system_repository.rb
85
+ - lib/ruby_deployer/general_dsl.rb
86
+ - lib/ruby_deployer/instance.rb
87
+ - lib/ruby_deployer/provision_dsl.rb
88
+ - lib/ruby_deployer/provisioner.rb
89
+ - lib/ruby_deployer/runner.rb
90
+ - lib/ruby_deployer/unprovisioner.rb
91
+ - lib/ruby_deployer/version.rb
92
+ - ruby_deployer.gemspec
93
+ homepage: ''
94
+ licenses: []
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 1.8.24
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: Ruby deployer helps you deploy your web applications
117
+ test_files: []