masterbaker 0.7.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d5c68e02c977b9c560db370a7b8affae5fae2701
4
+ data.tar.gz: 2b531229a74c94510fb329f21d55e1020f520019
5
+ SHA512:
6
+ metadata.gz: 67ad3b16e650e2bd460bbf310aa8bec625e708c05ad8af4036463227a8fd6bc6cc103f361c49be2962a0cca06255bf93bfb087533fb38c7fb94567847892a30a
7
+ data.tar.gz: 059a748b3380cb2b7a8aa426660c0a3cb2e964e7719020c98950de6cf3f0f9eaa0053fa29c343971476b2d016a576792f29ba807fd108e0b2225146230bc242d
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ /.vagrant
5
+ /examples/cookbooks
6
+ /examples/tmp
7
+ tmp/
8
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,44 @@
1
+ # Copyright (c) 2014 Mike Mackintosh
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.
21
+ #
22
+ #
23
+ # ORIGINAL LICENSE
24
+ #
25
+ # Copyright (c) 2012 Matthew Kocher and Doc Ritezel
26
+ #
27
+ # Permission is hereby granted, free of charge, to any person obtaining
28
+ # a copy of this software and associated documentation files (the
29
+ # "Software"), to deal in the Software without restriction, including
30
+ # without limitation the rights to use, copy, modify, merge, publish,
31
+ # distribute, sublicense, and/or sell copies of the Software, and to
32
+ # permit persons to whom the Software is furnished to do so, subject to
33
+ # the following conditions:
34
+ #
35
+ # The above copyright notice and this permission notice shall be
36
+ # included in all copies or substantial portions of the Software.
37
+ #
38
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
39
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
41
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
42
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
43
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
44
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # Bakist
2
+
3
+ Bakist spawned from the [Soloist](https://github.com/mkocher/soloist) project, and lets you quickly and easily converge [Chef](http://opscode.com/chef) recipes using [chef-solo](http://wiki.opscode.com/display/chef/Chef+Solo). It does not require a Chef server, but can exploit [community cookbooks](http://community.opscode.com/cookbooks), github-hosted cookbooks and locally-sourced cookbooks through [Librarian](https://github.com/applicationsonline/librarian).
4
+
5
+ Bakist was designed with users in mind, allowing a global runlist as well as user-specific.
6
+
7
+ Using Bakist
8
+ -------------
9
+
10
+ 1. You'll need to have Bakist installed:
11
+
12
+ $ gem install bakist
13
+
14
+ 2. You'll need a `Cheffile` in your home directory that points Librarian to all the cookbooks you've included:
15
+
16
+ $ cat ~/.bakery/Cheffile // or ~/.bakist/bakistrc
17
+ site "http://community.opscode.com/api/v1"
18
+ cookbook "pivotal_workstation",
19
+ :git => "https://github.com/pivotal/pivotal_workstation"
20
+
21
+ 3. You'll need to create a `~/.bakery/bakeryrc` or `~/.bakist/bakistrc` file in your home directory to tell Chef which recipes to converge:
22
+
23
+ $ cat /Users/pivotal/.bakery/bakeryrc
24
+ recipes:
25
+ - pivotal_workstation::default
26
+ - pivotal_workstation::sublime_text
27
+
28
+ 4. It's always a good idea to see what is found and will be installed on next run using `config`:
29
+
30
+ $ bake config
31
+
32
+
33
+ 4. You'll need to run `bakist` for anything to happen:
34
+
35
+ $ bake
36
+
37
+
38
+ Examples
39
+ --------
40
+
41
+ ##### Running a set of recipes
42
+
43
+ Here's an example of a `~/.bakery/bakeryrc` or `~/.bakist/bakistrc`:
44
+
45
+ cookbook_paths:
46
+ - /opt/beans
47
+ recipes:
48
+ - beans::chili
49
+ - beans::food_fight
50
+ - napkins
51
+
52
+ This tells Bakist to search in both `/opt/beans` and `./cookbooks` (relative to the `~/.bakery` or `~/.bakist` directories) for cookbooks to run. Then, it attempts to converge the `beans::chili`, `beans::food_fight` and `napkins` recipes.
53
+
54
+
55
+ ##### Setting node attributes
56
+
57
+ Bakist lets you override node attributes. Let's say we've got a `bash::prompt` recipe for which we want to set `node['bash']['prompt']['color']='p!nk'`. No problem!
58
+
59
+ recipes:
60
+ - bash::prompt
61
+ node_attributes:
62
+ bash:
63
+ prompt:
64
+ color: p!nk
65
+
66
+
67
+ ##### Conditionally modifying Bakist
68
+
69
+ Bakist allows conditionally switching on environment variables. Let's say we only want to include the `embarrassment::parental` recipe when the `MEGA_PRODUCTION` environment variable is set to `juggalos`. Here's the `~/.bakery/bakeryrc` or `~/.bakist/bakistrc`:
70
+
71
+ cookbook_paths:
72
+ - /fresno
73
+ recipes:
74
+ - disaster
75
+ env_variable_switches:
76
+ MEGA_PRODUCTION:
77
+ juggalos:
78
+ recipes:
79
+ - embarrassment::parental
80
+
81
+ So now, this is the result of our Bakist run:
82
+
83
+ $ MEGA_PRODUCTION=juggalos bake
84
+ Installing disaster (1.0.0)
85
+ Installing embarrassment (1.0.0)
86
+ … chef output …
87
+ INFO: Run List expands to [disaster, embarrassment::parental, faygo]
88
+ … chef output …
89
+
90
+ If we set `MEGA_PRODUCTION=godspeed`, the `embarrassment::parental` recipe is not converged.
91
+
92
+
93
+ ##### Running one-off recipes
94
+
95
+ Bakist can also run one-off recipes:
96
+
97
+ $ bake run_recipe lice::box
98
+ Installing lice (1.0.0)
99
+ … chef output …
100
+ INFO: Run List expands to [lice::box]
101
+ … chef output …
102
+
103
+ This just runs the `lice::box` recipe from your current set of cookbooks. It still uses all the `node_attributes` and `env_variable_switches` logic.
104
+
105
+
106
+ ##### Chef logging
107
+
108
+ Bakist runs `chef-solo` at log level `info` by default, which is helpful when you need to see what your Chef run is doing. If you need more information, you can set the `LOG_LEVEL` environment variable:
109
+
110
+ $ LOG_LEVEL=debug bake
111
+
112
+ The default log level is `FATAL` to prevent undesireable output.
113
+
114
+
115
+ License
116
+ =======
117
+
118
+ See LICENSE for details.
data/bin/bake ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ $:.push File.expand_path("../../lib", __FILE__)
3
+ require "masterbaker"
4
+ Masterbaker::CLI.start
@@ -0,0 +1,2 @@
1
+ require "masterbaker/version"
2
+ require "masterbaker/cli"
@@ -0,0 +1,178 @@
1
+ require "librarian/chef/cli"
2
+ require "masterbaker/remote_config"
3
+ require "awesome_print"
4
+ require "thor"
5
+
6
+ class Thor::Shell::Color
7
+ def say(string, color=:WHITE, nl=true, prefix=true)
8
+
9
+ if prefix
10
+ #super '★', :green, false
11
+ super ' Masterbaker ', :white, false
12
+ #super '★', :green, false
13
+ super ':: ', :white, false
14
+ end
15
+
16
+ super(string, color, nl)
17
+ end
18
+ end
19
+
20
+ module Masterbaker
21
+
22
+ class CLI < Thor
23
+ attr_writer :masterbaker_config
24
+ default_task :chef
25
+
26
+
27
+ desc "chef", "Run chef-solo"
28
+ method_option :remote, :aliases => "-r", :desc => "Run chef-solo on user@host"
29
+ method_option :identity, :aliases => "-i", :desc => "The SSH identity file"
30
+ def chef
31
+ #begin
32
+ say 'Masterbaker is Fetching Cookbooks', :green, true, false
33
+ install_cookbooks if cheffile_exists?
34
+ say 'Masterbaker is Preparing to Bake', :green, true, false
35
+ masterbaker_config.run_chef
36
+ #rescue Exception => msg
37
+ # say msg.backtrace.inspect
38
+ # say ' Your Bakery files were not found. Please make sure ', :RED, false
39
+ # say '~/.bakery/', :YELLOW, false, false
40
+ # say ' exists', :RED, true, false
41
+ # say '', nil, nil, false
42
+ #end
43
+ end
44
+
45
+ desc "run_recipe [cookbook::recipe, ...]", "Run individual recipes"
46
+ method_option :remote, :aliases => "-r", :desc => "Run recipes on user@host"
47
+ method_option :identity, :aliases => "-i", :desc => "The SSH identity file"
48
+ def run_recipe(*recipes)
49
+ masterbaker_config.royal_crown.recipes = recipes
50
+ chef
51
+ end
52
+
53
+ desc "config", "Dumps configuration data for Masterbaker"
54
+ def config
55
+ Kernel.ap(masterbaker_config.as_node_json)
56
+ end
57
+
58
+ no_tasks do
59
+ def install_cookbooks
60
+
61
+ Dir.chdir(File.dirname(config_path)) do
62
+ Librarian::Chef::Cli.with_environment do
63
+ Librarian::Chef::Cli.new.install
64
+ end
65
+ end
66
+
67
+ if user_config_path
68
+ say 'Masterbaker is Fetching User-Specific Cookbooks', :green, true, false
69
+ begin
70
+ Dir.chdir(File.dirname(user_config_path)) do
71
+ Librarian::Chef::Cli.with_environment do
72
+ libchef = Librarian::Chef::Cli.new.install
73
+ end
74
+ end
75
+ rescue
76
+ say 'Error getting user-specific cookbooks, scratching.', :red
77
+ abort
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ def masterbaker_config
84
+ @masterbaker_config ||= if options[:remote]
85
+ Masterbaker::RemoteConfig.from_file(config_path, remote)
86
+ else
87
+ Masterbaker::Config.from_file(config_path)
88
+ end.tap do |config|
89
+ config.merge!(user_config) if user_config_path
90
+ config.merge!(shop_config) if shop_config_path
91
+ #config.merge!(shop_managed_user_config) if shop_managed_user_config_path
92
+ end
93
+ end
94
+ end
95
+
96
+ private
97
+ def shop_config
98
+ Masterbaker::Config.from_file(shop_config_path)
99
+ end
100
+
101
+ def user_config
102
+ Masterbaker::Config.from_file(user_config_path)
103
+ end
104
+
105
+ def shop_managed_user_config
106
+ Masterbaker::Config.from_file(shop_managed_user_config_path)
107
+ end
108
+
109
+ def remote
110
+ @remote ||= if options[:identity]
111
+ Masterbaker::Remote.from_uri(options[:remote], options[:identity])
112
+ else
113
+ Masterbaker::Remote.from_uri(options[:remote])
114
+ end
115
+ end
116
+
117
+ def cheffile_exists?
118
+ File.exists?(File.expand_path("~/.bakery/Cheffile"))
119
+ end
120
+
121
+ def config_path
122
+ @config_path ||= File.expand_path("~/.bakery/bakeryrc")
123
+ end
124
+
125
+ # TODO: Fix librarian cookbook path defaults
126
+ def shop_managed_user_config_path
127
+ # current_user = ENV['SUDO_USER'] ||= ENV['USER']
128
+ # shop_managed_user_config_path = File.expand_path("~/.bakery/bakers/#{current_user}/bakeryrc")
129
+ # if File.exists?(shop_managed_user_config_path)
130
+ # @shop_managed_user_config_path ||= shop_managed_user_config_path
131
+ # end
132
+ end
133
+
134
+ def user_config_path
135
+ user_config_path = File.expand_path("~/.masterbaker/masterbakerrc")
136
+ if File.exists?(user_config_path)
137
+ @user_config_path ||= user_config_path
138
+ end
139
+ end
140
+
141
+ def shop_config_path
142
+ shop_config_path = File.expand_path("~/.bakery/shoprc")
143
+ if File.exists?(shop_config_path)
144
+ @shop_config_path ||= shop_config_path
145
+ end
146
+ end
147
+
148
+ def logo
149
+ say ' ', :green, true, false
150
+ say ' kkkkk ', :green, true, false
151
+ say ' kbbbaaaaaaaabk kkkkk ', :green, true, false
152
+ say ' kaabkbaaabkbaaaak baaaak ', :green, true, false
153
+ say ' kaaak kaaaab kaabb kaaaab ', :green, true, false
154
+ say ' kbaab kbaaaak kbaab kkbbbkkbbbb baaaak kbbk kkbbbbk kbbbkkkkbbk kbbbk kbbbbk ', :green, true, false
155
+ say ' kabab kaaaaabaaaab kaaaaaaaaaaab kaaaaa kbaabk baaabbaaakkbaaaaaaaaaabaaaak kbaaabk ', :green, true, false
156
+ say ' k kbbkkbaaaabaaaaaaak baaaak kbaaaak baaaabbaabk kbaaab kbaakkaaaabkbaabbaaaaa baaaab k ', :green, true, false
157
+ say ' kbaabk kaaaab kbaaaaakbaaaak kaaaaak kbaaaaaaaaaaak kbaaaakkbaakkbaaaak kkkbaaaak kbaaaak kbaabk ', :green, true, false
158
+ say ' kaaab baaaak kbaaaakaaaab baaaab kaaaabkbaaaaab baaaaababk kaaaab kaaaaa kaaaab baaak ', :green, true, false
159
+ say ' k kk kaaaab kaaaabbaaaak kaaaaa kbaaaak baaaak kaaaaakkk kbaaaak kaaaak baaaak kk k ', :green, true, false
160
+ say ' baaaabbkkkbaaabkaaaaaakbbaaaabkkbaaaab kaaaaabkbaaaaabkkkkbbaaaab baaaabbbaaaab ', :green, true, false
161
+ say ' kbaaaabaaaaaabk baaaaaaabaaaaaaaaaaaak kaaaaaaabaaaaaaaaabkbaaaak baaaaaabaaaak ', :green, true, false
162
+ say ' kbbbbkkbbaabk kbbbbk kbbbbkkbbbbk kbbbbbk kbbbbbkk bbbbk kbbbkkaaaaa ', :green, true, false
163
+ say ' kkkkkkbbbbbbbbbbbbbbbkkkkkkkk kbaaaak ', :green, true, false
164
+ say ' kkbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbkkk kkkbaaaabk ', :green, true, false
165
+ say ' kbbaabbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbaaaaaaaabk ', :green, true, false
166
+ say ' kkbaabbbbbaaaaaaaaaaaaaaaaaaaabbbbbbbbkkkkkbbbbbbbbbbaaaaaaaaaaaaaaaaaaabkk ', :green, true, false
167
+ say ' kbaaaabbbaaaaaaaaaaaaaaabbkkkk kkkbbbbbbbbbkkk ', :green, true, false
168
+ say ' kbbbbbaaaaaaaaaaaaaabbkk ', :green, true, false
169
+ say ' kkbbaaaaaabbkk ', :green, true, false
170
+ say ' kbaabk ', :green, true, false
171
+ say ' kk ', :green, true, false
172
+ say ' ', :green, true, false
173
+ say 'Preparing... ', :white, true
174
+ say ' ', :green, true, false
175
+ end
176
+
177
+ end
178
+ end
@@ -0,0 +1,113 @@
1
+ require "masterbaker/royal_crown"
2
+ require "tempfile"
3
+
4
+ module Masterbaker
5
+ class Config
6
+ attr_writer :solo_rb_path, :node_json_path
7
+ attr_reader :royal_crown
8
+
9
+ def self.from_file(royal_crown_path)
10
+ rc = Masterbaker::RoyalCrown.from_file(royal_crown_path)
11
+ new(rc)
12
+ end
13
+
14
+ def initialize(royal_crown)
15
+ @royal_crown = royal_crown
16
+ end
17
+
18
+ def run_chef
19
+ exec(conditional_sudo("bash -c '#{chef_solo}'"))
20
+ end
21
+
22
+ def chef_solo
23
+ "chef-solo -c '#{solo_rb_path}' -l '#{log_level}'"
24
+ end
25
+
26
+ def as_solo_rb
27
+ <<-SOLO_RB
28
+ file_cache_path "#{chef_cache_path}"
29
+ cookbook_path #{cookbook_paths.inspect}
30
+ json_attribs "#{node_json_path}"
31
+ SOLO_RB
32
+ end
33
+
34
+ def as_node_json
35
+ compiled.node_attributes.to_hash.merge({ "recipes" => compiled.recipes })
36
+ end
37
+
38
+ def chef_cache_path
39
+ "/var/chef/cache".tap do |cache_path|
40
+ system(conditional_sudo("mkdir -p #{cache_path}")) \
41
+ unless File.directory?(cache_path)
42
+ end
43
+ end
44
+
45
+ def cookbook_paths
46
+ ([royal_crown_cookbooks_directory] + compiled.cookbook_paths).map do |path|
47
+ File.expand_path(path, royal_crown_path)
48
+ end.uniq.select do |path|
49
+ File.directory?(path)
50
+ end
51
+ end
52
+
53
+ def solo_rb_path
54
+ @solo_rb_path ||= Tempfile.new(["solo", ".rb"]).tap do |file|
55
+ puts as_solo_rb if debug?
56
+ file.write(as_solo_rb)
57
+ file.close
58
+ end.path
59
+ end
60
+
61
+ def node_json_path
62
+ @node_json_path ||= Tempfile.new(["node", ".json"]).tap do |file|
63
+ puts JSON.pretty_generate(as_node_json) if debug?
64
+ file.write(JSON.dump(as_node_json))
65
+ file.close
66
+ end.path
67
+ end
68
+
69
+ def merge!(other)
70
+ royal_crown.recipes += other.royal_crown.recipes
71
+ royal_crown.cookbook_paths += other.royal_crown.cookbook_paths
72
+ royal_crown.node_attributes.merge!(other.royal_crown.node_attributes)
73
+ royal_crown.env_variable_switches.merge!(other.royal_crown.env_variable_switches)
74
+ end
75
+
76
+ def compiled
77
+ @compiled ||= royal_crown.dup.tap do |working_royal_crown|
78
+ while working_royal_crown["env_variable_switches"]
79
+ working_royal_crown.delete("env_variable_switches").each do |variable, switch|
80
+ switch.each do |value, inner|
81
+ working_royal_crown.merge!(inner) if ENV[variable] == value
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def log_level
89
+ ENV["LOG_LEVEL"] || "fatal"
90
+ end
91
+
92
+ def debug?
93
+ log_level == "debug"
94
+ end
95
+
96
+ private
97
+ def conditional_sudo(command)
98
+ root? ? command : "sudo -E #{command}"
99
+ end
100
+
101
+ def root?
102
+ Process.uid == 0
103
+ end
104
+
105
+ def royal_crown_cookbooks_directory
106
+ File.expand_path("cookbooks", royal_crown_path)
107
+ end
108
+
109
+ def royal_crown_path
110
+ File.dirname(royal_crown.path)
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,66 @@
1
+ require "net/ssh"
2
+ require "shellwords"
3
+ require "etc"
4
+
5
+ module Masterbaker
6
+ class RemoteError < RuntimeError; end
7
+
8
+ class Remote
9
+ attr_reader :user, :host, :key, :timeout, :stdout, :stderr, :exitstatus
10
+ attr_writer :connection
11
+
12
+ def self.from_uri(uri, key = "~/.ssh/id_rsa")
13
+ parsed = URI.parse("ssh://#{uri}")
14
+ new(parsed.user || Etc.getlogin, parsed.host, key)
15
+ end
16
+
17
+ def initialize(user, host, key, options = {})
18
+ @user = user
19
+ @host = host
20
+ @key = File.expand_path(key)
21
+ @timeout = options[:timeout] || 10000
22
+ end
23
+
24
+ def backtick(command)
25
+ @stdout = ""
26
+ @stderr = ""
27
+ exec(command)
28
+ @stdout
29
+ end
30
+
31
+ def system(command)
32
+ @stdout = STDOUT
33
+ @stderr = STDERR
34
+ exec(command)
35
+ exitstatus
36
+ end
37
+
38
+ def system!(*command)
39
+ system(*command).tap do |status|
40
+ raise RemoteError.new("#{command.join(" ")} exited #{status}") unless status == 0
41
+ end
42
+ end
43
+
44
+ def upload(from, to, opts = "--exclude .git")
45
+ Kernel.system("rsync -e 'ssh -i #{key}' -avz --delete #{from} #{user}@#{host}:#{to} #{opts}")
46
+ end
47
+
48
+ private
49
+ def connection
50
+ @connection ||= Net::SSH.start(host, user, :keys => [key], :timeout => timeout)
51
+ end
52
+
53
+ def exec(*command)
54
+ connection.open_channel do |channel|
55
+ channel.exec(*command) do |stream, success|
56
+ raise RemoteError.new("Could not run #{command.join(" ")}") unless success
57
+ stream.on_data { |_, data| stdout << data }
58
+ stream.on_extended_data { |_, type, data| stderr << data }
59
+ stream.on_request("exit-status") { |_, data| @exitstatus = data.read_long }
60
+ end
61
+ end
62
+ connection.loop
63
+ @exitstatus ||= 0
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,62 @@
1
+ require "masterbaker/config"
2
+ require "masterbaker/remote"
3
+
4
+ module Masterbaker
5
+ class RemoteConfig < Config
6
+ attr_reader :remote
7
+
8
+ def self.from_file(royal_crown_path, remote)
9
+ rc = Masterbaker::RoyalCrown.from_file(royal_crown_path)
10
+ new(rc, remote)
11
+ end
12
+
13
+ def initialize(royal_crown, remote)
14
+ @royal_crown = royal_crown
15
+ @remote = remote
16
+ end
17
+
18
+ def run_chef
19
+ remote.system!(conditional_sudo(%(/bin/bash -lc "#{chef_solo}")))
20
+ end
21
+
22
+ def node_json_path
23
+ @node_json_path ||= File.expand_path("node.json", chef_config_path).tap do |path|
24
+ remote.system!(%(echo '#{JSON.dump(as_node_json)}' | #{conditional_sudo("tee #{path}")}))
25
+ end
26
+ end
27
+
28
+ def solo_rb_path
29
+ @solo_rb_path ||= File.expand_path("solo.rb", chef_config_path).tap do |path|
30
+ remote.system!(%(echo '#{as_solo_rb}' | #{conditional_sudo("tee #{path}")}))
31
+ end
32
+ end
33
+
34
+ def chef_cache_path
35
+ @chef_cache_path ||= "/var/chef/cache".tap do |cache_path|
36
+ remote.system!(conditional_sudo("/bin/mkdir -m 777 -p #{cache_path}"))
37
+ end
38
+ end
39
+
40
+ def chef_config_path
41
+ @chef_config_path ||= "/etc/chef".tap do |path|
42
+ remote.system!(conditional_sudo("/bin/mkdir -m 777 -p #{path}"))
43
+ end
44
+ end
45
+
46
+ def cookbook_paths
47
+ @cookbook_paths ||= ["/var/chef/cookbooks".tap do |remote_path|
48
+ remote.system!(conditional_sudo("/bin/mkdir -m 777 -p #{remote_path}"))
49
+ super.each { |path| remote.upload("#{path}/", remote_path) }
50
+ end]
51
+ end
52
+
53
+ protected
54
+ def conditional_sudo(command)
55
+ root? ? command : "/usr/bin/sudo -E #{command}"
56
+ end
57
+
58
+ def root?
59
+ remote.user == "root"
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,79 @@
1
+ require "hashie"
2
+
3
+ module Masterbaker
4
+ class RoyalCrown < Hashie::Trash
5
+ property :path
6
+ property :recipes, :default => []
7
+ property :cookbook_paths, :default => []
8
+ property :node_attributes, :default => Hashie::Mash.new,
9
+ :transform_with => lambda { |v| Hashie::Mash.new(v) }
10
+ property :env_variable_switches, :default => Hashie::Mash.new,
11
+ :transform_with => lambda { |v| Hashie::Mash.new(v) }
12
+
13
+ def node_attributes=(hash)
14
+ self["node_attributes"] = Hashie::Mash.new(hash)
15
+ end
16
+
17
+ def merge!(other_royal_crown)
18
+ merge_recipes(other_royal_crown["recipes"])
19
+ merge_cookbook_paths(other_royal_crown["cookbook_paths"])
20
+ self.node_attributes.deep_merge!(other_royal_crown["node_attributes"])
21
+ self.env_variable_switches = other_royal_crown["env_variable_switches"]
22
+ self
23
+ end
24
+
25
+ def merge_recipes(new_recipes = [])
26
+ merge_array_property("recipes", new_recipes)
27
+ end
28
+
29
+ def merge_cookbook_paths(new_cookbook_paths = [])
30
+ merge_array_property("cookbook_paths", new_cookbook_paths)
31
+ end
32
+
33
+ def env_variable_switches=(hash)
34
+ self["env_variable_switches"] ||= Hashie::Mash.new
35
+ self["env_variable_switches"].merge!(Hashie::Mash.new(hash))
36
+ end
37
+
38
+ def to_yaml
39
+ to_hash.tap do |hash|
40
+ hash.delete("path")
41
+ self.class.nilable_properties.each { |k| hash[k] = nil if hash[k].empty? }
42
+ end
43
+ end
44
+
45
+ def save
46
+ return self unless path
47
+ File.open(path, "w+") { |file| file.write(YAML.dump(to_yaml)) }
48
+ self
49
+ end
50
+
51
+ def reload
52
+ self.class.from_file(path)
53
+ end
54
+
55
+ def self.from_file(file_path)
56
+ new(read_config(file_path).merge("path" => file_path))
57
+ end
58
+
59
+ def self.read_config(yaml_file)
60
+ content = File.read(yaml_file)
61
+ YAML.load(ERB.new(content).result).tap do |hash|
62
+ nilable_properties.each do |key|
63
+ hash.delete(key) if hash[key].nil?
64
+ end if hash
65
+ end || {}
66
+ end
67
+
68
+ private
69
+ def self.nilable_properties
70
+ (properties - [:path]).map(&:to_s)
71
+ end
72
+
73
+ def merge_array_property(property_name, values)
74
+ self[property_name] ||= []
75
+ self[property_name] += values
76
+ self[property_name].uniq!
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,3 @@
1
+ module Masterbaker
2
+ VERSION = "0.7.8"
3
+ end
@@ -0,0 +1,43 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # From the lovely work of "Matthew Kocher", "Doc Ritezel"
3
+ # who can be found at "kocher@gmail.com", "ritezel@gmail.com"
4
+ #
5
+ # Ported from Soloist
6
+ #
7
+ $:.push File.expand_path("../lib", __FILE__)
8
+ require "masterbaker/version"
9
+
10
+ Gem::Specification.new do |s|
11
+ s.name = "masterbaker"
12
+ s.version = Masterbaker::VERSION
13
+ s.platform = Gem::Platform::RUBY
14
+ s.authors = ["Mike Mackintosh"]
15
+ s.email = ["mike.mackintosh@gmail.com"]
16
+ s.homepage = "http://github.com/mikemackintosh/masterbaker"
17
+ s.summary = "Masterbaker is a simple way of running chef-solo"
18
+ s.description = "Makes running chef-solo easy."
19
+
20
+ s.rubyforge_project = "masterbaker"
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+
27
+ s.license = 'MIT'
28
+
29
+ s.add_dependency "chef"
30
+ s.add_dependency "librarian-chef"
31
+ s.add_dependency "thor"
32
+ s.add_dependency "hashie", "~> 2.0"
33
+ s.add_dependency "net-ssh"
34
+ s.add_dependency "awesome_print"
35
+
36
+ s.add_development_dependency "rspec"
37
+ s.add_development_dependency "guard-rspec"
38
+ s.add_development_dependency "guard-bundler"
39
+ s.add_development_dependency "guard-shell"
40
+ s.add_development_dependency "rb-fsevent"
41
+ s.add_development_dependency "terminal-notifier-guard"
42
+ s.add_development_dependency "gem-release"
43
+ end
metadata ADDED
@@ -0,0 +1,240 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: masterbaker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.8
5
+ platform: ruby
6
+ authors:
7
+ - Mike Mackintosh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chef
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: librarian-chef
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: hashie
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: net-ssh
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: awesome_print
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: guard-bundler
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: guard-shell
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rb-fsevent
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: terminal-notifier-guard
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: gem-release
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - '>='
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - '>='
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ description: Makes running chef-solo easy.
196
+ email:
197
+ - mike.mackintosh@gmail.com
198
+ executables:
199
+ - bake
200
+ extensions: []
201
+ extra_rdoc_files: []
202
+ files:
203
+ - .gitignore
204
+ - Gemfile
205
+ - LICENSE
206
+ - README.md
207
+ - bin/bake
208
+ - lib/masterbaker.rb
209
+ - lib/masterbaker/cli.rb
210
+ - lib/masterbaker/config.rb
211
+ - lib/masterbaker/remote.rb
212
+ - lib/masterbaker/remote_config.rb
213
+ - lib/masterbaker/royal_crown.rb
214
+ - lib/masterbaker/version.rb
215
+ - masterbaker.gemspec
216
+ homepage: http://github.com/mikemackintosh/masterbaker
217
+ licenses:
218
+ - MIT
219
+ metadata: {}
220
+ post_install_message:
221
+ rdoc_options: []
222
+ require_paths:
223
+ - lib
224
+ required_ruby_version: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - '>='
227
+ - !ruby/object:Gem::Version
228
+ version: '0'
229
+ required_rubygems_version: !ruby/object:Gem::Requirement
230
+ requirements:
231
+ - - '>='
232
+ - !ruby/object:Gem::Version
233
+ version: '0'
234
+ requirements: []
235
+ rubyforge_project: masterbaker
236
+ rubygems_version: 2.0.14
237
+ signing_key:
238
+ specification_version: 4
239
+ summary: Masterbaker is a simple way of running chef-solo
240
+ test_files: []