#!/bin/bash
# bash script to migrate containers from one backend storage to another.
set -e

ATOMIC_LIBEXEC="${ATOMIC_LIBEXEC-/usr/libexec/atomic}"
GOTAR="$ATOMIC_LIBEXEC/gotar"

main() {
if [ $(id -u) != 0 ];then
	echo "Run 'migrate' as root user"
	exit 
fi

NUMARGS=$#

if [ $NUMARGS -eq 0 ] || [ "$1" = "--help" ];then 
	echo "Usage: migrate COMMAND [ARGS] [OPTIONS]
       migrate [--help]

A self-sufficient tool for migrating docker containers from one backend storage to another

Commands:
    export  Export a container from an existing storage
    import  Import a container into a new storage"
	exit
fi

if [ "$1" = "export" ];then
   if [ -z "$2" ]; then
	echo "migrate: "export" requires a minimum of 1 argument.
See 'migrate export --help'

Usage: migrate export CONTAINER-ID [OPTIONS]

Export a container from an existing storage"
	exit
   elif [ "$2" = "--help" ];then
	echo "
Usage: migrate export CONTAINER-ID [OPTIONS]

Export a container from an existing storage

--graph   	    Root of the Docker runtime (Default: /var/lib/docker)
--export-location   Path for exporting the container (Default: /var/lib/atomic/migrate/containers)"
	exit
   else
	container_export $2 $3 $4
   fi
fi

if [ "$1" = "import" ];then
   if [ -z "$2" ]; then
        echo "migrate: "import" requires a minimum of 1 argument.
See 'migrate import --help'
        
Usage: migrate import CONTAINER-ID [OPTIONS]

Import a container into a new storage"
        exit
   elif [ "$2" = "--help" ];then
        echo "
Usage: migrate import CONTAINER-ID [OPTIONS]

Import a container into a new storage

--graph             Root of the Docker runtime (Default: /var/lib/docker)
--import-location   Path for importing the container (Default: /var/lib/atomic/migrate/containers)"
        exit
   else
        container_import $2 $3 $4
   fi
fi

}

get_docker_pid() {
	if ! systemctl is-active docker >/dev/null; then
		echo "Docker daemon is not running"
		exit 1
	fi

	pid=$(systemctl show -p MainPID docker.service)
	echo ${pid#*=}
}

container_export(){
	for arg in "$@"
	do 
		flag=$(echo $arg|cut -d'=' -f 1)
		val=$(echo $arg|cut -d'=' -f 2)
		case "$flag" in
			--container-id)
				containerID=$val
			;;
			--graph)
				dockerRootDir=$val
			;;
			--export-location)
				exportPath=$val
			;;
		esac
	done

	if [ -z "$containerID" ]; then
		echo "--container-id cannot be null"
		exit 1
	fi

	if [ -z "$exportPath" ]; then
		exportPath="/var/lib/atomic/migrate"
	fi

        dockerPid=$(get_docker_pid)
        dockerCmdline=$(cat /proc/$dockerPid/cmdline)||exit 1
        if [[ $dockerCmdline =~ "-g=" ]] || [[ $dockerCmdline =~ "-g/" ]] || [[ $dockerCmdline =~ "--graph" ]];then
                if [ -z "$dockerRootDir" ] || [ $dockerRootDir = "/var/lib/docker" ];then
                        echo "Docker is not located at the default (/var/lib/docker) root location."
                        echo "Please provide the new root location of the docker runtime in --graph option."
        		exit 1
                fi
        else
                dockerRootDir="/var/lib/docker"
        fi
        notruncContainerID=$(docker ps -aq --no-trunc|grep $containerID)||exit 1
        tmpDir=$exportPath/containers/migrate-$containerID
        mkdir -p $tmpDir
        cd $tmpDir
	containerBaseImageID=$(docker inspect --format '{{.Image}}' $containerID)||exit 1
	echo $dockerRootDir>containerInfo.txt
	echo $containerBaseImageID>>containerInfo.txt
	echo $notruncContainerID>>containerInfo.txt
	"$GOTAR" -cf container-metadata.tar $dockerRootDir/containers/$notruncContainerID 2> /dev/null
	if [[ ! -z $(docker diff $containerID) ]];then
		imageName=$(echo $RANDOM)
		docker commit $containerID $imageName 1>/dev/null||exit 1
		mkdir -p $tmpDir/temp
		docker save $imageName > $tmpDir/temp/image.tar||exit 1
		$(cd $tmpDir/temp; "$GOTAR" -xf image.tar)
		diffLayerID=$(python -c 'import json; f=open("temp/repositories"); j=json.load(f); print(j[j.keys()[0]]["latest"])')
		cd $tmpDir/temp/$diffLayerID
		cp layer.tar $tmpDir/container-diff.tar
		cd $tmpDir
		/usr/bin/tar --delete -f container-diff.tar run/gotar 2>/dev/null || true
		rm -rf temp
		docker rmi -f $imageName 1>/dev/null||exit 1
	fi
}

