#!/usr/bin/env ruby
require 'optparse'
require 'fileutils'
require 'net/http'
require 'etc'
require 'facter'

options = {}
OptionParser.new do |opts|
  opts.banner = "Usage: generate_container.rb [options]"

  opts.on("--fqdn [FQDN]", "FQDN") do |f|
    options[:fqdn] = f
  end

  opts.on("--ip [IP]", "IP address") do |i|
    options[:ip] = i
  end

  opts.on("--cidr [CIDR]", "CIDR") do |c|
    options[:cidr] = c
  end

  opts.on("--gateway [GATEWAY]", "Gateway") do |g|
    options[:gateway] = g
  end

  opts.on("--ip6 [IPv6]", "IPv6") do |i6|
    options[:ip6] = i6
  end

  opts.on("--cidr6 [CIDR]", "CIDR v6") do |c6|
    options[:cidr6] = c6
  end

  opts.on("--gateway6 [GATEWAY]", "Gateway v6") do |g6|
    options[:gateway6] = g6
  end

  opts.on("--os [VERSION]", "OS version") do |os|
    options[:os] = os
  end

  opts.on("--version [VERSION]", "OS version") do |v|
    options[:version] = v
  end

  opts.on("--puppet [PUPPET SERVER]", "Puppet server") do |p|
    options[:puppet] = p
  end

  opts.on("--ippuppet [IP PUPPET SERVER]", "IP Puppet server") do |ph|
    options[:ippuppet] = ph
  end

  opts.on("--ip6puppet [IPv6 PUPPET SERVER]", "IPv6 Puppet server") do |p6h|
    options[:ip6puppet] = p6h
  end

  opts.on("--dns [DNS SERVER]", "DNS Server") do |dn|
    options[:dns] = dn
  end

  opts.on("--idhypervisor [ID Hypervisor]", "ID Hypervisor") do |ih|
    options[:idhypervisor] = ih
  end

  opts.on("--provider [Provider]", "Provider") do |pr|
    options[:provider] = pr
  end

end.parse!

ip_split = options[:ip].split(".")
mac = "52:54:00:#{options[:idhypervisor]}0:"+ip_split[2].to_i.to_s(16).rjust(2,'0')+":"+ip_split[3].to_i.to_s(16).rjust(2,'0')
mac6 = "52:54:00:#{options[:idhypervisor]}1:"+ip_split[2].to_i.to_s(16).rjust(2,'0')+":"+ip_split[3].to_i.to_s(16).rjust(2,'0')

Dir.chdir('/srv')

if options[:version].nil? then
  options[:version] = "7"
end

if options[:os].nil? then
  options[:os] = "centos"
end

if options[:os] == "fedora" then
   options[:repo] = "--disablerepo='*' --enablerepo='fedora'"
else
  options[:repo] = ""
end

if not File.exist?("/srv/#{options[:os]}#{options[:version]}.tar") then
  system("yum -y --installroot=/srv/tmprootfs --releasever=#{options[:version]} #{options[:repo]} --nogpg install systemd passwd yum #{options[:os]}-release vim-minimal openssh-server procps-ng iputils emacs-nox wget curl git")
  system("yum -y --installroot=/srv/tmprootfs --releasever=#{options[:version]} #{options[:repo]} --nogpg groupinstall 'Minimal Install'")
  system("yum -y --installroot=/srv/tmprootfs --releasever=#{options[:version]} #{options[:repo]} --nogpg groupinstall 'Development Tools'")
  Dir.chdir("tmprootfs")
  system("tar cvf #{options[:os]}#{options[:version]}.tar --exclude '#{options[:os]}#{options[:version]}.tar' .")
  Dir.chdir("..")
  File.rename("tmprootfs/#{options[:os]}#{options[:version]}.tar","#{options[:os]}#{options[:version]}.tar")
  FileUtils.rm_rf("tmprootfs")
end

options[:hostname] = options[:fqdn].split(".").first

Dir.chdir('/var/lib/lxc')
if not File.exists?(options[:hostname])
  FileUtils.mkdir_p("/var/lib/lxc/"+options[:hostname]+"/rootfs")
  Dir.chdir("/var/lib/lxc/"+options[:hostname]+"/rootfs")
  system("tar xvf /srv/#{options[:os]}#{options[:version]}.tar")
