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.
Files changed (66) hide show
  1. data/Rakefile +1 -1
  2. data/VERSION +1 -1
  3. data/bin/rvc +46 -70
  4. data/devel/test-dependencies.sh +4 -0
  5. data/lib/rvc.rb +5 -6
  6. data/lib/rvc/command.rb +65 -0
  7. data/lib/rvc/command_slate.rb +112 -0
  8. data/lib/rvc/completion.rb +89 -58
  9. data/lib/rvc/connection.rb +48 -0
  10. data/lib/rvc/extensions/DistributedVirtualPortgroup.rb +1 -1
  11. data/lib/rvc/extensions/DistributedVirtualSwitch.rb +3 -3
  12. data/lib/rvc/extensions/HostSystem.rb +90 -0
  13. data/lib/rvc/extensions/VirtualMachine.rb +37 -7
  14. data/lib/rvc/field.rb +59 -12
  15. data/lib/rvc/fs.rb +34 -4
  16. data/lib/rvc/inventory.rb +5 -1
  17. data/lib/rvc/modules/alarm.rb +2 -0
  18. data/lib/rvc/modules/basic.rb +66 -61
  19. data/lib/rvc/modules/cluster.rb +117 -22
  20. data/lib/rvc/modules/connection.rb +40 -0
  21. data/lib/rvc/modules/core.rb +4 -16
  22. data/lib/rvc/modules/datacenter.rb +2 -0
  23. data/lib/rvc/modules/datastore.rb +11 -78
  24. data/lib/rvc/modules/device.rb +40 -5
  25. data/lib/rvc/modules/diagnostics.rb +169 -0
  26. data/lib/rvc/modules/esxcli.rb +9 -5
  27. data/lib/rvc/modules/find.rb +5 -3
  28. data/lib/rvc/modules/host.rb +46 -3
  29. data/lib/rvc/modules/issue.rb +2 -0
  30. data/lib/rvc/modules/mark.rb +5 -3
  31. data/lib/rvc/modules/perf.rb +99 -33
  32. data/lib/rvc/modules/permissions.rb +2 -0
  33. data/lib/rvc/modules/resource_pool.rb +2 -0
  34. data/lib/rvc/modules/role.rb +3 -1
  35. data/lib/rvc/modules/snapshot.rb +12 -4
  36. data/lib/rvc/modules/statsinterval.rb +13 -11
  37. data/lib/rvc/modules/vds.rb +67 -10
  38. data/lib/rvc/modules/vim.rb +19 -53
  39. data/lib/rvc/modules/vm.rb +27 -6
  40. data/lib/rvc/modules/vm_guest.rb +490 -0
  41. data/lib/rvc/modules/vmrc.rb +60 -32
  42. data/lib/rvc/modules/vnc.rb +2 -0
  43. data/lib/rvc/namespace.rb +114 -0
  44. data/lib/rvc/option_parser.rb +12 -15
  45. data/lib/rvc/readline-ffi.rb +4 -1
  46. data/lib/rvc/ruby_evaluator.rb +84 -0
  47. data/lib/rvc/shell.rb +68 -83
  48. data/lib/rvc/uri_parser.rb +59 -0
  49. data/lib/rvc/util.rb +134 -29
  50. data/lib/rvc/{extensions/PerfCounterInfo.rb → version.rb} +2 -4
  51. data/lib/rvc/{memory_session.rb → vim.rb} +10 -32
  52. data/test/modules/foo.rb +9 -0
  53. data/test/modules/foo/bar.rb +9 -0
  54. data/test/test_completion.rb +17 -0
  55. data/test/test_fs.rb +9 -11
  56. data/test/test_help.rb +46 -0
  57. data/test/test_helper.rb +12 -0
  58. data/test/test_metric.rb +1 -2
  59. data/test/test_modules.rb +38 -0
  60. data/test/test_parse_path.rb +1 -2
  61. data/test/test_shell.rb +138 -0
  62. data/test/test_uri.rb +34 -0
  63. metadata +115 -81
  64. data/lib/rvc/extensions/PerformanceManager.rb +0 -83
  65. data/lib/rvc/filesystem_session.rb +0 -101
  66. data/lib/rvc/modules.rb +0 -138
