#!/bin/bash

KURYR_KUBEADMIN_IMAGE_REPOSITORY="registry.k8s.io"
function get_k8s_log_level {
    if [[ ${ENABLE_DEBUG_LOG_LEVEL} == "True" ]]; then
        echo "4"
    else
        echo "2"
    fi
}

function kubeadm_install {

    if ! is_ubuntu; then
        (>&2 echo "WARNING: kubeadm installation is not supported in this \
distribution.")
        return
    fi

    apt_get install apt-transport-https
    curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
        sudo apt-key add -
    sudo add-apt-repository -y \
        "deb https://apt.kubernetes.io/ kubernetes-xenial main"
    REPOS_UPDATED=False apt_get_update

    # NOTE(gryf): kubectl will be installed alongside with the kubeadm as
    # a dependency, although let's pin it to the k8s version as well.
    apt_get install \
        kubelet="${KURYR_KUBERNETES_VERSION}-00" \
        kubeadm="${KURYR_KUBERNETES_VERSION}-00" \
        kubectl="${KURYR_KUBERNETES_VERSION}-00"
    sudo apt-mark hold kubelet kubeadm kubectl
    # NOTE(hongbin): This work-around an issue that kubelet pick a wrong
    # IP address if the node has multiple network interfaces.
    # See https://github.com/kubernetes/kubeadm/issues/203
    echo "KUBELET_EXTRA_ARGS=--node-ip=$HOST_IP" | sudo tee -a \
        /etc/default/kubelet
    sudo systemctl daemon-reload && sudo systemctl restart kubelet
}

function kubeadm_init {
    local cluster_ip_ranges
    local output_dir="${DATA_DIR}/kuryr-kubernetes"
    local cgroup_driver
    local cri_socket

    mkdir -p "${output_dir}"

    if [[ ${CONTAINER_ENGINE} == 'crio' ]]; then
        local crio_conf="/etc/crio/crio.conf"
        cgroup_driver=$(iniget ${crio_conf} crio.runtime cgroup_manager)
        cri_socket="unix:///var/run/crio/crio.sock"
    else
        # docker is used
        cgroup_driver=$(docker info -f '{{.CgroupDriver}}')
        cri_socket="/var/run/dockershim.sock"
    fi
    cluster_ip_ranges=()
    for service_subnet_id in ${KURYR_SERVICE_SUBNETS_IDS[@]}; do
        service_cidr=$(openstack --os-cloud devstack-admin \
            --os-region "$REGION_NAME" \
            subnet show "$service_subnet_id" \
            -c cidr -f value)
        cluster_ip_ranges+=($(split_subnet "$service_cidr" | cut -f1))
    done

    # TODO(gryf): take care of cri-o case aswell
    rm -f ${output_dir}/kubeadm-init.yaml
    cat >> ${output_dir}/kubeadm-init.yaml << EOF
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
imageRepository: "${KURYR_KUBEADMIN_IMAGE_REPOSITORY}"
etcd:
  external:
    endpoints:
    - "http://${SERVICE_HOST}:${ETCD_PORT}"
networking:
  serviceSubnet: "$(IFS=, ; echo "${cluster_ip_ranges[*]}")"
apiServer:
  extraArgs:
    endpoint-reconciler-type: "none"
    min-request-timeout: "300"
    allow-privileged: "true"
    v: "$(get_k8s_log_level)"
    logtostderr: "true"
controllerManager:
  extraArgs:
    master: "$KURYR_K8S_API_URL"
    min-resync-period: "3m"
    v: "$(get_k8s_log_level)"
    logtostderr: "true"
    leader-elect: "false"
scheduler:
  extraArgs:
    master: "${KURYR_K8S_API_URL}"
    v: "$(get_k8s_log_level)"
    logtostderr: "true"
    leader-elect: "false"
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
bootstrapTokens:
- token: "${KURYR_K8S_TOKEN}"
  ttl: 0s
localAPIEndpoint:
  advertiseAddress: "${K8S_API_SERVER_IP}"
  bindPort: ${K8S_API_SERVER_PORT}
nodeRegistration:
  criSocket: "$cri_socket"
  kubeletExtraArgs:
    enable-server: "true"
  taints:
    []
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
failSwapOn: false
address: "0.0.0.0"
enableServer: true
cgroupDriver: $cgroup_driver
EOF
    sudo kubeadm config images pull --image-repository=${KURYR_KUBEADMIN_IMAGE_REPOSITORY}
    args="--config ${output_dir}/kubeadm-init.yaml"
    # NOTE(gryf): skip installing kube proxy, kuryr will handle services.
    args+=" --skip-phases=addon/kube-proxy"
    args+=" --ignore-preflight-errors Swap"

    if ! is_service_enabled coredns; then
        # FIXME(gryf): Do we need specific configuration for coredns?
        args+=" --skip-phases=addon/coredns"
    fi
    sudo kubeadm init $args

    local kube_config_file=$HOME/.kube/config
    mkdir -p $(dirname ${kube_config_file})
    sudo cp /etc/kubernetes/admin.conf $kube_config_file
    safe_chown $STACK_USER:$STACK_USER $kube_config_file
}

