rvc 1.0.3 → 1.1.0
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/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/rvc/extensions/VirtualMachine.rb +1 -0
- data/lib/rvc/modules/host.rb +65 -0
- data/lib/rvc/modules/vm.rb +31 -1
- data/lib/rvc/modules/vmrc.rb +20 -3
- metadata +4 -34
- data/test/_test_completion.rb +0 -27
- data/test/_test_option_parser.rb +0 -6
data/Rakefile
CHANGED
@@ -7,7 +7,7 @@ begin
|
|
7
7
|
gem.email = "rlane@vmware.com"
|
8
8
|
#gem.homepage = ""
|
9
9
|
gem.authors = ["Rich Lane"]
|
10
|
-
gem.add_dependency 'rbvmomi', '>= 1.2.
|
10
|
+
gem.add_dependency 'rbvmomi', '>= 1.2.3'
|
11
11
|
gem.add_dependency 'trollop', '>= 1.16.2'
|
12
12
|
gem.add_dependency 'backports', '>= 1.18.2'
|
13
13
|
#gem.add_dependency 'ffi', '>= 1.0.7'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
@@ -21,6 +21,7 @@
|
|
21
21
|
class RbVmomi::VIM::VirtualMachine
|
22
22
|
def display_info
|
23
23
|
config, runtime, guest = collect :config, :runtime, :guest
|
24
|
+
err "Information currently unavailable" unless config and runtime and guest
|
24
25
|
|
25
26
|
puts "name: #{config.name}"
|
26
27
|
puts "note: #{config.annotation}" if config.annotation and !config.annotation.empty?
|
data/lib/rvc/modules/host.rb
CHANGED
@@ -27,3 +27,68 @@ end
|
|
27
27
|
def reboot hosts, opts
|
28
28
|
tasks hosts, :RebootHost, :force => opts[:force]
|
29
29
|
end
|
30
|
+
|
31
|
+
|
32
|
+
opts :evacuate do
|
33
|
+
summary "vMotion all VMs away from this host (experimental)"
|
34
|
+
arg :src, nil, :lookup => VIM::HostSystem
|
35
|
+
arg :dst, nil, :lookup => VIM::ComputeResource, :multi => true
|
36
|
+
opt :num, "Maximum concurrent vMotions", :default => 4
|
37
|
+
end
|
38
|
+
|
39
|
+
def evacuate src, dsts, opts
|
40
|
+
vim = src._connection
|
41
|
+
vms = src.vm
|
42
|
+
dst_hosts = dsts.map(&:host).flatten
|
43
|
+
checks = ['cpu', 'software']
|
44
|
+
|
45
|
+
dst_hosts.reject! { |host| host == src ||
|
46
|
+
host.runtime.connectionState != 'connected' ||
|
47
|
+
host.runtime.inMaintenanceMode }
|
48
|
+
|
49
|
+
candidates = {}
|
50
|
+
vms.each do |vm|
|
51
|
+
required_datastores = vm.datastore
|
52
|
+
result = vim.serviceInstance.QueryVMotionCompatibility(:vm => vm,
|
53
|
+
:host => dst_hosts,
|
54
|
+
:compatibility => checks)
|
55
|
+
result.reject! { |x| x.compatibility != checks ||
|
56
|
+
x.host.datastore & required_datastores != required_datastores }
|
57
|
+
candidates[vm] = result.map { |x| x.host }
|
58
|
+
end
|
59
|
+
|
60
|
+
if candidates.any? { |vm,hosts| hosts.empty? }
|
61
|
+
puts "The following VMs have no compatible vMotion destination:"
|
62
|
+
candidates.select { |vm,hosts| hosts.empty? }.each { |vm,hosts| puts " #{vm.name}" }
|
63
|
+
return
|
64
|
+
end
|
65
|
+
|
66
|
+
tasks = candidates.map do |vm,hosts|
|
67
|
+
host = hosts[rand(hosts.size)]
|
68
|
+
vm.MigrateVM_Task(:host => host, :priority => :defaultPriority)
|
69
|
+
end
|
70
|
+
|
71
|
+
progress tasks
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
opts :enter_maintenance_mode do
|
76
|
+
summary "Put hosts into maintenance mode"
|
77
|
+
arg :host, nil, :lookup => VIM::HostSystem, :multi => true
|
78
|
+
opt :timeout, "Timeout", :default => 0
|
79
|
+
end
|
80
|
+
|
81
|
+
def enter_maintenance_mode hosts, opts
|
82
|
+
tasks hosts, :EnterMaintenanceMode, :timeout => opts[:timeout]
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
opts :exit_maintenance_mode do
|
87
|
+
summary "Take hosts out of maintenance mode"
|
88
|
+
arg :host, nil, :lookup => VIM::HostSystem, :multi => true
|
89
|
+
opt :timeout, "Timeout", :default => 0
|
90
|
+
end
|
91
|
+
|
92
|
+
def exit_maintenance_mode hosts, opts
|
93
|
+
tasks hosts, :ExitMaintenanceMode, :timeout => opts[:timeout]
|
94
|
+
end
|
data/lib/rvc/modules/vm.rb
CHANGED
@@ -538,16 +538,25 @@ opts :clone do
|
|
538
538
|
arg :dst, "Path to new VM"
|
539
539
|
opt :pool, "Resource pool", :short => 'p', :type => :string, :lookup => VIM::ResourcePool
|
540
540
|
opt :host, "Host", :short => 'h', :type => :string, :lookup => VIM::HostSystem
|
541
|
-
opt :template, "Create a template"
|
541
|
+
opt :template, "Create a template", :short => 't'
|
542
|
+
opt :linked, "Create a linked clone", :short => 'l'
|
542
543
|
opt :powerOn, "Power on VM after clone"
|
543
544
|
end
|
544
545
|
|
545
546
|
def clone src, dst, opts
|
546
547
|
folder = lookup! File.dirname(dst), VIM::Folder
|
548
|
+
diskMoveType = nil
|
549
|
+
|
550
|
+
if opts[:linked]
|
551
|
+
deltaize_disks src
|
552
|
+
diskMoveType = :moveChildMostDiskBacking
|
553
|
+
end
|
554
|
+
|
547
555
|
task = src.CloneVM_Task(:folder => folder,
|
548
556
|
:name => File.basename(dst),
|
549
557
|
:spec => {
|
550
558
|
:location => {
|
559
|
+
:diskMoveType => diskMoveType,
|
551
560
|
:host => opts[:host],
|
552
561
|
:pool => opts[:pool],
|
553
562
|
},
|
@@ -558,6 +567,27 @@ def clone src, dst, opts
|
|
558
567
|
end
|
559
568
|
|
560
569
|
|
570
|
+
def deltaize_disks vm
|
571
|
+
real_disks = vm.config.hardware.device.grep(VIM::VirtualDisk).select { |x| x.backing.parent == nil }
|
572
|
+
unless real_disks.empty?
|
573
|
+
puts "Reconfiguring source VM to use delta disks..."
|
574
|
+
deviceChange = []
|
575
|
+
real_disks.each do |disk|
|
576
|
+
deviceChange << { :operation => :remove, :device => disk }
|
577
|
+
deviceChange << {
|
578
|
+
:operation => :add,
|
579
|
+
:fileOperation => :create,
|
580
|
+
:device => disk.dup.tap { |x|
|
581
|
+
x.backing = x.backing.dup
|
582
|
+
x.backing.fileName = "[#{disk.backing.datastore.name}]"
|
583
|
+
x.backing.parent = disk.backing
|
584
|
+
}
|
585
|
+
}
|
586
|
+
end
|
587
|
+
progress [vm.ReconfigVM_Task(:spec => { :deviceChange => deviceChange })]
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
561
591
|
def find_vmx_files ds
|
562
592
|
datastorePath = "[#{ds.name}] /"
|
563
593
|
searchSpec = {
|
data/lib/rvc/modules/vmrc.rb
CHANGED
@@ -22,7 +22,11 @@ require 'tmpdir'
|
|
22
22
|
|
23
23
|
VMRC_NAME = "vmware-vmrc-linux-x86-3.0.0"
|
24
24
|
VMRC_PKGVER = 1
|
25
|
-
|
25
|
+
VMRC_BASENAME = "#{VMRC_NAME}.#{VMRC_PKGVER}.tar.bz2"
|
26
|
+
VMRC_URL = "http://cloud.github.com/downloads/vmware/rvc/#{VMRC_BASENAME}"
|
27
|
+
VMRC_SHA256 = "cda9ba0b0078aee9a7b9704d720ef4c7d74ae2028efb71815d0eb91a5de75921"
|
28
|
+
|
29
|
+
CURL = ENV['CURL'] || 'curl'
|
26
30
|
|
27
31
|
def find_local_vmrc
|
28
32
|
path = File.join(Dir.tmpdir, VMRC_NAME, 'plugins', 'vmware-vmrc')
|
@@ -51,8 +55,10 @@ def view vms
|
|
51
55
|
host = vm._connection._host
|
52
56
|
fork do
|
53
57
|
ENV['https_proxy'] = ENV['HTTPS_PROXY'] = ''
|
54
|
-
$stderr.reopen("#{ENV['HOME']||'.'}/.rvc-vmrc.log", "
|
58
|
+
$stderr.reopen("#{ENV['HOME']||'.'}/.rvc-vmrc.log", "a")
|
55
59
|
$stderr.puts Time.now
|
60
|
+
$stderr.puts "Using VMRC #{vmrc}"
|
61
|
+
$stderr.flush
|
56
62
|
Process.setpgrp
|
57
63
|
exec vmrc, '-M', moref,
|
58
64
|
'-h', host,
|
@@ -66,7 +72,18 @@ opts :install do
|
|
66
72
|
end
|
67
73
|
|
68
74
|
def install
|
75
|
+
system "which #{CURL} > /dev/null" or err "curl not found"
|
76
|
+
system "which sha256sum > /dev/null" or err "sha256sum not found"
|
77
|
+
puts "Downloading VMRC..."
|
78
|
+
dir = Dir.mktmpdir
|
79
|
+
vmrc_file = "#{dir}/#{VMRC_BASENAME}"
|
80
|
+
checksum_file = "#{dir}/sha256sums"
|
81
|
+
system "#{CURL} -L #{VMRC_URL} -o #{vmrc_file}" or err "download failed"
|
82
|
+
puts "Checking integrity..."
|
83
|
+
File.open(checksum_file, 'w') { |io| io.puts "#{VMRC_SHA256} *#{vmrc_file}" }
|
84
|
+
system "sha256sum -c #{checksum_file}" or err "integrity check failed"
|
69
85
|
puts "Installing VMRC..."
|
70
|
-
system "
|
86
|
+
system "tar -xj -f #{vmrc_file} -C #{Dir.tmpdir}" or err("VMRC installation failed")
|
71
87
|
puts "VMRC was installed successfully."
|
88
|
+
FileUtils.rm_r dir
|
72
89
|
end
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rvc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 17
|
5
4
|
prerelease:
|
6
|
-
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 3
|
10
|
-
version: 1.0.3
|
5
|
+
version: 1.1.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Rich Lane
|
@@ -15,7 +10,7 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date: 2011-
|
13
|
+
date: 2011-04-05 00:00:00 -07:00
|
19
14
|
default_executable: rvc
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
@@ -26,12 +21,7 @@ dependencies:
|
|
26
21
|
requirements:
|
27
22
|
- - ">="
|
28
23
|
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 1
|
32
|
-
- 2
|
33
|
-
- 2
|
34
|
-
version: 1.2.2
|
24
|
+
version: 1.2.3
|
35
25
|
type: :runtime
|
36
26
|
version_requirements: *id001
|
37
27
|
- !ruby/object:Gem::Dependency
|
@@ -42,11 +32,6 @@ dependencies:
|
|
42
32
|
requirements:
|
43
33
|
- - ">="
|
44
34
|
- !ruby/object:Gem::Version
|
45
|
-
hash: 83
|
46
|
-
segments:
|
47
|
-
- 1
|
48
|
-
- 16
|
49
|
-
- 2
|
50
35
|
version: 1.16.2
|
51
36
|
type: :runtime
|
52
37
|
version_requirements: *id002
|
@@ -58,11 +43,6 @@ dependencies:
|
|
58
43
|
requirements:
|
59
44
|
- - ">="
|
60
45
|
- !ruby/object:Gem::Version
|
61
|
-
hash: 91
|
62
|
-
segments:
|
63
|
-
- 1
|
64
|
-
- 18
|
65
|
-
- 2
|
66
46
|
version: 1.18.2
|
67
47
|
type: :runtime
|
68
48
|
version_requirements: *id003
|
@@ -117,8 +97,6 @@ files:
|
|
117
97
|
- test/inventory_fixtures.rb
|
118
98
|
- test/test_fs.rb
|
119
99
|
- test/test_parse_path.rb
|
120
|
-
- test/_test_completion.rb
|
121
|
-
- test/_test_option_parser.rb
|
122
100
|
has_rdoc: true
|
123
101
|
homepage:
|
124
102
|
licenses: []
|
@@ -133,29 +111,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
111
|
requirements:
|
134
112
|
- - ">="
|
135
113
|
- !ruby/object:Gem::Version
|
136
|
-
hash: 3
|
137
|
-
segments:
|
138
|
-
- 0
|
139
114
|
version: "0"
|
140
115
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
116
|
none: false
|
142
117
|
requirements:
|
143
118
|
- - ">="
|
144
119
|
- !ruby/object:Gem::Version
|
145
|
-
hash: 3
|
146
|
-
segments:
|
147
|
-
- 0
|
148
120
|
version: "0"
|
149
121
|
requirements: []
|
150
122
|
|
151
123
|
rubyforge_project:
|
152
|
-
rubygems_version: 1.
|
124
|
+
rubygems_version: 1.6.2
|
153
125
|
signing_key:
|
154
126
|
specification_version: 3
|
155
127
|
summary: vSphere console UI
|
156
128
|
test_files:
|
157
|
-
- test/_test_completion.rb
|
158
|
-
- test/_test_option_parser.rb
|
159
129
|
- test/inventory_fixtures.rb
|
160
130
|
- test/test_fs.rb
|
161
131
|
- test/test_parse_path.rb
|
data/test/_test_completion.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'rvc'
|
3
|
-
require 'inventory_fixtures'
|
4
|
-
|
5
|
-
class CompletionTest < Test::Unit::TestCase
|
6
|
-
NodeBaz = FixtureNode.new
|
7
|
-
NodeBar = FixtureNode.new
|
8
|
-
NodeFoo = FixtureNode.new('bar' => NodeBar, 'baz' => NodeBaz)
|
9
|
-
Root = FixtureNode.new('foo' => NodeFoo)
|
10
|
-
|
11
|
-
def check word, expected
|
12
|
-
got = RVC::Completion::Completor[word]
|
13
|
-
assert_equal expected, got
|
14
|
-
end
|
15
|
-
|
16
|
-
def setup
|
17
|
-
@context = RVC::Context.new Root
|
18
|
-
end
|
19
|
-
|
20
|
-
def teardown
|
21
|
-
@context = nil
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_simple
|
25
|
-
check
|
26
|
-
end
|
27
|
-
end
|