#!/bin/sh

HOST_USER=$USER
HOST_UID=$(getent passwd | grep "^$USER:" | cut -d":" -f3)
CURRENT_DIRECTORY=$(basename `pwd`)
MOUNT_POINT=$(echo $CURRENT_DIRECTORY | tr '[:lower:]' '[:upper:]')
DEBIAN_RELEASE=wheezy
INVALID_OPTIONS=false
NO_GIT_BRANCH=false
GIT_BRANCH=
CONTAINER_NAME=
LIST_ALL_CONTAINERS=false
LXC_VERSION=$(lxc-ls --version)
DUMMY_MODE=false

# Detect OS
if [ -f /etc/lsb-release ]; then
  . /etc/lsb-release
  OS=$DISTRIB_ID
elif [ -f /etc/debian_version ]; then
  OS=Debian
elif [ -f /etc/arch-release ]; then
  OS=Arch
elif [ -f /etc/SuSE-release ]; then
  OS=Suse
else
  OS=$(uname -s)
fi

is_under_git_control() {
  git rev-parse --is-inside-work-tree > /dev/null 2>&1
}

if is_under_git_control; then
  GIT_BRANCH=$(git describe --contains --all HEAD)
fi

for i in "$@"; do
  case $i in
    attach|create|destroy|info|list|restart|start|setup|stop)
      COMMAND=$i
      shift
      ;;
    run)
      COMMAND=$i
      shift
      break
      ;;
    --no-branch)
      NO_GIT_BRANCH=true
      shift
      ;;
    --branch)
      GIT_BRANCH=$2
      shift 2
      ;;
    --release)
      DEBIAN_RELEASE=$2
      shift 2
      ;;
    --version)
      shift
      echo 0.8
      exit 0
      ;;
    --dummy)
      DUMMY_MODE=true
      shift
      ;;
    --all)
      LIST_ALL_CONTAINERS=true
      shift
      ;;
    jessie|sid|squeeze|stable|testing|wheezy)
      ;;
    *)
      BRANCH_EXISTS=$(git rev-parse --abbrev-ref --all | grep "^$i$")
      if [ -z $BRANCH_EXISTS ]; then
        echo "W: unknown option '$i'"
        INVALID_OPTIONS=true
      fi
      ;;
  esac
done

if $INVALID_OPTIONS; then
  exit 3
fi

if [ -z $COMMAND ]; then
  echo "E: missing command" >&2
  echo "" >&2
  echo "Usage: `basename $0` <command> [options]" >&2
  echo "" >&2
  echo "* command = {attach|create|destroy|info|list|restart|run|start|setup|stop}" >&2
  echo "* options = --no-branch" >&2
  echo "            --branch <branch-name>" >&2
  echo "            --dummy" >&2
  echo "            --release <debian-codename>" >&2
  echo "            --version" >&2
  echo "            --all" >&2
  exit 2
fi

if $NO_GIT_BRANCH || [ -z $GIT_BRANCH ]; then
  CONTAINER_NAME=$CURRENT_DIRECTORY
else
  CONTAINER_NAME=$CURRENT_DIRECTORY-$GIT_BRANCH
fi

compare_version() {
  VER1=$(echo $1 | sed 's/\.//g')
  VER2=$(echo $2 | sed 's/\.//g')
  [ $VER1 -ge $VER2 ]
}

run_sh() {
  if ! $DUMMY_MODE; then
    sudo sh -c "$@"
  fi
}

run() {
  CYAN=$(tput setaf 6)
  ENDCOLOR=$(tput sgr0)
  if $DUMMY_MODE; then
    echo "${CYAN}[HOLODEV] sudo $@${ENDCOLOR}"
  else
    sudo $@
  fi
}

is_container_stopped() {
  CONTAINER_STATUS=$(run lxc-info -s -n $CONTAINER_NAME)
  echo $CONTAINER_STATUS | grep STOPPED > /dev/null
}

is_apparmor_enabled() {
  if compare_version $LXC_VERSION '1.1.0' && [ -f /sys/module/apparmor/parameters/enabled ]; then
    APPARMOR_STATUS=$(cat /sys/module/apparmor/parameters/enabled)
    echo $APPARMOR_STATUS | grep -e '^Y$' > /dev/null
  else
    false
  fi
}

