mofa 0.1.7 → 0.2.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.
@@ -3,6 +3,8 @@ end
3
3
 
4
4
  require 'mofa/version'
5
5
  require 'mofa/mofa_cmd'
6
+ require 'mofa/provision_cmd'
7
+ require 'mofa/upload_cmd'
6
8
  require 'mofa/hostlist'
7
9
  require 'mofa/runlist_map'
8
10
  require 'mofa/attributes_map'
@@ -35,11 +35,35 @@ module Mofa
35
35
  runlist_map = RunlistMap.create(cookbook, hostlist, token, options[:runlist])
36
36
  attributes_map = AttributesMap.create(cookbook, hostlist, token, options[:runlist], options[:attributes])
37
37
 
38
- mofa_cmd = MofaCmd.create(cookbook, hostlist, runlist_map, attributes_map, token)
39
- mofa_cmd.prepare
40
- mofa_cmd.execute
41
- mofa_cmd.cleanup
38
+ cmd = ProvisionCmd.new(token, cookbook)
42
39
 
40
+ cmd.hostlist = hostlist
41
+ cmd.runlist_map = runlist_map
42
+ cmd.attributes_map = attributes_map
43
+
44
+ cmd.prepare
45
+ cmd.execute
46
+ cmd.cleanup
47
+ end
48
+
49
+ desc 'upload <cookbook>', 'package & upload cookbook into binrepo'
50
+ method_option :binrepo_host, :type => :string
51
+ method_option :binrepo_ssh_user, :type => :string
52
+ method_option :binrepo_ssh_keyfile, :type => :string
53
+
54
+ def upload(cookbook_path)
55
+ set_verbosity
56
+
57
+ cookbook_path ||= '.'
58
+
59
+ token = MofaCmd.generate_token
60
+ cookbook = Cookbook.create(cookbook_path, token)
61
+
62
+ cmd = UploadCmd.new(token, cookbook)
63
+
64
+ cmd.prepare
65
+ cmd.execute
66
+ cmd.cleanup
43
67
  end
44
68
 
45
69
  desc 'config', 'prints out mofa config.'
@@ -10,6 +10,8 @@ class Cookbook
10
10
  attr_accessor :name
11
11
  attr_accessor :version
12
12
  attr_accessor :type
13
+ attr_accessor :pkg_name
14
+ attr_accessor :pkg_dir
13
15
  attr_accessor :pkg_uri
14
16
  attr_accessor :source_uri
15
17
  attr_accessor :cookbooks_url
@@ -17,29 +19,28 @@ class Cookbook
17
19
  attr_accessor :mofa_yml_local
18
20
  attr_accessor :token
19
21
 
20
- def self.create(cookbook_name_or_path='.', token=nil)
21
- cb = nil
22
+ def self.create(cookbook_name_or_path, token)
23
+ cookbook = nil
22
24
  begin
23
25
  case
24
- when cookbook_name_or_path.match(/:/)
26
+ when cookbook_name_or_path.match(/@/)
25
27
  fail "Did not find released Cookbook #{cookbook_name_or_path}!" unless ReleasedCookbook.exists?(cookbook_name_or_path)
26
28
  fail "Did not find Version #{cookbook_version} of released Cookbook #{cookbook_name_or_path}!" unless ReleasedCookbook.exists?(cookbook_name_or_path, cookbook_version)
27
29
 
28
- cb = ReleasedCookbook.new(cookbook_name_or_path)
30
+ cookbook = ReleasedCookbook.new(cookbook_name_or_path)
29
31
 
30
32
  else
31
- cb = SourceCookbook.new(cookbook_name_or_path)
33
+ cookbook = SourceCookbook.new(cookbook_name_or_path)
32
34
  end
33
35
  rescue RuntimeError => e
34
36
  error e.message
35
37
  raise "Cookbook not found/detected!"
36
38
  end
37
- cb.token = token
38
- cb.autodetect_type
39
- cb.load_mofa_yml
40
- cb.load_mofa_yml_local
41
- cb
42
-
39
+ cookbook.token = token
40
+ cookbook.autodetect_type
41
+ cookbook.load_mofa_yml
42
+ cookbook.load_mofa_yml_local
43
+ cookbook
43
44
  end
44
45
 
45
46
  def autodetect_type
