File: leases.rb

package info (click to toggle)
ruby-rbvmomi 1.8.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,756 kB
  • sloc: ruby: 5,590; sh: 36; makefile: 7
file content (142 lines) | stat: -rw-r--r-- 5,769 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
82
83
84
85
86
87
88
89
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
require 'yaml'

# A class to manage VM leases
# 
# This class uses YAML encoded VM annotations (config.annotation) to manage a
# lease system. It helps add such lease info onto new and existing VMs and to
# find VMs that have expired leases or that are about to have expired leases.
# The calling code can use those to generate emails with about-to-expire 
# notifications, suspend, power off or destroy VMs that have exceeded their
# lease, etc. 
class LeaseTool
  # Lists of VM properties the LeaseTool needs to do its job. Can be used to
  # construct larger property collector calls that retrieve more info than just
  # one subsystem needs.
  # @return [Array] List of property names
  def vms_props_list 
    ['name', 'config.annotation']
  end
  
  # Fetch all VM properties that the LeaseTool needs on all VMs passed in. 
  # @param vms [Array] List of VIM::VirtualMachine instances
  # @return [Hash] Hash of VMs as keys and their properties as values
  def get_vms_props vms
    out = {}
    if vms.length > 0
      pc = vms.first._connection.serviceContent.propertyCollector
      out = pc.collectMultiple(vms, 'name', 'config.annotation')
    end
    out
  end
  
  # Retrieve the current time as used by the lease tool. 
  # @return [Time] Current time as used by the lease tool
  def current_time
    # XXX: Should swith to time provided by VC
    Time.now
  end
  
  # Helper function that sets the lease info in a passed in VM config. If there
  # is no annotation, it is added. If there is an annotation, it is updated to
  # include the lease info. Note that if the annotation isn't YAML, it is 
  # overwritten.  
  # @param vmconfig [Hash] Virtual Machine config spec
  # @param lease_minutes [int] Time to lease expiration from now in minutes
  # @return [Hash] Updated Virtual Machine config spec
  def set_lease_in_vm_config vmconfig, lease_minutes
    annotation = vmconfig[:annotation]
    annotation ||= ""
    note = YAML.load annotation
    if !note.is_a?(Hash)
      note = {}
    end
    lease = current_time + lease_minutes * 60
    note['lease'] = lease
    vmconfig[:annotation] = YAML.dump(note)
    vmconfig
  end
  
  # Issue ReconfigVM_Task on the VM to update the lease. User can pass in current
  # annotation, but if not, it is retrieved on demand. A task is returned, i.e.
  # function doesn't wait for completion.
  # @param vm [VIM::VirtualMachine] Virtual Machine instance
  # @param lease_minutes [int] Time to lease expiration from now in minutes
  # @param annotation [String] 'config.annotation' property of the VM. Optional.
  # @return [VIM::Task] VM reconfiguration task
  def set_lease_on_vm_task vm, lease_minutes, annotation = nil
    if !annotation
      annotation = vm.collect 'config.annotation' 
    end
    vmconfig = {:annotation => annotation}
    vmconfig = set_lease_in_vm_config vmconfig, lease_minutes
    # XXX: It may be a good idea to cite the VM version here to avoid
    #      concurrent writes to the annotation stepping on each others toes
    vm.ReconfigVM_Task(:spec => vmconfig)
  end
  
  # Issue ReconfigVM_Task to set the lease on all VMs that currently do not 
  # have a lease. All VM reconfigurations are done in parallel and the function
  # waits for all of them to complete
  # @param vms [Array] List of VIM::VirtualMachine instances, may or may not have leases
  # @param vmprops [Hash] Hash of VIM::VirtualMachine instances to their properties
  # @option opts [int]  :lease_minutes Time to lease expiration from now in minutes
  # @return [Array] List of previously leaseless VMs that now have a lease
  def set_lease_on_leaseless_vms vms, vmprops, opts = {}
    lease_minutes = opts[:lease_minutes]
    if !lease_minutes
      raise "Expected lease_minutes to be specified"
    end
    vms = find_leaseless_vms vms, vmprops
    if vms.length > 0
      tasks = vms.map do |vm|
        annotation = vmprops[vm]['config.annotation']
        task = set_lease_on_vm_task(vm, lease_minutes, annotation)
        task
      end
      si = vms.first._connection.serviceInstance
      si.wait_for_multiple_tasks [], tasks
    end
    vms
  end
  
  # Filter the list of passed in Virtual Machines and find the ones that currently
  # do not have a lease.
  # @param vms [Array] List of VIM::VirtualMachine instances, may or may not have leases
  # @param vmprops [Hash] Hash of VIM::VirtualMachine instances to their properties
  # @return [Array] List of leaseless VMs 
  def find_leaseless_vms vms, vmprops
    vms.reject do |vm|
      props = vmprops[vm]
      annotation = props['config.annotation']
      if annotation
        note = YAML.load annotation
        note.is_a?(Hash) && note['lease']
      end
    end
  end

  # Filter the list of passed in Virtul Machines and find the one that are 
  # expired. A time offset can be used to identify VMs that will expire at 
  # a certain point in the future. 
  # If a VM doesn't have a lease, it is treated as never expiring.
  # @param vms [Array] List of VIM::VirtualMachine instances, may or may not have leases
  # @param vmprops [Hash] Hash of VIM::VirtualMachine instances to their properties
  # @option opts [int]  :time_delta Time delta (seconds) to be added to current time
  # @return [Array] List of expired VMs 
  def filter_expired_vms vms, vmprops, opts = {}
    time_delta = opts[:time_delta] || 0
    time = current_time + time_delta
    
    out = vms.map do |vm|
      props = vmprops[vm]
      next unless annotation = props['config.annotation']
      note = YAML.load annotation
      next unless note.is_a?(Hash) && lease = note['lease']
      next unless time > lease
      time_to_expiration = ((lease - time) + time_delta)
      [vm, time_to_expiration]
    end.compact
    out = Hash[out]
    out
  end
end