itamae 1.2.0 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/Rakefile +0 -2
- data/itamae.gemspec +1 -1
- data/lib/itamae/backend.rb +67 -31
- data/lib/itamae/ext/specinfra.rb +0 -8
- data/lib/itamae/node.rb +6 -1
- data/lib/itamae/resource/base.rb +1 -1
- data/lib/itamae/runner.rb +44 -73
- data/lib/itamae/version.txt +1 -1
- data/spec/unit/lib/itamae/node_spec.rb +3 -2
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bee2953f7e53e6c977a24568b6f1ef50b2209f40
|
4
|
+
data.tar.gz: 2b8e4200cbcbf4f2106185355e240ba2c9798863
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73481813d9a2e6d6ed1033e787dc8e0392a6b47c1e68de5df4af6b43e76b6bd0a67e9095c826aa51b9cd74e62cbb08767f41210f55ddfa8e088996f58c339963
|
7
|
+
data.tar.gz: a1627a795d970cbfb2eba039bb13a5d33141c5209a1a75d967b549937e1db0bba7b03199e02f5758d0326be534d1758ee7673a4516e3f652c12a34742c2623a8
|
data/README.md
CHANGED
data/Rakefile
CHANGED
data/itamae.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
20
|
spec.add_runtime_dependency "thor"
|
21
|
-
spec.add_runtime_dependency "specinfra", ">= 2.
|
21
|
+
spec.add_runtime_dependency "specinfra", [">= 2.24.1", "< 3.0.0"]
|
22
22
|
spec.add_runtime_dependency "hashie"
|
23
23
|
spec.add_runtime_dependency "ansi"
|
24
24
|
spec.add_runtime_dependency "schash", "~> 0.1.0"
|
data/lib/itamae/backend.rb
CHANGED
@@ -25,20 +25,17 @@ module Itamae
|
|
25
25
|
CommandExecutionError = Class.new(StandardError)
|
26
26
|
|
27
27
|
class << self
|
28
|
-
def
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
def instance
|
33
|
-
unless @instance
|
34
|
-
raise "Before calling Backend.instance, call Backend.set_type."
|
35
|
-
end
|
36
|
-
|
37
|
-
@instance
|
28
|
+
def create(type, opts = {})
|
29
|
+
self.const_get(type.capitalize).new(opts)
|
38
30
|
end
|
39
31
|
end
|
40
32
|
|
41
33
|
class Base
|
34
|
+
def initialize(options)
|
35
|
+
@options = options
|
36
|
+
@backend = create_specinfra_backend
|
37
|
+
end
|
38
|
+
|
42
39
|
def run_command(commands, options = {})
|
43
40
|
options = {error: true}.merge(options)
|
44
41
|
|
@@ -62,7 +59,7 @@ module Itamae
|
|
62
59
|
|
63
60
|
Logger.debug "Executing `#{command}`..."
|
64
61
|
|
65
|
-
result =
|
62
|
+
result = @backend.run_command(command)
|
66
63
|
exit_status = result.exit_status
|
67
64
|
|
68
65
|
Logger.formatter.with_indent do
|
@@ -104,61 +101,100 @@ module Itamae
|
|
104
101
|
end
|
105
102
|
|
106
103
|
def get_command(*args)
|
107
|
-
|
104
|
+
@backend.command.get(*args)
|
108
105
|
end
|
109
106
|
|
110
107
|
def send_file(*args)
|
111
|
-
|
108
|
+
@backend.send_file(*args)
|
112
109
|
end
|
113
110
|
|
114
111
|
def send_directory(*args)
|
115
|
-
|
112
|
+
@backend.send_directory(*args)
|
113
|
+
end
|
114
|
+
|
115
|
+
def host_inventory
|
116
|
+
@backend.host_inventory
|
116
117
|
end
|
117
118
|
|
118
119
|
def finalize
|
119
120
|
# pass
|
120
121
|
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def create_specinfra_backend
|
126
|
+
raise NotImplementedError
|
127
|
+
end
|
121
128
|
end
|
122
129
|
|
123
130
|
# TODO: Make Specinfra's backends instanciatable
|
124
131
|
class Local < Base
|
125
|
-
|
126
|
-
|
132
|
+
private
|
133
|
+
def create_specinfra_backend
|
134
|
+
Specinfra::Backend::Exec.new()
|
127
135
|
end
|
128
136
|
end
|
129
137
|
|
130
138
|
class Ssh < Base
|
131
|
-
|
132
|
-
|
133
|
-
Specinfra.
|
134
|
-
|
135
|
-
|
139
|
+
private
|
140
|
+
def create_specinfra_backend
|
141
|
+
Specinfra::Backend::Ssh.new(
|
142
|
+
request_pty: true,
|
143
|
+
host: ssh_options[:host_name],
|
144
|
+
disable_sudo: ssh_options[:disable_sudo],
|
145
|
+
ssh_options: ssh_options,
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
149
|
+
def ssh_options
|
150
|
+
opts = {}
|
151
|
+
|
152
|
+
opts[:host_name] = @options[:host]
|
153
|
+
opts[:user] = @options[:user] || Etc.getlogin
|
154
|
+
opts[:keys] = [@options[:key]] if @options[:key]
|
155
|
+
opts[:port] = @options[:port] if @options[:port]
|
156
|
+
opts[:disable_sudo] = true unless @options[:sudo]
|
157
|
+
|
158
|
+
if @options[:vagrant]
|
159
|
+
config = Tempfile.new('', Dir.tmpdir)
|
160
|
+
hostname = opts[:host] || 'default'
|
161
|
+
`vagrant ssh-config #{hostname} > #{config.path}`
|
162
|
+
opts.merge!(Net::SSH::Config.for(hostname, [config.path]))
|
163
|
+
opts[:host] = opts.delete(:host_name)
|
164
|
+
end
|
165
|
+
|
166
|
+
if @options[:ask_password]
|
167
|
+
print "password: "
|
168
|
+
password = STDIN.noecho(&:gets).strip
|
169
|
+
print "\n"
|
170
|
+
opts.merge!(password: password)
|
171
|
+
end
|
136
172
|
|
137
|
-
|
173
|
+
opts
|
138
174
|
end
|
139
175
|
end
|
140
176
|
|
141
177
|
class Docker < Base
|
142
|
-
|
178
|
+
private
|
179
|
+
def create_specinfra_backend
|
143
180
|
begin
|
144
181
|
require 'docker'
|
145
182
|
rescue LoadError
|
146
183
|
Logger.fatal "To use docker backend, please install 'docker-api' gem"
|
147
184
|
end
|
148
185
|
|
149
|
-
Specinfra.configuration.docker_image = options[:image]
|
150
|
-
Specinfra.configuration.docker_container = options[:container]
|
151
|
-
|
152
186
|
# TODO: Move to Specinfra?
|
153
|
-
Excon.defaults[:ssl_verify_peer] = options[:tls_verify_peer]
|
154
|
-
|
155
|
-
Specinfra.configuration.backend = :docker
|
156
|
-
|
187
|
+
Excon.defaults[:ssl_verify_peer] = @options[:tls_verify_peer]
|
157
188
|
::Docker.logger = Logger
|
189
|
+
|
190
|
+
Specinfra::Backend::Docker.new(
|
191
|
+
docker_image: @options[:image],
|
192
|
+
docker_container: @options[:container],
|
193
|
+
)
|
158
194
|
end
|
159
195
|
|
160
196
|
def finalize
|
161
|
-
image =
|
197
|
+
image = @backend.commit_container
|
162
198
|
Logger.info "Image created: #{image.id}"
|
163
199
|
end
|
164
200
|
end
|
data/lib/itamae/ext/specinfra.rb
CHANGED
@@ -1,10 +1,2 @@
|
|
1
1
|
# TODO: Send patches to Specinfra
|
2
2
|
|
3
|
-
Specinfra::Command::Base::User.class_eval do
|
4
|
-
class << self
|
5
|
-
def update_home_directory(user, directory)
|
6
|
-
# -m: Move the content of the user's home directory to the new location.
|
7
|
-
"usermod -m -d #{escape(directory)} #{escape(user)}"
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
data/lib/itamae/node.rb
CHANGED
@@ -7,6 +7,11 @@ module Itamae
|
|
7
7
|
class Node < Hashie::Mash
|
8
8
|
ValidationError = Class.new(StandardError)
|
9
9
|
|
10
|
+
def initialize(initial_hash, backend = nil)
|
11
|
+
super(initial_hash)
|
12
|
+
@backend = backend
|
13
|
+
end
|
14
|
+
|
10
15
|
def reverse_merge(other_hash)
|
11
16
|
Hashie::Mash.new(other_hash).merge(self)
|
12
17
|
end
|
@@ -19,7 +24,7 @@ module Itamae
|
|
19
24
|
val = super(key)
|
20
25
|
if val.nil?
|
21
26
|
begin
|
22
|
-
val = host_inventory[key]
|
27
|
+
val = @backend.host_inventory[key]
|
23
28
|
rescue NotImplementedError, NameError
|
24
29
|
val = nil
|
25
30
|
end
|
data/lib/itamae/resource/base.rb
CHANGED
data/lib/itamae/runner.rb
CHANGED
@@ -8,9 +8,8 @@ module Itamae
|
|
8
8
|
def run(recipe_files, backend_type, options)
|
9
9
|
Logger.info "Starting Itamae..."
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
runner = self.new(node_from_options(options))
|
11
|
+
backend = Backend.create(backend_type, options)
|
12
|
+
runner = self.new(backend, options)
|
14
13
|
runner.load_recipes(recipe_files)
|
15
14
|
|
16
15
|
if dot_file = options[:dot]
|
@@ -23,81 +22,23 @@ module Itamae
|
|
23
22
|
|
24
23
|
runner.run(dry_run: options[:dry_run])
|
25
24
|
end
|
26
|
-
|
27
|
-
private
|
28
|
-
def node_from_options(options)
|
29
|
-
hash = {}
|
30
|
-
|
31
|
-
if options[:ohai]
|
32
|
-
unless Backend.instance.run_command("which ohai", error: false).exit_status == 0
|
33
|
-
# install Ohai
|
34
|
-
Logger.info "Installing Chef package... (to use Ohai)"
|
35
|
-
Backend.instance.run_command("curl -L https://www.opscode.com/chef/install.sh | bash")
|
36
|
-
end
|
37
|
-
|
38
|
-
Logger.info "Loading node data via ohai..."
|
39
|
-
hash.merge!(JSON.parse(Backend.instance.run_command("ohai").stdout))
|
40
|
-
end
|
41
|
-
|
42
|
-
if options[:node_json]
|
43
|
-
path = File.expand_path(options[:node_json])
|
44
|
-
Logger.info "Loading node data from #{path}..."
|
45
|
-
hash.merge!(JSON.load(open(path)))
|
46
|
-
end
|
47
|
-
|
48
|
-
if options[:node_yaml]
|
49
|
-
path = File.expand_path(options[:node_yaml])
|
50
|
-
Logger.info "Loading node data from #{path}..."
|
51
|
-
hash.merge!(YAML.load(open(path)))
|
52
|
-
end
|
53
|
-
|
54
|
-
Node.new(hash)
|
55
|
-
end
|
56
|
-
|
57
|
-
def set_backend_from_options(type, options)
|
58
|
-
opts = {}
|
59
|
-
|
60
|
-
case type
|
61
|
-
when :ssh
|
62
|
-
opts[:host] = options[:host]
|
63
|
-
opts[:user] = options[:user] || Etc.getlogin
|
64
|
-
opts[:keys] = [options[:key]] if options[:key]
|
65
|
-
opts[:port] = options[:port] if options[:port]
|
66
|
-
opts[:disable_sudo] = true unless options[:sudo]
|
67
|
-
|
68
|
-
if options[:vagrant]
|
69
|
-
config = Tempfile.new('', Dir.tmpdir)
|
70
|
-
hostname = opts[:host] || 'default'
|
71
|
-
`vagrant ssh-config #{hostname} > #{config.path}`
|
72
|
-
opts.merge!(Net::SSH::Config.for(hostname, [config.path]))
|
73
|
-
opts[:host] = opts.delete(:host_name)
|
74
|
-
end
|
75
|
-
|
76
|
-
if options[:ask_password]
|
77
|
-
print "password: "
|
78
|
-
password = STDIN.noecho(&:gets).strip
|
79
|
-
print "\n"
|
80
|
-
opts.merge!(password: password)
|
81
|
-
end
|
82
|
-
when :docker
|
83
|
-
opts = options
|
84
|
-
end
|
85
|
-
|
86
|
-
Backend.set_type(type, opts)
|
87
|
-
end
|
88
25
|
end
|
89
26
|
|
90
|
-
|
91
|
-
|
92
|
-
|
27
|
+
attr_reader :backend
|
28
|
+
attr_reader :node
|
29
|
+
attr_reader :tmpdir
|
30
|
+
attr_reader :children
|
31
|
+
|
32
|
+
def initialize(backend, options)
|
33
|
+
@backend = backend
|
34
|
+
@options = options
|
93
35
|
|
94
|
-
|
95
|
-
@node = node
|
36
|
+
@node = create_node
|
96
37
|
@tmpdir = "/tmp/itamae_tmp"
|
97
38
|
@children = RecipeChildren.new
|
98
39
|
|
99
|
-
|
100
|
-
|
40
|
+
@backend.run_command(["mkdir", "-p", @tmpdir])
|
41
|
+
@backend.run_command(["chmod", "777", @tmpdir])
|
101
42
|
end
|
102
43
|
|
103
44
|
def load_recipes(paths)
|
@@ -110,7 +51,37 @@ module Itamae
|
|
110
51
|
|
111
52
|
def run(options)
|
112
53
|
children.run(options)
|
113
|
-
|
54
|
+
@backend.finalize
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def create_node
|
59
|
+
hash = {}
|
60
|
+
|
61
|
+
if @options[:ohai]
|
62
|
+
unless @backend.run_command("which ohai", error: false).exit_status == 0
|
63
|
+
# install Ohai
|
64
|
+
Logger.info "Installing Chef package... (to use Ohai)"
|
65
|
+
@backend.run_command("curl -L https://www.opscode.com/chef/install.sh | bash")
|
66
|
+
end
|
67
|
+
|
68
|
+
Logger.info "Loading node data via ohai..."
|
69
|
+
hash.merge!(JSON.parse(@backend.run_command("ohai").stdout))
|
70
|
+
end
|
71
|
+
|
72
|
+
if @options[:node_json]
|
73
|
+
path = File.expand_path(@options[:node_json])
|
74
|
+
Logger.info "Loading node data from #{path}..."
|
75
|
+
hash.merge!(JSON.load(open(path)))
|
76
|
+
end
|
77
|
+
|
78
|
+
if @options[:node_yaml]
|
79
|
+
path = File.expand_path(@options[:node_yaml])
|
80
|
+
Logger.info "Loading node data from #{path}..."
|
81
|
+
hash.merge!(YAML.load(open(path)))
|
82
|
+
end
|
83
|
+
|
84
|
+
Node.new(hash, @backend)
|
114
85
|
end
|
115
86
|
end
|
116
87
|
end
|
data/lib/itamae/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.2.
|
1
|
+
1.2.2
|
@@ -2,10 +2,11 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Itamae
|
4
4
|
describe Node do
|
5
|
+
let(:backend) { nil }
|
5
6
|
describe "#reverse_merge" do
|
6
7
|
it "merges a hash but the method receiver's value will be preferred" do
|
7
|
-
a = described_class.new(a: :b, c: :d)
|
8
|
-
expected = described_class.new(a: :b, c: :d, e: :f)
|
8
|
+
a = described_class.new({a: :b, c: :d}, backend)
|
9
|
+
expected = described_class.new({a: :b, c: :d, e: :f}, backend)
|
9
10
|
expect(a.reverse_merge(a: :c, e: :f)).to eq(expected)
|
10
11
|
end
|
11
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: itamae
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryota Arai
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -30,14 +30,20 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: 2.24.1
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 3.0.0
|
34
37
|
type: :runtime
|
35
38
|
prerelease: false
|
36
39
|
version_requirements: !ruby/object:Gem::Requirement
|
37
40
|
requirements:
|
38
41
|
- - ">="
|
39
42
|
- !ruby/object:Gem::Version
|
40
|
-
version: 2.
|
43
|
+
version: 2.24.1
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 3.0.0
|
41
47
|
- !ruby/object:Gem::Dependency
|
42
48
|
name: hashie
|
43
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,7 +260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
254
260
|
version: '0'
|
255
261
|
requirements: []
|
256
262
|
rubyforge_project:
|
257
|
-
rubygems_version: 2.
|
263
|
+
rubygems_version: 2.4.5
|
258
264
|
signing_key:
|
259
265
|
specification_version: 4
|
260
266
|
summary: Simple Configuration Management Tool
|