function kubeadm_join {
    local output_dir="${DATA_DIR}/kuryr-kubernetes"
    local cgroup_driver
    local cri_socket

    mkdir -p "${output_dir}"

    if [[ ${CONTAINER_ENGINE} == 'crio' ]]; then
        local crio_conf="/etc/crio/crio.conf"
        cgroup_driver=$(iniget ${crio_conf} crio.runtime cgroup_manager)
        cri_socket="unix:///var/run/crio/crio.sock"
    else
        # docker is used
        cgroup_driver=$(docker info -f '{{.CgroupDriver}}')
        cri_socket="/var/run/dockershim.sock"
    fi
    cluster_ip_ranges=()
    for service_subnet_id in ${KURYR_SERVICE_SUBNETS_IDS[@]}; do
        service_cidr=$(openstack --os-cloud devstack-admin \
            --os-region "$REGION_NAME" \
            subnet show "$service_subnet_id" \
            -c cidr -f value)
        cluster_ip_ranges+=($(split_subnet "$service_cidr" | cut -f1))
    done

    # TODO(gryf): take care of cri-o case aswell
    rm -f ${output_dir}/kubeadm-join.yaml
    cat >> ${output_dir}/kubeadm-join.yaml << EOF
apiVersion: kubeadm.k8s.io/v1beta2
discovery:
  bootstrapToken:
    apiServerEndpoint: ${SERVICE_HOST}:${KURYR_K8S_API_PORT}
    token: "${KURYR_K8S_TOKEN}"
    unsafeSkipCAVerification: true
  tlsBootstrapToken: "${KURYR_K8S_TOKEN}"
kind: JoinConfiguration
nodeRegistration:
  criSocket: "$cri_socket"
  kubeletExtraArgs:
    enable-server: "true"
  taints:
    []
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
failSwapOn: false
address: "0.0.0.0"
enableServer: true
cgroupDriver: $cgroup_driver
EOF
    sudo -E kubeadm join --ignore-preflight-errors Swap \
        --config ${output_dir}/kubeadm-join.yaml
}

function get_k8s_apiserver {
    # assumption is, there is no other cluster, so there is only one API
    # server.
    echo "$(kubectl config view -o jsonpath='{.clusters[].cluster.server}')"
}

function get_k8s_token {
    local secret
    secret=$(kubectl get secrets -o jsonpath='{.items[0].metadata.name}')
    echo $(kubectl get secret $secret -o jsonpath='{.items[0].data.token}' | \
        base64 -d)
}

function kubeadm_reset {
    sudo kubeadm reset -f
    sudo iptables -F
    sudo iptables -t nat -F
    sudo iptables -t mangle -F
    sudo iptables -X
    sudo ipvsadm -C
}

function kubeadm_uninstall {
    sudo systemctl stop kubelet
    apt_get purge --allow-change-held-packages. kubelet kubeadm kubeadm \
        kubernetes-cni apt-transport-https
    sudo add-apt-repository -r -y \
        "deb https://apt.kubernetes.io/ kubernetes-xenial main"
    REPOS_UPDATED=False apt_get_update
    sudo rm -fr /etc/default/kubelet /etc/kubernetes
}