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

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
PACKAGE_BUILD="1"

LAST_HOST_COUNT_SEMAPHORE="host_count.sticky"
LAST_PLATFORM_SEMAPHORE="platform.sticky"

if ENV['PACKAGE_RELEASE']
  PACKAGE_RELEASE=ENV['PACKAGE_RELEASE']
else
  PACKAGE_RELEASE="3.24.5a"
end

if File.exist?("#{LAST_PLATFORM_SEMAPHORE}")
  DEFAULT_PLATFORM=File.open("#{LAST_PLATFORM_SEMAPHORE}", "r") { |f| f.read }
else
  DEFAULT_PLATFORM="debian/bookworm64"
end

if ENV['PLATFORM']
  PLATFORM=ENV['PLATFORM']
  File.open("#{LAST_PLATFORM_SEMAPHORE}", "w") { |f| f.write "#{PLATFORM}" }
else
  PLATFORM="#{DEFAULT_PLATFORM}"
end

# Dynamic Node Configuration The number of client hosts to provision and
# bootstrap to the hub. Adjust this as desired.
if ENV['HOSTS']
  hosts=ENV['HOSTS'].to_i
  File.open("#{LAST_HOST_COUNT_SEMAPHORE}", "w") { |f| f.write "#{hosts}" }
else
  if File.exist?("#{LAST_HOST_COUNT_SEMAPHORE}")
    hosts = File.open("#{LAST_HOST_COUNT_SEMAPHORE}", "r") { |f| f.read }.to_i
  else
    hosts = 1
  end
end

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  ##### No edits below this point are necessary #####

  # Every Vagrant virtual environment requires a box to build off of.
  config.vm.box = "#{PLATFORM}"
  config.vm.synced_folder ".", "/vagrant"

  if Vagrant.has_plugin?("vagrant-vbguest")
    config.vbguest.auto_update = true
    config.vbguest.installer_options = { allow_kernel_upgrade: true }
    config.vm.synced_folder ".", "/vagrant", type: "virtualbox"
    # Platform specific settings
    if "#{config.vm.box}" =~ /centos(-|\/)6.*/i
      # Fix repositories because CentOS 6 is now EOL.
      # Old CFEngine produced CentOS 6 Basebox: centos-6.5-x86_64-cfengine_enterprise-vagrant-201501201245
      # Old CFEngine produced CentOS 6 Basebox URL: http://cfengine.vagrant-baseboxes.s3.amazonaws.com/.box
      config.vbguest.installer_hooks[:before_install] = [ "sed -i 's/mirror.centos.org/vault.centos.org/;/^mirrorlist/d;s/^#baseurl/baseurl/' /etc/yum.repos.d/CentOS-Base.repo" ]
    end
  else
    if "#{config.vm.box}" =~ /centos(-|\/)6.*/i
      # Fix repositories because CentOS 6 is now EOL.
      config.vm.provision :shell, inline: <<-SHELL
