#!/bin/bash
#
# Copyright 2017 Red Hat, Inc.
#
# NAME
#     rht-vmsetkeyboard - loop through and adjust keyboard on all VMs
#
# SYNOPSIS
#     rht-vmsetkeyboard VMNAME|all "layout"
#
# DESCRIPTION
#     This tool loops through each VM: starting/remoting in/updating
#     settings/saving. Use localectl list-x11-keymap-layouts on 
#     foundation0 to see a list of valid layouts as an argument.
#
# CHANGELOG
#   * Mon Nov 13 2017 Robert Locke <rlocke@redhat.com>
#   - make more "robust"
#   * Wed May 11 2016 Robert Locke <rlocke@redhat.com>
#   - add support for RHT_ENROLLMENT -ge 512
#   * Mon Feb 22 2016 Robert Locke <rlocke@redhat.com>
#   - add support for RHT_NOSTARTVMS and RHT_NOFINISHVMS
#   * Tue Nov  3 2015 Robert Locke <rlocke@redhat.com>
#   - add a delay after any starting of classroom
#   * Mon Oct 26 2015 Robert Locke <rlocke@redhat.com>
#   - hard code classroom host name (fix for slow boot)
#   * Fri Oct 23 2015 Robert Locke <rlocke@redhat.com>
#   - add --prompt for classes that cannot start all
#   * Wed Oct 21 2015 Robert Locke <rlocke@redhat.com>
#   - avoid rc.local race condition (thanks MW devs!)
#   * Fri Oct  2 2015 Robert Locke <rlocke@redhat.com>
#   - add support for .lab.example.com
#   * Fri Jan 23 2015 Robert Locke <rlocke@redhat.com>
#   - support hostnames of vmname, vmnameX, and vmname.podX
#   * Fri Oct 31 2014 Robert Locke <rlocke@redhat.com>
#   - add branch to try both localectl commands for non-graphical RHEL7
#   * Wed Sep 24 2014 Robert Locke <rlocke@redhat.com>
#   - support multiple f0 infrastructure hostnames
#   * Wed Jul  2 2014 Robert Locke <rlocke@redhat.com>
#   - original code

PATH=/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/local/sbin

# Define variables
classroom_delay=180

# Source library of functions
source /usr/local/lib/rhttool.shlib
# trap on_exit EXIT

function print_usage() {
  local retcode=$1
  cat <<EOF
$0 is a script to automate setting keyboard to the VMs.

Usage: $0 [--prompt] all <Layout>
  will loop through all the VMs setting keyboard and saving

Usage: $0 <VMNAME> <Layout>
  will set the keyboard and save VMNAME

Use "localectl list-x11-keymap-layouts" to list valid RHEL7 <Layout>
Use "localectl list-keymaps" to list valid non-graphical RHEL7 <Layout>
Use "system-config-keyboard --help" to list valid RHEL6 <Layout>

EOF
  exit ${retcode}
}

function parse_opts() {
  ARGS=$(getopt -o hp -l "help,prompt" -n "rht-vmsetkeyboard" -- "$@")
  if [[ $? -ne 0 ]]; then
    print_usage 1
  fi
  eval set -- "${ARGS}"
  while true ; do
    case $1 in
      -h|--help)
        print_usage 0 ;;
      -p|--prompt)
        prompt=yes ; shift ;;
      --)
        shift ; break ;;
      *)
        echo "Error: bad option, $1" ; print_usage 1 ;;
    esac
  done
  # Process arguments
  [[ "$#" -eq 2 ]] || print_usage 1
  VMNAME="${1}"
  new_keyboard="${2}"
  if [[ -z "${new_keyboard}" ]]; then
    echo 'Warning: new keyboard not specified - nothing done.'
    exit 1
  fi
}

