rvc 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|