sed -i 's/mirror.centos.org/vault.centos.org/;/^mirrorlist/d;s/^#baseurl/baseurl/' /etc/yum.repos.d/CentOS-Base.repo
SHELL
    end
  end

  # Get the folder name of the vagrant project
  project_folder = File.basename(File.dirname(__FILE__))

  # Prettify the name (this allows people to easily re-use the vagrant project
  # and have potentially multiple instances running wihtout name collisions by
  # simply renaming the project folder.
  project_name = project_folder.gsub("vagrant_quickstart-", "")
  project_name.gsub("_", " ")

  # Specify the first three octects of the private host_only network for inter
  # vm communication
  first_three_network_octets = "192.168.56"

  # We reserve the hub ip for .2
  cfengine_hub_ip = "#{first_three_network_octets}.2"

  # All the hosts get port 80 forwarded to this port + host_number
  # (just like the IP)
  prefix_80_fwd = 9000

  # Begin Hub Configuration
  #

  hub_80_fwd = Integer("#{prefix_80_fwd+2}")

  config.vm.define :hub do |hub|
    hub.vm.hostname = "hub.example.com"
    hub.vm.network :private_network, ip: "#{cfengine_hub_ip}"
    hub.vm.network :forwarded_port, guest: 443, host: hub_80_fwd

    # This allows us to use a different set of masterfiles on the hub when initalizing the env.
    # Simply `MASTERFILES="/path/to/my/masterfiles" vagrant up`
    if ENV['MASTERFILES']
      hub.vm.synced_folder ENV['MASTERFILES'], "/var/cfengine/masterfiles"
    end

    # If ~/CFEngine exists, then mount it at /
    # This is primarily to make it easy for CFEngine maintainers
    if File.exist? File.expand_path('~/CFEngine')
      hub.vm.synced_folder '~/CFEngine', "/CFEngine"
    end
    hub.vm.provider "virtualbox" do |v|
      # v.gui = true
      v.customize ["modifyvm", :id, "--memory", "2048", "--cpus", "2"]
      v.name = "#{project_name} hub"

      # On MacOS DNS as-is with virtualbox does not seem to work. Workaround:
      if RUBY_PLATFORM.include? "darwin"
        v.auto_nat_dns_proxy = false
        v.customize ["modifyvm", :id, "--natdnsproxy1", "off"]
        v.customize ["modifyvm", :id, "--natdnshostresolver1", "off"]
      end
    end
    hub.vm.provider :libvirt do |v|
      v.memory = 2048
      v.cpus = 2
    end

    if RUBY_PLATFORM.include? "darwin"
      hub.vm.provision "shell", name: "fix-macos-dns", inline: <<~SHELL
        echo "nameserver 8.8.8.8" > /etc/resolv.conf
      SHELL
    end

    # Use a synced folder so that we can edit from outside of the environment
    # A typical workflow has masterfiles pulled from version control
    hub.vm.provision :shell, name: "install-hub", :path => "scripts/install_cfengine_enterprise.sh", :args => "hub #{PACKAGE_RELEASE} #{PACKAGE_BUILD}"
    hub.vm.provision :shell, name: "bootstrap-cfengine", :path => "scripts/bootstrap_cfengine.sh", :args => "#{cfengine_hub_ip}"
    hub.vm.provision :shell, name: "display-instructions", :path => "scripts/instructions.sh", :args => "#{cfengine_hub_ip}"

  end

  #
  # Begin Dynamic Node Specification
  #

  # Calculate Node IP
  # .1 is reserved for internal router
  # .2 is reserved for the hub
  # .3 begins host ips
  host_ip_offset = 2
  #maxhosts = 252
  # Without a license there is no sense in going beyond 25 hosts.
  maxhosts = 25

  # BEGIN client loop
  (1..hosts).each do |host_number|
    # Set padding for host name to make it look pretty
    host_name = "host" + host_number.to_s.rjust(3, '0')
    # Calculate ip address for host
    host_ip = "#{first_three_network_octets}.#{host_number+host_ip_offset}"
    # Calculate host port to forward to port 80
    host_80_fwd = Integer("#{prefix_80_fwd+host_number+host_ip_offset}")

    config.vm.define host_name.to_sym do |host|

      host.vm.hostname = "#{host_name}.example.com"
      host.vm.network :private_network, ip: "#{host_ip}"
      host.vm.network :forwarded_port, guest: 80, host: host_80_fwd

      host.vm.provider :virtualbox do |vb|
        # On MacOS DNS as-is with virtualbox does not seem to work. Workaround:
        if RUBY_PLATFORM.include? "darwin"
          vb.auto_nat_dns_proxy = false
          vb.customize ["modifyvm", :id, "--natdnsproxy1", "off"]
          vb.customize ["modifyvm", :id, "--natdnshostresolver1", "off"]
        end
      end

      if RUBY_PLATFORM.include? "darwin"
        host.vm.provision "shell", name: "fix-macos-dns", inline: <<~SHELL
          echo "nameserver 8.8.8.8" > /etc/resolv.conf
        SHELL
      end

      # It may not be the most elegant way, but if the box name contains the
      # word "windows" with a case insensitive match then use alternate
      # provisioners and more memory for the vm.

      # BEGIN box name based client config
      if "#{config.vm.box}" =~ /windows/i
        host.vm.provision :shell, name: "install-agent", :path => "scripts/install_cfengine_enterprise_windows_agent.bat", :args => "#{PACKAGE_RELEASE} #{PACKAGE_BUILD}"
        host.vm.provision :shell, name: "bootstrap", :path => "scripts/bootstrap_cfengine_windows_agent.bat", :args => "#{cfengine_hub_ip}"
        host.vm.provision :shell, name: "instructions",:path => "scripts/instructions.bat", :args => "#{cfengine_hub_ip}"
      else
        host.vm.provision :shell, name: "install-agent", :path => "scripts/install_cfengine_enterprise.sh", :args => "agent #{PACKAGE_RELEASE} #{PACKAGE_BUILD}"
        host.vm.provision :shell, name: "bootstrap", :path => "scripts/bootstrap_cfengine.sh", :args => "#{cfengine_hub_ip}"

        host.vm.provider "virtualbox" do |v|
          v.customize ["modifyvm", :id, "--memory", "256", "--cpus", "2"]
          #v.gui=true
          v.name = "#{project_name} agent #{host_name}"
        end # END box name based client config
        host.vm.provider :libvirt do |v|
          v.memory = 256
          v.cpus = 2
        end
      end # END client loop
      if "#{config.vm.box}" =~ /.*jammy64.*/i
        host.vm.provider "virtualbox" do |v|
          v.customize ["modifyvm", :id, "--memory", "512", "--cpus", "2"]
        end
      end
    end
  end
end
