Merge branch 'master' of bitbucket.org:corddesign/voltha
diff --git a/.gitignore b/.gitignore
index 0c3d63f..0f7b7b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,16 @@
 # Gradle
 .gradle
+buildSrc/build
 
 # Python
 */*.pyc
 
+# PyCharm
+.idea
+
+# Vagrant
+.vagrant
+
+# Ansible
+ansible/*.retry
 
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..73d0638
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,16 @@
+FROM alpine:3.1
+
+# Update to have latest images
+RUN apk add --update python py-pip
+
+# Install app dependencies
+RUN apk add build-base gcc abuild binutils python-dev && \
+    pip install scapy twisted
+
+# Bundle app source
+COPY voltha /voltha
+
+# Exposing process and default entry point
+# EXPOSE 8000
+CMD ["python", "voltha/voltha.py"]
+
diff --git a/Vagrantfile b/Vagrantfile
new file mode 100644
index 0000000..f9acea9
--- /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 ".", "/voltha", mount_options: ["dmode=700,fmode=600"]
+  else
+    config.vm.synced_folder ".", "/voltha"
+  end
+
+  config.vm.define "voltha" do |d|
+    d.ssh.forward_agent = true
+    d.vm.box = "ubuntu/trusty64"
+    d.vm.hostname = "voltha"
+    d.vm.network "private_network", ip: "10.100.198.220"
+    d.vm.provision :shell, path: "ansible/scripts/bootstrap_ansible.sh"
+    d.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /voltha/ansible/voltha.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/group_vars/all b/ansible/group_vars/all
new file mode 100644
index 0000000..6baada9
--- /dev/null
+++ b/ansible/group_vars/all
@@ -0,0 +1,9 @@
+ip: "{{ facter_ipaddress_eth1 }}"
+consul_extra: ""
+proxy_url: http://{{ facter_ipaddress_eth1 }}
+proxy_url2: http://{{ facter_ipaddress_eth1 }}
+registry_url: 10.100.198.220:5000/
+jenkins_ip: 10.100.198.220
+debian_version: trusty
+docker_cfg: docker.cfg
+docker_cfg_dest: /etc/default/docker
diff --git a/ansible/java/tasks/main.yml b/ansible/java/tasks/main.yml
new file mode 100644
index 0000000..beb4211
--- /dev/null
+++ b/ansible/java/tasks/main.yml
@@ -0,0 +1,5 @@
+- name: Package is present
+  apt:
+    name=openjdk-7-jdk
+    state=present
+  tags: [java]
diff --git a/ansible/roles/common/defaults/main.yml b/ansible/roles/common/defaults/main.yml
new file mode 100644
index 0000000..46f473c
--- /dev/null
+++ b/ansible/roles/common/defaults/main.yml
@@ -0,0 +1,11 @@
+hosts: [
+  { host_ip: "10.100.198.220", host_name: "voltha"},
+]
+
+use_latest_for:
+  - debian-keyring
+  - debian-archive-keyring
+
+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..3391255
--- /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: "{{ ansible_env['PWD'] }}/.ssh/known_hosts"
+    state: absent
+
+- name: Disable Known Host Checking
+  copy:
+    src: files/ssh_config
+    dest: "{{ ansible_env['PWD'] }}/.ssh/config"
+    owner: "{{ ansible_env['SUDO_USER'] }}"
+    group: "{{ ansible_env['SUDO_USER'] }}"
+    mode: 0600
diff --git a/ansible/roles/docker-compose/tasks/main.yml b/ansible/roles/docker-compose/tasks/main.yml
new file mode 100644
index 0000000..3845f4a
--- /dev/null
+++ b/ansible/roles/docker-compose/tasks/main.yml
@@ -0,0 +1,5 @@
+- name: Executable is present
+  get_url:
+    url: https://github.com/docker/compose/releases/download/1.6.2/docker-compose-Linux-x86_64
+    dest: /usr/local/bin/docker-compose
+    mode: 0755
diff --git a/ansible/roles/docker/defaults/main.yml b/ansible/roles/docker/defaults/main.yml
new file mode 100644
index 0000000..338d16e
--- /dev/null
+++ b/ansible/roles/docker/defaults/main.yml
@@ -0,0 +1,6 @@
+docker_extra: ""
+
+centos_files: [
+  { src: "docker.centos.repo", dest: "/etc/yum.repos.d/docker.repo" },
+  { src: "docker.centos.service", dest: "/lib/systemd/system/docker.service" },
+]
\ No newline at end of file
diff --git a/ansible/roles/docker/files/docker.centos.repo b/ansible/roles/docker/files/docker.centos.repo
new file mode 100644
index 0000000..b472187
--- /dev/null
+++ b/ansible/roles/docker/files/docker.centos.repo
@@ -0,0 +1,6 @@
+[dockerrepo]
+name=Docker Repository
+baseurl=https://yum.dockerproject.org/repo/main/centos/7
+enabled=1
+gpgcheck=1
+gpgkey=https://yum.dockerproject.org/gpg
\ No newline at end of file
diff --git a/ansible/roles/docker/files/docker.centos.service b/ansible/roles/docker/files/docker.centos.service
new file mode 100644
index 0000000..3bbef84
--- /dev/null
+++ b/ansible/roles/docker/files/docker.centos.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=Docker Application Container Engine
+Documentation=https://docs.docker.com
+After=network.target docker.socket
+Requires=docker.socket
+
+[Service]
+EnvironmentFile=-/etc/sysconfig/docker
+Type=notify
+ExecStart=/usr/bin/docker daemon --insecure-registry 10.100.198.200:5000 -H fd://
+MountFlags=slave
+LimitNOFILE=1048576
+LimitNPROC=1048576
+LimitCORE=infinity
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/docker/tasks/centos.yml b/ansible/roles/docker/tasks/centos.yml
new file mode 100644
index 0000000..a8910d4
--- /dev/null
+++ b/ansible/roles/docker/tasks/centos.yml
@@ -0,0 +1,23 @@
+- name: CentOS files are copied
+  copy:
+    src: "{{ item.src }}"
+    dest: "{{ item.dest }}"
+  with_items: centos_files
+  tags: [docker]
+
+- name: CentOS package is installed
+  yum:
+    name: docker-engine
+    state: present
+  tags: [docker]
+
+- name: CentOS Daemon is reloaded
+  command: systemctl daemon-reload
+  tags: [docker]
+
+- name: CentOS service is running
+  service:
+    name: docker
+    state: running
+  tags: [docker]
+
diff --git a/ansible/roles/docker/tasks/debian.yml b/ansible/roles/docker/tasks/debian.yml
new file mode 100644
index 0000000..f590f17
--- /dev/null
+++ b/ansible/roles/docker/tasks/debian.yml
@@ -0,0 +1,50 @@
+- name: Debian add Docker repository and update apt cache
+  apt_repository:
+    repo: deb https://apt.dockerproject.org/repo ubuntu-{{ debian_version }} main
+    update_cache: yes
+    state: present
+  tags: [docker]
+
+- name: Debian Docker is present
+  apt:
+    name: docker-engine
+    state: latest
+    force: yes
+  tags: [docker]
+
+- name: Debian python-pip is present
+  apt: name=python-pip state=present
+  tags: [docker]
+
+- name: Debian docker-py is present
+  pip:
+    name: docker-py
+    version: 1.6.0
+    state: present
+  tags: [docker]
+
+- name: Debian files are present
+  template:
+    src: "{{ docker_cfg }}"
+    dest: "{{ docker_cfg_dest }}"
+  register: copy_result
+  tags: [docker]
+
+- name: Debian Daemon is reloaded
+  command: systemctl daemon-reload
+  when: copy_result|changed and is_systemd is defined
+  tags: [docker]
+
+- name: vagrant user is added to the docker group
+  user:
+    name: "{{ ansible_env['SUDO_USER'] }}"
+    group: docker
+  register: user_result
+  tags: [docker]
+
+- name: Debian Docker service is restarted
+  service:
+    name: docker
+    state: restarted
+  when: copy_result|changed or user_result|changed
+  tags: [docker]
diff --git a/ansible/roles/docker/tasks/main.yml b/ansible/roles/docker/tasks/main.yml
new file mode 100644
index 0000000..1495847
--- /dev/null
+++ b/ansible/roles/docker/tasks/main.yml
@@ -0,0 +1,5 @@
+- include: debian.yml
+  when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
+
+- include: centos.yml
+  when: ansible_distribution == 'CentOS' or ansible_distribution == 'Red Hat Enterprise Linux'
diff --git a/ansible/roles/docker/templates/docker-swarm-master.service b/ansible/roles/docker/templates/docker-swarm-master.service
new file mode 100644
index 0000000..b284d4b
--- /dev/null
+++ b/ansible/roles/docker/templates/docker-swarm-master.service
@@ -0,0 +1,21 @@
+[Unit]
+Description=Docker Application Container Engine
+Documentation=https://docs.docker.com
+After=network.target docker.socket
+Requires=docker.socket
+
+[Service]
+Type=notify
+ExecStart=/usr/bin/docker daemon -H fd:// \
+          --insecure-registry 10.100.198.220:5000 \
+          --registry-mirror=http://10.100.198.220:5001 \
+          --cluster-store=consul://{{ ip }}:8500/swarm \
+          --cluster-advertise={{ ip }}:2375 {{ docker_extra }}
+MountFlags=master
+LimitNOFILE=1048576
+LimitNPROC=1048576
+LimitCORE=infinity
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/ansible/roles/docker/templates/docker-swarm-node.service b/ansible/roles/docker/templates/docker-swarm-node.service
new file mode 100644
index 0000000..55bcc50
--- /dev/null
+++ b/ansible/roles/docker/templates/docker-swarm-node.service
@@ -0,0 +1,23 @@
+[Unit]
+Description=Docker Application Container Engine
+Documentation=https://docs.docker.com
+After=network.target docker.socket
+Requires=docker.socket
+
+[Service]
+Type=notify
+ExecStart=/usr/bin/docker daemon -H fd:// \
+          -H tcp://0.0.0.0:2375 \
+          -H unix:///var/run/docker.sock \
+          --insecure-registry 10.100.198.220:5000 \
+          --registry-mirror=http://10.100.198.220:5001 \
+          --cluster-store=consul://{{ ip }}:8500/swarm \
+          --cluster-advertise={{ ip }}:2375 {{ docker_extra }}
+MountFlags=slave
+LimitNOFILE=1048576
+LimitNPROC=1048576
+LimitCORE=infinity
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/ansible/roles/docker/templates/docker.cfg b/ansible/roles/docker/templates/docker.cfg
new file mode 100644
index 0000000..cac4911
--- /dev/null
+++ b/ansible/roles/docker/templates/docker.cfg
@@ -0,0 +1 @@
+DOCKER_OPTS="$DOCKER_OPTS --insecure-registry 10.100.198.220:5000 -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --registry-mirror=http://10.100.198.220:5001"
diff --git a/ansible/scripts/bootstrap_ansible.sh b/ansible/scripts/bootstrap_ansible.sh
new file mode 100755
index 0000000..7602afa
--- /dev/null
+++ b/ansible/scripts/bootstrap_ansible.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+#
+# Copyright 2016 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 apt-transport-https
+cp /voltha/ansible/ansible.cfg /etc/ansible/ansible.cfg
diff --git a/ansible/voltha.yml b/ansible/voltha.yml
new file mode 100644
index 0000000..a92fc7c
--- /dev/null
+++ b/ansible/voltha.yml
@@ -0,0 +1,8 @@
+- hosts: localhost
+  remote_user: vagrant
+  serial: 1
+  roles:
+    - common
+    - docker
+    - docker-compose
+    - java
diff --git a/build.gradle b/build.gradle
index 1743e41..737cd30 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,32 +1,79 @@
 /*
- * This build file was auto generated by running the Gradle 'init' task
- * by 'zsolt' at '9/8/16 1:51 PM' with Gradle 2.12
+ * Copyright 2016 the original author or authors.
  *
- * This generated file contains a commented-out sample Java project to get you started.
- * For more details take a look at the Java Quickstart chapter in the Gradle
- * user guide available at https://docs.gradle.org/2.12/userguide/tutorial_java_projects.html
+ * 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.
  */
