Class: Jupiter::Host

Inherits:
Object
  • Object
show all
Defined in:
lib/jupiter/host.rb

Defined Under Namespace

Classes: InvalidGBSizeError, InvalidVMStateError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Host

Returns a new instance of Host.



6
7
8
9
10
11
12
13
14
15
# File 'lib/jupiter/host.rb', line 6

def initialize(options)
  self.name       = options.fetch(:name)
  self.vmpath     = options.fetch(:vmpath)
  self.host       = options.fetch(:host)
  self.sshport    = options.fetch(:sshport)
  self.sshuser    = options.fetch(:sshuser)
  self.sshpass    = options.fetch(:sshpass)
  self.dcname     = options.fetch(:dcname)
  self.timestamp  = Time.new.strftime('%Y-%m-%d-%H%M').freeze
end

Instance Attribute Details

#dcnameObject

Returns the value of attribute dcname.



4
5
6
# File 'lib/jupiter/host.rb', line 4

def dcname
  @dcname
end

#hostObject

Returns the value of attribute host.



4
5
6
# File 'lib/jupiter/host.rb', line 4

def host
  @host
end

#nameObject

Returns the value of attribute name.



4
5
6
# File 'lib/jupiter/host.rb', line 4

def name
  @name
end

#sshpassObject

Returns the value of attribute sshpass.



4
5
6
# File 'lib/jupiter/host.rb', line 4

def sshpass
  @sshpass
end

#sshportObject

Returns the value of attribute sshport.



4
5
6
# File 'lib/jupiter/host.rb', line 4

def sshport
  @sshport
end

#sshuserObject

Returns the value of attribute sshuser.



4
5
6
# File 'lib/jupiter/host.rb', line 4

def sshuser
  @sshuser
end

#timestampObject

Returns the value of attribute timestamp.



4
5
6
# File 'lib/jupiter/host.rb', line 4

def timestamp
  @timestamp
end

#vmpathObject

Returns the value of attribute vmpath.



4
5
6
# File 'lib/jupiter/host.rb', line 4

def vmpath
  @vmpath
end

Instance Method Details

#answer_vm_question(vm) ⇒ Object



214
215
216
# File 'lib/jupiter/host.rb', line 214

def answer_vm_question(vm)
  result = guestvm(vm).AnswerVM(questionId: '_vmx1', answerChoice: '2')
end

#change_config_value(key, value) ⇒ Object



139
140
141
142
# File 'lib/jupiter/host.rb', line 139

def change_config_value(key, value)
  self[key] = value
  return self
end

#clone_vm(vm, newvm) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/jupiter/host.rb', line 102

def clone_vm(vm, newvm)
  snapshot_create(vm)
  sleep 5
  ssh.exec!("mkdir #{vmpath}/#{newvm}")
  ssh.exec!("cp -Rfv #{vmpath}/#{vm}/* #{vmpath}/#{newvm}")
  rename_cp_files(vm, newvm)
  update_vmx(vm, newvm)
  update_vmxf(vm, newvm)
  update_vmdk(vm, newvm)
  register_vm(newvm)
  close_ssh
  snapshots_remove(vm)
  consolidate_snapshots(vm)
  sleep 5
  power_on_vm(newvm)
  sleep 5
  answer_vm_question(newvm) # Needed to answer the "Was the VM moved" question that pops up.
  sleep 5
  power_on_vm(newvm)
end

#close_sshObject



32
33
34
35
36
# File 'lib/jupiter/host.rb', line 32

def close_ssh
  ssh.close
  @ssh = nil
  true
end

#consolidate_snapshots(vm) ⇒ Object



67
68
69
# File 'lib/jupiter/host.rb', line 67

def consolidate_snapshots(vm)
  result = guestvm(vm).ConsolidateVMDisks_Task
end

#extract_template(original_name, new_name) ⇒ Object



