# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#
# This is a Vagrantfile to automatically provision a test environment
#
# See http://www.vagrantup.com/ for info on Vagrant.
#

VAGRANT_HOME = '/home/vagrant/'
TEST_DATA = ::File.join(VAGRANT_HOME, 'test_data')
RATIS_PATH = ::File.join(VAGRANT_HOME, 'ratis')
SCREEN_RC_PATH = ::File.join(RATIS_PATH, 'dev-support/vagrant/screenrcs')

# Settings common to all VMs
common_vm_settings = Proc.new do |vm|
  vm.customize ['modifyvm', :id, '--nictype2', '82543GC']
  vm.customize ['modifyvm', :id, '--largepages', 'on']
  vm.customize ['modifyvm', :id, '--nestedpaging', 'on']
  vm.customize ['modifyvm', :id, '--vtxvpid', 'on']
  vm.customize ['modifyvm', :id, '--hwvirtex', 'on']
  vm.customize ['modifyvm', :id, '--ioapic', 'on']
end

# Settings common to all test VMs
common_test_vm_settings = Proc.new do |testvm|
  # link in and build Ratis
  testvm.vm.synced_folder '../..', RATIS_PATH, type: 'rsync', rsync__exclude: '**/.vagrant/**'

  test_vm_memory = ENV.fetch 'TEST_VM_MEM', (15 * 1024)
  # starting screen wants a tty; for more see https://github.com/hashicorp/vagrant/issues/1673
  testvm.ssh.pty = true
  testvm.vm.provision :shell, privileged: false, name: 'Run Ratis Servers', inline: <<-EOH
    pkill -u vagrant -f ratis || true
    # divide 95% of the VM memory in to thirds for the servers
    export JAVA_OPTS="-Xmx #{(test_vm_memory.to_i * 0.95) / 3}"
    # screen wants a tty; use screen(1) for that
    script -c "screen -c #{SCREEN_RC_PATH}/ratis_$(hostname)_screenrc" /dev/stdout
  EOH
  testvm.ssh.pty = false

  testvm.vm.box = 'ratis-test'
  testvm.vm.box_url = 'ratistest.box'

  testvm.vm.provider :virtualbox do |vb|
    vb.gui = false

    vb.cpus = ENV.fetch 'TEST_VM_CPUs', 5
    vb.memory = test_vm_memory
    vb.linked_clone = true
    common_vm_settings.call(vb)
  end
end

