# -*- mode: ruby -*-
# vi: set ft=ruby :

require File.join(File.dirname(__FILE__), 'lib', 'vagrant_vm_facter.rb')
require 'yaml'

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
# return byte size of a Fixnum, multiply by 8 bits
# this is to determine which arch to run for VM (32bit or 64bit)
HOST_ARCH = (1.size)*8
WORKING_DIR = File.dirname(__FILE__)
HIERA_CONF = File.join(WORKING_DIR, 'modules/twitch_puppet/files/hiera.yaml')
# Allows for primitive selection of alternative settings.yaml files
if ENV['SETTINGS_FILE']
  SETTINGS_FILE=ENV['SETTINGS_FILE']
else
  SETTINGS_FILE = File.join(WORKING_DIR, 'settings.yaml')
end
DEFAULT_BOX = "ubuntu/xenial#{HOST_ARCH}"

# defaults
settings = Hash.new
default_puppet_opts='--templatedir=templates --trusted_node_data --no-stringify_facts'
puppet_opts = ''
global_facts = {
  'vagrant' => '1'
}

# attempt to load override settings from local file
if File.exists?(SETTINGS_FILE)
  settings = YAML.load_file(SETTINGS_FILE)
  # if we don't have a hash we have bogus data
  settings = Hash.new if not settings.kind_of?(Hash)
  if settings.key?('puppet')
    puppet_version = settings['puppet']['version']
    if settings['puppet']['options'].kind_of?(Array)
      # lets create stringified options list
      puppet_opts = settings['puppet']['options'].map { |l| "--#{l}" }.join(' ')
    end
  end
  # write custom hiera vagrant_1.yaml file
  vagrant_hiera = "#{WORKING_DIR}/hiera/vagrant_1.yaml"
  system("rm -f '#{vagrant_hiera}' && cp '#{SETTINGS_FILE}' '#{vagrant_hiera}'")
end

# dynamically create hiera.yaml in puppet root
if File.exists?(HIERA_CONF)
  hiera_yaml = YAML.load_file(HIERA_CONF)
  hierarchy = hiera_yaml[:hierarchy]
  last = hierarchy.pop
  # add a vagrant level to the hierarchy, before the last one
  hiera_yaml[:hierarchy] = hierarchy + ['vagrant_%{::vagrant}', last]
  # set datadir to be actual hiera dir
  hiera_yaml[:yaml][:datadir] = 'hiera'
  # write back to file to generate everytime
  IO.write("#{WORKING_DIR}/vagrant_hiera.yaml", hiera_yaml.to_yaml)
end

# if we've specified boxes in our settings.yaml, use it, otherwise use defaults
boxes = settings['vagrant_boxes'] || {
  'precise' => {
    # this is new precise box in the Vagrant cloud
    'box' => "ubuntu/precise#{HOST_ARCH}",
  },
  'trusty' => {
    # this is new trusty box in the Vagrant cloud
    'box' => "ubuntu/trusty#{HOST_ARCH}"
  },
  'xenial' => {
    # xenial vagrant image
    'box' => DEFAULT_BOX
  },
  'bionic' => {
    # xenial vagrant image
    'box' => "ubuntu/bionic#{HOST_ARCH}"
  }
}
# default to prod version of puppet
# TODO: read YAML where version will be set
puppet_version ||= '3.8.7-1puppetlabs1'
puppet_package ||= 'puppet'