end

pubkey = File.read("/root/.ssh/id_ecdsa.pub")

chroot = Process.fork do
  Dir.chdir("/")
  Dir.chroot("/var/lib/lxc/"+options[:hostname]+"/rootfs")
  filename = "/etc/sysconfig/network"
  outdata = "NETWORKING=yes\n"
  
  File.open(filename, 'w+') do |out|
    out << outdata
  end  
  
  outdata = "#{options[:fqdn]}\n"
  File.open("/etc/hostname", 'w+') do |out|
    out << outdata
  end


  outdata = <<EOF
net.ipv6.conf.all.dad_transmits = 0
net.ipv6.conf.all.accept_dad = 0
net.ipv6.conf.lo.dad_transmits = 0
net.ipv6.conf.lo.accept_dad = 0
net.ipv6.conf.eth1.dad_transmits = 0
net.ipv6.conf.eth1.accept_dad = 0
EOF


  File.open("/etc/sysctl.conf", 'w+') do |out|
    out << outdata
  end

  outdata = <<EOF
DEVICE=eth0
TYPE=Ethernet
IPADDR=#{options[:ip]}
PREFIX=#{options[:cidr]}
GATEWAY=#{options[:gateway]}
ONBOOT=yes
BOOTPROTO=none
NM_CONTROLLED=no
DELAY=0
EOF
  File.open("/etc/sysconfig/network-scripts/ifcfg-eth0", 'w+') do |out|
    out << outdata
 end


  if(options[:provider] == "ovh") then
    outdata = <<EOF
DEVICE=eth1
TYPE=Ethernet
IPV6INIT=yes
IPV6_AUTOCONF=no
IPV6ADDR=#{options[:ip6]}/#{options[:cidr6]}
ONBOOT=yes
BOOTPROTO=none
NM_CONTROLLED=no
DELAY=0
EOF
  elsif(options[:provider] == "hetzner") then
    outdata = <<EOF
DEVICE=eth1
TYPE=Ethernet
IPV6INIT=yes
IPV6_AUTOCONF=no
IPV6ADDR=#{options[:ip6]}/#{options[:cidr6]}
IPV6_DEFAULTGW=#{options[:gateway6]}
IP6_DEFAULTDEV=eth1
ONBOOT=yes
BOOTPROTO=none
NM_CONTROLLED=no
DELAY=0
EOF
  end

  File.open("/etc/sysconfig/network-scripts/ifcfg-eth1", 'w+') do |out|
    out << outdata
 end

 if(options[:provider] == "ovh") then
   outdata = <<EOF
if [[ "$1" == "eth1" ]]
then
  /sbin/ip -f inet6 route add #{options[:gateway6]} dev eth1
  /sbin/ip -f inet6 route add default via #{options[:gateway6]}
fi
EOF
   File.open("/sbin/ifup-local", 'w+') do |out|
      out << outdata
    end

   File.chmod(0755,"/sbin/ifup-local")  
 end
  
  outdata = <<EOF
nameserver #{options[:dns]}
EOF
  
  File.open("/etc/resolv.conf", 'w+') do |out|
    out << outdata
  end
  

  outdata = <<EOF