@@ -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 :show do
22
24
  summary "Show issues on the given entities"
23
25
  arg :entity, nil, :lookup => VIM::ManagedEntity, :multi => true
@@ -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 :mark do
22
24
  summary "Save an object for later use"
23
25
  arg :key, "Name for this mark"
@@ -29,7 +31,7 @@ rvc_alias :mark, :m
29
31
 
30
32
  def mark key, objs
31
33
  err "invalid mark name" unless key =~ /^\w+$/
32
- $shell.session.set_mark key, objs
34
+ shell.fs.marks[key] = objs
33
35
  end
34
36
 
35
37
 
@@ -42,7 +44,7 @@ rvc_alias :edit, :me
42
44
 
43
45
  def edit key
44
46
  editor = ENV['VISUAL'] || ENV['EDITOR'] || 'vi'
45
- objs = $shell.session.get_mark(key) or err "no such mark #{key.inspect}"
47
+ objs = shell.fs.marks[key] or err "no such mark #{key.inspect}"
46
48
  filename = File.join(Dir.tmpdir, "rvc.#{Time.now.to_i}.#{rand(65536)}")
47
49
  File.open(filename, 'w') { |io| objs.each { |obj| io.puts(obj.rvc_path_str) } }
48
50
  begin
@@ -61,5 +63,5 @@ opts :list do
61
63
  end
62
64
 
63
65
  def list
64
- $shell.session.marks.each { |x| puts x }
66
+ shell.fs.marks.each { |k,v| puts k }
65
67
  end
@@ -1,9 +1,24 @@
1
- begin
2
- require 'gnuplot'
3
- RVC::HAVE_GNUPLOT = true
4
- rescue LoadError
5
- RVC::HAVE_GNUPLOT = false
6
- end
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'
7
22
 
8
23
  TIMEFMT = '%Y-%m-%dT%H:%M:%SZ'
9
24
 
@@ -15,6 +30,39 @@ DISPLAY_TIMEFMT = {
15
30
  4 => '%Y/%m/%d',
16
31
  }
17
32
 
33
+ def require_gnuplot
34
+ begin
35
+ require 'gnuplot'
36
+ rescue LoadError
37
+ Gem::Specification.reset
38
+ begin
39
+ require 'gnuplot'
40
+ rescue LoadError
41
+ err "The gnuplot gem is not installed"
42
+ end
43
+ end
44
+ end
45
+
46
+ def find_interval pm, start
47
+ now = Time.now
48
+ ago = now - start
49
+
50
+ if ago < 3600
51
+ #puts "Using realtime interval, period = 20 seconds."
52
+ interval_id = 20
53
+ display_timefmt = DISPLAY_TIMEFMT[:realtime]
54
+ else
55
+ intervals = pm.historicalInterval
56
+ interval = intervals.find { |x| now - x.length < start }
57
+ err "start time is too long ago" unless interval
58
+ #puts "Using historical interval #{interval.name.inspect}, period = #{interval.samplingPeriod} seconds."
59
+ interval_id = interval.samplingPeriod
60
+ display_timefmt = DISPLAY_TIMEFMT[interval.key]
61
+ end
62
+
63
+ return interval_id, display_timefmt
64
+ end
65
+
18
66
  opts :plot do
19
67
  summary "Plot a graph of the given performance counters"
20
68
  arg :counter, "Counter name"
@@ -22,10 +70,17 @@ opts :plot do
22
70
  opt :terminal, "Display plot on terminal", :default => ENV['DISPLAY'].nil?
23
71
  opt :start, "Start time", :type => :date, :short => 's'
