Generate leaner P4 VM

Dev: 1.5 GB instead of 3.5 GB
Tutorial: 2.3 GB instead of 5.5 GB

Change-Id: Ib63d47578a2c9e16a97827bfba463f90cfe1187d
diff --git a/tools/dev/p4vm/README.md b/tools/dev/p4vm/README.md
index af56b8f..96cac47 100644
--- a/tools/dev/p4vm/README.md
+++ b/tools/dev/p4vm/README.md
@@ -26,9 +26,9 @@
 ## Recommended system requirements
 
 The VM is configured with 4 GB of RAM and 2 CPU cores (4 cores for the tutorial
-variant), while the disk has size of approx. 8 GB. For a flawless experience we
-recommend running the VM on a host system that has at least the double of
-resources.
+variant). The disk has size of approx. 4 GB but expect to grow up to 8 GB when
+building ONOS. For a flawless experience we recommend running the VM on a host
+system that has at least the double of resources.
 
 These are the recommended minimum requirements to be able to run a Mininet
 network with 1-10 BMv2 devices controlled by 1 ONOS instance. To emulate larger
@@ -48,10 +48,10 @@
 to download an Open Virtual Appliance (OVA) package to be imported using
 VirtualBox or any other x86 virtualization system that supports this format.
 
-Pre-built OVA package (approx. 3.5 GB):
+Pre-built OVA package (approx. 1.5 GB):
 <http://onlab.vicci.org/onos/onos-p4-dev.ova>
 
-The tutorial variant of the OVA package can be found here (approx 5.5 GB):
+The tutorial variant of the OVA package can be found here (approx 2.3 GB):
 <http://onlab.vicci.org/onos/onos-p4-tutorial.ova>
 
 ### Login credentials
@@ -66,8 +66,8 @@
 To build the VM you will need the following software installed in your host
 machine:
 
