#
# Cookbook:: irrigate-orchard_base
# Recipe:: splunk_agent
#
# Copyright: The Orchard
#
splunk_directory = node['splunk']['home_directory']
splunk_user      = node['splunk']['user']
splunk_group     = node['splunk']['group']
splunk_version   = node['splunk']['version']

group splunk_group

user splunk_user do
  home splunk_directory
  manage_home true
  group splunk_group
end

if node.attribute?('ec2') && !node['ec2']['instance_id'].nil?

  # If data_bag_name is specified, read token from encrypted data bag
  if node['splunk']['packagecloud_token_data_bag_name'] && !node['splunk']['packagecloud_token_data_bag_name'].empty?
    token_data_bag                 = data_bag_item('secrets', node['splunk']['packagecloud_token_data_bag_name'])
    packagecloud_splunk_read_token = token_data_bag['packagecloud_read_token'].chomp
  else
    raise 'Could not find Splunk packagecloud data bag'
  end

  prerequisite_packages = %w(
    acl
    apt-transport-https
    gnupg
  )

  prerequisite_packages.each do |package_name|
    package package_name do
      retries 10
      retry_delay 10
    end
  end

  template '/etc/apt/auth.conf.d/orchard-splunk' do
    source 'apt_auth.conf.erb'
    owner 'root'
    group 'root'
    mode '0600'
    variables(
      repo_url: 'https://packagecloud.io/orchardit/splunk/debian',
      repo_token: packagecloud_splunk_read_token
    )
  end

  # Manually fetch and add GPG key with curl (follows redirects now that packagecloud gpg urls return 302)
  execute 'add_packagecloud_splunk_gpg_key' do
    command "curl -fsSL https://#{packagecloud_splunk_read_token}@packagecloud.io/orchardit/splunk/gpgkey | gpg --dearmor -o /etc/apt/trusted.gpg.d/orchard-splunk.gpg"
    not_if { ::File.exist?('/etc/apt/trusted.gpg.d/orchard-splunk.gpg') }
  end

  # Determine apt architecture from node metadata (supports amd64 and arm64)
  arch_map = {
    'x86_64' => 'amd64',
    'amd64' => 'amd64',
    'aarch64' => 'arm64',
    'arm64' => 'arm64',
  }
  apt_arch = arch_map.fetch(node.dig('kernel', 'machine').to_s, 'amd64')

  apt_repository 'orchard-splunk' do
    action :add
    components ['main']
    uri 'https://packagecloud.io/orchardit/splunk/debian'
    signed_by '/etc/apt/trusted.gpg.d/orchard-splunk.gpg'
    arch apt_arch
  end

  package 'splunkforwarder' do
    notifies :run, 'execute[set_acls]', :immediately
    notifies :run, 'execute[set_splunk_home_ownership]', :immediately
    retries 10
    retry_delay 10
  end

  execute 'set_acls' do
    command "setfacl -d -m u:#{node['splunk']['user']}:r-x /var/log/ && setfacl -R -m u:#{node['splunk']['user']}:r-x /var/log/"
    action :nothing
  end

  execute 'set_splunk_home_ownership' do
    command "chown -R #{node['splunk']['user']}:#{node['splunk']['user']} #{node['splunk']['home_directory']}"
    action :nothing
  end

  custom_configuration_files = [
    'deploymentclient.conf',
    'inputs.conf',
    'outputs.conf',
  ]

  custom_configuration_files.each do |config_file|
    template "#{node['splunk']['home_directory']}/etc/system/local/#{config_file}" do
      source "splunk_#{config_file}.erb"
      sensitive true
      owner splunk_user
      group splunk_group
      notifies :restart, 'systemd_unit[splunk-agent.service]', :delayed
    end
  end

  systemd_unit 'splunk-agent.service' do
    content(
      Unit: {
        Description: 'Splunk Agent',
        Documentation: 'https://www.splunk.com',
        After: 'network.target',
      },
      Service: {
        User: splunk_user,
        Group: splunk_group,
        WorkingDirectory: splunk_directory,
        Type: 'forking',
        ExecStart: "#{splunk_directory}/bin/splunk start "\
          '--accept-license --answer-yes --no-prompt',
        ExecStop: "#{splunk_directory}/bin/splunk stop",
        TimeoutStartSec: '10s',
        TimeoutStopSec: '30s',
        RestartSec: '10s',
        Restart: 'on-failure',
      },
      Install: {
        WantedBy: 'multi-user.target',
      }
    )
    triggers_reload true
    action [:create, :enable]
  end