# determine the synced_folder_type
synced_folder_type = settings.has_key?('synced_folder_type') ? settings['synced_folder_type'] : nil

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  if Vagrant.has_plugin?("vagrant-cachier")
    # Configure cached packages to be shared between instances of the same base box.
    # More info on http://fgrehm.viewdocs.io/vagrant-cachier/usage
    config.cache.scope = :box

    # OPTIONAL: If you are using VirtualBox, you might want to use that to enable
    # NFS for shared folders. This is also very useful for vagrant-libvirt if you
    # want bi-directional sync
    #config.cache.synced_folder_opts = {
    #  type: :nfs,
    #  # The nolock option can be useful for an NFSv3 client that wants to avoid the
    #  # NLM sideband protocol. Without this option, apt-get might hang if it tries
    #  # to lock files needed for /var/cache/* operations. All of this can be avoided
    #  # by using NFSv4 everywhere. Please note that the tcp option is not the default.
    #  mount_options: ['rw', 'vers=3', 'tcp', 'nolock']
    #}
    # For more information please check http://docs.vagrantup.com/v2/synced-folders/basic_usage.html
  end

  # disable serial console logging
  # disable audio
  config.vm.provider "virtualbox" do |v|
    v.customize ["modifyvm", :id, "--uartmode1", "file", "/dev/null"]
    v.customize ["modifyvm", :id, "--audio", "none"]

    # set the default NIC type to virtio for performance
    v.customize ["modifyvm", :id, "--nictype1", "virtio"]
  end

  # the most simple box will likely at least require apt-update
  # we install ruby + puppet here to make sure its available
  # for the next provisioner (puppet) run
  config.vm.provision :shell do |shell|
    shell.inline =<<-EOS
      set -x
      #if ! grep -q $(hostname) /etc/hosts
      #then
      #  sed -i "s/^127.0.0.1 /127.0.0.1 $(hostname) /g" /etc/hosts
      #fi
      export DISTRO_NAME=$(/usr/bin/lsb_release -cs)
      PUPPET_PACKAGE="#{puppet_package}"
      case $DISTRO_NAME in
        bionic) PUPPET_PACKAGE='omnibus-puppet' ; DISTRO_PUPPET_VERSION="*";;
        xenial) RUBY_PKG=ruby-dev ; DISTRO_PUPPET_VERSION="3.8.5-2ubuntu0.1";;
        *) RUBY_PKG=ruby1.9.1-dev ; DISTRO_PUPPET_VERSION="#{puppet_version}" ; MANAGE_PUPPET_REPO='true';;
      esac
      export DEBIAN_FRONTEND=noninteractive
      apt-get update
      apt-get install -y lsb-release make
      # create the jtv user
      if ! id -u jtv >/dev/null 2>&1; then
        adduser jtv --disabled-password --gecos '' >/dev/null 2>&1
      fi
      # puppetlabs repo
      if [ ! -f /etc/apt/sources.list.d/puppetlabs.list -a -v MANAGE_PUPPET_REPO ]; then
        echo Adding PuppetLabs APT PPA... \
        $(wget -qO - https://apt.puppetlabs.com/pubkey.gpg | apt-key add -)
        echo "deb http://apt.puppetlabs.com ${DISTRO_NAME} main dependencies" > /etc/apt/sources.list.d/puppetlabs.list
      fi
      if [ "$DISTRO_NAME" = 'bionic' ]; then
        echo Adding bionic repo... \
        $(wget -qO - https://packages.internal.justin.tv/artifactory/api/gpg/key/public | apt-key add -)
	echo "deb [arch=amd64] http://packages.internal.justin.tv/internal/twitch ${DISTRO_NAME} main" > /etc/apt/sources.list.d/twitch.list
        apt-get update
      fi
      # puppet version check
      if [ "$(puppet --version 2>/dev/null)" != ${DISTRO_PUPPET_VERSION} ]; then
        echo Updating Puppet...
        apt-get install -qy ${PUPPET_PACKAGE}=${DISTRO_PUPPET_VERSION}
      fi
      puppet apply -e "host {$(hostname): ip => '127.0.1.1' }"
    EOS
  end

  if settings.has_key?('synced_folders')
    settings['synced_folders'].each_pair do |name,data|
      config.vm.synced_folder data['source'], data['target']
    end
  end

  boxes.each_pair do |name,opts|
    config.vm.define name do |box|
      box.vm.synced_folder ".", "/vagrant", disabled: false, create: true, type: synced_folder_type
      box.vm.box = opts['box'] || DEFAULT_BOX
      box.vm.box_url = opts['url']
      box.vm.hostname = opts['hostname'] || name

      if synced_folder_type == 'nfs'
        box.vm.network :private_network, type: 'dhcp', nic_type: 'virtio'
      end

      if opts.keys.include?('forward_ports')
        opts['forward_ports'].each_pair do |svc,o|
          box.vm.network(:forwarded_port, {
            guest: o['guest_port'],
            host: o['host_port'],
            protocol: o['protocol'] || 'tcp'
          })
        end
      end

      %w(cpus memory).each do |vbox_opt|
        if opts.keys.include?(vbox_opt)
          box.vm.provider('virtualbox') { |v| v.send("#{vbox_opt}=", opts[vbox_opt]) }
        end
      end

      override_facts = settings['facter'] || {}
      box_facts = opts['facter'] || {}
      vm_facts = global_facts.merge(override_facts).merge(box_facts)

      # https://www.vagrantup.com/docs/synced-folders/
      box.vm_facter(vm_facts,[default_puppet_opts,puppet_opts].join(' '))
    end
  end
end
