mofa 0.2.17 → 0.3.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.
- data/lib/mofa/attributes_map.rb +6 -1
- data/lib/mofa/cookbook.rb +1 -2
- data/lib/mofa/provision_cmd.rb +89 -67
- data/lib/mofa/released_cookbook.rb +37 -6
- data/lib/mofa/runlist_map.rb +14 -7
- data/lib/mofa/source_cookbook.rb +1 -1
- data/lib/mofa/version.rb +1 -1
- metadata +2 -2
data/lib/mofa/attributes_map.rb
CHANGED
@@ -44,6 +44,11 @@ class AttributesMap
|
|
44
44
|
attr_hash.each do |key, value|
|
45
45
|
if value.is_a?(Hash)
|
46
46
|
new_attr_hash[key] = deep_parse(value, placeholder, content)
|
47
|
+
elsif value.is_a?(Array)
|
48
|
+
new_attr_hash[key] = []
|
49
|
+
value.each do |value_item|
|
50
|
+
new_attr_hash[key].push(value_item.gsub(Regexp.new(Regexp.escape(placeholder)), content))
|
51
|
+
end
|
47
52
|
else
|
48
53
|
new_attr_hash[key] = value.gsub(Regexp.new(Regexp.escape(placeholder)), content)
|
49
54
|
end
|
@@ -72,4 +77,4 @@ class AttributesMap
|
|
72
77
|
new_attr_hash
|
73
78
|
end
|
74
79
|
|
75
|
-
end
|
80
|
+
end
|
data/lib/mofa/cookbook.rb
CHANGED
@@ -25,7 +25,6 @@ class Cookbook
|
|
25
25
|
case
|
26
26
|
when cookbook_name_or_path.match(/@/)
|
27
27
|
fail "Did not find released Cookbook #{cookbook_name_or_path}!" unless ReleasedCookbook.exists?(cookbook_name_or_path)
|
28
|
-
fail "Did not find Version #{cookbook_version} of released Cookbook #{cookbook_name_or_path}!" unless ReleasedCookbook.exists?(cookbook_name_or_path, cookbook_version)
|
29
28
|
|
30
29
|
cookbook = ReleasedCookbook.new(cookbook_name_or_path)
|
31
30
|
|
@@ -33,7 +32,7 @@ class Cookbook
|
|
33
32
|
cookbook = SourceCookbook.new(cookbook_name_or_path)
|
34
33
|
end
|
35
34
|
rescue RuntimeError => e
|
36
|
-
|
35
|
+
say e.message
|
37
36
|
raise "Cookbook not found/detected!"
|
38
37
|
end
|
39
38
|
cookbook.token = token
|
data/lib/mofa/provision_cmd.rb
CHANGED
@@ -42,8 +42,93 @@ class ProvisionCmd < MofaCmd
|
|
42
42
|
# This Code is Copy'n'Pasted from the old mofa tooling. Only to make the MVP work in time!!
|
43
43
|
# This needs to be refactored ASAP.
|
44
44
|
|
45
|
+
def prepare_host(hostname, host_index, solo_dir)
|
46
|
+
prerequesits_met = false
|
47
|
+
puts
|
48
|
+
puts "----------------------------------------------------------------------"
|
49
|
+
puts "Chef-Solo on Host #{hostname} (#{host_index}/#{hostlist.list.length.to_s})"
|
50
|
+
puts "----------------------------------------------------------------------"
|
51
|
+
|
52
|
+
puts "Pinging host #{hostname}..."
|
53
|
+
exit_status = system("ping -q -c 1 #{hostname} >/dev/null 2>&1")
|
54
|
+
unless exit_status then
|
55
|
+
puts " --> Host #{hostname} is unavailable!"
|
56
|
+
chef_solo_runs[hostname].store('status', 'UNAVAIL')
|
57
|
+
chef_solo_runs[hostname].store('status_msg', "Host #{hostname} unreachable.")
|
58
|
+
else
|
59
|
+
puts " --> Host #{hostname} is available."
|
60
|
+
prerequesits_met = true
|
61
|
+
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|
|
62
|
+
puts "Remotely creating solo_dir \"#{solo_dir}\" on host #{hostname}"
|
63
|
+
# remotely create the temp folder
|
64
|
+
out = ssh_exec!(ssh, "[ -d #{solo_dir} ] || mkdir #{solo_dir}")
|
65
|
+
puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
|
66
|
+
|
67
|
+
# remotely create a data_bags folder structure on the target host
|
68
|
+
if cookbook.instance_of?(SourceCookbook) and File.directory?("#{cookbook.source_dir}/data_bags")
|
69
|
+
Dir.entries("#{cookbook.source_dir}/data_bags").select { |f| !f.match(/^\.\.?$/) }.each do |data_bag|
|
70
|
+
puts "Remotely creating data_bags dir \"#{solo_dir}/data_bags/#{data_bag}\""
|
71
|
+
out = ssh_exec!(ssh, "[ -d #{solo_dir}/data_bags/#{data_bag} ] || mkdir -p #{solo_dir}/data_bags/#{data_bag}")
|
72
|
+
puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
prerequesits_met
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_solo_rb(sftp, hostname, solo_dir)
|
81
|
+
puts "Remotely creating \"#{solo_dir}/solo.rb\""
|
82
|
+
sftp.file.open("#{solo_dir}/solo.rb", "w") do |file|
|
83
|
+
if cookbook.instance_of?(SourceCookbook)
|
84
|
+
solo_rb = <<-"EOF"
|
85
|
+
cookbook_path [ "#{solo_dir}/cookbooks" ]
|
86
|
+
EOF
|
87
|
+
else
|
88
|
+
solo_rb = <<-"EOF"
|
89
|
+
recipe_url "#{cookbook.cookbooks_url}"
|
90
|
+
EOF
|
91
|
+
end
|
92
|
+
solo_rb += <<-"EOF"
|
93
|
+
data_bag_path "#{solo_dir}/data_bags"
|
94
|
+
log_level :info
|
95
|
+
log_location "#{solo_dir}/log"
|
96
|
+
verify_api_cert true
|
97
|
+
EOF
|
98
|
+
|
99
|
+
file.write(solo_rb)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_node_json(sftp, hostname, solo_dir, attributes_map)
|
104
|
+
puts "Remotely creating \"#{solo_dir}/node.json\""
|
105
|
+
node_json = {}
|
106
|
+
node_json.store('run_list', runlist_map.mp[hostname])
|
107
|
+
attributes_map.mp[hostname].each do |key, value|
|
108
|
+
node_json.store(key, value)
|
109
|
+
end
|
110
|
+
|
111
|
+
sftp.file.open("#{solo_dir}/node.json", "w") do |file|
|
112
|
+
file.write(JSON.pretty_generate(node_json))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_data_bags(sftp, hostname, solo_dir)
|
117
|
+
if cookbook.instance_of?(SourceCookbook) and File.directory?("#{cookbook.source_dir}/data_bags")
|
118
|
+
Dir.entries("#{cookbook.source_dir}/data_bags").select { |f| File.directory?(f) && !f.match(/^\.\.?$/) }.each do |data_bag|
|
119
|
+
Dir.entries("#{cookbook.source_dir}/data_bags/#{data_bag}").select { |f| f.match(/\.json$/) }.each do |data_bag_item|
|
120
|
+
puts "Uploading data_bag_item #{data_bag_item}... "
|
121
|
+
sftp.upload!("#{cookbook.source_dir}/data_bags/#{data_bag}/#{data_bag_item}", "#{solo_dir}/data_bags/#{data_bag}/#{data_bag_item}")
|
122
|
+
puts "OK."
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
45
128
|
def run_chef_solo_on_hosts
|
46
129
|
time = Time.new
|
130
|
+
# Create a temp working dir on the target host
|
131
|
+
solo_dir = '/var/tmp/' + time.strftime('%Y-%m-%d_%H%M%S')
|
47
132
|
puts
|
48
133
|
puts 'Chef-Solo Run started at ' + time.strftime('%Y-%m-%d %H:%M:%S')
|
49
134
|
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']}"
|
@@ -52,82 +137,19 @@ class ProvisionCmd < MofaCmd
|
|
52
137
|
host_index = 0
|
53
138
|
hostlist.list.each do |hostname|
|
54
139
|
host_index = host_index + 1
|
55
|
-
|
56
|
-
puts "----------------------------------------------------------------------"
|
57
|
-
puts "Chef-Solo on Host #{hostname} (#{host_index}/#{hostlist.list.length.to_s})"
|
58
|
-
puts "----------------------------------------------------------------------"
|
140
|
+
next unless prepare_host(hostname, host_index, solo_dir)
|
59
141
|
chef_solo_runs.store(hostname, {})
|
60
142
|
|
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
143
|
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
144
|
|
95
145
|
# remotely creating solo.rb
|
96
|
-
|
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
|
146
|
+
create_solo_rb(sftp, hostname, solo_dir)
|
108
147
|
|
109
148
|
# remotely creating node.json
|
110
|
-
|
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
|
149
|
+
create_node_json(sftp, hostname, solo_dir, attributes_map)
|
120
150
|
|
121
151
|
# remotely create data_bag items
|
122
|
-
|
123
|
-
Dir.entries("#{cookbook.source_dir}/data_bags").select { |f| File.directory?(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
|
152
|
+
create_data_bags(sftp, hostname, solo_dir)
|
131
153
|
|
132
154
|
if cookbook.instance_of?(SourceCookbook)
|
133
155
|
puts "Cookbook is a SourceCookbook! Uploading Snapshot Package #{cookbook.pkg_name}... "
|
@@ -1,10 +1,24 @@
|
|
1
1
|
class ReleasedCookbook < Cookbook
|
2
2
|
|
3
|
+
def self.get_name_and_version(cookbook_name_or_path)
|
4
|
+
# TODO: this needs proper vaidation!
|
5
|
+
name = cookbook_name_or_path.split(/@/).first
|
6
|
+
version = cookbook_name_or_path.split(/@/).last
|
7
|
+
{ 'name' => name, 'version' => version }
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.exists?(cookbook_name_or_path)
|
11
|
+
nv = get_name_and_version(cookbook_name_or_path)
|
12
|
+
url = "#{Mofa::Config.config['bin_repo']}/#{nv['name']}/#{nv['version']}/#{nv['name']}_#{nv['version']}-full.tar.gz"
|
13
|
+
puts "Checking if cookbook exists: #{url}"
|
14
|
+
RestClient.head(url)
|
15
|
+
end
|
16
|
+
|
3
17
|
def initialize(cookbook_name_or_path)
|
4
18
|
super()
|
5
|
-
|
6
|
-
@name =
|
7
|
-
@version =
|
19
|
+
nv = ReleasedCookbook.get_name_and_version(cookbook_name_or_path)
|
20
|
+
@name = nv['name']
|
21
|
+
@version = nv['version']
|
8
22
|
end
|
9
23
|
|
10
24
|
# ------------- Interface Methods
|
@@ -12,19 +26,26 @@ class ReleasedCookbook < Cookbook
|
|
12
26
|
def prepare
|
13
27
|
@pkg_name ||= "#{name}_#{version}-full.tar.gz"
|
14
28
|
@pkg_dir = "#{Mofa::Config.config['tmp_dir']}/.mofa/#{token}"
|
29
|
+
set_cookbooks_url
|
15
30
|
end
|
16
31
|
|
17
32
|
def execute
|
18
|
-
# TODO: Download & unpack released cookbook
|
19
|
-
# Important for guessing role runlists (when cookbook is an env-cookbook)
|
20
33
|
end
|
21
34
|
|
22
35
|
def cleanup
|
23
36
|
say "Removing folder #{pkg_dir}...#{nl}"
|
24
|
-
run "rm -
|
37
|
+
run "rm -rf #{pkg_dir}"
|
25
38
|
ok
|
26
39
|
end
|
27
40
|
|
41
|
+
def load_mofa_yml
|
42
|
+
@mofa_yml = MofaYml.load_from_file(".mofa.yml", self)
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_mofa_yml_local
|
46
|
+
@mofa_yml_local = MofaYml.load_from_file(".mofa.local.yml", self)
|
47
|
+
end
|
48
|
+
|
28
49
|
# ------------- /Interface Methods
|
29
50
|
|
30
51
|
def cleanup!
|
@@ -36,6 +57,16 @@ class ReleasedCookbook < Cookbook
|
|
36
57
|
end
|
37
58
|
end
|
38
59
|
|
60
|
+
def set_cookbooks_url
|
61
|
+
say 'Using remote URI as cookbooks_url: '
|
62
|
+
@cookbooks_url = "#{Mofa::Config.config['bin_repo']}/#{@name}/#{@version}/#{@name}_#{@version}-full.tar.gz"
|
63
|
+
say "#{@cookbooks_url}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def recipes
|
67
|
+
[]
|
68
|
+
end
|
69
|
+
|
39
70
|
private
|
40
71
|
|
41
72
|
def nl
|
data/lib/mofa/runlist_map.rb
CHANGED
@@ -11,6 +11,7 @@ class RunlistMap
|
|
11
11
|
rl.cookbook = cookbook
|
12
12
|
rl.hostlist = hostlist
|
13
13
|
rl.token = token
|
14
|
+
rl.option_runlist = option_runlist
|
14
15
|
rl.default_runlist_recipes = (!option_runlist.nil?) ? option_runlist : nil
|
15
16
|
rl
|
16
17
|
end
|
@@ -23,11 +24,17 @@ class RunlistMap
|
|
23
24
|
@default_runlist_recipes ||= [ "#{cookbook.name}::default" ]
|
24
25
|
@default_runlist_recipes = [ "#{@default_runlist_recipes}" ] unless @default_runlist_recipes.kind_of?(Array)
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
if option_runlist.nil?
|
28
|
+
case cookbook.type
|
29
|
+
when 'env'
|
30
|
+
guess_runlists_by_hostnames
|
31
|
+
else
|
32
|
+
set_default_runlist_for_every_host
|
33
|
+
end
|
34
|
+
else
|
35
|
+
hostlist.list.each do |hostname|
|
36
|
+
@mp.store(hostname, option_runlist)
|
37
|
+
end
|
31
38
|
end
|
32
39
|
end
|
33
40
|
|
@@ -50,9 +57,9 @@ class RunlistMap
|
|
50
57
|
hostlist.list.each do |hostname|
|
51
58
|
@default_runlist_recipes.each do |rl_entry|
|
52
59
|
next unless rl_entry.split(/::/)[0] == cookbook.name
|
53
|
-
@mp.store(hostname, rl_entry) if cookbook.recipes.include?(rl_entry.split(/::/)[1])
|
60
|
+
@mp.store(hostname, rl_entry) if cookbook.recipes.kind_of?(Array) and cookbook.recipes.include?(rl_entry.split(/::/)[1])
|
54
61
|
end
|
55
62
|
end
|
56
63
|
end
|
57
64
|
|
58
|
-
end
|
65
|
+
end
|
data/lib/mofa/source_cookbook.rb
CHANGED
data/lib/mofa/version.rb
CHANGED
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.
|
4
|
+
version: 0.3.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-10-
|
12
|
+
date: 2015-10-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|