Class: Chef::Knife::BaseVsphereCommand

Inherits:
Chef::Knife show all
Defined in:
lib/chef/knife/base_vsphere_command.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
73
74
75
76
77
78
79
80
81
# File 'lib/chef/knife/base_vsphere_command.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"

  option :proxy_host,
         :long => '--proxyhost PROXY_HOSTNAME',
         :description => 'Proxy hostname'

  option :proxy_port,
         :long => '--proxyport PROXY_PORT',
         :description => 'Proxy port'

  $default[:folder] = ''
end

Instance Method Details

#choose_datastore(dstores, size) ⇒ Object



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/chef/knife/base_vsphere_command.rb', line 203

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



280
281
282
283
# File 'lib/chef/knife/base_vsphere_command.rb', line 280

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

#find_all_in_folder(folder, type) ⇒ Object



262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/chef/knife/base_vsphere_command.rb', line 262

def find_all_in_folder(folder, type)
  if folder.instance_of?(RbVmomi::VIM::ClusterComputeResource) or folder.instance_of?(RbVmomi::VIM::ComputeResource)
    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



249
250
251
252
253
# File 'lib/chef/knife/base_vsphere_command.rb', line 249

def find_datastore(dsName)
  dc = get_datacenter
  baseEntity = dc.datastore
  baseEntity.find { |f| f.info.name == dsName } or abort "no such datastore #{dsName}"
end

#find_datastores_regex(regex) ⇒ Object



236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/chef/knife/base_vsphere_command.rb', line 236

def find_datastores_regex(regex)
  stores = Array.new()
  puts "Looking for all datastores that match /#{regex}/"
  dc = get_datacenter
  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



255
256
257
258
259
260
# File 'lib/chef/knife/base_vsphere_command.rb', line 255

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



159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/chef/knife/base_vsphere_command.rb', line 159

def find_folder(folderName)
  dc = get_datacenter
  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



276
277
278
# File 'lib/chef/knife/base_vsphere_command.rb', line 276

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

#find_network(networkName) ⇒ Object



172
173
174
175
176
# File 'lib/chef/knife/base_vsphere_command.rb', line 172

def find_network(networkName)
  dc = get_datacenter
  baseEntity = dc.network
  baseEntity.find { |f| f.name == networkName } or abort "no such network #{networkName}"
end

#find_pool(poolName) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/chef/knife/base_vsphere_command.rb', line 178

def find_pool(poolName)
  dc = get_datacenter
  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 or baseEntity.is_a? RbVmomi::VIM::ComputeResource
        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



83
84
85
86
87
88
# File 'lib/chef/knife/base_vsphere_command.rb', line 83

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



154
155
156
157
# File 'lib/chef/knife/base_vsphere_command.rb', line 154

def get_datacenter
  dcname = get_config(:vsphere_dc)
  traverse_folders_for_dc(config[:vim].rootFolder, dcname) or abort "datacenter not found"
end

#get_passwordObject



117
118
119
# File 'lib/chef/knife/base_vsphere_command.rb', line 117

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

#get_vim_connectionObject



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/chef/knife/base_vsphere_command.rb', line 90

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),
      :proxyHost => get_config(:proxy_host),
      :proxyPort => get_config(:proxy_port)
  }

  # 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



121
122
123
124
125
126
# File 'lib/chef/knife/base_vsphere_command.rb', line 121

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



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/chef/knife/base_vsphere_command.rb', line 294

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



285
286
287
288
289
290
291
292
# File 'lib/chef/knife/base_vsphere_command.rb', line 285

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_dc(folder, dcname) ⇒ Object



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

def traverse_folders_for_dc(folder, dcname)
  children = folder.children.find_all
  children.each do |child|
    if child.class == RbVmomi::VIM::Datacenter && child.name == dcname
      return child
    elsif child.class == RbVmomi::VIM::Folder
      dc = traverse_folders_for_dc(child, dcname)
      if dc then return dc end
    end
  end
  return false
end

#traverse_folders_for_vm(folder, vmname) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/chef/knife/base_vsphere_command.rb', line 128

def traverse_folders_for_vm(folder, vmname)
  children = folder.children.find_all
  children.each do |child|
    if child.class == RbVmomi::VIM::VirtualMachine && child.name == vmname
        return child
    elsif child.class == RbVmomi::VIM::Folder
      vm = traverse_folders_for_vm(child, vmname)
      if vm then return vm end
    end
  end
  return false
end