#
# Copyright (C) 2016 Red Hat, Inc.
#
# Licensed 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.

# Set up PXE boot for Ironic
#
# === Parameters
#
# [*package_ensure*]
#   (optional) Control the ensure parameter for the package resource
#   Defaults to 'present'
#
# [*tftp_root*]
#   (optional) Folder location to deploy PXE boot files
#   Defaults to '/tftpboot'
#
# [*http_root*]
#   (optional) Folder location to deploy HTTP PXE boot
#   Defaults to '/httpboot'
#
# [*http_port*]
#   (optional) port used by the HTTP service serving introspection and
#   deployment images.
#   Defaults to '8088'
#
# [*pxelinux_path*]
#   (optional) Path to directory containing pxelinux.0 .
#   Setting this to False will skip syslinux related resources.
#   Defaults to '$::ironic::params::pxelinux_path'
#
# [*syslinux_path*]
#   (optional) Path to directory containing syslinux files.
#   Setting this to False will skip syslinux related resources.
#   Defaults to '$::ironic::params::syslinux_path'
#
# [*syslinux_files*]
#   (optional) Array of PXE boot files to copy from $syslinux_path to $tftp_root.
#   Defaults to '$::ironic::params::syslinux_files'
#
# [*tftp_bind_host*]
#   (optional) The IP address TFTP server will listen on for TFTP.
#   Defaults to undef (listen on all ip addresses).
#
# [*ipxe_name_base*]
#   (optional) Beginning of the source file name which is copied to
#   $tftproot/ipxe.efi. Setting this to 'ipxe-snponly' on CentOS/RHEL would
#   results in the source file being /usr/share/ipxe/ipxe-snponly-x86_64.efi.
#   Defaults to $::ironic::params::ipxe_name_base
#
# [*uefi_ipxe_bootfile_name*]
#   (optional) Name of efi file used to boot servers with iPXE + UEFI. This
#   should be consistent with the uefi_ipxe_bootfile_name parameter in pxe
#   driver.
#   Defaults to $::ironic::params::uefi_ipxe_bootfile_name
#
# [*uefi_pxe_bootfile_name*]
#   (optional) Name of efi file used to boot servers with PXE + UEFI. This
#   should be consistent with the uefi_pxe_bootfile_name parameter in pxe
#   driver.
#   Defaults to 'bootx64.efi'
#
# [*tftp_use_xinetd*]
#   (optional) Override wheter to use xinetd instead of dnsmasq as the tftp
#   service facilitator.
#   Defaults to ironic::params::xinetd_available
#
# [*dnsmasq_log_facility*]
#   (optional) Log facility of the dnsmasq process to server tftp server.
#   Defaults to undef
#
# DEPRECATED PARAMETERS
#
# [*enable_ppc64le*]
#   (optional) Boolean value to dtermine if ppc64le support should be enabled
#   Defaults to undef
#
class ironic::pxe (
  $package_ensure          = 'present',
  $tftp_root               = '/tftpboot',
  $http_root               = '/httpboot',
  $http_port               = '8088',
  $pxelinux_path           = $::ironic::params::pxelinux_path,
  $syslinux_path           = $::ironic::params::syslinux_path,
  $syslinux_files          = $::ironic::params::syslinux_files,
  $tftp_bind_host          = undef,
  $ipxe_name_base          = $::ironic::params::ipxe_name_base,
  $uefi_ipxe_bootfile_name = $::ironic::params::uefi_ipxe_bootfile_name,
  $uefi_pxe_bootfile_name  = 'bootx64.efi',
  $tftp_use_xinetd         = $::ironic::params::xinetd_available,
  $dnsmasq_log_facility    = undef,
  # DEPRECATED PARAMETERS
  $enable_ppc64le          = undef
) inherits ironic::params {

  include ironic::deps
  include ironic::pxe::common

  if $enable_ppc64le != undef {
    warning('The ironic::pxe::enable_ppc64le parameter is deprecated and has no effect.')
  }

  $tftp_root_real = pick($::ironic::pxe::common::tftp_root, $tftp_root)
  $http_root_real = pick($::ironic::pxe::common::http_root, $http_root)
  $http_port_real = pick($::ironic::pxe::common::http_port, $http_port)
  $uefi_ipxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_ipxe_bootfile_name, $uefi_ipxe_bootfile_name)
  $uefi_pxe_bootfile_name_real = pick($::ironic::pxe::common::uefi_pxe_bootfile_name, $uefi_pxe_bootfile_name)

  if $::os['family'] == 'RedHat' {
    $arch = "-${::os['architecture']}"
  } else {
    $arch = ''
  }

  file { $tftp_root_real:
    ensure  => 'directory',
    seltype => 'tftpdir_t',
    owner   => $::ironic::params::user,
    group   => $::ironic::params::group,
    require => Anchor['ironic::config::begin'],
    before  => Anchor['ironic::config::end'],
  }

  ensure_resource( 'package', 'ironic-common', {
    ensure => $package_ensure,
    name   => $::ironic::params::common_package_name,
    tag    => ['openstack', 'ironic-package'],
  })

  file { "${tftp_root_real}/pxelinux.cfg":
    ensure  => 'directory',
    seltype => 'tftpdir_t',
    owner   => $::ironic::params::user,
    group   => $::ironic::params::group,
    require => Anchor['ironic::install::end'],
    tag     => 'ironic-tftp-file',
  }

  file { $http_root_real:
    ensure  => 'directory',
    seltype => 'httpd_sys_content_t',
    owner   => $::ironic::params::user,
    group   => $::ironic::params::group,
    require => Anchor['ironic::config::begin'],
    before  => Anchor['ironic::config::end'],
  }

  if $tftp_use_xinetd {
    if ! $::ironic::params::xinetd_available {
      fail('xinetd is not available in this distro. Please use tftp_use_xinetd=false')
    }

    ensure_resource( 'package', 'tftp-server', {
      'ensure' => $package_ensure,
      'name'   => $::ironic::params::tftpd_package,
      'tag'    => ['openstack', 'ironic-ipxe', 'ironic-support-package'],
    })

    $options = "--map-file ${tftp_root_real}/map-file"

    include xinetd

    xinetd::service { 'tftp':
      port        => '69',
      bind        => $tftp_bind_host,
      protocol    => 'udp',
      server_args => "${options} ${tftp_root_real}",
      server      => '/usr/sbin/in.tftpd',
      socket_type => 'dgram',
      cps         => '100 2',
      per_source  => '11',
      wait        => 'yes',
      subscribe   => Anchor['ironic::install::end'],
    }

    file { "${tftp_root_real}/map-file":
      ensure  => 'present',
      content => "r ^([^/]) ${tftp_root_real}/\\1",
    }
  } else {
    if ! $::ironic::params::dnsmasq_tftp_package {
      fail('ironic-dnsmasq-tftp-server is not available in this distro. Please use tftp_use_xnetd=true')
    }

    # NOTE(tkajinam): We can't use puppet-xinetd for cleanup because the xinetd
    #                 class forcefully installs the xinetd package.
    warning('Any prior xinetd based tftp server should be disabled and removed from the system.')

    file { "${tftp_root_real}/map-file":
      ensure  => 'absent',
    }

    package { 'dnsmasq-tftp-server':
      ensure => $package_ensure,
      name   => $::ironic::params::dnsmasq_tftp_package,
      tag    => ['openstack', 'ironic-ipxe', 'ironic-support-package'],
    }

    file { '/etc/ironic/dnsmasq-tftp-server.conf':
      ensure  => 'present',
      mode    => '0644',
      owner   => 'root',
      group   => 'root',
      content => template('ironic/dnsmasq_tftp_server.erb'),
    }

    service { 'dnsmasq-tftp-server':
      ensure    => 'running',
      name      => $::ironic::params::dnsmasq_tftp_service,
      enable    => true,
      hasstatus => true,
      subscribe => File['/etc/ironic/dnsmasq-tftp-server.conf'],
    }

    Package['dnsmasq-tftp-server'] ~> Service['dnsmasq-tftp-server']
    File[$tftp_root_real] -> Service['dnsmasq-tftp-server']
  }

  # NOTE(tkajinam): Ubuntu/Debian requires a separate package for pxelinux.0
  #                 and the file is stored in a different path.
  if $pxelinux_path {
    if $ironic::params::pxelinux_package {
      package { 'pxelinux':
        ensure => $package_ensure,
        name   => $::ironic::params::pxelinux_package,
        tag    => ['openstack', 'ironic-ipxe', 'ironic-support-package'],
      }
    }

    ironic::pxe::tftpboot_file { 'pxelinux.0':
      source_directory      => $pxelinux_path,
      destination_directory => $tftp_root_real,
      require               => Anchor['ironic-inspector::install::end'],
    }
  }

  if $syslinux_path {
    ensure_resource( 'package', 'syslinux', {
      ensure => $package_ensure,
      name   => $::ironic::params::syslinux_package,
      tag    => ['openstack', 'ironic-ipxe', 'ironic-support-package'],
    })

    ironic::pxe::tftpboot_file { $syslinux_files:
      source_directory      => $syslinux_path,
      destination_directory => $tftp_root_real,
      require               => Anchor['ironic-inspector::install::end'],
    }
  }

  ensure_resource( 'package', 'ipxe', {
    ensure => $package_ensure,
    name   => $::ironic::params::ipxe_package,
    tag    => ['openstack', 'ironic-ipxe', 'ironic-support-package'],
  })

  file { "${tftp_root_real}/undionly.kpxe":
    ensure    => 'file',
    seltype   => 'tftpdir_t',
    owner     => $::ironic::params::user,
    group     => $::ironic::params::group,
    mode      => '0744',
    source    => "${::ironic::params::ipxe_rom_dir}/undionly.kpxe",
    backup    => false,
    show_diff => false,
    require   => Anchor['ironic-inspector::install::end'],
    tag       => 'ironic-tftp-file',
  }

  file { "${tftp_root_real}/${uefi_ipxe_bootfile_name_real}":
    ensure    => 'file',
    seltype   => 'tftpdir_t',
    owner     => $::ironic::params::user,
    group     => $::ironic::params::group,
    mode      => '0744',
    source    => "${::ironic::params::ipxe_rom_dir}/${ipxe_name_base}${arch}.efi",
    backup    => false,
    show_diff => false,
    require   => Anchor['ironic-inspector::install::end'],
    tag       => 'ironic-tftp-file',
  }

  ensure_resource( 'package', 'grub-efi', {
    ensure => $package_ensure,
    name   => $::ironic::params::grub_efi_package,
    tag    => ['openstack', 'ironic-support-package'],
  })

  file { "${tftp_root_real}/grubx64.efi":
    ensure    => 'file',
    seltype   => 'tftpdir_t',
    owner     => $::ironic::params::user,
    group     => $::ironic::params::group,
    mode      => '0744',
    source    => "${::ironic::params::grub_efi_file}",
    backup    => false,
    show_diff => false,
    require   => Anchor['ironic-inspector::install::end'],
    tag       => 'ironic-tftp-file',
  }

  ensure_resource( 'package', 'shim', {
    ensure => $package_ensure,
    name   => $::ironic::params::shim_package,
    tag    => ['openstack', 'ironic-support-package'],
  })

  file { "${tftp_root_real}/${uefi_pxe_bootfile_name_real}":
    ensure    => 'file',
    seltype   => 'tftpdir_t',
    owner     => $::ironic::params::user,
    group     => $::ironic::params::group,
    mode      => '0744',
    source    => "${::ironic::params::shim_file}",
    backup    => false,
    show_diff => false,
    require   => Anchor['ironic-inspector::install::end'],
    tag       => 'ironic-tftp-file',
  }

  File["${tftp_root_real}"] -> File<| tag == 'ironic-tftp-file' |>

  include apache

  apache::vhost { 'ipxe_vhost':
    priority   => '10',
    options    => ['Indexes','FollowSymLinks'],
    docroot    => $http_root_real,
    port       => $http_port_real,
    # FIXME: for backwards compatibility we have to add listen to the ipxe vhost
    add_listen => false,
  }
  # FIXME: this can be removed after ipxe element is removed from instack-undercloud
  concat::fragment { 'ipxe_vhost-listen':
    target  => '10-ipxe_vhost.conf',
    order   => 1337,
    content => "Listen ${http_port_real}",
  }
}