@@ -4,215 +4,29 @@ require 'net/sftp'
4
4
  class MofaCmd
5
5
  attr_accessor :token
6
6
  attr_accessor :cookbook
7
- attr_accessor :hostlist
8
- attr_accessor :runlist_map
9
- attr_accessor :attributes_map
10
7
 
11
8
  def self.generate_token
12
9
  Digest::SHA1.hexdigest([Time.now, rand].join)[0..10]
13
10
  end
14
11
 
15
- def self.create(cookbook, hostlist, runlist_map, attributes_map, token)
16
- mofa_cmd = MofaCmd.new
17
- mofa_cmd.token = token
18
- mofa_cmd.cookbook = cookbook
19
- mofa_cmd.hostlist = hostlist
20
- mofa_cmd.runlist_map = runlist_map
21
- mofa_cmd.attributes_map = attributes_map
22
- mofa_cmd
12
+ def initialize(token, cookbook)
13
+ @token = token
14
+ @cookbook = cookbook
23
15
  end
24
16
 
17
+ # @abstract
25
18
  def prepare
26
- cookbook.prepare
19
+ raise RuntimeError, "must be implemented"
27
20
  end
28
21
 
22
+ # @abstract
29
23
  def execute
30
- cookbook.execute
31
- hostlist.retrieve
32
- runlist_map.generate
33
- attributes_map.generate
34
-
35
- puts "Runlist Map: #{runlist_map.mp.inspect}"
36
- puts "Attributes Map: #{attributes_map.mp.inspect}"
37
- puts "Hostlist before runlist filtering: #{hostlist.list.inspect}"
38
-
39
- hostlist.filter_by_runlist_map(runlist_map)
40
-
41
- puts "Hostlist after runlist filtering: #{hostlist.list.inspect}"
42
-
43
- exit_code = run_chef_solo_on_hosts
44
-
45
- exit_code
24
+ raise RuntimeError, "must be implemented"
46
25
  end
47
26
 
27
+ # @abstract
48
28
  def cleanup