24
72
  opt :end, "End time", :type => :date, :short => 'e'
73
+ summary <<-EOS
74
+
75
+ Example:
76
+ perf.plot cpu.usagemhz myvm myvm2 --start '20 minutes ago'
77
+
78
+ See perf.counters to determine which performance counters are available.
79
+ EOS
25
80
  end
26
81
 
27
82
  def plot counter_name, objs, opts
28
- err "The gnuplot gem is not installed" unless RVC::HAVE_GNUPLOT
83
+ require_gnuplot
29
84
  vim = single_connection objs
30
85
  pm = vim.serviceContent.perfManager
31
86
  group_key, counter_key, rollup_type = counter_name.split('.', 3)
@@ -35,20 +90,8 @@ def plot counter_name, objs, opts
35
90
  opts[:start] ||= opts[:end] - 1800
36
91
 
37
92
  err "end time is in the future" unless opts[:end] <= Time.now
38
- ago = now - opts[:start]
39
93
 
40
- if ago < 3600
41
- #puts "Using realtime interval, period = 20 seconds."
42
- interval_id = 20
43
- display_timefmt = DISPLAY_TIMEFMT[:realtime]
44
- else
45
- intervals = pm.historicalInterval
46
- interval = intervals.find { |x| now - x.length < opts[:start] }
47
- err "start time is too long ago" unless interval
48
- #puts "Using historical interval #{interval.name.inspect}, period = #{interval.samplingPeriod} seconds."
49
- interval_id = interval.samplingPeriod
50
- display_timefmt = DISPLAY_TIMEFMT[interval.key]
51
- end
94
+ interval_id, display_timefmt = find_interval pm, opts[:start]
52
95
 
53
96
  all_counters = Hash[pm.perfCounter.map { |x| [x.key, x] }]
54
97
 
@@ -59,9 +102,8 @@ def plot counter_name, objs, opts
59
102
  metric = metrics.find do |metric|
60
103
  counter = all_counters[metric.counterId]
61
104
  counter.groupInfo.key == group_key &&
62
- counter.nameInfo.key == counter_key &&
63
- counter.rollupType == rollup_type
64
- end or err "no such metric"
105
+ counter.nameInfo.key == counter_key
106
+ end or err "counter #{group_key}.#{counter_key} was not found in the #{interval_id}s interval"
65
107
  counter = all_counters[metric.counterId]
66
108
 
67
109
  specs = objs.map do |obj|
@@ -105,6 +147,10 @@ def retrieve_datasets pm, counter, specs
105
147
  results = pm.QueryPerf(:querySpec => specs)
106
148
  datasets = results.map do |result|
107
149
  times = result.sampleInfoCSV.split(',').select { |x| x['T'] }
150
+ if result.value.empty?
151
+ puts "No data for #{result.entity.name} #{counter.name}"
152
+ next
153
+ end
108
154
  data = result.value[0].value.split(',').map(&:to_i)
109
155
 
110
156
  if counter.unitInfo.key == 'percent'
@@ -123,7 +169,7 @@ def retrieve_datasets pm, counter, specs
123
169
  ds.using = '1:2'
124
170
  ds.title = result.entity.name
125
171
  end
126
- end
172
+ end.compact
127
173
  end
128
174
 
129
175
  def with_gnuplot persist
@@ -152,7 +198,7 @@ opts :watch do
152
198
  end
153
199
 
154
200
  def watch counter_name, objs, opts
155
- err "The gnuplot gem is not installed" unless RVC::HAVE_GNUPLOT
201
+ require_gnuplot
156
202
  with_gnuplot false do |gp|
157
203
  puts "Press Ctrl-C to stop."
158
204
  while true
@@ -181,6 +227,14 @@ def counters obj
181
227
  interval = nil
182
228
  end
183
229
 
