hocho 0.1.0.beta1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -5
- data/lib/hocho/command.rb +1 -4
- data/lib/hocho/drivers/base.rb +3 -0
- data/lib/hocho/drivers/bundler.rb +8 -44
- data/lib/hocho/drivers/mitamae.rb +87 -0
- data/lib/hocho/drivers/ssh_base.rb +122 -2
- data/lib/hocho/host.rb +48 -29
- data/lib/hocho/inventory.rb +14 -2
- data/lib/hocho/inventory_providers/file.rb +1 -1
- data/lib/hocho/property_providers.rb +1 -1
- data/lib/hocho/property_providers/add_default.rb +15 -0
- data/lib/hocho/runner.rb +4 -1
- data/lib/hocho/version.rb +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71a35bcabdd7fb28b6ddcde2093f7cdde9ddcafa
|
4
|
+
data.tar.gz: f4ac549145b6940d4bef0ade7b3338d3f89f2028
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5e35fb5d3d3263ae7fab63fb51d846ba3ce5bb41421dd43f8731dd256081f0e712f11c192aef676140ab8801adfc558927a71574fa5b32b5f7ef29f29dd2bd7
|
7
|
+
data.tar.gz: 82ecb70f5dbb71f3be59e3d5dd9c42e9c4d733604038d8d296eb94e2795e629dc779ede9de00df8ccf28efce72827ccdb4550d82854391c1ca06b3e929f49b97
|
data/README.md
CHANGED
@@ -4,14 +4,15 @@ Hocho is a wrapper of the provisioning tool [itamae](https://github.com/itamae-k
|
|
4
4
|
|
5
5
|
## Features
|
6
6
|
|
7
|
-
-
|
8
|
-
-
|
7
|
+
- Drivers
|
8
|
+
- `itamae ssh` support
|
9
|
+
- remote `itamae local` support on rsync+bundler
|
10
|
+
- remote `mitamae` support
|
9
11
|
- Simple pluggable host inventory, discovery
|
10
12
|
|
11
|
-
## vs. other softwares
|
12
|
-
|
13
13
|
## Installation
|
14
14
|
|
15
|
+
|
15
16
|
Add this line to your application's Gemfile:
|
16
17
|
|
17
18
|
```ruby
|
@@ -33,14 +34,24 @@ Or install it yourself as:
|
|
33
34
|
inventory_providers:
|
34
35
|
file:
|
35
36
|
path: './hosts'
|
37
|
+
property_providers:
|
38
|
+
- add_default:
|
39
|
+
properties:
|
40
|
+
blah: blahblah
|
41
|
+
# preferred_driver: mitamae
|
42
|
+
# driver_options:
|
43
|
+
# mitamae:
|
44
|
+
# mitamae_prepare_script: 'wget -O /usr/local/bin/mitamae https://...'
|
36
45
|
```
|
37
46
|
|
38
|
-
```
|
47
|
+
``` yaml
|
39
48
|
# ./hosts/test.yml
|
40
49
|
test.example.org:
|
41
50
|
# ssh_options:
|
42
51
|
# user: ...
|
43
52
|
properties:
|
53
|
+
# preferred_driver: bundler
|
54
|
+
# preferred_driver: mitamae
|
44
55
|
run_list:
|
45
56
|
- roles/app/default.rb
|
46
57
|
```
|
data/lib/hocho/command.rb
CHANGED
@@ -17,9 +17,6 @@ module Hocho
|
|
17
17
|
hosts = inventory.hosts
|
18
18
|
|
19
19
|
if options[:verbose]
|
20
|
-
hosts.each do |host|
|
21
|
-
config.property_providers.each { |_| _.determine(host) }
|
22
|
-
end
|
23
20
|
case options[:format]
|
24
21
|
when 'yaml'
|
25
22
|
puts hosts.map(&:to_h).to_yaml
|
@@ -82,7 +79,7 @@ module Hocho
|
|
82
79
|
private
|
83
80
|
|
84
81
|
def inventory
|
85
|
-
@inventory ||= Hocho::Inventory.new(config.inventory_providers)
|
82
|
+
@inventory ||= Hocho::Inventory.new(config.inventory_providers, config.property_providers)
|
86
83
|
end
|
87
84
|
|
88
85
|
def config
|
data/lib/hocho/drivers/base.rb
CHANGED
@@ -3,35 +3,22 @@ require 'hocho/drivers/ssh_base'
|
|
3
3
|
module Hocho
|
4
4
|
module Drivers
|
5
5
|
class Bundler < SshBase
|
6
|
-
def initialize(host, base_dir: '.', initializers: [], itamae_options: [], bundle_without: [], bundle_path: nil,
|
6
|
+
def initialize(host, base_dir: '.', initializers: [], itamae_options: [], bundle_without: [], bundle_path: nil, deploy_options: {})
|
7
7
|
super host, base_dir: base_dir, initializers: initializers
|
8
8
|
|
9
9
|
@itamae_options = itamae_options
|
10
10
|
@bundle_without = bundle_without
|
11
11
|
@bundle_path = bundle_path
|
12
|
-
@
|
13
|
-
@keep_synced_files = keep_synced_files
|
14
|
-
end
|
15
|
-
|
16
|
-
def keep_synced_files?
|
17
|
-
@keep_synced_files
|
12
|
+
@deploy_options = deploy_options
|
18
13
|
end
|
19
14
|
|
20
15
|
def run(dry_run: false)
|
21
|
-
deploy
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
cleanup
|
16
|
+
deploy(**@deploy_options) do
|
17
|
+
bundle_install
|
18
|
+
run_itamae(dry_run: dry_run)
|
19
|
+
end
|
26
20
|
end
|
27
21
|
|
28
|
-
def deploy
|
29
|
-
ssh_cmd = ['ssh', *host.openssh_config.flat_map { |l| ['-o', "\"#{l}\""] }].join(' ')
|
30
|
-
rsync_cmd = [*%w(rsync -az --copy-links --copy-unsafe-links --delete --exclude=.git), '--rsh', ssh_cmd, '.', "#{host.hostname}:#{host_basedir}"]
|
31
|
-
|
32
|
-
puts "=> $ #{rsync_cmd.inspect}"
|
33
|
-
system(*rsync_cmd, chdir: base_dir) or raise 'failed to rsync'
|
34
|
-
end
|
35
22
|
|
36
23
|
def bundle_install
|
37
24
|
bundle_path_env = @bundle_path ? "BUNDLE_PATH=#{@bundle_path.shellescape} " : nil
|
@@ -46,12 +33,7 @@ module Hocho
|
|
46
33
|
puts "=> #{host.name} # #{bundle_install.shelljoin}"
|
47
34
|
|
48
35
|
ssh_run("bash") do |c|
|
49
|
-
c
|
50
|
-
puts "[#{host.name}] #{data}"
|
51
|
-
end
|
52
|
-
c.on_extended_data do |c, _, data|
|
53
|
-
puts "[#{host.name}/ERR] #{data}"
|
54
|
-
end
|
36
|
+
set_ssh_output_hook(c)
|
55
37
|
|
56
38
|
c.send_data("cd #{host_basedir.shellescape}\n#{sudovars}\n#{sudocmd}#{bundle_install.shelljoin}\n")
|
57
39
|
c.eof!
|
@@ -69,12 +51,7 @@ module Hocho
|
|
69
51
|
prepare_sudo do |sh, sudovars, sudocmd|
|
70
52
|
puts "=> #{host.name} # #{host.bundler_cmd} exec #{itamae_cmd.shelljoin}"
|
71
53
|
ssh_run("bash") do |c|
|
72
|
-
c
|
73
|
-
puts "[#{host.name}] #{data}"
|
74
|
-
end
|
75
|
-
c.on_extended_data do |c, _, data|
|
76
|
-
puts "[#{host.name}/ERR] #{data}"
|
77
|
-
end
|
54
|
+
set_ssh_output_hook(c)
|
78
55
|
|
79
56
|
c.send_data("cd #{host_basedir.shellescape}\n#{sudovars}\n#{sudocmd}#{host.bundler_cmd} exec #{itamae_cmd.shelljoin}\n")
|
80
57
|
c.eof!
|
@@ -82,19 +59,6 @@ module Hocho
|
|
82
59
|
end
|
83
60
|
end
|
84
61
|
end
|
85
|
-
|
86
|
-
def cleanup
|
87
|
-
return unless !keep_synced_files? || !deploy_dir
|
88
|
-
|
89
|
-
cmd = "rm -rf #{host_basedir.shellescape}"
|
90
|
-
puts "=> #{host.name} $ #{cmd}"
|
91
|
-
ssh_run(cmd, error: false)
|
92
|
-
end
|
93
|
-
|
94
|
-
def host_basedir
|
95
|
-
@deploy_dir || "#{host_tmpdir}/itamae"
|
96
|
-
end
|
97
|
-
|
98
62
|
end
|
99
63
|
end
|
100
64
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'hocho/drivers/ssh_base'
|
2
|
+
|
3
|
+
module Hocho
|
4
|
+
module Drivers
|
5
|
+
class Mitamae < SshBase
|
6
|
+
def initialize(host, base_dir: '.', mitamae_path: 'mitamae', mitamae_prepare_script: [], mitamae_outdate_check_script: nil, initializers: [], mitamae_options: [], deploy_options: {})
|
7
|
+
super host, base_dir: base_dir, initializers: initializers
|
8
|
+
|
9
|
+
@mitamae_path = mitamae_path
|
10
|
+
@mitamae_prepare_script = mitamae_prepare_script
|
11
|
+
@mitamae_outdate_check_script = mitamae_outdate_check_script
|
12
|
+
@mitamae_options = mitamae_options
|
13
|
+
@deploy_options = deploy_options
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def run(dry_run: false)
|
18
|
+
deploy(**@deploy_options) do
|
19
|
+
prepare_mitamae
|
20
|
+
run_mitamae(dry_run: dry_run)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def mitamae_available?
|
25
|
+
exitstatus, _ = if @mitamae_path.start_with?('/')
|
26
|
+
ssh_run("test -x #{@mitamae_path.shellescape}", error: false)
|
27
|
+
else
|
28
|
+
ssh_run("which #{@mitamae_path.shellescape} 2>/dev/null >/dev/null", error: false)
|
29
|
+
end
|
30
|
+
exitstatus == 0
|
31
|
+
end
|
32
|
+
|
33
|
+
def mitamae_outdated?
|
34
|
+
if @mitamae_outdate_check_script
|
35
|
+
exitstatus, _ = ssh_run("export HOCHO_MITAMAE_PATH=#{@mitamae_path.shellescape}; #{@mitamae_outdate_check_script}", error: false)
|
36
|
+
exitstatus == 0
|
37
|
+
else
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def prepare_mitamae
|
43
|
+
return if mitamae_available? && !mitamae_outdated?
|
44
|
+
script = [*@mitamae_prepare_script].join("\n\n")
|
45
|
+
if script.empty?
|
46
|
+
raise "We have to prepare MItamae, but not mitamae_prepare_script is specified"
|
47
|
+
end
|
48
|
+
prepare_sudo do |sh, sudovars, sudocmd|
|
49
|
+
log_prefix = "=> #{host.name} # "
|
50
|
+
log_prefix_white = ' ' * log_prefix.size
|
51
|
+
puts "#{log_prefix}#{script.each_line.map{ |_| "#{log_prefix_white}#{_.chomp}" }.join("\n")}"
|
52
|
+
|
53
|
+
ssh_run("bash") do |c|
|
54
|
+
set_ssh_output_hook(c)
|
55
|
+
|
56
|
+
c.send_data("cd #{host_basedir.shellescape}\n#{sudovars}\n#{sudocmd} bash <<-'HOCHOEOS'\n#{script}HOCHOEOS\n")
|
57
|
+
c.eof!
|
58
|
+
end
|
59
|
+
end
|
60
|
+
availability, outdated = mitamae_available?, mitamae_outdated?
|
61
|
+
if !availability || outdated
|
62
|
+
status = [availability ? nil : 'unavailable', outdated ? 'outdated' : nil].compact.join(' and ')
|
63
|
+
raise "prepared MItamae, but it's still #{status}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def run_mitamae(dry_run: false)
|
68
|
+
with_host_node_json_file do
|
69
|
+
itamae_cmd = [@mitamae_path, 'local', '-j', host_node_json_path, *@mitamae_options]
|
70
|
+
itamae_cmd.push('--dry-run') if dry_run
|
71
|
+
# itamae_cmd.push('--color') if $stdout.tty?
|
72
|
+
itamae_cmd.push(*run_list)
|
73
|
+
|
74
|
+
prepare_sudo do |sh, sudovars, sudocmd|
|
75
|
+
puts "=> #{host.name} # #{itamae_cmd.shelljoin}"
|
76
|
+
ssh_run("bash") do |c|
|
77
|
+
set_ssh_output_hook(c)
|
78
|
+
|
79
|
+
c.send_data("cd #{host_basedir.shellescape}\n#{sudovars}\n#{sudocmd} #{itamae_cmd.shelljoin}\n")
|
80
|
+
c.eof!
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -9,6 +9,47 @@ module Hocho
|
|
9
9
|
host.ssh_connection
|
10
10
|
end
|
11
11
|
|
12
|
+
def finalize
|
13
|
+
remove_host_tmpdir!
|
14
|
+
remove_host_shmdir!
|
15
|
+
end
|
16
|
+
|
17
|
+
def deploy(deploy_dir: nil, shm_prefix: [])
|
18
|
+
@host_basedir = deploy_dir if deploy_dir
|
19
|
+
|
20
|
+
shm_prefix = [*shm_prefix]
|
21
|
+
|
22
|
+
ssh_cmd = ['ssh', *host.openssh_config.flat_map { |l| ['-o', "\"#{l}\""] }].join(' ')
|
23
|
+
shm_exclude = shm_prefix.map{ |_| "--exclude=#{_}" }
|
24
|
+
rsync_cmd = [*%w(rsync -az --copy-links --copy-unsafe-links --delete --exclude=.git), *shm_exclude, '--rsh', ssh_cmd, '.', "#{host.hostname}:#{host_basedir}"]
|
25
|
+
|
26
|
+
puts "=> $ #{rsync_cmd.shelljoin}"
|
27
|
+
system(*rsync_cmd, chdir: base_dir) or raise 'failed to rsync'
|
28
|
+
|
29
|
+
unless shm_prefix.empty?
|
30
|
+
shm_include = shm_prefix.map{ |_| "--include=#{_.sub(%r{/\z},'')}/***" }
|
31
|
+
rsync_cmd = [*%w(rsync -az --copy-links --copy-unsafe-links --delete), *shm_include, '--exclude=*', '--rsh', ssh_cmd, '.', "#{host.hostname}:#{host_shm_basedir}"]
|
32
|
+
puts "=> $ #{rsync_cmd.shelljoin}"
|
33
|
+
system(*rsync_cmd, chdir: base_dir) or raise 'failed to rsync'
|
34
|
+
shm_prefix.each do |x|
|
35
|
+
mkdir = if %r{\A[^/].*\/.+\z} === x
|
36
|
+
%Q(mkdir -vp "$(basename #{x.shellescape})" &&)
|
37
|
+
else
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
ssh_run(%Q(cd #{host_basedir} && #{mkdir} ln -sfv #{host_shm_basedir}/#{x.shellescape} ./#{x.sub(%r{/\z},'').shellescape}))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
yield
|
45
|
+
ensure
|
46
|
+
if !deploy_dir || !keep_synced_files
|
47
|
+
cmd = "rm -rf #{host_basedir.shellescape}"
|
48
|
+
puts "=> #{host.name} $ #{cmd}"
|
49
|
+
ssh_run(cmd, error: false)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
12
53
|
private
|
13
54
|
|
14
55
|
def prepare_sudo(password = host.sudo_password)
|
@@ -35,7 +76,8 @@ module Hocho
|
|
35
76
|
end
|
36
77
|
|
37
78
|
begin
|
38
|
-
|
79
|
+
tmpdir = host_shmdir ? "TMPDIR=#{host_shmdir.shellescape} " : nil
|
80
|
+
temp_executable = ssh.exec!("#{tmpdir}mktemp").chomp
|
39
81
|
raise unless temp_executable.start_with?('/')
|
40
82
|
|
41
83
|
ssh_run("chmod 0700 #{temp_executable.shellescape}; cat > #{temp_executable.shellescape}; chmod +x #{temp_executable.shellescape}") do |ch|
|
@@ -53,6 +95,69 @@ module Hocho
|
|
53
95
|
end
|
54
96
|
end
|
55
97
|
|
98
|
+
def set_ssh_output_hook(c)
|
99
|
+
outbuf, errbuf = [], []
|
100
|
+
check = ->(prefix,data,buf) do
|
101
|
+
has_newline = data.include?("\n")
|
102
|
+
lines = data.lines
|
103
|
+
last = lines.pop
|
104
|
+
if last[-1] == "\n"
|
105
|
+
buf << last
|
106
|
+
end
|
107
|
+
if has_newline
|
108
|
+
(buf+lines).join.each_line do |line|
|
109
|
+
puts "#{prefix} #{line}"
|
110
|
+
end
|
111
|
+
buf.replace([])
|
112
|
+
end
|
113
|
+
if last[-1] != "\n"
|
114
|
+
buf << last
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
c.on_data do |c, data|
|
119
|
+
check.call "[#{host.name}] ", data, outbuf
|
120
|
+
end
|
121
|
+
c.on_extended_data do |c, _, data|
|
122
|
+
check.call "[#{host.name}/ERR] ", data, errbuf
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def host_basedir
|
127
|
+
@host_basedir || "#{host_tmpdir}/itamae"
|
128
|
+
end
|
129
|
+
|
130
|
+
def host_shm_basedir
|
131
|
+
host_shmdir && "#{host_shmdir}/itamae"
|
132
|
+
end
|
133
|
+
|
134
|
+
def host_shmdir
|
135
|
+
return @host_shmdir if @host_shmdir
|
136
|
+
return nil if @host_shmdir == false
|
137
|
+
|
138
|
+
shmdir = host.shmdir
|
139
|
+
unless shmdir
|
140
|
+
if ssh.exec!('uname').chomp == 'Linux'
|
141
|
+
shmdir = '/dev/shm'
|
142
|
+
mount = ssh.exec!("grep -F #{shmdir.shellescape} /proc/mounts").each_line.map{ |_| _.chomp.split(' ') }
|
143
|
+
unless mount.find { |_| _[1] == shmdir }&.first == 'tmpfs'
|
144
|
+
@host_shmdir = false
|
145
|
+
return nil
|
146
|
+
end
|
147
|
+
else
|
148
|
+
@host_shmdir = false
|
149
|
+
return nil
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
mktemp_cmd = "TMPDIR=#{shmdir.shellescape} #{%w(mktemp -d -t hocho-run-XXXXXXXXX).shelljoin}"
|
154
|
+
|
155
|
+
res = ssh.exec!(mktemp_cmd)
|
156
|
+
unless res.start_with?(shmdir)
|
157
|
+
raise "Failed to shm mktemp #{mktemp_cmd.inspect} -> #{res.inspect}"
|
158
|
+
end
|
159
|
+
@host_shmdir = res.chomp
|
160
|
+
end
|
56
161
|
|
57
162
|
def host_tmpdir
|
58
163
|
@host_tmpdir ||= begin
|
@@ -60,13 +165,28 @@ module Hocho
|
|
60
165
|
mktemp_cmd.prepend("TMPDIR=#{host.tmpdir.shellescape} ") if host.tmpdir
|
61
166
|
|
62
167
|
res = ssh.exec!(mktemp_cmd)
|
63
|
-
unless res.start_with?('/
|
168
|
+
unless res.start_with?(host.tmpdir || '/')
|
64
169
|
raise "Failed to mktemp #{mktemp_cmd.inspect} -> #{res.inspect}"
|
65
170
|
end
|
66
171
|
res.chomp
|
67
172
|
end
|
68
173
|
end
|
69
174
|
|
175
|
+
def remove_host_tmpdir!
|
176
|
+
if @host_tmpdir
|
177
|
+
host_tmpdir, @host_tmpdir = @host_tmpdir, nil
|
178
|
+
ssh.exec!("rm -rf #{host_tmpdir.shellescape}")
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def remove_host_shmdir!
|
183
|
+
if @host_shmdir
|
184
|
+
host_shmdir, @host_shmdir = @host_shmdir, nil
|
185
|
+
ssh.exec!("rm -rf #{host_shmdir.shellescape}")
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
|
70
190
|
def host_node_json_path
|
71
191
|
"#{host_tmpdir}/node.json"
|
72
192
|
end
|
data/lib/hocho/host.rb
CHANGED
@@ -5,28 +5,34 @@ require 'net/ssh/proxy/command'
|
|
5
5
|
|
6
6
|
module Hocho
|
7
7
|
class Host
|
8
|
-
def initialize(name, provider: nil, properties: {}, tags: {}, ssh_options: nil, tmpdir: nil, sudo_password: nil)
|
8
|
+
def initialize(name, provider: nil, providers: nil, properties: {}, tags: {}, ssh_options: nil, tmpdir: nil, shmdir: nil, sudo_password: nil)
|
9
|
+
if provider
|
10
|
+
warn "DEPRECATION WARNING: #{caller[1]}: Hocho::Host.new(provider:) is deprecated. Use providers: instead "
|
11
|
+
end
|
12
|
+
|
9
13
|
@name = name
|
10
|
-
@
|
14
|
+
@providers = [*provider, *providers]
|
11
15
|
self.properties = properties
|
12
16
|
@tags = tags
|
13
17
|
@override_ssh_options = ssh_options
|
14
18
|
@tmpdir = tmpdir
|
19
|
+
@shmdir = shmdir
|
15
20
|
@sudo_password = sudo_password
|
16
21
|
end
|
17
22
|
|
18
|
-
attr_reader :name, :
|
23
|
+
attr_reader :name, :providers, :properties, :tmpdir, :shmdir
|
19
24
|
attr_writer :sudo_password
|
20
25
|
attr_accessor :tags
|
21
26
|
|
22
27
|
def to_h
|
23
28
|
{
|
24
29
|
name: name,
|
25
|
-
|
30
|
+
providers: providers,
|
26
31
|
tags: tags.to_h,
|
27
32
|
properties: properties.to_h,
|
28
33
|
}.tap do |h|
|
29
34
|
h[:tmpdir] = tmpdir if tmpdir
|
35
|
+
h[:shmdir] = shmdir if shmdir
|
30
36
|
h[:ssh_options] = @override_ssh_options if @override_ssh_options
|
31
37
|
end
|
32
38
|
end
|
@@ -35,12 +41,23 @@ module Hocho
|
|
35
41
|
@properties = Hashie::Mash.new(other)
|
36
42
|
end
|
37
43
|
|
38
|
-
def
|
44
|
+
def merge!(other)
|
45
|
+
@tags.merge!(other.tags)
|
46
|
+
@tmpdir = other.tmpdir if other.tmpdir
|
47
|
+
@shmdir = other.shmdir if other.shmdir
|
48
|
+
@properties.merge(other.properties)
|
49
|
+
end
|
50
|
+
|
51
|
+
def apply_property_providers(providers)
|
39
52
|
providers.each do |provider|
|
40
53
|
provider.determine(self)
|
41
54
|
end
|
42
55
|
end
|
43
56
|
|
57
|
+
def ssh_name
|
58
|
+
properties[:ssh_name] || name
|
59
|
+
end
|
60
|
+
|
44
61
|
def run_list
|
45
62
|
properties[:run_list] || []
|
46
63
|
end
|
@@ -58,70 +75,72 @@ module Hocho
|
|
58
75
|
end
|
59
76
|
|
60
77
|
def ssh_options
|
61
|
-
(Net::SSH::Config.for(
|
78
|
+
(Net::SSH::Config.for(ssh_name) || {}).merge(Hocho::Utils::Symbolize.keys_of(properties[:ssh_options] || {})).merge(@override_ssh_options || {})
|
62
79
|
end
|
63
80
|
|
64
|
-
def openssh_config
|
81
|
+
def openssh_config(separator='=')
|
65
82
|
ssh_options.flat_map do |key, value|
|
66
83
|
case key
|
67
84
|
when :encryption
|
68
|
-
|
85
|
+
[["Ciphers", [*value].join(?,)]]
|
69
86
|
when :compression
|
70
|
-
|
87
|
+
[["Compression", value]]
|
71
88
|
when :compression_level
|
72
|
-
|
89
|
+
[["CompressionLevel", value]]
|
73
90
|
when :timeout
|
74
|
-
|
91
|
+
[["ConnectTimeout", value]]
|
75
92
|
when :forward_agent
|
76
|
-
|
93
|
+
[["ForwardAgent", value ? 'yes' : 'no']]
|
77
94
|
when :keys_only
|
78
|
-
|
95
|
+
[["IdentitiesOnly", value ? 'yes' : 'no']]
|
79
96
|
when :global_known_hosts_file
|
80
|
-
|
97
|
+
[["GlobalKnownHostsFile", value]]
|
81
98
|
when :auth_methods
|
82
99
|
[].tap do |lines|
|
83
100
|
methods = value.dup
|
84
101
|
value.each do |val|
|
85
102
|
case val
|
86
103
|
when 'hostbased'
|
87
|
-
lines << "HostBasedAuthentication yes"
|
104
|
+
lines << ["HostBasedAuthentication", "yes"]
|
88
105
|
when 'password'
|
89
|
-
lines << "PasswordAuthentication yes"
|
106
|
+
lines << ["PasswordAuthentication", "yes"]
|
90
107
|
when 'publickey'
|
91
|
-
lines << "PubkeyAuthentication yes"
|
108
|
+
lines << ["PubkeyAuthentication", "yes"]
|
92
109
|
end
|
93
110
|
end
|
94
111
|
unless methods.empty?
|
95
|
-
lines << "PreferredAuthentications
|
112
|
+
lines << ["PreferredAuthentications", methods.join(?,)]
|
96
113
|
end
|
97
114
|
end
|
98
115
|
when :host_key
|
99
|
-
|
116
|
+
[["HostKeyAlgorithms", [*value].join(?,)]]
|
100
117
|
when :host_key_alias
|
101
|
-
|
118
|
+
[["HostKeyAlias", value]]
|
102
119
|
when :host_name
|
103
|
-
|
120
|
+
[["HostName", value]]
|
104
121
|
when :keys
|
105
122
|
[*value].map do |val|
|
106
|
-
|
123
|
+
["IdentityFile", val]
|
107
124
|
end
|
108
125
|
when :hmac
|
109
|
-
|
126
|
+
[["Macs", [*value].join(?,)]]
|
110
127
|
when :port
|
111
|
-
|
128
|
+
[["Port", value]]
|
112
129
|
when :proxy
|
113
130
|
if value.kind_of?(Net::SSH::Proxy::Command)
|
114
|
-
|
131
|
+
[["ProxyCommand", value.command_line_template]]
|
115
132
|
else
|
116
|
-
|
133
|
+
[["ProxyCommand", value]]
|
117
134
|
end
|
118
135
|
when :rekey_limit
|
119
|
-
|
136
|
+
[["RekeyLimit", value]]
|
120
137
|
when :user
|
121
|
-
|
138
|
+
[["User", value]]
|
122
139
|
when :user_known_hosts_file
|
123
|
-
|
140
|
+
[["UserKnownHostsFile", value]]
|
124
141
|
end
|
142
|
+
end.compact.map do |keyval|
|
143
|
+
keyval.join(separator)
|
125
144
|
end
|
126
145
|
end
|
127
146
|
|
data/lib/hocho/inventory.rb
CHANGED
@@ -1,11 +1,23 @@
|
|
1
1
|
module Hocho
|
2
2
|
class Inventory
|
3
|
-
def initialize(providers)
|
3
|
+
def initialize(providers, property_providers)
|
4
4
|
@providers = providers
|
5
|
+
@property_providers = property_providers
|
5
6
|
end
|
6
7
|
|
7
8
|
def hosts
|
8
|
-
@hosts ||= @providers.
|
9
|
+
@hosts ||= @providers.inject({}) do |r,provider|
|
10
|
+
provider.hosts.each do |host|
|
11
|
+
if r.key?(host.name)
|
12
|
+
r[host.name].merge!(host)
|
13
|
+
else
|
14
|
+
r[host.name] = host
|
15
|
+
end
|
16
|
+
end
|
17
|
+
r
|
18
|
+
end.each do |name, host|
|
19
|
+
host.apply_property_providers(@property_providers)
|
20
|
+
end.values
|
9
21
|
end
|
10
22
|
|
11
23
|
def filter(filters)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'hocho/property_providers/base'
|
2
|
+
|
3
|
+
module Hocho
|
4
|
+
module PropertyProviders
|
5
|
+
class AddDefault < Base
|
6
|
+
def initialize(properties: {})
|
7
|
+
@properties = properties
|
8
|
+
end
|
9
|
+
|
10
|
+
def determine(host)
|
11
|
+
host.properties.replace(host.properties.reverse_merge(@properties))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/hocho/runner.rb
CHANGED
@@ -18,7 +18,10 @@ module Hocho
|
|
18
18
|
def run(dry_run: false)
|
19
19
|
puts "Running using #{best_driver_name}"
|
20
20
|
driver_options = @driver_options[best_driver_name] || {}
|
21
|
-
best_driver.new(host, base_dir: base_dir, initializers: initializers, **driver_options)
|
21
|
+
driver = best_driver.new(host, base_dir: base_dir, initializers: initializers, **driver_options)
|
22
|
+
driver.run(dry_run: dry_run)
|
23
|
+
ensure
|
24
|
+
driver.finalize if driver
|
22
25
|
end
|
23
26
|
|
24
27
|
# def check_ssh_port
|
data/lib/hocho/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hocho
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sorah (Shota Fukumori)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- lib/hocho/drivers/base.rb
|
133
133
|
- lib/hocho/drivers/bundler.rb
|
134
134
|
- lib/hocho/drivers/itamae_ssh.rb
|
135
|
+
- lib/hocho/drivers/mitamae.rb
|
135
136
|
- lib/hocho/drivers/ssh_base.rb
|
136
137
|
- lib/hocho/host.rb
|
137
138
|
- lib/hocho/inventory.rb
|
@@ -139,6 +140,7 @@ files:
|
|
139
140
|
- lib/hocho/inventory_providers/base.rb
|
140
141
|
- lib/hocho/inventory_providers/file.rb
|
141
142
|
- lib/hocho/property_providers.rb
|
143
|
+
- lib/hocho/property_providers/add_default.rb
|
142
144
|
- lib/hocho/property_providers/base.rb
|
143
145
|
- lib/hocho/runner.rb
|
144
146
|
- lib/hocho/utils/finder.rb
|
@@ -161,12 +163,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
161
163
|
version: '0'
|
162
164
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
165
|
requirements:
|
164
|
-
- - "
|
166
|
+
- - ">="
|
165
167
|
- !ruby/object:Gem::Version
|
166
|
-
version:
|
168
|
+
version: '0'
|
167
169
|
requirements: []
|
168
170
|
rubyforge_project:
|
169
|
-
rubygems_version: 2.6.
|
171
|
+
rubygems_version: 2.6.8
|
170
172
|
signing_key:
|
171
173
|
specification_version: 4
|
172
174
|
summary: Server provisioning tool with itamae
|