Class: Chef::Knife::BaseVsphereCommand

Inherits:
Chef::Knife show all
Defined in:
lib/chef/knife/BaseVsphereCommand.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.get_common_optionsObject



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 25

def self.get_common_options
	unless defined? $default
		$default = Hash.new
	end

	option :vsphere_user,
		:short => "-u USERNAME",
		:long => "--vsuser USERNAME",
		:description => "The username for vsphere"

	option :vsphere_pass,
		:short => "-p PASSWORD",
		:long => "--vspass PASSWORD",
		:description => "The password for vsphere"

	option :vsphere_host,
		:long => "--vshost HOST",
		:description => "The vsphere host"

	option :vsphere_dc,
		:short => "-d DATACENTER",
		:long => "--vsdc DATACENTER",
		:description => "The Datacenter for vsphere"

	option :vsphere_path,
		:long => "--vspath SOAP_PATH",
		:description => "The vsphere SOAP endpoint path"
	$default[:vsphere_path] = "/sdk"

	option :vsphere_port,
		:long => "--vsport PORT",
		:description => "The VI SDK port number to use"
	$default[:vsphere_port] = 443

	option :vshere_nossl,
		:long => "--vsnossl",
		:description => "Disable SSL connectivity"

	option :vsphere_insecure,
		:long => "--vsinsecure",
		:description => "Disable SSL certificate verification"

	option :folder,
		:short => "-f FOLDER",
		:long => "--folder FOLDER",
		:description => "The folder to get VMs from"
	$default[:folder] = ''
end

Instance Method Details

#choose_datastore(dstores, size) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 186

def choose_datastore(dstores,size)
  vmdk_size_kb = size.to_i * 1024 * 1024
  vmdk_size_B = size.to_i * 1024 * 1024 * 1024
             
  candidates = []
  dstores.each  do |store|
    avail = number_to_human_size(store.summary[:freeSpace])
    cap = number_to_human_size(store.summary[:capacity])                     
    puts "#{ui.color("Datastore", :cyan)}: #{store.name} (#{avail}(#{store.summary[:freeSpace]}) / #{cap})"     
                      
    # vm's can span multiple datastores, so instead of grabbing the first one
    # let's find the first datastore with the available space on a LUN the vm 
    # is already using, or use a specified LUN (if given)
                      
    
    if ( store.summary[:freeSpace] - vmdk_size_B ) > 0
      # also let's not use more than 90% of total space to save room for snapshots.
      cap_remains = 100 * ( (store.summary[:freeSpace].to_f - vmdk_size_B.to_f ) / store.summary[:capacity].to_f )
      if(cap_remains.to_i > 10)
        candidates.push(store)
      end 
    end
  end
  if candidates.length > 0
    vmdk_datastore = candidates[0]
  else
    puts "Insufficient space on all LUNs designated or assigned to the virtual machine. Please specify a new target."
    vmdk_datastore = nil
  end
  return vmdk_datastore
end

#fatal_exit(msg) ⇒ Object



265
266
267
268
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 265

def fatal_exit(msg)
	ui.fatal(msg)
	exit 1
end

#find_all_in_folder(folder, type) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 247

def find_all_in_folder(folder, type)
	if folder.instance_of?(RbVmomi::VIM::ClusterComputeResource)
		folder = folder.resourcePool
	end
	if folder.instance_of?(RbVmomi::VIM::ResourcePool)
		folder.resourcePool.grep(type)
	elsif folder.instance_of?(RbVmomi::VIM::Folder)
		folder.childEntity.grep(type)
	else
		puts "Unknown type #{folder.class}, not enumerating"
		nil
	end
end

#find_datastore(dsName) ⇒ Object



233
234
235
236
237
238
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 233

def find_datastore(dsName)
	dcname = get_config(:vsphere_dc)
	dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
	baseEntity = dc.datastore
	baseEntity.find { |f| f.info.name == dsName } or abort "no such datastore #{dsName}"
end

#find_datastores_regex(regex) ⇒ Object



219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 219

def find_datastores_regex(regex)
  stores = Array.new()
  puts "Looking for all datastores that match /#{regex}/"
  dcname = get_config(:vsphere_dc)
  dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
  baseEntity = dc.datastore
  baseEntity.each do |ds|
    if ds.name.match /#{regex}/
      stores.push ds
    end
  end
  return stores
end

#find_device(vm, deviceName) ⇒ Object



240
241
242
243
244
245
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 240

def find_device(vm,deviceName)
  vm.config.hardware.device.each do |device|
    return device if device.deviceInfo.label == deviceName
  end
  nil
end

#find_folder(folderName) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 139

def find_folder(folderName)
	dcname = get_config(:vsphere_dc)
	dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
	baseEntity = dc.vmFolder
	entityArray = folderName.split('/')
	entityArray.each do |entityArrItem|
		if entityArrItem != ''
			baseEntity = baseEntity.childEntity.grep(RbVmomi::VIM::Folder).find { |f| f.name == entityArrItem } or
           abort "no such folder #{folderName} while looking for #{entityArrItem}"
		end
	end
	baseEntity
end

#find_in_folder(folder, type, name) ⇒ Object