49
- cookbook.cleanup
50
- end
51
-
52
- # FIXME
53
- # This Code is Copy'n'Pasted from the old mofa tooling. Only to make the MVP work in time!!
54
- # This needs to be refactored ASAP.
55
-
56
- def run_chef_solo_on_hosts
57
- time = Time.new
58
- puts
59
- puts 'Chef-Solo Run started at ' + time.strftime('%Y-%m-%d %H:%M:%S')
60
- puts "Will use ssh_user #{Mofa::Config.config['ssh_user']} and ssh_key_file #{Mofa::Config.config['ssh_keyfile']}"
61
- at_least_one_chef_solo_run_failed = false
62
- chef_solo_runs = {}
63
- host_index = 0
64
- hostlist.list.each do |hostname|
65
- host_index = host_index + 1
66
- puts
67
- puts "----------------------------------------------------------------------"
68
- puts "Chef-Solo on Host #{hostname} (#{host_index}/#{hostlist.list.length.to_s})"
69
- puts "----------------------------------------------------------------------"
70
- chef_solo_runs.store(hostname, {})
71
-
72
- # do only one for faster dev-cycle...
73
- #next unless hostname.match(/^dash/)
74
-
75
- puts "Pinging host #{hostname}..."
76
- exit_status = system("ping -q -c 1 #{hostname} >/dev/null 2>&1")
77
- unless exit_status then
78
- puts " --> Host #{hostname} is unavailable!"
79
- chef_solo_runs[hostname].store('status', 'UNAVAIL')
80
- chef_solo_runs[hostname].store('status_msg', "Host #{hostname} unreachable.")
81
- else
82
- puts " --> Host #{hostname} is available."
83
- prerequesits_met = true
84
- # Create a temp working dir on the target host
85
- solo_dir = '/var/tmp/' + time.strftime('%Y-%m-%d_%H%M%S')
86
- Net::SSH.start(hostname, Mofa::Config.config['ssh_user'], :keys => [Mofa::Config.config['ssh_keyfile']], :verbose => :error) do |ssh|
87
- puts "Remotely creating solo_dir \"#{solo_dir}\" on host #{hostname}"
88
- # remotely create the temp folder
89
- out = ssh_exec!(ssh, "[ -d #{solo_dir} ] || mkdir #{solo_dir}")
90
- puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
91
-
92
- # remotely create a data_bags folder structure on the target host
93
- if File.directory?("#{cookbook.source_dir}/data_bags")
94
- Dir.entries("#{cookbook.source_dir}/data_bags").select { |f| !f.match(/^\.\.?$/) }.each do |data_bag|
95
- puts "Remotely creating data_bags dir \"#{solo_dir}/data_bags/#{data_bag}\""
96
- out = ssh_exec!(ssh, "[ -d #{solo_dir}/data_bags/#{data_bag} ] || mkdir -p #{solo_dir}/data_bags/#{data_bag}")
97
- puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
98
- end
99
- end
100
- end
101
- end
102
-
103
- # skip the rest if prerequesits are not met
104
- next unless prerequesits_met
105
-
106
-
107
- Net::SFTP.start(hostname, Mofa::Config.config['ssh_user'], :keys => [Mofa::Config.config['ssh_keyfile']], :verbose => :error) do |sftp|
108
-
109
- # remotely creating solo.rb
110
- puts "Remotely creating \"#{solo_dir}/solo.rb\""
111
- sftp.file.open("#{solo_dir}/solo.rb", "w") do |file|
112
- solo_rb = <<-"EOF"
113
- cookbook_path [ "#{solo_dir}/cookbooks" ]
114
- data_bag_path "#{solo_dir}/data_bags"
115
- log_level :info
116
- log_location "#{solo_dir}/log"
117
- verify_api_cert true
118
- EOF
119
-
120
- file.write(solo_rb)
121
- end
122
-
123
- # remotely creating node.json
124
- puts "Remotely creating \"#{solo_dir}/node.json\""
125
- node_json = {}
126
- node_json.store('run_list', runlist_map.mp[hostname])
127
- attributes_map.mp[hostname].each do |key, value|
128
- node_json.store(key, value)
129
- end
130
-
131
- sftp.file.open("#{solo_dir}/node.json", "w") do |file|
132
- file.write(JSON.pretty_generate(node_json))
133
- end
134
-
135
- # remotely create data_bag items
136
- if File.directory?("#{cookbook.source_dir}/data_bags")
137
- Dir.entries("#{cookbook.source_dir}/data_bags").select { |f| !f.match(/^\.\.?$/) }.each do |data_bag|
138
- Dir.entries("#{cookbook.source_dir}/data_bags/#{data_bag}").select { |f| f.match(/\.json$/) }.each do |data_bag_item|
139
- puts "Uploading data_bag_item #{data_bag_item}... "
140
- sftp.upload!("#{cookbook.source_dir}/data_bags/#{data_bag}/#{data_bag_item}", "#{solo_dir}/data_bags/#{data_bag}/#{data_bag_item}")
141
- puts "OK."
142
- end
143
- end
144
- end
145
-
146
- if cookbook.instance_of?(SourceCookbook)
147
- puts "Cookbook is a SourceCookbook! Uploading Snapshot Package #{cookbook.pkg_name}... "
148
- sftp.upload!("#{cookbook.pkg_dir}/#{cookbook.pkg_name}", "#{solo_dir}/#{cookbook.pkg_name}")
149
- puts "OK."
150
- end
151
-
152
- # Do it -> Execute the chef-solo run!
153
- Net::SSH.start(hostname, Mofa::Config::config['ssh_user'], :keys => [Mofa::Config::config['ssh_keyfile']], :verbose => :error) do |ssh|
154
-
155
- if cookbook.instance_of?(SourceCookbook)
156
- puts "Remotely unpacking Snapshot Package #{cookbook.pkg_name}... "
157
- out = ssh_exec!(ssh, "cd #{solo_dir}; tar xvfz #{cookbook.pkg_name}")
158
- if out[0] != 0
159
- puts "ERROR (#{out[0]}): #{out[2]}"
160
- puts out[1]
161
- else
162
- puts "OK."
163
- end
164
- end
165
-
166
- puts "Remotely running chef-solo -c #{solo_dir}/solo.rb -j #{solo_dir}/node.json"
167
- out = ssh_exec!(ssh, "sudo chef-solo -c #{solo_dir}/solo.rb -j #{solo_dir}/node.json")
168
- if out[0] != 0
169
- puts "ERROR (#{out[0]}): #{out[2]}"
170
- out = ssh_exec!(ssh, "sudo cat #{solo_dir}/log")
171
- puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
172
- puts out[1]
173
- chef_solo_runs[hostname].store('status', 'FAIL')
174
- chef_solo_runs[hostname].store('status_msg', out[1])
175
- else
176
- unless Mofa::CLI::option_debug
177
- out = ssh_exec!(ssh, "sudo grep 'Chef Run' #{solo_dir}/log")
178
- puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
179
- puts "Done."
180
- else
181
- out = ssh_exec!(ssh, "sudo cat #{solo_dir}/log")
182
- puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
183
- puts out[1]
184
- end
185
- chef_solo_runs[hostname].store('status', 'SUCCESS')
186
- chef_solo_runs[hostname].store('status_msg', '')
187
- end
188
- out = ssh_exec!(ssh, "sudo chown -R #{Mofa::Config.config['ssh_user']}.#{Mofa::Config.config['ssh_user']} #{solo_dir}")
189
- puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
190
- end
191
- end
192
- at_least_one_chef_solo_run_failed = true if chef_solo_runs[hostname]['status'] == 'FAIL'
193
- end
194
-
195
- # ------- print out report
196
- puts
197
- puts "----------------------------------------------------------------------"
198
- puts "Chef-Solo Run REPORT"
199
- puts "----------------------------------------------------------------------"
200
- puts "Chef-Solo has been run on #{chef_solo_runs.keys.length.to_s} hosts."
201
-
202
- chef_solo_runs.each do |hostname, content|
203
- status_msg = ''
204
- status_msg = "(#{content['status_msg']})" if content['status'] == 'FAIL'
205
- puts "#{content['status']}: #{hostname} #{status_msg}"
206
- end
207
-
208
- exit_code = 0
209
- if at_least_one_chef_solo_run_failed
210
- exit_code = 1
211
- end
212
-
213
- puts "Exiting with exit code #{exit_code}."
214
- exit_code
215
-
29
+ raise RuntimeError, "must be implemented"
216
30
  end