230
+ active_intervals = pm.active_intervals
231
+ active_intervals_text = lambda do |level|
232
+ return '' unless level
233
+ xs = active_intervals[level]
234
+ return 'none' if xs.empty?
235
+ xs.map { |x| x.name.match(/Past (\w+)/)[1] } * ','
236
+ end
237
+
184
238
  metrics = pm.QueryAvailablePerfMetric(
185
239
  :entity => obj,
186
240
  :intervalId => interval)
@@ -188,12 +242,19 @@ def counters obj
188
242
  map { |id| pm.perfcounter_idhash[id] }
189
243
 
190
244
  groups = available_counters.group_by { |counter| counter.groupInfo }
245
+
246
+ table = Terminal::Table.new
247
+ table.add_row ["Name", "Description", "Unit", "Level", "Active Intervals"]
191
248
  groups.sort_by { |group,counters| group.key }.each do |group,counters|
192
- puts "#{group.label}:"
193
- counters.sort_by(&:pretty_name).each do |counter|
194
- puts " #{counter.pretty_name}: #{counter.nameInfo.label} (#{counter.unitInfo.label})"
249
+ table.add_separator
250
+ table.add_row [{ :value => group.label, :colspan => 5}]
251
+ table.add_separator
252
+ counters.sort_by(&:name).each do |counter|
253
+ table.add_row [counter.name, counter.nameInfo.label, counter.unitInfo.label,
254
+ counter.level, active_intervals_text[counter.level]]
195
255
  end
196
256
  end
257
+ puts(table)
197
258
  end
198
259
 
199
260
 
@@ -208,8 +269,7 @@ def counter counter_name, obj
208
269
  pm = vim.serviceContent.perfManager
209
270
  counter = pm.perfcounter_hash[counter_name] or err "no such counter #{counter_name.inspect}"
210
271
 
211
- intervals = pm.historicalInterval
212
- active_intervals = lambda { |level| intervals.select { |x| x.level >= level } }
272
+ active_intervals = pm.active_intervals
213
273
  active_intervals_text = lambda do |level|
214
274
  xs = active_intervals[level]
215
275
  xs.empty? ? 'none' : xs.map(&:name).map(&:inspect) * ', '
@@ -254,9 +314,15 @@ end
254
314
 
255
315
  def stats metrics, objs, opts
256
316
  metrics = metrics.split(",")
257
- obj = objs.first
258
- pm = obj._connection.serviceContent.perfManager
259
- interval = pm.provider_summary(obj).refreshRate
317
+
318
+ vim = single_connection objs
319
+ pm = vim.serviceContent.perfManager
320
+
321
+ metrics.each do |x|
322
+ err "no such metric #{x}" unless pm.perfcounter_hash.member? x
323
+ end
324
+
325
+ interval = pm.provider_summary(objs.first).refreshRate
260
326
  start_time = nil
261
327
  if interval == -1
262
328
  # Object does not support real time stats
@@ -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 :get do
22
24
  summary "Display the permissions of a managed entity"
23
25
  arg :obj, nil, :lookup => VIM::ManagedEntity, :multi => true
@@ -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 :create do
22
24
  summary "Create a resource pool"
23
25
  arg :name, "Name of the new resource pool."
@@ -18,8 +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 'rvc/vim'
22
+
21
23
  def cur_auth_mgr
22
- conn = $shell.fs.cur._connection
24
+ conn = shell.fs.cur._connection
23
25
  conn.serviceContent.authorizationManager
24
26
  end
25
27
 
@@ -18,6 +18,9 @@
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
+ VIM::VirtualMachine
23
+
21
24
  opts :create do
22
25
  summary "Snapshot a VM"
23
26
  arg :vm, nil, :lookup => VIM::VirtualMachine
@@ -71,11 +74,16 @@ end
71
74
 
72
75
 
73
76
  opts :remove do
74
- summary "Remove a snapshot"
75
- arg :snapshot, nil, :lookup => RVC::SnapshotFolder
77
+ summary "Remove snapshots"
78
+ arg :snapshots, nil, :multi => true, :lookup => RVC::SnapshotFolder
76
79
  opt :remove_children, "Whether to remove the snapshot's children too"
