ahamid-soloist 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.rvmrc +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +73 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +106 -0
- data/Rakefile +2 -0
- data/bin/soloist +31 -0
- data/lib/soloist.rb +9 -0
- data/lib/soloist/chef_config_generator.rb +82 -0
- data/lib/soloist/util.rb +41 -0
- data/lib/soloist/version.rb +3 -0
- data/soloist.gemspec +24 -0
- data/spec/chef_config_generator_spec.rb +242 -0
- data/spec/pivotal_workstation_cookbook.rb +1 -0
- data/spec/util_spec.rb +20 -0
- metadata +96 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm ruby-1.8.7-p299@soloist
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
soloist (0.9.0)
|
5
|
+
chef
|
6
|
+
json (>= 1.4.4, <= 1.5.2)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
bunny (0.7.1)
|
12
|
+
chef (0.10.2)
|
13
|
+
bunny (>= 0.6.0)
|
14
|
+
erubis
|
15
|
+
highline
|
16
|
+
json (>= 1.4.4, <= 1.5.2)
|
17
|
+
mixlib-authentication (>= 1.1.0)
|
18
|
+
mixlib-cli (>= 1.1.0)
|
19
|
+
mixlib-config (>= 1.1.2)
|
20
|
+
mixlib-log (>= 1.3.0)
|
21
|
+
moneta
|
22
|
+
net-ssh (~> 2.1.3)
|
23
|
+
net-ssh-multi (~> 1.0.1)
|
24
|
+
ohai (>= 0.6.0)
|
25
|
+
rest-client (>= 1.0.4, < 1.7.0)
|
26
|
+
treetop (~> 1.4.9)
|
27
|
+
uuidtools
|
28
|
+
diff-lcs (1.1.2)
|
29
|
+
erubis (2.7.0)
|
30
|
+
highline (1.6.2)
|
31
|
+
json (1.5.2)
|
32
|
+
mime-types (1.16)
|
33
|
+
mixlib-authentication (1.1.4)
|
34
|
+
mixlib-log
|
35
|
+
mixlib-cli (1.2.0)
|
36
|
+
mixlib-config (1.1.2)
|
37
|
+
mixlib-log (1.3.0)
|
38
|
+
moneta (0.6.0)
|
39
|
+
net-ssh (2.1.4)
|
40
|
+
net-ssh-gateway (1.1.0)
|
41
|
+
net-ssh (>= 1.99.1)
|
42
|
+
net-ssh-multi (1.0.1)
|
43
|
+
net-ssh (>= 1.99.2)
|
44
|
+
net-ssh-gateway (>= 0.99.0)
|
45
|
+
ohai (0.6.4)
|
46
|
+
mixlib-cli
|
47
|
+
mixlib-config
|
48
|
+
mixlib-log
|
49
|
+
systemu
|
50
|
+
yajl-ruby
|
51
|
+
polyglot (0.3.1)
|
52
|
+
rest-client (1.6.3)
|
53
|
+
mime-types (>= 1.16)
|
54
|
+
rspec (2.4.0)
|
55
|
+
rspec-core (~> 2.4.0)
|
56
|
+
rspec-expectations (~> 2.4.0)
|
57
|
+
rspec-mocks (~> 2.4.0)
|
58
|
+
rspec-core (2.4.0)
|
59
|
+
rspec-expectations (2.4.0)
|
60
|
+
diff-lcs (~> 1.1.2)
|
61
|
+
rspec-mocks (2.4.0)
|
62
|
+
systemu (2.2.0)
|
63
|
+
treetop (1.4.9)
|
64
|
+
polyglot (>= 0.3.1)
|
65
|
+
uuidtools (2.1.2)
|
66
|
+
yajl-ruby (0.8.2)
|
67
|
+
|
68
|
+
PLATFORMS
|
69
|
+
ruby
|
70
|
+
|
71
|
+
DEPENDENCIES
|
72
|
+
rspec (= 2.4.0)
|
73
|
+
soloist!
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright (c) 2010, 2011 Matthew Kocher
|
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.markdown
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
Soloist: Making chef-solo easier
|
2
|
+
================================
|
3
|
+
|
4
|
+
# Why?
|
5
|
+
You just want to use chef solo, not worry about where your config files are, or what they should look like (too much). You might think that json is a data serialization format and not a config file format. You might think that having two config files that you have to pass to an executable every time you run it is two too many.
|
6
|
+
|
7
|
+
# How?
|
8
|
+
Soloist is a script packaged as a gem which when run recurses up the file tree looking for a soloistrc file. When it finds it, it uses it to determine 1) Where its cookbooks are and 2) What recipes to run. It generates the necessary config files for chef solo, and kicks it off.
|
9
|
+
|
10
|
+
# That's exactly what I've always wanted! How do I use it?
|
11
|
+
* (sudo) gem install soloist
|
12
|
+
* create a directory to store your cookbooks in, and get a cookbook:
|
13
|
+
sh -c 'mkdir -p chef/cookbooks/pivotal_workstation && cd chef/cookbooks/pivotal_workstation && curl -L http://github.com/pivotal/pivotal_workstation/tarball/master | gunzip | tar xvf - --strip=1'
|
14
|
+
* create your soloistrc file in the root of your project.
|
15
|
+
|
16
|
+
# What if I'm just setting up my own machine, and have many projects?
|
17
|
+
Just put your soloistrc file in your home directory, and point it to wherever you want to keep your cookbooks. Or just dedicate a git repo to it, and go into that directory before running soloist.
|
18
|
+
|
19
|
+
# How do I write a solistrc file?
|
20
|
+
It's a yaml file, currently with two lists to maintain:
|
21
|
+
|
22
|
+
The first, _cookbook\_paths_, should point (using an absolute or path relative to your soloistrc file) to the directory containing your cookbooks, such was pivotal_workstation.
|
23
|
+
|
24
|
+
The second, _recipes_ should be a list of recipes you wish to run.
|
25
|
+
|
26
|
+
# Then What?
|
27
|
+
$> soloist
|
28
|
+
|
29
|
+
|
30
|
+
Example soloistrc Files
|
31
|
+
=======================
|
32
|
+
|
33
|
+
directory layout:
|
34
|
+
|
35
|
+
/Users/mkocher/workspace/project/soloistrc <-Config File
|
36
|
+
/Users/mkocher/workspace/project/chef/
|
37
|
+
/Users/mkocher/workspace/project/chef/cookbooks/pivotal_workstation/
|
38
|
+
|
39
|
+
|
40
|
+
soloistrc
|
41
|
+
---------
|
42
|
+
cookbook_paths:
|
43
|
+
- ./chef/cookbooks/
|
44
|
+
recipes:
|
45
|
+
- pivotal_workstation::ack
|
46
|
+
- pivotal_workstation::bash_path_order
|
47
|
+
- pivotal_workstation::bash_profile
|
48
|
+
- pivotal_workstation::bash_profile-better_history
|
49
|
+
- pivotal_workstation::defaults_fast_key_repeat_rate
|
50
|
+
- pivotal_workstation::dock_preferences
|
51
|
+
- pivotal_workstation::ec2_api_tools
|
52
|
+
- pivotal_workstation::finder_display_full_path
|
53
|
+
- pivotal_workstation::git
|
54
|
+
- pivotal_workstation::git_config_global_defaults
|
55
|
+
- pivotal_workstation::git_scripts
|
56
|
+
- pivotal_workstation::google_chrome
|
57
|
+
- pivotal_workstation::inputrc
|
58
|
+
- pivotal_workstation::mysql
|
59
|
+
- pivotal_workstation::osx_turn_on_locate
|
60
|
+
- pivotal_workstation::rvm
|
61
|
+
- pivotal_workstation::safari_preferences
|
62
|
+
- pivotal_workstation::set_multitouch_preferences
|
63
|
+
- pivotal_workstation::text_mate
|
64
|
+
- pivotal_workstation::textmate_set_defaults
|
65
|
+
- pivotal_workstation::turn_on_ssh
|
66
|
+
- pivotal_workstation::user_owns_usr_local
|
67
|
+
- pivotal_workstation::workspace_directory
|
68
|
+
|
69
|
+
Environment Variable Switching
|
70
|
+
==============================
|
71
|
+
I'm trying out adding support in the soloistrc file for selecting recipes based on environment variables. Cap should allow setting environment variables fairly easily on deploy, and they can be set permanently on the machine if desired. To use these, add a env_variable_switches key to your soloistrc. They keys of the hash should be the environment variable you wish to change the configuration based on, and the value should be a hash keyed by the value of the variable. It's easier than it sounds - see the example below. (NB: Note that the CamelSnake is gone in the soloistrc, and while the basic config accepts the old keys, environment variable switching requires snake case keys)
|
72
|
+
|
73
|
+
cookbook_paths:
|
74
|
+
- ./chef/cookbooks/
|
75
|
+
recipes:
|
76
|
+
- pivotal_workstation::ack
|
77
|
+
env_variable_switches:
|
78
|
+
RACK_ENV:
|
79
|
+
production:
|
80
|
+
cookbook_paths:
|
81
|
+
- ./chef/production_cookbooks/
|
82
|
+
recipes:
|
83
|
+
- production::foo
|
84
|
+
|
85
|
+
The values are merged in, so this results in a cookbook path of
|
86
|
+
[
|
87
|
+
"./chef/cookbooks/",
|
88
|
+
"./chef/production_cookbooks/"
|
89
|
+
]
|
90
|
+
and a recipe list of
|
91
|
+
[
|
92
|
+
"pivotal_workstation::ack",
|
93
|
+
"production::foo"
|
94
|
+
]
|
95
|
+
|
96
|
+
Log Level
|
97
|
+
=========
|
98
|
+
Soloist runs chef at log level info by default. Debug is very verbose, but makes debugging chef recipes much easier. Just set the LOG_LEVEL environment variable to 'debug' (or other valid chef log level) and it will be passed through.
|
99
|
+
|
100
|
+
Local Overrides (experimental)
|
101
|
+
==============================
|
102
|
+
Soloist is an easy way to share configuration across workstations. If you want to have configuration in chef that you don't want to share with the rest of the project, you can create a soloistrc_local file in addition to the soloistrc file. This file will be processed after the soloistrc, and everything in it will be added to the run list. Be careful that you are clear what goes where - if it's a dependency of the project, it should be checked into the soloistrc file in the project.
|
103
|
+
|
104
|
+
License
|
105
|
+
=======
|
106
|
+
Soloist is MIT Licensed. See MIT-LICENSE for details.
|
data/Rakefile
ADDED
data/bin/soloist
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'soloist')
|
3
|
+
require 'etc'
|
4
|
+
|
5
|
+
include Soloist::Util
|
6
|
+
|
7
|
+
log_level = ENV['LOG_LEVEL'] || "info"
|
8
|
+
|
9
|
+
soloistrc_contents, soloistrc_path = walk_up_and_find_file(with_or_without_dot("soloistrc"))
|
10
|
+
config_generator = Soloist::ChefConfigGenerator.new(YAML.load(soloistrc_contents), soloistrc_path)
|
11
|
+
|
12
|
+
soloistrc_contents, soloistrc_path = walk_up_and_find_file(with_or_without_dot("soloistrc_local"), :required => false)
|
13
|
+
config_generator.merge_config(YAML.load(soloistrc_contents), soloistrc_path) if soloistrc_contents
|
14
|
+
|
15
|
+
if ARGV.length >= 1
|
16
|
+
requested_recipe = ARGV[0]
|
17
|
+
raise "requested recipe '#{requested_recipe}' not in soloistrc or soloistrc_local" unless config_generator.recipes.include?(requested_recipe)
|
18
|
+
config_generator.recipes = [requested_recipe]
|
19
|
+
end
|
20
|
+
|
21
|
+
solo_rb = fileify(config_generator.solo_rb)
|
22
|
+
metadata_json = fileify(config_generator.json_file)
|
23
|
+
|
24
|
+
command = "bash -c '#{config_generator.preserved_environment_variables_string} chef-solo -j #{metadata_json.path} -c #{solo_rb.path} -l #{log_level}'"
|
25
|
+
|
26
|
+
if Etc.getlogin != "root"
|
27
|
+
command = 'sudo ' + command
|
28
|
+
end
|
29
|
+
|
30
|
+
puts "running chef: " + command
|
31
|
+
system(command) || exit(1)
|
data/lib/soloist.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Soloist
|
4
|
+
class Soloist::ChefConfigGenerator
|
5
|
+
include Soloist::Util
|
6
|
+
|
7
|
+
def initialize(config, relative_path_to_soloistrc)
|
8
|
+
@recipes = []
|
9
|
+
@cookbook_paths = []
|
10
|
+
@cookbook_gems = []
|
11
|
+
@preserved_environment_variables = %w{PATH BUNDLE_PATH GEM_HOME GEM_PATH RAILS_ENV RACK_ENV}
|
12
|
+
merge_config(config, relative_path_to_soloistrc)
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :preserved_environment_variables, :cookbook_paths, :cookbook_gems
|
16
|
+
attr_accessor :recipes
|
17
|
+
|
18
|
+
def support_old_format(hash)
|
19
|
+
hash['recipes'] ||= hash.delete('Recipes')
|
20
|
+
hash['cookbook_paths'] ||= hash.delete('Cookbook_Paths')
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def append_path(paths, relative_path_to_soloistrc)
|
25
|
+
paths.map do |path|
|
26
|
+
path.slice(0,1) == '/' ? path : "#{FileUtils.pwd}/#{relative_path_to_soloistrc}/#{path}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def merge_config(sub_hash, relative_path_to_soloistrc)
|
31
|
+
sub_hash = support_old_format(sub_hash)
|
32
|
+
if sub_hash["recipes"]
|
33
|
+
@recipes = (@recipes + sub_hash["recipes"]).uniq
|
34
|
+
end
|
35
|
+
if sub_hash["cookbook_paths"]
|
36
|
+
@cookbook_paths = (@cookbook_paths + append_path(sub_hash["cookbook_paths"], relative_path_to_soloistrc)).uniq
|
37
|
+
end
|
38
|
+
if sub_hash["cookbook_gems"]
|
39
|
+
(@cookbook_gems += sub_hash["cookbook_gems"]).uniq!
|
40
|
+
end
|
41
|
+
if sub_hash["env_variable_switches"]
|
42
|
+
merge_env_variable_switches(sub_hash["env_variable_switches"], relative_path_to_soloistrc)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def merge_env_variable_switches(hash_to_merge, relative_path_to_soloistrc)
|
47
|
+
hash_to_merge.keys.each do |variable|
|
48
|
+
@preserved_environment_variables << variable
|
49
|
+
ENV[variable] && ENV[variable].split(',').each do |env_variable_value|
|
50
|
+
sub_hash = hash_to_merge[variable] && hash_to_merge[variable][env_variable_value]
|
51
|
+
merge_config(sub_hash, relative_path_to_soloistrc) if sub_hash
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def solo_rb
|
57
|
+
all_cookbook_paths = cookbook_paths
|
58
|
+
cookbook_gems.each do |gem_cookbook|
|
59
|
+
require gem_cookbook
|
60
|
+
all_cookbook_paths << Kernel.const_get(camelize(gem_cookbook)).const_get('COOKBOOK_PATH')
|
61
|
+
end
|
62
|
+
"cookbook_path #{all_cookbook_paths.inspect}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def json_hash
|
66
|
+
{
|
67
|
+
"recipes" => @recipes
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def json_file
|
72
|
+
json_hash.to_json
|
73
|
+
end
|
74
|
+
|
75
|
+
def preserved_environment_variables_string
|
76
|
+
variable_array = []
|
77
|
+
preserved_environment_variables.map do |env_variable|
|
78
|
+
"#{env_variable}=#{ENV[env_variable]}" unless ENV[env_variable].nil?
|
79
|
+
end.compact.join(" ")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/soloist/util.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Soloist
|
2
|
+
module Util
|
3
|
+
def with_or_without_dot(file_name)
|
4
|
+
[file_name, ".#{file_name}"]
|
5
|
+
end
|
6
|
+
|
7
|
+
def fileify(contents)
|
8
|
+
file = Tempfile.new("soloist")
|
9
|
+
file << contents
|
10
|
+
file.flush
|
11
|
+
file
|
12
|
+
end
|
13
|
+
|
14
|
+
def walk_up_and_find_file(filenames, opts={})
|
15
|
+
pwd = FileUtils.pwd
|
16
|
+
file = nil
|
17
|
+
path_to_file = ""
|
18
|
+
while !file && FileUtils.pwd != '/'
|
19
|
+
file = filenames.detect { |f| File.exists?(f) }
|
20
|
+
FileUtils.cd("..")
|
21
|
+
path_to_file << "../" unless file
|
22
|
+
end
|
23
|
+
FileUtils.cd(pwd)
|
24
|
+
if file
|
25
|
+
file_contents = File.read(path_to_file + file) if file
|
26
|
+
[file_contents, path_to_file]
|
27
|
+
elsif opts[:required] == false
|
28
|
+
[nil, nil]
|
29
|
+
else
|
30
|
+
raise Errno::ENOENT, "#{filenames.join(" or ")} not found" unless file || opts[:required] == false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# stolen from activesupport
|
35
|
+
def camelize(term)
|
36
|
+
string = term.to_s
|
37
|
+
string = string.sub(/^[a-z\d]*/) { $&.capitalize }
|
38
|
+
string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/soloist.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "soloist/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ahamid-soloist"
|
7
|
+
s.version = Soloist::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Matthew Kocher"]
|
10
|
+
s.email = ["kocher@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/ahamid/soloist"
|
12
|
+
s.summary = %q{Soloist is a simple way of running chef-solo}
|
13
|
+
s.description = %q{Soloist is an easy way of running chef solo, but it's not doing much.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "soloist"
|
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
|
+
|
22
|
+
s.add_dependency "chef"
|
23
|
+
s.add_dependency "json", ">= 1.4.4", "<= 1.5.2"
|
24
|
+
end
|
@@ -0,0 +1,242 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'lib/soloist'
|
3
|
+
|
4
|
+
describe Soloist::ChefConfigGenerator do
|
5
|
+
describe "generation" do
|
6
|
+
before do
|
7
|
+
@config = <<-CONFIG
|
8
|
+
Cookbook_Paths:
|
9
|
+
- ./chef/cookbooks/
|
10
|
+
cookbook_gems:
|
11
|
+
- pivotal_workstation_cookbook
|
12
|
+
Recipes:
|
13
|
+
- pivotal_workstation::ack
|
14
|
+
CONFIG
|
15
|
+
@config = YAML.load(@config)
|
16
|
+
FileUtils.stub(:pwd).and_return("/current/working/directory")
|
17
|
+
@generator = Soloist::ChefConfigGenerator.new(@config, "../..")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "appends the current path and relative path to the cookbooks directory" do
|
21
|
+
@generator.cookbook_paths.should == ["/current/working/directory/../.././chef/cookbooks/"]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "does not append if an absolute path is given" do
|
25
|
+
@config['cookbook_paths'] = ["/foo/bar"]
|
26
|
+
@generator = Soloist::ChefConfigGenerator.new(@config, "../..")
|
27
|
+
@generator.cookbook_paths.should == ["/foo/bar"]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can generate a solo.rb contents" do
|
31
|
+
module ::PivotalWorkstationCookbook
|
32
|
+
COOKBOOK_PATH = "/var/lib/ruby/gems/pivotal_workstation/cookbooks/"
|
33
|
+
end
|
34
|
+
@generator.solo_rb.should == 'cookbook_path ["/current/working/directory/../.././chef/cookbooks/", "/var/lib/ruby/gems/pivotal_workstation/cookbooks/"]'
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can generate the json contents" do
|
38
|
+
@generator.json_hash.should == {
|
39
|
+
"recipes" => ['pivotal_workstation::ack']
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can generate json files" do
|
44
|
+
JSON.parse(@generator.json_file).should == {
|
45
|
+
"recipes" => ['pivotal_workstation::ack']
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "passing env variables to chef-solo through sudo" do
|
50
|
+
it "has a list of env variables which are passed through" do
|
51
|
+
@generator.preserved_environment_variables.should == %w{PATH BUNDLE_PATH GEM_HOME GEM_PATH RAILS_ENV RACK_ENV}
|
52
|
+
end
|
53
|
+
|
54
|
+
it "can generate an env_variable_string which is passed through sudo to chef-solo" do
|
55
|
+
ENV["FOO"]="BAR"
|
56
|
+
ENV["FAZ"]="FUZ"
|
57
|
+
@generator.stub!(:preserved_environment_variables).and_return(["FOO", "FAZ"])
|
58
|
+
@generator.preserved_environment_variables_string.should == "FOO=BAR FAZ=FUZ"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "adds any environment variables that are switched in the config" do
|
62
|
+
@config = <<-CONFIG
|
63
|
+
cookbook_paths:
|
64
|
+
- ./chef/cookbooks/
|
65
|
+
recipes:
|
66
|
+
- pivotal_workstation::ack
|
67
|
+
env_variable_switches:
|
68
|
+
ME_TOO:
|
69
|
+
development:
|
70
|
+
cookbook_paths:
|
71
|
+
- ./chef/dev_cookbooks/
|
72
|
+
recipes:
|
73
|
+
- pivotal_dev::foo
|
74
|
+
CONFIG
|
75
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "")
|
76
|
+
@generator.preserved_environment_variables.should =~ %w{PATH BUNDLE_PATH GEM_HOME GEM_PATH RAILS_ENV RACK_ENV ME_TOO}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "yaml config values" do
|
82
|
+
before do
|
83
|
+
FileUtils.stub(:pwd).and_return("/")
|
84
|
+
end
|
85
|
+
|
86
|
+
it "accepts Cookbook_Paths, because the CamelSnake is a typo that must be supported" do
|
87
|
+
@config = "Cookbook_Paths:\n- ./chef/cookbooks/\n"
|
88
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "..")
|
89
|
+
@generator.cookbook_paths.should == ["//.././chef/cookbooks/"]
|
90
|
+
end
|
91
|
+
|
92
|
+
it "accepts cookbook_paths, because it is sane" do
|
93
|
+
@config = "cookbook_paths:\n- ./chef/cookbooks/\n"
|
94
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "..")
|
95
|
+
@generator.cookbook_paths.should == ["//.././chef/cookbooks/"]
|
96
|
+
end
|
97
|
+
|
98
|
+
it "accepts Recipes, because that's the way it was" do
|
99
|
+
@config = "Recipes:\n- pivotal_workstation::ack"
|
100
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "")
|
101
|
+
@generator.json_hash.should == { "recipes" => ["pivotal_workstation::ack"]}
|
102
|
+
end
|
103
|
+
|
104
|
+
it "accepts recipes, because it's snake now" do
|
105
|
+
@config = "recipes:\n- pivotal_workstation::ack"
|
106
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "")
|
107
|
+
@generator.json_hash.should == { "recipes" => ["pivotal_workstation::ack"]}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "environment variable merging" do
|
112
|
+
before do
|
113
|
+
FileUtils.stub(:pwd).and_return("/")
|
114
|
+
end
|
115
|
+
|
116
|
+
it "merges in if the variable is set to the the value" do
|
117
|
+
@config = <<-CONFIG
|
118
|
+
cookbook_paths:
|
119
|
+
- ./chef/cookbooks/
|
120
|
+
recipes:
|
121
|
+
- pivotal_workstation::ack
|
122
|
+
env_variable_switches:
|
123
|
+
RACK_ENV:
|
124
|
+
development:
|
125
|
+
cookbook_paths:
|
126
|
+
- ./chef/dev_cookbooks/
|
127
|
+
recipes:
|
128
|
+
- pivotal_dev::foo
|
129
|
+
CONFIG
|
130
|
+
ENV["RACK_ENV"]="development"
|
131
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "../..")
|
132
|
+
@generator.cookbook_paths.should == [
|
133
|
+
"//../.././chef/cookbooks/",
|
134
|
+
"//../.././chef/dev_cookbooks/"
|
135
|
+
]
|
136
|
+
@generator.json_hash["recipes"].should == [
|
137
|
+
"pivotal_workstation::ack",
|
138
|
+
"pivotal_dev::foo"
|
139
|
+
]
|
140
|
+
end
|
141
|
+
|
142
|
+
it "merges cookbook_gems" do
|
143
|
+
@config = <<-CONFIG
|
144
|
+
cookbook_gems:
|
145
|
+
- pivotal_shared
|
146
|
+
env_variable_switches:
|
147
|
+
RACK_ENV:
|
148
|
+
development:
|
149
|
+
cookbook_gems:
|
150
|
+
- pivotal_shared
|
151
|
+
- pivotal_workstation
|
152
|
+
CONFIG
|
153
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "../..")
|
154
|
+
@generator.cookbook_gems.should =~ [
|
155
|
+
"pivotal_shared",
|
156
|
+
"pivotal_workstation"
|
157
|
+
]
|
158
|
+
end
|
159
|
+
|
160
|
+
it "splits the value on comma and applies all matching" do
|
161
|
+
ENV["ROLES"]="application,database"
|
162
|
+
@config = <<-CONFIG
|
163
|
+
cookbook_paths:
|
164
|
+
- ./chef/cookbooks/
|
165
|
+
recipes:
|
166
|
+
- pivotal_workstation::ack
|
167
|
+
env_variable_switches:
|
168
|
+
ROLES:
|
169
|
+
application:
|
170
|
+
cookbook_paths:
|
171
|
+
- ./chef/app_cookbooks/
|
172
|
+
recipes:
|
173
|
+
- pivotal_app::application
|
174
|
+
database:
|
175
|
+
cookbook_paths:
|
176
|
+
- ./chef/db_cookbooks/
|
177
|
+
recipes:
|
178
|
+
- pivotal_db::database
|
179
|
+
CONFIG
|
180
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(@config), "../..")
|
181
|
+
@generator.cookbook_paths.should =~ [
|
182
|
+
"//../.././chef/cookbooks/",
|
183
|
+
"//../.././chef/app_cookbooks/",
|
184
|
+
"//../.././chef/db_cookbooks/"
|
185
|
+
]
|
186
|
+
@generator.json_hash["recipes"].should =~ [
|
187
|
+
"pivotal_workstation::ack",
|
188
|
+
"pivotal_app::application",
|
189
|
+
"pivotal_db::database",
|
190
|
+
]
|
191
|
+
end
|
192
|
+
|
193
|
+
it "can deal with empty env switched variables, and passes them through" do
|
194
|
+
config = <<-CONFIG
|
195
|
+
env_variable_switches:
|
196
|
+
RACK_ENV:
|
197
|
+
CONFIG
|
198
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(config), "../..")
|
199
|
+
@generator.preserved_environment_variables.should include("RACK_ENV")
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
it "can deal with only having environment switched recipes/cookbooks" do
|
204
|
+
config = <<-CONFIG
|
205
|
+
env_variable_switches:
|
206
|
+
RACK_ENV:
|
207
|
+
development:
|
208
|
+
cookbook_paths:
|
209
|
+
- ./chef/development_cookbooks/
|
210
|
+
recipes:
|
211
|
+
- pivotal_development::foo
|
212
|
+
CONFIG
|
213
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(config), "../..")
|
214
|
+
@generator.cookbook_paths.should == [
|
215
|
+
"//../.././chef/development_cookbooks/"
|
216
|
+
]
|
217
|
+
@generator.json_hash["recipes"].should == [
|
218
|
+
"pivotal_development::foo"
|
219
|
+
]
|
220
|
+
end
|
221
|
+
it "can deal with only having empty recipes/cookbooks" do
|
222
|
+
config = <<-CONFIG
|
223
|
+
cookbook_paths:
|
224
|
+
recipes:
|
225
|
+
env_variable_switches:
|
226
|
+
RACK_ENV:
|
227
|
+
development:
|
228
|
+
cookbook_paths:
|
229
|
+
- ./chef/development_cookbooks/
|
230
|
+
recipes:
|
231
|
+
- pivotal_development::foo
|
232
|
+
CONFIG
|
233
|
+
@generator = Soloist::ChefConfigGenerator.new(YAML.load(config), "../..")
|
234
|
+
@generator.cookbook_paths.should == [
|
235
|
+
"//../.././chef/development_cookbooks/"
|
236
|
+
]
|
237
|
+
@generator.json_hash["recipes"].should == [
|
238
|
+
"pivotal_development::foo"
|
239
|
+
]
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# this file is loaded by the tests instead of the actual pivotal_workstation_cookbook
|
data/spec/util_spec.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'lib/soloist'
|
3
|
+
|
4
|
+
describe Soloist::Util do
|
5
|
+
class TestClass
|
6
|
+
extend Soloist::Util
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "walk_up_and_find_file" do
|
10
|
+
it "raises an error when the file isn't found" do
|
11
|
+
lambda do
|
12
|
+
TestClass.walk_up_and_find_file(["file_not_on_the_filesystem"])
|
13
|
+
end.should raise_error(Errno::ENOENT, "No such file or directory - file_not_on_the_filesystem not found")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "doesn't raise an error if :required => false is passed" do
|
17
|
+
TestClass.walk_up_and_find_file(["file_not_on_the_filesystem"], :required => false).should == [nil, nil]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ahamid-soloist
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.9.3
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Matthew Kocher
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-07-31 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: chef
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: json
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.4.4
|
35
|
+
- - <=
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.5.2
|
38
|
+
type: :runtime
|
39
|
+
version_requirements: *id002
|
40
|
+
description: Soloist is an easy way of running chef solo, but it's not doing much.
|
41
|
+
email:
|
42
|
+
- kocher@gmail.com
|
43
|
+
executables:
|
44
|
+
- soloist
|
45
|
+
extensions: []
|
46
|
+
|
47
|
+
extra_rdoc_files: []
|
48
|
+
|
49
|
+
files:
|
50
|
+
- .gitignore
|
51
|
+
- .rvmrc
|
52
|
+
- Gemfile
|
53
|
+
- Gemfile.lock
|
54
|
+
- MIT-LICENSE
|
55
|
+
- README.markdown
|
56
|
+
- Rakefile
|
57
|
+
- bin/soloist
|
58
|
+
- lib/soloist.rb
|
59
|
+
- lib/soloist/chef_config_generator.rb
|
60
|
+
- lib/soloist/util.rb
|
61
|
+
- lib/soloist/version.rb
|
62
|
+
- soloist.gemspec
|
63
|
+
- spec/chef_config_generator_spec.rb
|
64
|
+
- spec/pivotal_workstation_cookbook.rb
|
65
|
+
- spec/util_spec.rb
|
66
|
+
homepage: http://github.com/ahamid/soloist
|
67
|
+
licenses: []
|
68
|
+
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: "0"
|
86
|
+
requirements: []
|
87
|
+
|
88
|
+
rubyforge_project: soloist
|
89
|
+
rubygems_version: 1.8.4
|
90
|
+
signing_key:
|
91
|
+
specification_version: 3
|
92
|
+
summary: Soloist is a simple way of running chef-solo
|
93
|
+
test_files:
|
94
|
+
- spec/chef_config_generator_spec.rb
|
95
|
+
- spec/pivotal_workstation_cookbook.rb
|
96
|
+
- spec/util_spec.rb
|