mofa 0.5.6 → 0.5.13
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.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/.rubocop.yml +6 -0
- data/.ruby-version +1 -0
- data/Dockerfile +12 -0
- data/README.md +1 -1
- data/config.docker.yml +39 -0
- data/lib/mofa/attributes_map.rb +8 -2
- data/lib/mofa/cli.rb +12 -61
- data/lib/mofa/cmd_line_args.rb +25 -0
- data/lib/mofa/cookbook.rb +17 -22
- data/lib/mofa/hostlist.rb +2 -61
- data/lib/mofa/mofa_cmd.rb +13 -13
- data/lib/mofa/provision_cmd.rb +13 -15
- data/lib/mofa/released_cookbook.rb +19 -15
- data/lib/mofa/runlist_map.rb +1 -3
- data/lib/mofa/source_cookbook.rb +4 -4
- data/lib/mofa/upload_cmd.rb +1 -1
- data/lib/mofa/version.rb +1 -1
- data/mofa.gemspec +2 -0
- metadata +10 -9
- data/rspec/mofa/hostfile_spec.rb +0 -18
- data/rspec/mofa/test_hostlist.json +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 22340c00ac56402d53cb1ed841920ace967951402a866f9ca880c33d25616c73
|
4
|
+
data.tar.gz: 228bdcb23b75e5da076e1f6f5ec80be8e63f2df02eeb828f564666ae566d0502
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f31f027919a1a26cc1bb5eaf973631cc37762d39592dc688948d2ea4f29b5d94909d320ea43a595eb15fa67f262178f6e9024b8e2c91a8745fd5f163d95ef51b
|
7
|
+
data.tar.gz: 92c20936e7dd2b917d6be30d548bf6c6efef8249a51e002788500088cdfeaf0ce4e179c1688d1731b001dc90eb34db1561e88179ca2957ef042f905edd163c07
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.5
|
data/Dockerfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
FROM docker.io/chef/chefdk:1.6.11
|
2
|
+
|
3
|
+
RUN apt update && apt upgrade --yes && \
|
4
|
+
apt install build-essential rsync --yes && \
|
5
|
+
gem install mofa
|
6
|
+
|
7
|
+
RUN mkdir /root/.mofa
|
8
|
+
|
9
|
+
COPY config.docker.yml /root/.mofa/config.yml
|
10
|
+
|
11
|
+
ENV PATH="/root/.chefdk/gem/ruby/2.3.0/bin:${PATH}"
|
12
|
+
|
data/README.md
CHANGED
@@ -52,7 +52,7 @@ Before you can start using mofa please create a config file:
|
|
52
52
|
|
53
53
|
# local Development
|
54
54
|
|
55
|
-
$ git clone https://github.com/
|
55
|
+
$ git clone https://github.com/pingworks/mofa.git
|
56
56
|
$ cd mofa
|
57
57
|
$ bundle install
|
58
58
|
$ cd ../somewhere_chef-env_some_cookbook
|
data/config.docker.yml
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# global mofa settings
|
2
|
+
|
3
|
+
# Admin User Account that should be used for all mofa tasks.
|
4
|
+
# The user has to be able to login passwordless
|
5
|
+
# and has tohave passwordless sudo permissions.
|
6
|
+
ssh_user: sccchef
|
7
|
+
ssh_keyfile: ~/.ssh/id_rsa_sccchef
|
8
|
+
|
9
|
+
# where to build tmporary cookbook packages and so on
|
10
|
+
tmp_dir: /var/tmp
|
11
|
+
|
12
|
+
# A REST-Webservice that returns a list of hosts that are potentially
|
13
|
+
# manageable with this mofa.
|
14
|
+
service_hostlist_url: file:///opt/workshopbox/etc/hostlist.json
|
15
|
+
service_hostlist_default_filter: "localhost"
|
16
|
+
#service_hostlist_api_key: xyz
|
17
|
+
|
18
|
+
# The cookbook architectural pattern should becodified by following
|
19
|
+
# a coonaming schema:
|
20
|
+
# * Cookbooks beginning with "env_*" are Envrionment Cookbooks
|
21
|
+
# * Cookbooks haven a prefix like "<organisation_name>_*" are
|
22
|
+
# so-called Wrapper Cookbooks
|
23
|
+
# * Cookbooks having a "base_" Prefix are Base Cookbooks
|
24
|
+
|
25
|
+
cookbook_type_indicator:
|
26
|
+
env: "^env_.*"
|
27
|
+
wrapper: "^(scc_|fos_|allcop_).*"
|
28
|
+
base: ".*_base$"
|
29
|
+
|
30
|
+
# Binrepo for released cookbooks
|
31
|
+
binrepo_base_url: 'https://berks-api/cookbooks'
|
32
|
+
|
33
|
+
# Releasing into binrepo
|
34
|
+
binrepo_host: berks-api
|
35
|
+
binrepo_ssh_user: berks
|
36
|
+
binrepo_ssh_port: 22
|
37
|
+
binrepo_ssh_keyfile: /id_rsa
|
38
|
+
binrepo_import_dir: /data/cookbooks/import
|
39
|
+
|
data/lib/mofa/attributes_map.rb
CHANGED
@@ -47,10 +47,16 @@ class AttributesMap
|
|
47
47
|
elsif value.is_a?(Array)
|
48
48
|
new_attr_hash[key] = []
|
49
49
|
value.each do |value_item|
|
50
|
-
|
50
|
+
if value_item.is_a?(Hash)
|
51
|
+
new_attr_hash[key] = deep_parse(value, placeholder, content)
|
52
|
+
else
|
53
|
+
new_attr_hash[key].push(value_item.gsub(Regexp.new(Regexp.escape(placeholder)), content))
|
54
|
+
end
|
51
55
|
end
|
52
56
|
else
|
53
|
-
|
57
|
+
if value
|
58
|
+
new_attr_hash[key] = value.gsub(Regexp.new(Regexp.escape(placeholder)), content)
|
59
|
+
end
|
54
60
|
end
|
55
61
|
end
|
56
62
|
new_attr_hash
|
data/lib/mofa/cli.rb
CHANGED
@@ -16,26 +16,25 @@ module Mofa
|
|
16
16
|
class_option :debug, :type => :boolean, :aliases => '-vv', :desc => 'be very vebose'
|
17
17
|
|
18
18
|
desc 'provision <cookbook>', 'provisions Targethost(s) using a given cookbook.'
|
19
|
-
method_option :ignore_ping, :type => :boolean, :aliases => '-
|
20
|
-
method_option :target, :type => :string, :aliases => '-t'
|
19
|
+
method_option :ignore_ping, :type => :boolean, :aliases => '-P'
|
21
20
|
method_option :concrete_target, :type => :string, :aliases => '-T'
|
22
|
-
method_option :sshport, :type => :string, :aliases => '-P'
|
23
21
|
method_option :runlist, :type => :string, :aliases => '-o'
|
24
22
|
method_option :attributes, :type => :string, :aliases => '-j'
|
25
23
|
method_option :service_hostlist_url, :type => :string
|
26
24
|
method_option :override_mofa_secrets, :type => :string, :aliases => '-S'
|
27
|
-
|
25
|
+
method_option :ssh_port, :type => :string, :aliases => '-p', :default => '22'
|
26
|
+
method_option :ssh_user, :type => :string, :aliases => '-u', :default => 'sccchef'
|
27
|
+
method_option :ssh_keyfile, :type => :string, :aliases => '-i', :default => '~/.ssh/id_rsa_sccchef'
|
28
|
+
method_option :tmp_dir, :type => :string, :aliases => '-w', :default => '~/tmp/mofa'
|
29
|
+
method_option :binrepo_base_url, :type => :string, :aliases => '-r'
|
30
|
+
|
28
31
|
def provision(cookbook_name_or_path)
|
29
32
|
set_verbosity
|
30
|
-
|
31
33
|
cookbook_name_or_path ||= '.'
|
32
34
|
|
33
|
-
target_filter = options[:target]
|
34
|
-
#target_filter ||= Mofa::Config.config['profiles']['default']['target']
|
35
|
-
|
36
35
|
token = MofaCmd.generate_token
|
37
36
|
|
38
|
-
hostlist = Hostlist.create(
|
37
|
+
hostlist = Hostlist.create(options[:concrete_target])
|
39
38
|
cookbook = Cookbook.create(cookbook_name_or_path, token, options[:override_mofa_secrets])
|
40
39
|
runlist_map = RunlistMap.create(cookbook, hostlist, token, options[:runlist])
|
41
40
|
attributes_map = AttributesMap.create(cookbook, hostlist, token, options[:runlist], options[:attributes])
|
@@ -48,12 +47,13 @@ module Mofa
|
|
48
47
|
cmd.options = options
|
49
48
|
|
50
49
|
cmd.prepare
|
51
|
-
cmd.execute(options[:
|
50
|
+
cmd.execute(options[:ssh_port], options[:ssh_user], options[:ssh_keyfile])
|
52
51
|
cmd.cleanup
|
53
52
|
end
|
54
53
|
|
55
54
|
desc 'upload <cookbook>', 'package & upload cookbook into binrepo'
|
56
55
|
method_option :binrepo_host, :type => :string
|
56
|
+
method_option :binrepo_ssh_port, :type => :string
|
57
57
|
method_option :binrepo_ssh_user, :type => :string
|
58
58
|
method_option :binrepo_ssh_keyfile, :type => :string
|
59
59
|
|
@@ -68,7 +68,8 @@ module Mofa
|
|
68
68
|
cmd = UploadCmd.new(token, cookbook)
|
69
69
|
|
70
70
|
cmd.prepare
|
71
|
-
|
71
|
+
# FIXME: bring in the ssh-port in a different way
|
72
|
+
cmd.execute(22)
|
72
73
|
cmd.cleanup
|
73
74
|
end
|
74
75
|
|
@@ -78,29 +79,6 @@ module Mofa
|
|
78
79
|
puts VERSION
|
79
80
|
end
|
80
81
|
|
81
|
-
desc 'config', 'prints out mofa config.'
|
82
|
-
|
83
|
-
def config
|
84
|
-
config_print
|
85
|
-
end
|
86
|
-
|
87
|
-
desc 'setup', 'setup initial configuration'
|
88
|
-
|
89
|
-
def setup
|
90
|
-
set_verbosity
|
91
|
-
|
92
|
-
case
|
93
|
-
when !File.exists?("#{ENV['HOME']}/.mofa/config.yml")
|
94
|
-
begin
|
95
|
-
config_create
|
96
|
-
end until config_valid?
|
97
|
-
else
|
98
|
-
begin
|
99
|
-
config_edit
|
100
|
-
end until config_valid?
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
82
|
def self.option_verbose
|
105
83
|
@@option_verbose
|
106
84
|
end
|
@@ -129,33 +107,6 @@ module Mofa
|
|
129
107
|
say detail, :red
|
130
108
|
end
|
131
109
|
|
132
|
-
def config_create
|
133
|
-
say 'Creating a new mofa config (~/.mofa/config.yml)...'
|
134
|
-
|
135
|
-
say '- not implemented yet -'
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
def config_edit
|
140
|
-
say 'Editing mofa config (~/.mofa/config.yml)...'
|
141
|
-
|
142
|
-
say '- not implemented yet -'
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
|
-
def config_print
|
147
|
-
say 'Mofa Config (~/.mofa/config.yml):'
|
148
|
-
|
149
|
-
say '- not implemented yet -'
|
150
|
-
|
151
|
-
end
|
152
|
-
|
153
|
-
def config_valid?
|
154
|
-
say 'Validating Mofa config (~/.mofa/config.yml)...'
|
155
|
-
say '- not implemented yet -'
|
156
|
-
true
|
157
|
-
end
|
158
|
-
|
159
110
|
def self.exit_on_failure?
|
160
111
|
true
|
161
112
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Mofa
|
2
|
+
class CmdLineArgs
|
3
|
+
def self.instance
|
4
|
+
@__instance__ ||= new
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@cmd_line_args = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def register(cmd_line_args)
|
12
|
+
@cmd_line_args = cmd_line_args
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(key)
|
16
|
+
raise "Cmd Line Arg with key #{key} does not exist!" unless @cmd_line_args.key?(key)
|
17
|
+
@cmd_line_args[key]
|
18
|
+
end
|
19
|
+
|
20
|
+
def list
|
21
|
+
puts 'Comman Line Args:'
|
22
|
+
@cmd_line_args.inspect
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/mofa/cookbook.rb
CHANGED
@@ -24,16 +24,16 @@ class Cookbook
|
|
24
24
|
cookbook = nil
|
25
25
|
begin
|
26
26
|
case
|
27
|
-
|
28
|
-
|
27
|
+
when cookbook_name_or_path.match(/@/)
|
28
|
+
raise "Did not find released Cookbook #{cookbook_name_or_path}!" unless ReleasedCookbook.exists?(cookbook_name_or_path)
|
29
29
|
|
30
|
-
|
30
|
+
cookbook = ReleasedCookbook.new(cookbook_name_or_path, override_mofa_secrets)
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
else
|
33
|
+
cookbook = SourceCookbook.new(cookbook_name_or_path, override_mofa_secrets)
|
34
34
|
end
|
35
35
|
rescue RuntimeError => e
|
36
|
-
raise
|
36
|
+
raise 'Cookbook not found/detected: ' + e.message
|
37
37
|
end
|
38
38
|
cookbook.token = token
|
39
39
|
cookbook.autodetect_type
|
@@ -43,32 +43,29 @@ class Cookbook
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def autodetect_type
|
46
|
-
env_indicator =
|
47
|
-
|
48
|
-
base_indicator = Mofa::Config.config['cookbook_type_indicator']['base']
|
46
|
+
env_indicator = '^env_.*'
|
47
|
+
base_indicator = '.*_base$'
|
49
48
|
|
50
|
-
say
|
49
|
+
say 'Autodetecting Cookbook Architectural Type...'
|
51
50
|
|
52
51
|
case
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
else
|
60
|
-
@type = 'application'
|
52
|
+
when @name.match(env_indicator)
|
53
|
+
@type = 'env'
|
54
|
+
when @name.match(base_indicator)
|
55
|
+
@type = 'base'
|
56
|
+
else
|
57
|
+
@type = 'application'
|
61
58
|
end
|
62
59
|
say "#{type.capitalize} Cookbook"
|
63
60
|
end
|
64
61
|
|
65
|
-
def say(message =
|
62
|
+
def say(message = '', color = nil, force_new_line = (message.to_s !~ /( |\t)$/))
|
66
63
|
color ||= :green
|
67
64
|
super
|
68
65
|
end
|
69
66
|
|
70
67
|
def ok(detail=nil)
|
71
|
-
text = detail ? "OK, #{detail}." :
|
68
|
+
text = detail ? "OK, #{detail}." : 'OK.'
|
72
69
|
say text, :green
|
73
70
|
end
|
74
71
|
|
@@ -86,6 +83,4 @@ class Cookbook
|
|
86
83
|
exit_code = super(cmd, args.merge(:verbose => verbose))
|
87
84
|
fail "Failed to run #{cmd.inspect}!" unless exit_code == true
|
88
85
|
end
|
89
|
-
|
90
|
-
|
91
86
|
end
|
data/lib/mofa/hostlist.rb
CHANGED
@@ -4,20 +4,10 @@ require 'json'
|
|
4
4
|
|
5
5
|
class Hostlist
|
6
6
|
attr_accessor :list
|
7
|
-
attr_accessor :filter
|
8
|
-
attr_accessor :service_host
|
9
|
-
attr_accessor :service_url
|
10
|
-
attr_accessor :api_key
|
11
7
|
attr_accessor :concrete_target
|
12
8
|
|
13
|
-
def self.create(
|
9
|
+
def self.create(concrete_target)
|
14
10
|
hl = Hostlist.new
|
15
|
-
filter = Mofa::Config.config['service_hostlist_default_filter'] if concrete_target.nil? && filter.nil?
|
16
|
-
service_hostlist_url ||= Mofa::Config.config['service_hostlist_url']
|
17
|
-
hl.filter = filter
|
18
|
-
hl.service_host = Mofa::Config.config['service_hostlist_url'].gsub(/^http:\/\//, '').gsub(/\/.*$/, '').gsub(/:.*$/, '')
|
19
|
-
hl.service_url = service_hostlist_url
|
20
|
-
hl.api_key = Mofa::Config.config['service_hostlist_api_key']
|
21
11
|
hl.concrete_target = concrete_target
|
22
12
|
hl
|
23
13
|
end
|
@@ -30,65 +20,16 @@ class Hostlist
|
|
30
20
|
Hostlist::get_shortname(hostname).gsub(/\d+$/, '')
|
31
21
|
end
|
32
22
|
|
33
|
-
def has_concrete_target
|
34
|
-
return (@concrete_target.nil?) ? false : true
|
35
|
-
end
|
36
|
-
|
37
23
|
def retrieve
|
38
|
-
|
39
|
-
when has_concrete_target
|
40
|
-
@list = [@concrete_target]
|
41
|
-
when @service_url.match(/^http/)
|
42
|
-
fail "Hostlist Service not reachable! (cannot ping #{service_host})" unless up?
|
43
|
-
response = RestClient.get(@service_url, {:params => {:key => api_key}})
|
44
|
-
hosts_list_json = JSON.parse response.body
|
45
|
-
@list = hosts_list_json['data'].collect { |i| i['cname'] }
|
46
|
-
when @service_url.match(/^file:/)
|
47
|
-
json_file = @service_url.gsub(/^file:\/\//, '')
|
48
|
-
if File.exist?(json_file)
|
49
|
-
hosts_list_json = JSON.parse(File.read(json_file))
|
50
|
-
@list = hosts_list_json['data'].collect { |i| i['cname'] }
|
51
|
-
else
|
52
|
-
fail "Hostlist JSON-File not found: #{json_file}"
|
53
|
-
end
|
54
|
-
|
55
|
-
else
|
56
|
-
fail "Hostlist Service Url either has to be a http(s):// or a file:/// Url!"
|
57
|
-
end
|
58
|
-
apply_filter
|
59
|
-
sort_by_domainname
|
24
|
+
@list = [@concrete_target]
|
60
25
|
end
|
61
26
|
|
62
|
-
|
63
27
|
def up?
|
64
28
|
p = Net::Ping::TCP.new(@service_host, 'http')
|
65
29
|
p.ping?
|
66
30
|
end
|
67
31
|
|
68
|
-
def apply_filter
|
69
|
-
unless @filter.nil?
|
70
|
-
if @filter[0] == '/' && @filter[-1] == '/' && @filter.length > 2
|
71
|
-
regex = @filter[1..-2]
|
72
|
-
else
|
73
|
-
# building matcher
|
74
|
-
regex = @filter.gsub(/\*/, '__ASTERISK__')
|
75
|
-
regex = Regexp.escape(regex).gsub(/__ASTERISK__/, '.*')
|
76
|
-
regex = '^' + regex + '$'
|
77
|
-
end
|
78
|
-
@list.select! { |hostname| hostname.match(regex) }
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def sort_by_domainname
|
83
|
-
sortable = {}
|
84
|
-
@list.each do |hostname|
|
85
|
-
sortable.store(hostname.split(/\./).reverse.join('.'), hostname)
|
86
|
-
end
|
87
|
-
@list = sortable.keys.sort.collect { |s| sortable[s] }
|
88
|
-
end
|
89
|
-
|
90
32
|
def filter_by_runlist_map(runlist_map)
|
91
33
|
@list.select! { |hostname| runlist_map.mp.key?(hostname) }
|
92
34
|
end
|
93
|
-
|
94
35
|
end
|
data/lib/mofa/mofa_cmd.rb
CHANGED
@@ -17,42 +17,42 @@ class MofaCmd
|
|
17
17
|
|
18
18
|
# @abstract
|
19
19
|
def prepare
|
20
|
-
raise RuntimeError,
|
20
|
+
raise RuntimeError, 'must be implemented'
|
21
21
|
end
|
22
22
|
|
23
23
|
# @abstract
|
24
|
-
def execute(
|
25
|
-
raise RuntimeError,
|
24
|
+
def execute(_ssh_port)
|
25
|
+
raise RuntimeError, 'must be implemented'
|
26
26
|
end
|
27
27
|
|
28
28
|
# @abstract
|
29
29
|
def cleanup
|
30
|
-
raise RuntimeError,
|
30
|
+
raise RuntimeError, 'must be implemented'
|
31
31
|
end
|
32
32
|
|
33
33
|
def ssh_exec!(ssh, command)
|
34
|
-
stdout_data =
|
35
|
-
stderr_data =
|
34
|
+
stdout_data = ''
|
35
|
+
stderr_data = ''
|
36
36
|
exit_code = nil
|
37
37
|
exit_signal = nil
|
38
38
|
ssh.open_channel do |channel|
|
39
|
-
channel.exec(command) do |
|
39
|
+
channel.exec(command) do |_ch, success|
|
40
40
|
unless success
|
41
41
|
abort "FAILED: couldn't execute command (ssh.channel.exec)"
|
42
42
|
end
|
43
|
-
channel.on_data do |
|
44
|
-
stdout_data+=data
|
43
|
+
channel.on_data do |_ch, data|
|
44
|
+
stdout_data += data
|
45
45
|
end
|
46
46
|
|
47
|
-
channel.on_extended_data do |
|
48
|
-
stderr_data+=data
|
47
|
+
channel.on_extended_data do |_ch, _type, data|
|
48
|
+
stderr_data += data
|
49
49
|
end
|
50
50
|
|
51
|
-
channel.on_request(
|
51
|
+
channel.on_request('exit-status') do |_ch, data|
|
52
52
|
exit_code = data.read_long
|
53
53
|
end
|
54
54
|
|
55
|
-
channel.on_request(
|
55
|
+
channel.on_request('exit-signal') do |_ch, data|
|
56
56
|
exit_signal = data.read_long
|
57
57
|
end
|
58
58
|
end
|
data/lib/mofa/provision_cmd.rb
CHANGED
@@ -14,7 +14,7 @@ class ProvisionCmd < MofaCmd
|
|
14
14
|
cookbook.prepare
|
15
15
|
end
|
16
16
|
|
17
|
-
def execute(
|
17
|
+
def execute(ssh_port, ssh_user, ssh_keyfile)
|
18
18
|
cookbook.execute
|
19
19
|
|
20
20
|
hostlist.retrieve
|
@@ -30,7 +30,7 @@ class ProvisionCmd < MofaCmd
|
|
30
30
|
|
31
31
|
puts "Hostlist after runlist filtering: #{hostlist.list.inspect}"
|
32
32
|
|
33
|
-
exit_code = run_chef_solo_on_hosts(
|
33
|
+
exit_code = run_chef_solo_on_hosts(ssh_port, ssh_user, ssh_keyfile)
|
34
34
|
|
35
35
|
exit_code
|
36
36
|
end
|
@@ -56,12 +56,12 @@ class ProvisionCmd < MofaCmd
|
|
56
56
|
host_available
|
57
57
|
end
|
58
58
|
|
59
|
-
def prepare_host(hostname, host_index, solo_dir)
|
59
|
+
def prepare_host(hostname, host_index, solo_dir, ssh_port, ssh_user, ssh_keyfile)
|
60
60
|
puts
|
61
61
|
puts '----------------------------------------------------------------------'
|
62
62
|
puts "Chef-Solo on Host #{hostname} (#{host_index}/#{hostlist.list.length})"
|
63
63
|
puts '----------------------------------------------------------------------'
|
64
|
-
Net::SSH.start(hostname,
|
64
|
+
Net::SSH.start(hostname, ssh_user, keys: [ssh_keyfile], port: ssh_port, use_agent: false, verbose: :error) do |ssh|
|
65
65
|
puts "Remotely creating solo_dir \"#{solo_dir}\" on host #{hostname}"
|
66
66
|
# remotely create the temp folder
|
67
67
|
out = ssh_exec!(ssh, "[ -d #{solo_dir} ] || mkdir #{solo_dir}")
|
@@ -90,8 +90,6 @@ class ProvisionCmd < MofaCmd
|
|
90
90
|
file.write(solo_rb)
|
91
91
|
end
|
92
92
|
end
|
93
|
-
# log_level :info
|
94
|
-
# log_location "#{solo_dir}/log"
|
95
93
|
|
96
94
|
def create_node_json(sftp, hostname, solo_dir, attributes_map)
|
97
95
|
puts "Remotely creating \"#{solo_dir}/node.json\" on #{hostname}..."
|
@@ -121,13 +119,13 @@ class ProvisionCmd < MofaCmd
|
|
121
119
|
end
|
122
120
|
end
|
123
121
|
|
124
|
-
def run_chef_solo_on_hosts(
|
122
|
+
def run_chef_solo_on_hosts(ssh_port, ssh_user, ssh_keyfile)
|
125
123
|
time = Time.new
|
126
124
|
# Create a temp working dir on the target host
|
127
125
|
solo_dir = '/var/tmp/' + time.strftime('%Y-%m-%d_%H%M%S')
|
128
126
|
puts
|
129
127
|
puts 'Chef-Solo Run started at ' + time.strftime('%Y-%m-%d %H:%M:%S')
|
130
|
-
puts "Will use ssh_user #{
|
128
|
+
puts "Will use ssh_user '#{ssh_user}', ssh_port '#{ssh_port}' and ssh_keyfile '#{ssh_keyfile}'"
|
131
129
|
at_least_one_chef_solo_run_failed = false
|
132
130
|
chef_solo_runs = {}
|
133
131
|
host_index = 0
|
@@ -144,9 +142,9 @@ class ProvisionCmd < MofaCmd
|
|
144
142
|
end
|
145
143
|
end
|
146
144
|
|
147
|
-
prepare_host(hostname, host_index, solo_dir)
|
145
|
+
prepare_host(hostname, host_index, solo_dir, ssh_port, ssh_user, ssh_keyfile)
|
148
146
|
|
149
|
-
Net::SFTP.start(hostname,
|
147
|
+
Net::SFTP.start(hostname, ssh_user, keys: [ssh_keyfile], port: ssh_port, use_agent: false, verbose: :error) do |sftp|
|
150
148
|
# remotely creating solo.rb
|
151
149
|
create_solo_rb(sftp, hostname, solo_dir)
|
152
150
|
|
@@ -164,7 +162,7 @@ class ProvisionCmd < MofaCmd
|
|
164
162
|
# Do it -> Execute the chef-solo run!
|
165
163
|
begin
|
166
164
|
begin
|
167
|
-
Net::SSH.start(hostname,
|
165
|
+
Net::SSH.start(hostname, ssh_user, keys: [ssh_keyfile], port: ssh_port, use_agent: false, verbose: :error) do |ssh|
|
168
166
|
puts "Remotely unpacking Cookbook Package #{cookbook.pkg_name}... "
|
169
167
|
ssh.exec!("cd #{solo_dir}; tar xvfz #{cookbook.pkg_name}") do |_ch, _stream, line|
|
170
168
|
puts line if Mofa::CLI.option_debug
|
@@ -181,13 +179,13 @@ class ProvisionCmd < MofaCmd
|
|
181
179
|
raise e
|
182
180
|
end
|
183
181
|
begin
|
184
|
-
Net::SSH.start(hostname,
|
182
|
+
Net::SSH.start(hostname, ssh_user, keys: [ssh_keyfile], port: ssh_port, use_agent: false, verbose: :error) do |ssh|
|
185
183
|
puts "Remotely running chef-solo -c #{solo_dir}/solo.rb -j #{solo_dir}/node.json"
|
186
184
|
chef_run_exit_code = 0
|
187
185
|
ssh.exec!("sudo chef-solo -c #{solo_dir}/solo.rb -j #{solo_dir}/node.json") do |_ch, _stream, line|
|
188
186
|
puts line if Mofa::CLI.option_verbose || Mofa::CLI.option_debug
|
189
187
|
log_file.write(line)
|
190
|
-
chef_run_exit_code = 1 if line =~ /Chef run process exited unsuccessfully/
|
188
|
+
chef_run_exit_code = 1 if line =~ /Chef run process exited unsuccessfully/ || line =~ /chef-solo: command not found/
|
191
189
|
end
|
192
190
|
raise 'Chef run process exited unsuccessfully' if chef_run_exit_code != 0
|
193
191
|
chef_solo_runs[hostname].store('status', 'SUCCESS')
|
@@ -207,9 +205,9 @@ class ProvisionCmd < MofaCmd
|
|
207
205
|
log_file.write('chef-solo run: FAIL')
|
208
206
|
puts "ERRORS detected while provisioning #{hostname} (#{e.message})."
|
209
207
|
end
|
210
|
-
Net::SSH.start(hostname,
|
208
|
+
Net::SSH.start(hostname, ssh_user, keys: [ssh_keyfile], port: ssh_port, use_agent: false, verbose: :error) do |ssh|
|
211
209
|
snapshot_or_release = cookbook.is_a?(SourceCookbook) ? 'snapshot' : 'release'
|
212
|
-
out = ssh_exec!(ssh, "sudo chown -R #{
|
210
|
+
out = ssh_exec!(ssh, "sudo chown -R #{ssh_user}.#{ssh_user} #{solo_dir}")
|
213
211
|
puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
|
214
212
|
out = ssh_exec!(ssh, '[ -d /var/lib/mofa ] || sudo mkdir /var/lib/mofa')
|
215
213
|
puts "ERROR (#{out[0]}): #{out[2]}" if out[0] != 0
|
@@ -9,7 +9,7 @@ class ReleasedCookbook < Cookbook
|
|
9
9
|
|
10
10
|
def self.exists?(cookbook_name_or_path)
|
11
11
|
nv = get_name_and_version(cookbook_name_or_path)
|
12
|
-
url = "#{Mofa::
|
12
|
+
url = "#{Mofa::CLI::binrepo_base_url}/#{nv['name']}/#{nv['version']}/#{nv['name']}_#{nv['version']}-full.tar.gz"
|
13
13
|
puts "Checking if cookbook exists: #{url}"
|
14
14
|
RestClient.head(url)
|
15
15
|
end
|
@@ -26,7 +26,7 @@ class ReleasedCookbook < Cookbook
|
|
26
26
|
|
27
27
|
def prepare
|
28
28
|
@pkg_name ||= "#{name}_#{version}-full.tar.gz"
|
29
|
-
@pkg_dir = "#{Mofa::
|
29
|
+
@pkg_dir = "#{Mofa::CLI::option_tmp_dir}/.mofa/#{token}"
|
30
30
|
set_cookbooks_url
|
31
31
|
end
|
32
32
|
|
@@ -65,16 +65,20 @@ class ReleasedCookbook < Cookbook
|
|
65
65
|
|
66
66
|
# Sync in mofa_secrets
|
67
67
|
if override_mofa_secrets
|
68
|
-
if File.directory?("#{override_mofa_secrets}/#{name}
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
68
|
+
if File.directory?("#{override_mofa_secrets}/#{name}")
|
69
|
+
if File.directory?("#{override_mofa_secrets}/#{name}/cookbooks")
|
70
|
+
run "rsync -vr #{override_mofa_secrets}/#{name}/cookbooks/ #{pkg_dir}/tmp/cookbooks/"
|
71
|
+
if File.file?("#{override_mofa_secrets}/#{name}/.mofa.local.yml")
|
72
|
+
FileUtils.cp "#{override_mofa_secrets}/#{name}/.mofa.local.yml", "#{pkg_dir}/tmp/cookbooks/#{name}/"
|
73
|
+
end
|
74
|
+
if File.file?("#{override_mofa_secrets}/#{name}/.mofa.yml")
|
75
|
+
FileUtils.cp "#{override_mofa_secrets}/#{name}/.mofa.yml", "#{pkg_dir}/tmp/cookbooks/#{name}/"
|
76
|
+
end
|
77
|
+
else
|
78
|
+
run "rsync -vr #{override_mofa_secrets}/#{name}/ #{pkg_dir}/tmp/cookbooks/#{name}/"
|
75
79
|
end
|
76
80
|
else
|
77
|
-
|
81
|
+
say "Skipping non-existant mofa-secrets folder #{override_mofa_secrets}/#{name}"
|
78
82
|
end
|
79
83
|
end
|
80
84
|
|
@@ -110,17 +114,17 @@ class ReleasedCookbook < Cookbook
|
|
110
114
|
end
|
111
115
|
|
112
116
|
def cleanup!
|
113
|
-
unless (Dir.entries("#{Mofa::
|
114
|
-
say "Removing content of folder #{Mofa::
|
115
|
-
run "rm -r #{Mofa::
|
117
|
+
unless (Dir.entries("#{Mofa::CLI::option_tmp_dir}/.mofa") - %w{ . .. }).empty?
|
118
|
+
say "Removing content of folder #{Mofa::CLI::option_tmp_dir}/.mofa"
|
119
|
+
run "rm -r #{Mofa::CLI::option_tmp_dir}/.mofa/*"
|
116
120
|
else
|
117
|
-
say "Folder #{Mofa::
|
121
|
+
say "Folder #{Mofa::CLI::option_tmp_dir}/.mofa is (already) clean."
|
118
122
|
end
|
119
123
|
end
|
120
124
|
|
121
125
|
def set_cookbooks_url
|
122
126
|
say 'Using remote URI as cookbooks_url: '
|
123
|
-
@cookbooks_url = "#{Mofa::
|
127
|
+
@cookbooks_url = "#{Mofa::CLI::binrepo_base_url}/#{@name}/#{@version}/#{@name}_#{@version}-full.tar.gz"
|
124
128
|
say "#{@cookbooks_url}"
|
125
129
|
end
|
126
130
|
|
data/lib/mofa/runlist_map.rb
CHANGED
@@ -33,7 +33,7 @@ class RunlistMap
|
|
33
33
|
end
|
34
34
|
else
|
35
35
|
hostlist.list.each do |hostname|
|
36
|
-
@mp.store(hostname,
|
36
|
+
@mp.store(hostname, option_runlist)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -51,7 +51,6 @@ class RunlistMap
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
54
|
-
|
55
54
|
end
|
56
55
|
|
57
56
|
def set_default_runlist_for_every_host
|
@@ -62,5 +61,4 @@ class RunlistMap
|
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
65
|
-
|
66
64
|
end
|
data/lib/mofa/source_cookbook.rb
CHANGED
@@ -77,11 +77,11 @@ class SourceCookbook < Cookbook
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def cleanup!
|
80
|
-
unless (Dir.entries("#{Mofa::
|
81
|
-
say "Removing content of folder #{Mofa::
|
82
|
-
run "rm -r #{Mofa::
|
80
|
+
unless (Dir.entries("#{Mofa::CLI::option_tmp_dir}/.mofa") - %w{ . .. }).empty?
|
81
|
+
say "Removing content of folder #{Mofa::CLI::option_tmp_dir}/.mofa"
|
82
|
+
run "rm -r #{Mofa::CLI::option_tmp_dir}/.mofa/*"
|
83
83
|
else
|
84
|
-
say "Folder #{Mofa::
|
84
|
+
say "Folder #{Mofa::CLI::option_tmp_dir}/.mofa is (already) clean."
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
data/lib/mofa/upload_cmd.rb
CHANGED
data/lib/mofa/version.rb
CHANGED
data/mofa.gemspec
CHANGED
@@ -19,6 +19,8 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.add_development_dependency "guard-minitest"
|
20
20
|
s.add_development_dependency "rake"
|
21
21
|
s.add_runtime_dependency "thor"
|
22
|
+
# s.add_runtime_dependency "ed25519"
|
23
|
+
# s.add_runtime_dependency "bcrypt_pbkdf"
|
22
24
|
s.add_runtime_dependency "json"
|
23
25
|
s.add_runtime_dependency "rest-client"
|
24
26
|
s.add_runtime_dependency "net-ssh"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mofa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Birk
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -202,17 +202,21 @@ extra_rdoc_files: []
|
|
202
202
|
files:
|
203
203
|
- ".gitignore"
|
204
204
|
- ".rubocop.yml"
|
205
|
+
- ".ruby-version"
|
205
206
|
- ".travis.yml"
|
207
|
+
- Dockerfile
|
206
208
|
- Gemfile
|
207
209
|
- Guardfile
|
208
210
|
- LICENSE
|
209
211
|
- README.md
|
210
212
|
- Rakefile
|
211
213
|
- bin/mofa
|
214
|
+
- config.docker.yml
|
212
215
|
- config.yml.erb
|
213
216
|
- lib/mofa.rb
|
214
217
|
- lib/mofa/attributes_map.rb
|
215
218
|
- lib/mofa/cli.rb
|
219
|
+
- lib/mofa/cmd_line_args.rb
|
216
220
|
- lib/mofa/config.rb
|
217
221
|
- lib/mofa/cookbook.rb
|
218
222
|
- lib/mofa/hostlist.rb
|
@@ -225,12 +229,10 @@ files:
|
|
225
229
|
- lib/mofa/upload_cmd.rb
|
226
230
|
- lib/mofa/version.rb
|
227
231
|
- mofa.gemspec
|
228
|
-
- rspec/mofa/hostfile_spec.rb
|
229
|
-
- rspec/mofa/test_hostlist.json
|
230
232
|
homepage: https://github.com/pingworks/mofa
|
231
233
|
licenses: []
|
232
234
|
metadata: {}
|
233
|
-
post_install_message:
|
235
|
+
post_install_message:
|
234
236
|
rdoc_options: []
|
235
237
|
require_paths:
|
236
238
|
- lib
|
@@ -245,9 +247,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
245
247
|
- !ruby/object:Gem::Version
|
246
248
|
version: '0'
|
247
249
|
requirements: []
|
248
|
-
|
249
|
-
|
250
|
-
signing_key:
|
250
|
+
rubygems_version: 3.0.3
|
251
|
+
signing_key:
|
251
252
|
specification_version: 4
|
252
253
|
summary: a lightweight remote chef-solo runner
|
253
254
|
test_files: []
|
data/rspec/mofa/hostfile_spec.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'mofa/hostlist'
|
2
|
-
require 'mofa/config'
|
3
|
-
|
4
|
-
describe Hostlist do
|
5
|
-
before do
|
6
|
-
Mofa::Config.load
|
7
|
-
|
8
|
-
end
|
9
|
-
it "should initialize" do
|
10
|
-
hostlist = Hostlist.create("/.*/", "file://rspec/mofa/test_hostlist.json")
|
11
|
-
hostlist != nil
|
12
|
-
end
|
13
|
-
it "should retrieve" do
|
14
|
-
hostlist = Hostlist.create("/.*/", "file://rspec/mofa/test_hostlist.json")
|
15
|
-
puts hostlist.retrieve.count
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|