pennyworth-tool 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.hound.yml +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +18 -0
- data/CONTRIBUTING.md +67 -0
- data/COPYING +674 -0
- data/Gemfile +28 -0
- data/README.md +339 -0
- data/Rakefile +33 -0
- data/bin/pennyworth +26 -0
- data/config/setup.yml +17 -0
- data/examples/README.md +23 -0
- data/examples/kiwi/definitions/base_opensuse13.1_kvm/config.sh +87 -0
- data/examples/kiwi/definitions/base_opensuse13.1_kvm/config.xml +64 -0
- data/examples/kiwi/definitions/base_opensuse13.1_kvm/root/etc/sysconfig/network/ifcfg-eth0 +2 -0
- data/examples/kiwi/definitions/base_opensuse13.1_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
- data/examples/vagrant/Vagrantfile +14 -0
- data/files/99-libvirt.rules +2 -0
- data/files/image_test-template.xml +43 -0
- data/files/pool-default.xml +6 -0
- data/lib/image_runner.rb +89 -0
- data/lib/pennyworth.rb +65 -0
- data/lib/pennyworth/cli.rb +339 -0
- data/lib/pennyworth/cli_host_controller.rb +107 -0
- data/lib/pennyworth/commands/base_command.rb +96 -0
- data/lib/pennyworth/commands/boot_command.rb +29 -0
- data/lib/pennyworth/commands/build_base_command.rb +103 -0
- data/lib/pennyworth/commands/command.rb +43 -0
- data/lib/pennyworth/commands/down_command.rb +25 -0
- data/lib/pennyworth/commands/import_base_command.rb +112 -0
- data/lib/pennyworth/commands/import_ssh_keys_command.rb +27 -0
- data/lib/pennyworth/commands/list_command.rb +41 -0
- data/lib/pennyworth/commands/setup_command.rb +209 -0
- data/lib/pennyworth/commands/shutdown_command.rb +28 -0
- data/lib/pennyworth/commands/status_command.rb +26 -0
- data/lib/pennyworth/commands/up_command.rb +27 -0
- data/lib/pennyworth/exceptions.rb +39 -0
- data/lib/pennyworth/helper.rb +39 -0
- data/lib/pennyworth/host_config.rb +86 -0
- data/lib/pennyworth/host_runner.rb +133 -0
- data/lib/pennyworth/image_runner.rb +89 -0
- data/lib/pennyworth/libvirt.rb +93 -0
- data/lib/pennyworth/local_command_runner.rb +77 -0
- data/lib/pennyworth/local_runner.rb +34 -0
- data/lib/pennyworth/lock_service.rb +87 -0
- data/lib/pennyworth/remote_command_runner.rb +144 -0
- data/lib/pennyworth/runner.rb +27 -0
- data/lib/pennyworth/settings.rb +42 -0
- data/lib/pennyworth/spec.rb +96 -0
- data/lib/pennyworth/spec_profiler.rb +85 -0
- data/lib/pennyworth/ssh_keys_importer.rb +107 -0
- data/lib/pennyworth/urls.rb +28 -0
- data/lib/pennyworth/vagrant.rb +81 -0
- data/lib/pennyworth/vagrant_command.rb +120 -0
- data/lib/pennyworth/vagrant_runner.rb +44 -0
- data/lib/pennyworth/version.rb +22 -0
- data/lib/pennyworth/vm.rb +62 -0
- data/man/.gitignore +2 -0
- data/man/pennyworth.1.md +28 -0
- data/pennyworth.gemspec +57 -0
- data/prophet/Gemfile +3 -0
- data/prophet/prophet.rb +82 -0
- data/spec/base_command_spec.rb +30 -0
- data/spec/build_base_command_spec.rb +147 -0
- data/spec/cli_host_controller_spec.rb +113 -0
- data/spec/data/hosts.yaml +10 -0
- data/spec/data/kiwi/base_opensuse12.3_kvm.box +1 -0
- data/spec/data/kiwi/base_opensuse13.1_kvm.box +1 -0
- data/spec/data/kiwi/definitions/base_opensuse12.3_kvm/config.sh +1 -0
- data/spec/data/kiwi/definitions/base_opensuse12.3_kvm/config.xml +1 -0
- data/spec/data/kiwi/definitions/base_opensuse12.3_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
- data/spec/data/kiwi/definitions/base_opensuse13.1_kvm/config.sh +1 -0
- data/spec/data/kiwi/definitions/base_opensuse13.1_kvm/config.xml +1 -0
- data/spec/data/kiwi/definitions/base_opensuse13.1_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
- data/spec/data/kiwi2/box_state.yaml +14 -0
- data/spec/data/kiwi2/definitions/base_opensuse12.3_kvm/config.sh +1 -0
- data/spec/data/kiwi2/definitions/base_opensuse12.3_kvm/config.xml +1 -0
- data/spec/data/kiwi2/definitions/base_opensuse12.3_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
- data/spec/data/kiwi2/definitions/base_opensuse13.1_kvm/config.sh +1 -0
- data/spec/data/kiwi2/definitions/base_opensuse13.1_kvm/config.xml +1 -0
- data/spec/data/kiwi2/definitions/base_opensuse13.1_kvm/root/home/vagrant/.ssh/authorized_keys +1 -0
- data/spec/data/kiwi3/box_state.yaml +13 -0
- data/spec/data/kiwi3/definitions/base_opensuse12.3_kvm/.gitkeep +0 -0
- data/spec/data/kiwi3/definitions/base_opensuse13.1_kvm/.gitkeep +0 -0
- data/spec/data/kiwi3/import_state.yaml +3 -0
- data/spec/data/kiwi4/definitions/base_opensuse12.3_kvm/.gitkeep +0 -0
- data/spec/data/kiwi4/definitions/base_opensuse13.1_kvm/.gitkeep +0 -0
- data/spec/data/kiwi4/import_state.yaml +3 -0
- data/spec/data/kiwi5/import_state.yaml +3 -0
- data/spec/data/vagrant/.gitkeep +0 -0
- data/spec/host_config_spec.rb +197 -0
- data/spec/host_runner_spec.rb +112 -0
- data/spec/image_runner_spec.rb +62 -0
- data/spec/import_base_command_spec.rb +189 -0
- data/spec/local_command_runner_spec.rb +117 -0
- data/spec/local_runner_spec.rb +42 -0
- data/spec/lock_service_spec.rb +95 -0
- data/spec/remote_command_runner_spec.rb +115 -0
- data/spec/settings_spec.rb +26 -0
- data/spec/setup_command_spec.rb +49 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/spec_profiler_spec.rb +63 -0
- data/spec/spec_spec.rb +99 -0
- data/spec/support/command_runner_examples.rb +29 -0
- data/spec/support/runner_examples.rb +34 -0
- data/spec/urls_spec.rb +46 -0
- data/spec/vagrant_command_spec.rb +51 -0
- data/spec/vagrant_runner_spec.rb +40 -0
- data/spec/vagrant_spec.rb +288 -0
- data/spec/vm_spec.rb +56 -0
- metadata +257 -0
@@ -0,0 +1,34 @@
|
|
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
|
+
module Pennyworth
|
19
|
+
class LocalRunner < Runner
|
20
|
+
def initialize(opts = {})
|
21
|
+
@command_runner = LocalCommandRunner.new(opts)
|
22
|
+
end
|
23
|
+
|
24
|
+
def start
|
25
|
+
# Nothing to do here
|
26
|
+
|
27
|
+
"127.0.0.1"
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop
|
31
|
+
# Nothing to do here either
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# Copyright (c) 2015 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
|
+
module Pennyworth
|
19
|
+
class LockService
|
20
|
+
attr_reader :lock_server_host
|
21
|
+
attr_reader :lock_server_port
|
22
|
+
|
23
|
+
def initialize(lock_server_address)
|
24
|
+
fields = lock_server_address.split(":")
|
25
|
+
@lock_server_host = fields[0]
|
26
|
+
@lock_server_port = fields[1]
|
27
|
+
@sockets = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def socket(lock_name)
|
31
|
+
if !@sockets.has_key?(lock_name)
|
32
|
+
@sockets[lock_name] = TCPSocket.new(@lock_server_host, @lock_server_port)
|
33
|
+
end
|
34
|
+
@sockets[lock_name]
|
35
|
+
end
|
36
|
+
|
37
|
+
def request_lock(lock_name)
|
38
|
+
socket(lock_name).puts("g #{lock_name}")
|
39
|
+
response = socket(lock_name).gets
|
40
|
+
if response =~ /^1/
|
41
|
+
return true
|
42
|
+
elsif response =~ /^0/
|
43
|
+
return false
|
44
|
+
else
|
45
|
+
raise LockError.new("Error, received: #{response}")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def keep_lock
|
50
|
+
# Sleep forever to keep process running to keep TCP connection to lock
|
51
|
+
# server open. When the process is ended the connection is closed and the
|
52
|
+
# lock is released. Users can end the process and release the lock with
|
53
|
+
# Ctrl-C.
|
54
|
+
sleep
|
55
|
+
end
|
56
|
+
|
57
|
+
def release_lock(lock_name)
|
58
|
+
if !@sockets[lock_name]
|
59
|
+
raise LockError.new("Lock '#{lock_name}' doesn't exist")
|
60
|
+
end
|
61
|
+
@sockets[lock_name].close
|
62
|
+
@sockets.delete(lock_name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def locked?(lock_name)
|
66
|
+
socket(lock_name).puts("i #{lock_name}")
|
67
|
+
response = socket(lock_name).gets
|
68
|
+
if response =~ /^1/
|
69
|
+
return true
|
70
|
+
else
|
71
|
+
return false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def info(lock_name)
|
76
|
+
if locked?(lock_name)
|
77
|
+
socket(lock_name).puts("d #{lock_name}")
|
78
|
+
response = socket(lock_name).gets
|
79
|
+
response =~ /^#{lock_name}: (.*):/
|
80
|
+
client = $1
|
81
|
+
return "'#{lock_name}' is locked by #{client}"
|
82
|
+
else
|
83
|
+
return "'#{lock_name}' is not locked"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,144 @@
|
|
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
|
+
# The purpose of this class is to execute commands on a remote machine via SSH.
|
19
|
+
module Pennyworth
|
20
|
+
class RemoteCommandRunner
|
21
|
+
def initialize(ip, username)
|
22
|
+
@ip = ip
|
23
|
+
@username = username
|
24
|
+
end
|
25
|
+
|
26
|
+
def run(*args)
|
27
|
+
# When ssh executes commands, it passes them through shell expansion.
|
28
|
+
# For example, compare
|
29
|
+
#
|
30
|
+
# $ echo '$HOME'
|
31
|
+
# $HOME
|
32
|
+
#
|
33
|
+
# with
|
34
|
+
#
|
35
|
+
# $ ssh localhost echo '$HOME'
|
36
|
+
# /home/dmajda
|
37
|
+
#
|
38
|
+
# To mitigate that and maintain usual Cheetah semantics, we need to
|
39
|
+
# protect the command and its arguments using another layer of escaping.
|
40
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
41
|
+
args.map! { |a| Shellwords.escape(a) } if !options[:skip_escape]
|
42
|
+
|
43
|
+
if user = options.delete(:as)
|
44
|
+
args = ["su", "-l", user, "-c"] + args
|
45
|
+
end
|
46
|
+
|
47
|
+
Cheetah.run(
|
48
|
+
"ssh",
|
49
|
+
"-o",
|
50
|
+
"UserKnownHostsFile=/dev/null",
|
51
|
+
"-o",
|
52
|
+
"StrictHostKeyChecking=no",
|
53
|
+
"#{@username}@#{@ip}",
|
54
|
+
"LC_ALL=C",
|
55
|
+
*args,
|
56
|
+
options
|
57
|
+
)
|
58
|
+
rescue Cheetah::ExecutionFailed => e
|
59
|
+
raise ExecutionFailed.new(e)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Copy a local file to the remote system.
|
63
|
+
#
|
64
|
+
# +source+:: Path to the local file
|
65
|
+
# +destination+:: Path to the remote file or directory. If +destination+ is a
|
66
|
+
# path, the same filename as +source+ will be used.
|
67
|
+
# +opts+:: Options to modify the attributes of the remote file.
|
68
|
+
#
|
69
|
+
# Available options:
|
70
|
+
# [owner]:: Owner of the file, e.g. "tux"
|
71
|
+
# [group]:: Group of the file, e.g. "users"
|
72
|
+
# [mode]:: Mode of the file, e.g. "600"
|
73
|
+
def inject_file(source, destination, opts = {})
|
74
|
+
# Append filename (taken from +source+) to destination if it is a path, so
|
75
|
+
# that +destination+ is always the full target path including the filename.
|
76
|
+
destination += File.basename(source) if destination.end_with?("/")
|
77
|
+
|
78
|
+
Cheetah.run(
|
79
|
+
"scp",
|
80
|
+
"-o",
|
81
|
+
"UserKnownHostsFile=/dev/null",
|
82
|
+
"-o",
|
83
|
+
"StrictHostKeyChecking=no",
|
84
|
+
source,
|
85
|
+
"#{@username}@#{@ip}:#{destination}"
|
86
|
+
)
|
87
|
+
|
88
|
+
if opts[:owner] || opts[:group]
|
89
|
+
owner_group = opts[:owner] || ""
|
90
|
+
owner_group += ":#{opts[:group]}" if opts[:group]
|
91
|
+
run "chown", "-R", owner_group, destination
|
92
|
+
end
|
93
|
+
|
94
|
+
if opts[:mode]
|
95
|
+
run "chmod", opts[:mode], destination
|
96
|
+
end
|
97
|
+
rescue Cheetah::ExecutionFailed => e
|
98
|
+
raise ExecutionFailed.new(e)
|
99
|
+
end
|
100
|
+
|
101
|
+
def extract_file(source, destination)
|
102
|
+
Cheetah.run(
|
103
|
+
"scp",
|
104
|
+
"-o",
|
105
|
+
"UserKnownHostsFile=/dev/null",
|
106
|
+
"-o",
|
107
|
+
"StrictHostKeyChecking=no",
|
108
|
+
"#{@username}@#{@ip}:#{source}",
|
109
|
+
destination
|
110
|
+
)
|
111
|
+
rescue Cheetah::ExecutionFailed => e
|
112
|
+
raise ExecutionFailed.new(e)
|
113
|
+
end
|
114
|
+
|
115
|
+
def inject_directory(source, destination, opts = {})
|
116
|
+
if opts[:owner] || opts[:group]
|
117
|
+
owner_group = opts[:owner] || ""
|
118
|
+
owner_group += ":#{opts[:group]}" if opts[:group]
|
119
|
+
end
|
120
|
+
|
121
|
+
chown_cmd = " && chown #{owner_group} '#{destination}'" if owner_group
|
122
|
+
mkdir_cmd = "test -d '#{destination}' || (mkdir -p '#{destination}' #{chown_cmd} )"
|
123
|
+
|
124
|
+
run mkdir_cmd, skip_escape: true
|
125
|
+
|
126
|
+
Cheetah.run(
|
127
|
+
"scp",
|
128
|
+
"-r",
|
129
|
+
"-o",
|
130
|
+
"UserKnownHostsFile=/dev/null",
|
131
|
+
"-o",
|
132
|
+
"StrictHostKeyChecking=no",
|
133
|
+
source,
|
134
|
+
"#{@username}@#{@ip}:#{destination}"
|
135
|
+
)
|
136
|
+
|
137
|
+
if owner_group
|
138
|
+
run "chown", "-R", owner_group, File.join(destination, File.basename(source))
|
139
|
+
end
|
140
|
+
rescue Cheetah::ExecutionFailed => e
|
141
|
+
raise ExecutionFailed.new(e)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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
|
+
module Pennyworth
|
19
|
+
# Base class for the runner classes
|
20
|
+
class Runner
|
21
|
+
attr_reader :command_runner
|
22
|
+
|
23
|
+
def cleanup_directory(dir)
|
24
|
+
command_runner.run("test -d #{dir} && rm -r #{dir}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
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
|
+
module Pennyworth
|
19
|
+
class Settings
|
20
|
+
|
21
|
+
attr_accessor :verbose, :silent, :definitions_dir
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@verbose = false
|
25
|
+
@silent = false
|
26
|
+
@definitions_dir = File.expand_path("~/.pennyworth")
|
27
|
+
end
|
28
|
+
|
29
|
+
def kiwi_dir
|
30
|
+
File.join(@definitions_dir, "/kiwi")
|
31
|
+
end
|
32
|
+
|
33
|
+
def vagrant_dir
|
34
|
+
File.join(@definitions_dir, "/vagrant")
|
35
|
+
end
|
36
|
+
|
37
|
+
def version
|
38
|
+
Pennyworth::VERSION
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,96 @@
|
|
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
|
+
require "cheetah"
|
19
|
+
require "libvirt"
|
20
|
+
require "socket"
|
21
|
+
require "open-uri"
|
22
|
+
require "yaml"
|
23
|
+
|
24
|
+
require_relative "exceptions"
|
25
|
+
require_relative "helper"
|
26
|
+
require_relative "libvirt"
|
27
|
+
require_relative "runner"
|
28
|
+
require_relative "vagrant"
|
29
|
+
require_relative "vagrant_runner"
|
30
|
+
require_relative "image_runner"
|
31
|
+
require_relative "host_config"
|
32
|
+
require_relative "host_runner"
|
33
|
+
require_relative "lock_service"
|
34
|
+
require_relative "ssh_keys_importer"
|
35
|
+
require_relative "vm"
|
36
|
+
require_relative "spec_profiler"
|
37
|
+
require_relative "remote_command_runner"
|
38
|
+
require_relative "settings"
|
39
|
+
require_relative "local_runner"
|
40
|
+
require_relative "local_command_runner"
|
41
|
+
|
42
|
+
module Pennyworth
|
43
|
+
module SpecHelper
|
44
|
+
def start_system(opts)
|
45
|
+
opts = {
|
46
|
+
skip_ssh_setup: false
|
47
|
+
}.merge(opts)
|
48
|
+
username = opts[:username] || "root"
|
49
|
+
if opts[:box]
|
50
|
+
runner = VagrantRunner.new(opts[:box], RSpec.configuration.vagrant_dir, username)
|
51
|
+
password = opts[:password] || "vagrant"
|
52
|
+
elsif opts[:image]
|
53
|
+
runner = ImageRunner.new(opts[:image], username)
|
54
|
+
password = opts[:password] || "linux"
|
55
|
+
elsif opts[:host]
|
56
|
+
config = HostConfig.new(RSpec.configuration.hosts_file)
|
57
|
+
config.read
|
58
|
+
runner = HostRunner.new(opts[:host], config, username)
|
59
|
+
elsif opts[:local]
|
60
|
+
runner = LocalRunner.new(env: opts[:env])
|
61
|
+
end
|
62
|
+
|
63
|
+
raise "No image specified." unless runner
|
64
|
+
|
65
|
+
system = VM.new(runner)
|
66
|
+
|
67
|
+
# Make sure to stop the machine again when the example group is done
|
68
|
+
self.class.after(:all) do
|
69
|
+
system.stop
|
70
|
+
end
|
71
|
+
|
72
|
+
measure("Boot machine '#{opts[:box] || opts[:image] || opts[:host]}'") do
|
73
|
+
system.start
|
74
|
+
end
|
75
|
+
if !opts[:skip_ssh_setup] && !opts[:host] && !opts[:local]
|
76
|
+
SshKeysImporter.import(system.ip, username, password)
|
77
|
+
end
|
78
|
+
|
79
|
+
system
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
RSpec.configure do |config|
|
85
|
+
defaults = Pennyworth::Settings.new
|
86
|
+
config.include(Pennyworth::SpecHelper)
|
87
|
+
config.add_setting :pennyworth_mode, default: false
|
88
|
+
config.add_setting :vagrant_dir, default: defaults.vagrant_dir
|
89
|
+
config.add_setting :hosts_file, default: File.join(defaults.definitions_dir, "/hosts.yaml")
|
90
|
+
|
91
|
+
config.before(:all) do
|
92
|
+
unless RSpec.configuration.pennyworth_mode
|
93
|
+
Pennyworth::Libvirt.ensure_libvirt_env_started
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,85 @@
|
|
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
|
+
require "benchmark"
|
19
|
+
|
20
|
+
def measure(label, &block)
|
21
|
+
own_parent = @parent_measurement
|
22
|
+
measurement = {
|
23
|
+
label: label,
|
24
|
+
child_measurements: []
|
25
|
+
}
|
26
|
+
|
27
|
+
@parent_measurement = measurement
|
28
|
+
time = Benchmark.measure do
|
29
|
+
block.call
|
30
|
+
end
|
31
|
+
@parent_measurement = own_parent
|
32
|
+
measurement.merge!(time: time.real)
|
33
|
+
|
34
|
+
# Calculate time that was not spent in the measured child blocks but somewhere
|
35
|
+
# else
|
36
|
+
if !measurement[:child_measurements].empty?
|
37
|
+
other_time = measurement[:time]
|
38
|
+
measurement[:child_measurements].each do |child|
|
39
|
+
other_time -= child[:time]
|
40
|
+
end
|
41
|
+
measurement[:child_measurements] << { label: "Other", time: other_time }
|
42
|
+
end
|
43
|
+
|
44
|
+
if own_parent
|
45
|
+
own_parent[:child_measurements] << measurement
|
46
|
+
else
|
47
|
+
@measurements << measurement
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def print_measurement(measurement, indent = 0)
|
52
|
+
name = measurement[:label][0..65-indent].ljust(70-indent)
|
53
|
+
STDERR.puts (" " * indent) + "#{name}: #{measurement[:time]}"
|
54
|
+
|
55
|
+
if measurement[:child_measurements]
|
56
|
+
measurement[:child_measurements].each do |child|
|
57
|
+
print_measurement(child, indent + 2)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
RSpec.configure do |config|
|
63
|
+
config.before(:all) do
|
64
|
+
@measurements = []
|
65
|
+
end
|
66
|
+
|
67
|
+
config.around(:each) do |example|
|
68
|
+
if RSpec.configuration.pennyworth_mode
|
69
|
+
example.run
|
70
|
+
else
|
71
|
+
measure(example.metadata[:full_description]) do
|
72
|
+
example.run
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
config.after(:all) do
|
78
|
+
if !RSpec.configuration.pennyworth_mode
|
79
|
+
@measurements.each do |measurement|
|
80
|
+
print_measurement(measurement)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|