+import org.opencord.gradle.rules.*
+import org.yaml.snakeyaml.Yaml
 
-/*
-// Apply the java plugin to add support for Java
-apply plugin: 'java'
+allprojects {
+    apply plugin: 'base'
+    apply plugin: 'de.gesellix.docker'
 
-// In this section you declare where to find the dependencies of your project
-repositories {
-    // Use 'jcenter' for resolving your dependencies.
-    // You can declare any Maven/Ivy/file repository here.
-    jcenter()
+    docker {
+        // dockerHost = System.env.DOCKER_HOST ?: 'unix:///var/run/docker.sock'
+        // dockerHost = System.env.DOCKER_HOST ?: 'https://192.168.99.100:2376'
+        // certPath = System.getProperty('docker.cert.path') ?: "${System.getProperty('user.home')}/.docker/machine/machines/default"
+        // authConfigPlain = [
+        //   "username"       : "joe",
+        //   "password"       : "some-pw-as-needed",
+        //   "email"          : "joe@acme.com",
+        //   "serveraddress"  : "https://index.docker.io/v1/"
+        //  ]
+    }
 }
 
-// In this section you declare the dependencies for your production and test code
-dependencies {
-    // The production code uses the SLF4J logging API at compile time
-    compile 'org.slf4j:slf4j-api:1.7.18'
+ext {
 
-    // Declare the dependency for your favourite test framework you want to use in your tests.
-    // TestNG is also supported by the Gradle Test task. Just change the
-    // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
-    // 'test.useTestNG()' to your build script.
-    testCompile 'junit:junit:4.12'
+    // Target registry to be used to publish docker images needed for deployment
+    targetReg = project.hasProperty('targetReg') ? project.getProperty('targetReg') : 'localhost:5000'
+
+    // The tag used to tag the docker images push to the target registry
+    targetTag = project.hasProperty('targetTag') ? project.getProperty('targetTag') : 'candidate'
+
+    // Deployment target config file (yaml format); this can be overwritten from the command line
+    // using the -PdeployConfig=<file-path> syntax.
+    deployConfig = project.hasProperty('deployConfig') ? project.getProperty('deployConfig') : './config/default.yml'
+
+    dockerPath = project.hasProperty('dockerPath') ? project.getProperty('dockerPath') : '/usr/bin'
+
 }
-*/
+
+// ~~~~~~~~~~~~~~~~~~~ Global tasks ~~~~~~~~~~~~~~~~~~~~~~~
+
+// To be used to fetch upstream binaries, clone repos, etc.
+task fetch {
+    // ...
+}
+
+// To be used to generate all needed binaries that need to be present on the target
+// as docker images in the local docker runner.
+task buildImages(type: Exec) {
+    commandLine "$dockerPath/docker", 'build', '-t', 'cord/voltha', '-f', 'Dockerfile', '.'
+}
+
+task tagImage(type: Exec) {
+   dependsOn buildImages
+   commandLine "$dockerPath/docker", 'tag', 'cord/voltha', "$targetReg/cord/voltha:$targetTag"
+}
+
+// Publish image(s) built during the build step into targetReg registry using the targetTag
+// tag. See maas subproject for examples on how to do this.
+task publishImages(type: Exec) {
+    dependsOn tagImage
+    commandLine "$dockerPath/docker", 'push', "$targetReg/cord/voltha:$targetTag"
+}
+
+task publish {
+    dependsOn publishImages
+}
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
new file mode 100644
index 0000000..cbb6652
--- /dev/null
+++ b/buildSrc/build.gradle
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+apply plugin: 'groovy'
+
+repositories {
+    // maven { url 'https://repo.gradle.org/gradle/libs' }
+    maven { url 'https://plugins.gradle.org/m2/' }
+    // mavenCentral()
+}
+
+dependencies {
+    compile gradleApi()
+    compile localGroovy()
+    compile 'de.gesellix:gradle-docker-plugin:2016-05-05T13-15-11'
+    compile 'org.yaml:snakeyaml:1.10'
+    //compile 'gradle.plugin.com.tmiyamon:gradle-config:0.2.1'
+}
diff --git a/buildSrc/buildSrc.iml b/buildSrc/buildSrc.iml
new file mode 100644
index 0000000..2c235a5
--- /dev/null
+++ b/buildSrc/buildSrc.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":buildSrc" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/org/opencord/gradle/rules/DockerFetchRule.groovy b/buildSrc/src/main/groovy/org/opencord/gradle/rules/DockerFetchRule.groovy
new file mode 100644
index 0000000..a9bb91b
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/opencord/gradle/rules/DockerFetchRule.groovy
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package org.opencord.gradle.rules
+
+import org.gradle.api.Rule
+import de.gesellix.gradle.docker.tasks.DockerPullTask
+
+
+/**
+ * Gradle Rule class to fetch a docker image
+ */
+class DockerFetchRule implements Rule {
+
+    def project
+
+    DockerFetchRule(project) {
+        this.project = project
+    }
+
+    String getDescription() {
+        'Rule Usage: fetch<component-name>'
+    }
+
+    void apply(String taskName) {
+        if (taskName.startsWith('fetch')) {
+            project.task(taskName, type: DockerPullTask) {
+                ext.compName = taskName - 'fetch'
+                def spec = project.comps[ext.compName]
+                imageName = spec.name + '@' + spec.digest
+            }
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/opencord/gradle/rules/DockerPublishRule.groovy b/buildSrc/src/main/groovy/org/opencord/gradle/rules/DockerPublishRule.groovy
new file mode 100644
index 0000000..39b6bba
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/opencord/gradle/rules/DockerPublishRule.groovy
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package org.opencord.gradle.rules
+
+import org.gradle.api.Rule
+import de.gesellix.gradle.docker.tasks.DockerPushTask
+
+
+/**
+ * Gradle Rule class to publish (push) a docker image to a private repo
+ */
+class DockerPublishRule implements Rule {
+
+    def project
+    def dependency
+
+    DockerPublishRule(project) {
+        this.project = project
+    }
+
+    DockerPublishRule(project, dependency) {
+        this.project = project
+        this.dependency = dependency
+    }
+
+    String getDescription() {
+        'Rule Usage: publish<component-name>'
+    }
+
+    void apply(String taskName) {
+        if (taskName.startsWith('publish')) {
+            project.task(taskName, type: DockerPushTask) {
+                ext.compName = taskName - 'publish'
+                println "Publish rule: $taskName + $compName"
+                def tagTask = "tag$compName"
+                println "Tagtask: $tagTask"
+                if (dependency) {
+                    dependsOn dependency
+                }
+                dependsOn tagTask
+                def spec = project.comps[ext.compName]
+                repositoryName = spec.name + ':' + project.targetTag
+                registry = project.targetReg
+            }
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/opencord/gradle/rules/DockerTagRule.groovy b/buildSrc/src/main/groovy/org/opencord/gradle/rules/DockerTagRule.groovy
new file mode 100644
index 0000000..474e16d
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/opencord/gradle/rules/DockerTagRule.groovy
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package org.opencord.gradle.rules
+
+import org.gradle.api.Rule
+import de.gesellix.gradle.docker.tasks.DockerTagTask
+
+
+/**
+ * Gradle Rule class to tag a docker image
+ */
+class DockerTagRule implements Rule {
+
+    def project
+
+    DockerTagRule(project) {
+        this.project = project
+    }
+
+    String getDescription() {
+        'Rule Usage: tag<component-name>'
+    }
+
+    void apply(String taskName) {
+        if (taskName.startsWith('tag') && !taskName.equals('tag')) {
+            project.task(taskName, type: DockerTagTask) {
+                ext.compName = taskName - 'tag'
+                def spec = project.comps[compName]
+                imageId = spec.name + '@' + spec.digest
+                tag = compName + ':' + project.targetTag
+            }
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/opencord/gradle/rules/GitSubmoduleUpdateRule.groovy b/buildSrc/src/main/groovy/org/opencord/gradle/rules/GitSubmoduleUpdateRule.groovy
new file mode 100644
index 0000000..3b46424
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/opencord/gradle/rules/GitSubmoduleUpdateRule.groovy
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package org.opencord.gradle.rules
+
+import org.gradle.api.Rule
+import org.gradle.api.tasks.Exec
+
+
+/**
+ * Gradle Rule class to fetch a docker image
+ */
+class GitSubmoduleUpdateRule implements Rule {
+
+    def project
+
+    GitSubmoduleUpdateRule(project) {
+        this.project = project
+    }
+
+    String getDescription() {
+        'Rule Usage: gitupdate<component-name>'
+    }
+
+    void apply(String taskName) {
+        if (taskName.startsWith('gitupdate')) {
+            project.task(taskName, type: Exec) {
+                ext.compName = taskName - 'gitupdate'
+                def spec = project.comps[ext.compName]
+                workingDir = '.'
+                commandLine '/usr/bin/git', 'submodule', 'update', '--init', '--recursive', spec.componentDir
+            }
+        }
+    }
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..1a644c7
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1 @@
+org.gradle.daemon=true
diff --git a/settings.gradle b/settings.gradle
index ea83177..90a3b41 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -9,11 +9,4 @@
  * in the user guide at https://docs.gradle.org/2.12/userguide/multi_project_builds.html
  */
 
-/*
-// To declare projects as part of a multi-project build use the 'include' method
-include 'shared'
-include 'api'
-include 'services:webservice'
-*/
-
 rootProject.name = 'voltha'