Example - Enforce Anti-Affinity Rules

We can use the automation techniques that we've learnt so far to write a method to solve a realistic task.

Task

Write an Automation Method that enforces anti-affinity rules for VMs, based on a server_role tag applied to each VM. There should be only one VM of any server_role type running on any host in the cluster.

The Automation Method should be run from a Button visible on the VM details page. If another VM with the same server_role tag is found running on the same host (hypervisor) as the displayed VM, then we live migrate the current VM to another host with no other such tagged VMs (VM migration is only supported when we're working with a VMware vCenter Provider). We also email all users in the EvmGroup-administrator group that the migration occurred.

We can achieve the task using the following script (also available here):

#----------------------------------------------------------------------------
#
# CFME Automate Method: enforce_anti-affinity
#
# Notes: This method enforces an anti-affinity rule based on server_role tag
#
#----------------------------------------------------------------------------

begin
  #----------------------------------------------------------------------------
  def relocate_vm(vm)
    #
    # Get our host name
    #
    our_host = vm.host_name                         # <-- Virtual Column
    #
    # Loop through the other hosts in our cluster
    #
    target_host = nil
    vm.ems_cluster.hosts.each do |this_host|      # <-- Two levels of Association
      next if this_host.name == our_host
      host_invalid = false
      this_host.vms.each do |this_vm|             # <-- Association
        if this_vm.tags(:server_role).first == our_server_role
          host_invalid = true
          break
        end
      end
      next if host_invalid
      #
      # If we get to here then no duplicate server_role VMs have been found
      # on this host
      #
      target_host = this_host
      break
    end
    if target_host.nil?
      raise "No suitable Host found to migrate VM #{vm.name} to"
    else
      $evm.log(:info, "Migrating VM #{vm.name} to host: #{target_host.name}")
      #
      # Migrate the VM to this host
      #
      vm.migrate(target_host)                      # <-- Method
    end
    return target_host.name
  end
  #----------------------------------------------------------------------------

  #----------------------------------------------------------------------------
  def send_email(group_name, vm_name, new_host)
    #
    # Find the group passed to us, and pull out the user emails
    #
    recipients = []
    group = $evm.vmdb('miq_group').find_by_description(group_name)
    group.users.each do |group_member|             # <-- Association
      recipients << group_member.email             # <-- Attribute
    end
    #
    # 'from' is the current logged-user who clicked the button
    #
    from = $evm.root['user'].email
    subject = "VM migration"
    body = "VM Name: #{vm_name} was live-migrated to Host: #{new_host}"
    body += " in accordance with anti-affinity rules"
    #
    # Send emails
    #
    recipients.each do |recipient|
      $evm.log(:info, "Sending email to <#{recipient}> from <#{from}> subject: <#{subject}>")
      $evm.execute(:send_email, recipient, from, subject, body)
    end
  end
  #----------------------------------------------------------------------------


  #----------------------------------------------------------------------------
  # Main code
  #----------------------------------------------------------------------------
  #
  # We've been called from a button on the VM object, so we know that
  # $evm.root['vm'] will be loaded
  #
  vm = $evm.root['vm']
  #
  # Find out this VM's server_role tag
  #
  our_server_role = vm.tags(:server_role).first
  $evm.log(:info, "VM #{vm.name} has a server_role tag of: #{our_server_role}")
  #
  # Loop through the other VMs on the same host
  #
  vm.host.vms.each do |this_vm|             # <-- Two levels of Association
    next if this_vm.name == vm.name
    if this_vm.tags(:server_role).first == our_server_role
      $evm.log(:info, "VM #{this_vm.name} also has a server_role tag of: #{our_server_role}, taking remedial action")
      new_host = relocate_vm(vm)
      send_email('EvmGroup-administrator', vm.name, new_host)
    end
  end
  exit MIQ_OK

rescue => err
  $evm.log(:error, "[#{err}]\n#{err.backtrace.join("\n")}")
  exit MIQ_STOP
end

results matching ""

    No results matching ""