217
31
 
218
32
  def ssh_exec!(ssh, command)
@@ -246,8 +60,5 @@ class MofaCmd
246
60
  [exit_code, stdout_data, stderr_data, exit_signal]
247
61
  end
248
62
 
249
-
250
- private
251
-
252
63
  end
253
64
 
@@ -0,0 +1,204 @@
1
+ require 'net/ssh'
2
+ require 'net/sftp'
3
+
4
+ class ProvisionCmd < MofaCmd
5
+ attr_accessor :hostlist
6
+ attr_accessor :runlist_map
7
+ attr_accessor :attributes_map
8
+
9
+ def initialize(token, cookbook)
10
+ super(token, cookbook)
11
+ end
12
+
13
+ def prepare
14
+ cookbook.prepare
15
+ end
16
+
17
+ def execute
18
+ cookbook.execute
19
+
20
+ hostlist.retrieve
21
+ runlist_map.generate
22
+ attributes_map.generate
23
+
24
+ puts "Runlist Map: #{runlist_map.mp.inspect}"
25
+ puts "Attributes Map: #{attributes_map.mp.inspect}"
26
+ puts "Hostlist before runlist filtering: #{hostlist.list.inspect}"
27
+
28
+ hostlist.filter_by_runlist_map(runlist_map)
29
+
30
+ puts "Hostlist after runlist filtering: #{hostlist.list.inspect}"
31
+
32
+ exit_code = run_chef_solo_on_hosts
33
+
34
+ exit_code
35
+ end
36
+
37
+ def cleanup
38
+ cookbook.cleanup
39
+ end
40
+
41
+ # FIXME
42
+ # This Code is Copy'n'Pasted from the old mofa tooling. Only to make the MVP work in time!!
43
+ # This needs to be refactored ASAP.
44
+
45
+ def run_chef_solo_on_hosts
46
+ time = Time.new
47
+ puts
48
+ puts 'Chef-Solo Run started at ' + time.strftime('%Y-%m-%d %H:%M:%S')
49
+ puts "Will use ssh_user #{Mofa::Config.config['ssh_user']}, ssh_port #{Mofa::Config.config['ssh_port']} and ssh_key_file #{Mofa::Config.config['ssh_keyfile']}"
50
+ at_least_one_chef_solo_run_failed = false
51
+ chef_solo_runs = {}
52
+ host_index = 0
53
+ hostlist.list.each do |hostname|
54
+ host_index = host_index + 1
55
+ puts
56
+ puts "----------------------------------------------------------------------"
57
+ puts "Chef-Solo on Host #{hostname} (#{host_index}/#{hostlist.list.length.to_s})"
58
+ puts "----------------------------------------------------------------------"
59
+ chef_solo_runs.store(hostname, {})
60
+
61
+ puts "Pinging host #{hostname}..."
62
+ exit_status = system("ping -q -c 1 #{hostname} >/dev/null 2>&1")
63
+ unless exit_status then
64
+ puts " --> Host #{hostname} is unavailable!"
65
+ chef_solo_runs[hostname].store('status', 'UNAVAIL')
66
+ chef_solo_runs[hostname].store('status_msg', "Host #{hostname} unreachable.")
67
+ else
68
+ puts " --> Host #{hostname} is available."
69
+ prerequesits_met = true
70
+ # Create a temp working dir on the target host
71
+ solo_dir = '/var/tmp/' + time.strftime('%Y-%m-%d_%H%M%S')
72
+ Net::SSH.start(hostname, Mofa::Config.config['ssh_user'], :keys => [Mofa::Config.config['ssh_keyfile']], :port => Mofa::Config.config['ssh_port'], :verbose => :error) do |ssh|
73
+ puts "Remotely creating solo_dir \"#{solo_dir}\" on host #{hostname}"
74
+ # remotely create the temp folder
75
+ out = ssh_exec!(ssh, "[ -d #{solo_dir} ] || mkdir #{solo_dir}")
76
+ puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
77
+
78
+ # remotely create a data_bags folder structure on the target host
79
+ if File.directory?("#{cookbook.source_dir}/data_bags")
80
+ Dir.entries("#{cookbook.source_dir}/data_bags").select { |f| !f.match(/^\.\.?$/) }.each do |data_bag|
81
+ puts "Remotely creating data_bags dir \"#{solo_dir}/data_bags/#{data_bag}\""
82
+ out = ssh_exec!(ssh, "[ -d #{solo_dir}/data_bags/#{data_bag} ] || mkdir -p #{solo_dir}/data_bags/#{data_bag}")
83
+ puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ # skip the rest if prerequesits are not met
90
+ next unless prerequesits_met
91
+
92
+
93
+ Net::SFTP.start(hostname, Mofa::Config.config['ssh_user'], :keys => [Mofa::Config.config['ssh_keyfile']], :port => Mofa::Config.config['ssh_port'], :verbose => :error) do |sftp|
94
+
95
+ # remotely creating solo.rb
96
+ puts "Remotely creating \"#{solo_dir}/solo.rb\""
97
+ sftp.file.open("#{solo_dir}/solo.rb", "w") do |file|
98
+ solo_rb = <<-"EOF"
99
+ cookbook_path [ "#{solo_dir}/cookbooks" ]
100
+ data_bag_path "#{solo_dir}/data_bags"
101
+ log_level :info
102
+ log_location "#{solo_dir}/log"
103
+ verify_api_cert true
104
+ EOF
105
+
106
+ file.write(solo_rb)
107
+ end
108
+
109
+ # remotely creating node.json
110
+ puts "Remotely creating \"#{solo_dir}/node.json\""
111
+ node_json = {}
112
+ node_json.store('run_list', runlist_map.mp[hostname])
113
+ attributes_map.mp[hostname].each do |key, value|
114
+ node_json.store(key, value)
115
+ end
116
+
117
+ sftp.file.open("#{solo_dir}/node.json", "w") do |file|
118
+ file.write(JSON.pretty_generate(node_json))
119
+ end
120
+
121
+ # remotely create data_bag items
122
+ if File.directory?("#{cookbook.source_dir}/data_bags")
123
+ Dir.entries("#{cookbook.source_dir}/data_bags").select { |f| !f.match(/^\.\.?$/) }.each do |data_bag|
124
+ Dir.entries("#{cookbook.source_dir}/data_bags/#{data_bag}").select { |f| f.match(/\.json$/) }.each do |data_bag_item|
125
+ puts "Uploading data_bag_item #{data_bag_item}... "
126
+ sftp.upload!("#{cookbook.source_dir}/data_bags/#{data_bag}/#{data_bag_item}", "#{solo_dir}/data_bags/#{data_bag}/#{data_bag_item}")
127
+ puts "OK."
128
+ end
129
+ end
130
+ end
131
+
132
+ if cookbook.instance_of?(SourceCookbook)
133
+ puts "Cookbook is a SourceCookbook! Uploading Snapshot Package #{cookbook.pkg_name}... "
134
+ sftp.upload!("#{cookbook.pkg_dir}/#{cookbook.pkg_name}", "#{solo_dir}/#{cookbook.pkg_name}")
135
+ puts "OK."
136
+ end
137
+
138
+ # Do it -> Execute the chef-solo run!
139
+ Net::SSH.start(hostname, Mofa::Config::config['ssh_user'], :keys => [Mofa::Config::config['ssh_keyfile']], :port => Mofa::Config.config['ssh_port'], :verbose => :error) do |ssh|
140
+
141
+ if cookbook.instance_of?(SourceCookbook)
142
+ puts "Remotely unpacking Snapshot Package #{cookbook.pkg_name}... "
143
+ out = ssh_exec!(ssh, "cd #{solo_dir}; tar xvfz #{cookbook.pkg_name}")
144
+ if out[0] != 0
145
+ puts "ERROR (#{out[0]}): #{out[2]}"
146
+ puts out[1]
147
+ else
148
+ puts "OK."
149
+ end
150
+ end
151
+
152
+ puts "Remotely running chef-solo -c #{solo_dir}/solo.rb -j #{solo_dir}/node.json"
153
+ out = ssh_exec!(ssh, "sudo chef-solo -c #{solo_dir}/solo.rb -j #{solo_dir}/node.json")
154
+ if out[0] != 0
155
+ puts "ERROR (#{out[0]}): #{out[2]}"
156
+ out = ssh_exec!(ssh, "sudo cat #{solo_dir}/log")
157
+ puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
158
+ puts out[1]
159
+ chef_solo_runs[hostname].store('status', 'FAIL')
160
+ chef_solo_runs[hostname].store('status_msg', out[1])
161
+ else
162
+ unless Mofa::CLI::option_debug
163
+ out = ssh_exec!(ssh, "sudo grep 'Chef Run' #{solo_dir}/log")
164
+ puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
165
+ puts "Done."
166
+ else
167
+ out = ssh_exec!(ssh, "sudo cat #{solo_dir}/log")
168
+ puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
169
+ puts out[1]
170
+ end
171
+ chef_solo_runs[hostname].store('status', 'SUCCESS')
172
+ chef_solo_runs[hostname].store('status_msg', '')
173
+ end
174
+ out = ssh_exec!(ssh, "sudo chown -R #{Mofa::Config.config['ssh_user']}.#{Mofa::Config.config['ssh_user']} #{solo_dir}")
175
+ puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
176
+ end
177
+ end
178
+ at_least_one_chef_solo_run_failed = true if chef_solo_runs[hostname]['status'] == 'FAIL'
179
+ end
180
+
181
+ # ------- print out report
182
+ puts
183
+ puts "----------------------------------------------------------------------"
184
+ puts "Chef-Solo Run REPORT"
185
+ puts "----------------------------------------------------------------------"
186
+ puts "Chef-Solo has been run on #{chef_solo_runs.keys.length.to_s} hosts."
187
+
188
+ chef_solo_runs.each do |hostname, content|
189
+ status_msg = ''
190
+ status_msg = "(#{content['status_msg']})" if content['status'] == 'FAIL'
191
+ puts "#{content['status']}: #{hostname} #{status_msg}"
192
+ end
193
+
194
+ exit_code = 0
195
+ if at_least_one_chef_solo_run_failed
196
+ exit_code = 1
197
+ end
198
+
199
+ puts "Exiting with exit code #{exit_code}."
200
+ exit_code
201
+
202
+ end
203
+
204
+ end
@@ -1,18 +1,16 @@
1
1
  class ReleasedCookbook < Cookbook
