Vagrant devel environment

Change-Id: Ic872fd224e1b096d48e89b5f5f2bb6ecc32a8f12
diff --git a/Vagrantfile b/Vagrantfile
new file mode 100644
index 0000000..5db90c5
--- /dev/null
+++ b/Vagrantfile
@@ -0,0 +1,28 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+Vagrant.configure(2) do |config|
+
+  if (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
+    config.vm.synced_folder ".", "/platform-install", mount_options: ["dmode=700,fmode=600"]
+  else
+    config.vm.synced_folder ".", "/platform-install"
+  end
+
+  config.vm.define "platdev" do |d|
+    d.ssh.forward_agent = true
+    d.vm.box = "ubuntu/trusty64"
+    d.vm.hostname = "platdev"
+    d.vm.network "private_network", ip: "10.100.198.200"
+    d.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    d.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /platform-install/ansible/platdev.yml -c local"
+    d.vm.provider "virtualbox" do |v|
+      v.memory = 2048
+    end
+  end
+
+  if Vagrant.has_plugin?("vagrant-cachier")
+    config.cache.scope = :box
+  end
+
+end
diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg
new file mode 100644
index 0000000..bd331b2
--- /dev/null
+++ b/ansible/ansible.cfg
@@ -0,0 +1,9 @@
+[defaults]
+callback_plugins=/etc/ansible/callback_plugins/
+host_key_checking=False
+deprecation_warnings=False
+
+[privilege_escalation]
+become=True
+become_method=sudo
+become_user=root
diff --git a/ansible/platdev.yml b/ansible/platdev.yml
new file mode 100644
index 0000000..d3a34fc
--- /dev/null
+++ b/ansible/platdev.yml
@@ -0,0 +1,7 @@
+- hosts: localhost
+  remote_user: vagrant
+  serial: 1
+  roles:
+    - common
+    - java8-oracle
+    - buildtools
diff --git a/ansible/roles/buildtools/defaults/main.yml b/ansible/roles/buildtools/defaults/main.yml
new file mode 100644
index 0000000..b7568df
--- /dev/null
+++ b/ansible/roles/buildtools/defaults/main.yml
@@ -0,0 +1,2 @@
+apt_packages:
+  - maven
diff --git a/ansible/roles/buildtools/tasks/main.yml b/ansible/roles/buildtools/tasks/main.yml
new file mode 100644
index 0000000..6c0e3fa
--- /dev/null
+++ b/ansible/roles/buildtools/tasks/main.yml
@@ -0,0 +1,6 @@
+- name: Apt packages
+  apt:
+    name: "{{ item }}"
+  with_items: "{{ apt_packages }}"
+  tags: [buildtools]
+
diff --git a/ansible/roles/common/defaults/main.yml b/ansible/roles/common/defaults/main.yml
new file mode 100644
index 0000000..0393a03
--- /dev/null
+++ b/ansible/roles/common/defaults/main.yml
@@ -0,0 +1,12 @@
+hosts: [
+  { host_ip: "10.100.198.200", host_name: "platdev"},
+]
+
+use_latest_for:
+  - debian-keyring
+  - debian-archive-keyring
+  - rng-tools
+
+obsolete_services:
+  - puppet
+  - chef-client
diff --git a/ansible/roles/common/files/ssh_config b/ansible/roles/common/files/ssh_config
new file mode 100644
index 0000000..990a43d
--- /dev/null
+++ b/ansible/roles/common/files/ssh_config
@@ -0,0 +1,3 @@
+Host *
+   StrictHostKeyChecking no
+   UserKnownHostsFile=/dev/null
diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml
new file mode 100644
index 0000000..3ee9d2e
--- /dev/null
+++ b/ansible/roles/common/tasks/main.yml
@@ -0,0 +1,40 @@
+- name: JQ is present
+  apt:
+    name: jq
+    force: yes
+  tags: [common]
+
+- name: Host is present
+  lineinfile:
+    dest: /etc/hosts
+    regexp: "^{{ item.host_ip }}"
+    line: "{{ item.host_ip }} {{ item.host_name }}"
+  with_items: "{{ hosts }}"
+  tags: [common]
+
+- name: Latest apt packages
+  apt:
+    name: "{{ item }}"
+  with_items: "{{ use_latest_for }}"
+  tags: [common]
+
+- name: Services are not running
+  service:
+    name: "{{ item }}"
+    state: stopped
+  ignore_errors: yes
+  with_items: "{{ obsolete_services }}"
+  tags: [common]
+
+- name: Ensure known_hosts file is absent
+  file:
+    path: /home/vagrant/.ssh/known_hosts
+    state: absent
+
+- name: Disable Known Host Checking
+  copy:
+    src: files/ssh_config
+    dest: /home/vagrant/.ssh/config
+    owner: vagrant
+    group: vagrant
+    mode: 0600
diff --git a/ansible/roles/java8-oracle/tasks/main.yml b/ansible/roles/java8-oracle/tasks/main.yml
new file mode 100644
index 0000000..809fbee
--- /dev/null
+++ b/ansible/roles/java8-oracle/tasks/main.yml
@@ -0,0 +1,20 @@
+---
+- name: Install add-apt-repository
+  sudo: yes
+  apt: name=software-properties-common state=latest
+
+- name: Add Oracle Java repository
+  sudo: yes
+  apt_repository: repo='ppa:webupd8team/java'
+
+- name: Accept Java 8 license
+  sudo: yes
+  debconf: name='oracle-java8-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select'
+
+- name: Install Oracle Java 8
+  sudo: yes
+  apt: name={{item}} state=latest
+  with_items:
+  - oracle-java8-installer
+  - ca-certificates
+  - oracle-java8-set-default
diff --git a/build.gradle b/build.gradle
index 867e73e..8bde489 100644
--- a/build.gradle
+++ b/build.gradle
@@ -89,6 +89,35 @@
 
 // ---------------- Useful tasks ----------------
 
+List.metaClass.asParam = { prefix, sep ->
+  if (delegate.size() == 0) {
+    ""
+  }
+  String result = "--" + prefix + "="
+  String p = ""
+  delegate.each {
+    result += p + "${it}"
+    p = sep
+  }
+  result
+}
+
+List.metaClass.p = { value, name ->
+  if (value != null && value != "") {
+      delegate << name + "=" + value
+  } else {
+      delegate
+  }
+}
+
+List.metaClass.p = { spec ->
+  if (spec != null && spec != "") {
+      delegate += spec
+  } else {
+      delegate
+  }
+}
+
 task fetchUpstreamImages {
     comps.each { name, spec -> if (spec.type == 'image') { dependsOn "fetch" + name } }
 }
@@ -167,3 +196,57 @@
 
     args = args.p(skipTags.asParam("skip-tags", ",")).p(extraVars.asParam("extra-vars", " ")) << "cord-head-playbook.yml"
 }
