Initial outline of opencord integration repo
- Vagrantfile to support standardized 'corddev' development environment
- Ansible playbooks to properly bring up devenv
- Gradle build structure
- Gradle plugin to manage docker-based workflow (pull, build, run, tag,
push, etc.)
- Gradle top-level build file to allow pre-fetching and publishing
component docker images. Supported main tasks: fetch, publish
- Example to how to manage 'as-is' upstream components
- Added initial content to README.md
- Added initial content to docs/quickstart.md
- Updated .gitignore
- Placeholder, parametric entry for deploy step
- Placeholder deployment profile config file (config/default.yml)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8e389c9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+# Java
+*.class
+*.jar
+*.war
+*.oar
+
+# Eclipse
+.project
+.classpath
+.settings
+
+# Idea
+.idea
+*.iml
+*.iws
+*.ipr
+
+# OS
+Thumbs.db
+.DS_Store
+
+# Vagrant
+.vagrant
+
+# Docker registry
+/registry
+
+# Build
+build
+
+# Gradle
+.gradle
+
+# Ansible
+ansible/*.retry
+
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..5c294b6
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2014 Open Networking Laboratory
+
+ 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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..83dcd31
--- /dev/null
+++ b/README.md
@@ -0,0 +1,45 @@
+# Welcome to OpenCORD
+
+This repository is an entry point to OpenCORD. It helps you to build and deploy OpenCORD.
+
+
+### What is CORD
+
+CORD (Central Office Reimagined as a Data Center) is a revolutionary concept to
+turn Telco Central Offices (and MSO Head Ends) into a modern mini data-center, a.k.a. POD.
+The POD is made up of commodity servers, switches, and other networking devices.
+The POD is an application deployment platform optimized for both conventional cloud-scale
+applications as well as virtual network functions (VNF).
+
+
+### What is OpenCORD
+
+OpenCORD is a reference implementation of the CORD concept and is comprised of:
+
+- A number of POD hardware specifications, which can serve as reference implementations
+- A software platform that when deployed on the servers implements service-agnostic software infrastructure enabling deployment of sophisticated network services
+- A few sample service implementations that can be readily deployed onto OpenCORD PODs
+- A deployment automation framework that simplifies the installation of the platform layers as well as the sample services
+- An extendable test framework and test suite to verify and characterize the platfrom as well as the sample services
+- Extensive documentatio to work with OpenCORD
+
+
+### Quick Start
+
+If this is your first encounter with OpenCORD, you may consider giving it a quick spin. We made it real easy. You can bring up OpenCORD on a single server or on a few servers (with or without a real fabric) with a few commands.
+
+Please follow our [Quick Start Tutorial](docs/quickstart.md).
+
+
+### Further Topics
+
+* POD Reference Designs [coming]
+* CORD Software Architecure [coming]
+* Customizing CORD [coming]
+
+
+### References
+
+* [Project Home](http://opencord.org)
+* [Jira](http://jira.opencord.org)
+* [Gerrit](http://gerrit.opencord.org)
diff --git a/Vagrantfile b/Vagrantfile
new file mode 100644
index 0000000..917fbaa
--- /dev/null
+++ b/Vagrantfile
@@ -0,0 +1,36 @@
+# -*- 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 ".", "/opencord", mount_options: ["dmode=700,fmode=600"]
+ else
+ config.vm.synced_folder ".", "/opencord"
+ end
+
+ config.vm.define "corddev" do |d|
+ d.vm.box = "ubuntu/trusty64"
+ d.vm.hostname = "corddev"
+ 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 /opencord/ansible/corddev.yml -c local"
+ d.vm.provider "virtualbox" do |v|
+ v.memory = 2048
+ end
+ end
+
+ config.vm.define "prod" do |d|
+ d.vm.box = "ubuntu/trusty64"
+ d.vm.hostname = "prod"
+ d.vm.network "private_network", ip: "10.100.198.201"
+ d.vm.provider "virtualbox" do |v|
+ v.memory = 1024
+ 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/corddev.yml b/ansible/corddev.yml
new file mode 100644
index 0000000..5bdfa0b
--- /dev/null
+++ b/ansible/corddev.yml
@@ -0,0 +1,10 @@
+- hosts: localhost
+ remote_user: vagrant
+ serial: 1
+ roles:
+ - common
+ - docker
+ - docker-compose
+ - consul-template
+ - registry
+ - java8-oracle
diff --git a/ansible/group_vars/all b/ansible/group_vars/all
new file mode 100644
index 0000000..5c59599
--- /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.200:5000/
+jenkins_ip: 10.100.198.200
+debian_version: trusty
+docker_cfg: docker.cfg
+docker_cfg_dest: /etc/default/docker
diff --git a/ansible/host_vars/10.100.198.200 b/ansible/host_vars/10.100.198.200
new file mode 100644
index 0000000..48505cb
--- /dev/null
+++ b/ansible/host_vars/10.100.198.200
@@ -0,0 +1 @@
+ansible_ssh_private_key_file: /opencord/.vagrant/machines/cd/virtualbox/private_key
diff --git a/ansible/roles/common/defaults/main.yml b/ansible/roles/common/defaults/main.yml
new file mode 100644
index 0000000..4ccfffb
--- /dev/null
+++ b/ansible/roles/common/defaults/main.yml
@@ -0,0 +1,8 @@
+hosts: [
+ { host_ip: "10.100.198.200", host_name: "corddev"},
+ { host_ip: "10.100.198.201", host_name: "prod"},
+]
+
+obsolete_services:
+ - puppet
+ - chef-client
diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml
new file mode 100644
index 0000000..32b60e8
--- /dev/null
+++ b/ansible/roles/common/tasks/main.yml
@@ -0,0 +1,21 @@
+- 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: Services are not running
+ service:
+ name: "{{ item }}"
+ state: stopped
+ ignore_errors: yes
+ with_items: obsolete_services
+ tags: [common]
diff --git a/ansible/roles/consul-template/files/consul-template b/ansible/roles/consul-template/files/consul-template
new file mode 100755
index 0000000..46262c6
--- /dev/null
+++ b/ansible/roles/consul-template/files/consul-template
Binary files differ
diff --git a/ansible/roles/consul-template/files/example.conf.tmpl b/ansible/roles/consul-template/files/example.conf.tmpl
new file mode 100644
index 0000000..fbedd1d
--- /dev/null
+++ b/ansible/roles/consul-template/files/example.conf.tmpl
@@ -0,0 +1 @@
+The address is {{getv "/nginx/nginx"}}
diff --git a/ansible/roles/consul-template/files/example.ctmpl b/ansible/roles/consul-template/files/example.ctmpl
new file mode 100644
index 0000000..8a215ab
--- /dev/null
+++ b/ansible/roles/consul-template/files/example.ctmpl
@@ -0,0 +1,3 @@
+{{range service "nginx"}}
+The address is {{.Address}}:{{.Port}}
+{{end}}
diff --git a/ansible/roles/consul-template/files/example.toml b/ansible/roles/consul-template/files/example.toml
new file mode 100644
index 0000000..4c2d3a1
--- /dev/null
+++ b/ansible/roles/consul-template/files/example.toml
@@ -0,0 +1,6 @@
+[template]
+src = "example.conf.tmpl"
+dest = "/tmp/example.conf"
+keys = [
+ "/nginx/nginx"
+]
\ No newline at end of file
diff --git a/ansible/roles/consul-template/tasks/main.yml b/ansible/roles/consul-template/tasks/main.yml
new file mode 100644
index 0000000..06a5e03
--- /dev/null
+++ b/ansible/roles/consul-template/tasks/main.yml
@@ -0,0 +1,19 @@
+- name: Directory is created
+ file:
+ path: /data/consul-template
+ state: directory
+ tags: [consul-template]
+
+- name: File is copied
+ copy:
+ src: consul-template
+ dest: /usr/local/bin/consul-template
+ mode: 0755
+ tags: [consul-template]
+
+- name: Example template is copied
+ copy:
+ src: example.ctmpl
+ dest: /data/consul-template/example.ctmpl
+ mode: 0644
+ tags: [consul-template]
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..aa10934
--- /dev/null
+++ b/ansible/roles/docker/tasks/debian.yml
@@ -0,0 +1,61 @@
+- 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: vagrant
+ 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]
+
+- name: DockerUI is running
+ docker:
+ image: abh1nav/dockerui
+ name: dockerui
+ ports: 9000:9000
+ privileged: yes
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ when: not skip_ui is defined
+ tags: [docker]
\ No newline at end of file
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..1ec64aa
--- /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.200:5000 \
+ --registry-mirror=http://10.100.198.200: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..09f5141
--- /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.200:5000 \
+ --registry-mirror=http://10.100.198.200: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..ac03f17
--- /dev/null
+++ b/ansible/roles/docker/templates/docker.cfg
@@ -0,0 +1 @@
+DOCKER_OPTS="$DOCKER_OPTS --insecure-registry 10.100.198.200:5000 -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --registry-mirror=http://10.100.198.200:5001"
\ No newline at end of file
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/ansible/roles/registry/files/mirror-config.yml b/ansible/roles/registry/files/mirror-config.yml
new file mode 100644
index 0000000..65ff62c
--- /dev/null
+++ b/ansible/roles/registry/files/mirror-config.yml
@@ -0,0 +1,23 @@
+version: 0.1
+log:
+ fields:
+ service: registry
+storage:
+ cache:
+ blobdescriptor: inmemory
+ filesystem:
+ rootdirectory: /var/lib/registry
+ delete:
+ enabled: true
+http:
+ addr: :5000
+ headers:
+ X-Content-Type-Options: [nosniff]
+health:
+ storagedriver:
+ enabled: true
+ interval: 10s
+ threshold: 3
+
+proxy:
+ remoteurl: https://registry-1.docker.io
diff --git a/ansible/roles/registry/tasks/main.yml b/ansible/roles/registry/tasks/main.yml
new file mode 100644
index 0000000..ceb8e46
--- /dev/null
+++ b/ansible/roles/registry/tasks/main.yml
@@ -0,0 +1,35 @@
+- name: Directories are present
+ file:
+ path: "{{ item }}"
+ state: directory
+ recurse: yes
+ with_items:
+ - /data/registry-mirror/conf
+ tags: [registry]
+
+- name: Configuration is copied
+ copy:
+ src: mirror-config.yml
+ dest: /data/registry-mirror/conf/config.yml
+ tags: [registry]
+
+- name: Registry container is running
+ docker:
+ name: registry
+ image: registry:2.4.0
+ ports: 5000:5000
+ volumes:
+ - /vagrant/registry:/var/lib/registry/docker/registry
+ - /data/registry/conf:/conf
+ tags: [registry]
+
+- name: Mirror container is running
+ docker:
+ name: registry-mirror
+ image: registry:2.4.0
+ ports: 5001:5000
+ volumes:
+ - /vagrant/registry-mirror:/var/lib/registry/docker/registry
+ - /data/registry-mirror/conf:/conf
+ command: /conf/config.yml
+ tags: [registry]
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..e479884
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+import org.opencord.build.rules.*
+import org.yaml.snakeyaml.Yaml
+
+allprojects {
+ apply plugin: 'base'
+ apply plugin: 'de.gesellix.docker'
+ //apply plugin: 'com.tmiyamon.config'
+
+ 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/"
+ // ]
+ }
+}
+
+ext {
+
+ // Upstream registry to simplify filling out the comps table below
+ upstreamReg = 'docker.io'
+
+ // Target registry to be used to publish docker images needed for deployment
+ targetReg = 'localhost:5000'
+
+ // The tag used to tag the docker images push to the target registry
+ targetTag = 'candidate'
+
+ // Component table
+ comps = [
+ 'nginx': [ 'type': 'image',
+ 'upstream': upstreamReg,
+ 'name': 'nginx',
+ 'digest': 'sha256:b555f8c64ab4e85405e0d8b03f759b73ce88deb802892a3b155ef55e3e832806' ],
+ 'swarm': [ 'type': 'image',
+ 'upstream': upstreamReg,
+ 'name': 'swarm',
+ 'digest': 'sha256:6ca9b40980e2fcdcd229900ec8933f3e92c14ead22c9404cb09736cb4f3a9248' ],
+ ]
+
+ // 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'
+
+}
+
+task fetchUpstreamImages {
+ comps.each { name, spec -> if (spec.type == 'image') { dependsOn "fetch" + name } }
+}
+
+task fetch {
+ dependsOn fetchUpstreamImages
+}
+
+task publishImages {
+ comps.each { name, _ -> dependsOn "publish" + name }
+}
+
+task publish {
+ dependsOn publishImages
+}
+
+tasks.addRule(new DockerFetchRule(project))
+tasks.addRule(new DockerPublishRule(project))
+tasks.addRule(new DockerTagRule(project))
+
+task deploy {
+ // TODO this is a place-holder.
+ doFirst {
+ println "Using deployment config: $deployConfig"
+ File configFile = new File(deployConfig)
+ def yaml = new Yaml()
+ def config = yaml.load(configFile.newReader())
+ println "Config: $config"
+ println "Access some data in config:\n\tSeed server IP=${config.seedServer.ip}"
+ }
+}
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/src/main/groovy/org/opencord/build/rules/DockerFetchRule.groovy b/buildSrc/src/main/groovy/org/opencord/build/rules/DockerFetchRule.groovy
new file mode 100644
index 0000000..01f9176
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/opencord/build/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.build.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<image-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/build/rules/DockerPublishRule.groovy b/buildSrc/src/main/groovy/org/opencord/build/rules/DockerPublishRule.groovy
new file mode 100644
index 0000000..75a5990
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/opencord/build/rules/DockerPublishRule.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.build.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
+
+ DockerPublishRule(project) {
+ this.project = project
+ }
+
+ String getDescription() {
+ 'Rule Usage: publish<image-name>'
+ }
+
+ void apply(String taskName) {
+ if (taskName.startsWith('publish')) {
+ project.task(taskName, type: DockerPushTask) {
+ ext.compName = taskName - 'publish'
+ dependsOn "tag" + compName
+ repositoryName = compName + ':' + project.targetTag
+ registry = project.targetReg
+ }
+ }
+ }
+}
diff --git a/buildSrc/src/main/groovy/org/opencord/build/rules/DockerTagRule.groovy b/buildSrc/src/main/groovy/org/opencord/build/rules/DockerTagRule.groovy
new file mode 100644
index 0000000..114bdfc
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/opencord/build/rules/DockerTagRule.groovy
@@ -0,0 +1,49 @@
+/*
+ * 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.build.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<image-name>'
+ }
+
+ void apply(String taskName) {
+ if (taskName.startsWith('tag')) {
+ project.task(taskName, type: DockerTagTask) {
+ ext.compName = taskName - 'tag'
+ dependsOn "fetch" + compName
+ def spec = project.comps[ext.compName]
+ imageId = spec.name + '@' + spec.digest
+ tag = compName + ':' + project.targetTag
+ }
+ }
+ }
+}
diff --git a/components/nginx/build.gradle b/components/nginx/build.gradle
new file mode 100644
index 0000000..8980e82
--- /dev/null
+++ b/components/nginx/build.gradle
@@ -0,0 +1,66 @@
+plugins {
+ id "com.github.ben-manes.versions" version "0.12.0"
+ id "de.gesellix.docker" version "2016-05-05T13-15-11"
+}
+
+import de.gesellix.gradle.docker.tasks.*
+
+import static groovy.json.JsonOutput.prettyPrint
+import static groovy.json.JsonOutput.toJson
+
+allprojects {
+ apply plugin: 'base'
+ apply plugin: 'de.gesellix.docker'
+ 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/"
+ // ]
+ }
+}
+
+task ping(type: DockerPingTask) {
+ doLast { println prettyPrint(toJson(result.content)) }
+}
+
+task info(type: DockerInfoTask) {
+ doLast { println prettyPrint(toJson(info)) }
+}
+
+task version(type: DockerVersionTask) {
+ doLast { println prettyPrint(toJson(version)) }
+}
+
+//task publish(type: DockerPublishTask) {
+// imageName = 'nginx'
+// imageTag = 'cand'
+// buildContextDirectory = file('./docker/')
+// targetRegistries = [
+// dev: "localhost:5000"
+// ]
+//}
+
+task fetch(type: DockerPullTask) {
+ imageName = 'nginx@sha256:b555f8c64ab4e85405e0d8b03f759b73ce88deb802892a3b155ef55e3e832806'
+ // tag = 'sha256:b555f8c64ab4e85405e0d8b03f759b73ce88deb802892a3b155ef55e3e832806'
+ // tag = '1.10.0'
+ // authConfigPlain = getDockerClient().readDefaultAuthConfig()
+}
+
+task tag(type: DockerTagTask) {
+ dependsOn fetch
+ imageId = 'nginx@sha256:b555f8c64ab4e85405e0d8b03f759b73ce88deb802892a3b155ef55e3e832806'
+ tag = 'nginx:cand'
+}
+
+task publish(type: DockerPushTask) {
+ dependsOn tag
+
+ repositoryName = 'nginx:cand'
+ registry = 'localhost:5000'
+}
diff --git a/config/default.yml b/config/default.yml
new file mode 100644
index 0000000..70945c3
--- /dev/null
+++ b/config/default.yml
@@ -0,0 +1,8 @@
+---
+
+size: 2
+
+seedServer:
+ ip: '10.100.198.202'
+
+otherServers: []
diff --git a/docs/objectives.md b/docs/objectives.md
new file mode 100644
index 0000000..389e76c
--- /dev/null
+++ b/docs/objectives.md
@@ -0,0 +1,151 @@
+# CORD Repo Requirements and Design
+
+## Two Main Objectives
+
+**Trying CORD Must be a Pleasant Experience**
+
+1. Very pleasant first impression for shrink-wrapped "copy-paste" trial
+ * 5-10 simple commands
+ * 1-2 verified prerequisites
+ * <60 minutes)
+1. One/two relevant baked-in use-case(s)
+1. A few supported target environments to chose from (see below)
+
+**Extending, customizing CORD should be well supported**
+
+1. Straightforward to customize and extend
+1. Customizations, extensions can be implemented in their own repo(s) to allow their own SCM by user, independent of CORD CI/CD repos
+1. Tutorials on-line (as well as embedded in the top-level repo) provides step-by-step guidance
+
+## Definitions
+
+[illustration to be added to further explain these:]
+
+* Dev host
+* Dev env (may be a VM on the dev host)
+* Target (deployment) environments
+* Upstream artifacts
+* Upstream artifact repo(s)
+* Result/staged artifact repo
+* Replicated local repo
+* Build phase/process
+* Deployment phase/process
+ * Seed stage
+ * Push stage
+ * Local (pull) stage
+* Use-case phase
+* Clean-up processes
+
+
+## Detailed Short-Term Requirements
+
+These requirements are to support the intended experience outlined above:
+
+* Supported environments for dev host:
+ * Mac OS X
+ * Linux
+ * [Possibly Windows - lower prio, but it may be feasible due to the vagrant/external deployment models]
+* Supported target (deployment) configurations [lets narrow this down for 1st release]:
+ * all-in-one on local VM (Vagrant)
+ * all-in-one IP-accessible bare-metal server (with Ubuntu 14.04LTS pre-installed)
+ * all-in-one AWS node, pre-instantiated with Ubuntu 14.04LTS
+ * all-in-one AWS node, automated pre-instantiation (needs AWS credentials, default region, but can be overridden, pem file, etc.)
+ * few-server, server-only, distributed deployment, local physical servers with given IP
+ * few-server, AWS, remote-deployed with auto-created nodes
+ * real-pod - config 1
+ * real-pod - config 2
+ * real-pod - config 3
+* Trial mode should have minimalistic prerequisites on the development host:
+ * git - to clone the top-level repo
+ * vagrant - to bring up the development environment, and also as deployment target
+* Trial mode should allow host to be cleaned up (no trace left if user decides to wipe)
+* Example steps to achieve above goal
+ * Step 1: git clone <opencord repo>
+ * Step 2: cd <repo>
+ * Step 3: vagrant up cord-devenv # may take a few minutes for the 1st time
+ * Step 4: vagrant ssh cord-devenv
+ * Step 5: cd \<repo>
+ * Step 6: \<config target>
+ * Step 7: \<deploy to target> # may take a few times ten minutes for the 1st time
+* In addition to vagrant-based Linux dev env, MAC OS X shall be supported as native dev env too (albeit with more setup effort, which shall be well documented too)
+* Consistent, clean, informative console feedback as the deployment progresses
+* All assumption are verified (prerequisites, version numbers, etc.)
+* Informative, helpful, consistent error messages that help to diagnose the problem and to make progress
+* Allow continuation of deployment process in case of error disrupted previous run (should not need to wipe everything)
+ * Idempotent steps as much as possible
+* Easy full re-deployment after changes made in local devenv shall be supported (and be fast)
+* Embedded documentation, but also available on-line
+* All upstream artifacts shall be version-controlled, traceable and verifiable (md5, sha1 or sha256)
+ * Upstream includes:
+ * Vagrant box
+ * Docker images
+ * git source repos
+ * [git binary artifacts]
+ * Maven repos
+ * Python/pip repos
+ * Debian repos
+* Upstream references shall be configurable
+* We shall support the creation and the use of controlled local artifact repositories which can contain all upstream dependencies
+ * To support isolated lab environments
+ * To allow cascading, connected (recursive) CI/CD pipelines
+ * Best would be to consolidate all these formats into one packaging and deployment format: docker image/container
+* When/if upstream points to an intranet repo, deployment process must not require Internet access (only access to the local artifact repo)
+* Rely on DevOps 2.0 latest/best practices:
+ * Not to reinvent the wheel
+ * Allow people to be self-sufficient (using their modern skills)
+ * Will make our job easier: no need to explain; we can point to contemporary docs
+* Number of git repos involved in CORD deployment should be "healthy"
+ * One top-level CI/CD repo to allow above experience
+ * It may check out a few additional sub-repos automatically
+ * Sub-repos should be used for truly self-contained projects:
+ * Where loose coupling with other projects is really desirable
+ * When there repo lines up naturally with team ownership
+ * When project is useful without the rest of the CORD ensemble
+* Three domains of configuration:
+ * Source of upstream prerequisites
+ * Target deployment environment
+ * Deployed use-case
+* Multi-server (N server) deployment should not require to copy all artifacts remotely N time, but rather a one-time push/pull of such artifacts to a local repo, and additional servers shall pull from the local repo.
+* Well-supported and well-documented manual steps for the following work-flows:
+ * Dev host: Verify pre-requisites on dev host
+ * Dev host or dev env: Pull down or update local top-level repo
+ * Dev host: Build development env
+ * Dev host: start/stop dev env (once it is built)
+ * Dev env: Pull down all prerequisites
+ * Dev env: Update prerequisites after updating top-level repo (or modifying upstream configs)
+ * Dev env: Build all target artifacts (whatever needs building)
+ * Dev env: Run pre-deployment tests (if any)
+ * Dev env: Select server and start it if needed (docker image with docker registry)
+ * Dev env: Push all target artifacts to target artifact repo (with optional tag)
+ * Dev env: Select / configure target (manual config of target descriptor files)
+ * Dev env: Verify target readiness
+ * Dev env: Deploy to select target (from optional tag)
+ * Target: Execute select post-deploy test suite(s) on select target
+ * Dev env or target: Destroy/wipe target (as applicable)
+
+
+## Detailed Longer-term Requirements
+
+* Supported evaluation use-cases shall include:
+ * Testing HA scenarios
+ * Testing scale-out and scale-in scenarios
+ * Testing upgrade process scenarios
+ * Numerical tests (performance tests)
+ * [Posting tests to test report server]
+* The CI/CD environment shall be embedded into the CORD repo
+* The CI/CD environment shall support easy setup of:
+ * Multiple deployment stations (for various types of tests, such as post-commit regression tests, daily smoke- and performance tests)
+ * Local or remote git repo for SCM
+ * Self-contained jenkins profile(s) for automating CI/CD pipeline (useful/meaningful as is, but customizable by user)
+
+
+# Design
+
+[to be flashed out once we ratify the requirements]
+
+
+## Open Issues
+
+* On AWS we need a container-only use-case (absolutely no VMs) - is that feasible?
+* Same is needed in a Vagrant-based local simulated env - is that feasible?
+* Role of local Orchestrator in deployment and management of the basic infrastructure - we believe that this shall be minimized to avoid self-management loop. Specifically, local Orchestrator shall not manage what it depends on for its own functionality
diff --git a/docs/quick.md b/docs/quick.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/docs/quick.md
diff --git a/docs/quickstart.md b/docs/quickstart.md
new file mode 100644
index 0000000..494bf23
--- /dev/null
+++ b/docs/quickstart.md
@@ -0,0 +1,117 @@
+# OpenCORD Quick Start Guide
+
+[*This description is for a stand-alone bare-metal target server.
+If we succeed to bring up CORD on a VM, we will relax the text and
+go for the simpler experience.*]
+
+This tutorial walks you through the steps to bring up an OpenCORD "POD" on a single server.
+This deployment uses a simulated fabric, but it is good to get a quick feel
+for what is involved and how CORD works.
+
+Specifically, the tutorial covers the following:
+
+1. Bring up a build environment
+2. Fetch and build all binary artifacts
+3. Deploy the software to the target platform (server)
+4. Run some tests on the platform
+5. Clean-up
+
+### What you need (Prerequisites)
+
+You will need a build machine (can be your developer laptop) and a target server.
+
+Build host:
+
+* Mac OS X, Linux, or Windows with a 64-bit OS
+* Git (2.5.4 or later) - [TODO add pointers and/or instructions]
+* Vagrant (1.8.1 or later) - [TODO add pointers and/or instructions]
+* Access to the Internet (at least through the fetch phase)
+* SSH access to the target server
+
+Target server:
+
+* 64-bit server, with
+ * 16GB+ RAM
+ * 30GB+ disk
+* Ubuntu 14.04 LTS freshly installed (see [TBF]() for instruction on how to install Ubuntu 14.04).
+
+
+### Bring up an Use the OpenCORD Build Environment
+
+On the build host, clone the OpenCORD integration repository and switch into its top directory:
+
+ ```
+ git clone https://gerrit.opencord.org/opencord
+ cd opencord
+ ```
+
+Bring up the standardized OpenCORD build and development environment (VM). This will take a few minutes, depending on your connection speed:
+
+ ```
+ vagrant up corddev
+ ```
+
+Login to the build environment:
+
+ ```
+ vagrant ssh corddev
+ ```
+
+Switch to the OpenCORD integration directory, which is shared from your host:
+
+ ```
+ cd /opencord
+ ```
+
+Pre-fetch all pre-requisites needed to build all components for OpenCORD. This is the step that takes the longest time as a large number of images and files need to be downloaded.
+
+ ```
+ ./gradlew fetch
+ ```
+
+Time to build artifacts needed for deployment:
+
+ ```
+ ./gradlew build
+ ```
+
+Lets publish all artifacts to the staging registry (Docker registry).
+
+ ```
+ ./gradlew publish
+ ```
+
+
+### Deploy to the Target Server
+
+Deploy the software to the target platform:
+
+ ```
+ ./gradlew deploy
+ ```
+
+Execute a set of basic health tests on the platform:
+
+ ```
+ ./gradlew post-deploy-tests
+ ```
+
+
+### Optional cleanup
+
+Exit from the build environment and destroy it:
+
+ ```
+ exit
+ vagrant destroy -f
+ ```
+
+
+### Congratulations
+
+If you got this far, you successfully built, deployed, and tested your first OpenCORD POD.
+
+
+### Further Steps
+
+[TODO]
\ No newline at end of file
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/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..2c6137b
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..cf051c0
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu May 05 16:09:18 PDT 2016
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..72d362d
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/scripts/bootstrap_ansible.sh b/scripts/bootstrap_ansible.sh
new file mode 100755
index 0000000..d8550fc
--- /dev/null
+++ b/scripts/bootstrap_ansible.sh
@@ -0,0 +1,25 @@
+#!/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
+cp /opencord/ansible/ansible.cfg /etc/ansible/ansible.cfg
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..8a5ffa7
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+//include 'components/nginx'
+