77
80
  end
78
81
 
79
- def remove snapshot, opts
80
- tasks [snapshot.find_tree.snapshot], :RemoveSnapshot, :removeChildren => opts[:remove_children]
82
+ def remove snapshots, opts
83
+ # Sort by path and use reverse_each to remove child snapshots first
84
+ snapshots.sort_by! {|s| s.rvc_path_str }
85
+
86
+ snapshots.reverse_each do |snapshot|
87
+ tasks [snapshot.find_tree.snapshot], :RemoveSnapshot, :removeChildren => opts[:remove_children]
88
+ end
81
89
  end
@@ -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
  #see vSphere Client: Administration -> vCenter Server Settings -> Statistics -> Statistics Intervals
22
24
 
23
25
  def stats_time secs
@@ -39,19 +41,19 @@ opts :list do
39
41
  end
40
42
 
41
43
  def list
42
- conn = single_connection [$shell.fs.cur]
43
- perfman = conn.serviceContent.perfManager
44
+ conn = lookup_single('~@')
45
+ pm = conn.serviceContent.perfManager
44
46
 
45
- columns = [" Name ", "Interval Duration", "Save For ", "Statistics Level"]
46
- format = columns.map {|s| "%-#{s.size}s"}.join(" | ")
47
- puts sprintf format, *columns
48
- puts columns.map {|s| "-" * s.size }.join("-+-")
47
+ table = Terminal::Table.new
48
+ table.add_row ["Name", "Enabled", "Interval Duration", "Save For", "Statistics Level"]
49
+ table.add_separator
49
50
 
50
- perfman.historicalInterval.each do |interval|
51
- puts sprintf format, "[#{interval.enabled ? 'x' : ' '}] #{interval.name}",
52
- stats_time(interval.samplingPeriod),
53
- stats_time(interval.length), interval.level.to_s
51
+ pm.historicalInterval.each do |interval|
52
+ table.add_row [interval.name, interval.enabled, stats_time(interval.samplingPeriod),
53
+ stats_time(interval.length), interval.level]
54
54
  end
55
+
56
+ puts table
55
57
  end
56
58
 
57
59
 
@@ -65,7 +67,7 @@ opts :update do
65
67
  end
66
68
 
67
69
  def update name, opts
68
- conn = single_connection [$shell.fs.cur]
70
+ conn = single_connection [shell.fs.cur]
69
71
  perfman = conn.serviceContent.perfManager
70
72
 
71
73
  interval = perfman.historicalInterval.select {|i| i.name == name or i.name == "Past #{name}" }.first
@@ -18,7 +18,9 @@
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 "terminal-table/import"
21
+ require 'rvc/vim'
22
+
23
+ require "terminal-table"
22
24
 
23
25
  opts :summarize do
24
26
  summary ""
@@ -440,13 +442,13 @@ opts :show_running_config do
440
442
  end
441
443
 
442
444
  def show_running_config vds
443
- MODULES['basic'].info vds
445
+ shell.cmds.basic.info vds
444
446
  portgroups = vds.children['portgroups']
445
447
  portgroups.rvc_link vds, 'portgroups'
446
448
  vds.children['portgroups'].children.each do |name, pg|
447
449
  pg.rvc_link portgroups, name
448
450
  puts '---'
449
- MODULES['basic'].info pg
451
+ shell.cmds.basic.info pg
450
452
  end
451
453
  end
452
454
 
@@ -461,13 +463,13 @@ def show_all_portgroups path
461
463
  paths = nil
462
464
  end
463
465
 
464
- vds = MODULES['find'].find_items nil, paths, ['vds']
466
+ vds = shell.cmds.find.find_items nil, paths, ['vds']
465
467
  pgs = []
466
468
  vds.each do |v|