2
- attr_accessor :pkg_dir
3
- attr_accessor :pkg_name
4
2
 
5
3
  def initialize(cookbook_name_or_path)
6
4
  super()
7
5
  # TODO: this needs proper vaidation!
8
- @name = cookbook_name_or_path.split(/:/).first
9
- @version = cookbook_name_or_path.split(/:/).last
6
+ @name = cookbook_name_or_path.split(/@/).first
7
+ @version = cookbook_name_or_path.split(/@/).last
10
8
  end
11
9
 
12
10
  # ------------- Interface Methods
13
11
 
14
12
  def prepare
15
- @pkg_name = "#{name}-#{version}.tar.gz"
13
+ @pkg_name ||= "#{name}_#{version}-full.tar.gz"
16
14
  @pkg_dir = "#{Mofa::Config.config['tmp_dir']}/.mofa/#{token}"
17
15
  end
18
16
 
@@ -4,14 +4,14 @@ class RunlistMap
4
4
  attr_accessor :hostlist
5
5
  attr_accessor :token
6
6
  attr_accessor :option_runlist
7
- attr_accessor :default_runlist
7
+ attr_accessor :default_runlist_recipes
8
8
 
9
9
  def self.create(cookbook, hostlist, token, option_runlist = nil)
10
10
  rl = RunlistMap.new