-- [Vagrant](https://www.vagrantup.com/) (tested v2.0.1)
-- [VirtualBox](https://www.virtualbox.org/wiki/Downloads) (tested with v5.2.8)
+- [Vagrant](https://www.vagrantup.com/) (tested v2.1.1)
+- [VirtualBox](https://www.virtualbox.org/wiki/Downloads) (tested with v5.2.10)
 
 Optionally, to export the VM as an OVA package you will also need
 [sshpass](https://gist.github.com/arunoda/7790979).
@@ -108,8 +108,6 @@
 3. reduce VM disk size (by removing build artifacts);
 4. generate a file named `onos-p4-dev.ova`.
 
-The generated OVA file will have size of approx. 3.5-4 GB.
-
 ### Building the tutorial VM
 
 To build the tutorial VM, simply set the environment variable `P4_VM_TYPE` to `tutorial` before building.
diff --git a/tools/dev/p4vm/Vagrantfile b/tools/dev/p4vm/Vagrantfile
index e6f124c..0157bf2 100644
--- a/tools/dev/p4vm/Vagrantfile
+++ b/tools/dev/p4vm/Vagrantfile
@@ -17,8 +17,6 @@
     end
   end
   config.vm.hostname = "onos-p4-" + P4_VM_TYPE
-  # By default vagrant creates a NAT interface.
-  # Create a second one host-only.
   config.vm.network "private_network", :type => 'dhcp', :adapter => 2
   config.vm.provision "shell", path: "root-bootstrap.sh", :args => P4_VM_TYPE
 end
diff --git a/tools/dev/p4vm/bm-commands.sh b/tools/dev/p4vm/bm-commands.sh
index ee96f22..3081de4 100644
--- a/tools/dev/p4vm/bm-commands.sh
+++ b/tools/dev/p4vm/bm-commands.sh
@@ -1,10 +1,5 @@
 #!/usr/bin/env bash
 
-BUILD_DIR=~/p4tools
-
-export BMV2_PATH=${BUILD_DIR}/bmv2
-export P4RUNTIME_PATH=${BUILD_DIR}/p4runtime
-
 bm-cli () {
     if [ -z "$1" ]; then
         echo "No argument supplied. Usage: bm-cli <BMV2 DEVICE ID>"
@@ -12,7 +7,7 @@
     fi
     tport=$(head -n 1 /tmp/bmv2-$1-thrift-port)
     echo "Starting CLI for BMv2 instance $1 (Thrift port $tport)..."
-    sudo ${BMV2_PATH}/tools/runtime_CLI.py --thrift-port ${tport} ${@:2}
+    sudo bm_CLI --thrift-port ${tport} ${@:2}
 }
 
 bm-dbg () {
@@ -22,7 +17,7 @@
     fi
     tport=$(head -n 1 /tmp/bmv2-$1-thrift-port)
     echo "Starting debugger for BMv2 instance $1 (Thrift port $tport)..."
-    sudo ${BMV2_PATH}/tools/p4dbg.py --thrift-port ${tport} ${@:2}
+    sudo bm_p4dbg --thrift-port ${tport} ${@:2}
 }
 
 bm-nmsg () {
@@ -32,7 +27,7 @@
     fi
     tport=$(head -n 1 /tmp/bmv2-$1-thrift-port)
     echo "Starting nanomsg event listener for BMv2 instance $1 (Thrift port $tport)..."
-    sudo ${BMV2_PATH}/tools/nanomsg_client.py --thrift-port ${tport} ${@:2}
+    sudo bm_nanomsg_events --thrift-port ${tport} ${@:2}
 }
 
 bm-log () {
@@ -44,9 +39,3 @@
     echo "---"
     tail -f /tmp/bmv2-$1-log
 }
-
-bm-sysrepo-reset () {
-    echo "Resetting sysrepo data store..."
-    sudo rm -rf /etc/sysrepo/data/*
-    sudo ${P4RUNTIME_PATH}/proto/sysrepo/install_yangs.sh
-}
diff --git a/tools/dev/p4vm/export-ova.sh b/tools/dev/p4vm/export-ova.sh
index 32e1694..6507849 100755
--- a/tools/dev/p4vm/export-ova.sh
+++ b/tools/dev/p4vm/export-ova.sh
@@ -4,27 +4,48 @@
 
 VM_TYPE=${P4_VM_TYPE:-dev}
 
+function wait_vm_shutdown {
+    set +x
+    while vboxmanage showvminfo $1 | grep -c "running (since"
+    do
+    echo "Waiting for VM to shutdown..."
+    sleep 1
+    done
+    sleep 2
+    set -x
+}
+
 # Remove references to the existing vagrant-built VM (if any).
 # We want to build a new one from scratch, not start an existing one.
 rm -rf .vagrant/
-
 vagrant up
 
 SSH_PORT=`vagrant port --guest 22`
 VB_UUID=`cat .vagrant/machines/default/virtualbox/id`
+VMDK_PATH=`VBoxManage showvminfo ${VB_UUID} --machinereadable | grep vmdk | cut -d'=' -f2`
 
+# Take snapshot before cleanup for local use
+# e.g. to avoid re-building P4 tools from scratch
+vboxmanage controlvm ${VB_UUID} acpipowerbutton
+wait_vm_shutdown ${VB_UUID}
+VBoxManage snapshot ${VB_UUID} take "pre-cleanup"
+
+# Cleanup
+vagrant up
 sshpass -p 'rocks' \
     ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
     -p ${SSH_PORT} sdn@127.0.0.1 "bash /vagrant/pre-ova-cleanup.sh"
-
 sleep 5
 vboxmanage controlvm ${VB_UUID} acpipowerbutton
-
-# Wait for VM to power off
-sleep 30
+wait_vm_shutdown ${VB_UUID}
 
 # Remove vagrant shared folder
 vboxmanage sharedfolder remove ${VB_UUID} -name "vagrant"
 
-rm -rf onos-p4-${VM_TYPE}.ova
+rm -f onos-p4-${VM_TYPE}.ova
 vboxmanage export ${VB_UUID} -o onos-p4-${VM_TYPE}.ova
+
+sleep 1
+vboxmanage snapshot ${VB_UUID} restore pre-cleanup
+sleep 1
+vboxmanage snapshot ${VB_UUID} delete pre-cleanup
diff --git a/tools/dev/p4vm/install-p4-tools.sh b/tools/dev/p4vm/install-p4-tools.sh
index 8625daa..a5c5bee 100755
--- a/tools/dev/p4vm/install-p4-tools.sh
+++ b/tools/dev/p4vm/install-p4-tools.sh
@@ -71,17 +71,13 @@
         mktemp \
         pkg-config \
         protobuf-c-compiler \
-        python \
-        python-dev \
-        python-ipaddr \
-        python-pip \
-        python-scapy \
-        python-setuptools \
+        python2.7 \
+        python2.7-dev \
         tcpdump \
         wget \
         unzip
 
-    sudo pip install setuptools cffi grpcio
+    sudo -H pip install setuptools cffi grpcio scapy ipaddr
 }
 
 function do_requirements_1404 {
diff --git a/tools/dev/p4vm/pre-ova-cleanup.sh b/tools/dev/p4vm/pre-ova-cleanup.sh
index e63c344..d4e28fb 100755
--- a/tools/dev/p4vm/pre-ova-cleanup.sh
+++ b/tools/dev/p4vm/pre-ova-cleanup.sh
@@ -6,15 +6,21 @@
 sudo userdel -r -f vagrant
 
 # Free space on disk
-cd ~/p4tools/protobuf && make clean
-cd ~/p4tools/grpc && make clean
-cd ~/p4tools/bmv2 && make clean
-cd ~/p4tools/bmv2/targets && make clean
-cd ~/p4tools/p4runtime && make clean
-rm -rf ~/p4tools/p4c/build
-rm -rf ~/p4tools/libyang/build
-rm -rf ~/p4tools/sysrepo/build
+rm -rf ~/p4tools/protobuf
+rm -rf ~/p4tools/grpc
+rm -rf ~/p4tools/bmv2
+rm -rf ~/p4tools/p4runtime
+rm -rf ~/p4tools/p4c
+rm -rf ~/p4tools/libyang
+rm -rf ~/p4tools/sysrepo
 
+sudo apt-get clean
 sudo apt-get -y autoremove
+sudo rm -rf /tmp/*
 
-cat /dev/null > ~/.bash_history
+# Zerofill virtual hd to save space when exporting
+time sudo dd if=/dev/zero of=/tmp/zero bs=1M || true
+sync ; sleep 1 ; sync ; sudo rm -f /tmp/zero
+
+history -c
+rm -f ~/.bash_history
diff --git a/tools/dev/p4vm/root-bootstrap.sh b/tools/dev/p4vm/root-bootstrap.sh
index dfbfd46..f413cc6 100755
--- a/tools/dev/p4vm/root-bootstrap.sh
+++ b/tools/dev/p4vm/root-bootstrap.sh
@@ -11,14 +11,13 @@
 usermod -aG vboxsf sdn
 update-locale LC_ALL="en_US.UTF-8"
 
+
 if [ ${VM_TYPE} = "tutorial" ]
 then
-    cp /vagrant/tutorial-bootstrap.sh /home/sdn/tutorial.sh
-    sudo chown sdn:sdn /home/sdn/tutorial.sh
     su sdn <<'EOF'
-bash /home/sdn/tutorial.sh
+cd /home/sdn
+bash /vagrant/tutorial-bootstrap.sh
 EOF
-    rm -rf /home/sdn/tutorial.sh
 fi
 
 # Java 8
@@ -27,24 +26,27 @@
 apt-get update
 echo "oracle-java8-installer shared/accepted-oracle-license-v1-1 select true" | debconf-set-selections
 
-# Workaround to: https://stackoverflow.com/questions/46815897/jdk-8-is-not-installed-error-404-not-found
-set +e
-apt-get install -y oracle-java8-installer
-set -e
-sed -i 's|JAVA_VERSION=8u161|JAVA_VERSION=8u171|' /var/lib/dpkg/info/oracle-java8-installer.*
-sed -i 's|PARTNER_URL=http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/|PARTNER_URL=http://download.oracle.com/otn-pub/java/jdk/8u171-b11/512cd62ec5174c3487ac17c61aaa89e8/|' /var/lib/dpkg/info/oracle-java8-installer.*
-sed -i 's|SHA256SUM_TGZ="6dbc56a0e3310b69e91bb64db63a485bd7b6a8083f08e48047276380a0e2021e"|SHA256SUM_TGZ="b6dd2837efaaec4109b36cfbb94a774db100029f98b0d78be68c27bec0275982"|' /var/lib/dpkg/info/oracle-java8-installer.*
-sed -i 's|J_DIR=jdk1.8.0_161|J_DIR=jdk1.8.0_171|' /var/lib/dpkg/info/oracle-java8-installer.*
-
 apt-get -y --no-install-recommends install \
+    avahi-daemon \
+    bridge-utils \
+    git \
+    git-review \
+    htop \
     oracle-java8-installer \
     oracle-java8-set-default \
-    zip unzip \
-    bridge-utils \
-    avahi-daemon \
-    htop \
+    python2.7 \
+    python2.7-dev \
     valgrind \
-    git-review
+    zip unzip \
+    tcpdump \
+    vlan \
+    ntp \
+    vim nano emacs \
+
+
+curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
+python2.7 get-pip.py --force-reinstall
+rm -f get-pip.py
 
 tee -a /etc/ssh/sshd_config <<EOF
 
diff --git a/tools/dev/p4vm/user-bootstrap.sh b/tools/dev/p4vm/user-bootstrap.sh
index fdbaf5b..e068727 100755
--- a/tools/dev/p4vm/user-bootstrap.sh
+++ b/tools/dev/p4vm/user-bootstrap.sh
@@ -14,11 +14,10 @@
 source ~/onos/tools/dev/bash_profile
 source ~/onos/tools/dev/p4vm/bm-commands.sh
 EOF
-source ~/.profile
 
 # Build and install P4 tools
 bash /vagrant/install-p4-tools.sh
 
 # Mininet
 git clone git://github.com/mininet/mininet ~/mininet
-sudo ~/mininet/util/install.sh -nwv
+sudo ~/mininet/util/install.sh -nv