virtualbox-guestcontrol 1.0.2 → 1.1
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.
- data/Gemfile +2 -0
- data/README.md +3 -0
- data/bin/rvbox +1 -112
- data/lib/virtualbox-guestcontrol.rb +4 -207
- data/lib/virtualbox/guest_control/command.rb +125 -0
- data/lib/virtualbox/guest_control/machine.rb +229 -0
- data/lib/virtualbox/guest_control/usb_device.rb +59 -0
- data/lib/{virtualbox-guestcontrol → virtualbox/guest_control}/version.rb +1 -1
- data/virtualbox-guestcontrol.gemspec +2 -1
- metadata +23 -4
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -20,6 +20,9 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
TODO: Write usage instructions here
|
22
22
|
|
23
|
+
bundle exec rvbox execute --username XXX --password YYY "ZZZ" "c:\\windows\system32\\systeminfo.exe" |grep "System Up Time"
|
24
|
+
bundle exec rvbox execute --username XXX --password YYY "ZZZ" "c:\\windows\system32\\shutdown.exe" -s -t 0
|
25
|
+
|
23
26
|
## Contributing
|
24
27
|
|
25
28
|
1. Fork it
|
data/bin/rvbox
CHANGED
@@ -1,116 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require File.expand_path("../../lib/virtualbox-guestcontrol.rb", __FILE__)
|
3
3
|
|
4
|
-
|
5
|
-
option ["-u", "--username"], "USERNAME", "username to log in as"
|
6
|
-
option ["-p", "--password"], "PASSWORD", "password to log in as"
|
7
|
-
option ["-t", "--timeout"], "TIMEOUT", "timeout in seconds"
|
8
|
-
option ["-b", "--vboxmanage"], "PATH", "path to VBoxManage"
|
9
|
-
|
10
|
-
def virtual_box
|
11
|
-
VirtualBox::GuestControl::Runner.configure do |c|
|
12
|
-
c.name = name
|
13
|
-
c.username = username
|
14
|
-
c.password = password
|
15
|
-
c.vbox_manage = vboxmanage unless vboxmanage.nil?
|
16
|
-
c.default_timeout = timeout unless vboxmanage.nil?
|
17
|
-
end
|
18
|
-
VirtualBox::GuestControl::Runner.new
|
19
|
-
end
|
20
|
-
|
21
|
-
subcommand "start", "start up the given VM" do
|
22
|
-
parameter "NAME", "name of virtual machine"
|
23
|
-
|
24
|
-
def execute
|
25
|
-
virtual_box.start!
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
subcommand "shutdown", "shutdown the given VM" do
|
30
|
-
parameter "NAME", "name of virtual machine"
|
31
|
-
|
32
|
-
def execute
|
33
|
-
virtual_box.shutdown!
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
subcommand "restart", "restart the given VM" do
|
38
|
-
parameter "NAME", "name of virtual machine"
|
39
|
-
|
40
|
-
def execute
|
41
|
-
virtual_box.restart!
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
subcommand "info", "list all known info about the VM" do
|
46
|
-
parameter "NAME", "name of virtual machine"
|
47
|
-
|
48
|
-
def execute
|
49
|
-
virtual_box.state.tap do |map|
|
50
|
-
map.keys.sort.each do |key|
|
51
|
-
puts [key, map[key]].join(": ")
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
subcommand "usblist", "list usb devices on host" do
|
58
|
-
def execute
|
59
|
-
VirtualBox::GuestControl::Runner.usb_devices.each do |device|
|
60
|
-
puts device.to_s
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
subcommand "usbdetach", "detach usb devices on host" do
|
66
|
-
parameter "NAME", "name of virtual machine"
|
67
|
-
|
68
|
-
def execute
|
69
|
-
VirtualBox::GuestControl::Runner.usb_devices.each do |device|
|
70
|
-
device.detach(name)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
subcommand "status", "says if the vm is booted or not" do
|
76
|
-
parameter "NAME", "name of virtual machine"
|
77
|
-
|
78
|
-
def execute
|
79
|
-
if virtual_box.started?
|
80
|
-
puts "VM is started"
|
81
|
-
else
|
82
|
-
puts "VM is shutdown"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
subcommand "list", "lists the available VMs" do
|
88
|
-
option ["--uuid"], :flag, "show only uuid", :default => false
|
89
|
-
option ["--name"], :flag, "show only name", :default => false
|
90
|
-
|
91
|
-
def execute
|
92
|
-
VirtualBox::GuestControl::Runner.virtual_machines.each do |name, uuid|
|
93
|
-
if uuid?
|
94
|
-
puts uuid
|
95
|
-
elsif name?
|
96
|
-
puts name
|
97
|
-
else
|
98
|
-
puts [name, uuid].join("\t")
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
subcommand "execute", "execute a given command" do
|
105
|
-
parameter "NAME", "name of virtual machine"
|
106
|
-
parameter "[COMMAND_PARAMETERS] ...", "command and parameters to pass to the VM", :attribute_name => :command_parameters
|
107
|
-
|
108
|
-
def execute
|
109
|
-
image_name, arguments = command_parameters
|
110
|
-
virtual_box.execute *command_parameters
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
VirtualBoxCommand.run(ARGV)
|
4
|
+
VirtualBox::GuestControl::Command.run(ARGV)
|
116
5
|
|
@@ -4,215 +4,12 @@ require 'active_support/configurable'
|
|
4
4
|
require 'active_support/time'
|
5
5
|
require 'active_support/core_ext/hash/indifferent_access'
|
6
6
|
require 'clamp'
|
7
|
+
require 'state_machine'
|
7
8
|
|
8
9
|
module VirtualBox
|
9
10
|
module GuestControl
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
self.config[:default_timeout] = 240.seconds
|
14
|
-
self.config[:vbox_manage] = Shellter.which("VBoxManage")
|
15
|
-
|
16
|
-
config_accessor :vbox_manage
|
17
|
-
config_accessor :name
|
18
|
-
config_accessor :default_timeout
|
19
|
-
config_accessor :username
|
20
|
-
config_accessor :password
|
21
|
-
|
22
|
-
def valid?
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
def started?
|
27
|
-
state[:GuestAdditionsRunLevel] == "2" || state[:GuestAdditionsRunLevel] == "3"
|
28
|
-
end
|
29
|
-
|
30
|
-
def shutdown?
|
31
|
-
["poweroff", "aborted", "saved"].include?(state[:VMState])
|
32
|
-
end
|
33
|
-
|
34
|
-
def shutdown!(force = false)
|
35
|
-
return if shutdown?
|
36
|
-
|
37
|
-
detach_usb_devices
|
38
|
-
|
39
|
-
if force
|
40
|
-
Shellter.run(vbox_manage, "controlvm", ":name", "poweroff", :name => name)
|
41
|
-
wait_until { shutdown? }
|
42
|
-
else
|
43
|
-
begin
|
44
|
-
Shellter.run(vbox_manage, "controlvm", ":name", "acpipowerbutton", :name => name)
|
45
|
-
wait_until { shutdown? }
|
46
|
-
rescue TimeoutError
|
47
|
-
shutdown_machine(true)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def start!
|
53
|
-
return if started?
|
54
|
-
Shellter.run!(vbox_manage, "startvm", ":name", :name => name)
|
55
|
-
wait_until { started? }
|
56
|
-
end
|
57
|
-
|
58
|
-
def restart!
|
59
|
-
shutdown!
|
60
|
-
start!
|
61
|
-
end
|
62
|
-
|
63
|
-
# VBoxManage guestcontrol <vmname>|<uuid>
|
64
|
-
# exec[ute]
|
65
|
-
# --image <path to program>
|
66
|
-
# --username <name> --password <password>
|
67
|
-
# [--dos2unix]
|
68
|
-
# [--environment "<NAME>=<VALUE> [<NAME>=<VALUE>]"]
|
69
|
-
# [--timeout <msec>] [--unix2dos] [--verbose]
|
70
|
-
# [--wait-exit] [--wait-stdout] [--wait-stderr]
|
71
|
-
# [-- [<argument1>] ... [<argumentN>]]
|
72
|
-
def execute(command, *arguments)
|
73
|
-
with_started_machine do
|
74
|
-
options = arguments.extract_options!
|
75
|
-
params = ["guestcontrol", ":name", "execute", "--image", ":command"]
|
76
|
-
|
77
|
-
options[:name] = name
|
78
|
-
options[:command] = command
|
79
|
-
|
80
|
-
if username
|
81
|
-
params += ["--username", ":username"]
|
82
|
-
options[:username] = username
|
83
|
-
end
|
84
|
-
|
85
|
-
if password
|
86
|
-
params += ["--password", ":password"]
|
87
|
-
options[:password] = password
|
88
|
-
end
|
89
|
-
|
90
|
-
# params += ["--timeout", ":timeout"]
|
91
|
-
params += ["--wait-exit", "--wait-stdout"]
|
92
|
-
# options[:timeout] = default_timeout.to_s
|
93
|
-
|
94
|
-
unless arguments.empty?
|
95
|
-
params += ["--"] + arguments
|
96
|
-
end
|
97
|
-
|
98
|
-
params << options
|
99
|
-
|
100
|
-
result = Shellter.run(vbox_manage, *params)
|
101
|
-
puts result.stdout.read
|
102
|
-
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def state
|
107
|
-
result = Shellter.run!(vbox_manage, "showvminfo", ":name", "--machinereadable", :name => name)
|
108
|
-
{}.with_indifferent_access.tap do |map|
|
109
|
-
result.stdout.read.lines.each do |line|
|
110
|
-
name, value = line.strip.split("=").map { |y| y.gsub(/(^"|"$)/, "") }
|
111
|
-
map[name] = value
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
class UsbDevice
|
117
|
-
class << self
|
118
|
-
def parse(output, vbox_manage)
|
119
|
-
[].tap do |devices|
|
120
|
-
device = nil
|
121
|
-
output.lines.each do |line|
|
122
|
-
if device
|
123
|
-
if line.strip.blank?
|
124
|
-
devices << device
|
125
|
-
device = nil
|
126
|
-
else
|
127
|
-
key, value = line.split(":")
|
128
|
-
key = key.strip.gsub(" ", "_").underscore
|
129
|
-
value = value.strip
|
130
|
-
device.send(:"#{key}=", value)
|
131
|
-
end
|
132
|
-
else
|
133
|
-
next unless line =~ /UUID:/
|
134
|
-
value = line.split(":").last.strip
|
135
|
-
device = new(value, vbox_manage)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
attr_accessor :uuid, :vendor_id, :product_id, :revision
|
143
|
-
attr_accessor :manufacturer, :product, :address, :current_state
|
144
|
-
attr_accessor :serial_number
|
145
|
-
attr_accessor :vbox_manage
|
146
|
-
|
147
|
-
def initialize(uuid, vbox_manage)
|
148
|
-
self.vbox_manage = vbox_manage
|
149
|
-
self.uuid = uuid
|
150
|
-
end
|
151
|
-
|
152
|
-
def detach(name)
|
153
|
-
result = Shellter.run(vbox_manage, "controlvm", ":name", "usbdetach", ":uuid", :name => name, :uuid => uuid)
|
154
|
-
end
|
155
|
-
|
156
|
-
def attach(name)
|
157
|
-
Shellter.run!(vbox_manage, "controlvm", ":name", "usbattach", ":uuid", :name => name, :uuid => uuid)
|
158
|
-
end
|
159
|
-
|
160
|
-
def to_s
|
161
|
-
"#{product} (#{uuid}): #{current_state}"
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
def detach_usb_devices
|
166
|
-
self.class.usb_devices.each do |device|
|
167
|
-
device.detach(name)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def attach_usb_devices
|
172
|
-
self.class.usb_devices.each do |device|
|
173
|
-
device.attach(name)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
VM_MATCHER = /^"([^"]*)" \{(.*)\}$/
|
178
|
-
|
179
|
-
class << self
|
180
|
-
def virtual_machines
|
181
|
-
result = Shellter.run!(vbox_manage, "list", "vms")
|
182
|
-
result.stdout.read.lines.map do |line|
|
183
|
-
line.scan(VM_MATCHER).first
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def usb_devices
|
188
|
-
result = Shellter.run!(vbox_manage, "list", "usbhost")
|
189
|
-
UsbDevice.parse(result.stdout, vbox_manage)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
private
|
194
|
-
|
195
|
-
def wait_until
|
196
|
-
Timeout::timeout(default_timeout) do
|
197
|
-
loop do
|
198
|
-
result = yield
|
199
|
-
if result
|
200
|
-
break
|
201
|
-
else
|
202
|
-
sleep 5
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
def with_started_machine(shutdown_after = false)
|
209
|
-
begin
|
210
|
-
start!
|
211
|
-
yield
|
212
|
-
ensure
|
213
|
-
shutdown! if shutdown_after
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
11
|
+
autoload :Machine, 'virtualbox/guest_control/machine'
|
12
|
+
autoload :UsbDevice, 'virtualbox/guest_control/usb_device'
|
13
|
+
autoload :Command, 'virtualbox/guest_control/command'
|
217
14
|
end
|
218
15
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
module GuestControl
|
3
|
+
|
4
|
+
class Command < Clamp::Command
|
5
|
+
option ["-u", "--username"], "USERNAME", "username to log in as"
|
6
|
+
option ["-p", "--password"], "PASSWORD", "password to log in as"
|
7
|
+
option ["-t", "--timeout"], "TIMEOUT", "timeout in seconds"
|
8
|
+
option ["-b", "--vboxmanage"], "PATH", "path to VBoxManage"
|
9
|
+
|
10
|
+
def machine
|
11
|
+
VirtualBox::GuestControl::Machine.find_by_name(name).tap do |machine|
|
12
|
+
raise "No such machine #{name}" unless machine.present?
|
13
|
+
machine.username = username
|
14
|
+
machine.password = password
|
15
|
+
machine.vbox_manage = vboxmanage unless vboxmanage.nil?
|
16
|
+
machine.default_timeout = timeout unless vboxmanage.nil?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
subcommand "start", "start up the given VM" do
|
21
|
+
parameter "NAME", "name of virtual machine"
|
22
|
+
|
23
|
+
def execute
|
24
|
+
if machine.can_start?
|
25
|
+
machine.start!
|
26
|
+
else
|
27
|
+
puts "Machine can't start because it is currently: #{machine.status}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
subcommand "shutdown", "shutdown the given VM" do
|
33
|
+
parameter "NAME", "name of virtual machine"
|
34
|
+
|
35
|
+
def execute
|
36
|
+
if machine.can_shutdown?
|
37
|
+
machine.shutdown!
|
38
|
+
else
|
39
|
+
puts "Machine can't shutdown because it is currently: #{machine.status}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
subcommand "restart", "restart the given VM" do
|
45
|
+
parameter "NAME", "name of virtual machine"
|
46
|
+
|
47
|
+
def execute
|
48
|
+
virtual_box.restart!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
subcommand "info", "list all known info about the VM" do
|
53
|
+
parameter "NAME", "name of virtual machine"
|
54
|
+
|
55
|
+
def execute
|
56
|
+
machine.environment.each do |key, value|
|
57
|
+
puts [key, value].join("\t")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
subcommand "usblist", "list usb devices on host" do
|
63
|
+
def execute
|
64
|
+
UsbDevice.all.each do |device|
|
65
|
+
puts device.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
subcommand "usbdetach", "detach usb devices on host" do
|
71
|
+
parameter "NAME", "name of virtual machine"
|
72
|
+
|
73
|
+
def execute
|
74
|
+
machine.usb_devices.each do |device|
|
75
|
+
device.detach(name)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
subcommand "status", "says if the vm is booted or not" do
|
81
|
+
parameter "NAME", "name of virtual machine"
|
82
|
+
|
83
|
+
def execute
|
84
|
+
puts machine.status
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
subcommand "list", "lists the available VMs" do
|
89
|
+
option ["--uuid"], :flag, "show only uuid", :default => false
|
90
|
+
option ["--name"], :flag, "show only name", :default => false
|
91
|
+
|
92
|
+
def execute
|
93
|
+
VirtualBox::GuestControl::Machine.all.each do |machine|
|
94
|
+
if uuid?
|
95
|
+
puts machine.uuid
|
96
|
+
elsif name?
|
97
|
+
puts machine.name
|
98
|
+
else
|
99
|
+
puts [machine.name, machine.uuid].join("\t")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
subcommand "execute", "execute a given command" do
|
106
|
+
parameter "NAME", "name of virtual machine"
|
107
|
+
parameter "[COMMAND_PARAMETERS] ...", "command and parameters to pass to the VM", :attribute_name => :command_parameters
|
108
|
+
|
109
|
+
def execute
|
110
|
+
image_name = command_parameters.shift
|
111
|
+
result = machine.execute image_name, *command_parameters
|
112
|
+
if result.success?
|
113
|
+
puts result.stdout.read
|
114
|
+
else
|
115
|
+
puts "Command failed with exit status #{result.exit_code}"
|
116
|
+
puts "Standard output:"
|
117
|
+
puts result.stdout.read
|
118
|
+
puts "Standard error:"
|
119
|
+
puts result.stderr.read
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
module GuestControl
|
3
|
+
class Machine
|
4
|
+
VM_MATCHER = /^"([^"]*)" \{(.*)\}$/
|
5
|
+
|
6
|
+
include ActiveSupport::Configurable
|
7
|
+
|
8
|
+
self.config[:default_timeout] = 240.seconds
|
9
|
+
self.config[:vbox_manage] = Shellter.which("VBoxManage")
|
10
|
+
|
11
|
+
config_accessor :vbox_manage
|
12
|
+
|
13
|
+
config_accessor :default_timeout
|
14
|
+
config_accessor :username
|
15
|
+
config_accessor :password
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def all
|
19
|
+
result = Shellter.run!(vbox_manage, "list", "vms")
|
20
|
+
result.stdout.read.lines.map do |line|
|
21
|
+
new(*line.scan(VM_MATCHER).first)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_by_uuid(uuid)
|
26
|
+
all.detect { |machine| machine.uuid == uuid }
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_by_name(name)
|
30
|
+
all.detect { |machine| machine.name == name }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(name, uuid)
|
35
|
+
@name = name
|
36
|
+
@uuid = uuid
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_accessor :name
|
40
|
+
attr_accessor :uuid
|
41
|
+
|
42
|
+
state_machine :initial => :poweroff do
|
43
|
+
|
44
|
+
event :start do
|
45
|
+
transition [:saved, :aborted, :poweroff] => :running
|
46
|
+
end
|
47
|
+
|
48
|
+
event :shutdown do
|
49
|
+
transition :running => :poweroff
|
50
|
+
end
|
51
|
+
|
52
|
+
before_transition any => :running do |machine, transition|
|
53
|
+
Shellter.run!(machine.vbox_manage, "startvm", ":name", :name => machine.name)
|
54
|
+
machine.wait_until { machine.running? }
|
55
|
+
machine.wait_until { machine.guest_additions_started? }
|
56
|
+
end
|
57
|
+
|
58
|
+
before_transition :running => :poweroff do |machine, transition|
|
59
|
+
machine.detach_usb_devices!
|
60
|
+
|
61
|
+
begin
|
62
|
+
Shellter.run(machine.vbox_manage, "controlvm", ":name", "acpipowerbutton", :name => machine.name)
|
63
|
+
machine.wait_until { machine.poweroff? }
|
64
|
+
rescue TimeoutError
|
65
|
+
Shellter.run(machine.vbox_manage, "controlvm", ":name", "poweroff", :name => machine.name)
|
66
|
+
wait_until { machine.shutdown? }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
state :poweroff do
|
71
|
+
def status
|
72
|
+
"Powered Off"
|
73
|
+
end
|
74
|
+
|
75
|
+
def execute(*arguments)
|
76
|
+
with_started_machine do
|
77
|
+
execute(*arguments)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
state :aborted do
|
83
|
+
def status
|
84
|
+
"Aborted"
|
85
|
+
end
|
86
|
+
|
87
|
+
def execute(*arguments)
|
88
|
+
with_started_machine do
|
89
|
+
execute(*arguments)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
state :running do
|
95
|
+
def status
|
96
|
+
"Running"
|
97
|
+
end
|
98
|
+
|
99
|
+
def execute(command, *arguments)
|
100
|
+
|
101
|
+
options = arguments.extract_options!
|
102
|
+
params = ["guestcontrol", ":name", "execute", "--image", ":command"]
|
103
|
+
|
104
|
+
options[:name] = name
|
105
|
+
options[:command] = command
|
106
|
+
|
107
|
+
if username
|
108
|
+
params += ["--username", ":username"]
|
109
|
+
options[:username] = username
|
110
|
+
end
|
111
|
+
|
112
|
+
if password
|
113
|
+
params += ["--password", ":password"]
|
114
|
+
options[:password] = password
|
115
|
+
end
|
116
|
+
|
117
|
+
# params += ["--timeout", ":timeout"]
|
118
|
+
params += ["--wait-exit", "--wait-stdout"]
|
119
|
+
# options[:timeout] = default_timeout.to_s
|
120
|
+
|
121
|
+
unless arguments.empty?
|
122
|
+
params += ["--"] + arguments
|
123
|
+
end
|
124
|
+
|
125
|
+
params << options
|
126
|
+
|
127
|
+
Shellter.run(vbox_manage, *params)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
state :saved do
|
132
|
+
def status
|
133
|
+
"Saved State"
|
134
|
+
end
|
135
|
+
|
136
|
+
def execute(*arguments)
|
137
|
+
with_started_machine do
|
138
|
+
execute(*arguments)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def wait_until
|
145
|
+
Timeout::timeout(default_timeout) do
|
146
|
+
loop do
|
147
|
+
result = yield
|
148
|
+
if result
|
149
|
+
break
|
150
|
+
else
|
151
|
+
sleep 5
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def state
|
158
|
+
environment[:VMState]
|
159
|
+
end
|
160
|
+
|
161
|
+
def guest_additions_started?
|
162
|
+
guest_additions_run_level >= 2
|
163
|
+
end
|
164
|
+
|
165
|
+
def guest_additions_run_level
|
166
|
+
environment[:GuestAdditionsRunLevel].to_i
|
167
|
+
end
|
168
|
+
|
169
|
+
def restart!
|
170
|
+
shutdown!
|
171
|
+
start!
|
172
|
+
end
|
173
|
+
|
174
|
+
# VBoxManage guestcontrol <vmname>|<uuid>
|
175
|
+
# exec[ute]
|
176
|
+
# --image <path to program>
|
177
|
+
# --username <name> --password <password>
|
178
|
+
# [--dos2unix]
|
179
|
+
# [--environment "<NAME>=<VALUE> [<NAME>=<VALUE>]"]
|
180
|
+
# [--timeout <msec>] [--unix2dos] [--verbose]
|
181
|
+
# [--wait-exit] [--wait-stdout] [--wait-stderr]
|
182
|
+
# [-- [<argument1>] ... [<argumentN>]]
|
183
|
+
|
184
|
+
|
185
|
+
def environment
|
186
|
+
result = Shellter.run!(vbox_manage, "showvminfo", ":name", "--machinereadable", :name => name)
|
187
|
+
{}.with_indifferent_access.tap do |map|
|
188
|
+
result.stdout.read.lines.each do |line|
|
189
|
+
name, value = line.strip.split("=").map { |y| y.gsub(/(^"|"$)/, "") }
|
190
|
+
map[name] = value
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def with_started_machine(shutdown_after = false)
|
196
|
+
begin
|
197
|
+
start!
|
198
|
+
yield
|
199
|
+
ensure
|
200
|
+
shutdown! if shutdown_after
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def usb_devices
|
205
|
+
UsbDevice.all(vbox_manage)
|
206
|
+
end
|
207
|
+
|
208
|
+
def detach_usb_devices!
|
209
|
+
usb_devices.each do |usb_device|
|
210
|
+
detach!(usb_device)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def attach_usb_devices!
|
215
|
+
usb_devices.each do |usb_device|
|
216
|
+
attach!(usb_device)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def detach!(usb_device)
|
221
|
+
Shellter.run(vbox_manage, "controlvm", ":name", "usbdetach", ":uuid", :name => name, :uuid => usb_device.uuid)
|
222
|
+
end
|
223
|
+
|
224
|
+
def attach!(usb_device)
|
225
|
+
Shellter.run!(vbox_manage, "controlvm", ":name", "usbattach", ":uuid", :name => name, :uuid => usb_device.uuid)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
module GuestControl
|
3
|
+
class UsbDevice
|
4
|
+
include ActiveSupport::Configurable
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def all(vbox_manage)
|
8
|
+
result = Shellter.run!(vbox_manage, "list", "usbhost")
|
9
|
+
parse(result.stdout)
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse(output)
|
13
|
+
[].tap do |devices|
|
14
|
+
device = nil
|
15
|
+
output.lines.each do |line|
|
16
|
+
if device
|
17
|
+
if line.strip.blank?
|
18
|
+
devices << device
|
19
|
+
device = nil
|
20
|
+
else
|
21
|
+
key, value = line.split(":")
|
22
|
+
key = key.strip.gsub(" ", "_").underscore
|
23
|
+
value = value.strip
|
24
|
+
begin
|
25
|
+
device.send(:"#{key}=", value)
|
26
|
+
rescue
|
27
|
+
# this is the version/speed attribute... maybe we should parse it
|
28
|
+
#puts [key, value].join(" => ")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
else
|
32
|
+
next unless line =~ /UUID:/
|
33
|
+
value = line.split(":").last.strip
|
34
|
+
device = new(value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_accessor :uuid, :vendor_id, :product_id, :revision
|
42
|
+
attr_accessor :manufacturer, :product, :address, :current_state, :port
|
43
|
+
attr_accessor :serial_number
|
44
|
+
attr_accessor :vbox_manage
|
45
|
+
|
46
|
+
def initialize(uuid)
|
47
|
+
self.uuid = uuid
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
"#{product} (#{uuid}): #{current_state}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def state
|
55
|
+
current_state
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
require File.expand_path('../lib/virtualbox
|
2
|
+
require File.expand_path('../lib/virtualbox/guest_control/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Andrew Eberbach"]
|
@@ -18,4 +18,5 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.add_dependency 'shellter'
|
19
19
|
gem.add_dependency 'activesupport', "~> 3.0"
|
20
20
|
gem.add_dependency 'clamp'
|
21
|
+
gem.add_dependency 'state_machine'
|
21
22
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: virtualbox-guestcontrol
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: '1.1'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-12-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: shellter
|
@@ -59,6 +59,22 @@ dependencies:
|
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: state_machine
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
62
78
|
description: Runs stuff inside of a VirtualBox VM
|
63
79
|
email:
|
64
80
|
- andrew@ebertech.ca
|
@@ -74,7 +90,10 @@ files:
|
|
74
90
|
- Rakefile
|
75
91
|
- bin/rvbox
|
76
92
|
- lib/virtualbox-guestcontrol.rb
|
77
|
-
- lib/virtualbox
|
93
|
+
- lib/virtualbox/guest_control/command.rb
|
94
|
+
- lib/virtualbox/guest_control/machine.rb
|
95
|
+
- lib/virtualbox/guest_control/usb_device.rb
|
96
|
+
- lib/virtualbox/guest_control/version.rb
|
78
97
|
- virtualbox-guestcontrol.gemspec
|
79
98
|
homepage: ''
|
80
99
|
licenses: []
|
@@ -96,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
115
|
version: '0'
|
97
116
|
requirements: []
|
98
117
|
rubyforge_project:
|
99
|
-
rubygems_version: 1.8.
|
118
|
+
rubygems_version: 1.8.24
|
100
119
|
signing_key:
|
101
120
|
specification_version: 3
|
102
121
|
summary: Runs stuff inside of a VirtualBox VM
|