467
469
  v.portgroup.each { |pg| pgs << pg}
468
470
  end
469
- RVC::MODULES['basic'].table pgs, { :field => ["vds_name", "name", "vlan"],
470
- :field_given => true }
471
+ shell.cmds.basic.table pgs, { :field => ["vds_name", "name", "vlan"],
472
+ :field_given => true }
471
473
  end
472
474
 
473
475
  opts :show_all_vds do
@@ -481,9 +483,9 @@ def show_all_vds path
481
483
  paths = nil
482
484
  end
483
485
 
484
- vds = MODULES['find'].find_items nil, paths, ['vds']
485
- RVC::MODULES['basic'].table vds, { :field => ['name', 'vlans', 'hosts'],
486
- :field_given => true }
486
+ vds = shell.cmds.find.find_items nil, paths, ['vds']
487
+ shell.cmds.basic.table vds, { :field => ['name', 'vlans', 'hosts'],
488
+ :field_given => true }
487
489
  end
488
490
 
489
491
  opts :show_all_ports do
@@ -571,7 +573,7 @@ def show_all_ports path
571
573
  rows.each { |r| r.delete_at(2) }
572
574
  end
573
575
 
574
- t = table(columns)
576
+ t = Terminal::Table.new(columns)
575
577
  rows.sort_by { |o| o[0] }.each { |o| t << o }
576
578
  puts t
577
579
  end
@@ -603,3 +605,58 @@ def abbrev_hostnames names
603
605
  }
604
606
  end
605
607
  end
608
+
609
+ opts :add_hosts do
610
+ summary "Add hosts to a vDS"
611
+ arg :vds, nil, :lookup => VIM::DistributedVirtualSwitch
612
+ arg :hosts, nil, :lookup => VIM::HostSystem, :multi => true
613
+ opt :vmnic, "Name of vmnic (multiple allowed)", :multi => true, :type => :string
614
+ end
615
+
616
+ def add_hosts vds, hosts, opts
617
+ pnicSpec = opts[:vmnic].map do |x|
618
+ VIM::DistributedVirtualSwitchHostMemberPnicSpec({:pnicDevice => x})
619
+ end
620
+ dvsConfig = VIM::DVSConfigSpec({
621
+ :configVersion => vds.config.configVersion,
622
+ :host => hosts.map do |host|
623
+ {
624
+ :operation => :add,
625
+ :host => host,
626
+ :backing => VIM::DistributedVirtualSwitchHostMemberPnicBacking({
627
+ :pnicSpec => pnicSpec
628
+ })
629
+ }
630
+ end
631
+ })
632
+ task = vds.ReconfigureDvs_Task(:spec => dvsConfig)
633
+ progress([task])
634
+ end
635
+
636
+ opts :create_vmknic do
637
+ summary "Create a vmknic on vDS on one or more hosts. Always uses DHCP"
638
+ arg :portgroup, nil, :lookup => VIM::Network
639
+ arg :host, nil, :lookup => VIM::HostSystem, :multi => true
640
+ end
641
+
642
+ def create_vmknic portgroup, hosts, opts
643
+ if !portgroup.is_a?(VIM::DistributedVirtualPortgroup)
644
+ err "Legacy switches not supported yet"
645
+ end
646
+ hosts.each do |host|
647
+ ns = host.configManager.networkSystem
648
+ vmknic_name = ns.AddVirtualNic(
649
+ :portgroup => "",
650
+ :nic => {
651
+ :ip => {
652
+ :dhcp => true
653
+ },
654
+ :distributedVirtualPort => VIM::DistributedVirtualSwitchPortConnection(
655
+ :portgroupKey => portgroup.key,
656
+ :switchUuid => portgroup.config.distributedVirtualSwitch.uuid,
657
+ )
658
+ }
659
+ )
660
+ puts "Host #{host.name}: Added vmknic #{vmknic_name}"
661
+ end
662
+ end