specinfra 2.25.1 → 2.26.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.
- 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
|