else
  packages = %w(
    grep
    procps-ng
  )

  # Install packages
  packages.each do |name|
    package name
  end

  package 'splunkforwarder' do
    action :remove
    notifies :run, 'execute[clean_splunk_directory]', :immediately
  end

  # Clean up splunk directory
  execute 'clean_splunk_directory' do
    command "/usr/bin/rm -rf /opt/splunkforwarder/* && /usr/bin/rm -rf /opt/splunk-#{splunk_version}.tar.gz"
    action :nothing
  end

  # Get AWS credentials and S3 installer path from encrypted data bag
  data_bag_name          = node['splunk']['aws_credentials_data_bag_name']
  splunk_aws_credentials = data_bag_item('secrets', data_bag_name)
  s3_bucket              = splunk_aws_credentials['s3_bucket'].chomp
  s3_remote_path         = splunk_aws_credentials['s3_remote_path'].chomp
  access_key_id          = splunk_aws_credentials['aws_access_key_id'].chomp
  secret_access_key      = splunk_aws_credentials['aws_secret_access_key'].chomp

  # only_if necessary here as systemic mode changes make this not idempotent
  s3_file "/opt/splunk-#{splunk_version}.tar.gz" do
    remote_path s3_remote_path
    bucket s3_bucket
    aws_access_key_id access_key_id
    aws_secret_access_key secret_access_key
    action :create
    not_if { ::File.exist?("/opt/splunk-#{splunk_version}.tar.gz") }
    notifies :run, 'execute[remove_splunk]', :immediately
  end

  # This is only run when a new file is pulled down from S3.
  # Add only_if to prevent it from running (and failing) on initial bootstrap
  # Remove only files (and not the directory) or the following step fails.
  execute 'remove_splunk' do
    command "find #{splunk_directory} -type f -exec rm -rf {} \\;"
    only_if { ::File.exist?("#{splunk_directory}/bin/splunk") }
    action :nothing
  end

  tar_extract "/opt/splunk-#{splunk_version}.tar.gz" do
    action :extract_local
    target_dir splunk_directory
    tar_flags '--overwrite'
    user splunk_user
    creates "#{splunk_directory}/bin/splunk"
  end

  splunk_acl_cron_script = "#{splunk_directory}/cron_script.sh"

  file splunk_acl_cron_script do
    owner splunk_user
    group splunk_group
    mode '0755'
  end

  cron 'run_splunk_acl_cron_script' do
    minute '*/10'
    hour '*'
    day '*'
    user 'root'
    path '/bin:/sbin:/usr/bin:/usr/sbin'
    command "/bin/bash #{splunk_acl_cron_script}"
  end

  splunk_remote_host = node['splunk']['remote_host']
  splunk_remote_port = node['splunk']['remote_port']

  systemd_unit 'splunk-agent.service' do
    content(
      Unit: {
        Description: 'Splunk Agent',
        Documentation: 'https://www.splunk.com',
        After: 'network.target',
      },
      Service: {
        User: splunk_user,
        Group: splunk_group,
        WorkingDirectory: splunk_directory,
        Type: 'forking',
        ExecStart: "#{splunk_directory}/bin/splunk start "\
          '--accept-license --answer-yes --auto-ports --no-prompt',
        ExecStartPost: "#{splunk_directory}/bin/splunk set deploy-poll "\
          "#{splunk_remote_host}:#{splunk_remote_port} --accept-license "\
          '--answer-yes --auto-ports --no-prompt -auth admin:changeme',
        ExecStop: "#{splunk_directory}/bin/splunk stop",
        TimeoutStartSec: '10s',
        TimeoutStopSec: '30s',
        RestartSec: '10s',
        Restart: 'on-failure',
      },
      Install: {
        WantedBy: 'multi-user.target',
      }
    )
    triggers_reload true
    action [:create, :enable]
  end
end

service 'splunk-agent' do
  supports restart: true, status: true, reload: false
  action [:enable, :start]
end