Vagrant.configure('2') do |config|
  config.vm.define 'ratis-build'.to_sym do |ratisbuild|
    ratisbuild.vm.hostname = 'ratis-build'
    # setup a local Maven settings.xml if available
    if File.exist?(File.expand_path('~/.m2/settings.xml'))
      config.vm.provision 'shell', privileged: false, inline: 'mkdir -p ~/.m2'

      config.vm.provision 'file', source: '~/.m2/settings.xml',
                                  destination: "#{VAGRANT_HOME}/.m2/settings.xml"
    end

    # install packages
    ratisbuild.vm.provision :shell, name: 'Install Packages', inline: <<-EOH
      set -e
      # setup /usr/local/bin for non-packaged software
      if [[ $(egrep -c 'PATH.*/usr/local/bin' /etc/environment) -eq 0 ]]; then
        echo 'export PATH=${PATH}:/usr/local/bin' >> /etc/environment
      fi

      # install Java
      apt-get update
      apt-get -y install openjdk-8-jdk-headless

      # install Maven
      mkdir -p /usr/local
      wget --continue http://apache.mirrors.ionfish.org/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.tar.gz
      tar -xzf apache-maven-3.6.0-bin.tar.gz -C /usr/local
      [ -L /usr/local/bin/mvn ] || ln -s /usr/local/apache-maven-3.6.0/bin/mvn /usr/local/bin/mvn

      # Namazu dependencies
      apt-get install -y git libnetfilter-queue-dev libzmq3-dev
      wget --continue https://dl.google.com/go/go1.11.2.linux-amd64.tar.gz
      tar -xzf go1.11.2.linux-amd64.tar.gz -C /usr/local
      [ -L /usr/local/bin/go ] || ln -s /usr/local/go/bin/go /usr/local/bin/go
    EOH

    # download and build Namazu
    ratisbuild.vm.provision :shell, privileged: false, name: 'Build Namazu', inline: <<-EOH
      set -e
      cd ~/
      [ '!' -d namazu ] && git clone https://github.com/osrg/namazu
      cd namazu
      export GOROOT=/usr/local/go
      export GOPATH=`pwd`
      # for some reason seelog fails to pull automatically
      go get -u github.com/cihub/seelog
      ./build
    EOH

    # link in and build Ratis
    config.vm.synced_folder '../..', RATIS_PATH

    ratisbuild.vm.provision :shell, privileged: false, name: 'Build Ratis', inline: <<-EOH
      set -e
      # load proxies or other environment specifics loaded via a Vagrantfile.local
      # or otherwise into /etc/environment
      . /etc/environment
      cd #{RATIS_PATH}
      mvn package -DskipTests
    EOH

    ratisbuild.vm.provider :virtualbox do |vb|
      vb.gui = false
      vb.memory = ENV.fetch 'BUILD_VM_MEM', 2 * 1024
      vb.cpus = ENV.fetch 'BUILD_VM_CPUs', 1
      common_vm_settings.call(vb)
    end

    ratisbuild.vm.box = 'ubuntu/bionic64'
  end

  # Configure a generic VM with three Ratis servers
  config.vm.define 'ratis-servers'.to_sym do |server|
    server.vm.hostname = 'ratis-server'
    motd = %(Welcome to the Ratis test VM
             ========================================
             This VM provides the following:
             * screen -x -- this will connect you to a GNU Screen session running all three Ratis daemons
             * clean-up and restart on your hypervisor with: vagrant up --provision ratisserver
             ========================================
            )
    server.vm.provision :shell, name: 'Update MOTD', inline: <<-EOH.gsub(/^\s+/, '').strip
      set -e
      cat <<EOF >/etc/motd
      #{motd.gsub(/^\s+/, ' ').strip}
      EOF
    EOH

    # normal test VM spin-up steps
    common_test_vm_settings.call(server)
  end

  # Configure a pathological VM with three Ratis servers running on bad disks
  config.vm.define 'ratis-hdd-slowdown'.to_sym do |hdd|
    hdd.vm.hostname = 'ratis-hdd-slowdown'
    motd = %(Welcome to the Ratis flakey disk test VM
             ========================================
             This VM provides the following:
             * screen -x -- this will connect you to a GNU Screen session running all three Ratis daemons
             * sudo screen -x -- this will connect you to a GNU Screen session running the Namazu fuzzing daemon
             * clean-up and restart on your hypervisor with: vagrant up --provision ratishddslowdown
             ========================================
            )

    hdd.vm.provision :shell, name: 'Update MOTD', inline: <<-EOH.gsub(/^\s+/, '').strip
      cat <<EOF >/etc/motd
      #{motd.gsub(/^\s+/, ' ').strip}
      EOF
    EOH

    hdd.vm.provision :shell, name: 'Prepare Namazu Daemon', inline: <<-EOH
      set -e
      pkill -u root -f namazu || true
      fusermount -u #{TEST_DATA}/data0_slowed/ || true
      fusermount -u #{TEST_DATA}/data1_slowed/ || true
      fusermount -u #{TEST_DATA}/data2_slowed/ || true
      mkdir -p #{TEST_DATA}/data{0,0_slowed,1,1_slowed,2,2_slowed}
      chown vagrant #{TEST_DATA}/data{0,0_slowed,1,1_slowed,2,2_slowed}
    EOH

    hdd.ssh.pty = true
    # screen wants a tty; use screen(1) for that
    hdd.vm.provision :shell, name: 'Run Namazu Daemon', inline: <<-EOH
      script -c "screen -c #{SCREEN_RC_PATH}/namazu_hdd_screenrc" /dev/stdout
    EOH
    hdd.ssh.pty = false

    # normal test VM spin-up steps
    common_test_vm_settings.call(hdd)
  end
end
