specinfra 2.25.1 → 2.26.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/specinfra/backend/base.rb +31 -29
- data/lib/specinfra/backend/docker.rb +87 -85
- data/lib/specinfra/backend/dockerfile.rb +25 -24
- data/lib/specinfra/backend/exec.rb +58 -56
- data/lib/specinfra/backend/lxc.rb +34 -32
- data/lib/specinfra/backend/shell_script.rb +19 -17
- data/lib/specinfra/backend/ssh.rb +131 -129
- data/lib/specinfra/backend/telnet.rb +87 -85
- data/lib/specinfra/backend/winrm.rb +19 -17
- data/lib/specinfra/command/module/systemd.rb +44 -37
- data/lib/specinfra/command/module/zfs.rb +21 -14
- data/lib/specinfra/command/module.rb +6 -1
- data/lib/specinfra/command.rb +4 -1
- data/lib/specinfra/core.rb +18 -0
- data/lib/specinfra/ext/class.rb +9 -0
- data/lib/specinfra/ext/string.rb +14 -0
- data/lib/specinfra/ext.rb +2 -0
- data/lib/specinfra/helper/detect_os.rb +15 -13
- data/lib/specinfra/helper/os.rb +21 -16
- data/lib/specinfra/helper/set.rb +8 -3
- data/lib/specinfra/version.rb +1 -1
- data/lib/specinfra.rb +1 -38
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4aa147d96470a2427c0fa6e4935a0bb9d6f7b8c
|
4
|
+
data.tar.gz: 93a02c122359e5881ab9983cb7fce3cb34e78f5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c581e6ffa5a7a7fa5bf00f5320a05a358d54fe0a61d2233bcdcef6acc37d1310365527b67967ae2d12c460d7ac17c4c2bd768721b8b1a5c662a35e98e2ddebbd
|
7
|
+
data.tar.gz: db718882e9224df3f6adef39d750c19d253cbc18ce1a39f1cda229c04455928f3247ed554c61c3d2d6725742b9fdd64f450734cd718cd30b700d161daa63e143
|
@@ -1,45 +1,47 @@
|
|
1
1
|
require 'singleton'
|
2
2
|
require 'specinfra/command_result'
|
3
3
|
|
4
|
-
module Specinfra
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
module Specinfra
|
5
|
+
module Backend
|
6
|
+
class Base
|
7
|
+
def self.instance
|
8
|
+
@instance ||= self.new
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
def initialize(config = {})
|
12
|
+
@config = config
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
def get_config(key)
|
16
|
+
@config[key] || Specinfra.configuration.send(key)
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
def set_config(key, value)
|
20
|
+
@config[key] = value
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
def os_info
|
24
|
+
return @os_info if @os_info
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
Specinfra::Helper::DetectOs.subclasses.each do |klass|
|
27
|
+
if @os_info = klass.new(self).detect
|
28
|
+
@os_info[:arch] ||= self.run_command('uname -m').stdout.strip
|
29
|
+
return @os_info
|
30
|
+
end
|
29
31
|
end
|
30
32
|
end
|
31
|
-
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
def command
|
35
|
+
CommandFactory.new(os_info)
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
def host_inventory
|
39
|
+
@inventory ||= HostInventory.new(self)
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
42
|
+
def set_example(e)
|
43
|
+
@example = e
|
44
|
+
end
|
43
45
|
end
|
44
46
|
end
|
45
47
|
end
|
@@ -1,109 +1,111 @@
|
|
1
|
-
module Specinfra
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
module Specinfra
|
2
|
+
module Backend
|
3
|
+
class Docker < Exec
|
4
|
+
def initialize(config = {})
|
5
|
+
super
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'docker' unless defined?(::Docker)
|
9
|
+
rescue LoadError
|
10
|
+
fail "Docker client library is not available. Try installing `docker-api' gem."
|
11
|
+
end
|
12
|
+
|
13
|
+
::Docker.url = get_config(:docker_url)
|
14
|
+
|
15
|
+
if image = get_config(:docker_image)
|
16
|
+
@images = []
|
17
|
+
@base_image = get_or_pull_image(image)
|
18
|
+
|
19
|
+
create_and_start_container
|
20
|
+
ObjectSpace.define_finalizer(self, proc { cleanup_container })
|
21
|
+
elsif container = get_config(:docker_container)
|
22
|
+
@container = ::Docker::Container.get(container)
|
23
|
+
else
|
24
|
+
fail 'Please specify docker_image or docker_container.'
|
25
|
+
end
|
10
26
|
end
|
11
27
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@base_image = get_or_pull_image(image)
|
17
|
-
|
18
|
-
create_and_start_container
|
19
|
-
ObjectSpace.define_finalizer(self, proc { cleanup_container })
|
20
|
-
elsif container = get_config(:docker_container)
|
21
|
-
@container = ::Docker::Container.get(container)
|
22
|
-
else
|
23
|
-
fail 'Please specify docker_image or docker_container.'
|
28
|
+
def run_command(cmd, opts={})
|
29
|
+
cmd = build_command(cmd)
|
30
|
+
cmd = add_pre_command(cmd)
|
31
|
+
docker_run!(cmd)
|
24
32
|
end
|
25
|
-
end
|
26
33
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
docker_run!(cmd)
|
31
|
-
end
|
34
|
+
def build_command(cmd)
|
35
|
+
cmd
|
36
|
+
end
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
|
38
|
+
def add_pre_command(cmd)
|
39
|
+
cmd
|
40
|
+
end
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
|
42
|
+
def send_file(from, to)
|
43
|
+
if @base_image.nil?
|
44
|
+
fail 'Cannot call send_file without docker_image.'
|
45
|
+
end
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
@images << current_image.insert_local('localPath' => from, 'outputPath' => to)
|
48
|
+
cleanup_container
|
49
|
+
create_and_start_container
|
44
50
|
end
|
45
51
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
def commit_container
|
52
|
-
@container.commit
|
53
|
-
end
|
52
|
+
def commit_container
|
53
|
+
@container.commit
|
54
|
+
end
|
54
55
|
|
55
|
-
|
56
|
+
private
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
def create_and_start_container
|
59
|
+
opts = { 'Image' => current_image.id }
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
61
|
+
if current_image.json["Config"]["Cmd"].nil?
|
62
|
+
opts.merge!({'Cmd' => ['/bin/sh']})
|
63
|
+
end
|
63
64
|
|
64
|
-
|
65
|
+
opts.merge!({'OpenStdin' => true})
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
67
|
+
if path = get_config(:path)
|
68
|
+
(opts['Env'] ||= []) << "PATH=#{path}"
|
69
|
+
end
|
69
70
|
|
70
|
-
|
71
|
-
|
71
|
+
env = get_config(:env).to_a.map { |v| v.join('=') }
|
72
|
+
opts['Env'] = opts['Env'].to_a.concat(env)
|
72
73
|
|
73
|
-
|
74
|
+
opts.merge!(get_config(:docker_container_create_options) || {})
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
76
|
+
@container = ::Docker::Container.create(opts)
|
77
|
+
@container.start
|
78
|
+
end
|
78
79
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
def cleanup_container
|
81
|
+
@container.stop
|
82
|
+
@container.delete
|
83
|
+
end
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
|
85
|
+
def current_image
|
86
|
+
@images.last || @base_image
|
87
|
+
end
|
87
88
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
89
|
+
def docker_run!(cmd, opts={})
|
90
|
+
stdout, stderr, status = @container.exec(['/bin/sh', '-c', cmd])
|
91
|
+
|
92
|
+
CommandResult.new :stdout => stdout.join, :stderr => stderr.join,
|
93
|
+
:exit_status => status
|
94
|
+
rescue ::Docker::Error::DockerError => e
|
95
|
+
raise
|
96
|
+
rescue => e
|
97
|
+
@container.kill
|
98
|
+
err = stderr.nil? ? ([e.message] + e.backtrace) : stderr
|
99
|
+
CommandResult.new :stdout => [stdout].join, :stderr => err.join,
|
100
|
+
:exit_status => (status || 1)
|
101
|
+
end
|
101
102
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
103
|
+
def get_or_pull_image(name)
|
104
|
+
begin
|
105
|
+
::Docker::Image.get(name)
|
106
|
+
rescue ::Docker::Error::NotFoundError
|
107
|
+
::Docker::Image.create('fromImage' => name)
|
108
|
+
end
|
107
109
|
end
|
108
110
|
end
|
109
111
|
end
|
@@ -1,31 +1,32 @@
|
|
1
|
-
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
module Specinfra
|
2
|
+
module Backend
|
3
|
+
class Dockerfile < Specinfra::Backend::Base
|
4
|
+
def initialize(config = {})
|
5
|
+
super
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
@lines = []
|
8
|
+
ObjectSpace.define_finalizer(self) {
|
9
|
+
if get_config(:dockerfile_finalizer).nil?
|
10
|
+
puts @lines
|
11
|
+
else
|
12
|
+
get_config(:dockerfile_finalizer).call(@lines)
|
13
|
+
end
|
14
|
+
}
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
def run_command(cmd, opts={})
|
18
|
+
@lines << "RUN #{cmd}"
|
19
|
+
CommandResult.new
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
def send_file(from, to)
|
23
|
+
@lines << "ADD #{from} #{to}"
|
24
|
+
CommandResult.new
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
def from(base)
|
28
|
+
@lines << "FROM #{base}"
|
29
|
+
end
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
@@ -2,77 +2,79 @@ require 'singleton'
|
|
2
2
|
require 'fileutils'
|
3
3
|
require 'shellwords'
|
4
4
|
|
5
|
-
module Specinfra
|
6
|
-
|
7
|
-
|
8
|
-
cmd =
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
module Specinfra
|
6
|
+
module Backend
|
7
|
+
class Exec < Base
|
8
|
+
def run_command(cmd, opts={})
|
9
|
+
cmd = build_command(cmd)
|
10
|
+
cmd = add_pre_command(cmd)
|
11
|
+
stdout = with_env do
|
12
|
+
`#{build_command(cmd)} 2>&1`
|
13
|
+
end
|
14
|
+
# In ruby 1.9, it is possible to use Open3.capture3, but not in 1.8
|
15
|
+
# stdout, stderr, status = Open3.capture3(cmd)
|
16
|
+
|
17
|
+
if @example
|
18
|
+
@example.metadata[:command] = cmd
|
19
|
+
@example.metadata[:stdout] = stdout
|
20
|
+
end
|
15
21
|
|
16
|
-
|
17
|
-
@example.metadata[:command] = cmd
|
18
|
-
@example.metadata[:stdout] = stdout
|
22
|
+
CommandResult.new :stdout => stdout, :exit_status => $?.exitstatus
|
19
23
|
end
|
20
24
|
|
21
|
-
|
22
|
-
|
25
|
+
def send_file(from, to)
|
26
|
+
FileUtils.cp(from, to)
|
27
|
+
end
|
23
28
|
|
24
|
-
|
25
|
-
|
26
|
-
|
29
|
+
def send_directory(from, to)
|
30
|
+
FileUtils.cp_r(from, to)
|
31
|
+
end
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
|
33
|
+
def build_command(cmd)
|
34
|
+
shell = get_config(:shell) || '/bin/sh'
|
35
|
+
cmd = cmd.shelljoin if cmd.is_a?(Array)
|
36
|
+
cmd = "#{shell.shellescape} -c #{cmd.to_s.shellescape}"
|
31
37
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
38
|
+
path = get_config(:path)
|
39
|
+
if path
|
40
|
+
cmd = %Q{env PATH="#{path}" #{cmd}}
|
41
|
+
end
|
36
42
|
|
37
|
-
|
38
|
-
if path
|
39
|
-
cmd = %Q{env PATH="#{path}" #{cmd}}
|
43
|
+
cmd
|
40
44
|
end
|
41
45
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
def with_env
|
47
|
-
keys = %w[BUNDLER_EDITOR BUNDLE_BIN_PATH BUNDLE_GEMFILE
|
48
|
-
RUBYOPT GEM_HOME GEM_PATH GEM_CACHE]
|
46
|
+
private
|
47
|
+
def with_env
|
48
|
+
keys = %w[BUNDLER_EDITOR BUNDLE_BIN_PATH BUNDLE_GEMFILE
|
49
|
+
RUBYOPT GEM_HOME GEM_PATH GEM_CACHE]
|
49
50
|
|
50
|
-
|
51
|
+
keys.each { |key| ENV["_SPECINFRA_#{key}"] = ENV[key] ; ENV.delete(key) }
|
51
52
|
|
52
|
-
|
53
|
-
|
53
|
+
env = get_config(:env) || {}
|
54
|
+
env[:LANG] ||= 'C'
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
env.each do |key, value|
|
57
|
+
key = key.to_s
|
58
|
+
ENV["_SPECINFRA_#{key}"] = ENV[key];
|
59
|
+
ENV[key] = value
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
yield
|
63
|
+
ensure
|
64
|
+
keys.each { |key| ENV[key] = ENV.delete("_SPECINFRA_#{key}") }
|
65
|
+
env.each do |key, value|
|
66
|
+
key = key.to_s
|
67
|
+
ENV[key] = ENV.delete("_SPECINFRA_#{key}");
|
68
|
+
end
|
67
69
|
end
|
68
|
-
end
|
69
70
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
71
|
+
def add_pre_command(cmd)
|
72
|
+
if get_config(:pre_command)
|
73
|
+
pre_cmd = build_command(get_config(:pre_command))
|
74
|
+
"#{pre_cmd} && #{cmd}"
|
75
|
+
else
|
76
|
+
cmd
|
77
|
+
end
|
76
78
|
end
|
77
79
|
end
|
78
80
|
end
|
@@ -1,43 +1,45 @@
|
|
1
|
-
module Specinfra
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module Specinfra
|
2
|
+
module Backend
|
3
|
+
class Lxc < Exec
|
4
|
+
def initialize(config = {})
|
5
|
+
super
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
begin
|
8
|
+
require 'lxc/extra' unless defined?(::LXC::Extra)
|
9
|
+
rescue LoadError
|
10
|
+
fail "LXC client library is not available. Try installing `lxc-extra' gem"
|
11
|
+
end
|
10
12
|
end
|
11
|
-
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
def run_command(cmd, opts={})
|
15
|
+
cmd = build_command(cmd)
|
16
|
+
cmd = add_pre_command(cmd)
|
17
|
+
out, ret = ct.execute do
|
18
|
+
out = `#{cmd} 2>&1`
|
19
|
+
[out, $?.dup]
|
20
|
+
end
|
21
|
+
if @example
|
22
|
+
@example.metadata[:command] = cmd
|
23
|
+
@example.metadata[:stdout] = out
|
24
|
+
end
|
25
|
+
CommandResult.new :stdout => out, :exit_status => ret.exitstatus
|
23
26
|
end
|
24
|
-
CommandResult.new :stdout => out, :exit_status => ret.exitstatus
|
25
|
-
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
def build_command(cmd)
|
29
|
+
cmd
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
def add_pre_command(cmd)
|
33
|
+
cmd
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
def send_file(from, to)
|
37
|
+
FileUtils.cp(from, File.join(ct.config_item('lxc.rootfs'), to))
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
40
|
+
def ct
|
41
|
+
@ct ||= ::LXC::Container.new(get_config(:lxc))
|
42
|
+
end
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
@@ -1,26 +1,28 @@
|
|
1
1
|
require 'singleton'
|
2
2
|
|
3
|
-
module Specinfra
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
module Specinfra
|
4
|
+
module Backend
|
5
|
+
class ShellScript < Base
|
6
|
+
def initialize(config = {})
|
7
|
+
super
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def run_command(cmd, opts={})
|
13
|
-
@lines << cmd
|
14
|
-
CommandResult.new
|
15
|
-
end
|
9
|
+
@lines = [ "#!/bin/sh", "" ]
|
10
|
+
ObjectSpace.define_finalizer(self, Writer.new(@lines))
|
11
|
+
end
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
def run_command(cmd, opts={})
|
14
|
+
@lines << cmd
|
15
|
+
CommandResult.new
|
20
16
|
end
|
21
17
|
|
22
|
-
|
23
|
-
|
18
|
+
class Writer
|
19
|
+
def initialize(lines)
|
20
|
+
@lines = lines
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(*args)
|
24
|
+
puts @lines
|
25
|
+
end
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|