rvc 1.6.0 → 1.7.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/bin/rvc +46 -70
- data/devel/test-dependencies.sh +4 -0
- data/lib/rvc.rb +5 -6
- data/lib/rvc/command.rb +65 -0
- data/lib/rvc/command_slate.rb +112 -0
- data/lib/rvc/completion.rb +89 -58
- data/lib/rvc/connection.rb +48 -0
- data/lib/rvc/extensions/DistributedVirtualPortgroup.rb +1 -1
- data/lib/rvc/extensions/DistributedVirtualSwitch.rb +3 -3
- data/lib/rvc/extensions/HostSystem.rb +90 -0
- data/lib/rvc/extensions/VirtualMachine.rb +37 -7
- data/lib/rvc/field.rb +59 -12
- data/lib/rvc/fs.rb +34 -4
- data/lib/rvc/inventory.rb +5 -1
- data/lib/rvc/modules/alarm.rb +2 -0
- data/lib/rvc/modules/basic.rb +66 -61
- data/lib/rvc/modules/cluster.rb +117 -22
- data/lib/rvc/modules/connection.rb +40 -0
- data/lib/rvc/modules/core.rb +4 -16
- data/lib/rvc/modules/datacenter.rb +2 -0
- data/lib/rvc/modules/datastore.rb +11 -78
- data/lib/rvc/modules/device.rb +40 -5
- data/lib/rvc/modules/diagnostics.rb +169 -0
- data/lib/rvc/modules/esxcli.rb +9 -5
- data/lib/rvc/modules/find.rb +5 -3
- data/lib/rvc/modules/host.rb +46 -3
- data/lib/rvc/modules/issue.rb +2 -0
- data/lib/rvc/modules/mark.rb +5 -3
- data/lib/rvc/modules/perf.rb +99 -33
- data/lib/rvc/modules/permissions.rb +2 -0
- data/lib/rvc/modules/resource_pool.rb +2 -0
- data/lib/rvc/modules/role.rb +3 -1
- data/lib/rvc/modules/snapshot.rb +12 -4
- data/lib/rvc/modules/statsinterval.rb +13 -11
- data/lib/rvc/modules/vds.rb +67 -10
- data/lib/rvc/modules/vim.rb +19 -53
- data/lib/rvc/modules/vm.rb +27 -6
- data/lib/rvc/modules/vm_guest.rb +490 -0
- data/lib/rvc/modules/vmrc.rb +60 -32
- data/lib/rvc/modules/vnc.rb +2 -0
- data/lib/rvc/namespace.rb +114 -0
- data/lib/rvc/option_parser.rb +12 -15
- data/lib/rvc/readline-ffi.rb +4 -1
- data/lib/rvc/ruby_evaluator.rb +84 -0
- data/lib/rvc/shell.rb +68 -83
- data/lib/rvc/uri_parser.rb +59 -0
- data/lib/rvc/util.rb +134 -29
- data/lib/rvc/{extensions/PerfCounterInfo.rb → version.rb} +2 -4
- data/lib/rvc/{memory_session.rb → vim.rb} +10 -32
- data/test/modules/foo.rb +9 -0
- data/test/modules/foo/bar.rb +9 -0
- data/test/test_completion.rb +17 -0
- data/test/test_fs.rb +9 -11
- data/test/test_help.rb +46 -0
- data/test/test_helper.rb +12 -0
- data/test/test_metric.rb +1 -2
- data/test/test_modules.rb +38 -0
- data/test/test_parse_path.rb +1 -2
- data/test/test_shell.rb +138 -0
- data/test/test_uri.rb +34 -0
- metadata +115 -81
- data/lib/rvc/extensions/PerformanceManager.rb +0 -83
- data/lib/rvc/filesystem_session.rb +0 -101
- data/lib/rvc/modules.rb +0 -138
@@ -18,7 +18,10 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
require '
|
21
|
+
require 'rvc/vim'
|
22
|
+
VIM::Datastore
|
23
|
+
|
24
|
+
require 'terminal-table'
|
22
25
|
|
23
26
|
opts :download do
|
24
27
|
summary "Download a file from a datastore"
|
@@ -27,34 +30,9 @@ opts :download do
|
|
27
30
|
end
|
28
31
|
|
29
32
|
def download file, local_path
|
30
|
-
|
31
|
-
http = Net::HTTP.new(main_http.address, main_http.port)
|
32
|
-
http.use_ssl = true
|
33
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
34
|
-
#http.set_debug_output $stderr
|
35
|
-
http.start
|
36
|
-
err "certificate mismatch" unless main_http.peer_cert.to_der == http.peer_cert.to_der
|
33
|
+
download_path = http_path file.datastore.send(:datacenter).name, file.datastore.name, file.path
|
37
34
|
|
38
|
-
|
39
|
-
path = http_path file.datastore.send(:datacenter).name, file.datastore.name, file.path
|
40
|
-
http.request_get(path, headers) do |res|
|
41
|
-
case res
|
42
|
-
when Net::HTTPOK
|
43
|
-
len = res.content_length
|
44
|
-
count = 0
|
45
|
-
File.open(local_path, 'wb') do |io|
|
46
|
-
res.read_body do |segment|
|
47
|
-
count += segment.length
|
48
|
-
io.write segment
|
49
|
-
$stdout.write "\e[0G\e[Kdownloading #{count}/#{len} bytes (#{(count*100)/len}%)"
|
50
|
-
$stdout.flush
|
51
|
-
end
|
52
|
-
end
|
53
|
-
$stdout.puts
|
54
|
-
else
|
55
|
-
err "download failed: #{res.message}"
|
56
|
-
end
|
57
|
-
end
|
35
|
+
http_download file.datastore._connection, download_path, local_path
|
58
36
|
end
|
59
37
|
|
60
38
|
|
@@ -69,54 +47,9 @@ def upload local_path, dest
|
|
69
47
|
err "local file does not exist" unless File.exists? local_path
|
70
48
|
real_datastore_path = "#{dir.path}/#{datastore_filename}"
|
71
49
|
|
72
|
-
|
73
|
-
http = Net::HTTP.new(main_http.address, main_http.port)
|
74
|
-
http.use_ssl = true
|
75
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
76
|
-
#http.set_debug_output $stderr
|
77
|
-
http.start
|
78
|
-
err "certificate mismatch" unless main_http.peer_cert.to_der == http.peer_cert.to_der
|
50
|
+
upload_path = http_path dir.datastore.send(:datacenter).name, dir.datastore.name, real_datastore_path
|
79
51
|
|
80
|
-
|
81
|
-
stream = ProgressStream.new(io, io.stat.size) do |s|
|
82
|
-
$stdout.write "\e[0G\e[Kuploading #{s.count}/#{s.len} bytes (#{(s.count*100)/s.len}%)"
|
83
|
-
$stdout.flush
|
84
|
-
end
|
85
|
-
|
86
|
-
headers = {
|
87
|
-
'cookie' => dir.datastore._connection.cookie,
|
88
|
-
'content-length' => io.stat.size.to_s,
|
89
|
-
'Content-Type' => 'application/octet-stream',
|
90
|
-
}
|
91
|
-
path = http_path dir.datastore.send(:datacenter).name, dir.datastore.name, real_datastore_path
|
92
|
-
request = Net::HTTP::Put.new path, headers
|
93
|
-
request.body_stream = stream
|
94
|
-
res = http.request(request)
|
95
|
-
$stdout.puts
|
96
|
-
case res
|
97
|
-
when Net::HTTPOK
|
98
|
-
else
|
99
|
-
err "upload failed: #{res.message}"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
class ProgressStream
|
105
|
-
attr_reader :io, :len, :count
|
106
|
-
|
107
|
-
def initialize io, len, &b
|
108
|
-
@io = io
|
109
|
-
@len = len
|
110
|
-
@count = 0
|
111
|
-
@cb = b
|
112
|
-
end
|
113
|
-
|
114
|
-
def read n
|
115
|
-
io.read(n).tap do |c|
|
116
|
-
@count += c.length if c
|
117
|
-
@cb[self]
|
118
|
-
end
|
119
|
-
end
|
52
|
+
http_upload dir.datastore._connection, local_path, upload_path
|
120
53
|
end
|
121
54
|
|
122
55
|
|
@@ -256,7 +189,7 @@ def find_orphans ds, opts
|
|
256
189
|
if data.empty?
|
257
190
|
puts "No orphans found"
|
258
191
|
else
|
259
|
-
puts(
|
192
|
+
puts(Terminal::Table.new do
|
260
193
|
data.sort_by { |a| a[1] }.each do |x|
|
261
194
|
dir, dirSize, numFiles = x
|
262
195
|
self.headings = 'Directory', 'Space Used', '# Files'
|
@@ -287,14 +220,14 @@ def find_orphans ds, opts
|
|
287
220
|
RbVmomi::VIM::Datastore::FakeDatastoreFolder.new(ds, "#{dirInfo[0]}")
|
288
221
|
end
|
289
222
|
opts[:mark] ||= "#{dsName}_orphans"
|
290
|
-
|
223
|
+
shell.cmds.mark.mark opts[:mark], results
|
291
224
|
puts "Saved results to mark '#{opts[:mark]}'"
|
292
225
|
|
293
226
|
i = 0
|
294
227
|
results.each do |r|
|
295
228
|
display_path = r.path
|
296
229
|
puts "#{i} #{display_path}"
|
297
|
-
|
230
|
+
shell.cmds.mark.mark i.to_s, [r]
|
298
231
|
i += 1
|
299
232
|
end
|
300
233
|
end
|
data/lib/rvc/modules/device.rb
CHANGED
@@ -1,3 +1,26 @@
|
|
1
|
+
# Copyright (c) 2011 VMware, Inc. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require 'rvc/vim'
|
22
|
+
VIM::Datastore
|
23
|
+
|
1
24
|
opts :connect do
|
2
25
|
summary "Connect a virtual device"
|
3
26
|
arg :device, nil, :lookup => VIM::VirtualDevice, :multi => true
|
@@ -21,13 +44,14 @@ end
|
|
21
44
|
opts :remove do
|
22
45
|
summary "Remove a virtual device"
|
23
46
|
arg :device, nil, :lookup => VIM::VirtualDevice, :multi => true
|
47
|
+
opt :no_destroy, "Do not delete backing files"
|
24
48
|
end
|
25
49
|
|
26
|
-
def remove devs
|
50
|
+
def remove devs, opts
|
27
51
|
vm_devs = devs.group_by(&:rvc_vm)
|
28
52
|
tasks = vm_devs.map do |vm,my_devs|
|
29
53
|
device_changes = my_devs.map do |dev|
|
30
|
-
fileOp = dev.backing.is_a?(VIM::VirtualDeviceFileBackingInfo) ? 'destroy' : nil
|
54
|
+
fileOp = (dev.backing.is_a?(VIM::VirtualDeviceFileBackingInfo) && !opts[:no_destroy]) ? 'destroy' : nil
|
31
55
|
{ :operation => :remove, :fileOperation => fileOp, :device => dev }
|
32
56
|
end
|
33
57
|
spec = { :deviceChange => device_changes }
|
@@ -82,15 +106,26 @@ end
|
|
82
106
|
opts :add_disk do
|
83
107
|
summary "Add a hard drive to a virtual machine"
|
84
108
|
arg :vm, nil, :lookup => VIM::VirtualMachine
|
109
|
+
arg :path, "Filename on the datastore", :lookup_parent => VIM::Datastore::FakeDatastoreFolder, :required => false
|
85
110
|
opt :size, 'Size', :default => '10G'
|
86
111
|
opt :controller, 'Virtual controller', :type => :string, :lookup => VIM::VirtualController
|
112
|
+
opt :file_op, 'File operation (create|reuse|replace)', :default => 'create'
|
87
113
|
end
|
88
114
|
|
89
|
-
def add_disk vm, opts
|
115
|
+
def add_disk vm, path, opts
|
90
116
|
controller, unit_number = pick_controller vm, opts[:controller], [VIM::VirtualSCSIController, VIM::VirtualIDEController]
|
91
117
|
id = "disk-#{controller.key}-#{unit_number}"
|
92
|
-
|
93
|
-
|
118
|
+
|
119
|
+
if path
|
120
|
+
dir, file = *path
|
121
|
+
filename = "#{dir.datastore_path}/#{file}"
|
122
|
+
else
|
123
|
+
filename = "#{File.dirname(vm.summary.config.vmPathName)}/#{id}.vmdk"
|
124
|
+
end
|
125
|
+
|
126
|
+
opts[:file_op] = nil if opts[:file_op] == 'reuse'
|
127
|
+
|
128
|
+
_add_device vm, opts[:file_op], VIM::VirtualDisk(
|
94
129
|
:key => -1,
|
95
130
|
:backing => VIM.VirtualDiskFlatVer2BackingInfo(
|
96
131
|
:fileName => filename,
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# Copyright (c) 2012 VMware, Inc. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
DEFAULT_SERVER_PLACEHOLDER = '0.0.0.0'
|
22
|
+
|
23
|
+
def wait_for_multiple_tasks tasks, timeout
|
24
|
+
if tasks == []
|
25
|
+
return []
|
26
|
+
end
|
27
|
+
pc = tasks.first._connection.serviceContent.propertyCollector
|
28
|
+
done = false
|
29
|
+
t1 = Time.now
|
30
|
+
while !done && (Time.now - t1) < timeout
|
31
|
+
tasks_props = pc.collectMultiple(tasks, 'info.state')
|
32
|
+
if tasks_props.reject{|t,f| ['success', 'error'].member?(f['info.state'])}.empty?
|
33
|
+
done = true
|
34
|
+
end
|
35
|
+
sleep 2
|
36
|
+
end
|
37
|
+
tasks_props = pc.collectMultiple(tasks, 'info.state', 'info.error')
|
38
|
+
results = Hash[tasks_props.map do |task, props|
|
39
|
+
result = if props['info.state'] == 'success'
|
40
|
+
task.info.result
|
41
|
+
elsif props['info.state'] == 'error'
|
42
|
+
props['info.error']
|
43
|
+
else
|
44
|
+
"Timed out"
|
45
|
+
end
|
46
|
+
[task, result]
|
47
|
+
end]
|
48
|
+
results
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
opts :vm_create do
|
53
|
+
summary "Check that VMs can be created on all hosts in a cluster"
|
54
|
+
arg :cluster, nil, :lookup => VIM::ComputeResource, :multi => true
|
55
|
+
opt :datastore, "Datastore to put (temporary) VMs on", :lookup => VIM::Datastore
|
56
|
+
opt :vm_folder, "VM Folder to place (temporary) VMs in", :lookup => VIM::Folder
|
57
|
+
opt :timeout, "Time to wait for VM creation to finish", :type => :int, :default => 3 * 60
|
58
|
+
end
|
59
|
+
|
60
|
+
def vm_create clusters, opts
|
61
|
+
datastore = opts[:datastore]
|
62
|
+
vm_folder = opts[:vm_folder]
|
63
|
+
err "datastore is a required parameter" unless datastore
|
64
|
+
err "vm_folder is a required parameter" unless vm_folder
|
65
|
+
|
66
|
+
puts "Creating one VM per host ... (timeout = #{opts[:timeout]} sec)"
|
67
|
+
result = _vm_create clusters, datastore, vm_folder, opts
|
68
|
+
|
69
|
+
errors = result.select{|h, x| x['status'] != 'green'}
|
70
|
+
errors.each do |host, info|
|
71
|
+
puts "Failed to create VM on host #{host} (in cluster #{info['cluster']}): #{info['error']}"
|
72
|
+
end
|
73
|
+
if errors.length == 0
|
74
|
+
puts "Success"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def _vm_create clusters, datastore, vm_folder, opts = {}
|
79
|
+
pc = datastore._connection.serviceContent.propertyCollector
|
80
|
+
datastore_path = "[#{datastore.name}]"
|
81
|
+
run = Time.now.to_i % 1000
|
82
|
+
tasks_map = {}
|
83
|
+
cluster_host_map = {}
|
84
|
+
clusters_props = pc.collectMultiple(clusters, 'name', 'resourcePool', 'host')
|
85
|
+
all_hosts = clusters_props.map{|c, p| p['host']}.flatten
|
86
|
+
hosts_props = pc.collectMultiple(all_hosts, 'name')
|
87
|
+
|
88
|
+
hosts_infos = Hash[all_hosts.map{|host| [host, {}]}]
|
89
|
+
|
90
|
+
clusters.each do |cluster|
|
91
|
+
cluster_props = clusters_props[cluster]
|
92
|
+
rp = cluster_props['resourcePool']
|
93
|
+
hosts = cluster_props['host']
|
94
|
+
hosts.map do |host|
|
95
|
+
cluster_host_map[host] = cluster
|
96
|
+
config = {
|
97
|
+
:name => "VM-on-#{hosts_props[host]['name']}-#{run}",
|
98
|
+
:guestId => 'otherGuest',
|
99
|
+
:files => { :vmPathName => datastore_path },
|
100
|
+
:numCPUs => 1,
|
101
|
+
:memoryMB => 16,
|
102
|
+
:deviceChange => [
|
103
|
+
{
|
104
|
+
:operation => :add,
|
105
|
+
:device => VIM.VirtualCdrom(
|
106
|
+
:key => -2,
|
107
|
+
:connectable => {
|
108
|
+
:allowGuestControl => true,
|
109
|
+
:connected => true,
|
110
|
+
:startConnected => true,
|
111
|
+
},
|
112
|
+
:backing => VIM.VirtualCdromIsoBackingInfo(
|
113
|
+
:fileName => datastore_path
|
114
|
+
),
|
115
|
+
:controllerKey => 200,
|
116
|
+
:unitNumber => 0
|
117
|
+
)
|
118
|
+
}
|
119
|
+
],
|
120
|
+
}
|
121
|
+
task = vm_folder.CreateVM_Task(:config => config,
|
122
|
+
:pool => rp,
|
123
|
+
:host => host)
|
124
|
+
tasks_map[task] = host
|
125
|
+
hosts_infos[host][:create_task] = task
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
create_tasks = tasks_map.keys
|
130
|
+
create_results = wait_for_multiple_tasks create_tasks, opts[:timeout]
|
131
|
+
create_results.each { |t, r| hosts_infos[tasks_map[t]][:create_result] = r }
|
132
|
+
|
133
|
+
vms = create_results.select{|t, x| x.is_a? VIM::VirtualMachine}
|
134
|
+
destroy_tasks = Hash[vms.map{|t, x| [x.Destroy_Task, t]}]
|
135
|
+
|
136
|
+
destroy_results = wait_for_multiple_tasks destroy_tasks.keys, opts[:timeout]
|
137
|
+
destroy_results.each do |t, r|
|
138
|
+
create_task = destroy_tasks[t]
|
139
|
+
hosts_infos[tasks_map[create_task]][:destroy_result] = r
|
140
|
+
end
|
141
|
+
|
142
|
+
out = {}
|
143
|
+
all_hosts.each do |host|
|
144
|
+
host_info = hosts_infos[host]
|
145
|
+
host_props = hosts_props[host]
|
146
|
+
cluster = cluster_host_map[host]
|
147
|
+
cluster_props = clusters_props[cluster]
|
148
|
+
|
149
|
+
result = host_info[:create_result]
|
150
|
+
result = host_info[:destroy_result] if result.is_a?(VIM::VirtualMachine)
|
151
|
+
if result == nil
|
152
|
+
error_str = nil
|
153
|
+
status = 'green'
|
154
|
+
elsif result.is_a?(String)
|
155
|
+
error_str = result
|
156
|
+
status = 'red'
|
157
|
+
else
|
158
|
+
error_str = "#{result.fault.class.wsdl_name}: #{result.localizedMessage}"
|
159
|
+
status = 'red'
|
160
|
+
end
|
161
|
+
|
162
|
+
out[host_props['name']] = {
|
163
|
+
'cluster' => cluster_props['name'],
|
164
|
+
'status' => status,
|
165
|
+
'error' => error_str
|
166
|
+
}
|
167
|
+
end
|
168
|
+
out
|
169
|
+
end
|
data/lib/rvc/modules/esxcli.rb
CHANGED
@@ -18,9 +18,13 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
+
require 'rvc/vim'
|
22
|
+
|
23
|
+
require 'rvc/ttl_cache'
|
24
|
+
|
21
25
|
raw_opts :execute, "Execute an esxcli command"
|
22
26
|
|
23
|
-
EsxcliCache = TTLCache.new 60
|
27
|
+
EsxcliCache = RVC::TTLCache.new 60
|
24
28
|
|
25
29
|
def lookup_esxcli host, args
|
26
30
|
cur = EsxcliCache[host, :esxcli]
|
@@ -40,14 +44,14 @@ def lookup_esxcli host, args
|
|
40
44
|
return cur
|
41
45
|
end
|
42
46
|
|
43
|
-
rvc_completor :execute do |
|
44
|
-
if
|
47
|
+
rvc_completor :execute do |word, args|
|
48
|
+
if args.length == 1
|
45
49
|
# HostSystem argument
|
46
|
-
|
50
|
+
shell.completion.fs_candidates word
|
47
51
|
else
|
48
52
|
# esxcli namespace/method/arguments
|
49
53
|
host = lookup_single! args[0], VIM::HostSystem
|
50
|
-
o = lookup_esxcli host, args[1
|
54
|
+
o = lookup_esxcli host, args[1...-1]
|
51
55
|
|
52
56
|
case o
|
53
57
|
when VIM::EsxcliCommand
|
data/lib/rvc/modules/find.rb
CHANGED
@@ -18,6 +18,8 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
+
require 'rvc/vim'
|
22
|
+
|
21
23
|
opts :find do
|
22
24
|
summary "Find objects matching certain criteria"
|
23
25
|
arg :args, "Paths or +terms", :required => false, :multi => true
|
@@ -37,14 +39,14 @@ def find args, opts
|
|
37
39
|
|
38
40
|
results = find_items args[:term], args[:root], opts[:type]
|
39
41
|
|
40
|
-
|
42
|
+
shell.cmds.mark.mark opts[:mark], results
|
41
43
|
|
42
44
|
i = 0
|
43
|
-
cwd =
|
45
|
+
cwd = shell.fs.cur.rvc_path_str
|
44
46
|
cwd_prefix = /^#{Regexp.escape cwd}\//
|
45
47
|
results.each do |r|
|
46
48
|
puts "#{i} #{r.rvc_path_str.gsub(cwd_prefix, '')}"
|
47
|
-
|
49
|
+
shell.cmds.mark.mark i.to_s, [r]
|
48
50
|
i += 1
|
49
51
|
end
|
50
52
|
end
|
data/lib/rvc/modules/host.rb
CHANGED
@@ -18,14 +18,35 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
+
require 'rvc/vim'
|
22
|
+
|
21
23
|
opts :reboot do
|
22
|
-
summary "Reboot
|
24
|
+
summary "Reboot hosts"
|
23
25
|
arg :host, nil, :lookup => VIM::HostSystem, :multi => true
|
24
|
-
opt :force, "Reboot even if in maintenance mode", :default => false
|
26
|
+
opt :force, "Reboot even if not in maintenance mode", :default => false
|
27
|
+
opt :wait, "Wait for the host to be connected again", :type => :boolean
|
25
28
|
end
|
26
29
|
|
27
30
|
def reboot hosts, opts
|
28
31
|
tasks hosts, :RebootHost, :force => opts[:force]
|
32
|
+
|
33
|
+
if opts[:wait]
|
34
|
+
puts "Waiting for hosts to reboot ..."
|
35
|
+
# There is no proper way to wait for a host to reboot, so we
|
36
|
+
# implement a heuristic that is close enough:
|
37
|
+
# First we wait for a moment to give the host time to actually
|
38
|
+
# disconnect. Then we just wait for it to be responding again.
|
39
|
+
sleep 3 * 60
|
40
|
+
|
41
|
+
hosts.each do |host|
|
42
|
+
# We could use the property collector here to wait for an
|
43
|
+
# update instead of polling.
|
44
|
+
while !(host.runtime.connectionState == "connected" && host.runtime.powerState == "poweredOn")
|
45
|
+
sleep 10
|
46
|
+
end
|
47
|
+
puts "Host #{host.name} is back up"
|
48
|
+
end
|
49
|
+
end
|
29
50
|
end
|
30
51
|
|
31
52
|
|
@@ -76,10 +97,18 @@ opts :enter_maintenance_mode do
|
|
76
97
|
summary "Put hosts into maintenance mode"
|
77
98
|
arg :host, nil, :lookup => VIM::HostSystem, :multi => true
|
78
99
|
opt :timeout, "Timeout", :default => 0
|
100
|
+
opt :evacuate_powered_off_vms, "Evacuate powered off vms", :type => :boolean
|
101
|
+
opt :no_wait, "Don't wait for Task to complete", :type => :boolean
|
79
102
|
end
|
80
103
|
|
81
104
|
def enter_maintenance_mode hosts, opts
|
82
|
-
|
105
|
+
if opts[:no_wait]
|
106
|
+
hosts.each do |host|
|
107
|
+
host.EnterMaintenanceMode_Task(:timeout => opts[:timeout], :evacuatePoweredOffVms => opts[:evacuate_powered_off_vms])
|
108
|
+
end
|
109
|
+
else
|
110
|
+
tasks hosts, :EnterMaintenanceMode, :timeout => opts[:timeout], :evacuatePoweredOffVms => opts[:evacuate_powered_off_vms]
|
111
|
+
end
|
83
112
|
end
|
84
113
|
|
85
114
|
|
@@ -160,3 +189,17 @@ def add_nfs_datastore hosts, opts
|
|
160
189
|
datastoreSystem.CreateNasDatastore :spec => spec
|
161
190
|
end
|
162
191
|
end
|
192
|
+
|
193
|
+
|
194
|
+
opts :rescan_storage do
|
195
|
+
summary "Rescan HBAs and VMFS"
|
196
|
+
arg :host, nil, :lookup => VIM::HostSystem, :multi => true
|
197
|
+
end
|
198
|
+
|
199
|
+
def rescan_storage hosts
|
200
|
+
hosts.each do |host|
|
201
|
+
storageSystem = host.configManager.storageSystem
|
202
|
+
storageSystem.RescanAllHba
|
203
|
+
storageSystem.RescanVmfs
|
204
|
+
end
|
205
|
+
end
|