pennyworth-tool 0.1.0 → 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 +38 -4
- data/examples/README.md +1 -1
- data/examples/{kiwi → boxes}/definitions/base_opensuse13.1_kvm/config.sh +0 -0
- data/examples/{kiwi → boxes}/definitions/base_opensuse13.1_kvm/config.xml +0 -0
- data/examples/{kiwi → boxes}/definitions/base_opensuse13.1_kvm/root/etc/sysconfig/network/ifcfg-eth0 +0 -0
- data/examples/{kiwi → boxes}/definitions/base_opensuse13.1_kvm/root/home/vagrant/.ssh/authorized_keys +0 -0
- data/lib/pennyworth/cli.rb +11 -11
- data/lib/pennyworth/commands/base_command.rb +8 -8
- data/lib/pennyworth/commands/build_base_command.rb +36 -14
- data/lib/pennyworth/commands/import_base_command.rb +4 -4
- data/lib/pennyworth/commands/list_command.rb +1 -1
- data/lib/pennyworth/commands/setup_command.rb +43 -10
- data/lib/pennyworth/exceptions.rb +0 -12
- data/lib/pennyworth/local_command_runner.rb +0 -2
- data/lib/pennyworth/matchers.rb +148 -0
- data/lib/pennyworth/remote_command_runner.rb +1 -2
- data/lib/pennyworth/runner.rb +1 -1
- data/lib/pennyworth/settings.rb +2 -2
- data/lib/pennyworth/spec.rb +1 -0
- data/lib/pennyworth/version.rb +1 -3
- data/lib/pennyworth/vm.rb +26 -1
- data/spec/build_base_command_spec.rb +18 -10
- data/spec/data/{kiwi → boxes}/definitions/base_opensuse12.3_kvm/config.sh +0 -0
- data/spec/data/{kiwi → boxes}/definitions/base_opensuse12.3_kvm/config.xml +0 -0
- data/spec/data/{kiwi → boxes}/definitions/base_opensuse12.3_kvm/root/home/vagrant/.ssh/authorized_keys +0 -0
- data/spec/data/{kiwi → boxes}/definitions/base_opensuse13.1_kvm/config.sh +0 -0
- data/spec/data/{kiwi → boxes}/definitions/base_opensuse13.1_kvm/config.xml +0 -0
- data/spec/data/{kiwi → boxes}/definitions/base_opensuse13.1_kvm/root/home/vagrant/.ssh/authorized_keys +0 -0
- data/spec/data/{kiwi3/definitions/base_opensuse12.3_kvm/.gitkeep → boxes/definitions/veewee_definition/definition.rb} +0 -0
- data/spec/data/{kiwi2 → boxes2}/definitions/base_opensuse12.3_kvm/config.sh +0 -0
- data/spec/data/{kiwi2 → boxes2}/definitions/base_opensuse12.3_kvm/config.xml +0 -0
- data/spec/data/{kiwi2 → boxes2}/definitions/base_opensuse12.3_kvm/root/home/vagrant/.ssh/authorized_keys +0 -0
- data/spec/data/{kiwi2 → boxes2}/definitions/base_opensuse13.1_kvm/config.sh +0 -0
- data/spec/data/{kiwi2 → boxes2}/definitions/base_opensuse13.1_kvm/config.xml +0 -0
- data/spec/data/{kiwi2 → boxes2}/definitions/base_opensuse13.1_kvm/root/home/vagrant/.ssh/authorized_keys +0 -0
- data/spec/data/{kiwi3/definitions/base_opensuse13.1_kvm → boxes3/definitions/base_opensuse12.3_kvm}/.gitkeep +0 -0
- data/spec/data/{kiwi4/definitions/base_opensuse12.3_kvm → boxes3/definitions/base_opensuse13.1_kvm}/.gitkeep +0 -0
- data/spec/data/{kiwi4/definitions/base_opensuse13.1_kvm → boxes4/definitions/base_opensuse12.3_kvm}/.gitkeep +0 -0
- data/spec/data/boxes4/definitions/base_opensuse13.1_kvm/.gitkeep +0 -0
- data/spec/import_base_command_spec.rb +15 -15
- data/spec/matchers_spec.rb +175 -0
- data/spec/remote_command_runner_spec.rb +5 -15
- data/spec/setup_command_spec.rb +63 -1
- metadata +33 -29
@@ -0,0 +1,148 @@
|
|
1
|
+
# Copyright (c) 2013-2014 SUSE LLC
|
2
|
+
#
|
3
|
+
# This program is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of version 3 of the GNU General Public License as
|
5
|
+
# published by the Free Software Foundation.
|
6
|
+
#
|
7
|
+
# This program is distributed in the hope that it will be useful,
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
10
|
+
# GNU General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License
|
13
|
+
# along with this program; if not, contact SUSE LLC.
|
14
|
+
#
|
15
|
+
# To contact SUSE about this file by physical or electronic mail,
|
16
|
+
# you may find current contact information at www.suse.com
|
17
|
+
|
18
|
+
RSpec::Matchers.define :fail do
|
19
|
+
match do |result|
|
20
|
+
if @exit_code
|
21
|
+
result.exit_code == @exit_code
|
22
|
+
else
|
23
|
+
result.exit_code != 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
chain :with_exit_code do |exit_code|
|
28
|
+
@exit_code = exit_code
|
29
|
+
end
|
30
|
+
|
31
|
+
failure_message do |result|
|
32
|
+
message = "Expected\n #{result.cmd}\nto fail"
|
33
|
+
if @exit_code
|
34
|
+
message += " with exit code #{@exit_code} but it exited with #{result.exit_code}"
|
35
|
+
else
|
36
|
+
message += " but it succeeded."
|
37
|
+
end
|
38
|
+
|
39
|
+
message
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
RSpec::Matchers.define :have_stderr do |expected|
|
44
|
+
match do |result|
|
45
|
+
if expected.is_a?(Regexp)
|
46
|
+
expected.match(result.stderr)
|
47
|
+
else
|
48
|
+
expected == result.stderr
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
failure_message do |result|
|
53
|
+
if expected.is_a?(Regexp)
|
54
|
+
message = "Expected stderr to match #{expected.inspect}"
|
55
|
+
message += " (was:\n\n#{(result.stderr)})"
|
56
|
+
else
|
57
|
+
message = "Expected stderr to be '#{expected}'"
|
58
|
+
message += "\n\nDiff of stderr:"
|
59
|
+
differ = RSpec::Support::Differ.new(color: true)
|
60
|
+
message += differ.diff(result.stderr, expected)
|
61
|
+
end
|
62
|
+
|
63
|
+
message
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
RSpec::Matchers.define :include_stderr do |expected|
|
68
|
+
match do |result|
|
69
|
+
result.stderr.include? expected
|
70
|
+
end
|
71
|
+
|
72
|
+
failure_message do |result|
|
73
|
+
"Expected stderr '#{result.stdout}' to include '#{expected}'"
|
74
|
+
end
|
75
|
+
failure_message_when_negated do |result|
|
76
|
+
"Expected stderr '#{result.stdout}' to not include '#{expected}'"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
RSpec::Matchers.define_negated_matcher :not_include_stderr, :include_stderr
|
80
|
+
|
81
|
+
RSpec::Matchers.define :have_stdout do |expected|
|
82
|
+
match do |result|
|
83
|
+
if expected.is_a?(Regexp)
|
84
|
+
expected.match(result.stdout)
|
85
|
+
else
|
86
|
+
expected == result.stdout
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
failure_message do |result|
|
91
|
+
if expected.is_a?(Regexp)
|
92
|
+
message = "Expected stdout to match #{expected.inspect}"
|
93
|
+
message += " (was:\n\n#{(result.stdout)})"
|
94
|
+
else
|
95
|
+
message = "Expected stdout to be '#{expected}'"
|
96
|
+
message += "\n\nDiff of stdout:"
|
97
|
+
differ = RSpec::Support::Differ.new(color: true)
|
98
|
+
message += differ.diff(result.stdout, expected)
|
99
|
+
end
|
100
|
+
|
101
|
+
message
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
RSpec::Matchers.define :include_stdout do |expected|
|
106
|
+
match do |result|
|
107
|
+
result.stdout.include? expected
|
108
|
+
end
|
109
|
+
|
110
|
+
failure_message do |result|
|
111
|
+
"Expected stdout '#{result.stdout}' to include '#{expected}'"
|
112
|
+
end
|
113
|
+
failure_message_when_negated do |result|
|
114
|
+
"Expected stdout '#{result.stdout}' to not include '#{expected}'"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
RSpec::Matchers.define_negated_matcher :not_include_stdout, :include_stdout
|
118
|
+
|
119
|
+
RSpec::Matchers.define :succeed do
|
120
|
+
chain :with_stderr do
|
121
|
+
@allow_stderr = true
|
122
|
+
end
|
123
|
+
|
124
|
+
chain :with_or_without_stderr do
|
125
|
+
@ignore_stderr = true
|
126
|
+
end
|
127
|
+
|
128
|
+
match do |result|
|
129
|
+
return false if result.exit_code != 0
|
130
|
+
return false if !@ignore_stderr && !result.stderr.empty? && !@allow_stderr
|
131
|
+
return false if result.stderr.empty? && @allow_stderr
|
132
|
+
|
133
|
+
true
|
134
|
+
end
|
135
|
+
|
136
|
+
failure_message do |result|
|
137
|
+
message = "Expected\n #{result.cmd}\nto succeed"
|
138
|
+
if result.exit_code != 0
|
139
|
+
message += " but it returned with exit code #{result.exit_code}"
|
140
|
+
elsif !result.stderr.empty? && !@allow_stderr
|
141
|
+
message += " but it had stderr output.\nThe output was:\n#{result.stderr}"
|
142
|
+
elsif result.stderr.empty? && @allow_stderr
|
143
|
+
message += " with stderr output but stderr was empty."
|
144
|
+
end
|
145
|
+
|
146
|
+
message
|
147
|
+
end
|
148
|
+
end
|
@@ -46,6 +46,7 @@ module Pennyworth
|
|
46
46
|
|
47
47
|
Cheetah.run(
|
48
48
|
"ssh",
|
49
|
+
"-q",
|
49
50
|
"-o",
|
50
51
|
"UserKnownHostsFile=/dev/null",
|
51
52
|
"-o",
|
@@ -55,8 +56,6 @@ module Pennyworth
|
|
55
56
|
*args,
|
56
57
|
options
|
57
58
|
)
|
58
|
-
rescue Cheetah::ExecutionFailed => e
|
59
|
-
raise ExecutionFailed.new(e)
|
60
59
|
end
|
61
60
|
|
62
61
|
# Copy a local file to the remote system.
|
data/lib/pennyworth/runner.rb
CHANGED
data/lib/pennyworth/settings.rb
CHANGED
data/lib/pennyworth/spec.rb
CHANGED
data/lib/pennyworth/version.rb
CHANGED
data/lib/pennyworth/vm.rb
CHANGED
@@ -21,6 +21,10 @@ module Pennyworth
|
|
21
21
|
class VM
|
22
22
|
attr_accessor :ip, :runner
|
23
23
|
|
24
|
+
class CommandResult
|
25
|
+
attr_accessor :stdout, :stderr, :exit_code, :cmd, :error
|
26
|
+
end
|
27
|
+
|
24
28
|
def initialize(runner)
|
25
29
|
@runner = runner
|
26
30
|
end
|
@@ -34,7 +38,28 @@ module Pennyworth
|
|
34
38
|
end
|
35
39
|
|
36
40
|
def run_command(*args)
|
37
|
-
|
41
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
42
|
+
|
43
|
+
opts.merge!(
|
44
|
+
stdout: :capture,
|
45
|
+
stderr: :capture
|
46
|
+
)
|
47
|
+
|
48
|
+
result = CommandResult.new
|
49
|
+
result.cmd = args.join(" ")
|
50
|
+
begin
|
51
|
+
stdout, stderr = command_runner.run(*args, opts)
|
52
|
+
result.exit_code = 0
|
53
|
+
result.stdout = stdout
|
54
|
+
result.stderr = stderr
|
55
|
+
rescue Cheetah::ExecutionFailed => e
|
56
|
+
result.error = e
|
57
|
+
result.exit_code = e.status.exitstatus
|
58
|
+
result.stdout = e.stdout
|
59
|
+
result.stderr = e.stderr
|
60
|
+
end
|
61
|
+
|
62
|
+
result
|
38
63
|
end
|
39
64
|
|
40
65
|
def inject_file(source, destination, opts = {})
|
@@ -19,7 +19,7 @@ require "spec_helper.rb"
|
|
19
19
|
|
20
20
|
describe Pennyworth::BuildBaseCommand do
|
21
21
|
|
22
|
-
let(:tmp_dir) { "/tmp/
|
22
|
+
let(:tmp_dir) { "/tmp/vagrant-build-environment" }
|
23
23
|
let(:expected_content) {
|
24
24
|
<<-EOT
|
25
25
|
---
|
@@ -41,8 +41,8 @@ EOT
|
|
41
41
|
context "with non-existing box state file" do
|
42
42
|
before(:each) do
|
43
43
|
Pennyworth::Cli.settings = Pennyworth::Settings.new
|
44
|
-
@
|
45
|
-
@cmd = Pennyworth::BuildBaseCommand.new(@
|
44
|
+
@boxes_dir = File.join(test_data_dir, "boxes")
|
45
|
+
@cmd = Pennyworth::BuildBaseCommand.new(@boxes_dir)
|
46
46
|
end
|
47
47
|
|
48
48
|
it "reads box sources state of one box" do
|
@@ -59,7 +59,7 @@ EOT
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it "writes box state file" do
|
62
|
-
box_state_file = File.join(@
|
62
|
+
box_state_file = File.join(@boxes_dir, "box_state.yaml")
|
63
63
|
|
64
64
|
box_state = {}
|
65
65
|
[ "base_opensuse13.1_kvm", "base_opensuse12.3_kvm" ].each do |box|
|
@@ -92,26 +92,36 @@ EOT
|
|
92
92
|
# Don't actually build
|
93
93
|
allow(@cmd).to receive(:base_image_create)
|
94
94
|
allow(@cmd).to receive(:base_image_export)
|
95
|
-
allow(@cmd).to receive(:base_image_cleanup_build)
|
96
95
|
|
97
96
|
allow(@cmd).to receive(:log) # Don't print to stdout
|
98
97
|
|
99
98
|
@cmd.execute(tmp_dir, "base_opensuse13.1_kvm")
|
100
99
|
@cmd.execute(tmp_dir, "base_opensuse12.3_kvm")
|
101
100
|
|
102
|
-
box_state_file = File.join(@
|
101
|
+
box_state_file = File.join(@boxes_dir, "box_state.yaml")
|
103
102
|
|
104
103
|
expect(File.read(box_state_file)).to eq expected_content
|
105
104
|
|
106
105
|
FileUtils.rm(box_state_file) if File.exist?(box_state_file)
|
107
106
|
end
|
107
|
+
|
108
|
+
it "triggers kiwi builds" do
|
109
|
+
expect(@cmd).to receive(:build_kiwi)
|
110
|
+
allow(@cmd).to receive(:base_image_cleanup_build)
|
111
|
+
@cmd.execute(tmp_dir, "base_opensuse13.1_kvm")
|
112
|
+
end
|
113
|
+
|
114
|
+
it "triggers veewee builds" do
|
115
|
+
expect(@cmd).to receive(:build_veewee)
|
116
|
+
@cmd.execute(tmp_dir, "veewee_definition")
|
117
|
+
end
|
108
118
|
end
|
109
119
|
|
110
120
|
context "with existing box state file" do
|
111
121
|
before(:each) do
|
112
122
|
Pennyworth::Cli.settings = Pennyworth::Settings.new
|
113
|
-
@
|
114
|
-
@cmd = Pennyworth::BuildBaseCommand.new(@
|
123
|
+
@boxes_dir = File.join(test_data_dir, "boxes2")
|
124
|
+
@cmd = Pennyworth::BuildBaseCommand.new(@boxes_dir)
|
115
125
|
end
|
116
126
|
|
117
127
|
it "reads box state file" do
|
@@ -129,8 +139,6 @@ EOT
|
|
129
139
|
allow(@cmd).to receive(:write_box_state_file) # Don't actually write data
|
130
140
|
|
131
141
|
expect(@cmd).to receive(:base_image_create)
|
132
|
-
expect(@cmd).to receive(:base_image_export)
|
133
|
-
expect(@cmd).to receive(:base_image_cleanup_build)
|
134
142
|
@cmd.execute(tmp_dir, "base_opensuse13.1_kvm")
|
135
143
|
end
|
136
144
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -28,13 +28,13 @@ describe Pennyworth::ImportBaseCommand do
|
|
28
28
|
stub_request(:get, /example.com.*import_state.yaml/).
|
29
29
|
with(headers: {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
|
30
30
|
to_return(status: 200, body: File.read(File.join(test_data_dir,
|
31
|
-
"/
|
31
|
+
"/boxes5/import_state.yaml")), headers: {})
|
32
32
|
end
|
33
33
|
|
34
34
|
context "without box state file" do
|
35
35
|
before(:each) do
|
36
|
-
@
|
37
|
-
@cmd = Pennyworth::ImportBaseCommand.new(@
|
36
|
+
@boxes_dir = File.join(test_data_dir, "boxes")
|
37
|
+
@cmd = Pennyworth::ImportBaseCommand.new(@boxes_dir, "http://example.com/pennyworth/")
|
38
38
|
allow(Pennyworth::Libvirt).to receive(:ensure_libvirt_env_started)
|
39
39
|
allow(@cmd).to receive(:log)
|
40
40
|
allow(@cmd).to receive(:write_import_state_file) # Don't write state
|
@@ -43,7 +43,7 @@ describe Pennyworth::ImportBaseCommand do
|
|
43
43
|
it "imports a local box" do
|
44
44
|
expect(@cmd).to receive(:base_image_clean).with("base_opensuse12.3_kvm")
|
45
45
|
expect_any_instance_of(Pennyworth::Vagrant).to receive(:run).with("box", "add",
|
46
|
-
"base_opensuse12.3_kvm", "#{@
|
46
|
+
"base_opensuse12.3_kvm", "#{@boxes_dir}/base_opensuse12.3_kvm.box",
|
47
47
|
"--force")
|
48
48
|
|
49
49
|
@cmd.execute("base_opensuse12.3_kvm", :local => true)
|
@@ -66,14 +66,14 @@ describe Pennyworth::ImportBaseCommand do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
it "fetches the box state file from an url with a trailing slash" do
|
69
|
-
cmd = Pennyworth::ImportBaseCommand.new(@
|
69
|
+
cmd = Pennyworth::ImportBaseCommand.new(@boxes_dir, "http://example.com/pennyworth/")
|
70
70
|
cmd.read_remote_box_state_file()
|
71
71
|
|
72
72
|
assert_requested(@box_state_get)
|
73
73
|
end
|
74
74
|
|
75
75
|
it "fetches the box state file from an url without a trailing slash" do
|
76
|
-
cmd = Pennyworth::ImportBaseCommand.new(@
|
76
|
+
cmd = Pennyworth::ImportBaseCommand.new(@boxes_dir, "http://example.com/pennyworth")
|
77
77
|
cmd.read_remote_box_state_file()
|
78
78
|
|
79
79
|
assert_requested(@box_state_get)
|
@@ -83,12 +83,12 @@ describe Pennyworth::ImportBaseCommand do
|
|
83
83
|
|
84
84
|
context "with box state file" do
|
85
85
|
before(:each) do
|
86
|
-
@
|
87
|
-
@cmd = Pennyworth::ImportBaseCommand.new(@
|
86
|
+
@boxes_dir = File.join(test_data_dir, "boxes2")
|
87
|
+
@cmd = Pennyworth::ImportBaseCommand.new(@boxes_dir)
|
88
88
|
allow(Pennyworth::Libvirt).to receive(:ensure_libvirt_env_started)
|
89
89
|
allow(@cmd).to receive(:log)
|
90
90
|
allow(@cmd).to receive(:fetch_remote_box_state_file).and_return(
|
91
|
-
File.read(File.join(@
|
91
|
+
File.read(File.join(@boxes_dir, "box_state.yaml")))
|
92
92
|
end
|
93
93
|
|
94
94
|
it "writes import state file" do
|
@@ -96,7 +96,7 @@ describe Pennyworth::ImportBaseCommand do
|
|
96
96
|
allow(@cmd).to receive(:vagrant)
|
97
97
|
allow_any_instance_of(Pennyworth::Vagrant).to receive(:run)
|
98
98
|
|
99
|
-
import_state_file = File.join(@
|
99
|
+
import_state_file = File.join(@boxes_dir, "import_state.yaml")
|
100
100
|
|
101
101
|
FileUtils.rm(import_state_file) if File.exist?(import_state_file)
|
102
102
|
|
@@ -126,13 +126,13 @@ base_opensuse12.3_kvm: e4e743b5340686d8488dbce54b5644d8
|
|
126
126
|
|
127
127
|
context "with box and import state files" do
|
128
128
|
before(:each) do
|
129
|
-
@
|
130
|
-
@cmd = Pennyworth::ImportBaseCommand.new(@
|
129
|
+
@boxes_dir = File.join(test_data_dir, "boxes3")
|
130
|
+
@cmd = Pennyworth::ImportBaseCommand.new(@boxes_dir, "http://example.com/pennyworth/")
|
131
131
|
allow(Pennyworth::Libvirt).to receive(:ensure_libvirt_env_started)
|
132
132
|
allow(@cmd).to receive(:log)
|
133
133
|
allow(@cmd).to receive(:write_import_state_file) # Don't write state
|
134
134
|
allow(@cmd).to receive(:fetch_remote_box_state_file).and_return(
|
135
|
-
File.read(File.join(@
|
135
|
+
File.read(File.join(@boxes_dir, "box_state.yaml")))
|
136
136
|
end
|
137
137
|
|
138
138
|
it "imports changed local box" do
|
@@ -166,8 +166,8 @@ base_opensuse12.3_kvm: e4e743b5340686d8488dbce54b5644d8
|
|
166
166
|
|
167
167
|
context "without box state, but with import state files" do
|
168
168
|
before(:each) do
|
169
|
-
@
|
170
|
-
@cmd = Pennyworth::ImportBaseCommand.new(@
|
169
|
+
@boxes_dir = File.join(test_data_dir, "boxes4")
|
170
|
+
@cmd = Pennyworth::ImportBaseCommand.new(@boxes_dir)
|
171
171
|
allow(Pennyworth::Libvirt).to receive(:ensure_libvirt_env_started)
|
172
172
|
allow(@cmd).to receive(:log)
|
173
173
|
end
|