Archive

Posts Tagged ‘ruby’

Delaying VM Deletion during Retirement in CFME 5.4

September 29th, 2015 No comments

At $DAYJOB we would like to be able to “un-retire” a VM, especially in those cases where a customer retires it and “didn’t know that’s what it would do” or similar. To meet these requirements, I’ve introduced a delay in processing the full retirement by overriding the default pre_retirement.rb method. Here’s the gist of things:

#
# Description: This method powers-off the VM on the provider and waits for Retirement Delay to pass before continuing
#
 
require 'miq_dev_util'
 
@logger = MiqDevUtil::Logger.new($evm, 'pre_retirement')
 
vm = $evm.root['vm']
customer_id = $evm.instantiate('/Configuration/Methods/get_customer_identifier')['return_value']
retirement_delay = $evm.instantiate("/Infrastructure/VM/Retirement/Configuration/RetirementDelay/#{customer_id}")['retirement_delay'].gsub(' ', '.')
 
#TODO: Figure out a way to ensure retirement_delay is valid
 
@logger.log('info', "Found Customer #{customer_id} with retirement delay #{retirement_delay}")
 
# Power off the VM
unless vm.nil? || vm.attributes['power_state'] == 'off'
  ems = vm.ext_management_system
  @logger.log('info', "Powering Off VM <#{vm.name}> in provider <#{ems.try(:name)}>")
  vm.stop
end
 
# If we don't have a delay, continue on
if retirement_delay.nil?
  @logger.log('info', "No retirement delay requested. Continuing with the process")
 
# Otherwise process the delay
else
  if vm.retirement_state == 'retiring'
    @logger.log('info', "Delaying #{retirement_delay} before finishing retirement for #{vm.name}")
    # The VM isn't really retired here, but for display purposes lets see what happens
    # The retirement date isn't set, so that may be a way to differentiate if we need to
    vm['retired'] = true # Because exposing the retired= method is too hard?
    vm.retirement_state = 'delaying'
    $evm.root['ae_result']         = 'retry'
    $evm.root['ae_retry_interval'] = "#{retirement_delay}"
  elsif vm.retirement_state == 'delaying'
    @logger.log('info', "Retirement delay reached. Continuing with the process.")
    vm['retired'] = false # Have to set this back so finish_retirement doesn't bomb later.
    vm.retirement_state = 'retiring'
  end
end

Some items of note:

  1. I’m using the miq_dev_util module written by my colleague that provides a couple of nice utility functions. In this case I’m only using the logging, so swapping that out would be no big deal.
  2. The VM gets “retired” very early on so that the VM shows up with an ‘R’ for an icon and it is obvious it’s been retired – even though it hasn’t been deleted. During this time, the Retirement Status is set to “Delaying”.
  3. We take advantage of the retry capabilities of the state machine to perform the delay for us.
  4. customer_identifier is something internal to us. You can use whatever key you like to search for the appropriate instance of RetirementDelay. Eventually, retirement_delay should contain a ruby-valid time statement, such as ’60.minutes’ or ‘7.days’

Hope you find this useful!

CloudForms VMware Tools Upgrade method

May 14th, 2015 No comments

I wrote a method a while back to allow me to upgrade VMware tools from within the CloudForms interface. I thought I would share it. I usually create a VM button to call the method, but it could probably be used elsewhere with some tweaking.

For the button, create it with System/Process/Request, Message create and Request upgrade_vmware_tools.

Screen Shot 2015-05-14 at 10.31.33 AM

Next, create an instance under /System/Process/Request called upgrade_vmware_tools that has a relationship field pointing to the location of your method. In my case, I chose /Infrastructure/VM/Operations/Methods/upgrade_vmware_tools

Screen Shot 2015-05-14 at 10.32.56 AM

Finally, you can create your instance and method.

Screen Shot 2015-05-14 at 10.33.32 AM

Here’s the code for what I wrote:

###################################
#
# CFME Automate Method: upgrade_vmware_tools
#
# Inputs: $evm.root['vm']
#
###################################
begin
  # Method for logging
  def log(level, message)
    @method = 'upgrade_vmware_tools'
    $evm.log(level, "#{@method} - #{message}")
  end
 
  def dump_attributes(my_object, my_object_name)
    $evm.log(:info, "Begin #{my_object_name}.attributes")
    my_object.attributes.sort.each { |k, v| $evm.log(:info, "#{my_object_name} Attribute - #{k}: #{v}")}
    $evm.log(:info, "End #{my_object_name}.attributes")
    $evm.log(:info, "")
  end
 
  def dump_associations(my_object, my_object_name)
    $evm.log(:info, "Begin #{my_object_name}.associations")
    my_object.associations.sort.each { |a| $evm.log(:info, "#{my_object_name} Association - #{a}")}
    $evm.log(:info, "End #{my_object_name}.associations")
    $evm.log(:info, "")
  end
 
  def dump_virtual_columns(my_object, my_object_name)
    $evm.log(:info, "Begin #{my_object_name}.virtual_columns")
    my_object.virtual_column_names.sort.each { |vcn| $evm.log(:info, "#{my_object_name} Virtual Column - #{vcn}")}
    $evm.log(:info, "End #{my_object_name}.virtual_columns")
    $evm.log(:info, "")
  end
 
  log(:info, "CFME Automate Method Started")
 
  # Log information 
  #dump_attributes($evm.root, "$evm.root")
  #dump_associations($evm.root['vm'], "vm")
  #dump_virtual_columns($evm.root, "$evm.root")
 
  def find_vm(dc, name)
    vm = {}
    dc.datastoreFolder.childEntity.collect do |datastore|
      vm[:instance] = datastore.vm.find { |x| x.name == name }
      if vm[:instance]
        vm[:datastore] = datastore.name
        break
      end
    end
    vm
  end
 
  def upg_tools(vm)
    if vm[:instance][:guest][:guestFamily] == 'windowsGuest'
      instopts = '/s /v "/qn REBOOT=ReallySuppress"'
    else
      instopts = nil
    end
 
    $evm.log(:info, "Upgrading VMware Tools on #{vm[:instance][:name]}")
    upgtask = vm[:instance].UpgradeTools_Task(:installerOptions => instopts).wait_for_completion
  end
 
  require 'rbvmomi'
 
  VIM = RbVmomi::VIM
  rvm  = $evm.root['vm']
  ems = rvm.ext_management_system()
 
  credentials = { :host => ems['hostname'], :user => ems.authentication_userid(), :password => ems.authentication_password(), :insecure => true }
  vim = VIM.connect credentials
 
  dc = vim.serviceInstance.find_datacenter
  vm = find_vm(dc, rvm.name)
  rc = upg_tools(vm)
 
  # Exit method
  log(:info, "CFME Automate Method Ended")
  exit MIQ_OK
 
  # Ruby rescue 
rescue => err
  log(:error, "[#{err}]\n#{err.backtrace.join("\n")}")
  exit MIQ_ABORT
end