chef_cap 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=nested
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2-p0@chef_cap
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source :rubygems
2
+
3
+ group :development do
4
+ gem "rspec-rails", "2.1"
5
+ gem 'wirble'
6
+ gem 'capistrano'
7
+ end
8
+
9
+ group :test do
10
+ gem "rspec-rails", "2.1"
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,37 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ capistrano (2.5.19)
5
+ highline
6
+ net-scp (>= 1.0.0)
7
+ net-sftp (>= 2.0.0)
8
+ net-ssh (>= 2.0.14)
9
+ net-ssh-gateway (>= 1.0.0)
10
+ diff-lcs (1.1.2)
11
+ highline (1.6.1)
12
+ net-scp (1.0.4)
13
+ net-ssh (>= 1.99.1)
14
+ net-sftp (2.0.5)
15
+ net-ssh (>= 2.0.9)
16
+ net-ssh (2.0.23)
17
+ net-ssh-gateway (1.0.1)
18
+ net-ssh (>= 1.99.1)
19
+ rspec (2.1.0)
20
+ rspec-core (~> 2.1.0)
21
+ rspec-expectations (~> 2.1.0)
22
+ rspec-mocks (~> 2.1.0)
23
+ rspec-core (2.1.0)
24
+ rspec-expectations (2.1.0)
25
+ diff-lcs (~> 1.1.2)
26
+ rspec-mocks (2.1.0)
27
+ rspec-rails (2.1.0)
28
+ rspec (~> 2.1.0)
29
+ wirble (0.1.3)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ capistrano
36
+ rspec-rails (= 2.1)
37
+ wirble
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010-11 Case Commons, LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,49 @@
1
+ = Chef Cap
2
+
3
+ * http://github.com/casecommons/chef_cap/
4
+
5
+ == DESCRIPTION
6
+
7
+ capistrano + chef-solo == deployment + server automation
8
+
9
+ Using chef's JSON configuration format to drive capistrano and chef-solo so you can use both to not only deploy your application but also completely automate the configuration of your servers.
10
+
11
+ == INSTALL
12
+
13
+ Add chef_cap to your Gemfile
14
+
15
+ group :development do
16
+ gem 'chef_cap'
17
+ end
18
+
19
+ Then run:
20
+
21
+ $ bundle install
22
+
23
+ === Rails 3
24
+
25
+ $ rails generate chef_cap:install
26
+
27
+ === Rails 2
28
+
29
+ Edit your Rakefile and add:
30
+
31
+ require 'chef_cap/tasks'
32
+
33
+ Then run:
34
+
35
+ $ bundle exec rake chef_cap:install
36
+
37
+ Which will overwrite your Capfile and create a chef directory with sample files unless one already exists.
38
+
39
+ == REQUIREMENTS
40
+
41
+ * Capistrano 2.x
42
+
43
+ == LICENSE
44
+
45
+ MIT
46
+
47
+ == NOTICE
48
+
49
+ Chef and chef-solo are © 2010 Opscode (http://www.opscode.com/)
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+ require 'rake'
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+
7
+ task :default => :spec
8
+
9
+ desc "Run all specs in spec directory (excluding plugin specs)"
10
+ RSpec::Core::RakeTask.new(:spec)
data/chef_cap.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "chef_cap/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "chef_cap"
7
+ s.version = ChefCap::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Case Commons, LLC"]
10
+ s.email = ["casecommons-dev@googlegroups.com"]
11
+ s.homepage = "https://github.com/Casecommons/chef_cap"
12
+ s.license = "MIT"
13
+ s.add_dependency('capistrano', '>= 2.5.5')
14
+ s.summary = %q{capistrano + chef-solo == chef_cap"}
15
+ s.description = %q{chef_cap uses chef"s JSON config format to drive both capistrano and chef-solo"}
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,3 @@
1
+ {
2
+ "from_file_key": "from_file_value"
3
+ }
@@ -0,0 +1 @@
1
+ dsa imaprivatekey
@@ -0,0 +1 @@
1
+ imapublickey
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "chef_cap"
@@ -0,0 +1,18 @@
1
+ require 'rake'
2
+
3
+ namespace :chef_cap do
4
+ desc "Install chefcap JSON and cookbooks for the first time"
5
+ task :install => :environment do
6
+ require "fileutils"
7
+ templates_path = File.join(File.dirname(__FILE__), "..", "generators", "chef_cap", "templates", "chef")
8
+
9
+ FileUtils.cp_r File.join(templates_path, "..", "Capfile"), File.join(Rails.root, "Capfile")
10
+
11
+ if File.exist?(Rails.root + "chef/node.json") || File.directory?(Rails.root + "chef/cookbooks")
12
+ puts "Already initialized chef_cap?"
13
+ else
14
+ FileUtils.mkdir_p(Rails.root + "chef")
15
+ FileUtils.cp_r Dir.glob(templates_path, "/*"), (Rails.root + "chef")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module ChefCap
2
+ VERSION = "0.0.5"
3
+ end
data/lib/chef_cap.rb ADDED
@@ -0,0 +1,14 @@
1
+ require "chef_cap/version"
2
+
3
+ module ChefCap
4
+
5
+ class Capistrano
6
+ RECIPES_PATH = File.expand_path(File.join(File.dirname(__FILE__), "..", "recipes"))
7
+
8
+ def self.load_recipes(capistrano)
9
+ Dir[File.join(RECIPES_PATH, "*.rb")].each { |recipe| capistrano.send(:load, recipe) }
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,14 @@
1
+ module ChefCap
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def install
7
+ copy_file "Capfile", "Capfile"
8
+ directory "chef/cookbooks/gems/recipes"
9
+ copy_file "chef/node.json", "chef/node.json"
10
+ copy_file "chef/cookbooks/gems/recipes/default.rb", "chef/cookbooks/gems/recipes/default.rb"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+
3
+ # Set up gems listed in the Gemfile.
4
+ gemfile = File.expand_path('Gemfile', __FILE__)
5
+ begin
6
+ ENV['BUNDLE_GEMFILE'] = gemfile
7
+ require 'bundler'
8
+ Bundler.setup
9
+ rescue Bundler::GemNotFound => e
10
+ STDERR.puts e.message
11
+ STDERR.puts "Try running `bundle install`."
12
+ exit!
13
+ end if File.exist?(gemfile)
14
+ require "chef_cap"
15
+ load 'deploy' if respond_to?(:namespace) # cap2 differentiator
16
+ ::ChefCap::Capistrano.load_recipes(self)
17
+ Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
18
+ load 'config/deploy'
@@ -0,0 +1,11 @@
1
+ node[:gems].each do |gem|
2
+ gem_package gem[:name] do
3
+ if gem[:version] && !gem[:version].empty?
4
+ version gem[:version]
5
+ end
6
+ if gem[:source]
7
+ source gem[:source]
8
+ end
9
+ action :install
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ {
2
+ "application": {
3
+ "name": "your-app-name",
4
+ "repository": "your-repo"
5
+ },
6
+ "upload": [
7
+ ],
8
+ "environments": {
9
+ "defaults": {
10
+ "user": "deploy",
11
+ "branch": "master",
12
+ "use_sudo": false,
13
+ "ssh": {
14
+ "deploy_key_file": "<%= ENV['HOME'] %>/.ssh/servers_deploy_key",
15
+ "authorized_pub_file": "<%= ENV['HOME'] %>/.ssh/your_workstations_public_key.pub",
16
+ "known_hosts": "github.com,207.97.227.239 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==",
17
+ "options": {
18
+ "keys": "<%= ENV['HOME'] %>/.ssh/your_workstations_private_key"
19
+ }
20
+ }
21
+ },
22
+ "production": {
23
+ "rails_env": "production",
24
+ "database": {
25
+ "user": "production-db-user",
26
+ "host": "production-db-host"
27
+ },
28
+ "servers": [
29
+ {
30
+ "hostname": "some.fq.dn",
31
+ "roles": ["web", "app", "db"],
32
+ "primary": ["web", "app", "db"]
33
+ }
34
+ ]
35
+ }
36
+ },
37
+ "shared": {
38
+ "gems": [
39
+ { "name": "bundler" },
40
+ { "name": "chef", "version": ">=0.9.12" }
41
+ ],
42
+ "run_list": ["gems"]
43
+ },
44
+ "roles": {
45
+ "web": {},
46
+ "app": {},
47
+ "db": {}
48
+ }
49
+ // "deploy_recipe": "yourcustomdeployrecipe",
50
+ }
@@ -0,0 +1,196 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "lib", "chef_dna_parser"))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), "lib", "chef_cap_helper"))
3
+ require File.expand_path(File.join(File.dirname(__FILE__), "lib", "chef_cap_configuration"))
4
+ require File.expand_path(File.join(File.dirname(__FILE__), "lib", "chef_cap_initializer"))
5
+
6
+ class DnaConfigurationError < Exception; end
7
+
8
+ ChefCapConfiguration.configuration = self
9
+ ChefDnaParser.load_dna
10
+
11
+ before "deploy", "chef:setup"
12
+
13
+ set :application, ChefDnaParser.parsed["application"]["name"] rescue nil
14
+ set :repository, ChefDnaParser.parsed["application"]["repository"] rescue nil
15
+
16
+ ChefCapConfiguration.set_repository_settings
17
+
18
+ if ChefDnaParser.parsed["environments"]
19
+ if environment_defaults = ChefDnaParser.parsed["environments"]["defaults"]
20
+ ChefCapHelper.parse_hash(environment_defaults)
21
+ end
22
+
23
+ ChefDnaParser.parsed["environments"].each_key do |environment|
24
+ next if environment == "default"
25
+ environment_hash = ChefDnaParser.parsed["environments"][environment]
26
+
27
+ desc "Set server roles for the #{environment} environment"
28
+ task environment.to_sym do
29
+ set :environment_settings, environment_hash
30
+ set :rails_env, environment_hash["rails_env"] || environment
31
+ default_environment["RAILS_ENV"] = rails_env
32
+
33
+ ChefCapHelper.parse_hash(environment_hash)
34
+
35
+ (environment_hash["servers"] || []).each do |server|
36
+ if server["roles"] && server["hostname"]
37
+ server["roles"].each do |role|
38
+ options = {}
39
+ options[:primary] = true if server["primary"] && server["primary"].include?(role)
40
+ role role.to_sym, server["hostname"], options
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ private_key = ssh_deploy_key_file rescue false
49
+ public_key = ssh_authorized_pub_file rescue false
50
+ known_hosts = ssh_known_hosts rescue false
51
+ if private_key || public_key || known_hosts
52
+ private_key_remote_file = ".ssh/id_rsa"
53
+ if private_key
54
+ key_contents = File.read(private_key)
55
+ private_key_remote_file = ".ssh/id_dsa" if key_contents =~ /DSA/i
56
+ end
57
+
58
+
59
+ namespace :ssh do
60
+ desc "Transfer SSH keys to the remote server"
61
+ task :transfer_keys do
62
+ run "mkdir -p ~/.ssh"
63
+ if private_key
64
+ put(File.read(private_key), private_key_remote_file, :mode => "0600")
65
+ end
66
+ put(File.read(public_key), ".ssh/authorized_keys", :mode => "0600") if public_key
67
+ put(known_hosts, ".ssh/known_hosts", :mode => "0600") if known_hosts
68
+ end
69
+ end
70
+ before "chef:setup", "ssh:transfer_keys"
71
+
72
+ depend(:remote, :file, private_key_remote_file) if private_key
73
+ depend(:remote, :file, ".ssh/authorized_keys") if public_key
74
+ depend(:remote, :file, ".ssh/known_hosts") if known_hosts
75
+ end
76
+
77
+ ssh_options[:paranoid] = ssh_options_paranoid rescue nil
78
+ ssh_options[:keys] = ssh_options_keys rescue nil
79
+ ssh_options[:forward_agent] = ssh_options_forward_agent rescue nil
80
+ ssh_options[:username] = ssh_options_username rescue user rescue nil
81
+
82
+ if ChefDnaParser.parsed["upload"]
83
+ uploads_for_roles = {}
84
+ ChefDnaParser.parsed["upload"].each do |upload|
85
+ unless upload.has_key?("source") && upload.has_key?("destination") && upload.has_key?("roles")
86
+ raise DnaConfigurationError, "Invalid upload entry, should be {'source':value, 'destination':value, 'roles':[list], 'mode':value}"
87
+ end
88
+ upload["roles"].each do |role|
89
+ uploads_for_roles[role] ||= []
90
+ uploads_for_roles[role] << [upload["source"], upload["destination"], {:mode => upload["mode"] || "0644"}]
91
+ end
92
+ end
93
+
94
+ uploads_for_roles.each_pair do |role, file_uploads|
95
+ task "chef_upload_for_#{role}".to_sym, :roles => role do
96
+ file_uploads.each do |file_to_upload|
97
+ # TODO: better then mac local -> linux remote compatibility here
98
+ run "md5sum #{file_to_upload[1]} | cut -f1 -d ' '" do |channel, stream, data|
99
+ remote_md5 = data.to_s.strip
100
+ local_md5 = `md5 #{file_to_upload[0]} | cut -f 2 -d '='`.to_s.strip
101
+ if remote_md5 == local_md5
102
+ puts "#{File.basename(file_to_upload[1])} matches checksum, skipping"
103
+ else
104
+ upload file_to_upload[0], file_to_upload[1], :host => channel[:host]
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ namespace :chef do
112
+ desc "Uploads specified files to remote server"
113
+ task :upload_all do
114
+ uploads_for_roles.keys.each do |role|
115
+ send "chef_upload_for_#{role}".to_sym
116
+ end
117
+ end
118
+ end
119
+
120
+ before "chef:deploy", "chef:upload_all"
121
+ end
122
+
123
+ if ChefDnaParser.parsed["chef"] && ChefDnaParser.parsed["chef"]["root"]
124
+ set :chef_root_path, ChefDnaParser.parsed["chef"]["root"]
125
+ elsif ChefDnaParser.file_path
126
+ default_chef_path = File.expand_path(File.join(File.dirname(ChefDnaParser.file_path)))
127
+ if File.directory?(File.join(default_chef_path, "cookbooks"))
128
+ set :chef_root_path, default_chef_path
129
+ end
130
+ else
131
+ raise DnaConfigurationError, "Could not find cookbooks in JSON or as a subdirectory of where your JSON is!"
132
+ end
133
+
134
+ namespace :chef do
135
+ desc "Setup chef solo on the server(s)"
136
+ task :setup do
137
+ sudo "rvm default exec gem specification --version '>=0.9.12' chef 2>&1 | awk 'BEGIN { s = 0 } /^name:/ { s = 1; exit }; END { if(s == 0) exit 1 }' || sudo rvm default exec gem install chef --no-ri --no-rdoc && echo 'Chef Solo already on this server.'"
138
+ sudo "rvm default exec which chef-solo"
139
+ end
140
+
141
+ desc "Run chef-solo on the server(s)"
142
+ task :deploy do
143
+ put "cookbook_path '/tmp/chef-cap-#{rails_env}/cookbooks'", "/tmp/chef-cap-solo-#{rails_env}.rb", :mode => "0600"
144
+ sudo "rm -rf /tmp/chef-cap-#{rails_env}"
145
+ upload chef_root_path, "/tmp/chef-cap-#{rails_env}", :mode => "0700"
146
+
147
+
148
+ begin
149
+ env_settings = environment_settings
150
+ rescue
151
+ raise "Could not load environment_settings, usually this means you tried to run the deploy task without calling an <env> first"
152
+ end
153
+ parallel do |session|
154
+ session.else "echo 'Deploying Chef to this machine'" do |channel, stream, data|
155
+ roles_for_host = ChefCapHelper.roles_for_host(roles, channel[:host])
156
+
157
+ json_to_modify = ChefDnaParser.parsed.dup
158
+ hash_for_host = ChefCapHelper.merge_roles_for_host(json_to_modify["roles"], roles_for_host)
159
+
160
+ shared_hash = json_to_modify["shared"] || {}
161
+ shared_hash.each { |k, v| ChefCapHelper.recursive_merge(json_to_modify, k, v) }
162
+ hash_for_host.each {|k, v| ChefCapHelper.recursive_merge(json_to_modify, k, v) }
163
+
164
+ json_to_modify["environment"] ||= json_to_modify["environments"]["defaults"] || {} rescue {}
165
+ env_settings.each { |k, v| ChefCapHelper.recursive_merge(json_to_modify["environment"] || {}, k, v) }
166
+
167
+ json_to_modify["environment"]["revision"] = ChefCapHelper.set_revision if ChefCapHelper.has_revision?
168
+ json_to_modify["environment"]["servers"] = ChefCapHelper.intialize_primary_values(json_to_modify["environment"]["servers"])
169
+
170
+ should_not_deploy = no_deploy rescue false
171
+ json_to_modify["run_list"] = ChefCapHelper.rewrite_run_list_for_deploy(json_to_modify, should_not_deploy)
172
+
173
+ set "node_hash_for_#{channel[:host].gsub(/\./, "_")}", json_to_modify
174
+ put json_to_modify.to_json, "/tmp/chef-cap-#{rails_env}-#{channel[:host]}.json", :mode => "0600"
175
+ end
176
+ end
177
+
178
+ chef.run_chef_solo
179
+ end
180
+
181
+ task :run_chef_solo do
182
+ db = find_servers(:roles => [:db]).map(&:host)
183
+ app_and_web_only = find_servers(:roles => [:app, :web]).map(&:host) - db
184
+
185
+ run_chef_solo = "env PATH=$PATH:/usr/sbin rvm default exec chef-solo -c /tmp/chef-cap-solo-#{rails_env}.rb -j /tmp/chef-cap-#{rails_env}-`hostname`.json #{ENV['DEBUG'] ? '-l debug' : ''}"
186
+ sudo(run_chef_solo, :hosts => db) if db.any?
187
+ sudo(run_chef_solo, :hosts => app_and_web_only) if app_and_web_only.any?
188
+ end
189
+
190
+ desc "Remove all chef-cap files from /tmp"
191
+ task :cleanup do
192
+ sudo "rm -rf /tmp/chef-cap*"
193
+ end
194
+ end
195
+
196
+ before "chef:deploy", "chef:setup"
data/recipes/cook.rb ADDED
@@ -0,0 +1,7 @@
1
+ desc "Run chef without deploy"
2
+ task :cook do
3
+ set :no_deploy, true
4
+ chef.deploy
5
+ end
6
+
7
+ before "cook", "chef:setup"
@@ -0,0 +1,19 @@
1
+ class ChefCapConfiguration
2
+ class << self
3
+ attr_accessor :configuration
4
+
5
+ def set_repository_settings
6
+ repository_value = @configuration.send(:repository) rescue false
7
+ case repository_value
8
+ when /git/
9
+ @configuration.send(:set, :scm, :git)
10
+ @configuration.send(:set, :git_enable_submodules, 1)
11
+ @configuration.send(:default_run_options)[:pty] = true
12
+ @configuration.send(:depend, :remote, :command, "git")
13
+ when /svn/
14
+ @configuration.send(:set, :scm, :svn)
15
+ @configuration.send(:depend, :remote, :command, "svn")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,77 @@
1
+ class ChefCapHelper
2
+ class << self
3
+ def debug(message)
4
+ puts "** #{message}" if ENV["DEBUG"]
5
+ end
6
+
7
+ def parse_hash(hash, prefix = nil)
8
+ hash.each do |key, value|
9
+ if value.is_a? Hash
10
+ parse_hash(value, [prefix, key].compact.join("_"))
11
+ else
12
+ key = [prefix, key].compact.join("_").to_sym
13
+ debug("Setting #{key.inspect} => #{value.inspect}")
14
+ ChefCapConfiguration.configuration.set key, value
15
+ end
16
+ end
17
+ end
18
+
19
+ def recursive_merge(hash, key, value)
20
+ case "#{hash[key].class}_#{value.class}"
21
+ when "Array_Array"
22
+ hash[key] = hash[key] | value
23
+ when "Hash_Hash"
24
+ hash[key] = hash[key].merge(value)
25
+ else
26
+ hash[key] = value
27
+ end
28
+ hash
29
+ end
30
+
31
+ def roles_for_host(roles, current_host)
32
+ roles.select do |role_name, role|
33
+ role.servers.map(&:host).include?(current_host)
34
+ end.map(&:first).map(&:to_s)
35
+ end
36
+
37
+ def merge_roles_for_host(roles_hash, roles_for_host)
38
+ return {} if roles_hash.nil?
39
+
40
+ merged_hash_for_host = {}
41
+ roles_hash.each do |role_name, role_hash|
42
+ if roles_for_host.include?(role_name.to_s)
43
+ role_hash.each do |role_hash_key, role_hash_key_value|
44
+ merged_hash_for_host.merge(recursive_merge(merged_hash_for_host, role_hash_key, role_hash_key_value))
45
+ end
46
+ end
47
+ end
48
+ merged_hash_for_host
49
+ end
50
+
51
+ def set_revision
52
+ ENV["rev"] || ENV["tag"] || ENV["REV"] || ENV["TAG"] || ENV["revision"] || ENV["REVISION"]
53
+ end
54
+
55
+ def has_revision?
56
+ !set_revision.nil?
57
+ end
58
+
59
+ def rewrite_run_list_for_deploy(json_hash, should_not_deploy = false)
60
+ return nil if json_hash["run_list"].nil?
61
+ new_run_list = json_hash["run_list"].dup
62
+ if json_hash.has_key? "deploy_recipe"
63
+ deploy_recipe = new_run_list.delete(json_hash["deploy_recipe"])
64
+ new_run_list << deploy_recipe if deploy_recipe && !should_not_deploy
65
+ end
66
+ new_run_list
67
+ end
68
+
69
+ def intialize_primary_values(array_of_server_hashes)
70
+ array_of_server_hashes.each do |server_hash|
71
+ server_hash["primary"] ||= []
72
+ end
73
+ array_of_server_hashes
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,6 @@
1
+ class ChefCapInitializer
2
+
3
+ def self.load(configuration)
4
+
5
+ end
6
+ end
@@ -0,0 +1,36 @@
1
+ require "json"
2
+ require "erb"
3
+ require "fileutils"
4
+
5
+ class ChefDnaParser
6
+
7
+ class << self
8
+ attr_accessor :dna, :parsed, :file_path, :test_dna
9
+
10
+ def test_dna=(json)
11
+ @test_dna = json
12
+ end
13
+
14
+ def load_dna
15
+ @parsed ||= {}
16
+ @dna ||= ""
17
+ if @test_dna
18
+ @dna = ERB.new(@test_dna).result(binding)
19
+ else
20
+ @file_path = ENV["DNA"] || ENV["dna"] || default_dna_path
21
+
22
+ @dna = ERB.new(File.read(file_path)).result(binding)
23
+ end
24
+ @parsed = JSON.parse(@dna)
25
+ end
26
+
27
+ def default_dna_path
28
+ File.join(rails_root, "chef", "node.json")
29
+ end
30
+
31
+ def rails_root
32
+ FileUtils.pwd
33
+ end
34
+ end
35
+
36
+ end