start_if_stopped() {
  if is_container_stopped; then
    do_start
  fi
}

info() {
  GRAY=$(tput bold; tput setaf 8)
  ENDCOLOR=$(tput sgr0)
  if ! $DUMMY_MODE; then
    echo "${GRAY}[HOLODEV] $@${ENDCOLOR}"
  fi
}

highlight() {
  YELLOW=$(tput bold; tput setaf 3)
  ENDCOLOR=$(tput sgr0)
  echo "${YELLOW}[HOLODEV] $@${ENDCOLOR}"
}

error() {
  RED=$(tput bold; tput setaf 1)
  ENDCOLOR=$(tput sgr0)
  echo "${RED}[HOLODEV] $@${ENDCOLOR}"
}

create_default_configuration_file() {
  info "creating default configuration file"
  run_sh "sed -i 's/lxc.network./#lxc.network./' /var/lib/lxc/$CONTAINER_NAME/config"
  run_sh "echo >> /var/lib/lxc/$CONTAINER_NAME/config"
  run_sh "echo \# holodev configurations >> /var/lib/lxc/$CONTAINER_NAME/config"
  run_sh "echo lxc.network.type = veth >> /var/lib/lxc/$CONTAINER_NAME/config"
  run_sh "echo lxc.network.link = virbr0 >> /var/lib/lxc/$CONTAINER_NAME/config"
  run_sh "echo lxc.mount = /var/lib/lxc/$CONTAINER_NAME/fstab >> /var/lib/lxc/$CONTAINER_NAME/config"
  if is_apparmor_enabled; then
    run_sh "echo lxc.aa_allow_incomplete = 1 >> /var/lib/lxc/$CONTAINER_NAME/config"
  fi
  if [ -f /etc/apparmor.d/disabled/usr.bin.lxc-start ]; then
    run_sh "echo lxc.aa_profile = unconfined >> /var/lib/lxc/$CONTAINER_NAME/config"
  fi
}

lxc_attach() {
  if [ $OS = 'Arch' ]; then
    run lxc-attach --clear-env -n $CONTAINER_NAME -- $@
  else
    run lxc-attach -n $CONTAINER_NAME -- $@
  fi
}

create_user_into_container() {
  info "creating my user into the container"
  if $DUMMY_MODE || ! sudo grep $HOST_USER /var/lib/lxc/$CONTAINER_NAME/rootfs/etc/passwd > /dev/null; then
    lxc_attach adduser --system --shell /bin/bash --home /$MOUNT_POINT --uid $HOST_UID --disabled-password --quiet $HOST_USER
    lxc_attach chown $HOST_USER:nogroup /$MOUNT_POINT
  fi
}

add_user_to_sudo() {
  info "adding the user created in the container to sudo"
  if ! sudo test -e /var/lib/lxc/$CONTAINER_NAME/rootfs/etc/sudoers.d/sudo-group-nopasswd; then
    lxc_attach apt-get update
    lxc_attach apt-get -y install debian-archive-keyring sudo
    run_sh "echo '%sudo ALL=(ALL) NOPASSWD:ALL' > /var/lib/lxc/$CONTAINER_NAME/rootfs/etc/sudoers.d/sudo-group-nopasswd"
    lxc_attach adduser $HOST_USER sudo
  fi
}

setup_libvirt_Debian() {
  NET_AUTOSTART=$(sudo virsh net-info default | grep Autostart: | awk '{print $2}')
  NET_ACTIVE=$(sudo virsh net-info default | grep Active: | awk '{print $2}')
  if [ $NET_AUTOSTART != 'yes' ]; then
    sudo virsh net-autostart default
  fi
  if [ $NET_ACTIVE != 'yes' ]; then
    sudo virsh net-start default
  fi
}

setup_libvirt_Ubuntu() {
  setup_libvirt_Debian
}

setup_libvirt_Suse() {
  setup_libvirt_Debian
}

setup_libvirt_Arch() {
  while systemctl list-units  | grep libvirt-guests.service | grep -q "deactivating"; do
    sleep 2s
  done
  while [ ! -S /var/run/libvirt/libvirt-sock ]; do
    sleep 2s
  done
  setup_libvirt_Debian
}