11
11
  rl.cookbook = cookbook
12
12
  rl.hostlist = hostlist
13
13
  rl.token = token
14
- rl.default_runlist = (!option_runlist.nil?) ? option_runlist : nil
14
+ rl.default_runlist_recipes = (!option_runlist.nil?) ? option_runlist : nil
15
15
  rl
16
16
  end
17
17
 
@@ -20,7 +20,7 @@ class RunlistMap
20
20
  end
21
21
 
22
22
  def generate
23
- @default_runlist ||= "recipe[#{cookbook.name}::default]"
23
+ @default_runlist_recipes ||= [ "#{cookbook.name}::default" ]
24
24
 
25
25
  case cookbook.type
26
26
  when 'env'
@@ -47,8 +47,10 @@ class RunlistMap
47
47
 
48
48
  def set_default_runlist_for_every_host
49
49
  hostlist.list.each do |hostname|
50
- if cookbook.recipies.include?(@default_runlist.split(/::/)[1])
51
- @mp.store(hostname, @default_runlist)
50
+ puts "Default Runlist Recipes: #{@default_runlist_recipes}"
51
+ @default_runlist_recipes.each do |rl_entry|
52
+ next unless rl_entry.split(/::/)[0] == cookbook.name
53
+ @mp.store(hostname, @default_runlist) if cookbook.recipes.include?(rl_entry.split(/::/)[1])
52
54
  end
