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 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> <snapshot name>
40
- removes a vm snapshot from management
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
- shows status of vms
48
+ shows status of vms
43
49
 
44
50
  VM SET SUB-COMMANDS
45
51
  createset <set name>
46
- creates a vm set with the specified name
52
+ creates a vm set with the specified name
47
53
  currentset
48
- shows the current vm set in use
54
+ shows the current vm set in use
49
55
  listsets
50
- lists all vm sets
56
+ lists all vm sets
51
57
  removeset <set name>
52
- removes the vm set with the specified name
58
+ removes the vm set with the specified name
53
59
  usedefaultset
54
- uses the default vm set
60
+ uses the default vm set
55
61
  useset <set name>
56
- uses the vm set with the specified name
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> <snapshot name>'
25
- puts ' removes a vm snapshot from management'
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 ' shows status of vms'
33
+ puts ' shows status of vms'
28
34
  puts
29
35
  puts 'VM SET SUB-COMMANDS'
30
36
  puts ' createset <set name>'
31
- puts ' creates a vm set with the specified name'
37
+ puts ' creates a vm set with the specified name'
32
38
  puts ' currentset'
33
- puts ' shows the current vm set in use'
39
+ puts ' shows the current vm set in use'
34
40
  puts ' listsets'
35
- puts ' lists all vm sets'
41
+ puts ' lists all vm sets'
36
42
  puts ' removeset <set name>'
37
- puts ' removes the vm set with the specified name'
43
+ puts ' removes the vm set with the specified name'
38
44
  puts ' usedefaultset'
39
- puts ' uses the default vm set'
45
+ puts ' uses the default vm set'
40
46
  puts ' useset <set name>'
41
- puts ' uses the vm set with the specified name'
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 if ARGV.length == 1
66
- expect_args(6) do
67
- hostname, username, password, vm_name, snapshot_name = ARGV[1..5]
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 if ARGV.length == 1
78
- expect_args(5) do
79
- hostname, username, vm_name, snapshot_name = ARGV[1..4]
80
- printing_delegator.remove_vm(hostname, username, vm_name, snapshot_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 if ARGV.length == 1
86
- expect_args(2) {printing_delegator.create_set ARGV[1]}
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 if ARGV.length == 1
93
- expect_args(2) {printing_delegator.remove_set ARGV[1]}
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 if ARGV.length == 1
98
- expect_args(2) {printing_delegator.use_set ARGV[1]}
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, snapshot_name)
51
+ def remove_vm(hostname, username, vm_name)
42
52
  begin
43
- @vm_set.remove_vm(hostname, username, vm_name, snapshot_name)
44
- puts "Removed (#{vm_name}, #{snapshot_name}) on host, #{hostname}"
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 VM snapshot: #{e.message}"
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
@@ -1,3 +1,3 @@
1
1
  module NetVbox
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
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 ===(other)
41
- self.ssh_connection_info === other.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!(command)}
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
@@ -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, snapshot_name)
36
- vm_info = VmInfo.new(SshConnectionInfo.new(hostname, username, nil), vm_name, snapshot_name)
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.index(vm_info).nil?
22
+ if all.detect {|i| i.clashes_with? vm_info}.nil?
23
23
  write_vm_info(all << vm_info)
24
24
  else
25
- raise "(#{vm_info.vm_name}, #{vm_info.snapshot_name}) is already under management"
25
+ raise "The VM, #{vm_info.vm_name}, is already under management"
26
26
  end
27
27
  end
28
28
 
29
- def remove_vm(vm_info)
29
+ def remove_vm(hostname, username, vm_name)
30
30
  all = all_vm_info
31
- updated = all.select {|i| !(i === vm_info)}
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 "(#{vm_info.vm_name}, #{vm_info.snapshot_name}) is not under management"
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
- snapshot_name = get_value 'Enter snapshot name: '
24
- @printing_delegator.remove_vm(hostname, username, vm_name, snapshot_name)
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.5
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-04 00:00:00.000000000 Z
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: &8515500 !ruby/object:Gem::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: *8515500
24
+ version_requirements: *8198200
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: highline
27
- requirement: &8529760 !ruby/object:Gem::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: *8529760
35
+ version_requirements: *8197020
36
36
  description:
37
37
  email:
38
38
  - hsu.dennis@gmail.com