127.0.0.1       localhost
#{options[:ip]}             #{options[:fqdn]} #{options[:hostname]}
#{options[:ip6puppet]}             #{options[:puppet]}
::1             localhost ip6-localhost ip6-loopback
fe00::0         ip6-localnet
ff00::0         ip6-mcastprefix
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters
EOF
  
  File.open("/etc/hosts", 'w+') do |out|
    out << outdata
  end

  Dir.mkdir("/root/.ssh") if not File.directory?("/root/.ssh")

  filename = "/root/.ssh/authorized_keys"
  File.open(filename, "w+") do |out|
    out << pubkey
  end

  FileUtils.rm('/etc/systemd/system/multi-user.target.wants/auditd.service')
  FileUtils.rm('/etc/systemd/system/sockets.target.wants/avahi-daemon.socket')
  FileUtils.rm('/etc/systemd/system/multi-user.target.wants/avahi-daemon.service')
  FileUtils.rm('/etc/systemd/system/dbus-org.freedesktop.Avahi.service')
  FileUtils.rm('/etc/systemd/system/multi-user.target.wants/kdump.service')
  FileUtils.rm('/usr/lib/systemd/system/getty.target')
  FileUtils.rm("/etc/systemd/system/getty.target.wants/getty@tty1.service")
  FileUtils.symlink("/dev/null","/etc/systemd/system/getty.target.wants/getty@tty1.service")
  FileUtils.symlink("/usr/lib/systemd/system/poweroff.target","/etc/systemd/system/sigpwr.target")
  FileUtils.symlink("/dev/null","/etc/systemd/system/systemd-udevd.service")
  FileUtils.symlink("/dev/null","/etc/systemd/system/systemd-udevd-control.socket")
  FileUtils.symlink("/dev/null","/etc/systemd/system/systemd-udevd-kernel.socket")
  FileUtils.symlink("/dev/null","/etc/systemd/system/proc-sys-fs-binfmt_misc.automount")
  
  system("rpm -ivh http://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm")
  system("yum -y install puppet")

  filename = "/etc/puppet/puppet.conf"
  outdata = File.read(filename)
  
  outdata.gsub!(/\[agent\]/, "[agent]\nserver=#{options[:puppet]}\ncertname=#{options[:fqdn]}") if not outdata.include?("certname")
  
  File.open(filename, 'w+') do |out|
    out << outdata
  end

  outdata = <<EOF
START=no
DAEMON_OPTS=""
export LANG=en_US.UTF-8
EOF
  File.open("/etc/default/puppet", 'w+') do |out|
    out << outdata
  end
end

Process.wait

outdata = <<EOF
# For additional config options, please look at lxc.container.conf(5)
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br-int
lxc.network.hwaddr = #{mac}
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br-ex
lxc.network.hwaddr = #{mac6}
lxc.rootfs = /var/lib/lxc/#{options[:hostname]}/rootfs

lxc.arch = x86_64
lxc.utsname = #{options[:fqdn]}

lxc.autodev = 1

lxc.devttydir = lxc
lxc.tty = 4
lxc.pts = 1024
lxc.kmsg = 0


# Mount entries
lxc.mount.auto = proc:mixed sys:ro

# Ensure hostname is changed on clone
lxc.hook.clone = /usr/share/lxc/hooks/clonehostname


# hostname(1).
# lxc.cap.drop = sys_admin
# lxc.cap.drop = net_raw          # breaks dhcp/ping
# lxc.cap.drop = setgid           # breaks login (initgroups/setgroups)
# lxc.cap.drop = dac_read_search  # breaks login (pam unix_chkpwd)
# lxc.cap.drop = setuid           # breaks sshd,nfs statd
# lxc.cap.drop = audit_control    # breaks sshd (set_loginuid failed)
# lxc.cap.drop = audit_write
# lxc.cap.drop = setpcap          # big big login delays in Fedora 20 systemd
#
lxc.cap.drop = mac_admin mac_override
# lxc.cap.drop = setfcap
lxc.cap.drop = sys_module sys_nice sys_pacct
lxc.cap.drop = sys_rawio sys_time

# Control Group devices: all denied except those whitelisted
lxc.cgroup.devices.deny = a
# Allow any mknod (but not reading/writing the node)
lxc.cgroup.devices.allow = c *:* m
lxc.cgroup.devices.allow = b *:* m
lxc.cgroup.devices.allow = c 1:3 rwm    # /dev/null
lxc.cgroup.devices.allow = c 1:5 rwm    # /dev/zero
lxc.cgroup.devices.allow = c 1:7 rwm    # /dev/full
lxc.cgroup.devices.allow = c 5:0 rwm    # /dev/tty
lxc.cgroup.devices.allow = c 1:8 rwm    # /dev/random
lxc.cgroup.devices.allow = c 1:9 rwm    # /dev/urandom
lxc.cgroup.devices.allow = c 136:* rwm  # /dev/tty[1-4] ptys and lxc console
lxc.cgroup.devices.allow = c 5:2 rwm    # /dev/ptmx pty master

# Blacklist some syscalls which are not safe in privileged
# containers
lxc.seccomp = /usr/share/lxc/config/common.seccomp
EOF

filename = "/var/lib/lxc/#{options[:hostname]}/config"
File.open(filename, 'w') do |out|
out << outdata
end