53
55
  end
54
56
  end
@@ -1,7 +1,4 @@
1
1
  class SourceCookbook < Cookbook
2
- attr_accessor :pkg_dir
3
- attr_accessor :pkg_name
4
-
5
2
  COOKBOOK_IGNORE=%w(.mofa .idea .kitchen .vagrant .bundle test)
6
3
 
7
4
  def initialize(cookbook_name_or_path)
@@ -12,6 +9,7 @@ class SourceCookbook < Cookbook
12
9
  @source_uri = "file://#{path.realpath}"
13
10
 
14
11
  say "source_dir=#{source_dir}"
12
+
15
13
  autodetect_name
16
14
  autodetect_version
17
15
  end
@@ -21,13 +19,14 @@ class SourceCookbook < Cookbook
21
19
  def prepare
22
20
  fail "Source URI is not a file:// URI!" unless source_uri =~ /^file:\/\/.*/
23
21
  fail "Folder #{source_dir} is not a Cookbook Folder!" unless cookbook_folder?(source_dir)
24
- @pkg_name = "#{name}-#{token}-SNAPSHOT.tar.gz"
22
+
23
+ @pkg_name ||= "#{name}_#{version}-SNAPSHOT.tar.gz"
25
24
  @pkg_dir = "#{source_dir}/.mofa/#{token}"
26
25
  end
27
26
 
28
27
  def execute
29
28
  package
30
- stage
29
+ set_cookbooks_url
31
30
  end
32
31
 
33
32
  def cleanup
@@ -37,6 +36,7 @@ class SourceCookbook < Cookbook
37
36
  end
38
37
 
39
38
  # ------------- /Interface Methods
39
+
40
40
  def source_dir
