summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kud/hosting_providers/vagrant/Vagrantfile4
-rw-r--r--kud/tests/vIPSec/README.md36
-rwxr-xr-xkud/tests/vIPSec/ipsec163
-rwxr-xr-xkud/tests/vIPSec/pktgen77
-rwxr-xr-xkud/tests/vIPSec/remote_ipsec164
-rwxr-xr-xkud/tests/vIPSec/sink48
-rw-r--r--src/k8splugin/api/brokerhandler.go14
-rw-r--r--src/k8splugin/api/brokerhandler_test.go49
-rw-r--r--src/k8splugin/api/profilehandler.go29
-rw-r--r--src/k8splugin/api/profilehandler_test.go13
-rw-r--r--src/k8splugin/internal/app/instance.go27
-rw-r--r--src/k8splugin/internal/db/README.md123
-rw-r--r--src/k8splugin/internal/db/testing.go14
-rw-r--r--src/k8splugin/internal/rb/definition.go48
-rw-r--r--src/k8splugin/internal/rb/profile.go28
-rw-r--r--src/orchestrator/go.sum1
-rw-r--r--src/orchestrator/internal/db/README.md123
-rw-r--r--src/orchestrator/internal/logutils/logger.go28
18 files changed, 923 insertions, 66 deletions
diff --git a/kud/hosting_providers/vagrant/Vagrantfile b/kud/hosting_providers/vagrant/Vagrantfile
index f771d549..2d1b5ab4 100644
--- a/kud/hosting_providers/vagrant/Vagrantfile
+++ b/kud/hosting_providers/vagrant/Vagrantfile
@@ -10,8 +10,8 @@
##############################################################################
box = {
- :virtualbox => { :name => 'elastic/ubuntu-18.04-x86_64', :version => '20191013.0.0' },
- :libvirt => { :name => 'generic/ubuntu1810'}
+ :virtualbox => { :name => 'elastic/ubuntu-16.04-x86_64', :version => '20180708.0.0' },
+ :libvirt => { :name => 'elastic/ubuntu-16.04-x86_64', :version=> '20180210.0.0'}
}
require 'yaml'
diff --git a/kud/tests/vIPSec/README.md b/kud/tests/vIPSec/README.md
new file mode 100644
index 00000000..3046db7a
--- /dev/null
+++ b/kud/tests/vIPSec/README.md
@@ -0,0 +1,36 @@
+# vIPSec use case in ONAP
+This use case is composed of four virtual functions (VFs) including two
+IPSec gateways, a packet generator and a traffic sink, each running in
+separate Ubuntu Virtual Machines:
+
+ * [Packet generator][1]: Sends packets to the packet sink through the
+tunnel constructed thru IPSec. This includes a script that installs the
+packet generator based on packetgen[4].
+ * [IPsec gateways][2]: Two IPSec gateways constructed the secure tunnel
+for traffic transportation. This includes a script to install and configure
+the IPSec gateways thru VPP.
+ * [Traffic sink][3]: Displays the traffic volume that lands at the sink
+VM using the link http://192.168.80.250:667 through your browser
+and enable automatic page refresh by clicking the "Off" button. You
+can see the traffic volume in the charts.
+
+This set of scripts aims to construct the vIPSec use case in order to set
+up a secure tunnel between peers and improve its performance along with
+hardware acceleration technologies such as SRIOV and QAT.
+
+User can apply the helm chart named 'vipsec' inside the k8s/kud/demo folder
+to set up the whole use case. A fully-functional Kubernetes cluster, Virtlet
+as well as ovn4nfv-k8s[5] plugin need to be pre-installed for the usage.
+*[Place needs improvements] After having the virtual machines ready, please
+manually change the MAC address inside the ipsec.conf to enable the routing.
+And also start up the packetgen to send packet with src and dst defined in
+the templates/values.yaml inside the helm chart. Detail instructions will be
+put inside the helm chart.
+
+If you'd like to test the performance with QAT/SRIOV involved, first get
+these hardwares pre-configured. Then change the value of 'qat_enabled' and
+'sriov_enabled' inside templates/values.yaml of the helm chart accordingly.
+User could observe variance in throughput inside the traffic sink.
+
+[4] https://pktgen-dpdk.readthedocs.io/en/latest/
+[5] https://github.com/opnfv/ovn4nfv-k8s-plugin
diff --git a/kud/tests/vIPSec/ipsec b/kud/tests/vIPSec/ipsec
new file mode 100755
index 00000000..4b278574
--- /dev/null
+++ b/kud/tests/vIPSec/ipsec
@@ -0,0 +1,163 @@
+#!/bin/bash
+# COPYRIGHT NOTICE STARTS HERE
+#
+# Copyright 2019 Intel Co., Ltd.
+#
+# 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.
+#
+# COPYRIGHT NOTICE ENDS HERE
+
+# This script prepares the runtime environment
+# for running vIPSec shell scripts on Ubuntu 18.04
+
+set -o nounset
+set -o pipefail
+set -o xtrace
+set -o errexit
+
+function setup_dependencies {
+ apt-get update
+ apt-get install -y curl gnupg2 pciutils make gcc libnuma-dev python git linux-headers-`uname -r` module-init-tools libssl-dev
+ echo "deb [trusted=yes] https://packagecloud.io/fdio/release/ubuntu bionic main" >> /etc/apt/sources.list.d/99fd.io.list
+ curl -L https://packagecloud.io/fdio/master/gpgkey | apt-key add -
+}
+
+function install_vpp {
+ apt-get update
+ apt-get install -y vpp vpp-plugin-core vpp-plugin-dpdk
+}
+
+function install_dpdk {
+ cd /opt
+ git clone http://dpdk.org/git/dpdk
+ cd /opt/dpdk
+ export RTE_TARGET=x86_64-native-linux-gcc/ && export DESTDIR=/opt/dpdk && export RTE_SDK=/opt/dpdk && make install T=x86_64-native-linux-gcc
+ modprobe uio
+ insmod x86_64-native-linux-gcc/kmod/igb_uio.ko
+}
+
+function ipsec_settings {
+# Create vpp configuration file
+ cat > /opt/config/vpp.config << EOF
+ unix {
+ exec /opt/config/ipsec.conf
+ nodaemon
+ cli-listen /run/vpp/cli.sock
+ log /tmp/vpp.log
+ }
+
+ cpu {
+ main-core 0
+ corelist-workers 1
+ }
+
+ dpdk {
+ socket-mem 512
+ log-level debug
+ no-tx-checksum-offload
+ dev default{
+ num-tx-desc 512
+ num-rx-desc 512
+ }
+ dev interfaceABus
+ {
+ workers 0
+ }
+ dev interfaceBBus
+ {
+ workers 0
+ }
+ vdev crypto_aesni_mb0
+
+ no-multi-seg
+
+ #enable_cryptodev
+
+ }
+EOF
+
+# Check if sriov and qat are enabled, bind the pci devices with igb_uio driver
+ if [ "$sriov_enabled" = true ]; then
+ export interfaceABus=$(lspci -D -nn | grep -m1 '8086:154c' | cut -d ' ' -f 1)
+ export interfaceBBus=$(lspci -D -nn | grep -m2 '8086:154c' | cut -d ' ' -f 1 | tail -n1)
+ else
+ export interfaceABus=$(ls -la /sys/class/net | grep 'eth1' | cut -d '/' -f 5)
+ export interfaceBBus=$(ls -la /sys/class/net | grep 'eth3' | cut -d '/' -f 5)
+ fi
+ sed -i -e "s/interfaceABus/${interfaceABus}/g" -e "s/interfaceBBus/${interfaceBBus}/g" /opt/config/vpp.config
+ python /opt/dpdk/usertools/dpdk-devbind.py -b igb_uio $interfaceABus $interfaceBBus
+ export interfaceA=$(vppctl sh int | awk '$2 == "1"' | cut -d ' ' -f 1)
+ export interfaceB=$(vppctl sh int | awk '$2 == "2"' | cut -d ' ' -f 1)
+
+ if [ "$qat_enabled" = true ]; then
+ export qatABus=$(lspci -D -nn | grep -m1 '8086:37c9' | cut -d ' ' -f 1)
+ export qatBBus=$(lspci -D -nn | grep -m2 '8086:37c9' | cut -d ' ' -f 1 | tail -n1)
+ python /opt/dpdk/usertools/dpdk-devbind.py -b igb_uio $qatABus $qatBBus
+ sed -i "/#enable_cryptodev/a\n dev $qatABus\n dev $qatBBus\n" /opt/config/vpp.config
+ sed -i "/vdev crypto_aesni_mb0/d" /opt/config/vpp.config
+ fi
+
+# Create the sample ipsec configuration file
+ cat > /opt/config/ipsec.conf << EOF
+ set interface state VirtualFunctionEthernet0/5/0 up
+ set interface state VirtualFunctionEthernet0/6/0 up
+
+ set interface ip address VirtualFunctionEthernet0/5/0 input_interface_ip/24
+ set interface ip address VirtualFunctionEthernet0/6/0 output_interface_ip/24
+
+ set int promiscuous on VirtualFunctionEthernet0/5/0
+ set int promiscuous on VirtualFunctionEthernet0/6/0
+
+ set ip arp VirtualFunctionEthernet0/6/0 remote_tunnel_ip fa:16:3e:a6:e4:c7
+ set ip arp VirtualFunctionEthernet0/5/0 input_interface_ip fa:16:3e:f1:65:dc
+
+ ip route add count 1 packet_dst/32 via route_interface VirtualFunctionEthernet0/6/0
+
+ ipsec spd add 1
+ set interface ipsec spd VirtualFunctionEthernet0/6/0 1
+ ipsec sa add 1 spi 1921681003 esp tunnel-src output_interface_ip tunnel-dst remote_tunnel_ip crypto-key 2b7e151628aed2a6abf7158809cf4f3d crypto-alg aes-cbc-128 integ-key 6867666568676665686766656867666568676669 integ-alg sha1-96
+ ipsec policy add spd 1 traffic_direction priority 100 action protect sa 1 local-ip-range packet_src-packet_src remote-ip-range packet_dst-packet_dst
+ ipsec policy add spd 1 traffic_direction priority 90 protocol 50 action bypass local-ip-range packet_src-255.255.255.255 remote-ip-range remote_tunnel_ip-remote_tunnel_ip
+EOF
+
+# Replace all ip and interfaces inside the ipsec configuration file
+ sed -i -e "s/input_interface_ip/${input_interface_ip}/g" -e "s/output_interface_ip/${output_interface_ip}/g" -e "s/remote_tunnel_ip/${remote_tunnel_ip}/g" -e "s/route_interface/${route_interface}/g" -e "s#VirtualFunctionEthernet0/5/0#${interfaceA}#g" -e "s#VirtualFunctionEthernet0/6/0#${interfaceB}/g" -e "s/packet_src/${packet_src}/g" -e "s/packet_dst/${packet_dst}/g" -e "s/traffic_direction/${traffic_direction}/g" /opt/config/ipsec.conf
+ vpp -c /opt/config/vpp.config
+}
+
+
+mkdir /opt/config
+echo "$demo_artifacts_version" > /opt/config/demo_artifacts_version.txt
+echo "$dcae_collector_ip" > /opt/config/dcae_collector_ip.txt
+echo "$dcae_collector_port" > /opt/config/dcae_collector_port.txt
+echo "$ipsec_private_net_gw" > /opt/config/ipsec_private_net_gw_ip.txt
+echo "$ipsec_private_net_cidr" > /opt/config/ipsec_private_net_cidr.txt
+echo "$ipsec_private_network_name" > /opt/config/ipsec_private_network_name.txt
+echo "$packet_src" > /opt/config/packet_source_ip.txt
+echo "$packet_dst" > /opt/config/packet_destination_ip.txt
+echo "$remote_tunnel_ip" > /opt/config/remote_tunnel.txt
+echo "$route_interface" > /opt/config/route_interface.txt
+echo "$traffic_direction" > /opt/config/traffic_direction.txt
+echo "$vipsecA_private_ip_0" > /opt/config/vipsecA_private_ip0.txt
+echo "$vipsecA_private_ip_2" > /opt/config/vipsecA_private_ip2.txt
+echo "$protected_clientA_network_name" > /opt/config/protected_clientA_network_name.txt
+echo "$protected_clientA_net_gw" > /opt/config/protected_clientA_net_gw.txt
+echo "$protected_clientA_net_cidr" > /opt/config/protected_clientA_net_cidr.txt
+
+echo 'vm.nr_hugepages = 1024' >> /etc/sysctl.conf
+sysctl -p
+
+setup_dependencies
+install_vpp
+install_dpdk
+ipsec_settings
diff --git a/kud/tests/vIPSec/pktgen b/kud/tests/vIPSec/pktgen
new file mode 100755
index 00000000..14d7e6ca
--- /dev/null
+++ b/kud/tests/vIPSec/pktgen
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+# COPYRIGHT NOTICE STARTS HERE
+#
+# Copyright 2019 Intel Co., Ltd.
+#
+# 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.
+#
+# COPYRIGHT NOTICE ENDS HERE
+
+# This script prepares the runtime environment
+# for running vIPSec shell scripts on Ubuntu18.04
+
+set -o nounset
+set -o pipefail
+set -o xtrace
+set -o errexit
+
+
+DPDK_DIR=$PWD/dpdk
+Pktgen_Dir=$PWD/pktgen-dpdk
+
+function setup_dependencies {
+ sudo apt-get update
+ git clone http://dpdk.org/git/dpdk
+ git clone http://dpdk.org/git/apps/pktgen-dpdk
+ KERNEL_VERSION=$(uname -r)
+ echo $KERNEL_VERSION
+ sudo apt-get install -y linux-headers-$KERNEL_VERSION libpcap-dev gcc make libnuma-dev liblua5.3-dev python
+}
+
+function build_dpdk {
+ export RTE_SDK=$DPDK_DIR
+ export RTE_TARGET=x86_64-native-linux-gcc
+ export DESTDIR=$DPDK_DIR
+ cd $RTE_SDK
+ make install T=x86_64-native-linux-gcc
+ echo "DPDK install finished"
+ modprobe uio
+ insmod x86_64-native-linux-gcc/kmod/igb_uio.ko
+ export interface=$(lspci -nn | grep -m1 'Ethernet controller' | cut -d ' ' -f 1)
+ python ./usertools/dpdk-devbind.py -b igb_uio $interface
+}
+
+function build_pktgen {
+ cd $Pktgen_Dir
+ export RTE_SDK=$DPDK_DIR
+ export RTE_TARGET=x86_64-native-linux-gcc
+ make
+}
+
+mkdir /opt/config
+echo "$demo_artifacts_version" > /opt/config/demo_artifacts_version.txt
+echo "$vpg_private_ip_0" > /opt/config/vpg_private_ip0.txt
+echo "$ipsec_a_private_ip_0" > /opt/config/ipsec_a_private_ip0.txt
+echo "$protected_clientA_network_name" > /opt/config/protected_clientA_network_name.txt
+echo "$dcae_collector_ip" > /opt/config/dcae_collector_ip.txt
+echo "$dcae_collector_port" > /opt/config/dcae_collector_port.txt
+echo "$protected_clientA_net_gw" > /opt/config/protected_clientA_net_gw.txt
+echo "$protected_clientA_net_cidr" > /opt/config/protected_clientA_net_cidr.txt
+
+echo 'vm.nr_hugepages = 1024' >> /etc/sysctl.conf
+sysctl -p
+
+setup_dependencies
+build_dpdk
+build_pktgen
diff --git a/kud/tests/vIPSec/remote_ipsec b/kud/tests/vIPSec/remote_ipsec
new file mode 100755
index 00000000..6a676c96
--- /dev/null
+++ b/kud/tests/vIPSec/remote_ipsec
@@ -0,0 +1,164 @@
+#!/bin/bash
+
+# COPYRIGHT NOTICE STARTS HERE
+#
+# Copyright 2019 Intel Co., Ltd.
+#
+# 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.
+#
+# COPYRIGHT NOTICE ENDS HERE
+
+# This script prepares the runtime environment
+# for running vIPSec shell scripts on Ubuntu18.04
+
+set -o nounset
+set -o pipefail
+set -o xtrace
+set -o errexit
+
+function setup_dependencies {
+ apt-get update
+ apt-get install -y curl gnupg2 pciutils make gcc libnuma-dev python git linux-headers-`uname -r` module-init-tools libssl-dev
+ echo "deb [trusted=yes] https://packagecloud.io/fdio/release/ubuntu bionic main" >> /etc/apt/sources.list.d/99fd.io.list
+ curl -L https://packagecloud.io/fdio/master/gpgkey | apt-key add -
+}
+
+function install_vpp {
+ apt-get update
+ apt-get install -y vpp vpp-plugin-core vpp-plugin-dpdk
+}
+
+function install_dpdk {
+ cd /opt
+ git clone http://dpdk.org/git/dpdk
+ cd /opt/dpdk
+ export RTE_TARGET=x86_64-native-linux-gcc/ && export DESTDIR=/opt/dpdk && export RTE_SDK=/opt/dpdk && make install T=x86_64-native-linux-gcc
+ modprobe uio
+ insmod x86_64-native-linux-gcc/kmod/igb_uio.ko
+}
+
+function ipsec_settings {
+# Create vpp configuration file
+ cat > /opt/config/vpp.config << EOF
+ unix {
+ exec /opt/config/ipsec.conf
+ nodaemon
+ cli-listen /run/vpp/cli.sock
+ log /tmp/vpp.log
+ }
+
+ cpu {
+ main-core 0
+ corelist-workers 1
+ }
+
+ dpdk {
+ socket-mem 512
+ log-level debug
+ no-tx-checksum-offload
+ dev default{
+ num-tx-desc 512
+ num-rx-desc 512
+ }
+ dev interfaceABus
+ {
+ workers 0
+ }
+ dev interfaceBBus
+ {
+ workers 0
+ }
+ vdev crypto_aesni_mb0
+
+ no-multi-seg
+
+ #enable_cryptodev
+
+ }
+EOF
+
+# Check if sriov and qat are enabled, bind the pci devices with igb_uio driver
+ if [ "$sriov_enabled" = true ]; then
+ export interfaceABus=$(lspci -D -nn | grep -m1 '8086:154c' | cut -d ' ' -f 1)
+ export interfaceBBus=$(lspci -D -nn | grep -m2 '8086:154c' | cut -d ' ' -f 1 | tail -n1)
+ else
+ export interfaceABus=$(ls -la /sys/class/net | grep 'eth1' | cut -d '/' -f 5)
+ export interfaceBBus=$(ls -la /sys/class/net | grep 'eth3' | cut -d '/' -f 5)
+ fi
+ sed -i -e "s/interfaceABus/${interfaceABus}/g" -e "s/interfaceBBus/${interfaceBBus}/g" /opt/config/vpp.config
+ python /opt/dpdk/usertools/dpdk-devbind.py -b igb_uio $interfaceABus $interfaceBBus
+ export interfaceA=$(vppctl sh int | awk '$2 == "1"' | cut -d ' ' -f 1)
+ export interfaceB=$(vppctl sh int | awk '$2 == "2"' | cut -d ' ' -f 1)
+
+ if [ "$qat_enabled" = true ]; then
+ export qatABus=$(lspci -D -nn | grep -m1 '8086:37c9' | cut -d ' ' -f 1)
+ export qatBBus=$(lspci -D -nn | grep -m2 '8086:37c9' | cut -d ' ' -f 1 | tail -n1)
+ python /opt/dpdk/usertools/dpdk-devbind.py -b igb_uio $qatABus $qatBBus
+ sed -i "/#enable_cryptodev/a\n dev $qatABus\n dev $qatBBus\n" /opt/config/vpp.config
+ sed -i "/vdev crypto_aesni_mb0/d" /opt/config/vpp.config
+ fi
+
+# Create ipsec configuration file
+ cat > /opt/config/ipsec.conf << EOF
+ set interface state VirtualFunctionEthernet0/5/0 up
+ set interface state VirtualFunctionEthernet0/6/0 up
+
+ set interface ip address VirtualFunctionEthernet0/5/0 input_interface_ip/24
+ set interface ip address VirtualFunctionEthernet0/6/0 output_interface_ip/24
+
+ set int promiscuous on VirtualFunctionEthernet0/5/0
+ set int promiscuous on VirtualFunctionEthernet0/6/0
+
+ set ip arp VirtualFunctionEthernet0/6/0 remote_tunnel_ip fa:16:3e:a6:e4:c7
+ set ip arp VirtualFunctionEthernet0/5/0 routing_ip fa:16:3e:f1:65:dc
+
+ ip route add count 1 packet_dst/32 via route_interface VirtualFunctionEthernet0/6/0
+
+ ipsec spd add 1
+ set interface ipsec spd VirtualFunctionEthernet0/6/0 1
+ ipsec sa add 1 spi 1921681004 esp tunnel-src local_tunnel_ip tunnel-dst remote_tunnel_ip crypto-key 2b7e151628aed2a6abf7158809cf4f3d crypto-alg aes-cbc-128 integ-key 6867666568676665686766656867666568676669 integ-alg sha1-96
+ ipsec policy add spd 1 traffic_direction priority 100 action protect sa 1 local-ip-range packet_src-packet_src remote-ip-range packet_dst-packet_dst
+ ipsec policy add spd 1 traffic_direction priority 90 protocol 50 action bypass local-ip-range packet_src-255.255.255.255 remote-ip-range remote_tunnel_ip-remote_tunnel_ip
+EOF
+
+# Replace the actual ip and interfaces into the ipsec configuration
+ sed -i -e "s/input_interface_ip/${input_interface_ip}/g" -e "s/output_interface_ip/${output_interface_ip}/g" -e "s/routing_ip/${vsn_private_ip_0}/g" -e "s#VirtualFunctionEthernet0/5/0#${interfaceA}#g" -e "s#VirtualFunctionEthernet0/6/0#${interfaceB}#g" -e "s/local_tunnel_ip/${local_tunnel_ip}/g" -e "s/remote_tunnel_ip/${remote_tunnel_ip}/g" -e "s/route_interface/${route_interface}/g" -e "s/packet_src/${packet_src}/g" -e "s/packet_dst/${packet_dst}/g" -e "s/traffic_direction/${traffic_direction}/g" /opt/config/ipsec.conf
+ vpp -c /opt/config/vpp.config
+}
+
+
+mkdir /opt/config
+echo "$demo_artifacts_version" > /opt/config/demo_artifacts_version.txt
+echo "$dcae_collector_ip" > /opt/config/dcae_collector_ip.txt
+echo "$dcae_collector_port" > /opt/config/dcae_collector_port.txt
+echo "$ipsec_private_net_gw" > /opt/config/ipsec_private_net_gw_ip.txt
+echo "$ipsec_private_net_cidr" > /opt/config/ipsec_private_net_cidr.txt
+echo "$ipsec_private_network_name" > /opt/config/ipsec_private_network_name.txt
+echo "$packet_src" > /opt/config/packet_source_ip.txt
+echo "$packet_dst" > /opt/config/packet_destination_ip.txt
+echo "$remote_tunnel_ip" > /opt/config/remote_tunnel.txt
+echo "$route_interface" > /opt/config/route_interface.txt
+echo "$traffic_direction" > /opt/config/traffic_direction.txt
+echo "$vipsecB_private_ip_0" > /opt/config/vipsecB_private_ip0.txt
+echo "$vipsecB_private_ip_2" > /opt/config/vipsecB_private_ip2.txt
+echo "$protected_clientB_network_name" > /opt/config/protected_clientB_network_name.txt
+echo "$protected_clientB_net_gw" > /opt/config/protected_clientB_net_gw.txt
+echo "$protected_clientB_net_cidr" > /opt/config/protected_clientB_net_cidr.txt
+
+echo 'vm.nr_hugepages = 1024' >> /etc/sysctl.conf
+sysctl -p
+
+setup_dependencies
+install_vpp
+install_dpdk
+ipsec_settings
diff --git a/kud/tests/vIPSec/sink b/kud/tests/vIPSec/sink
new file mode 100755
index 00000000..c180d43c
--- /dev/null
+++ b/kud/tests/vIPSec/sink
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# COPYRIGHT NOTICE STARTS HERE
+#
+# Copyright 2019 Intel Co., Ltd.
+#
+# 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.
+#
+# COPYRIGHT NOTICE ENDS HERE
+
+# This script prepares the runtime environment
+# for running vIPSec shell scripts on Ubuntu 18.04
+
+set -o nounset
+set -o pipefail
+set -o xtrace
+set -o errexit
+
+function setup_dependencies {
+ apt-get update
+ apt install -y wget darkstat net-tools unzip
+
+ # Configure and run Darkstat
+ sed -i "s/START_DARKSTAT=.*/START_DARKSTAT=yes/g;s/INTERFACE=.*/INTERFACE=\"-i eth1\"/g" /etc/darkstat/init.cfg
+
+ systemctl restart darkstat
+}
+
+mkdir -p /opt/config/
+echo "$protected_net_cidr" > /opt/config/protected_net_cidr.txt
+echo "$vfw_private_ip_0" > /opt/config/fw_ipaddr.txt
+echo "$vsn_private_ip_0" > /opt/config/sink_ipaddr.txt
+echo "$demo_artifacts_version" > /opt/config/demo_artifacts_version.txt
+echo "$protected_net_gw" > /opt/config/protected_net_gw.txt
+echo "$protected_private_net_cidr" > /opt/config/unprotected_net.txt
+
+setup_dependencies
+
diff --git a/src/k8splugin/api/brokerhandler.go b/src/k8splugin/api/brokerhandler.go
index b377baf1..7671db44 100644
--- a/src/k8splugin/api/brokerhandler.go
+++ b/src/k8splugin/api/brokerhandler.go
@@ -134,15 +134,13 @@ func (b brokerInstanceHandler) createHandler(w http.ResponseWriter, r *http.Requ
return
}
- rbName := req.getAttributeValue(req.SDNCDirectives, "k8s-rb-definition-name")
- if rbName == "" {
- http.Error(w, "k8s-rb-definition-name is missing from sdnc-directives", http.StatusBadRequest)
+ if req.VFModuleModelInvariantID == "" {
+ http.Error(w, "vf-module-model-invariant-id is empty", http.StatusBadRequest)
return
}
- rbVersion := req.getAttributeValue(req.SDNCDirectives, "k8s-rb-definition-version")
- if rbVersion == "" {
- http.Error(w, "k8s-rb-definition-version is missing from sdnc-directives", http.StatusBadRequest)
+ if req.VFModuleModelVersionID == "" {
+ http.Error(w, "vf-module-model-version-id is empty", http.StatusBadRequest)
return
}
@@ -160,8 +158,8 @@ func (b brokerInstanceHandler) createHandler(w http.ResponseWriter, r *http.Requ
// Setup the resource parameters for making the request
var instReq app.InstanceRequest
- instReq.RBName = rbName
- instReq.RBVersion = rbVersion
+ instReq.RBName = req.VFModuleModelInvariantID
+ instReq.RBVersion = req.VFModuleModelVersionID
instReq.ProfileName = profileName
instReq.CloudRegion = cloudRegion
instReq.Labels = map[string]string{
diff --git a/src/k8splugin/api/brokerhandler_test.go b/src/k8splugin/api/brokerhandler_test.go
index 00ca3b7b..83ff588b 100644
--- a/src/k8splugin/api/brokerhandler_test.go
+++ b/src/k8splugin/api/brokerhandler_test.go
@@ -48,18 +48,19 @@ func TestBrokerCreateHandler(t *testing.T) {
expectedCode: http.StatusUnprocessableEntity,
},
{
- label: "Missing parameter failure",
+ label: "Missing vf-module-*-id parameter",
input: bytes.NewBuffer([]byte(`{
"vf-module-model-customization-id": "84sdfkio938",
- "user_directives": {
+ "vf-module-model-invariant-id": "123456qwerty",
+ "sdnc_directives": {
"attributes": [
{
- "attribute_name": "k8s-rb-definition-name",
- "attribute_value": "test-rbdef"
+ "attribute_name": "vf_module_name",
+ "attribute_value": "test-vf-module-name"
},
{
- "attribute_name": "k8s-rb-definition-version",
- "attribute_value": "v1"
+ "attribute_name": "k8s-rb-profile-name",
+ "attribute_value": "profile1"
}
]
}
@@ -67,9 +68,11 @@ func TestBrokerCreateHandler(t *testing.T) {
expectedCode: http.StatusBadRequest,
},
{
- label: "Deprecated parameters passed (user_directives)",
+ label: "Missing parameter from sdnc_directives",
input: bytes.NewBuffer([]byte(`{
- "vf-module-model-customization-id": "97sdfkio168",
+ "vf-module-model-customization-id": "84sdfkio938",
+ "vf-module-model-invariant-id": "123456qwerty",
+ "vf-module-model-version-id": "123qweasdzxc",
"sdnc_directives": {
"attributes": [
{
@@ -77,22 +80,6 @@ func TestBrokerCreateHandler(t *testing.T) {
"attribute_value": "test-vf-module-name"
}
]
- },
- "user_directives": {
- "attributes": [
- {
- "attribute_name": "rb-definition-name",
- "attribute_value": "test-rbdef"
- },
- {
- "attribute_name": "rb-definition-version",
- "attribute_value": "v1"
- },
- {
- "attribute_name": "rb-profile-name",
- "attribute_value": "profile1"
- }
- ]
}
}`)),
expectedCode: http.StatusBadRequest,
@@ -101,6 +88,8 @@ func TestBrokerCreateHandler(t *testing.T) {
label: "Succesfully create an Instance",
input: bytes.NewBuffer([]byte(`{
"vf-module-model-customization-id": "84sdfkio938",
+ "vf-module-model-invariant-id": "123456qwerty",
+ "vf-module-model-version-id": "123qweasdzxc",
"sdnc_directives": {
"attributes": [
{
@@ -108,14 +97,6 @@ func TestBrokerCreateHandler(t *testing.T) {
"attribute_value": "test-vf-module-name"
},
{
- "attribute_name": "k8s-rb-definition-name",
- "attribute_value": "test-rbdef"
- },
- {
- "attribute_name": "k8s-rb-definition-version",
- "attribute_value": "v1"
- },
- {
"attribute_name": "k8s-rb-profile-name",
"attribute_value": "profile1"
}
@@ -149,8 +130,8 @@ func TestBrokerCreateHandler(t *testing.T) {
{
ID: "HaKpys8e",
Request: app.InstanceRequest{
- RBName: "test-rbdef",
- RBVersion: "v1",
+ RBName: "123456qwerty",
+ RBVersion: "123qweasdzxc",
ProfileName: "profile1",
CloudRegion: "region1",
},
diff --git a/src/k8splugin/api/profilehandler.go b/src/k8splugin/api/profilehandler.go
index 68ab77a4..acd23060 100644
--- a/src/k8splugin/api/profilehandler.go
+++ b/src/k8splugin/api/profilehandler.go
@@ -21,6 +21,7 @@ import (
"io"
"io/ioutil"
"net/http"
+ "strings"
"github.com/onap/multicloud-k8s/src/k8splugin/internal/rb"
@@ -30,12 +31,12 @@ import (
// Used to store backend implementations objects
// Also simplifies mocking for unit testing purposes
type rbProfileHandler struct {
- // Interface that implements bundle Definition operations
- // We will set this variable with a mock interface for testing
+ // Interface that implements bundle profile operations
+ // Set this variable with a mock interface for testing
client rb.ProfileManager
}
-// createHandler handles creation of the definition entry in the database
+// createHandler creates a profile entry in the database
func (h rbProfileHandler) createHandler(w http.ResponseWriter, r *http.Request) {
var p rb.Profile
@@ -70,7 +71,7 @@ func (h rbProfileHandler) createHandler(w http.ResponseWriter, r *http.Request)
}
}
-// uploadHandler handles upload of the bundle tar file into the database
+// uploadHandler uploads the profile artifact tar file into the database
func (h rbProfileHandler) uploadHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
rbName := vars["rbname"]
@@ -97,8 +98,8 @@ func (h rbProfileHandler) uploadHandler(w http.ResponseWriter, r *http.Request)
w.WriteHeader(http.StatusOK)
}
-// getHandler handles GET operations on a particular ids
-// Returns a rb.Definition
+// getHandler gets a Profile Key in the database
+// Returns an rb.Profile
func (h rbProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
rbName := vars["rbname"]
@@ -107,8 +108,14 @@ func (h rbProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) {
ret, err := h.client.Get(rbName, rbVersion, prName)
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ // Separate "Not found" from generic DB errors
+ if strings.Contains(err.Error(), "Error finding") {
+ http.Error(w, err.Error(), http.StatusNotFound)
+ return
+ } else {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
}
w.Header().Set("Content-Type", "application/json")
@@ -120,8 +127,8 @@ func (h rbProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) {
}
}
-// getHandler handles GET operations on a particular ids
-// Returns a rb.Definition
+// getHandler gets all profiles of a Resource Bundle Key in the database
+// Returns a list of rb.Profile
func (h rbProfileHandler) listHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
rbName := vars["rbname"]
@@ -142,7 +149,7 @@ func (h rbProfileHandler) listHandler(w http.ResponseWriter, r *http.Request) {
}
}
-// deleteHandler handles DELETE operations on a particular bundle definition id
+// deleteHandler deletes a particular Profile Key in the database
func (h rbProfileHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
rbName := vars["rbname"]
diff --git a/src/k8splugin/api/profilehandler_test.go b/src/k8splugin/api/profilehandler_test.go
index 4dae377c..9ec9c54c 100644
--- a/src/k8splugin/api/profilehandler_test.go
+++ b/src/k8splugin/api/profilehandler_test.go
@@ -184,10 +184,19 @@ func TestRBProfileGetHandler(t *testing.T) {
},
},
{
- label: "Get Non-Exiting Bundle Profile",
- expectedCode: http.StatusInternalServerError,
+ label: "Get Non-Existing Profile",
+ expectedCode: http.StatusNotFound,
prname: "non-existing-profile",
rbProClient: &mockRBProfile{
+ Items: nil,
+ Err: pkgerrors.New("Error finding master table"),
+ },
+ },
+ {
+ label: "Faulty DB response",
+ expectedCode: http.StatusInternalServerError,
+ prname: "profile",
+ rbProClient: &mockRBProfile{
// list of Profiles that will be returned by the mockclient
Items: []rb.Profile{},
Err: pkgerrors.New("Internal Error"),
diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go
index fef9962f..5d8b2100 100644
--- a/src/k8splugin/internal/app/instance.go
+++ b/src/k8splugin/internal/app/instance.go
@@ -32,19 +32,21 @@ import (
// InstanceRequest contains the parameters needed for instantiation
// of profiles
type InstanceRequest struct {
- RBName string `json:"rb-name"`
- RBVersion string `json:"rb-version"`
- ProfileName string `json:"profile-name"`
- CloudRegion string `json:"cloud-region"`
- Labels map[string]string `json:"labels"`
+ RBName string `json:"rb-name"`
+ RBVersion string `json:"rb-version"`
+ ProfileName string `json:"profile-name"`
+ CloudRegion string `json:"cloud-region"`
+ Labels map[string]string `json:"labels"`
+ OverrideValues map[string]string `json:"override-values"`
}
// InstanceResponse contains the response from instantiation
type InstanceResponse struct {
- ID string `json:"id"`
- Request InstanceRequest `json:"request"`
- Namespace string `json:"namespace"`
- Resources []helm.KubernetesResource `json:"resources"`
+ ID string `json:"id"`
+ Request InstanceRequest `json:"request"`
+ Namespace string `json:"namespace"`
+ Resources []helm.KubernetesResource `json:"resources"`
+ OverrideValues map[string]string `json:"override-values"`
}
// InstanceMiniResponse contains the response from instantiation
@@ -133,7 +135,14 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
return InstanceResponse{}, pkgerrors.New("Unable to find Profile to create instance")
}
+ //Convert override values from map to array of strings of the following format
+ //foo=bar
overrideValues := []string{}
+ if i.OverrideValues != nil {
+ for k, v := range i.OverrideValues {
+ overrideValues = append(overrideValues, k+"="+v)
+ }
+ }
//Execute the kubernetes create command
sortedTemplates, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues)
diff --git a/src/k8splugin/internal/db/README.md b/src/k8splugin/internal/db/README.md
new file mode 100644
index 00000000..cba1b7ea
--- /dev/null
+++ b/src/k8splugin/internal/db/README.md
@@ -0,0 +1,123 @@
+# Database Abstraction Layer
+
+This package contains implementations of the Database interface defined in `store.go`
+Any database can be used as the backend as long as the following interface is implemented;
+
+```go
+type Store interface {
+ // Returns nil if db health is good
+ HealthCheck() error
+
+ // Unmarshal implements any unmarshaling needed for the database
+ Unmarshal(inp []byte, out interface{}) error
+
+ // Creates a new master table with key and links data with tag and
+ // creates a pointer to the newly added data in the master table
+ Create(table string, key Key, tag string, data interface{}) error
+
+ // Reads data for a particular key with specific tag.
+ Read(table string, key Key, tag string) ([]byte, error)
+
+ // Update data for particular key with specific tag
+ Update(table string, key Key, tag string, data interface{}) error
+
+ // Deletes a specific tag data for key.
+ // TODO: If tag is empty, it will delete all tags under key.
+ Delete(table string, key Key, tag string) error
+
+ // Reads all master tables and data from the specified tag in table
+ ReadAll(table string, tag string) (map[string][]byte, error)
+}
+```
+
+Therefore, `mongo.go`, `consul.go` implement the above interface and can be used as the backend as needed based on initial configuration.
+
+## Details on Mongo Implementation
+
+`mongo.go` implements the above interface using the `go.mongodb.org/mongo-driver` package.
+The code converts incoming binary data and creates a new document in the database.
+
+### Create
+
+Arguments:
+```go
+collection string
+key interface
+tag string
+data []byte
+```
+
+Create inserts the provided `data` into the `collection` which returns an auto-generated (by `mongodb`) ID which we then associate with the `key` that is provided as one of the arguments.
+
+We use the `FindOneAndUpdate` mongo API to achieve this with the `upsert` option set to `true`.
+We create the following documents in mongodb for each new definition added to the database:
+
+There is a Master Key document that contains references to other documents which are related to this `key`.
+
+#### Master Key Entry
+```json
+{
+ "_id" : ObjectId("5e0a8554b78a15f71d2dce7e"),
+ "key" : { "rbname" : "edgex", "rbversion" : "v1"},
+ "defmetadata" : ObjectId("5e0a8554be261ecb57f067eb"),
+ "defcontent" : ObjectId("5e0a8377bcfcdd0f01dc7b0d")
+}
+```
+#### Metadata Key Entry
+```json
+{
+ "_id" : ObjectId("5e0a8554be261ecb57f067eb"),
+ "defmetadata" : { "rbname" : "edgex", "rbversion" : "v1", "chartname" : "", "description" : "", "labels" : null }
+}
+```
+#### Definition Content
+```json
+{
+ "_id" : ObjectId("5e0a8377bcfcdd0f01dc7b0d"),
+ "defcontent" : "H4sICCVd3FwAA3Byb2ZpbGUxLnRhcgDt1NEKgjAUxvFd7ylG98aWOsGXiYELxLRwJvj2rbyoIPDGiuD/uzmwM9iB7Vvruvrgw7CdXHsUn6Ejm2W3aopcP9eZLYRJM1voPN+ZndAm16kVSn9onheXMLheKeGqfdM0rq07/3bfUv9PJUkiR9+H+tSVajRymM6+lEqN7njxoVSbU+z2deX388r9nWzkr8fGSt5d79pnLOZfm0f+dRrzb7P4DZD/LyDJAAAAAAAAAAAAAAAA/+0Ksq1N5QAoAAA="
+}
+```
+
+### Unmarshal
+
+Data in mongo is stored as `bson` which is a compressed form of `json`. We need mongo to convert the stored `bson` data to regular `json`
+that we can use in our code when returned.
+
+We just use the `bson.Unmarshal` API to achieve this.
+
+### Read
+
+Arguments:
+```go
+collection string
+key interface
+tag string
+```
+
+Read is straight forward and it uses the `FindOne` API to find our Mongo document based on the provided `key` and then gets the corresponding data for the given `tag`. It will return []byte which can then be passed to the `Unmarshal` function to get the desired GO object.
+
+### Delete
+
+Delete is similar to Read and deletes all the objectIDs being stored for a given `key` in the collection.
+
+## Testing Interfaces
+
+The following interface exists to allow for the development of unit tests which don't require mongo to be running.
+It is mentioned so in the code as well.
+
+```go
+// MongoCollection defines the a subset of MongoDB operations
+// Note: This interface is defined mainly for mock testing
+type MongoCollection interface {
+ InsertOne(ctx context.Context, document interface{},
+ opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
+ FindOne(ctx context.Context, filter interface{},
+ opts ...*options.FindOneOptions) *mongo.SingleResult
+ FindOneAndUpdate(ctx context.Context, filter interface{},
+ update interface{}, opts ...*options.FindOneAndUpdateOptions) *mongo.SingleResult
+ DeleteOne(ctx context.Context, filter interface{},
+ opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
+ Find(ctx context.Context, filter interface{},
+ opts ...*options.FindOptions) (*mongo.Cursor, error)
+}
+``` \ No newline at end of file
diff --git a/src/k8splugin/internal/db/testing.go b/src/k8splugin/internal/db/testing.go
index 5f69dcb4..9a427e03 100644
--- a/src/k8splugin/internal/db/testing.go
+++ b/src/k8splugin/internal/db/testing.go
@@ -15,6 +15,7 @@ package db
import (
"encoding/json"
+
pkgerrors "github.com/pkg/errors"
)
@@ -40,6 +41,19 @@ func (m *MockDB) HealthCheck() error {
}
func (m *MockDB) Create(table string, key Key, tag string, data interface{}) error {
+ djs, err := json.Marshal(data)
+ if err != nil {
+ return err
+ }
+
+ d := make(map[string][]byte)
+ d[tag] = djs
+
+ if m.Items == nil {
+ m.Items = make(map[string]map[string][]byte)
+ }
+ m.Items[key.String()] = d
+
return m.Err
}
diff --git a/src/k8splugin/internal/rb/definition.go b/src/k8splugin/internal/rb/definition.go
index 65ae8e00..73ea44da 100644
--- a/src/k8splugin/internal/rb/definition.go
+++ b/src/k8splugin/internal/rb/definition.go
@@ -26,6 +26,7 @@ import (
"path/filepath"
"github.com/onap/multicloud-k8s/src/k8splugin/internal/db"
+ "github.com/onap/multicloud-k8s/src/k8splugin/internal/logutils"
pkgerrors "github.com/pkg/errors"
)
@@ -101,6 +102,40 @@ func (v *DefinitionClient) Create(def Definition) (Definition, error) {
return Definition{}, pkgerrors.Wrap(err, "Creating DB Entry")
}
+ // Create a default profile automatically
+ prc := NewProfileClient()
+ pr, err := prc.Create(Profile{
+ RBName: def.RBName,
+ RBVersion: def.RBVersion,
+ ProfileName: "default",
+ Namespace: "default",
+ ReleaseName: "default",
+ })
+
+ if err != nil {
+ logutils.Error("Create Default Profile", logutils.Fields{
+ "error": err,
+ "rb-name": def.RBName,
+ "rb-version": def.RBVersion,
+ "profile-name": "default",
+ "namespace": "default",
+ "release-name": "default",
+ })
+ return Definition{}, pkgerrors.Wrap(err, "Creating Default Profile")
+ }
+
+ err = prc.Upload(pr.RBName, pr.RBVersion, pr.ProfileName, prc.getEmptyProfile())
+ if err != nil {
+ logutils.Error("Upload Empty Profile", logutils.Fields{
+ "error": err,
+ "rb-name": pr.RBName,
+ "rb-version": pr.RBVersion,
+ "profile-name": pr.ProfileName,
+ "profile-content": prc.getEmptyProfile(),
+ })
+ return Definition{}, pkgerrors.Wrap(err, "Upload Empty Profile")
+ }
+
return def, nil
}
@@ -173,6 +208,19 @@ func (v *DefinitionClient) Delete(name string, version string) error {
return pkgerrors.Wrap(err, "Delete Resource Bundle Definition Content")
}
+ //Delete the default profile as well
+ prc := NewProfileClient()
+ err = prc.Delete(name, version, "default")
+ if err != nil {
+ logutils.Error("Delete Default Profile", logutils.Fields{
+ "error": err,
+ "rb-name": name,
+ "rb-version": version,
+ "profile-name": "default",
+ })
+ return pkgerrors.Wrap(err, "Deleting default profile")
+ }
+
return nil
}
diff --git a/src/k8splugin/internal/rb/profile.go b/src/k8splugin/internal/rb/profile.go
index 49768d4b..6efa23b8 100644
--- a/src/k8splugin/internal/rb/profile.go
+++ b/src/k8splugin/internal/rb/profile.go
@@ -338,3 +338,31 @@ func (v *ProfileClient) Resolve(rbName string, rbVersion string,
return sortedTemplates, nil
}
+
+// Returns an empty profile with the following contents
+// Contains a manifest.yaml pointing to an override_values.yaml
+// The override_values.yaml file is empty.
+func (v *ProfileClient) getEmptyProfile() []byte {
+ return []byte{
+ 0x1F, 0x8B, 0x08, 0x08, 0x25, 0x5D, 0xDC, 0x5C, 0x00, 0x03, 0x70,
+ 0x72, 0x6F, 0x66, 0x69, 0x6C, 0x65, 0x31, 0x2E, 0x74, 0x61, 0x72,
+ 0x00, 0xED, 0xD4, 0xD1, 0x0A, 0x82, 0x30, 0x14, 0xC6, 0xF1, 0x5D,
+ 0xEF, 0x29, 0x46, 0xF7, 0xC6, 0x96, 0x3A, 0xC1, 0x97, 0x89, 0x81,
+ 0x0B, 0xC4, 0xB4, 0x70, 0x26, 0xF8, 0xF6, 0xAD, 0xBC, 0xA8, 0x20,
+ 0xF0, 0xC6, 0x8A, 0xE0, 0xFF, 0xBB, 0x39, 0xB0, 0x33, 0xD8, 0x81,
+ 0xED, 0x5B, 0xEB, 0xBA, 0xFA, 0xE0, 0xC3, 0xB0, 0x9D, 0x5C, 0x7B,
+ 0x14, 0x9F, 0xA1, 0x23, 0x9B, 0x65, 0xB7, 0x6A, 0x8A, 0x5C, 0x3F,
+ 0xD7, 0x99, 0x2D, 0x84, 0x49, 0x33, 0x5B, 0xE8, 0x3C, 0xDF, 0x99,
+ 0x9D, 0xD0, 0x26, 0xD7, 0xA9, 0x15, 0x4A, 0x7F, 0x68, 0x9E, 0x17,
+ 0x97, 0x30, 0xB8, 0x5E, 0x29, 0xE1, 0xAA, 0x7D, 0xD3, 0x34, 0xAE,
+ 0xAD, 0x3B, 0xFF, 0x76, 0xDF, 0x52, 0xFF, 0x4F, 0x25, 0x49, 0x22,
+ 0x47, 0xDF, 0x87, 0xFA, 0xD4, 0x95, 0x6A, 0x34, 0x72, 0x98, 0xCE,
+ 0xBE, 0x94, 0x4A, 0x8D, 0xEE, 0x78, 0xF1, 0xA1, 0x54, 0x9B, 0x53,
+ 0xEC, 0xF6, 0x75, 0xE5, 0xF7, 0xF3, 0xCA, 0xFD, 0x9D, 0x6C, 0xE4,
+ 0xAF, 0xC7, 0xC6, 0x4A, 0xDE, 0x5D, 0xEF, 0xDA, 0x67, 0x2C, 0xE6,
+ 0x5F, 0x9B, 0x47, 0xFE, 0x75, 0x1A, 0xF3, 0x6F, 0xB3, 0xF8, 0x0D,
+ 0x90, 0xFF, 0x2F, 0x20, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x0A, 0xB2, 0xAD,
+ 0x4D, 0xE5, 0x00, 0x28, 0x00, 0x00,
+ }
+}
diff --git a/src/orchestrator/go.sum b/src/orchestrator/go.sum
index dcda41d4..732bc280 100644
--- a/src/orchestrator/go.sum
+++ b/src/orchestrator/go.sum
@@ -201,6 +201,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rubenv/sql-migrate v0.0.0-20190902133344-8926f37f0bc1/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
diff --git a/src/orchestrator/internal/db/README.md b/src/orchestrator/internal/db/README.md
new file mode 100644
index 00000000..cba1b7ea
--- /dev/null
+++ b/src/orchestrator/internal/db/README.md
@@ -0,0 +1,123 @@
+# Database Abstraction Layer
+
+This package contains implementations of the Database interface defined in `store.go`
+Any database can be used as the backend as long as the following interface is implemented;
+
+```go
+type Store interface {
+ // Returns nil if db health is good
+ HealthCheck() error
+
+ // Unmarshal implements any unmarshaling needed for the database
+ Unmarshal(inp []byte, out interface{}) error
+
+ // Creates a new master table with key and links data with tag and
+ // creates a pointer to the newly added data in the master table
+ Create(table string, key Key, tag string, data interface{}) error
+
+ // Reads data for a particular key with specific tag.
+ Read(table string, key Key, tag string) ([]byte, error)
+
+ // Update data for particular key with specific tag
+ Update(table string, key Key, tag string, data interface{}) error
+
+ // Deletes a specific tag data for key.
+ // TODO: If tag is empty, it will delete all tags under key.
+ Delete(table string, key Key, tag string) error
+
+ // Reads all master tables and data from the specified tag in table
+ ReadAll(table string, tag string) (map[string][]byte, error)
+}
+```
+
+Therefore, `mongo.go`, `consul.go` implement the above interface and can be used as the backend as needed based on initial configuration.
+
+## Details on Mongo Implementation
+
+`mongo.go` implements the above interface using the `go.mongodb.org/mongo-driver` package.
+The code converts incoming binary data and creates a new document in the database.
+
+### Create
+
+Arguments:
+```go
+collection string
+key interface
+tag string
+data []byte
+```
+
+Create inserts the provided `data` into the `collection` which returns an auto-generated (by `mongodb`) ID which we then associate with the `key` that is provided as one of the arguments.
+
+We use the `FindOneAndUpdate` mongo API to achieve this with the `upsert` option set to `true`.
+We create the following documents in mongodb for each new definition added to the database:
+
+There is a Master Key document that contains references to other documents which are related to this `key`.
+
+#### Master Key Entry
+```json
+{
+ "_id" : ObjectId("5e0a8554b78a15f71d2dce7e"),
+ "key" : { "rbname" : "edgex", "rbversion" : "v1"},
+ "defmetadata" : ObjectId("5e0a8554be261ecb57f067eb"),
+ "defcontent" : ObjectId("5e0a8377bcfcdd0f01dc7b0d")
+}
+```
+#### Metadata Key Entry
+```json
+{
+ "_id" : ObjectId("5e0a8554be261ecb57f067eb"),
+ "defmetadata" : { "rbname" : "edgex", "rbversion" : "v1", "chartname" : "", "description" : "", "labels" : null }
+}
+```
+#### Definition Content
+```json
+{
+ "_id" : ObjectId("5e0a8377bcfcdd0f01dc7b0d"),
+ "defcontent" : "H4sICCVd3FwAA3Byb2ZpbGUxLnRhcgDt1NEKgjAUxvFd7ylG98aWOsGXiYELxLRwJvj2rbyoIPDGiuD/uzmwM9iB7Vvruvrgw7CdXHsUn6Ejm2W3aopcP9eZLYRJM1voPN+ZndAm16kVSn9onheXMLheKeGqfdM0rq07/3bfUv9PJUkiR9+H+tSVajRymM6+lEqN7njxoVSbU+z2deX388r9nWzkr8fGSt5d79pnLOZfm0f+dRrzb7P4DZD/LyDJAAAAAAAAAAAAAAAA/+0Ksq1N5QAoAAA="
+}
+```
+
+### Unmarshal
+
+Data in mongo is stored as `bson` which is a compressed form of `json`. We need mongo to convert the stored `bson` data to regular `json`
+that we can use in our code when returned.
+
+We just use the `bson.Unmarshal` API to achieve this.
+
+### Read
+
+Arguments:
+```go
+collection string
+key interface
+tag string
+```
+
+Read is straight forward and it uses the `FindOne` API to find our Mongo document based on the provided `key` and then gets the corresponding data for the given `tag`. It will return []byte which can then be passed to the `Unmarshal` function to get the desired GO object.
+
+### Delete
+
+Delete is similar to Read and deletes all the objectIDs being stored for a given `key` in the collection.
+
+## Testing Interfaces
+
+The following interface exists to allow for the development of unit tests which don't require mongo to be running.
+It is mentioned so in the code as well.
+
+```go
+// MongoCollection defines the a subset of MongoDB operations
+// Note: This interface is defined mainly for mock testing
+type MongoCollection interface {
+ InsertOne(ctx context.Context, document interface{},
+ opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
+ FindOne(ctx context.Context, filter interface{},
+ opts ...*options.FindOneOptions) *mongo.SingleResult
+ FindOneAndUpdate(ctx context.Context, filter interface{},
+ update interface{}, opts ...*options.FindOneAndUpdateOptions) *mongo.SingleResult
+ DeleteOne(ctx context.Context, filter interface{},
+ opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
+ Find(ctx context.Context, filter interface{},
+ opts ...*options.FindOptions) (*mongo.Cursor, error)
+}
+``` \ No newline at end of file
diff --git a/src/orchestrator/internal/logutils/logger.go b/src/orchestrator/internal/logutils/logger.go
new file mode 100644
index 00000000..2e8f9969
--- /dev/null
+++ b/src/orchestrator/internal/logutils/logger.go
@@ -0,0 +1,28 @@
+package logutils
+
+import (
+ log "github.com/sirupsen/logrus"
+)
+
+//Fields is type that will be used by the calling function
+type Fields map[string]interface{}
+
+func init() {
+ // Log as JSON instead of the default ASCII formatter.
+ log.SetFormatter(&log.JSONFormatter{})
+}
+
+// Error uses the fields provided and logs
+func Error(msg string, fields Fields) {
+ log.WithFields(log.Fields(fields)).Error(msg)
+}
+
+// Warn uses the fields provided and logs
+func Warn(msg string, fields Fields) {
+ log.WithFields(log.Fields(fields)).Warn(msg)
+}
+
+// Info uses the fields provided and logs
+func Info(msg string, fields Fields) {
+ log.WithFields(log.Fields(fields)).Info(msg)
+}