function keyit() {
  vm_name=$1
  new_keymap=$2
  # Start if VM is not running
  if ! is_running ${vm_name} ; then
    rht-vmctl start ${vm_name}
    if [[ "${vm_name}" == "classroom" ]]; then
      sleep ${classroom_delay}
    fi
  fi
  echo "Setting keyboard on ${vm_name}"
  if [[ "${vm_name}" == "classroom" ]]; then
    host_name=${vm_name}.example.com
  elif getent hosts ${vm_name}.example.com &> /dev/null ; then
    host_name=${vm_name}.example.com
  elif getent hosts ${vm_name}${enrollment}.example.com &> /dev/null ; then
    host_name=${vm_name}${enrollment}.example.com
  elif getent hosts ${vm_name}.pod${enrollment}.example.com &> /dev/null ; then
    host_name=${vm_name}.pod${enrollment}.example.com
  elif getent hosts ${vm_name}.lab.example.com &> /dev/null ; then
    host_name=${vm_name}.lab.example.com
  else
    echo "ERROR: Unresolvable - ${vm_name}"
    return
  fi
  if wait_tcp_port ${host_name} 22 ; then
    if [[ "${vm_name}" == "classroom" ]]; then
      ssh="ssh"
    else
      push_sshkey ${host_name} &> /dev/null
      ssh="ssh -i /root/.ssh/.rhttoolkey"
    fi
    echo -n "Waiting for rc.local to finish"
    while ! ${ssh} root@${host_name} "[[ ! -x /etc/rc.d/rc.local || -f /var/lock/subsys/local ]]" &>/dev/null ; do
      echo -n "."
      sleep 5
    done
    echo " Done."
    if ! rht_set_keyboard ${host_name} ${new_keyboard} ; then
      echo "ERROR: Something went wrong setting a keyboard"
      return 1
    fi
  else
    echo "ERROR: Unreachable."
    return
  fi
  echo -n "Waiting for ${vm_name} to shutdown"
  ${ssh} root@${host_name} "shutdown -h now" &> /dev/null
  while is_running ${vm_name} ; do
    echo -n "."
    sleep 5
  done
  echo " Done."
  echo "Saving and restarting ${vm_name}"
  rht-vmctl save ${vm_name}
}

# Main code

# If I need root privileges to run, then use sudo to call myself
if [[ "$EUID" -gt "0" ]] ; then
  debug 'Using sudo to become root.'
  sudo $0 "$@"
  exit
fi

parse_opts "$@"

# Source some variables that we need - should provide:
# RHT_VMS="desktop server"
# RHT_ENROLLMENT=5
source /etc/rht
# Validate
if [[ -z "${RHT_VMS}" || -z "${RHT_ENROLLMENT}" ]]; then
  echo "ERROR: missing a needed variable from /etc/rht"
  echo "RHT_VMS = '${RHT_VMS}'"
  echo "RHT_ENROLLMENT = '${RHT_ENROLLMENT}'"
  exit 1
fi

# Set/adjust enrollment for RHT_ENROLLMENT -ge 512
enrollment=$((RHT_ENROLLMENT%512))

# Validate VMNAME
match=0
my_vms=${VMNAME}
if [[ "${VMNAME}" == "all" ]]; then
  [[ -n "${RHT_VM0}" ]] && my_vms="${RHT_VM0} ${RHT_VMS}" || my_vms="${RHT_VMS}"
  # Excising vms in RHT_NOSTARTVMS and RHT_NOFINISHVMS
  if [[ -n "${RHT_NOSTARTVMS}" || -n "${RHT_NOFINISHVMS}" ]]; then
    for no_vms in ${RHT_NOSTARTVMS} ${RHT_NOFINISHVMS} ; do
      my_vms="${my_vms/${no_vms}/}"
    done
  fi
  match=1
else
  for i in $RHT_VMS $RHT_VM0 ; do
    [[ "$i" == "$VMNAME" ]] && match=1
  done
fi
if [[ $match -eq 0 ]]; then
  echo "ERROR: unrecognized VMNAME specified, ${VMNAME}."
  print_usage 1
fi

# If we are on foundation0 and classroom in VMNAME, then do classroom first
if [[ $my_vms == *classroom* ]] ; then
  keyit classroom ${new_keyboard}
  # Wait for it to be up - complete guess that it gets close enough in 60
  echo "Waiting for classroom to finish coming up."
  sleep ${classroom_delay}
fi

# For each my_vms
for vm_name in ${my_vms} ; do
  # Skip classroom because we already did it
  [[ "classroom" == "${vm_name}" ]] && continue
  if [[ -n "${prompt}" ]]; then
    confirm=''
    while [[ "${confirm}" != 'y' && "${confirm}" != 'n' ]]; do
      echo -n "Process ${vm_name} y(es) n(o)? "
      read confirm
    done
  else
    confirm='y'
  fi
  [[ "${confirm}" == "y" ]] && keyit ${vm_name} ${new_keyboard}
done

exit 0
