#
# Cookbook:: irrigate-jenkins
# Recipe:: agent
#
# Copyright:: (C) 2016 The Orchard
#

require 'openssl'
require 'net/ssh'

jenkins_user = node['jenkins']['user']
jenkins_home_dir = node['jenkins']['jenkins_home_dir']

user jenkins_user do
  comment 'Jenkins user'
  home jenkins_home_dir
  manage_home true
  shell '/bin/bash'
end

cron 'jenkins_user_password_rotation' do
  weekday 3
  hour 0
  minute 30
  command "echo #{node['jenkins']['user']}:$(openssl rand -base64 24) | chpasswd"
end

# SSH Key for master authentication
ssh_authorize_key 'jenkins@all-agents.theorchard.local' do
  key 'AAAAB3NzaC1yc2EAAAADAQABAAACAQCiosRmf5zPirdrZ1PGjh5oekGS5V5wlb3/BH4XUq2VkpvCPZn0cKZqPhLNfVSRcyEm9Zbtx5Z+Vquzu/28g13VZx+JfJstEF35/ux0FPa2xjsnxmrkIakrhqe/xLzEJxMsFsWXmAiG0wTOv6dMrebpkvyshde1OkYOfqy6mJgStyxSFnk86Ij6krW6+6hFSbyOoYI4XPH98F0Ng8KAXy2OhqFIGpNMeoz+uRgmPgqVwC+/ZKyZO/xO01MUPBIUFTAD0DUEyXhrRyehGRopCK6jhxaclu6Nmy2jc7QLOWgSIr/Pn9KxwCa64MdOcGx962QMP0mYXUIH158HLejllDWwJMrzSXgKl2MQ96AdzbW72zV6did8ZUPPKLOaBAH5eNiDZzBlqLwWUQPBgHVxam3mCJdAUk/t2zowPsgGllgOSwvcRTX5/PJsWoo4lEOnqz32bcq2vcyB1JEWjFgt9BjzhrvoZvBudWPAeKXRP6HxotUpql5WzZtKuhre8RLhLjXY0az2TbSlCgPrgkr1OtdZfJzK6gel/q9HKt9bj99H3jEdROBkTfNIi5p3fbq4Ot9j70i9LcsT7Uikq5bS0j4spHClJrHkC+xXuwDtaP1oxglZARR/EVyWHTRp1HtRnTmccbyySN8BOMqh+KuhUr1IlnDANiIRFg6eeDa60hK8Bw=='
  home jenkins_home_dir
  user jenkins_user
end

# SSH Key for master authentication, from data bag
data_bag_name = node['jenkins']['agent_private_key_data_bag_name']
jenkins_keys = data_bag_item('secrets', data_bag_name)

key = OpenSSL::PKey::RSA.new(jenkins_keys['key'])
public_key = [key.to_blob].pack('m0')
key_name = "jenkins@#{node['jenkins']['stack_name']}"
ssh_authorize_key key_name do
  key public_key
  home jenkins_home_dir
  user jenkins_user
end

# SSH private key for OrchardCI github access
agent_ssh_key_location = jenkins_home_dir + '/.ssh/id_rsa'
agent_private_key = data_bag_item('secrets', 'jenkins_agent_ssh_private_key')
private_key = agent_private_key['key'].chomp
file agent_ssh_key_location do
  owner jenkins_user
  group jenkins_user
  mode '0600'
  content private_key
end

ssh_known_hosts_entry 'github.com' do
  hash_entries true
end

# Credentials for auto registration on master
case node['jenkins']['cli']['protocol']
when 'http'
  jenkins_credentials = data_bag_item('secrets', 'jenkins_cli_credentials')
  jenkins_cli_user = jenkins_credentials['username'].chomp
  jenkins_cli_pass = jenkins_credentials['password'].chomp
  file node['jenkins']['cli_credentials_file_path'] do
    owner 'root'
    group 'root'
    mode '0600'
    content "#{jenkins_cli_user}:#{jenkins_cli_pass}"
  end

when 'ssh'
  cli_data_bag_name = node['jenkins']['cli_private_key_data_bag_name']
  cli_private_key_data = data_bag_item('secrets', cli_data_bag_name)
  cli_private_key = cli_private_key_data['key'].chomp
  file node['jenkins']['cli_credentials_file_path'] do
    owner 'root'
    group 'root'
    mode '0600'
    content cli_private_key
  end
end

# Relax ssh host key checks or initial git clone and other ssh will fail
key_config = "Host *\n\tStrictHostKeyChecking no\n"
file "#{jenkins_home_dir}/.ssh/config" do
  owner jenkins_user
  group jenkins_user
  mode '0600'
  content key_config
end

