#!/usr/bin/env bash
# @file Linux VMWare Workstation Install
# @brief Installs VMWare Workstation Pro on Linux devices, applies a "publicly-retrieved" license key (see disclaimer), and automatically accepts the terms and conditions
# @description
#     This script ensures the user included `vmware` in their software installation list. It then checks for presence of the `vmware` utility. If it is not present, then the script:
#
#     1. Downloads the [VMWare Workstation Pro](https://www.vmware.com/content/vmware/vmware-published-sites/us/products/workstation-pro.html.html) Linux installer
#     2. Installs VMWare Workstation Pro
#     3. Passes options to the installation script that automatically apply a publicly retrived license key and accept the Terms & Conditions
#
#     **DISCLAIMER:** If you plan on using VMWare Workstation for anything but evaluation purposes, then we highly suggest purchasing a copy
#     of VMWare Workstation. The "publicly-retrived" license keys are scattered throughout GitHub and we are not exactly
#     sure why they work. You can pass in your own key by utilizing the `VMWARE_WORKSTATION_LICENSE_KEY` environment variable. More details on
#     using environment variables or repository-housed encrypted secrets can be found in our [Secrets documentation](https://install.doctor/docs/customization/secrets).
#
#     ## VMWare on macOS
#
#     This script only installs VMWare Workstation on Linux. The macOS-variant titled VMWare Fusion can be installed using a Homebrew
#     cask so a "work-around" script does not have to be used.
#
#     ## VMWare vs. Parallels vs. VirtualBox vs. KVM vs. Hyper-V
#
#     There are a handful of VM virtualization providers you can choose from. VMWare is a nice compromise between OS compatibility and performance.
#     Parallels, on the hand, might be better for macOS since it is designed specifically for macOS. Finally, VirtualBox is a truly free,
#     open-source option that does not come with the same optimizations that VMWare and Parallels provide.
#
#     Other virtualization options include KVM (Linux / macOS) and Hyper-V (Windows). These options are better used for headless
#     systems.
#
#     ## Links
#
#     * [VMWare Workstation homepage](https://www.vmware.com/content/vmware/vmware-published-sites/us/products/workstation-pro.html.html)
# @file Vagrant VMWare Utility
# @brief Installs the `vagrant-vmware-utility` if both Vagrant and VMWare are installed
# @description
#     This script first checks if `vagrant`, `vmware`, and `vagrant-vmware-utility` are available in the `PATH`. If they are present, then the script
#     configures the [`vagrant-vmware-utility`](https://developer.hashicorp.com/vagrant/docs/providers/vmware/vagrant-vmware-utility) by generating the required security certificates and enabling the service.
#     This system package enables the capability of controlling both VMWare Workstation and VMWare Fusion with Vagrant.
#
#     Since this script runs only when `vagrant`, `vmware`, and `vagrant-vmware-utility` are in the `PATH`, this means that it will run
#     when you use an installation template that includes all three pieces of software in the software list defined in
#     `home/.chezmoidata.yaml`.
#
#     ## Links
#
#     * [Vagrant VMWare Utility on GitHub](https://github.com/hashicorp/vagrant-vmware-desktop)
#     * [`home/.chezmoidata.yaml`](https://github.com/megabyte-labs/install.doctor/blob/master/home/.chezmoidata.yaml)
# @file VMWare Configuration
# @brief Patches VMWare to leverage kernel optimizations, support macOS, and work harmoniously with Secure Boot. It also enables optional services such as the USB service.
# @description
#     This script performs various VMWare optimizations that allow VMWare to work optimally with all features enabled.

{{- $softwareGroup := nospace (cat "_" .host.softwareGroup) -}}
{{- $softwareList := list (index .softwareGroups $softwareGroup | toString | replace "[" "" | replace "]" "") | uniq | join " " -}}