234
235
236
237
238
239
240
241
242
# File 'lib/jupiter/host.rb', line 234

def extract_template(original_name, new_name)
  file_exists = ssh.exec!("find #{vmpath}/#{original_name}.tar.gz").chomp
  if file_exists == "#{vmpath}/#{original_name}.tar.gz"
    ssh.exec!("cd #{vmpath} && tar -zxvf #{original_name}.tar.gz && rm #{original_name}.tar.gz")
  else
    close_ssh
    return false
  end
end

#flatten_hash(hash_to_flatten) ⇒ Object



153
154
155
# File 'lib/jupiter/host.rb', line 153

def flatten_hash(hash_to_flatten)
  hash_to_flatten.map{|k,v| "#{k} = \"#{v}\""}.join("\n")
end

#generate_mac_addressObject



161
162
163
# File 'lib/jupiter/host.rb', line 161

def generate_mac_address
  (1..6).map{"%0.2X"%rand(256)}.join(":")
end

#guest_ip(vm) ⇒ Object



51
52
53
# File 'lib/jupiter/host.rb', line 51

def guest_ip(vm)
  result = guestvm(vm).guest_ip
end

#guestvm(vmname) ⇒ Object



47
48
49
# File 'lib/jupiter/host.rb', line 47

def guestvm(vmname)
  vm  = vmhost.find_vm(vmname) or fail "\n\nVirtual Machine was not found. Although its files might exist, it may not be registered on the server. You can register the VM with the following command:\n\njupiter register --guest=#{vmname} --host=#{name}\n\n"
end

#power_cycle_vm(vm) ⇒ Object



88
89
90
91
92
# File 'lib/jupiter/host.rb', line 88

def power_cycle_vm(vm)
  guestvm(vm).PowerOffVM_Task
  sleep 5
  guestvm(vm).PowerOnVM_Task
end

#power_off_vm(vm) ⇒ Object



84
85
86
# File 'lib/jupiter/host.rb', line 84

def power_off_vm(vm)
  result = guestvm(vm).PowerOffVM_Task
end

#power_on_vm(vm) ⇒ Object



80
81
82
# File 'lib/jupiter/host.rb', line 80

def power_on_vm(vm)
  result = guestvm(vm).PowerOnVM_Task
end

#read_config_to_hash(file) ⇒ Object



144
145
146
147
# File 'lib/jupiter/host.rb', line 144

