# The docker mongo sharding is based on the article here:
# https://sebastianvoss.com/docker-mongodb-sharded-cluster.html

Vagrant.configure("2") do |config|
  config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box"
  config.vm.box = "trusty_64"
  # The exposed ports can be changed here; the ssh port is never necessary.
  # The mongo port is where the sharded replica-set mongo router is exposed.
  config.vm.network "forwarded_port", guest: 22, host: 2225
  config.vm.network "forwarded_port", guest: 27017, host: 27050
  config.vm.provider "virtualbox" do |v|
    v.name = "Mongo Sharded RS Docker"
    # You may need to configure this to run benignly on your host machine
    v.memory = 1536
    v.cpus = 2
  end

  $script = <<SCRIPT
if [ -f ~/vagrant_provisioned_date ]; then
    echo Already provisioned.
else


echo Starting provisioning.
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' \
    | sudo tee /etc/apt/sources.list.d/mongodb.list
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
echo 'deb https://get.docker.com/ubuntu docker main' \
    | sudo tee /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install --force-yes -y apt-transport-https lxc-docker mongodb-org-shell mongodb-org-tools


# kill and remove any existing docker containers; this makes things fresh
#docker kill rs1_srv1 rs1_srv2 rs1_srv3 rs2_srv1 rs2_srv2 rs2_srv3 cfg1 cfg2 cfg3 mongos1
#docker rm rs1_srv1 rs1_srv2 rs1_srv3 rs2_srv1 rs2_srv2 rs2_srv3 cfg1 cfg2 cfg3 mongos1
# Clean up all of the docker images
docker kill $(docker ps -a -q)
docker rm $(docker ps -a -q)
docker rmi $(docker images -q)


echo -- Making mongodb docker --
mkdir -p mongod
cat <<EOT > mongod/Dockerfile
FROM ubuntu:latest

# Add 10gen official apt source to the sources list
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/10gen.list

# Install MongoDB
RUN apt-get update
RUN apt-get install -y mongodb-org

# Create the MongoDB data directory
RUN mkdir -p /data/db

EXPOSE 27017
ENTRYPOINT ["usr/bin/mongod"]
EOT
docker build -t kitware/mongodb mongod


echo -- Making mongos docker --
mkdir -p mongos
cat <<EOT > mongos/Dockerfile
FROM kitware/mongodb:latest

EXPOSE 27017
ENTRYPOINT ["usr/bin/mongos"]
EOT
docker build -t kitware/mongos mongos

echo -- Creating replica set dockers --
# Create two replica sets
docker run -it -p 27020:27017 --name rs1_srv1 -d kitware/mongodb:latest --replSet rs1 --noprealloc --smallfiles
docker run -it -p 27021:27017 --name rs1_srv2 -d kitware/mongodb:latest --replSet rs1 --noprealloc --smallfiles
docker run -it -p 27022:27017 --name rs1_srv3 -d kitware/mongodb:latest --replSet rs1 --noprealloc --smallfiles

docker run -it -p 27030:27017 --name rs2_srv1 -d kitware/mongodb:latest --replSet rs2 --noprealloc --smallfiles
docker run -it -p 27031:27017 --name rs2_srv2 -d kitware/mongodb:latest --replSet rs2 --noprealloc --smallfiles
docker run -it -p 27032:27017 --name rs2_srv3 -d kitware/mongodb:latest --replSet rs2 --noprealloc --smallfiles


# Wait sometimes makes this succeed
sleep 20
ps axww | grep docker
mongo --port 27020 admin --eval 'db.stats\(\)' && mongo --port 27021 admin --eval 'db.stats\(\)' && mongo --port 27022 admin --eval 'db.stats\(\)'


# Determine host IP as perceived by a docker container
hostip=`docker inspect -f \'\{\{ .NetworkSettings.Gateway \}\}\' rs1_srv1`

# Configure the replica sets
until mongo --port 27020 admin --eval 'db.stats\(\)' && mongo --port 27021 admin --eval 'db.stats\(\)' && mongo --port 27022 admin --eval 'db.stats\(\)'; do echo 'waiting for mongo rs1'; sleep 1; done
mongo --port 27020 admin <<EOT
rs.initiate({_id: 'rs1', version: 1, members: [
{_id: 0, host: '$hostip:27020'},
{_id: 1, host: '$hostip:27021'},
{_id: 2, host: '$hostip:27022'}]})
while (true) {
    var stat = rs.status();
    if (stat.ok==1 && stat.members && stat.members.length==3 &&
            stat.members[0].state==1 && stat.members[1].state==2 &&
            stat.members[2].state==2) {
        break;
    }
    print('waiting for set to be fully up');
    sleep(1000);
}
rs.status()
EOT

until mongo --port 27030 admin --eval 'db.stats\(\)' && mongo --port 27031 admin --eval 'db.stats\(\)' && mongo --port 27032 admin --eval 'db.stats\(\)'; do echo 'waiting for mongo rs2'; sleep 1; done
mongo --port 27030 admin <<EOT
rs.initiate({_id: 'rs2', version: 1, members: [
{_id: 0, host: '$hostip:27030'},
{_id: 1, host: '$hostip:27031'},
{_id: 2, host: '$hostip:27032'}]})
while (true) {
    var stat = rs.status();
    if (stat.ok==1 && stat.members && stat.members.length==3 &&
            stat.members[0].state==1 && stat.members[1].state==2 &&
            stat.members[2].state==2) {
        break;
    }
    print('waiting for set to be fully up');
    sleep(1000);
}
rs.status()
EOT

# Create config servers
docker run -it -p 27040:27017 --name cfg1 -d kitware/mongodb:latest --noprealloc --smallfiles --configsvr --dbpath /data/db --port 27017
docker run -it -p 27041:27017 --name cfg2 -d kitware/mongodb:latest --noprealloc --smallfiles --configsvr --dbpath /data/db --port 27017
docker run -it -p 27042:27017 --name cfg3 -d kitware/mongodb:latest --noprealloc --smallfiles --configsvr --dbpath /data/db --port 27017

until mongo --port 27040 admin --eval 'db.stats\(\)' && mongo --port 27041 admin --eval 'db.stats\(\)' && mongo --port 27042 admin --eval 'db.stats\(\)'; do echo 'waiting for mongo cfg'; sleep 1; done

# Create router
docker run -it -p 27017:27017 --name mongos1 -d kitware/mongos:latest --port 27017 --configdb $hostip:27040,$hostip:27041,$hostip:27042

# Configure router
until mongo --port 27017 admin --eval 'sh.status\(\)'; do echo 'waiting for mongos'; sleep 1; done
mongo --port 27017 admin <<EOT
sh.addShard('rs1/$hostip:27020')
sh.addShard('rs2/$hostip:27030')
sh.status()
EOT

# Record that we provisioned
date > ~/vagrant_provisioned_date
echo Done provisioning.

fi
SCRIPT
  config.vm.provision "shell", inline: $script

end
