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
@@ -0,0 +1,48 @@
|
|
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
|
+
module RVC
|
22
|
+
|
23
|
+
# This module should be mixed in with all connection classes.
|
24
|
+
module Connection
|
25
|
+
include InventoryObject
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
include InventoryObject::ClassMethods
|
29
|
+
|
30
|
+
def folder?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.included m
|
36
|
+
m.extend ClassMethods
|
37
|
+
end
|
38
|
+
|
39
|
+
def _connection
|
40
|
+
self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class NullConnection
|
45
|
+
include Connection
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -58,11 +58,11 @@ class RbVmomi::VIM::DistributedVirtualSwitch
|
|
58
58
|
vlan.vlanId.each { |range| trunk_ranges << Range.new(range.start,range.end) }
|
59
59
|
end
|
60
60
|
end
|
61
|
-
trunks =
|
61
|
+
trunks = $shell.cmds.vds.merge_ranges(trunk_ranges).map { |r|
|
62
62
|
if r.begin == r.end then "#{r.begin}" else "#{r.begin}-#{r.end}" end
|
63
63
|
}.join ','
|
64
64
|
|
65
|
-
tags =
|
65
|
+
tags = $shell.cmds.vds.merge_ranges(tag_ranges).map { |r|
|
66
66
|
if r.begin == r.end then "#{r.begin}" else "#{r.begin}-#{r.end}" end
|
67
67
|
}.join ','
|
68
68
|
str = ""
|
@@ -141,7 +141,7 @@ class RbVmomi::VIM::DistributedVirtualSwitch
|
|
141
141
|
portgroups = RVC::FakeFolder.new(self, :portgroup_children)
|
142
142
|
portgroups.define_singleton_method :display_info, lambda {
|
143
143
|
vds = self.rvc_parent
|
144
|
-
|
144
|
+
$shell.cmds.basic.table vds.portgroup, {}
|
145
145
|
}
|
146
146
|
|
147
147
|
{
|
@@ -31,7 +31,97 @@ class RbVmomi::VIM::HostSystem
|
|
31
31
|
" (host): cpu #{numCpuPkgs}*#{numCpuCores}*#{"%.2f" % (cpuMhz.to_f/1000)} GHz, memory #{"%.2f" % (memorySize/10**9)} GB"
|
32
32
|
end
|
33
33
|
|
34
|
+
field 'state.connection' do
|
35
|
+
summary "State of connection to VC."
|
36
|
+
property 'runtime.connectionState'
|
37
|
+
end
|
38
|
+
|
39
|
+
field 'state.power' do
|
40
|
+
summary "Host power state."
|
41
|
+
property 'runtime.powerState'
|
42
|
+
end
|
43
|
+
|
44
|
+
field 'uptime' do
|
45
|
+
summary "Host's uptime in days"
|
46
|
+
properties %w(runtime.bootTime)
|
47
|
+
block { |t| t ? MetricNumber.new(((Time.now-t) / (24 * 60 * 60)), 'd') : nil }
|
48
|
+
end
|
49
|
+
|
50
|
+
field 'num.vms' do
|
51
|
+
summary "Number of VMs on the host"
|
52
|
+
properties %w(vm)
|
53
|
+
block { |t| t ? t.length : nil }
|
54
|
+
end
|
55
|
+
|
56
|
+
field 'num.poweredonvms' do
|
57
|
+
summary "Number of VMs on the host"
|
58
|
+
properties %w(vm)
|
59
|
+
block do |vms|
|
60
|
+
if vms && vms.length > 0
|
61
|
+
conn = vms.first._connection
|
62
|
+
pc = conn.propertyCollector
|
63
|
+
vmsProps = pc.collectMultiple(vms, 'runtime.powerState')
|
64
|
+
vmsProps.select{|vm, p| p['runtime.powerState'] == 'poweredOn'}.length
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
field 'cpuusage' do
|
70
|
+
summary "Realtime CPU usage in percent"
|
71
|
+
properties %w(summary.hardware.numCpuCores summary.hardware.cpuMhz summary.quickStats)
|
72
|
+
block do |cores, mhz, stats|
|
73
|
+
if cores && mhz && stats
|
74
|
+
value = stats.overallCpuUsage.to_f * 100 / (cores * mhz)
|
75
|
+
MetricNumber.new(value, '%')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
field 'memusage' do
|
81
|
+
summary "Realtime Mem usage in percent"
|
82
|
+
properties %w(summary.hardware.memorySize summary.quickStats)
|
83
|
+
block do |mem, stats|
|
84
|
+
if mem && stats
|
85
|
+
value = stats.overallMemoryUsage.to_f * 100 / (mem / 1024.0 / 1024.0)
|
86
|
+
MetricNumber.new(value, '%')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
[['.realtime', 1], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
|
92
|
+
field "cpuusage#{label}" do
|
93
|
+
summary "CPU Usage in Percent"
|
94
|
+
perfmetrics %w(cpu.usage)
|
95
|
+
perfmetric_settings :max_samples => max_samples
|
96
|
+
block do |value|
|
97
|
+
if value
|
98
|
+
value = value.sum.to_f / value.length / 100
|
99
|
+
MetricNumber.new(value, '%')
|
100
|
+
else
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
[['.realtime', 1], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
|
108
|
+
field "memusage#{label}" do
|
109
|
+
summary "Mem Usage in Percent"
|
110
|
+
perfmetrics %w(mem.usage)
|
111
|
+
perfmetric_settings :max_samples => max_samples
|
112
|
+
block do |value|
|
113
|
+
if value
|
114
|
+
value = value.sum.to_f / value.length / 100
|
115
|
+
MetricNumber.new(value, '%')
|
116
|
+
else
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
34
123
|
def display_info
|
124
|
+
super
|
35
125
|
summary = self.summary
|
36
126
|
runtime = summary.runtime
|
37
127
|
stats = summary.quickStats
|
@@ -28,26 +28,34 @@ class RbVmomi::VIM::VirtualMachine
|
|
28
28
|
|
29
29
|
field 'storagebw' do
|
30
30
|
summary "Storage Bandwidth"
|
31
|
-
perfmetrics %w(
|
31
|
+
perfmetrics %w(virtualDisk.read virtualDisk.write)
|
32
32
|
block do |read, write|
|
33
33
|
if read && write
|
34
|
-
|
35
|
-
|
34
|
+
read = read.select{|x| x != -1}
|
35
|
+
write = write.select{|x| x != -1}
|
36
|
+
if read.length > 0 && write.length > 0
|
37
|
+
io = (read.sum.to_f / read.length) + (write.sum.to_f / write.length)
|
38
|
+
MetricNumber.new(io * 1024, 'B/s')
|
39
|
+
end
|
36
40
|
else
|
37
41
|
nil
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
|
-
[['', 5], ['.realtime',
|
46
|
+
[['', 5], ['.realtime', 3], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
|
43
47
|
field "storageiops#{label}" do
|
44
48
|
summary "Storage IOPS"
|
45
|
-
perfmetrics %w(
|
49
|
+
perfmetrics %w(virtualDisk.numberReadAveraged virtualDisk.numberWriteAveraged)
|
46
50
|
perfmetric_settings :max_samples => max_samples
|
47
51
|
block do |read, write|
|
48
52
|
if read && write
|
49
|
-
|
50
|
-
|
53
|
+
read = read.select{|x| x != -1}
|
54
|
+
write = write.select{|x| x != -1}
|
55
|
+
if read.length > 0 && write.length > 0
|
56
|
+
io = (read.sum.to_f / read.length) + (write.sum.to_f / write.length)
|
57
|
+
MetricNumber.new(io, 'IOPS')
|
58
|
+
end
|
51
59
|
else
|
52
60
|
nil
|
53
61
|
end
|
@@ -55,6 +63,24 @@ class RbVmomi::VIM::VirtualMachine
|
|
55
63
|
end
|
56
64
|
end
|
57
65
|
|
66
|
+
['Read', 'Write'].each do |type|
|
67
|
+
[['', 5], ['.realtime', 1], ['.5min', 5 * 3], ['.10min', 10 * 3]].each do |label, max_samples|
|
68
|
+
field "storagelatency.#{type.downcase}#{label}" do
|
69
|
+
summary "Storage Latency #{type}"
|
70
|
+
perfmetrics ["virtualDisk.total#{type}Latency"]
|
71
|
+
perfmetric_settings :max_samples => max_samples
|
72
|
+
block do |latency|
|
73
|
+
if latency
|
74
|
+
io = (latency.sum.to_f / latency.length)
|
75
|
+
MetricNumber.new(io, 'ms')
|
76
|
+
else
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
58
84
|
field 'ip' do
|
59
85
|
summary "The guest tools reported IP address."
|
60
86
|
property 'guest.ipAddress'
|
@@ -157,6 +183,10 @@ class RbVmomi::VIM::VirtualMachine
|
|
157
183
|
storage.perDatastoreUsage.map do |usage|
|
158
184
|
puts " #{usage.datastore.name}: committed=#{usage.committed.metric}B uncommitted=#{usage.uncommitted.metric}B unshared=#{usage.unshared.metric}B"
|
159
185
|
end
|
186
|
+
|
187
|
+
if runtime.dasVmProtection
|
188
|
+
puts "HA protected: #{runtime.dasVmProtection.dasProtected ? 'yes' : 'no'}"
|
189
|
+
end
|
160
190
|
end
|
161
191
|
|
162
192
|
def self.ls_properties
|
data/lib/rvc/field.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 'set'
|
22
|
+
|
21
23
|
module RVC
|
22
24
|
|
23
25
|
module ObjectWithFields
|
@@ -39,24 +41,69 @@ module ObjectWithFields
|
|
39
41
|
@fields[name] = RVC::Field.new(name).tap { |f| f.instance_eval &b }
|
40
42
|
end
|
41
43
|
end
|
44
|
+
|
45
|
+
def field_properties names
|
46
|
+
out = []
|
47
|
+
names.each do |name|
|
48
|
+
name = name.to_s
|
49
|
+
field = self.class.fields[name]
|
50
|
+
if field == nil
|
51
|
+
nil
|
52
|
+
elsif self.class < VIM::ManagedObject
|
53
|
+
out += field.properties
|
54
|
+
end
|
55
|
+
end
|
56
|
+
out.uniq
|
57
|
+
end
|
58
|
+
|
59
|
+
def perfmetrics names
|
60
|
+
out = []
|
61
|
+
names.each do |name|
|
62
|
+
name = name.to_s
|
63
|
+
field = self.class.fields[name]
|
64
|
+
if field == nil
|
65
|
+
nil
|
66
|
+
else
|
67
|
+
perfmetrics = field.perfmetrics
|
68
|
+
if perfmetrics.length > 0
|
69
|
+
perfopts = field.perfmetric_settings.dup
|
70
|
+
perfopts[:max_samples] ||= 5
|
71
|
+
out << {:metrics => perfmetrics, :opts => perfopts}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
out.uniq
|
76
|
+
end
|
42
77
|
|
43
|
-
def field name
|
78
|
+
def field name, props_values = {}, perf_values = {}
|
44
79
|
name = name.to_s
|
45
80
|
field = self.class.fields[name]
|
46
81
|
if field == nil
|
47
82
|
return nil
|
48
83
|
elsif self.class < VIM::ManagedObject
|
49
|
-
|
50
|
-
if
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
84
|
+
properties = field.properties
|
85
|
+
if properties.all?{|x| props_values.has_key?(x)}
|
86
|
+
props = properties.map{|x| props_values[x]}
|
87
|
+
else
|
88
|
+
*props = collect *field.properties
|
89
|
+
end
|
90
|
+
perfmetrics = field.perfmetrics
|
91
|
+
if perfmetrics.length > 0
|
92
|
+
if perfmetrics.all?{|x| perf_values.has_key?(x)}
|
93
|
+
props += perfmetrics.map do |x|
|
94
|
+
perf_values[x]
|
95
|
+
end
|
96
|
+
else
|
97
|
+
perfmgr = self._connection.serviceContent.perfManager
|
98
|
+
perfopts = field.perfmetric_settings.dup
|
99
|
+
perfopts[:max_samples] ||= 5
|
100
|
+
stats = perfmgr.retrieve_stats [self], field.perfmetrics, perfopts
|
101
|
+
props += field.perfmetrics.map do |x|
|
102
|
+
if stats[self]
|
103
|
+
stats[self][:metrics][x]
|
104
|
+
else
|
105
|
+
nil
|
106
|
+
end
|
60
107
|
end
|
61
108
|
end
|
62
109
|
end
|
data/lib/rvc/fs.rb
CHANGED
@@ -21,7 +21,7 @@
|
|
21
21
|
module RVC
|
22
22
|
|
23
23
|
class FS
|
24
|
-
attr_reader :root, :cur
|
24
|
+
attr_reader :root, :cur, :marks
|
25
25
|
|
26
26
|
MARK_PATTERN = /^~(?:([\d\w]*|~|@))$/
|
27
27
|
REGEX_PATTERN = /^%/
|
@@ -31,6 +31,7 @@ class FS
|
|
31
31
|
fail unless root.is_a? RVC::InventoryObject
|
32
32
|
@root = root
|
33
33
|
@cur = root
|
34
|
+
@marks = {}
|
34
35
|
end
|
35
36
|
|
36
37
|
def display_path
|
@@ -39,7 +40,7 @@ class FS
|
|
39
40
|
|
40
41
|
def cd dst
|
41
42
|
fail unless dst.is_a? RVC::InventoryObject
|
42
|
-
|
43
|
+
@marks['~'] = [@cur]
|
43
44
|
@cur = dst
|
44
45
|
end
|
45
46
|
|
@@ -70,7 +71,7 @@ class FS
|
|
70
71
|
# XXX shouldnt be nil
|
71
72
|
[(cur.respond_to?(:parent) && cur.parent) ? cur.parent : (cur.rvc_parent || cur)]
|
72
73
|
when MARK_PATTERN
|
73
|
-
if first and objs = $
|
74
|
+
if first and objs = @marks[$1]
|
74
75
|
objs
|
75
76
|
else
|
76
77
|
[]
|
@@ -83,7 +84,7 @@ class FS
|
|
83
84
|
cur.children.select { |k,v| k =~ regex }.map { |k,v| v.rvc_link(cur, k); v }
|
84
85
|
else
|
85
86
|
# XXX check for ambiguous child
|
86
|
-
if first and arc =~ /^\d+$/ and objs =
|
87
|
+
if first and arc =~ /^\d+$/ and objs = @marks[arc]
|
87
88
|
objs
|
88
89
|
else
|
89
90
|
if child = cur.traverse_one(arc)
|
@@ -96,6 +97,35 @@ class FS
|
|
96
97
|
end
|
97
98
|
end
|
98
99
|
|
100
|
+
def delete_numeric_marks
|
101
|
+
@marks.reject! { |k,v| k =~ /^\d+$/ }
|
102
|
+
end
|
103
|
+
|
104
|
+
# Utility methods
|
105
|
+
|
106
|
+
def lookup_single path
|
107
|
+
objs = lookup path
|
108
|
+
Util.err "Not found: #{path.inspect}" if objs.empty?
|
109
|
+
Util.err "More than one match for #{path.inspect}" if objs.size > 1
|
110
|
+
objs.first
|
111
|
+
end
|
112
|
+
|
113
|
+
def lookup! path, types
|
114
|
+
types = [types] unless types.is_a? Enumerable
|
115
|
+
lookup(path).tap do |objs|
|
116
|
+
objs.each do |obj|
|
117
|
+
Util.err "Expected #{types*'/'} but got #{obj.class} at #{path.inspect}" unless types.any? { |type| obj.is_a? type }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def lookup_single! path, type
|
123
|
+
objs = lookup!(path, type)
|
124
|
+
Util.err "Not found: #{path.inspect}" if objs.empty?
|
125
|
+
Util.err "More than one match for #{path.inspect}" if objs.size > 1
|
126
|
+
objs.first
|
127
|
+
end
|
128
|
+
|
99
129
|
private
|
100
130
|
|
101
131
|
def glob_to_regex str
|
data/lib/rvc/inventory.rb
CHANGED
data/lib/rvc/modules/alarm.rb
CHANGED