if platform_family?('debian')
  # Prerequisite packages for packagecloud repositories
  prerequisite_packages = %w(
    ca-certificates
    curl
    dmidecode
    gpg
    locales-all
    lsb-release
    wget
  )

  prerequisite_packages.each do |name|
    package name
  end

  apt_repository 'mysql' do
    components node['jenkins']['agent']['mysql_apt_components']
    key 'BCA43417C3B485DD128EC6D4B7B3B788A8D3785C'
    keyserver 'keyserver.ubuntu.com'
    trusted false
    uri 'http://repo.mysql.com/apt/debian'
  end

  # Manually fetch and add GPG key with curl
  execute 'add_gpg_key' do
    command 'curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /etc/apt/keyrings/postgresql.gpg'
    not_if { ::File.exist?('/etc/apt/keyrings/postgresql.gpg') }
  end

  apt_repository 'postgresql' do
    components ['main']
    distribution "#{node['lsb']['codename']}-pgdg"
    signed_by '/etc/apt/keyrings/postgresql.gpg'
    trusted false
    uri 'https://apt.postgresql.org/pub/repos/apt'
  end

  apt_repository 'sbt' do
    components ['main']
    distribution 'all'
    key '2EE0EA64E40A89B84B2DF73499E82A75642AC823'
    keyserver 'keyserver.ubuntu.com'
    trusted false
    uri 'https://repo.scala-sbt.org/scalasbt/debian'
  end

  # Manually fetch and add Amazon Corretto GPG key with curl
  execute 'add_corretto_gpg_key' do
    command 'curl -fsSL https://apt.corretto.aws/corretto.key | gpg --dearmor -o /etc/apt/keyrings/corretto.gpg'
    not_if { ::File.exist?('/etc/apt/keyrings/corretto.gpg') }
  end

  apt_repository 'corretto' do
    components ['main']
    distribution 'stable'
    signed_by '/etc/apt/keyrings/corretto.gpg'
    trusted false
    uri 'https://apt.corretto.aws'
  end

  packages = %w(
    alsa-tools
    ansible
    awscli
    bison
    build-essential
    bzip2
    cron
    ffmpeg
    fontconfig
    fonts-recommended
    gcc
    git
    g++
    htop
    java-21-amazon-corretto-jdk
    libjpeg62-turbo
    libjpeg62-turbo-dev
    libmysqlclient-dev
    libmysqlclient24
    libreadline8
    libreadline-dev
    libsqlite3-dev
    jq
    make
    maven
    mysql-community-client
    nfs-common
    nmap
    openjdk-17-jdk
    openjdk-17-jre
    openjdk-17-jdk-headless
    openjdk-17-jre-headless
    postfix
    postgresql-client
    postgresql-common
    psmisc
    readline-common
    redis
    redis-tools
    sbt
    sqlite3
    sshpass
    strace
    unzip
    xfonts-75dpi
    xvfb
    zip
    zlib1g
    zlib1g-dev
  )

  packages.each do |name|
    package name
  end
end

execute 'permit_jenkins_docker' do
  command "gpasswd -a #{jenkins_user} docker &&" \
           'touch /var/cache/.dockerenabled'
  creates '/var/cache/.dockerenabled'
  notifies :restart, 'service[docker]'
end

# Override asound.conf to bypass virtual soundcard drivers
template '/etc/asound.conf' do
  source 'asound.conf.erb'
  mode '0644'
  owner 'root'
  group 'root'
end

# Docker disk space cleanup
cron 'docker_cleanup' do
  hour '*/2'
  minute '0'
  user 'root'
  command '/usr/bin/docker rm -v $(/usr/bin/docker ps -a -q -f status=exited) >/dev/null 2>&1'
end

# Docker images cleanup to remove all unused images.
cron 'docker_images_cleanup' do
  hour '*'
  minute '0'
  user 'root'
  command '/usr/bin/docker system prune -a -f --filter until=8h >/dev/null 2>&1'
end

# Remove anything in /tmp that has been modified more than an hour ago.
cron 'temp_cleanup' do
  hour '*'
  minute '30'
  user 'root'
  command '/bin/find /tmp -type f -mmin +60 -exec rm -rf {} \; > /dev/null 2>&1'
end

# Remove any jobs that have been modified more than 2 days ago.
cron 'jobs_cleanup' do
  hour '*'
  minute '40'
  user 'root'
  command "/bin/find #{jenkins_home_dir}/workspace -maxdepth 1 -type d -mtime +2 -exec rm -rf {} \\; > /dev/null 2>&1"
end

# By default the Workspace Cleanup plugin uses "deferred wipeout", which means that workspace directories are renamed
# rather than deleted. This deferred wipeout will fail if the Jenkins user does not have permissions to delete the contents
# of the workspace (for example when root-owned files have been generated by a Docker container). This cron will take care
# of these directories, and they can be deleted irrespective of age.
cron 'old_workspace_cleanup' do
  hour '*'
  minute '20'
  user 'root'
  command "/bin/find #{jenkins_home_dir}/workspace/*_ws-cleanup_* -maxdepth 0 -type d -exec rm -rf {} \\; > /dev/null 2>&1"
end

# CIS 4.1.1 - allow auditd configuration to remain compliant but clean Docker audit logs, which fill up to 10s of GB/day.
# If CIS score were not affected, we would simply adjust auditd rules, but instead handle out-of-band.
cron 'auditd_cleanup' do
  hour '*'
  minute '*/15'
  user 'root'
  command '/bin/find /var/log/audit -type f -mmin +10 -exec rm -rf {} \; > /dev/null 2>&1'
end

cookbook_file '/root/cleanup_containers.sh' do
  source 'cleanup_containers.sh'
  mode '0755'
  owner 'root'
  group 'root'
end

cron 'docker_running_containers_cleanup' do
  hour '*'
  minute '*/15'
  user 'root'
  command "/usr/bin/bash cleanup_containers.sh #{node['jenkins']['agent']['docker_run_limit_seconds']} >>#{node['jenkins']['agent']['container_clean_up_log_file']} 2>&1"
end
