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 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.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.3
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?
@@ -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
@@ -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 = {
@@ -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
- VMRC_URL = "https://github.com/downloads/vmware/rvc/#{VMRC_NAME}.#{VMRC_PKGVER}.tar.bz2"
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", "w")
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 "curl -L #{VMRC_URL} | tar -xj -C #{Dir.tmpdir}" or err("VMRC installation failed")
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
- segments:
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-03-28 00:00:00 -07:00
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
- hash: 27
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.4.2
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
@@ -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
@@ -1,6 +0,0 @@
1
- require 'test/unit'
2
- require 'rvc'
3
- require 'inventory_fixtures'
4
-
5
- class OptionParserTest < Test::Unit::TestCase
6
- end