41
41
  source_uri.gsub(/^file:\/\//, '')
42
42
  end
@@ -75,7 +75,7 @@ class SourceCookbook < Cookbook
75
75
  end
76
76
  end
77
77
 
78
- def stage
78
+ def set_cookbooks_url
79
79
  if mofahub_available?
80
80
  say 'Staging (uploading to mofa-hub) Cookbook Snapshot: '
81
81
  @cookbooks_url = upload_to_mofahub
@@ -115,7 +115,7 @@ class SourceCookbook < Cookbook
115
115
  end
116
116
 
117
117
  def cleanup_and_repackage
118
- say "Shrinking Cookbook Snapshot #{pkg_name}... "
118
+ say "Shrinking Cookbook #{pkg_name}... "
119
119
 
120
120
  tar_verbose = (Mofa::CLI::option_debug) ? 'v' : ''
121
121
 
@@ -0,0 +1,58 @@
1
+ require 'net/ssh'
2
+ require 'net/sftp'
3
+
4
+ class UploadCmd < MofaCmd
5
+
6
+ def initialize(token, cookbook)
7
+ super(token, cookbook)
8
+ end
9
+
10
+ def prepare
11
+ fail unless binrepo_up?
12
+
13
+ # upload always means: package a release
14
+ cookbook.pkg_name = "#{cookbook.name}_#{cookbook.version}-full.tar.gz"
15
+ cookbook.prepare
16
+ end
17
+
18
+ def execute
19
+ cookbook.execute
20
+ upload_cookbook_pkg
21
+ end
22
+
23
+ def cleanup
24
+ cookbook.cleanup
25
+ end
26
+
27
+ def binrepo_up?
28
+ binrepo_up = true
29
+
30
+ exit_status = system("ping -q -c 1 #{Mofa::Config.config['binrepo_host']} >/dev/null 2>&1")
31
+ unless exit_status then
32
+ puts " --> Binrepo host #{Mofa::Config.config['binrepo_host']} is unavailable!"
33
+ binrepo_up = false
34
+ end
35
+
36
+ puts "Binrepo #{ Mofa::Config.config['binrepo_ssh_user']}@#{Mofa::Config.config['binrepo_host']}:#{Mofa::Config.config['binrepo_import_dir']} not present or not reachable!" unless binrepo_up
37
+ binrepo_up
38
+
39
+ end
40
+
41
+ def upload_cookbook_pkg
42
+ puts "Will use ssh_user #{Mofa::Config.config['binrepo_ssh_user']} and ssh_key_file #{Mofa::Config.config['binrepo_ssh_keyfile']}"
43
+ puts "Uploading cookbook pkg #{cookbook.pkg_name} to binrepo import folder #{Mofa::Config.config['binrepo_host']}:#{Mofa::Config.config['binrepo_import_dir']}..."
44
+
45
+ fail unless binrepo_up?
46
+ begin
47
+ Net::SFTP.start(Mofa::Config.config['binrepo_host'], Mofa::Config.config['binrepo_ssh_user'], :keys => [Mofa::Config.config['binrepo_ssh_keyfile']], :port => Mofa::Config.config['binrepo_ssh_port'], :verbose => :error) do |sftp|
48
+ sftp.upload!("#{cookbook.pkg_dir}/#{cookbook.pkg_name}", "#{Mofa::Config.config['binrepo_import_dir']}/#{cookbook.pkg_name}")
49
+ end
50
+ puts "OK."
51
+ rescue RuntimeError => e
52
+ puts "Error: #{e.message}"
53
+ raise "Failed to upload cookbook #{cookbook.name}!"
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -1,3 +1,3 @@
1
1
  module Mofa
2
- VERSION = "0.1.7"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mofa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-08 00:00:00.000000000 Z
12
+ date: 2015-04-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -228,9 +228,11 @@ files:
228
228
  - lib/mofa/hostlist.rb
229
229
  - lib/mofa/mofa_cmd.rb
230
230
  - lib/mofa/mofa_yml.rb
231
+ - lib/mofa/provision_cmd.rb
231
232
  - lib/mofa/released_cookbook.rb
232
233
  - lib/mofa/runlist_map.rb
233
234
  - lib/mofa/source_cookbook.rb
235
+ - lib/mofa/upload_cmd.rb
234
236
  - lib/mofa/version.rb
235
237
  - mofa.gemspec
236
238
  homepage: https://github.com/pingworks/mofa