#
# Cookbook Name:: docker-grid
# Recipe:: engine
#
# Copyright 2016, whitestar
#
# 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.
#

# https://dcos.io/docs/1.8/administration/installing/custom/system-requirements/

bash 'systemctl_daemon-reload' do
  code <<-EOH
    systemctl daemon-reload
  EOH
  action :nothing
end

if node['docker-grid']['engine']['storage-driver'] == 'overlay'
  bash 'load_overlayfs_kernel_module' do
    code <<-EOH
      modprobe overlay
    EOH
    not_if 'lsmod | grep overlay'
  end

  template '/etc/modules-load.d/overlay.conf' do
    source  'etc/modules-load.d/overlay.conf'
    owner 'root'
    group 'root'
    mode '0644'
  end
end

log 'reboot_message' do
  message 'Please reboot this machine because of kernel boot option modified.'
  level :warn
  action :nothing
end

userns_remap = node['docker-grid']['engine']['userns-remap']
if !userns_remap.nil? && !userns_remap.empty?
  unless Gem::Version.create(node['docker-grid']['engine']['version'].tr('~', '-')) >= Gem::Version.create('1.10')
    # tr('~', '-') for Ubuntu.
    Chef::Application.fatal!('Docker version must be 1.10 or later for userns-remap.')  # and exit.
  end
  # By default user namespace feature is inactive in RHEL family (>= 7.2).
  if node['platform_family'] == 'rhel'
    unless Gem::Version.create(node['platform_version']) >= Gem::Version.create('7.2')
      Chef::Application.fatal!('Platform version must be 7.2 or later for kernel user namespace feature.')  # and exit.
    end

    bash 'enable_user_namespace_feature_of_kernerl' do
      code <<-"EOH"
        grubby --args='user_namespace.enable=1' --update-kernel=/boot/vmlinuz-#{node['kernel']['release']}
      EOH
      not_if "grubby --info=/boot/vmlinuz-#{node['kernel']['release']} | grep 'user_namespace.enable=1'"
      notifies :write, 'log[reboot_message]'
    end
  end

  subid_files = [
    '/etc/subuid',
    '/etc/subgid',
  ]

  subid_files.each {|subid_file|
    file subid_file do
      owner 'root'
      group 'root'
      mode '0644'
      action :touch
      not_if { File.exist?(subid_file) }
    end
  }

  this_recipe = self
  remap_user = userns_remap == 'default' ? 'dockremap' : userns_remap
  ruby_block 'adds_subid_entries' do
    action :run
    not_if "cat /etc/subuid | grep #{remap_user}"
    not_if "cat /etc/subgid | grep #{remap_user}"
    notifies :restart, 'service[docker]'
    block do
      subid_files.each {|subid_file|
        max_start_id = 100_000
        offset = 0
        already_exist = false

        begin
          File.open(subid_file) {|file|
            file.each_line {|line|
              entry = line.split(':')
              if entry[0] == remap_user
                already_exist = true
                break
              end
              if entry[1].to_i >= max_start_id
                max_start_id = entry[1].to_i
                offset = entry[2].to_i
              end
            }
          }

          if already_exist
            this_recipe.log "#{remap_user} already exists in #{subid_file}"
          else
            File.open(subid_file, 'a') {|file|
              entry_str = "#{remap_user}:#{max_start_id + offset}:65536"
              this_recipe.log "#{remap_user} (#{entry_str}) is added in #{subid_file}"
              file.puts entry_str
            }
          end
        rescue IOError => e
          puts e
        end
      }
    end
  end
end

directory '/etc/systemd/system/docker.service.d' do
  owner 'root'
  group 'root'
  mode '0755'
  action :create
end

template '/etc/systemd/system/docker.service.d/override.conf' do
  source  'etc/systemd/system/docker.service.d/override.conf'
  owner 'root'
  group 'root'
  mode '0644'
  notifies :run, 'bash[systemctl_daemon-reload]'
  notifies :restart, 'service[docker]'
end

case node['platform_family']
when 'rhel'
  # https://dcos.io/docs/1.8/administration/installing/custom/system-requirements/install-docker-centos/
  template '/etc/yum.repos.d/docker.repo' do
    source  'etc/yum.repos.d/docker.repo'
    owner 'root'
    group 'root'
    mode '0644'
  end

  [
    'docker-engine-selinux',
    'docker-engine',
  ].each {|pkg|
    resources(package: pkg) rescue package pkg do
      action :install
      version node['docker-grid']['engine']['version']
      # dockerrepo is disabled by default to prevent automatic update.
      options '--enablerepo=dockerrepo'
    end
  }
when 'debian'
  # https://docs.docker.com/engine/installation/linux/ubuntulinux/
  pkgs = [
    'apt-transport-https',
    'ca-certificates',
  ]

  if node['docker-grid']['engine']['storage-driver'] == 'aufs'
    pkgs += [
      "linux-image-extra-#{node['os_version']}",
      'linux-image-extra-virtual',
    ]
  end

  pkgs.each {|pkg|
    resources(package: pkg) rescue package pkg do
      action :install
    end
  }

  template '/etc/apt/sources.list.d/docker.list' do
    source  'etc/apt/sources.list.d/docker.list'
    owner 'root'
    group 'root'
    mode '0644'
  end

  apt_repo_config = node['docker-grid']['apt_repo']
  bash 'apt-key_adv_docker_tools_key' do
    code <<-"EOH"
      apt-key adv --keyserver #{apt_repo_config['keyserver']} --recv-keys #{apt_repo_config['recv-keys']}
      apt-get update
    EOH
    not_if 'apt-key list | grep -i docker'
  end

  # Pinning Docker version
  template '/etc/apt/preferences.d/docker.pref' do
    source  'etc/apt/preferences.d/docker.pref'
    owner 'root'
    group 'root'
    mode '0644'
  end

  [
    'docker-engine',
  ].each {|pkg|
    resources(package: pkg) rescue package pkg do
      action :install
      version node['docker-grid']['engine']['version']
    end
  }
end

service 'docker' do
  action [:start, :enable]
end

users = node['docker-grid']['engine']['users_allow']
group 'docker' do
  members users unless users.empty?
  action :create
  append true
end
