mofa 0.1.7 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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