container_import(){
	for arg in "$@"
        do
                flag=$(echo $arg|cut -d'=' -f 1)
                val=$(echo $arg|cut -d'=' -f 2)
                case "$flag" in
                        --container-id)
                                containerID=$val
                        ;;
                        --graph)
                                dockerRootDir=$val
                        ;;
                        --import-location)
                                importPath=$val
                        ;;
                esac
        done

        if [ -z "$containerID" ]; then
                echo "--container-id cannot be null"
                exit
        fi

        if [ -z "$importPath" ]; then
                importPath="/var/lib/atomic/migrate"
        fi

        dockerPid=$(get_docker_pid)
        dockerCmdline=$(cat /proc/$dockerPid/cmdline)||exit 1
        if [[ $dockerCmdline =~ "-g=" ]] || [[ $dockerCmdline =~ "-g/" ]] || [[ $dockerCmdline =~ "--graph" ]];then
                if [ -z "$dockerRootDir" ] || [ $dockerRootDir = "/var/lib/docker" ];then
                        echo "Docker is not located at the default (/var/lib/docker) root location."
                        echo "Please provide the new root location of the docker runtime in --graph option."
                        exit 1
                fi
        else
                dockerRootDir="/var/lib/docker"
        fi

        cd $importPath/containers/migrate-$containerID
        dockerBaseImageID=$(sed -n '2p' containerInfo.txt)||exit 1
        if [[ -f container-diff.tar ]];then
                cat container-diff.tar|docker run -i -v "$GOTAR:/run/gotar" $dockerBaseImageID /run/gotar -xf -
        else
                docker run -i $dockerBaseImageID echo "container_import"
        fi
	newContainerID=$(docker ps -lq)||exit 1
	newContainerName=$(docker inspect -f '{{.Name}}' $newContainerID)||exit 1
	newNotruncContainerID=$(docker ps -aq --no-trunc|grep $newContainerID)||exit 1					
	cd $dockerRootDir/containers/$newNotruncContainerID
	rm -rf *
	cp $importPath/containers/migrate-$containerID/container-metadata.tar .
	"$GOTAR" -xf container-metadata.tar	
	rm container-metadata.tar
	oldDockerRootDir=$(sed -n '1p' $importPath/containers/migrate-$containerID/containerInfo.txt)||exit 1
	oldNotruncContainerID=$(sed -n '3p' $importPath/containers/migrate-$containerID/containerInfo.txt)||exit 1
	cp -r ${oldDockerRootDir:1}/containers/$oldNotruncContainerID/* .
	baseDir=$(echo $oldDockerRootDir|cut -d"/" -f 2)
	rm -rf $baseDir

	oldStorageDriver=$(sed -n '1p' $importPath/info.txt)||exit 1
	newStorageDriver=$(docker info|grep "Storage Driver"|cut -d" " -f 3)

	sed -i "s|\"Driver\":\"$oldStorageDriver\"|\"Driver\":\"$newStorageDriver\"|g" config.v2.json	
	sed -i "s|$oldDockerRootDir/containers/$oldNotruncContainerID|$dockerRootDir/containers/$oldNotruncContainerID|g" config.v2.json

	cd $dockerRootDir
	find . -name "*$newNotruncContainerID*" -type d -exec rename $newNotruncContainerID $oldNotruncContainerID {} +
	find . -name "*$newNotruncContainerID*" -type f -exec rename $newNotruncContainerID $oldNotruncContainerID {} +
}

main "$@"