do_restart() {
  do_stop
  do_start
}

do_attach() {
  highlight "opening console to '$CONTAINER_NAME'"
  start_if_stopped
  lxc_attach su - $HOST_USER
}

do_setup() {
  which sudo > /dev/null; if [ $? -ne 0 ]; then
    echo
    error "sudo not found!" 1>&2
    error "Please install sudo first and add yourself to the sudo group"
    exit 4
  fi

  sudo which brctl > /dev/null; if [ $? -ne 0 ]; then
    echo
    error "brctl not found!" 1>&2
    error "Please install bridge-utils first and run 'setup' again"
    exit 4
  fi

  virbr0=$(sudo brctl show | grep virbr0 2>&1)
  if [ -z "$virbr0" ]; then
    info "configuring 'virbr0' virtual network device..."
    setup_libvirt_$OS
  fi
}

do_create() {
  highlight "creating '$CONTAINER_NAME' with '$DEBIAN_RELEASE'"

  # create container, deboostrap debian
  if [ ! -d /var/lib/lxc/$CONTAINER_NAME ]; then
    run lxc-create -n $CONTAINER_NAME -t debian -- -r $DEBIAN_RELEASE
  fi

  # mount current curectory (suppose is the source-code of project i'm working on) into container
  run_sh "echo $(pwd) /var/lib/lxc/$CONTAINER_NAME/rootfs/$MOUNT_POINT none bind 0 0 > /var/lib/lxc/$CONTAINER_NAME/fstab"

  # create directory into container to mount project sources I'm working on
  if ! sudo test -d /var/lib/lxc/$CONTAINER_NAME/rootfs/$MOUNT_POINT; then
    run_sh "mkdir /var/lib/lxc/$CONTAINER_NAME/rootfs/$MOUNT_POINT"
  fi

  create_default_configuration_file
  start_if_stopped
  create_user_into_container
  add_user_to_sudo
}

do_info() {
  highlight "getting info about '$CONTAINER_NAME'"
  run lxc-info -n $CONTAINER_NAME
}

do_run() {
  COMMAND=$@
  highlight "running '$COMMAND' under '$CONTAINER_NAME'"
  start_if_stopped
  lxc_attach su - $HOST_USER -c "$COMMAND"
}

up_network() {
  # be sure network is up and running
  if lxc_attach which systemctl; then
    RETRY=5
    info "checking if systemd is active"
    while [ $RETRY -gt 0 ]; do
      if lxc_attach systemctl 2>&1 | grep -q -e 'Unknown error -1'; then
        RETRY=$(echo "$RETRY - 1" | bc)
        sleep 1s
      else
        RETRY=0
        SYSTEMD_IS_ACTIVE=true
      fi
    done
    if [ $SYSTEMD_IS_ACTIVE ]; then
      info "waiting the system be operational"
      IS_SYSTEM_RUNNING=$(lxc_attach systemctl is-system-running)
      while ! echo $IS_SYSTEM_RUNNING | grep -q -e 'degraded' -e 'running'; do
        sleep 1s
        IS_SYSTEM_RUNNING=$(lxc_attach systemctl is-system-running)
      done
      lxc_attach systemctl enable systemd-networkd.service
      lxc_attach systemctl start systemd-networkd.service
    fi
  fi
  lxc_attach service networking start
}

do_start() {
  highlight "starting '$CONTAINER_NAME'"
  run lxc-start -n $CONTAINER_NAME -d
  run lxc-wait -n $CONTAINER_NAME -s RUNNING
  up_network
}

do_stop() {
  highlight "stopping '$CONTAINER_NAME'"
  run lxc-stop -n $CONTAINER_NAME
}

do_destroy() {
  highlight "destroing '$CONTAINER_NAME'"
  run lxc-destroy -n $CONTAINER_NAME -f
}

do_list() {
  highlight "listing containers"
  if $LIST_ALL_CONTAINERS; then
    run lxc-ls -1
  else
    run lxc-ls -1 $CURRENT_DIRECTORY
  fi
}

do_$COMMAND $@
exit 0