+
+task deploySingle (type: Exec) {
+    dependsOn copyAnsibleInventory
+
+    println "Using deployment config: $deployConfig"
+    File configFile = new File(deployConfig)
+    def yaml = new Yaml()
+    def config = yaml.load(configFile.newReader())
+
+    executable = "ansible-playbook"
+    args = ["-i", "inventory/single-prod"]
+
+    if ( config.seedServer.user != null && config.seedServer.user != "" ) {
+        args = args << "--user=$config.seedServer.user"
+    }
+
+    def extraVars = []
+    if (config.seedServer) {
+        extraVars = extraVars.p(config.seedServer.extraVars)
+            .p(config.seedServer.password, "ansible_ssh_pass")
+            .p(config.seedServer.sudoPassword, "ansible_sudo_pass")
+            .p(config.seedServer.fabric_ip, "fabric_ip")
+            .p(config.seedServer.management_ip, "management_ip")
+            .p(config.seedServer.management_network, "management_network")
+            .p(config.seedServer.management_iface, "management_iface")
+            .p(config.seedServer.external_ip, "external_ip")
+            .p(config.seedServer.external_network, "external_network")
+            .p(config.seedServer.external_iface, "external_iface")
+            .p(config.seedServer.fabric_ip, "fabric_ip")
+            .p(config.seedServer.fabric_network, "fabric_network")
+            .p(config.seedServer.fabric_iface, "fabric_iface")
+            .p(config.seedServer.domain, "domain")
+            .p(config.seedServer.virtualbox_support, "virtualbox_support")
+            .p(config.seedServer.power_helper_user, "power_helper_user")
+            .p(config.seedServer.power_helper_host, "power_helper_host")
+            .p(config.seedServer.port, "ansible_ssh_port")
+    }
+
+    if (config.otherServers) {
+        extraVars = extraVars.p(config.otherServers.location, "prov_location")
+            .p(config.otherServers.rolesPath, "prov_role_path")
+            .p(config.otherServers.role, "prov_role")
+    }
+
+    if (config.docker) {
+        extraVars = extraVars.p(config.docker.registry, "docker_registry")
+            .p(config.docker.imageVersion, "docker_image_version")
+    }
+
+    def skipTags = [].p(config.seedServer.skipTags)
+
+    args = args.p(skipTags.asParam("skip-tags", ",")).p(extraVars.asParam("extra-vars", " ")) << "cord-single-playbook.yml"
+}
+
diff --git a/config/cloudlab.yml b/config/cloudlab.yml
new file mode 100644
index 0000000..104eaca
--- /dev/null
+++ b/config/cloudlab.yml
@@ -0,0 +1,52 @@
+# Deployment configuration for a single-node physical hardware POD
+---
+seedServer:
+
+  # Put the IP of your CloudLab node here
+  ip: '128.104.222.83'
+
+  # User name and password used by Ansible to connect to the host for remote
+  # provisioning.   Put your CloudLab username here; also add your password or
+  # run ssh-agent to allow for password-less SSH login.
+  user: 'acb'
+  password: 'onos_test'
+
+  #
+  # *** For a single-node pod on CloudLab, you don't need to change anything below here ***
+  #
+
+  # Network address information for the head node:
+  #
+  # fabric_ip     - the IP address and mask bits to be used to configure the network
+  #                 interface connected to the leaf - spine fabric
+  #
+  # management_ip - the IP address and mask bits to be used to configure the network
+  #                 interface connecting the head node to the POD internal
+  #                 management network. The head node will deliver DHCP addresses to
+  #                 the other compute nodes over this interface
+  #
+  # external_ip   - the IP address and mask bits to be used to configure the network
+  #                 interface connecting the head node (and the POD) to the
+  #                 Internet. All traffic in the POD to external hosts will be
+  #                 NAT-ed through this interface
+  management_ip: '10.6.0.1/24'
+  management_iface: 'eth2'
+  external_iface: 'eth0'
+  skipTags:
+    - 'interface_config'
+    - 'switch_support'
+  extraVars:
+    - 'on_cloudlab=True'
+
+docker:
+  imageVersion: candidate
+
+otherNodes:
+  # Experimental
+  #
+  # Specifies the subnet and address range that will be used to allocate IP addresses
+  # to the compute nodes as they are deployed into the POD.
+  fabric:
+    network: 10.6.1.1/24
+    range_low: 10.6.1.2
+    range_high: 10.6.1.253
diff --git a/cord-single-playbook.yml b/cord-single-playbook.yml
index ee657e9..ed1f648 100644
--- a/cord-single-playbook.yml
+++ b/cord-single-playbook.yml
@@ -9,7 +9,7 @@
   tasks:
   - include_vars: vars/cord_single_defaults.yml
   - include_vars: vars/cord.yml
-  - include_vars: vars/cord_keystone.yml
+  - include_vars: vars/example_keystone.yml
 
 - name: DNS Server and apt-cacher-ng Setup
   hosts: head
diff --git a/gradle.properties b/gradle.properties
index 1a644c7..c955ae8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1 +1,4 @@
 org.gradle.daemon=true
+
+# Uncomment for running on CloudLab
+#deployConfig=/platform-install/config/cloudlab.yml
diff --git a/scripts/bootstrap_ansible.sh b/scripts/bootstrap_ansible.sh
new file mode 100755
index 0000000..6190f48
--- /dev/null
+++ b/scripts/bootstrap_ansible.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright 2012 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+echo "Installing Ansible..."
+apt-get install -y software-properties-common
+apt-add-repository ppa:ansible/ansible
+apt-get update
+apt-get install -y ansible python-netaddr
+cp /platform-install/ansible.cfg /etc/ansible/ansible.cfg
+