Class: OpenNebula::VirtualMachine
- Inherits:
-
Object
- Object
- OpenNebula::VirtualMachine
- Defined in:
- service/objects/vm.rb
Overview
Extensions for OpenNebula::VirtualMachine class
Defined Under Namespace
Classes: ShowbackError
Constant Summary collapse
- SCHEDULABLE_ACTIONS =
Actions supported by OpenNebula scheduler
%w( terminate terminate-hard hold release stop suspend resume reboot reboot-hard poweroff poweroff-hard undeploy undeploy-hard snapshot-create )
- CONF_KEYS =
VM Template keys updatable(and rewritable) by #updateconf
Set[ "INPUT", "RAW", "OS", "FEATURES", "GRAPHICS", "CONTEXT" ]
Instance Attribute Summary collapse
-
#vim_vm ⇒ Object
readonly
Returns the value of attribute vim_vm.
Instance Method Summary collapse
-
#at_vcenter_ds?(ds_name) ⇒ Boolean
Checks if vm is on given vCenter Datastore.
-
#calculate_showback(stime_req, etime_req, _group_by_day = false) ⇒ Hash
Calculates VMs Showback.
-
#conf ⇒ Object
Returns VM conf(template parts rewrittable by #updateconf).
- #DELETE File.join('/var/lib/one/sunstone_vnc_tokens/', "one-#{id}") ⇒ Object
-
#drives ⇒ Array<Hash>
List VM Drives.
-
#generate_schedule_str(id, action, time) ⇒ Object
Generates template for OpenNebula scheduler record.
-
#getResourcesAllocationLimits ⇒ Hash | String
Gets resources allocation limits from vCenter node.
- #got_disk_snapshots? ⇒ Boolean
-
#got_snapshots? ⇒ Boolean
(also: #got_snapshot?)
Gives info about snapshots availability.
-
#host ⇒ Array<String> | nil
Returns host id and name, where VM has been deployed.
-
#hot_resize(spec = {}) ⇒ Boolean | String
Resizes VM without powering off the VM.
-
#hotAddEnabled? ⇒ Hash | String
Checks if resources hot add enabled.
-
#hotResourcesControlConf(spec = { :cpu => true, :ram => true }) ⇒ true | String
Sets resources hot add settings.
-
#initialize(xml, client) ⇒ VirtualMachine
constructor
initialize method, watchout updates in main code branch.
-
#lcm_state! ⇒ Object
Returns actual lcm state without calling info! method.
-
#lcm_state_str! ⇒ Object
Returns actual lcm state as string without calling info! method.
-
#list_disk_snapshots ⇒ Hash
Returns all available snapshots in Hash form(DISK_ID => Array<Hash<Snapshot>>).
-
#list_snapshots ⇒ Array<Hash>, ...
Returns all available snapshots.
-
#passwd(password) ⇒ Object
Changes VM password in Context(must be changing on VM immediately).
-
#schedule(action, time, _periodic = nil) ⇒ Object
Adds actions to OpenNebula internal scheduler, like –schedule in 'onevm' cli utility.
-
#schedule_actions ⇒ Array
Returns allowed actions to schedule.
-
#scheduler ⇒ NilClass | Hash | Array
Lists actions scheduled in OpenNebula.
-
#setResourcesAllocationLimits(spec) ⇒ NilClass | String, String | Array(backtrace)
Sets resources allocation limits at vCenter node.
-
#snapshot_create(name = "") ⇒ Object
Create snapshot overload, brings restriction and quota check.
-
#snapshot_create_original ⇒ Object
Original OpenNebula#VirtualMachine.snapshot_create method.
- #start_vmrc ⇒ Object
-
#start_vnc ⇒ Object
Generates VNC proxy token file.
-
#state! ⇒ Object
Returns actual state without calling info! method.
-
#state_str! ⇒ Object
Returns actual state as string without calling info! method.
-
#stop_vnc ⇒ Object
Deletes VNC proxy token file.
-
#traffic_records ⇒ Hash
List TrafficRecords.
-
#uid(info = true) ⇒ Integer
Returns owner user ID.
-
#uname(info = true, from_pool = false) ⇒ String
Returns owner user name.
-
#unschedule(id) ⇒ Object
Unschedules given action by ID.
-
#updateconf_safe(new_conf) ⇒ Object
Safe updateconf method - doesn't delete ANY keys.
-
#vcenter_datastore_name ⇒ String
Gets the datastore, where VM allocated is.
-
#vcenter_get_vm(force = false) ⇒ RbVmomi::VIM::VirtualMachine
Generates RbVmomi::VIM::VirtualMachine object with inited connection and ref.
-
#vcenter_get_vm_ds ⇒ String
Gets the datastore, where VM allocated is.
-
#vcenter_powerState ⇒ String
Returns VM power state on vCenter.
-
#wait_for_state(st = 3, lcm_s = 3) ⇒ Boolean
Waits until VM will have the given state.
Constructor Details
#initialize(xml, client) ⇒ VirtualMachine
initialize method, watchout updates in main code branch
38 39 40 41 42 43 |
# File 'service/objects/vm.rb', line 38 def initialize(xml, client) @vim_vm = nil LockableExt.make_lockable(self, VM_METHODS) super(xml, client) end |
Instance Attribute Details
#vim_vm ⇒ Object (readonly)
Returns the value of attribute vim_vm.
7 8 9 |
# File 'service/objects/vm.rb', line 7 def vim_vm @vim_vm end |
Instance Method Details
#at_vcenter_ds?(ds_name) ⇒ Boolean
Checks if vm is on given vCenter Datastore
220 221 222 |
# File 'service/objects/vm.rb', line 220 def at_vcenter_ds? ds_name vcenter_datastore_name == ds_name end |
#calculate_showback(stime_req, etime_req, _group_by_day = false) ⇒ Hash
Calculates VMs Showback
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'service/objects/vm.rb', line 391 def calculate_showback stime_req, etime_req, _group_by_day = false raise ShowbackError, ["Wrong Time-period given", stime_req, etime_req] if stime_req >= etime_req info! stime, etime = stime_req, etime_req raise ShowbackError, ["VM didn't exist in given time-period", etime, self['/VM/STIME'].to_i] if self['/VM/STIME'].to_i > etime stime = self['/VM/STIME'].to_i if self['/VM/STIME'].to_i > stime etime = self['/VM/ETIME'].to_i if self['/VM/ETIME'].to_i < etime && self['/VM/ETIME'].to_i != 0 bp = self['//BILLING_PERIOD'] if bp.nil? || bp == 'PAYG' then billing = Billing.new self, stime, etime billing.make_bill billing.receipt return { id: id, name: name, showback: billing.bill, TOTAL: billing.total } elsif bp.include? 'PRE' then curr = self['/VM/STIME'].to_i period = bp.split('_')[1].to_i delta = period * 86400 total = 0 while curr < etime do if (stime..etime).include? curr then b = Billing.new self, curr, curr + delta b.make_bill b.receipt total += b.total end curr += delta end reduce_factor = 1 reduce_factors = IONe::Settings['PRE_PAID_REDUCE_FACTOR'].keys_to_i!.sort.to_h reduce_factors.each do | period_key, factor | if period >= period_key then reduce_factor = factor else break end end reduce_factor = reduce_factor.to_f return { id: id, name: name, total_billed: total, reduce_factor: reduce_factor, TOTAL: total * reduce_factor } else raise ShowbackError, ["Unknown BILLING_PERIOD!", bp] end end |
#conf ⇒ Object
Returns VM conf(template parts rewrittable by #updateconf)
589 590 591 592 593 594 |
# File 'service/objects/vm.rb', line 589 def conf info! to_hash['VM']['TEMPLATE'].select do | key | CONF_KEYS === key end end |
#DELETE File.join('/var/lib/one/sunstone_vnc_tokens/', "one-#{id}") ⇒ Object
579 |
# File 'service/objects/vm.rb', line 579 File.delete(File.join('/var/lib/one/sunstone_vnc_tokens/', "one-#{id}")) |
#drives ⇒ Array<Hash>
List VM Drives
485 486 487 488 |
# File 'service/objects/vm.rb', line 485 def drives r = to_hash!['VM']['TEMPLATE']['DISK'] r.class == Array ? r : [r] end |
#generate_schedule_str(id, action, time) ⇒ Object
Generates template for OpenNebula scheduler record
46 47 48 49 50 51 |
# File 'service/objects/vm.rb', line 46 def generate_schedule_str id, action, time "\nSCHED_ACTION=[\n" + " ACTION=\"#{action}\",\n" + " ID=\"#{id}\",\n" + " TIME=\"#{time}\" ]" end |
#getResourcesAllocationLimits ⇒ Hash | String
Method searches VM by it's default name: one-(id)-(name), if target vm got another name, you should provide it
Gets resources allocation limits from vCenter node
303 304 305 306 307 308 309 310 311 |
# File 'service/objects/vm.rb', line 303 def getResourcesAllocationLimits begin vm = vcenter_get_vm true vm_disk = vm.disks.first { cpu: vm.config.cpuAllocation.limit, ram: vm.config.memoryAllocation.limit, iops: vm_disk.storageIOAllocation.limit } rescue => e "Unexpected error, cannot handle it: #{e.}" end end |
#got_disk_snapshots? ⇒ Boolean
342 343 344 345 |
# File 'service/objects/vm.rb', line 342 def got_disk_snapshots? self.info! !self.to_hash['VM']['SNAPSHOTS'].nil? end |
#got_snapshots? ⇒ Boolean Also known as: got_snapshot?
Gives info about snapshots availability
336 337 338 339 |
# File 'service/objects/vm.rb', line 336 def got_snapshots? self.info! !self.to_hash['VM']['TEMPLATE']['SNAPSHOT'].nil? end |
#host ⇒ Array<String> | nil
Returns host id and name, where VM has been deployed
205 206 207 208 209 210 211 |
# File 'service/objects/vm.rb', line 205 def host history = to_hash!['VM']["HISTORY_RECORDS"]['HISTORY'] # Searching hostname at VM allocation history history = history.last if history.class == Array # If history consists of 2 or more lines - returns last return history['HID'], history['HOSTNAME'] rescue return nil end |
#hot_resize(spec = {}) ⇒ Boolean | String
Method returns true if resize action ended correct, false if VM not support hot reconfiguring
Resizes VM without powering off the VM
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'service/objects/vm.rb', line 236 def hot_resize spec = {} return false if !self.hotAddEnabled? begin vm = vcenter_get_vm query = { :numCPUs => spec[:cpu], :memoryMB => spec[:ram] } vm.ReconfigVM_Task(:spec => query).wait_for_completion return true rescue => e return "Reconfigure Error:#{e.}" end end |
#hotAddEnabled? ⇒ Hash | String
Method searches VM by it's default name: one-(id)-(name), if target vm got another name, you should provide it
Checks if resources hot add enabled
255 256 257 258 259 260 261 262 263 264 |
# File 'service/objects/vm.rb', line 255 def hotAddEnabled? begin vm = vcenter_get_vm return { :cpu => vm.config.cpuHotAddEnabled, :ram => vm.config.memoryHotAddEnabled } rescue => e return "Unexpected error, cannot handle it: #{e.}" end end |
#hotResourcesControlConf(spec = { :cpu => true, :ram => true }) ⇒ true | String
Sets resources hot add settings
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'service/objects/vm.rb', line 271 def hotResourcesControlConf spec = { :cpu => true, :ram => true } begin vm = vcenter_get_vm query = { :cpuHotAddEnabled => spec[:cpu], :memoryHotAddEnabled => spec[:ram] } state = true begin LOG_DEBUG 'Powering VM Off' LOG_DEBUG vm.PowerOffVM_Task.wait_for_completion rescue state = false end LOG_DEBUG 'Reconfiguring VM' LOG_DEBUG vm.ReconfigVM_Task(:spec => query).wait_for_completion begin LOG_DEBUG 'Powering VM On' LOG_DEBUG vm.PowerOnVM_Task.wait_for_completion rescue nil end if state rescue => e "Unexpected error, cannot handle it: #{e.}" end end |
#lcm_state! ⇒ Object
Returns actual lcm state without calling info! method
372 373 374 |
# File 'service/objects/vm.rb', line 372 def lcm_state! self.info! || self.lcm_state end |
#lcm_state_str! ⇒ Object
Returns actual lcm state as string without calling info! method
382 383 384 |
# File 'service/objects/vm.rb', line 382 def lcm_state_str! self.info! || self.lcm_state_str end |
#list_disk_snapshots ⇒ Hash
Returns all available snapshots in Hash form(DISK_ID => Array<Hash<Snapshot>>)
356 357 358 359 360 361 362 363 364 |
# File 'service/objects/vm.rb', line 356 def list_disk_snapshots snaps = to_hash!['VM']['SNAPSHOTS'] return {} if snaps.nil? (snaps.class == Array ? snaps : [snaps]).inject({}) do | r, snap | r[snap['DISK_ID']] = snap['SNAPSHOT'].class == Array ? snap['SNAPSHOT'] : [snap['SNAPSHOT']] r end end |
#list_snapshots ⇒ Array<Hash>, ...
Returns all available snapshots
349 350 351 352 |
# File 'service/objects/vm.rb', line 349 def list_snapshots out = self.to_hash!['VM']['TEMPLATE']['SNAPSHOT'] out.class == Array ? out : [out] end |
#passwd(password) ⇒ Object
Changes VM password in Context(must be changing on VM immediately)
584 585 586 |
# File 'service/objects/vm.rb', line 584 def passwd password updateconf_safe({ CONTEXT: { PASSWORD: password } }) end |
#schedule(action, time, _periodic = nil) ⇒ Object
Adds actions to OpenNebula internal scheduler, like –schedule in 'onevm' cli utility
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'service/objects/vm.rb', line 64 def schedule action, time, _periodic = nil return 'Unsupported action' if !SCHEDULABLE_ACTIONS.include? action self.info! id = begin ids = self.to_hash['VM']['USER_TEMPLATE']['SCHED_ACTION'] if ids.class == Array then ids.last['ID'].to_i + 1 elsif ids.class == Hash then ids['ID'].to_i + 1 elsif ids.class == NilClass then ids.to_i else raise end rescue 0 end # str_periodic = '' self.update(self.user_template_str << generate_schedule_str(id, action, time)) end |
#schedule_actions ⇒ Array
Returns allowed actions to schedule
55 56 57 |
# File 'service/objects/vm.rb', line 55 def schedule_actions SCHEDULABLE_ACTIONS end |
#scheduler ⇒ NilClass | Hash | Array
Lists actions scheduled in OpenNebula
114 115 116 117 |
# File 'service/objects/vm.rb', line 114 def scheduler self.info! self.to_hash['VM']['USER_TEMPLATE']['SCHED_ACTION'] end |
#setResourcesAllocationLimits(spec) ⇒ NilClass | String, String | Array(backtrace)
Attention!!! VM will be rebooted at the process
Valid units are: CPU - MHz, RAM - MB
Method searches VM by it's default name: one-(id)-(name), if target vm got another name, you should provide it
Sets resources allocation limits at vCenter node
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'service/objects/vm.rb', line 150 def setResourcesAllocationLimits spec return nil, 'Unsupported query' if self['//IMPORTED'] == 'YES' return nil, 'Nothing to do' if spec.empty? query, vm = {}, vcenter_get_vm disk = vm.disks.first query[:cpuAllocation] = { :limit => spec[:cpu].to_i, :reservation => 0 } if !spec[:cpu].nil? query[:memoryAllocation] = { :limit => spec[:ram].to_i } if !spec[:ram].nil? if !spec[:iops].nil? then disk.storageIOAllocation.limit = spec[:iops].to_i disk.backing.sharing = nil query[:deviceChange] = [{ :device => disk, :operation => :edit }] end return nil, 'Nothing to do' if query.empty? vm.ReconfigVM_Task(:spec => query).wait_for_completion return nil, 'Success' rescue => e return "Reconfigure Error:#{e.}", e.backtrace end |
#snapshot_create(name = "") ⇒ Object
Create snapshot overload, brings restriction and quota check
458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
# File 'service/objects/vm.rb', line 458 def snapshot_create name = "" info! if self['/VM/USER_TEMPLATE/SNAPSHOTS_ALLOWED'] != 'TRUE' && !IONe::Settings['SNAPSHOTS_ALLOWED_DEFAULT'] then return OpenNebula::Error.new("Snapshots aren't allowed for this VM. Set SNAPSHOTS_ALLOWED attribute to TRUE") end snapshots_quota = self['/VM/USER_TEMPLATE/SNAPSHOTS_QUOTA'] if !snapshots_quota.nil? and list_snapshots.length >= snapshots_quota.to_i then return OpenNebula::Error.new("Unable to create a snapshot, snapshots quota exceed") end snapshot_create_original name end |
#snapshot_create_original ⇒ Object
Original OpenNebula#VirtualMachine.snapshot_create method
456 |
# File 'service/objects/vm.rb', line 456 alias :snapshot_create_original :snapshot_create |
#start_vmrc ⇒ Object
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
# File 'service/objects/vm.rb', line 500 def start_vmrc r = info! return { error: "No access to VM" } if OpenNebula.is_error? r unless [state, lcm_state] == [3, 3] then return { error: "VM isn't running" } end unless self['USER_TEMPLATE/HYPERVISOR'] == 'vcenter' then return { error: "VM isn't vCenter VM" } end unless self['MONITORING/VCENTER_ESX_HOST'] then return { error: "Can't determine ESX host from monitoring, try again later"} end vcenter_get_vm ticket = @vim_vm.AcquireTicket(:ticketType => 'webmks') begin f = File.open(File.join('/var/lib/one/sunstone_vmrc_tokens/', ticket.ticket.sanitize), 'w') f.write("https://#{ticket.host}:#{ticket.port}") f.close rescue return { error: "Cannot create VNC proxy token" } end return { ticket: ticket.ticket } end |
#start_vnc ⇒ Object
Generates VNC proxy token file
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 |
# File 'service/objects/vm.rb', line 532 def start_vnc r = info! return { error: "No access to VM" } if OpenNebula.is_error? r if self['TEMPLATE/GRAPHICS/TYPE'].nil? || !(["vnc", "spice"].include?(self['TEMPLATE/GRAPHICS/TYPE'].downcase)) return { error: "VM has no VNC configured" } end # Proxy data host = self['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME'] vnc_port = self['TEMPLATE/GRAPHICS/PORT'] # vnc_pw = self['TEMPLATE/GRAPHICS/PASSWD'] # If it is a vCenter VM if self['USER_TEMPLATE/HYPERVISOR'] == "vcenter" if self['MONITORING/VCENTER_ESX_HOST'] host = self['MONITORING/VCENTER_ESX_HOST'] else return { error: "Could not determine the vCenter ESX host where the VM is running. Wait till the VCENTER_ESX_HOST attribute is retrieved once the host has been monitored" } end end # Generate token random_str: host:port random_str = rand(36**20).to_s(36) # random string a-z0-9 length 20 token = "#{random_str}: #{host}:#{vnc_port}" token_file = "one-#{self['ID']}" # Create token file begin f = File.open(File.join('/var/lib/one/sunstone_vnc_tokens/', token_file), 'w') f.write(token) f.close rescue return { error: "Cannot create VNC proxy token" } end return { :token => random_str, :vm_name => self['NAME'] } end |
#state! ⇒ Object
Returns actual state without calling info! method
367 368 369 |
# File 'service/objects/vm.rb', line 367 def state! self.info! || self.state end |
#state_str! ⇒ Object
Returns actual state as string without calling info! method
377 378 379 |
# File 'service/objects/vm.rb', line 377 def state_str! self.info! || self.state_str end |
#stop_vnc ⇒ Object
Deletes VNC proxy token file
578 579 580 |
# File 'service/objects/vm.rb', line 578 def stop_vnc File.delete(File.join('/var/lib/one/sunstone_vnc_tokens/', "one-#{id}")) end |
#traffic_records ⇒ Hash
List TrafficRecords
492 493 494 495 496 497 498 |
# File 'service/objects/vm.rb', line 492 def traffic_records info! { records: TrafficRecords.new(id).records, monitoring: monitoring(['NETTX', 'NETRX']) } end |
#uid(info = true) ⇒ Integer
Returns owner user ID
318 319 320 321 |
# File 'service/objects/vm.rb', line 318 def uid info = true self.info! if info self['UID'].to_i end |
#uname(info = true, from_pool = false) ⇒ String
Returns owner user name
327 328 329 330 331 332 |
# File 'service/objects/vm.rb', line 327 def uname info = true, from_pool = false self.info! if info return @xml[0].children[3].text.to_i unless from_pool @xml.children[3].text end |
#unschedule(id) ⇒ Object
Not working, if action is already initialized
Unschedules given action by ID
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'service/objects/vm.rb', line 91 def unschedule id self.info! schedule_data, object = self.to_hash['VM']['USER_TEMPLATE']['SCHED_ACTION'], nil if schedule_data.class == Array then schedule_data.map do | el | object = el if el['ID'] == id.to_s end elsif schedule_data.class == Hash then return 'none' if schedule_data['ID'] != id.to_s object = schedule_data else return 'none' end action, time = object['ACTION'], object['TIME'] template = self.user_template_str template.slice!(generate_schedule_str(id, action, time)) self.update(template) end |
#updateconf_safe(new_conf) ⇒ Object
Safe updateconf method - doesn't delete ANY keys. Merges new conf with actual conf
605 606 607 608 609 610 |
# File 'service/objects/vm.rb', line 605 def updateconf_safe new_conf curr_conf = conf updateconf( curr_conf.deep_merge(new_conf.to_s!).to_one_template ) end |
#vcenter_datastore_name ⇒ String
Gets the datastore, where VM allocated is
226 227 228 |
# File 'service/objects/vm.rb', line 226 def vcenter_datastore_name vcenter_get_vm.datastore.first.name end |
#vcenter_get_vm(force = false) ⇒ RbVmomi::VIM::VirtualMachine
Generates RbVmomi::VIM::VirtualMachine object with inited connection and ref
191 192 193 194 195 196 197 198 |
# File 'service/objects/vm.rb', line 191 def vcenter_get_vm force = false return @vim_vm if @vim_vm && !force info! h = Host.new_with_id(host.first, @client) @vim_vm = RbVmomi::VIM::VirtualMachine.new(h.vim, deploy_id.split('_').first) end |
#vcenter_get_vm_ds ⇒ String
Gets the datastore, where VM allocated is
215 216 217 |
# File 'service/objects/vm.rb', line 215 def vcenter_get_vm_ds return vcenter_get_vm.datastore.first end |
#vcenter_powerState ⇒ String
Returns VM power state on vCenter
182 183 184 185 186 187 |
# File 'service/objects/vm.rb', line 182 def vcenter_powerState vm = vcenter_get_vm vm.summary.runtime.powerState rescue => e "Unexpected error, cannot handle it: #{e.}" end |
#wait_for_state(st = 3, lcm_s = 3) ⇒ Boolean
Waits until VM will have the given state
123 124 125 126 127 128 129 130 131 132 |
# File 'service/objects/vm.rb', line 123 def wait_for_state st = 3, lcm_s = 3 i = 0 until state!() == st && lcm_state!() == lcm_s do return false if i >= 3600 sleep(1) i += 1 end true end |