{{- $secretKey := "" -}}
{{- if (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "VMWARE_WORKSTATION_LICENSE_KEY")) -}}
{{-   $secretKey = (default "4C21U-2KK9Q-M8130-4V2QH-CF810" (includeTemplate "secrets/VMWARE_WORKSTATION_LICENSE_KEY" | decrypt | trim)) -}}
{{- else -}}
{{-   $secretKey = (default "4C21U-2KK9Q-M8130-4V2QH-CF810" (env "VMWARE_WORKSTATION_LICENSE_KEY")) -}}
{{- end }}

# Source: https://gist.github.com/PurpleVibe32/30a802c3c8ec902e1487024cdea26251
# key: {{ $secretKey }}

{{ includeTemplate "universal/profile" }}
{{ includeTemplate "universal/logg" }}

function vmwareSetup() {
  ### Run on Linux only
  if [ -f /etc/os-release ]; then
    ### Run if vmware is to be installed
    {{- if (contains " vmware" $softwareList) -}}
    ### Install VMware Workstation
    if ! command -v vmware > /dev/null; then
      ### Download VMWare Workstation
      logg info 'VMware Workstation is not installed'
      VMWARE_WORKSTATION_URL=https://www.vmware.com/go/getworkstation-linux
      VMWARE_WORKSTATION_DIR=/tmp/workstation-downloads
      mkdir -p $VMWARE_WORKSTATION_DIR
      logg info 'Downloading VMware Workstation Installer'
      curl -sSLA "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20220101 Firefox/102.0" "$VMWARE_WORKSTATION_URL" -o "$VMWARE_WORKSTATION_DIR/tryworkstation-linux-64.sh"

      ### Register product key / license
      VMWARE_WORKSTATION_LICENSE_KEY='{{- $secretKey -}}'
      if [ -n "$VMWARE_WORKSTATION_LICENSE_KEY" ]; then
        logg info 'Registering VMware Workstation Pro license with serial number'
        sudo "$VMWARE_WORKSTATION_DIR/tryworkstation-linux-64.sh" --eulas-agreed --console --required --set-setting vmware-workstation serialNumber "$VMWARE_WORKSTATION_LICENSE_KEY"
      else
        logg info 'Agreeing to VMWare Workstation Pro license (without serial number)'
        sudo "$VMWARE_WORKSTATION_DIR/tryworkstation-linux-64.sh" --eulas-agreed --console --required
      fi
      logg success 'VMware Workstation installed successfully'
    else
      logg info 'VMware Workstation is already installed'
    fi
    {{ end -}}

    ### Run logic if VMware is installed
    if command -v vmware > /dev/null; then
      ### Build kernel modules if they are not present
      if [ ! -f "/lib/modules/$(uname -r)/misc/vmmon.ko" ] || [ ! -f "/lib/modules/$(uname -r)/misc/vmnet.ko" ]; then
        ### Build VMWare host modules
        logg info 'Building VMware host modules'
        if sudo vmware-modconfig --console --install-all; then
          logg success 'Built VMWare host modules successfully with sudo vmware-modconfig --console --install-all'
        else
          logg info 'Acquiring VMware version from CLI'
          VMW_VERSION="$(vmware --version | cut -f 3 -d' ')"
          mkdir -p /tmp/vmw_patch
          cd /tmp/vmw_patch
          logg info 'Downloading VMware host module patches'
          curl -sSL "https://github.com/mkubecek/vmware-host-modules/archive/workstation-$VMW_VERSION.tar.gz" -o /tmp/vmw_patch/workstation.tar.gz
          tar -xzf /tmp/vmw_patch/workstation.tar.gz
          cd vmware*
          logg info 'Running sudo make and sudo make install'
          sudo make
          sudo make install
          logg success 'Successfully configured VMware host module patches'
        fi

        ### Sign VMware host modules if Secure Boot is enabled
        if [ -f /sys/firmware/efi ]; then
          logg info 'Signing host modules'
          mkdir -p /tmp/vmware
          cd /tmp/vmware
          openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj "/CN=VMware/"
          "/usr/src/linux-headers-$(uname -r)/scripts/sign-file" sha256 ./MOK.priv ./MOK.der "$(modinfo -n vmmon)"
          "/usr/src/linux-headers-$(uname -r)/scripts/sign-file" sha256 ./MOK.priv ./MOK.der "$(modinfo -n vmnet)"
          echo '' | mokutil --import MOK.der
          logg success 'Successfully signed VMware host modules. Reboot the host before powering on VMs'
        fi

        ### Patch VMware with Unlocker
        if [ ! -f /usr/lib/vmware/isoimages/darwin.iso ]; then
          logg info 'Acquiring VMware Unlocker latest release version'
          UNLOCKER_URL="$(curl -sSL 'https://api.github.com/repos/DrDonk/unlocker/releases/latest' | jq  -r '.assets[0].browser_download_url')"
          mkdir -p /tmp/vmware-unlocker
          cd /tmp/vmware-unlocker
          logg info 'Downloading unlocker.zip'
          curl -sSL "$UNLOCKER_URL" -o unlocker.zip
          unzip unlocker.zip
          cd linux
          logg info 'Running the unlocker'
          echo "y" | sudo ./unlock
          logg success 'Successfully unlocked VMware for macOS compatibility'
        else
          logg info '/usr/lib/vmware/isoimages/darwin.iso is already present on the system so VMware macOS unlocking will not be performed'
        fi

        if [[ ! "$(test -d /proc && grep Microsoft /proc/version > /dev/null)" ]]; then
          ### Start / enable VMWare service
          logg info 'Ensuring vmware.service is enabled and running'
          sudo systemctl enable vmware.service
          sudo systemctl restart vmware.service

          ### Start / enable VMWare Workstation Server service
          logg info 'Ensuring vmware-workstation-server.service is enabled and running'
          sudo systemctl enable vmware-workstation-server.service
          sudo systemctl restart vmware-workstation-server.service

          ### Start / enable VMWare USB Arbitrator service
          if command -v vmware-usbarbitrator.service > /dev/null; then
            logg info 'Ensuring vmware-usbarbitrator.service is enabled and running'
            sudo systemctl enable vmware-usbarbitrator.service
            sudo systemctl restart vmware-usbarbitrator.service
          else
            logg warn 'vmware-usbarbitrator does not exist in the PATH'
          fi
        fi
      else
        logg info 'VMware host modules are present'
      fi
    else
      logg warn 'VMware Workstation is not installed so the VMware Unlocker will not be installed'
    fi
  fi

  # @description Only run logic if both Vagrant and VMWare are installed
  if command -v vagrant > /dev/null && command -v vmware-id > /dev/null; then
      # @description  Vagrant VMWare Utility configuration
      if command -v vagrant-vmware-utility > /dev/null; then
          if [ -f /usr/local/bin/certificates/vagrant-utility.key ]; then
              logg info 'Assuming Vagrant VMWare Utility certificates have been properly generated since /usr/local/bin/certificates/vagrant-utility.key is present'
          else
              logg info 'Generating Vagrant VMWare Utility certificates'
              sudo vagrant-vmware-utility certificate generate
              logg success 'Generated Vagrant VMWare Utility certificates via vagrant-vmware-utility certificate generate'
          fi
          logg info 'Ensuring the Vagrant VMWare Utility service is enabled'
          sudo vagrant-vmware-utility service install || EXIT_CODE=$?
          if [ -n "$EXIT_CODE" ]; then
              logg info 'The Vagrant VMWare Utility command vagrant-vmware-utility service install failed. It is probably already setup.'
          fi
      fi
  else
      logg info 'Vagrant is not installed so the Vagrant plugins will not be installed'
      logg info 'Vagrant or VMWare is not installed so the Vagrant VMWare utility will not be configured'
  fi
}

vmwareSetup