261
262
263
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 261

def find_in_folder(folder, type, name)
	folder.childEntity.grep(type).find { |o| o.name == name }
end

#find_network(networkName) ⇒ Object



153
154
155
156
157
158
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 153

def find_network(networkName)
	dcname = get_config(:vsphere_dc)
	dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
	baseEntity = dc.network
	baseEntity.find { |f| f.name == networkName } or abort "no such network #{networkName}"
end

#find_pool(poolName) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 160

def find_pool(poolName)
	dcname = get_config(:vsphere_dc)
	dc = config[:vim].serviceInstance.find_datacenter(dcname) or abort "datacenter not found"
	baseEntity = dc.hostFolder
	entityArray = poolName.split('/')
	entityArray.each do |entityArrItem|
		if entityArrItem != ''
			if baseEntity.is_a? RbVmomi::VIM::Folder
				baseEntity = baseEntity.childEntity.find { |f| f.name == entityArrItem } or
             abort "no such pool #{poolName} while looking for #{entityArrItem}"
			elsif baseEntity.is_a? RbVmomi::VIM::ClusterComputeResource
				baseEntity = baseEntity.resourcePool.resourcePool.find { |f| f.name == entityArrItem } or
             abort "no such pool #{poolName} while looking for #{entityArrItem}"
			elsif baseEntity.is_a? RbVmomi::VIM::ResourcePool
				baseEntity = baseEntity.resourcePool.find { |f| f.name == entityArrItem } or
             abort "no such pool #{poolName} while looking for #{entityArrItem}"
			else
				abort "Unexpected Object type encountered #{baseEntity.type} while finding resourcePool"
			end
		end
	end

     baseEntity = baseEntity.resourcePool if not baseEntity.is_a?(RbVmomi::VIM::ResourcePool) and baseEntity.respond_to?(:resourcePool)
     baseEntity
end

#get_config(key) ⇒ Object



74
75
76
77
78
79
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 74

def get_config(key)
	key = key.to_sym
	rval = config[key] || Chef::Config[:knife][key] || $default[key]
	Chef::Log.debug("value for config item #{key}: #{rval}")
	rval
end

#get_datacenterObject



135
136
137
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 135

def get_datacenter
   dc = config[:vim].serviceInstance.find_datacenter(get_config(:vsphere_dc)) or abort "datacenter not found"
end

#get_passwordObject



106
107
108
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 106

def get_password
  @password ||= ui.ask("Enter your password: ") { |q| q.echo = false }
end

#get_vim_connectionObject



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 81

def get_vim_connection

	conn_opts = {
		:host => get_config(:vsphere_host),
		:path => get_config(:vshere_path),
		:port => get_config(:vsphere_port),
		:use_ssl => !get_config(:vsphere_nossl),
		:user => get_config(:vsphere_user),
		:password => get_config(:vsphere_pass),
		:insecure => get_config(:vsphere_insecure)
	}
	
	# Grab the password from the command line
	# if tt is not in the config file
	if not conn_opts[:password]
                               conn_opts[:password] = get_password
                             end

	#    opt :debug, "Log SOAP messages", :short => 'd', :default => (ENV['RBVMOMI_DEBUG'] || false)

	vim = RbVmomi::VIM.connect conn_opts
	config[:vim] = vim
	return vim
end

#get_vm(vmname) ⇒ Object



110
111
112
113
114
115
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 110

def get_vm(vmname)
		          vim = get_vim_connection
		          baseFolder = find_folder(get_config(:folder));
  retval = traverse_folders_for_vm(baseFolder,vmname)
  return retval
end

#tcp_test_port(hostname, port) ⇒ Object



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 279

def tcp_test_port(hostname,port)
  tcp_socket = TCPSocket.new(hostname, port)
  readable = IO.select([tcp_socket], nil, nil, 5)
  if readable
    Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}") if port == 22
    true
  else
    false
  end
  rescue Errno::ETIMEDOUT
    false
  rescue Errno::EPERM
    false
  rescue Errno::ECONNREFUSED
    sleep 2
    false
  rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH
    sleep 2
    false
  ensure
    tcp_socket && tcp_socket.close
end

#tcp_test_port_vm(vm, port) ⇒ Object



270
271
272
273
274
275
276
277
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 270

def tcp_test_port_vm(vm,port)
  ip = vm.guest.ipAddress
  if ip.nil?
    sleep 2
    return false
  end
  tcp_test_port(ip, port)
end

#traverse_folders_for_vm(folder, vmname) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/chef/knife/BaseVsphereCommand.rb', line 117

def traverse_folders_for_vm(folder,vmname)
          # not sure why @vm is necessary, but it returns class Array
          # instead of class VirtualMachine without it... ugh
          @vm = nil
		           folders = find_all_in_folder(folder, RbVmomi::VIM::Folder)
		           folders.each do |child|
            traverse_folders_for_vm(child,vmname)
            vms = find_all_in_folder(folder,RbVmomi::VIM::VirtualMachine)
            vms.each do |vm|
              if vm.name == vmname
                @vm = vm
                return @vm
              end
            end
          end
          return @vm
end