netvbox 0.0.5 → 0.0.6
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/README.rdoc +24 -9
- data/bin/netvbox +42 -24
- data/lib/netvbox/printing_delegator.rb +30 -4
- data/lib/netvbox/version.rb +1 -1
- data/lib/netvbox/vm.rb +39 -13
- data/lib/netvbox/vm_set.rb +41 -3
- data/lib/netvbox/vm_set_config.rb +5 -5
- data/lib/netvbox/wizard_delegator.rb +13 -2
- metadata +6 -6
data/README.rdoc
CHANGED
@@ -32,26 +32,41 @@ netvbox uses sub-commands. Below is the help listing.
|
|
32
32
|
adds a vm snapshot on the specified host
|
33
33
|
list
|
34
34
|
lists vm snapshots
|
35
|
+
listips
|
36
|
+
lists ip addresses of vms with guest additions installed
|
35
37
|
load
|
36
38
|
loads vm snapshots
|
37
39
|
poweroff
|
38
40
|
powers off all vms
|
39
|
-
remove <ssh host> <username> <vm name>
|
40
|
-
removes
|
41
|
+
remove <ssh host> <username> <vm name>
|
42
|
+
removes snapshot of specified vm from management
|
43
|
+
sshhosts <command>
|
44
|
+
runs the specified command on host computers
|
45
|
+
sshguests <ssh user> <ssh password> <command>
|
46
|
+
runs the specified command on guest vms
|
41
47
|
status
|
42
|
-
|
48
|
+
shows status of vms
|
43
49
|
|
44
50
|
VM SET SUB-COMMANDS
|
45
51
|
createset <set name>
|
46
|
-
|
52
|
+
creates a vm set with the specified name
|
47
53
|
currentset
|
48
|
-
|
54
|
+
shows the current vm set in use
|
49
55
|
listsets
|
50
|
-
|
56
|
+
lists all vm sets
|
51
57
|
removeset <set name>
|
52
|
-
|
58
|
+
removes the vm set with the specified name
|
53
59
|
usedefaultset
|
54
|
-
|
60
|
+
uses the default vm set
|
55
61
|
useset <set name>
|
56
|
-
|
62
|
+
uses the vm set with the specified name
|
63
|
+
|
64
|
+
* Tip: You will be prompted for input if you leave out sub-command
|
65
|
+
arguments (e.g. netvbox add)
|
66
|
+
|
57
67
|
|
68
|
+
== Changelog
|
69
|
+
*0.0.6*
|
70
|
+
- _Breaking change:_ sub-command, remove, no longer requires snapshot name.
|
71
|
+
- _Feature:_ can now list the IP addresses of guest VMs with sub-command, listips.
|
72
|
+
- _Feature:_ parallel ssh on hosts or guests. currently only supports ssh with password.
|
data/bin/netvbox
CHANGED
@@ -17,36 +17,42 @@ def print_help
|
|
17
17
|
puts ' adds a vm snapshot on the specified host'
|
18
18
|
puts ' list'
|
19
19
|
puts ' lists vm snapshots'
|
20
|
+
puts ' listips'
|
21
|
+
puts ' lists ip addresses of vms with guest additions installed'
|
20
22
|
puts ' load'
|
21
23
|
puts ' loads vm snapshots'
|
22
24
|
puts ' poweroff'
|
23
25
|
puts ' powers off all vms'
|
24
|
-
puts ' remove <ssh host> <username> <vm name>
|
25
|
-
puts ' removes
|
26
|
+
puts ' remove <ssh host> <username> <vm name>'
|
27
|
+
puts ' removes snapshot of specified vm from management'
|
28
|
+
puts ' sshhosts <command>'
|
29
|
+
puts ' runs the specified command on host computers'
|
30
|
+
puts ' sshguests <ssh user> <ssh password> <command>'
|
31
|
+
puts ' runs the specified command on guest vms'
|
26
32
|
puts ' status'
|
27
|
-
puts '
|
33
|
+
puts ' shows status of vms'
|
28
34
|
puts
|
29
35
|
puts 'VM SET SUB-COMMANDS'
|
30
36
|
puts ' createset <set name>'
|
31
|
-
puts '
|
37
|
+
puts ' creates a vm set with the specified name'
|
32
38
|
puts ' currentset'
|
33
|
-
puts '
|
39
|
+
puts ' shows the current vm set in use'
|
34
40
|
puts ' listsets'
|
35
|
-
puts '
|
41
|
+
puts ' lists all vm sets'
|
36
42
|
puts ' removeset <set name>'
|
37
|
-
puts '
|
43
|
+
puts ' removes the vm set with the specified name'
|
38
44
|
puts ' usedefaultset'
|
39
|
-
puts '
|
45
|
+
puts ' uses the default vm set'
|
40
46
|
puts ' useset <set name>'
|
41
|
-
puts '
|
47
|
+
puts ' uses the vm set with the specified name'
|
42
48
|
puts
|
43
49
|
puts '* Tip: You will be prompted for input if you leave out sub-command'
|
44
50
|
puts ' arguments (e.g. netvbox add)'
|
45
51
|
end
|
46
52
|
|
47
53
|
def expect_args(num_expected_args)
|
48
|
-
if ARGV.length == num_expected_args
|
49
|
-
yield ARGV
|
54
|
+
if ARGV.length - 1 == num_expected_args
|
55
|
+
yield ARGV[1..-1]
|
50
56
|
else
|
51
57
|
puts 'Wrong number of arguments'
|
52
58
|
print_help
|
@@ -55,6 +61,7 @@ end
|
|
55
61
|
|
56
62
|
def process_args
|
57
63
|
command = ARGV[0]
|
64
|
+
has_command_args = ARGV.length > 1
|
58
65
|
vm_set_manager = NetVbox::VmSetManager.new(NETVBOX_HOME)
|
59
66
|
vm_set = vm_set_manager.current_set
|
60
67
|
printing_delegator = NetVbox::PrintingDelegator.new(vm_set_manager, vm_set)
|
@@ -62,40 +69,51 @@ def process_args
|
|
62
69
|
begin
|
63
70
|
case command
|
64
71
|
when 'add'
|
65
|
-
return wizard_delegator.add_vm
|
66
|
-
expect_args(
|
67
|
-
hostname, username, password, vm_name, snapshot_name =
|
72
|
+
return wizard_delegator.add_vm unless has_command_args
|
73
|
+
expect_args(5) do |command_args|
|
74
|
+
hostname, username, password, vm_name, snapshot_name = command_args[0..4]
|
68
75
|
printing_delegator.add_vm(hostname, username, password, vm_name, snapshot_name)
|
69
76
|
end
|
70
77
|
when 'list'
|
71
78
|
printing_delegator.list_vms
|
79
|
+
when 'listips'
|
80
|
+
printing_delegator.list_vm_ips
|
72
81
|
when 'load'
|
73
82
|
printing_delegator.load_snapshots
|
74
83
|
when 'poweroff'
|
75
84
|
printing_delegator.poweroff_all
|
76
85
|
when 'remove'
|
77
|
-
return wizard_delegator.remove_vm
|
78
|
-
expect_args(
|
79
|
-
hostname, username, vm_name
|
80
|
-
printing_delegator.remove_vm(hostname, username, vm_name
|
86
|
+
return wizard_delegator.remove_vm unless has_command_args
|
87
|
+
expect_args(3) do |command_args|
|
88
|
+
hostname, username, vm_name = command_args[0..2]
|
89
|
+
printing_delegator.remove_vm(hostname, username, vm_name)
|
90
|
+
end
|
91
|
+
when 'sshhosts'
|
92
|
+
return wizard_delegator.ssh_hosts unless has_command_args
|
93
|
+
expect_args(1) {|command_args| printing_delegator.ssh_hosts command_args[0]}
|
94
|
+
when 'sshguests'
|
95
|
+
return wizard_delegator.ssh_guests unless has_command_args
|
96
|
+
expect_args(3) do |command_args|
|
97
|
+
username, pw, command = command_args[0..2]
|
98
|
+
printing_delegator.ssh_guests(username, pw, command)
|
81
99
|
end
|
82
100
|
when 'status'
|
83
101
|
printing_delegator.print_status
|
84
102
|
when 'createset'
|
85
|
-
return wizard_delegator.create_set
|
86
|
-
expect_args(
|
103
|
+
return wizard_delegator.create_set unless has_command_args
|
104
|
+
expect_args(1) {|command_args| printing_delegator.create_set command_args[0]}
|
87
105
|
when 'currentset'
|
88
106
|
printing_delegator.print_current_set
|
89
107
|
when 'listsets'
|
90
108
|
printing_delegator.list_sets
|
91
109
|
when 'removeset'
|
92
|
-
return wizard_delegator.remove_set
|
93
|
-
expect_args(
|
110
|
+
return wizard_delegator.remove_set unless has_command_args
|
111
|
+
expect_args(1) {|command_args| printing_delegator.remove_set command_args[0]}
|
94
112
|
when 'usedefaultset'
|
95
113
|
printing_delegator.use_default_set
|
96
114
|
when 'useset'
|
97
|
-
return wizard_delegator.use_set
|
98
|
-
expect_args(
|
115
|
+
return wizard_delegator.use_set unless has_command_args
|
116
|
+
expect_args(1) {|command_args| printing_delegator.use_set command_args[0]}
|
99
117
|
else
|
100
118
|
puts "Unknown command: #{command}. See help."
|
101
119
|
end
|
@@ -26,6 +26,16 @@ module NetVbox
|
|
26
26
|
puts 'No vms' if all_vm_info.empty?
|
27
27
|
end
|
28
28
|
|
29
|
+
def list_vm_ips
|
30
|
+
puts 'Retrieving VM IP addresses for VMs with guest additions...'
|
31
|
+
all_ips = @vm_set.all_ips
|
32
|
+
all_ips.each do |vm_info, ip|
|
33
|
+
ip_string = (ip == :ip_unavailable) ? 'unavailable' : ip
|
34
|
+
printf "%-40s %s\n", "#{vm_info.vm_name} on #{vm_info.ssh_connection_info.hostname}", "[#{ip_string}]"
|
35
|
+
end
|
36
|
+
puts 'There are no vms' if all_ips.empty?
|
37
|
+
end
|
38
|
+
|
29
39
|
def load_snapshots
|
30
40
|
puts 'Loading snapshots...'
|
31
41
|
@vm_set.load_snapshots
|
@@ -38,13 +48,29 @@ module NetVbox
|
|
38
48
|
print_status
|
39
49
|
end
|
40
50
|
|
41
|
-
def remove_vm(hostname, username, vm_name
|
51
|
+
def remove_vm(hostname, username, vm_name)
|
42
52
|
begin
|
43
|
-
@vm_set.remove_vm(hostname, username, vm_name
|
44
|
-
puts "Removed
|
53
|
+
@vm_set.remove_vm(hostname, username, vm_name)
|
54
|
+
puts "Removed #{vm_name} snapshot on host, #{hostname}"
|
45
55
|
rescue => e
|
46
|
-
puts "Could not remove
|
56
|
+
puts "Could not remove #{vm_name} snapshot: #{e.message}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def ssh_hosts(command)
|
61
|
+
all_output = @vm_set.ssh_hosts command
|
62
|
+
all_output.each do |vm_info, output|
|
63
|
+
output.split("\n").each {|line| puts "[#{vm_info.ssh_connection_info.hostname}] #{line}"}
|
64
|
+
end
|
65
|
+
puts 'There are no vms' if all_output.empty?
|
66
|
+
end
|
67
|
+
|
68
|
+
def ssh_guests(username, password, command)
|
69
|
+
all_output = @vm_set.ssh_guests(username, password, command)
|
70
|
+
all_output.each do |vm_info, output|
|
71
|
+
output.split("\n").each {|line| puts "[#{vm_info.vm_name} on #{vm_info.ssh_connection_info.hostname}] #{line}"}
|
47
72
|
end
|
73
|
+
puts 'There are no vms' if all_output.empty?
|
48
74
|
end
|
49
75
|
|
50
76
|
def print_status
|
data/lib/netvbox/version.rb
CHANGED
data/lib/netvbox/vm.rb
CHANGED
@@ -12,13 +12,9 @@ module NetVbox
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def ==(other)
|
15
|
-
self === other &&
|
16
|
-
self.password == other.password
|
17
|
-
end
|
18
|
-
|
19
|
-
def ===(other)
|
20
15
|
self.hostname == other.hostname &&
|
21
|
-
self.username == other.username
|
16
|
+
self.username == other.username &&
|
17
|
+
self.password == other.password
|
22
18
|
end
|
23
19
|
end
|
24
20
|
|
@@ -31,16 +27,24 @@ module NetVbox
|
|
31
27
|
@snapshot_name = snapshot_name
|
32
28
|
end
|
33
29
|
|
30
|
+
def clashes_with?(other)
|
31
|
+
clashes_with_params?(other.ssh_connection_info.hostname, other.ssh_connection_info.username, other.vm_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def clashes_with_params?(hostname, username, vm_name)
|
35
|
+
self.ssh_connection_info.hostname == hostname &&
|
36
|
+
self.ssh_connection_info.username == username &&
|
37
|
+
self.vm_name == vm_name
|
38
|
+
end
|
39
|
+
|
34
40
|
def ==(other)
|
35
41
|
self.ssh_connection_info == other.ssh_connection_info &&
|
36
42
|
self.vm_name == other.vm_name &&
|
37
43
|
self.snapshot_name == other.snapshot_name
|
38
44
|
end
|
39
45
|
|
40
|
-
def
|
41
|
-
self.ssh_connection_info
|
42
|
-
self.vm_name == other.vm_name &&
|
43
|
-
self.snapshot_name == other.snapshot_name
|
46
|
+
def to_s
|
47
|
+
"host: #{self.ssh_connection_info.hostname}, vm: #{vm_name}, snapshot: #{snapshot_name}"
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
@@ -79,7 +83,28 @@ module NetVbox
|
|
79
83
|
return if showvminfo('accelerate3d') == 'on'
|
80
84
|
poweroff
|
81
85
|
command = "VBoxManage snapshot \"#{@vm_info.vm_name}\" restore \"#{@vm_info.snapshot_name}\" && VBoxManage startvm \"#{@vm_info.vm_name}\" --type headless"
|
82
|
-
my_ssh {|ssh| ssh.exec!
|
86
|
+
my_ssh {|ssh| ssh.exec! command}
|
87
|
+
end
|
88
|
+
|
89
|
+
def ssh_host(command)
|
90
|
+
my_ssh {|ssh| ssh.exec! command} || ''
|
91
|
+
end
|
92
|
+
|
93
|
+
def ssh_guest(username, pw, command)
|
94
|
+
begin
|
95
|
+
hostname = vm_ip
|
96
|
+
rescue
|
97
|
+
return 'Guest VM IP unavailable'
|
98
|
+
end
|
99
|
+
ssh_info = SshConnectionInfo.new(hostname, username, pw)
|
100
|
+
my_ssh(ssh_info) {|ssh| ssh.exec! command} || ''
|
101
|
+
end
|
102
|
+
|
103
|
+
def vm_ip
|
104
|
+
command = "VBoxManage guestproperty get \"#{@vm_info.vm_name}\" /VirtualBox/GuestInfo/Net/0/V4/IP"
|
105
|
+
out = my_ssh {|ssh| ssh.exec! command}
|
106
|
+
return out['Value:'.length..-1].strip unless (out =~ /^Value:/).nil?
|
107
|
+
raise "Cannot get IP for #{@vm_info.vm_name}: #{out}"
|
83
108
|
end
|
84
109
|
|
85
110
|
private
|
@@ -89,8 +114,7 @@ module NetVbox
|
|
89
114
|
my_ssh {|ssh| ssh.exec!(command).strip}
|
90
115
|
end
|
91
116
|
|
92
|
-
def my_ssh
|
93
|
-
ssh_info = @vm_info.ssh_connection_info
|
117
|
+
def my_ssh(ssh_info=@vm_info.ssh_connection_info)
|
94
118
|
begin
|
95
119
|
# can raise SocketError or Net::SSH::AuthenticationFailed
|
96
120
|
Net::SSH.start(ssh_info.hostname, ssh_info.username, :password => ssh_info.password) {|ssh| return yield ssh}
|
@@ -98,6 +122,8 @@ module NetVbox
|
|
98
122
|
return 'connection error'
|
99
123
|
rescue Net::SSH::AuthenticationFailed
|
100
124
|
return 'authentication error'
|
125
|
+
rescue => e
|
126
|
+
return e.message
|
101
127
|
end
|
102
128
|
end
|
103
129
|
end
|
data/lib/netvbox/vm_set.rb
CHANGED
@@ -32,9 +32,8 @@ module NetVbox
|
|
32
32
|
@vm_set_config.add_vm(vm_info)
|
33
33
|
end
|
34
34
|
|
35
|
-
def remove_vm(hostname, username, vm_name
|
36
|
-
|
37
|
-
@vm_set_config.remove_vm(vm_info)
|
35
|
+
def remove_vm(hostname, username, vm_name)
|
36
|
+
@vm_set_config.remove_vm(hostname, username, vm_name)
|
38
37
|
end
|
39
38
|
|
40
39
|
# return Hash of VmInfo to status
|
@@ -48,6 +47,45 @@ module NetVbox
|
|
48
47
|
status_map
|
49
48
|
end
|
50
49
|
|
50
|
+
# return Hash of VmInfo to (vm ip or :ip_unavailable)
|
51
|
+
def all_ips
|
52
|
+
ip_map = {}
|
53
|
+
threads = []
|
54
|
+
get_vms.each do |vm|
|
55
|
+
threads << Thread.new(vm) do |vm|
|
56
|
+
begin
|
57
|
+
ip_map[vm.vm_info] = vm.vm_ip
|
58
|
+
rescue
|
59
|
+
ip_map[vm.vm_info] = :ip_unavailable
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
threads.each(&:join)
|
64
|
+
ip_map
|
65
|
+
end
|
66
|
+
|
67
|
+
# return Hash of VmInfo to output of command
|
68
|
+
def ssh_hosts(command)
|
69
|
+
output_map = {}
|
70
|
+
threads = []
|
71
|
+
get_vms.each do |vm|
|
72
|
+
threads << Thread.new(vm) {|vm| output_map[vm.vm_info] = vm.ssh_host(command)}
|
73
|
+
end
|
74
|
+
threads.each(&:join)
|
75
|
+
output_map
|
76
|
+
end
|
77
|
+
|
78
|
+
# return Hash of VmInfo to output of command
|
79
|
+
def ssh_guests(username, pw, command)
|
80
|
+
output_map = {}
|
81
|
+
threads = []
|
82
|
+
get_vms.each do |vm|
|
83
|
+
threads << Thread.new(vm) {|vm| output_map[vm.vm_info] = vm.ssh_guest(username, pw, command)}
|
84
|
+
end
|
85
|
+
threads.each(&:join)
|
86
|
+
output_map
|
87
|
+
end
|
88
|
+
|
51
89
|
private
|
52
90
|
|
53
91
|
def get_vms
|
@@ -19,20 +19,20 @@ module NetVbox
|
|
19
19
|
|
20
20
|
def add_vm(vm_info)
|
21
21
|
all = all_vm_info
|
22
|
-
if all.
|
22
|
+
if all.detect {|i| i.clashes_with? vm_info}.nil?
|
23
23
|
write_vm_info(all << vm_info)
|
24
24
|
else
|
25
|
-
raise "
|
25
|
+
raise "The VM, #{vm_info.vm_name}, is already under management"
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
def remove_vm(
|
29
|
+
def remove_vm(hostname, username, vm_name)
|
30
30
|
all = all_vm_info
|
31
|
-
updated = all.select {|i| !(
|
31
|
+
updated = all.select {|i| !i.clashes_with_params?(hostname, username, vm_name)}
|
32
32
|
if all != updated
|
33
33
|
write_vm_info(updated)
|
34
34
|
else
|
35
|
-
raise "
|
35
|
+
raise "The VM, #{vm_name}, is not under management"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -20,8 +20,19 @@ module NetVbox
|
|
20
20
|
hostname = get_value 'Enter hostname of VM host: '
|
21
21
|
username = get_value 'Enter ssh username: '
|
22
22
|
vm_name = get_value 'Enter VM name: '
|
23
|
-
|
24
|
-
|
23
|
+
@printing_delegator.remove_vm(hostname, username, vm_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def ssh_hosts
|
27
|
+
command = get_value 'Enter command: '
|
28
|
+
@printing_delegator.ssh_hosts command
|
29
|
+
end
|
30
|
+
|
31
|
+
def ssh_guests
|
32
|
+
username = get_value 'Enter ssh username: '
|
33
|
+
pw = get_password 'Enter ssh password: '
|
34
|
+
command = get_value 'Enter command: '
|
35
|
+
@printing_delegator.ssh_guests(username, pw, command)
|
25
36
|
end
|
26
37
|
|
27
38
|
def create_set
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: netvbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-12-
|
12
|
+
date: 2011-12-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: net-ssh
|
16
|
-
requirement: &
|
16
|
+
requirement: &8198200 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *8198200
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: highline
|
27
|
-
requirement: &
|
27
|
+
requirement: &8197020 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *8197020
|
36
36
|
description:
|
37
37
|
email:
|
38
38
|
- hsu.dennis@gmail.com
|