def read_config_to_hash(file)
  file_contents = ssh.exec!(%Q[cat #{file}])
  Hash[file_contents.split("\n").map { |line| line.split('=').map(&:strip).map { |value| value.gsub(/\A"|"\z/, '') } }]
end

#reboot_vm(vm) ⇒ Object



94
95
96
# File 'lib/jupiter/host.rb', line 94

def reboot_vm(vm)
  result = guestvm(vm).RebootGuest
end

#register_vm(vm) ⇒ Object



71
72
73
74
# File 'lib/jupiter/host.rb', line 71

def register_vm(vm)
  ssh.exec!("vim-cmd solo/registervm #{vmpath}/#{vm}/#{vm}.vmx")
  snapshots_remove(vm)
end

#rename_copied_template(original_name, new_name) ⇒ Object



244
245
246
247
248
249
250
251
# File 'lib/jupiter/host.rb', line 244

def rename_copied_template(original_name, new_name)
  if !new_name.nil? && !original_name.nil?
    ssh.exec!("mv #{vmpath}/#{original_name} #{vmpath}/#{new_name}")
    rename_cp_files(original_name, new_name)
  else
    return false
  end
end

#rename_cp_files(vm, newvm) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/jupiter/host.rb', line 123

def rename_cp_files(vm, newvm)
  old_files_path = "#{vmpath}/#{newvm}/#{vm}"
  new_files_path = "#{vmpath}/#{newvm}/#{newvm}"
  ssh.exec!("rm -f #{vmpath}/#{newvm}/vmware-*.log")
  ssh.exec!("rm -f #{old_files_path}.vmx~")
  ssh.exec!("rm -f #{old_files_path}.vmsd")
  ssh.exec!("rm -f #{old_files_path}-*.vmsn")
  ssh.exec!("rm -f #{old_files_path}-0000*.vmdk")
  ssh.exec!("mv #{old_files_path}-aux.xml #{new_files_path}-aux.xml")
  ssh.exec!("mv #{old_files_path}-flat.vmdk #{new_files_path}-flat.vmdk")
  ssh.exec!("mv #{old_files_path}.nvram #{new_files_path}.nvram")
  ssh.exec!("mv #{old_files_path}.vmdk #{new_files_path}.vmdk")
  ssh.exec!("mv #{old_files_path}.vmx #{new_files_path}.vmx")
  ssh.exec!("mv #{old_files_path}.vmxf #{new_files_path}.vmxf")
end

#resize_vmdk(vm, size_in_GB) ⇒ Object

Raises:



205
206
207
208
209
210
211
212
# File 'lib/jupiter/host.rb', line 205

def resize_vmdk(vm, size_in_GB)
  size_in_GB.tr!('^.0-9', '')
  raise InvalidGBSizeError.new("You can only increase the size of the drive, not reduce it.") if vmdk_size(vm).to_f > size_in_GB.to_f
  raise InvalidVMStateError.new("#{vm} must be shutdown before the drive can be resized.") if vm_state(vm) == 'running'
  result = ssh.exec!(%Q[vmkfstools -X #{size_in_GB}G #{vmpath}/#{vm}/#{vm}.vmdk])
  close_ssh
  return result
end

#server_uptimeObject



17
18
19
20
# File 'lib/jupiter/host.rb', line 17

def server_uptime
  puts ssh.exec!("uptime")
  close_ssh
end

#server_vm_listObject



22
23
24
25
26
# File 'lib/jupiter/host.rb', line 22

def server_vm_list
  vm_list = ssh.exec!("ls #{vmpath}").to_s
  close_ssh
  vm_list.split("\n")
end

#setup_template(original_name, new_name) ⇒ Object



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/jupiter/host.rb', line 218

def setup_template(original_name, new_name)
  extract_template(original_name, new_name)
  rename_copied_template(original_name, new_name)
  update_vmx(original_name, new_name)
  update_vmxf(original_name, new_name)
  update_vmdk(original_name, new_name)
  register_vm(new_name)
  close_ssh
  sleep 5
  power_on_vm(new_name)
  sleep 5
  answer_vm_question(new_name) # Needed to answer the "Was the VM moved" question that pops up.
  sleep 5
  power_on_vm(new_name)
end

#shutdown_vm(vm) ⇒ Object



98
99
100
# File 'lib/jupiter/host.rb', line 98

def shutdown_vm(vm)
  result = guestvm(vm).ShutdownGuest
end

#snapshot_create(vm) ⇒ Object



59
60
61
# File 'lib/jupiter/host.rb', line 59

def snapshot_create(vm)
  result = guestvm(vm).CreateSnapshot_Task(name: "snapshot_#{timestamp}", memory: false, quiesce: true)
end

#snapshots_remove(vm) ⇒ Object



63
64
65
# File 'lib/jupiter/host.rb', line 63

def snapshots_remove(vm)
  result = guestvm(vm).RemoveAllSnapshots_Task
end

#sshObject



28
29
30
# File 'lib/jupiter/host.rb', line 28

def ssh
  @ssh ||= Net::SSH.start(host, sshuser, password: sshpass, port: sshport)
end

#unregister_vm(vm) ⇒ Object



76
77
78
# File 'lib/jupiter/host.rb', line 76

def unregister_vm(vm)
  ssh.exec!("vim-cmd vmsvc/unregister #{vmpath}/#{vm}/#{vm}.vmx")
end

#update_vmdk(vm, newvm) ⇒ Object



189
190
191
192
193
194
195
# File 'lib/jupiter/host.rb', line 189

def update_vmdk(vm, newvm)
  file_with_path = "#{vmpath}/#{newvm}/#{newvm}.vmdk"
  file_contents = ssh.exec!(%Q[cat #{file_with_path}])
  file_contents[vm]= newvm
  write_to_file(file_contents, file_with_path)
  return true
end

#update_vmx(vm, newvm) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/jupiter/host.rb', line 165

def update_vmx(vm, newvm)
  vmx_hash = read_config_to_hash("#{vmpath}/#{newvm}/#{newvm}.vmx")
  vmx_hash['ethernet0.generatedAddress'] = generate_mac_address
  vmx_hash['uuid.bios'] = uuid(newvm)
  vmx_hash['uuid.location'] = uuid(newvm)
  vmx_hash['displayName'] = newvm
  vmx_hash['nvram'] = "#{newvm}.nvram"
  vmx_hash['extendedConfigFile'] = "#{newvm}.vmxf"
  vmx_hash['scsi0:0.fileName'] = "#{newvm}.vmdk"
  swap_derived_name = vmx_hash['sched.swap.derivedName']
  swap_derived_name["#{vm}/#{vm}"]= "#{newvm}/#{newvm}"
  vmx_hash['sched.swap.derivedName'] = swap_derived_name
  write_to_file(flatten_hash(vmx_hash), "#{vmpath}/#{newvm}/#{newvm}.vmx")
  return true
end

#update_vmxf(vm, newvm) ⇒ Object



181
182
183
184
185
186
187
# File 'lib/jupiter/host.rb', line 181

def update_vmxf(vm, newvm)
  file_with_path = "#{vmpath}/#{newvm}/#{newvm}.vmxf"
  newuuid = uuid(newvm)
  file_contents = "<?xml version=\"1.0\"?>\n<Foundry>\n<VM>\n<VMId type=\"string\">#{newuuid}</VMId>\n<ClientMetaData>\n<clientMetaDataAttributes/>\n<HistoryEventList/></ClientMetaData>\n<vmxPathName type=\"string\">#{newvm}.vmx</vmxPathName></VM></Foundry>"
  write_to_file(file_contents, file_with_path)
  return true
end

#uuid(newvm) ⇒ Object



149
150
151
# File 'lib/jupiter/host.rb', line 149

def uuid(newvm)
  @uuid ||= Jupiter::UUID.new.generate(newvm)
end

#vm_state(vm) ⇒ Object



55
56
57
# File 'lib/jupiter/host.rb', line 55

def vm_state(vm)
  result = guestvm(vm).guest.guestState
end

#vmdk_size(vm) ⇒ Object



197
198
199
200
201
202
203
# File 'lib/jupiter/host.rb', line 197

def vmdk_size(vm)
  file_with_path = "#{vmpath}/#{vm}/#{vm}.vmdk"
  vmdk_contents = ssh.exec!(%Q[cat #{file_with_path}])
  close_ssh
  vmfs_sectors = vmdk_contents[/\RW(.*?)VMFS/,1]
  gb_size = ((vmfs_sectors.to_f * 512) / (1024 * 1024 * 1024))
end

#vmhostObject



38
39
40
41
42
43
44
45
# File 'lib/jupiter/host.rb', line 38

def vmhost
  if /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.match(host)
    vim = RbVmomi::VIM.connect host: host, user: sshuser, password: sshpass, insecure: true
    dc  = vim.serviceInstance.find_datacenter(dcname) or fail "datacenter not found"
  else
    return false
  end
end

#write_to_file(file_content, full_path_to_file) ⇒ Object



157
158
159
# File 'lib/jupiter/host.rb', line 157

def write_to_file(file_content, full_path_to_file)
  ssh.exec!(%Q[echo '#{file_content}' > #{full_path_to_file}])
end