itamae 1.6.3 → 1.7.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile +3 -1
- data/Rakefile +37 -25
- data/lib/itamae/backend.rb +16 -1
- data/lib/itamae/cli.rb +3 -2
- data/lib/itamae/notification.rb +2 -2
- data/lib/itamae/recipe.rb +5 -5
- data/lib/itamae/recipe_children.rb +2 -7
- data/lib/itamae/resource/base.rb +16 -10
- data/lib/itamae/resource/execute.rb +0 -1
- data/lib/itamae/resource/file.rb +5 -4
- data/lib/itamae/runner.rb +26 -8
- data/lib/itamae/version.txt +1 -1
- data/spec/integration/Vagrantfile +1 -0
- data/spec/integration/recipes/dry_run.rb +6 -0
- data/spec/integration/spec_helper.rb +3 -6
- data/spec/unit/lib/itamae/resource/base_spec.rb +3 -10
- data/wercker.yml +5 -13
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c693dfeb747bd80dffef33f292b26a2a8e075f81
|
4
|
+
data.tar.gz: b11be7c402d731d2444cf79600b63e82987b2c1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85df294c1e5860f42b81ddcff13ef64245504d65a063a0061ac72a513af4af3d5d0fe1d416b095d9b8cf11c12e67aa9a1f5dc5cba711e08c9427cdd9cde4223c
|
7
|
+
data.tar.gz: 11d1f27227fa148d113222f3bc03a14058edcdc071e93dcc5a026928aae06c78ab3e3a4160c08b4671e3636da53168572f9fe1f31186ba9a4a59d2d2b9e5277f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## v1.6.4.pre
|
2
|
+
|
3
|
+
Features
|
4
|
+
|
5
|
+
- `--profile` option (experimental)
|
6
|
+
- `--profile PATH` saves executed commands to `PATH` in JSON format
|
7
|
+
|
8
|
+
Bugfixes
|
9
|
+
|
10
|
+
- [Suppress errors of `edit` action of `file` resource when the target file doesn't exist in `dry-run` mode](https://github.com/itamae-kitchen/itamae/pull/144)
|
11
|
+
|
1
12
|
## v1.6.3
|
2
13
|
|
3
14
|
Features
|
data/Gemfile
CHANGED
@@ -3,6 +3,9 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in itamae.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
+
gem 'vagrant', github: 'mitchellh/vagrant'
|
7
|
+
gem 'vagrant-digitalocean'
|
8
|
+
|
6
9
|
path = Pathname.new("Gemfile.local")
|
7
10
|
eval(path.read) if path.exist?
|
8
11
|
|
@@ -11,4 +14,3 @@ group :test do
|
|
11
14
|
gem 'growl'
|
12
15
|
end
|
13
16
|
end
|
14
|
-
|
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require 'rspec/core/rake_task'
|
|
3
3
|
require 'tempfile'
|
4
4
|
require 'net/ssh'
|
5
5
|
|
6
|
-
vagrant_bin =
|
6
|
+
vagrant_bin = 'vagrant'
|
7
7
|
|
8
8
|
desc 'Run unit and integration specs.'
|
9
9
|
task :spec => ['spec:unit', 'spec:integration:all']
|
@@ -16,10 +16,13 @@ namespace :spec do
|
|
16
16
|
|
17
17
|
namespace :integration do
|
18
18
|
targets = []
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
status = `cd spec/integration && #{vagrant_bin} status`
|
20
|
+
unless $?.exitstatus == 0
|
21
|
+
raise "vagrant status failed.\n#{status}"
|
22
|
+
end
|
23
|
+
|
24
|
+
status.split("\n\n")[1].each_line do |line|
|
25
|
+
targets << line.match(/^[^ ]+/)[0]
|
23
26
|
end
|
24
27
|
|
25
28
|
task :all => targets
|
@@ -30,27 +33,37 @@ namespace :spec do
|
|
30
33
|
|
31
34
|
namespace :provision do
|
32
35
|
task target do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
options = Net::SSH::Config.for(target, [config.path])
|
36
|
+
config = Tempfile.new('', Dir.tmpdir)
|
37
|
+
env = {"VAGRANT_CWD" => File.expand_path('./spec/integration')}
|
38
|
+
system env, "#{vagrant_bin} up #{target}"
|
39
|
+
system env, "#{vagrant_bin} ssh-config #{target} > #{config.path}"
|
40
|
+
options = Net::SSH::Config.for(target, [config.path])
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
suites = [
|
43
|
+
[
|
44
|
+
"spec/integration/recipes/default.rb",
|
45
|
+
"spec/integration/recipes/default2.rb",
|
46
|
+
"spec/integration/recipes/redefine.rb",
|
47
|
+
],
|
48
|
+
[
|
49
|
+
"--dry-run",
|
50
|
+
"spec/integration/recipes/dry_run.rb",
|
51
|
+
],
|
52
|
+
]
|
53
|
+
suites.each do |suite|
|
54
|
+
cmd = %w!bundle exec bin/itamae ssh!
|
55
|
+
cmd << "-h" << options[:host_name]
|
56
|
+
cmd << "-u" << options[:user]
|
57
|
+
cmd << "-p" << options[:port].to_s
|
58
|
+
cmd << "-i" << options[:keys].first
|
59
|
+
cmd << "-l" << (ENV['LOG_LEVEL'] || 'debug')
|
60
|
+
cmd << "-j" << "spec/integration/recipes/node.json"
|
61
|
+
cmd += suite
|
50
62
|
|
51
|
-
|
52
|
-
system
|
53
|
-
|
63
|
+
p cmd
|
64
|
+
unless system(*cmd)
|
65
|
+
raise "#{cmd} failed"
|
66
|
+
end
|
54
67
|
end
|
55
68
|
end
|
56
69
|
end
|
@@ -86,4 +99,3 @@ namespace :release do
|
|
86
99
|
system "git commit -m 'Bump up version'"
|
87
100
|
end
|
88
101
|
end
|
89
|
-
|
data/lib/itamae/backend.rb
CHANGED
@@ -35,9 +35,12 @@ module Itamae
|
|
35
35
|
end
|
36
36
|
|
37
37
|
class Base
|
38
|
+
attr_reader :executed_commands
|
39
|
+
|
38
40
|
def initialize(options)
|
39
41
|
@options = options
|
40
42
|
@backend = create_specinfra_backend
|
43
|
+
@executed_commands = []
|
41
44
|
end
|
42
45
|
|
43
46
|
def run_command(commands, options = {})
|
@@ -50,7 +53,9 @@ module Itamae
|
|
50
53
|
|
51
54
|
Itamae.logger.with_indent do
|
52
55
|
reset_output_handler
|
53
|
-
|
56
|
+
|
57
|
+
result = run_command_with_profiling(command)
|
58
|
+
|
54
59
|
flush_output_handler_buffer
|
55
60
|
|
56
61
|
if result.exit_status == 0 || !options[:error]
|
@@ -186,6 +191,16 @@ module Itamae
|
|
186
191
|
def shell
|
187
192
|
@options[:shell]
|
188
193
|
end
|
194
|
+
|
195
|
+
def run_command_with_profiling(command)
|
196
|
+
start_at = Time.now
|
197
|
+
result = @backend.run_command(command)
|
198
|
+
duration = Time.now.to_f - start_at.to_f
|
199
|
+
|
200
|
+
@executed_commands << {command: command, duration: duration}
|
201
|
+
|
202
|
+
result
|
203
|
+
end
|
189
204
|
end
|
190
205
|
|
191
206
|
class Local < Base
|
data/lib/itamae/cli.rb
CHANGED
@@ -15,12 +15,13 @@ module Itamae
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.define_exec_options
|
18
|
-
option :dot, type: :string, default: nil, desc: "Only write dependency graph in DOT", banner: "PATH"
|
18
|
+
option :dot, type: :string, default: nil, desc: "[EXPERIMENTAL] Only write dependency graph in DOT", banner: "PATH"
|
19
19
|
option :node_json, type: :string, aliases: ['-j']
|
20
20
|
option :node_yaml, type: :string, aliases: ['-y']
|
21
21
|
option :dry_run, type: :boolean, aliases: ['-n']
|
22
22
|
option :shell, type: :string, default: "/bin/sh"
|
23
|
-
option :ohai, type: :boolean, default: false, desc: "This option is DEPRECATED and will be
|
23
|
+
option :ohai, type: :boolean, default: false, desc: "This option is DEPRECATED and will be unavailable."
|
24
|
+
option :profile, type: :string, desc: "[EXPERIMENTAL] Save profiling data", banner: "PATH"
|
24
25
|
end
|
25
26
|
|
26
27
|
desc "local RECIPE [RECIPE...]", "Run Itamae locally"
|
data/lib/itamae/notification.rb
CHANGED
data/lib/itamae/recipe.rb
CHANGED
@@ -58,24 +58,24 @@ module Itamae
|
|
58
58
|
context.instance_eval(File.read(path), path, 1)
|
59
59
|
end
|
60
60
|
|
61
|
-
def run
|
61
|
+
def run
|
62
62
|
show_banner
|
63
63
|
|
64
64
|
Itamae.logger.with_indent do
|
65
|
-
@children.run
|
66
|
-
run_delayed_notifications
|
65
|
+
@children.run
|
66
|
+
run_delayed_notifications
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
private
|
71
71
|
|
72
|
-
def run_delayed_notifications
|
72
|
+
def run_delayed_notifications
|
73
73
|
@delayed_notifications.uniq! do |notification|
|
74
74
|
[notification.action, notification.action_resource]
|
75
75
|
end
|
76
76
|
|
77
77
|
while notification = @delayed_notifications.shift
|
78
|
-
notification.run
|
78
|
+
notification.run
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -53,14 +53,9 @@ module Itamae
|
|
53
53
|
end.flatten
|
54
54
|
end
|
55
55
|
|
56
|
-
def run
|
56
|
+
def run
|
57
57
|
self.each do |resource|
|
58
|
-
|
59
|
-
when Resource::Base
|
60
|
-
resource.run(nil, dry_run: options[:dry_run])
|
61
|
-
when Recipe
|
62
|
-
resource.run(options)
|
63
|
-
end
|
58
|
+
resource.run
|
64
59
|
end
|
65
60
|
end
|
66
61
|
|
data/lib/itamae/resource/base.rb
CHANGED
@@ -120,7 +120,7 @@ module Itamae
|
|
120
120
|
process_attributes
|
121
121
|
end
|
122
122
|
|
123
|
-
def run(specific_action = nil
|
123
|
+
def run(specific_action = nil)
|
124
124
|
Itamae.logger.debug "#{resource_type}[#{resource_name}]"
|
125
125
|
|
126
126
|
Itamae.logger.with_indent_if(Itamae.logger.debug?) do
|
@@ -133,11 +133,11 @@ module Itamae
|
|
133
133
|
end
|
134
134
|
|
135
135
|
[specific_action || attributes.action].flatten.each do |action|
|
136
|
-
run_action(action
|
136
|
+
run_action(action)
|
137
137
|
end
|
138
138
|
|
139
|
-
verify unless
|
140
|
-
notify
|
139
|
+
verify unless runner.dry_run?
|
140
|
+
notify if updated?
|
141
141
|
end
|
142
142
|
|
143
143
|
@updated = false
|
@@ -146,7 +146,7 @@ module Itamae
|
|
146
146
|
exit 2
|
147
147
|
end
|
148
148
|
|
149
|
-
def action_nothing
|
149
|
+
def action_nothing
|
150
150
|
# do nothing
|
151
151
|
end
|
152
152
|
|
@@ -166,7 +166,7 @@ module Itamae
|
|
166
166
|
|
167
167
|
alias_method :current, :current_attributes
|
168
168
|
|
169
|
-
def run_action(action
|
169
|
+
def run_action(action)
|
170
170
|
original_attributes = @attributes # preserve and restore later
|
171
171
|
@current_action = action
|
172
172
|
|
@@ -187,12 +187,18 @@ module Itamae
|
|
187
187
|
show_differences
|
188
188
|
|
189
189
|
method_name = "action_#{action}"
|
190
|
-
if
|
190
|
+
if runner.dry_run?
|
191
191
|
unless respond_to?(method_name)
|
192
192
|
Itamae.logger.error "action #{action.inspect} is unavailable"
|
193
193
|
end
|
194
194
|
else
|
195
|
-
|
195
|
+
args = [method_name]
|
196
|
+
if method(method_name).arity == 1
|
197
|
+
# for plugin compatibility
|
198
|
+
args << runner.options
|
199
|
+
end
|
200
|
+
|
201
|
+
public_send(*args)
|
196
202
|
end
|
197
203
|
|
198
204
|
updated! if different?
|
@@ -327,7 +333,7 @@ module Itamae
|
|
327
333
|
@updated
|
328
334
|
end
|
329
335
|
|
330
|
-
def notify
|
336
|
+
def notify
|
331
337
|
(notifications + recipe.children.subscribing(self)).each do |notification|
|
332
338
|
message = "Notifying #{notification.action} to #{notification.action_resource.resource_type} resource '#{notification.action_resource.resource_name}'"
|
333
339
|
|
@@ -346,7 +352,7 @@ module Itamae
|
|
346
352
|
if notification.delayed?
|
347
353
|
@recipe.delayed_notifications << notification
|
348
354
|
elsif notification.immediately?
|
349
|
-
notification.run
|
355
|
+
notification.run
|
350
356
|
end
|
351
357
|
end
|
352
358
|
end
|
data/lib/itamae/resource/file.rb
CHANGED
@@ -20,9 +20,11 @@ module Itamae
|
|
20
20
|
when :edit
|
21
21
|
attributes.exist = true
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
unless runner.dry_run?
|
24
|
+
content = backend.receive_file(attributes.path)
|
25
|
+
attributes.block.call(content)
|
26
|
+
attributes.content = content
|
27
|
+
end
|
26
28
|
end
|
27
29
|
|
28
30
|
send_tempfile
|
@@ -163,4 +165,3 @@ module Itamae
|
|
163
165
|
end
|
164
166
|
end
|
165
167
|
end
|
166
|
-
|
data/lib/itamae/runner.rb
CHANGED
@@ -13,18 +13,20 @@ module Itamae
|
|
13
13
|
runner.load_recipes(recipe_files)
|
14
14
|
|
15
15
|
if dot_file = options[:dot]
|
16
|
-
|
17
|
-
open(dot_file, 'w') do |f|
|
18
|
-
f.write(runner.children.deps_in_dot)
|
19
|
-
end
|
16
|
+
runner.save_dependency_graph(dot_file)
|
20
17
|
return
|
21
18
|
end
|
22
19
|
|
23
|
-
runner.run
|
20
|
+
runner.run
|
21
|
+
|
22
|
+
if profile = options[:profile]
|
23
|
+
runner.save_profile(profile)
|
24
|
+
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
28
|
attr_reader :backend
|
29
|
+
attr_reader :options
|
28
30
|
attr_reader :node
|
29
31
|
attr_reader :tmpdir
|
30
32
|
attr_reader :children
|
@@ -55,11 +57,28 @@ module Itamae
|
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
58
|
-
def run
|
59
|
-
children.run
|
60
|
+
def run
|
61
|
+
children.run
|
60
62
|
@backend.finalize
|
61
63
|
end
|
62
64
|
|
65
|
+
def dry_run?
|
66
|
+
@options[:dry_run]
|
67
|
+
end
|
68
|
+
|
69
|
+
def save_dependency_graph(path)
|
70
|
+
Itamae.logger.info "Writing dependency graph in DOT to #{path}..."
|
71
|
+
open(path, 'w') do |f|
|
72
|
+
f.write(runner.children.deps_in_dot)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def save_profile(path)
|
77
|
+
open(path, 'w', 0600) do |f|
|
78
|
+
f.write(@backend.executed_commands.to_json)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
63
82
|
private
|
64
83
|
def create_node
|
65
84
|
hash = {}
|
@@ -91,4 +110,3 @@ module Itamae
|
|
91
110
|
end
|
92
111
|
end
|
93
112
|
end
|
94
|
-
|
data/lib/itamae/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.7.0.pre
|
@@ -5,10 +5,8 @@ require 'tempfile'
|
|
5
5
|
set :backend, :ssh
|
6
6
|
|
7
7
|
def vagrant(cmd)
|
8
|
-
|
9
|
-
|
10
|
-
system env, "/usr/bin/vagrant #{cmd}"
|
11
|
-
end
|
8
|
+
env = {"VAGRANT_CWD" => File.dirname(__FILE__)}
|
9
|
+
system(env, "vagrant #{cmd}")
|
12
10
|
end
|
13
11
|
|
14
12
|
if ENV['ASK_SUDO_PASSWORD']
|
@@ -38,8 +36,7 @@ set :ssh_options, options
|
|
38
36
|
# set :disable_sudo, true
|
39
37
|
|
40
38
|
# Set environment variables
|
41
|
-
# set :env, :LANG => 'C', :LC_MESSAGES => 'C'
|
39
|
+
# set :env, :LANG => 'C', :LC_MESSAGES => 'C'
|
42
40
|
|
43
41
|
# Set PATH
|
44
42
|
# set :path, '/sbin:/usr/local/sbin:$PATH'
|
45
|
-
|
@@ -102,7 +102,9 @@ describe TestResource do
|
|
102
102
|
|
103
103
|
let(:commands) { double(:commands) }
|
104
104
|
let(:runner) do
|
105
|
-
|
105
|
+
instance_double(Itamae::Runner).tap do |r|
|
106
|
+
allow(r).to receive(:dry_run?).and_return(false)
|
107
|
+
end
|
106
108
|
end
|
107
109
|
let(:recipe) do
|
108
110
|
double(:recipe).tap do |r|
|
@@ -120,14 +122,5 @@ describe TestResource do
|
|
120
122
|
expect(subject).to receive(:action_name)
|
121
123
|
subject.run
|
122
124
|
end
|
123
|
-
|
124
|
-
context 'with dry_run' do
|
125
|
-
context 'when specified action is unavailable' do
|
126
|
-
it 'logs error' do
|
127
|
-
expect(Itamae.logger).to receive(:error).with(/action :name is unavailable/)
|
128
|
-
subject.run(nil, dry_run: true)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
125
|
end
|
133
126
|
end
|
data/wercker.yml
CHANGED
@@ -47,25 +47,17 @@ build:
|
|
47
47
|
name: chmod 600 id_rsa
|
48
48
|
code: chmod 600 $HOME/.ssh/id_rsa.vagrant
|
49
49
|
|
50
|
-
- script:
|
51
|
-
name: download vagrant
|
52
|
-
code: wget https://dl.bintray.com/mitchellh/vagrant/vagrant_1.6.3_x86_64.deb
|
53
|
-
|
54
|
-
- script:
|
55
|
-
name: install vagrant
|
56
|
-
code: sudo dpkg -i vagrant_1.6.3_x86_64.deb
|
57
|
-
|
58
50
|
- script:
|
59
51
|
name: install libxml and libxslt
|
60
52
|
code: sudo apt-get install libxml2-dev libxslt1-dev
|
61
53
|
|
62
54
|
- script:
|
63
|
-
name: install
|
64
|
-
code:
|
55
|
+
name: bundle install
|
56
|
+
code: bundle install --deployment -j4
|
65
57
|
|
66
58
|
- script:
|
67
59
|
name: start vm
|
68
|
-
code: vagrant up --provider=digital_ocean
|
60
|
+
code: bundle exec vagrant up --provider=digital_ocean
|
69
61
|
cwd: spec/integration
|
70
62
|
|
71
63
|
# Add more steps here:
|
@@ -76,10 +68,10 @@ build:
|
|
76
68
|
after-steps:
|
77
69
|
- script:
|
78
70
|
name: shutdown vm
|
79
|
-
code: vagrant destroy -f
|
71
|
+
code: bundle exec vagrant destroy -f
|
80
72
|
cwd: spec/integration
|
81
73
|
|
82
74
|
- script:
|
83
75
|
name: shutdown old vms
|
84
|
-
code: ruby ci/destroy_old_droplets.rb
|
76
|
+
code: bundle exec ruby ci/destroy_old_droplets.rb
|
85
77
|
|
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.
|
4
|
+
version: 1.7.0.pre
|
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-
|
11
|
+
date: 2015-11-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -244,6 +244,7 @@ files:
|
|
244
244
|
- spec/integration/recipes/default2.rb
|
245
245
|
- spec/integration/recipes/define/default.rb
|
246
246
|
- spec/integration/recipes/define/files/remote_file_in_definition
|
247
|
+
- spec/integration/recipes/dry_run.rb
|
247
248
|
- spec/integration/recipes/files/remote_file_auto
|
248
249
|
- spec/integration/recipes/hello.erb
|
249
250
|
- spec/integration/recipes/hello.txt
|
@@ -276,9 +277,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
276
277
|
version: '0'
|
277
278
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
278
279
|
requirements:
|
279
|
-
- - "
|
280
|
+
- - ">"
|
280
281
|
- !ruby/object:Gem::Version
|
281
|
-
version:
|
282
|
+
version: 1.3.1
|
282
283
|
requirements: []
|
283
284
|
rubyforge_project:
|
284
285
|
rubygems_version: 2.4.5
|
@@ -292,6 +293,7 @@ test_files:
|
|
292
293
|
- spec/integration/recipes/default2.rb
|
293
294
|
- spec/integration/recipes/define/default.rb
|
294
295
|
- spec/integration/recipes/define/files/remote_file_in_definition
|
296
|
+
- spec/integration/recipes/dry_run.rb
|
295
297
|
- spec/integration/recipes/files/remote_file_auto
|
296
298
|
- spec/integration/recipes/hello.erb
|
297
299
|
- spec/integration/recipes/hello.txt
|