Create ONAP's ODL Fluorine SR1 distro

Modules installed:
- AAA
- Controller
- Daexim
- Netconf
- MDSAL (pulled trnasitively)
- ODL Parent
- YangTools (pulled transitively)

Brings karaf from 255.9 MB to 215.7 MB.

Note: Oxygen SR3 was 353.2 MB when Fluorine SR1 is 255.9 MB,
so upstream ODL has already shrink their distribution size.

Change-Id: Ic8618156efd4fc842b496bc25557eb322a6dbf26
Issue-ID: CCSDK-1105
Signed-off-by: Alexis de Talhouët <adetalhouet89@gmail.com>
Reviewed-on: https://gerrit.onap.org/r/79075
Tested-by: ONAP Jobbuilder <onap-jobbuilder@jenkins.onap.org>
Reviewed-by: Dan Timoney <dtimoney@att.com>
diff --git a/opendaylight/onap-distribution/fluorine/karaf/pom.xml b/opendaylight/onap-distribution/fluorine/karaf/pom.xml
new file mode 100644
index 0000000..dbada05
--- /dev/null
+++ b/opendaylight/onap-distribution/fluorine/karaf/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>karaf4-parent</artifactId>
+        <version>3.1.4</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.onap.ccsdk.distribution</groupId>
+    <artifactId>distribution-opendaylight-onap-fluorine-karaf</artifactId>
+    <version>0.4.1-SNAPSHOT</version>
+    <name>ccsdk-distribution :: onap :: opendaylight :: fluorine :: karaf</name>
+    <modelVersion>4.0.0</modelVersion>
+
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+            <comments>OpenDaylight distribution build specific for ONAP projects.</comments>
+        </license>
+    </licenses>
+
+    <properties>
+        <!-- <karaf.localFeature></karaf.localFeature> -->
+        <opendaylight.version>0.9.1</opendaylight.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.opendaylight.integration</groupId>
+                <artifactId>all-artifacts</artifactId>
+                <version>${opendaylight.version}</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+
+        <!-- AAA -->
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>features-aaa</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- Controller -->
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>features-extras</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>features-mdsal</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>features-mdsal-benchmark</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>features-mdsal-trace</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- Daexim -->
+        <dependency>
+            <groupId>org.opendaylight.daexim</groupId>
+            <artifactId>daexim-features</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- Netconf -->
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>features-netconf</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>features-netconf-connector</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>features-restconf</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>features-yanglib</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!--ODL Parent-->
+        <dependency>
+            <groupId>org.opendaylight.odlparent</groupId>
+            <artifactId>features-akka</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.odlparent</groupId>
+            <artifactId>features-odlparent</artifactId>
+            <classifier>features</classifier>
+            <type>xml</type>
+            <scope>runtime</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-cli-jar</artifactId>
+            <!-- This scope test here is just a trick, so that we can use aaa-cli-jar in maven-dependency-plugin, but don't have karaf-maven-plugin choke on it -->
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-aaa-cli-jar</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/assembly/bin</outputDirectory>
+                            <includeArtifactIds>aaa-cli-jar</includeArtifactIds>
+                            <overWriteReleases>true</overWriteReleases>
+                            <overWriteSnapshots>true</overWriteSnapshots>
+                            <overWriteIfNewer>true</overWriteIfNewer>
+                            <excludeTransitive>true</excludeTransitive>
+                            <!-- Do not include version in JAR filename, as external scripts call this utility,
+                                 and they understandly do not want to have to adjust for every ODL release;
+                                 see e.g. https://github.com/dfarrell07/puppet-opendaylight/pull/140 -->
+                            <stripVersion>true</stripVersion>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- ODLPARENT-142: Heavy-handed workaround to remove mysql dependencies from system -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-antrun-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>run</goal>
+                        </goals>
+                        <configuration>
+                            <tasks>
+                                <delete includeemptydirs="true">
+                                    <fileset dir="${project.build.directory}/assembly/system/mysql"/>
+                                </delete>
+                            </tasks>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/configure-cluster-ipdetect.sh b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/configure-cluster-ipdetect.sh
new file mode 100755
index 0000000..7b97ef9
--- /dev/null
+++ b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/configure-cluster-ipdetect.sh
@@ -0,0 +1,265 @@
+#!/bin/bash
+#
+# Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+# Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+#
+
+
+function usage()
+{
+    # Print any error messages
+    test "$1" != "" && echo " ERROR: $1"
+
+    # Print standard usage help
+    cat << EOF
+ This script is used to configure cluster parameters on this
+ controller. The user should restart controller to apply changes.
+
+ Usage: $0 <seed_nodes_list>
+  - seed_nodes_list: List of seed nodes, separated by comma or space.
+
+ The script checks that one (any) of the the controller's active IP
+ addresses is present in the seed_nodes_list. When running this script
+ on multiple  seed nodes, keep the seed_node_list same on all nodes.
+
+ Optionally, shards can be configured in a more granular way by
+ modifying the file "custom_shard_configs.txt" in the same folder
+ as this tool.  Please see that file for more details.
+
+This script is currently limited to IPv4 addresses. If you have
+problems running this script, please use 'configure_cluster.sh'.
+
+EOF
+
+    exit 1
+}
+
+
+function start_banner
+{
+cat <<EOF
+################################################
+##             Configure Cluster              ##
+################################################
+EOF
+}
+
+function end_banner
+{
+cat <<EOF
+################################################
+##   NOTE: Manually restart controller to     ##
+##         apply configuration.               ##
+################################################
+EOF
+}
+
+# Utility function for joining strings.
+function join {
+    delim=',\n\t\t\t\t'
+    final=$1; shift
+
+    for str in $* ; do
+        final=${final}${delim}${str}
+    done
+
+    echo ${final}
+}
+
+function create_strings
+{
+    # Using a list of controller IPs, create the strings for data
+    # and rpc seed nodes, as well as the list of members.
+
+    # First create an arrays with one string per controller.
+    # Then merge the array using the join utility defined above.
+    count=1
+    for ip in ${CONTROLLERIPS[@]} ; do
+        ds[$count]=\\\"akka.tcp:\\/\\/opendaylight-cluster-data@${ip}:2550\\\"
+        rpc[$count]=\\\"akka.tcp:\\/\\/odl-cluster-rpc@${ip}:2551\\\"
+        members[$count]=\\\"member-${count}\\\"
+        count=$[count + 1]
+    done
+
+    DATA_SEED_LIST=$(join ${ds[@]})
+    RPC_SEED_LIST=$(join ${rpc[@]})
+    MEMBER_NAME_LIST=$(join ${members[@]})
+}
+
+function module_shards_builder
+{
+
+    module_shards_string="module-shards = [\n\t{\n\t\tname = \"default\"\n\t\tshards = [\n\t\t\t{\n\t\t\t\tname = \"default\"\n\t\t\t\treplicas = []\n\t\t\t}\n\t\t]\n\t}"
+    for name in ${FRIENDLY_MODULE_NAMES[@]} ; do
+        module_shards_string="${module_shards_string},\n\t{\n\t\tname = \"${name}\"\n\t\tshards = [\n\t\t\t{\n\t\t\t\tname=\"${name}\"\n\t\t\t\treplicas = []\n\t\t\t}\n\t\t]\n\t}"
+    done
+
+    echo -e ${module_shards_string}"\n]"
+}
+
+function modules_builder
+{
+
+    modules_string="modules = [\n\t"
+    count=1
+    for name in ${FRIENDLY_MODULE_NAMES[@]} ; do
+        modules_string="${modules_string}\n\t{\n\t\tname = \"${name}\"\n\t\tnamespace = \"${MODULE_NAMESPACES[${count}]}\"\n\t\tshard-strategy = \"module\"\n\t},"
+        count=$[count + 1]
+    done
+
+    # using ::-1 below to remove the extra comma we get from the above loop
+    echo -e ${modules_string::-1}"\n]"
+}
+
+
+function get_index ()
+{
+    # Determine if the local IP address is in the CONTROLLER_LIST
+    # and its index in the list. Return the index.
+
+    local MY_IP=$1
+    shift
+    local IP_ADDRS=("$@")
+    local COUNTER=1
+
+    for IP in ${IP_ADDRS[@]} ;
+    do
+        if [ "$MY_IP" == "$IP" ]; then
+            echo "$COUNTER"
+            return
+        fi
+        COUNTER=$[$COUNTER + 1]
+    done
+    echo "$COUNTER"
+}
+
+function get_local_ip_addresses
+{
+    # Get the local node's IP addresses as list
+    LOCAL_IPS=()
+    for IP in `hostname -I`
+    do
+        LOCAL_IPS+=("$IP")
+    done
+    echo ${LOCAL_IPS[@]}
+}
+
+function get_cli_params
+{
+    # Check if params have been supplied
+    CONTROLLER_LIST=$*
+
+    # Verify we have controller list
+    test "${CONTROLLER_LIST}" == "" && usage "Missing controller list"
+
+    # Create the list of controllers from the CONTROLLER_LIST variable
+    CONTROLLERIPS=( ${CONTROLLER_LIST//,/ } )
+
+    # Get the local node's IP addresses
+    LOCAL_IPS=$(get_local_ip_addresses)
+
+    for CONTROLLER_IP in ${LOCAL_IPS[@]} ;
+    do
+        INDEX=$(get_index $CONTROLLER_IP ${CONTROLLERIPS[@]})
+        if [ ${INDEX} -le ${#CONTROLLERIPS[@]} ] ; then
+            break
+        fi
+    done
+
+    test ${INDEX} -le 0 -o ${INDEX} -gt ${#CONTROLLERIPS[@]} && \
+        usage "Controller's local IP address not in the controller list"
+
+    CONTROLLER_ID="member-${INDEX}"
+}
+
+
+function modify_conf_files
+{
+    BIN_DIR=`dirname $0`
+    CUSTOM_SHARD_CONFIG_FILE=${BIN_DIR}'/custom_shard_config.txt'
+    echo "Configuring unique name in akka.conf"
+    sed -i -e "/roles[ ]*=/ { :loop1 /.*\]/ b done1; N; b loop1; :done1 s/roles.*\]/roles = [\"${CONTROLLER_ID}\"]/}" ${AKKACONF}
+
+    echo "Configuring hostname in akka.conf"
+    sed -i -e "s/hostname[ ]*=.*\"/hostname = \"${CONTROLLER_IP}\"/" ${AKKACONF}
+
+    echo "Configuring data and rpc seed nodes in akka.conf"
+    sed -i -e "/seed-nodes[ ]*=/ { :loop2 /.*\]/ b done2; N; b loop2; :done2 s/seed-nodes.*opendaylight-cluster-data.*\]/seed-nodes = [${DATA_SEED_LIST}]/; s/seed-nodes.*odl-cluster-rpc.*\]/seed-nodes = [${RPC_SEED_LIST}]/}" ${AKKACONF}
+
+    if [ -f ${CUSTOM_SHARD_CONFIG_FILE} ]; then
+        source ${CUSTOM_SHARD_CONFIG_FILE}
+        if [ "${#FRIENDLY_MODULE_NAMES[@]}" -ne "${#MODULE_NAMESPACES[@]}" ]; then
+            echo -e "\ncustom shard config file \"${CUSTOM_SHARD_CONFIG_FILE}\" does not have the same number of FRIENDLY_MODULE_NAMES[] and MODULE_NAMESPACES[]\n"
+            exit 1
+        fi
+        module_shards_builder > ${MODULESHARDSCONF}
+        modules_builder > ${MODULESCONF}
+        cat ${MODULESCONF}
+    fi
+
+    echo "Configuring replication type in module-shards.conf"
+    sed -i -e "/^[^#].*replicas[ ]*=/ { :loop /.*\]/ b done; N; b loop; :done s/replicas.*\]/replicas = [${MEMBER_NAME_LIST}]/}" ${MODULESHARDSCONF}
+}
+
+
+function verify_configuration_files
+{
+    # Constants
+    BIN_DIR=`dirname $0`
+    test ${BIN_DIR} == '.' && BIN_DIR=${PWD}
+    CONTROLLER_DIR=`dirname ${BIN_DIR}`
+    CONF_DIR=${CONTROLLER_DIR}/configuration/initial
+    AKKACONF=${CONF_DIR}/akka.conf
+    MODULESCONF=${CONF_DIR}/modules.conf
+    MODULESHARDSCONF=${CONF_DIR}/module-shards.conf
+
+    # Verify configuration files are present in expected location.
+    if [ ! -f ${AKKACONF} -o ! -f ${MODULESHARDSCONF} ]; then
+        # Check if the configuration files exist in the system
+        # directory, then copy them over.
+        ORIG_CONF_DIR=${CONTROLLER_DIR}/system/org/opendaylight/controller/sal-clustering-config
+        version=$(sed -n -e 's/.*<version>\(.*\)<\/version>/\1/p' ${ORIG_CONF_DIR}/maven-metadata-local.xml)
+        ORIG_CONF_DIR=${ORIG_CONF_DIR}/${version}
+        ORIG_AKKA_CONF=sal-clustering-config-${version}-akkaconf.xml
+        ORIG_MODULES_CONF=sal-clustering-config-${version}-moduleconf.xml
+        ORIG_MODULESHARDS_CONF=sal-clustering-config-${version}-moduleshardconf.xml
+
+        if [ -f ${ORIG_CONF_DIR}/${ORIG_AKKA_CONF} -a \
+             -f ${ORIG_CONF_DIR}/${ORIG_MODULES_CONF} -a \
+             -f ${ORIG_CONF_DIR}/${ORIG_MODULESHARDS_CONF} ]; then
+            cat <<EOF
+ NOTE: Cluster configuration files not found. Copying from
+ ${ORIG_CONF_DIR}
+EOF
+            mkdir -p ${CONF_DIR}
+            cp ${ORIG_CONF_DIR}/${ORIG_AKKA_CONF} ${AKKACONF}
+            cp ${ORIG_CONF_DIR}/${ORIG_MODULES_CONF} ${MODULESCONF}
+            cp ${ORIG_CONF_DIR}/${ORIG_MODULESHARDS_CONF} ${MODULESHARDSCONF}
+
+        else
+            cat << EOF
+ ERROR: Cluster configurations files not found. Please\
+ configure clustering feature.
+EOF
+            exit 1
+        fi
+    fi
+}
+
+function main
+{
+    get_cli_params $*
+    start_banner
+    verify_configuration_files
+    create_strings
+    modify_conf_files
+    end_banner
+}
+
+main $*
+
+# vim: ts=4 sw=4 sts=4 et ft=sh :
diff --git a/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/configure_cluster.sh b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/configure_cluster.sh
new file mode 100755
index 0000000..c3f1a43
--- /dev/null
+++ b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/configure_cluster.sh
@@ -0,0 +1,228 @@
+#!/bin/bash
+#
+# Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+#
+
+
+function usage()
+{
+    # Print any error messages
+    test "$1" != "" && echo " ERROR: $1"
+
+    # Print standard usage help
+    cat << EOF
+ This script is used to configure cluster parameters on this
+ controller. The user should restart controller to apply changes.
+
+ Usage: $0 <index> <seed_nodes_list>
+  - index: Integer within 1..N, where N is the number of seed nodes.
+  - seed_nodes_list: List of seed nodes, separated by comma or space.
+
+ The address at the provided index should belong this controller.
+ When running this script on multiple seed nodes, keep the
+ seed_node_list same, and vary the index from 1 through N.
+
+ Optionally, shards can be configured in a more granular way by
+ modifying the file "custom_shard_configs.txt" in the same folder
+ as this tool.  Please see that file for more details
+
+EOF
+
+    exit 1
+}
+
+
+function start_banner
+{
+cat <<EOF
+################################################
+##             Configure Cluster              ##
+################################################
+EOF
+}
+
+function end_banner
+{
+cat <<EOF
+################################################
+##   NOTE: Manually restart controller to     ##
+##         apply configuration.               ##
+################################################
+EOF
+}
+
+# Utility function for joining strings.
+function join {
+    delim=',\n\t\t\t\t'
+    final=$1; shift
+
+    for str in $* ; do
+        final=${final}${delim}${str}
+    done
+
+    echo ${final}
+}
+
+function create_strings
+{
+    # Using a list of controller IPs, create the strings for data
+    # and rpc seed nodes, as well as the list of members.
+
+    # First create an arrays with one string per controller.
+    # Then merge the array using the join utility defined above.
+    count=1
+    for ip in ${CONTROLLERIPS[@]} ; do
+        ds[$count]=\\\"akka.tcp:\\/\\/opendaylight-cluster-data@${ip}:2550\\\"
+        rpc[$count]=\\\"akka.tcp:\\/\\/odl-cluster-rpc@${ip}:2551\\\"
+        members[$count]=\\\"member-${count}\\\"
+        count=$[count + 1]
+    done
+
+    DATA_SEED_LIST=$(join ${ds[@]})
+    RPC_SEED_LIST=$(join ${rpc[@]})
+    MEMBER_NAME_LIST=$(join ${members[@]})
+}
+
+function module_shards_builder
+{
+
+    module_shards_string="module-shards = [\n\t{\n\t\tname = \"default\"\n\t\tshards = [\n\t\t\t{\n\t\t\t\tname = \"default\"\n\t\t\t\treplicas = []\n\t\t\t}\n\t\t]\n\t}"
+    for name in ${FRIENDLY_MODULE_NAMES[@]} ; do
+        module_shards_string="${module_shards_string},\n\t{\n\t\tname = \"${name}\"\n\t\tshards = [\n\t\t\t{\n\t\t\t\tname=\"${name}\"\n\t\t\t\treplicas = []\n\t\t\t}\n\t\t]\n\t}"
+    done
+
+    echo -e ${module_shards_string}"\n]"
+}
+
+function modules_builder
+{
+
+    modules_string="modules = [\n\t"
+    count=1
+    for name in ${FRIENDLY_MODULE_NAMES[@]} ; do
+        modules_string="${modules_string}\n\t{\n\t\tname = \"${name}\"\n\t\tnamespace = \"${MODULE_NAMESPACES[${count}]}\"\n\t\tshard-strategy = \"module\"\n\t},"
+        count=$[count + 1]
+    done
+
+    if [ ${count} == 1 ]; then
+        # if no modules found in custom_shard_config.txt just close the bracket
+        echo -e ${modules_string}"\n]"
+    else
+        # using ::-1 below to remove the extra comma we get from the above loop
+        echo -e ${modules_string::-1}"\n]"
+    fi
+}
+
+function get_cli_params
+{
+    # Check if params have been supplied
+    test $# -eq 0 && usage
+
+    # First param is index, and rest are controller list
+    INDEX=$1; shift
+    CONTROLLER_LIST=$*
+
+    # Verify we have controller list
+    test "${CONTROLLER_LIST}" == "" && usage "Missing controller list"
+
+    # Create the list of controllers from the CONTROLLER_LIST variable
+    CONTROLLERIPS=( ${CONTROLLER_LIST//,/ } )
+
+    test ${INDEX} -le 0 -o ${INDEX} -gt ${#CONTROLLERIPS[@]} && \
+        usage "Invalid index"
+
+    CONTROLLER_ID="member-${INDEX}"
+    CONTROLLER_IP="${CONTROLLERIPS[((${INDEX} - 1))]}"
+}
+
+
+function modify_conf_files
+{
+    BIN_DIR=`dirname $0`
+    CUSTOM_SHARD_CONFIG_FILE=${BIN_DIR}'/custom_shard_config.txt'
+    echo "Configuring unique name in akka.conf"
+    sed -i -e "/roles[ ]*=/ { :loop1 /.*\]/ b done1; N; b loop1; :done1 s/roles.*\]/roles = [\"${CONTROLLER_ID}\"]/}" ${AKKACONF}
+
+    echo "Configuring hostname in akka.conf"
+    sed -i -e "s/hostname[ ]*=.*\"/hostname = \"${CONTROLLER_IP}\"/" ${AKKACONF}
+
+    echo "Configuring data and rpc seed nodes in akka.conf"
+    sed -i -e "/seed-nodes[ ]*=/ { :loop2 /.*\]/ b done2; N; b loop2; :done2 s/seed-nodes.*opendaylight-cluster-data.*\]/seed-nodes = [${DATA_SEED_LIST}]/; s/seed-nodes.*odl-cluster-rpc.*\]/seed-nodes = [${RPC_SEED_LIST}]/}" ${AKKACONF}
+
+    if [ -f ${CUSTOM_SHARD_CONFIG_FILE} ]; then
+        source ${CUSTOM_SHARD_CONFIG_FILE}
+        if [ "${#FRIENDLY_MODULE_NAMES[@]}" -ne "${#MODULE_NAMESPACES[@]}" ]; then
+            echo -e "\ncustom shard config file \"${CUSTOM_SHARD_CONFIG_FILE}\" does not have the same number of FRIENDLY_MODULE_NAMES[] and MODULE_NAMESPACES[]\n"
+            exit 1
+        fi
+        module_shards_builder > ${MODULESHARDSCONF}
+        modules_builder > ${MODULESCONF}
+        cat ${MODULESCONF}
+    fi
+
+    echo "Configuring replication type in module-shards.conf"
+    sed -i -e "/^[^#].*replicas[ ]*=/ { :loop /.*\]/ b done; N; b loop; :done s/replicas.*\]/replicas = [${MEMBER_NAME_LIST}]/}" ${MODULESHARDSCONF}
+}
+
+
+function verify_configuration_files
+{
+    # Constants
+    BIN_DIR=`dirname $0`
+    test ${BIN_DIR} == '.' && BIN_DIR=${PWD}
+    CONTROLLER_DIR=`dirname ${BIN_DIR}`
+    CONF_DIR=${CONTROLLER_DIR}/configuration/initial
+    AKKACONF=${CONF_DIR}/akka.conf
+    MODULESCONF=${CONF_DIR}/modules.conf
+    MODULESHARDSCONF=${CONF_DIR}/module-shards.conf
+
+    # Verify configuration files are present in expected location.
+    if [ ! -f ${AKKACONF} -o ! -f ${MODULESHARDSCONF} ]; then
+        # Check if the configuration files exist in the system
+        # directory, then copy them over.
+        ORIG_CONF_DIR=${CONTROLLER_DIR}/system/org/opendaylight/controller/sal-clustering-config
+        version=$(sed -n -e 's/.*<version>\(.*\)<\/version>/\1/p' ${ORIG_CONF_DIR}/maven-metadata-local.xml)
+        ORIG_CONF_DIR=${ORIG_CONF_DIR}/${version}
+        ORIG_AKKA_CONF=sal-clustering-config-${version}-akkaconf.xml
+        ORIG_MODULES_CONF=sal-clustering-config-${version}-moduleconf.xml
+        ORIG_MODULESHARDS_CONF=sal-clustering-config-${version}-moduleshardconf.xml
+
+        if [ -f ${ORIG_CONF_DIR}/${ORIG_AKKA_CONF} -a \
+             -f ${ORIG_CONF_DIR}/${ORIG_MODULES_CONF} -a \
+             -f ${ORIG_CONF_DIR}/${ORIG_MODULESHARDS_CONF} ]; then
+            cat <<EOF
+ NOTE: Cluster configuration files not found. Copying from
+ ${ORIG_CONF_DIR}
+EOF
+            mkdir -p ${CONF_DIR}
+            cp ${ORIG_CONF_DIR}/${ORIG_AKKA_CONF} ${AKKACONF}
+            cp ${ORIG_CONF_DIR}/${ORIG_MODULES_CONF} ${MODULESCONF}
+            cp ${ORIG_CONF_DIR}/${ORIG_MODULESHARDS_CONF} ${MODULESHARDSCONF}
+
+        else
+            cat << EOF
+ ERROR: Cluster configurations files not found. Please\
+ configure clustering feature.
+EOF
+            exit 1
+        fi
+    fi
+}
+
+function main
+{
+    get_cli_params $*
+    start_banner
+    verify_configuration_files
+    create_strings
+    modify_conf_files
+    end_banner
+}
+
+main $*
+
+# vim: ts=4 sw=4 sts=4 et ft=sh :
diff --git a/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/custom_shard_config.txt b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/custom_shard_config.txt
new file mode 100644
index 0000000..e536349
--- /dev/null
+++ b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/custom_shard_config.txt
@@ -0,0 +1,17 @@
+# If this file has entries, they will be used to configure the module
+# shards that will be available.  Otherwise, the default shards will
+# be used.  Below, the commented lines are the current default shards
+# (inventory, network-topology, and toaster)
+#
+# These configurations are an array and the indexes need to increment
+# from 1,2,3...
+#
+# There is a FRIENDLY_MODULE_NAME[$index] that will map to the
+# MODULE_NAMESPACES[$index]
+#
+FRIENDLY_MODULE_NAMES[1]='inventory'
+MODULE_NAMESPACES[1]='urn:opendaylight:inventory'
+FRIENDLY_MODULE_NAMES[2]='topology'
+MODULE_NAMESPACES[2]='urn:TBD:params:xml:ns:yang:network-topology'
+FRIENDLY_MODULE_NAMES[3]='toaster'
+MODULE_NAMESPACES[3]='http://netconfcentral.org/ns/toaster'
diff --git a/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/set_persistence.sh b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/set_persistence.sh
new file mode 100755
index 0000000..15c2271
--- /dev/null
+++ b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/bin/set_persistence.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+#
+# Copyright (c) 2015 Brocade Communications Systems, Inc. and others.  All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+#
+
+
+function usage()
+{
+    # Print any error messages
+    test "$1" != "" && echo " ERROR: $1"
+
+    # Print standard usage help
+    cat << EOF
+ This script is used to enable or disable the config datastore
+ persistence. The default state is enabled. The user should
+ restart controller to apply changes. The script can be used
+ before starting controller for the first time.
+
+ Usage: $0 <on/off>
+
+EOF
+
+    exit 1
+}
+
+
+function end_banner
+{
+cat <<EOF
+################################################
+##   NOTE: Manually restart controller to     ##
+##         apply configuration.               ##
+################################################
+EOF
+}
+
+
+function get_cli_params
+{
+    # Check if params have been supplied
+    test $# -eq 0 && usage
+
+    # First param is on/off
+    SWITCH="$1"
+
+    # Verify we only have 1 param
+    test $# -ne 1 && usage "Too many parameters"
+}
+
+
+function modify_conf_file
+{
+    if [ "${SWITCH}" == "off"  ]; then
+        echo "disabling config datastore persistence"
+        sed -i -e "s/^#persistent=true/persistent=false/" ${CLUSTERCONF}
+    elif [ "${SWITCH}" == "on"  ]; then
+        echo "enabling config datastore persistence"
+        sed -i -e "s/^persistent=false/#persistent=true/" ${CLUSTERCONF}
+    else
+        usage "Allowed values are on/off"
+    fi
+}
+
+
+function verify_configuration_file
+{
+    # Constants
+    BIN_DIR=`dirname $0`
+    test ${BIN_DIR} == '.' && BIN_DIR=${PWD}
+    CONTROLLER_DIR=`dirname ${BIN_DIR}`
+    CONF_DIR=${CONTROLLER_DIR}/etc
+    CLUSTERCONF=${CONF_DIR}/org.opendaylight.controller.cluster.datastore.cfg
+
+    # Verify configuration files are present in expected location.
+    if [ ! -f ${CLUSTERCONF} ]; then
+        # Check if the configuration files exist in the system
+        # directory, then copy them over.
+        ORIG_CONF_DIR=${CONTROLLER_DIR}/system/org/opendaylight/controller/sal-clustering-config
+        version=$(sed -n -e 's/.*<version>\(.*\)<\/version>/\1/p' ${ORIG_CONF_DIR}/maven-metadata-local.xml)
+        ORIG_CONF_DIR=${ORIG_CONF_DIR}/${version}
+        ORIG_CLUSTER_CONF=sal-clustering-config-${version}-datastore.cfg
+
+        if [ -f ${ORIG_CONF_DIR}/${ORIG_CLUSTER_CONF} ]; then
+            cat <<EOF
+ NOTE: Cluster configuration file not found. Copying from
+ ${ORIG_CONF_DIR}
+EOF
+            cp ${ORIG_CONF_DIR}/${ORIG_CLUSTER_CONF} ${CLUSTERCONF}
+
+        else
+            usage "Cluster configuration file not found"
+        fi
+    fi
+}
+
+function main
+{
+    get_cli_params "$@"
+    verify_configuration_file
+    modify_conf_file
+    end_banner
+}
+
+main "$@"
+
+# vim: ts=4 sw=4 sts=4 et ft=sh :
+
diff --git a/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/etc/org.ops4j.pax.url.mvn.cfg b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/etc/org.ops4j.pax.url.mvn.cfg
new file mode 100644
index 0000000..cdd5837
--- /dev/null
+++ b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/etc/org.ops4j.pax.url.mvn.cfg
@@ -0,0 +1,96 @@
+################################################################################
+#
+#    Licensed to the Apache Software Foundation (ASF) under one or more
+#    contributor license agreements.  See the NOTICE file distributed with
+#    this work for additional information regarding copyright ownership.
+#    The ASF licenses this file to You 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.
+#
+################################################################################
+
+#
+# If set to true, the following property will not allow any certificate to be used
+# when accessing Maven repositories through SSL
+#
+#org.ops4j.pax.url.mvn.certificateCheck=
+
+#
+# Path to the local Maven settings file.
+# The repositories defined in this file will be automatically added to the list
+# of default repositories if the 'org.ops4j.pax.url.mvn.repositories' property
+# below is not set.
+# The following locations are checked for the existence of the settings.xml file
+#   * 1. looks for the specified url
+#   * 2. if not found looks for ${user.home}/.m2/settings.xml
+#   * 3. if not found looks for ${maven.home}/conf/settings.xml
+#   * 4. if not found looks for ${M2_HOME}/conf/settings.xml
+#
+#org.ops4j.pax.url.mvn.settings=
+
+#
+# Path to the local Maven repository which is used to avoid downloading
+# artifacts when they already exist locally.
+# The value of this property will be extracted from the settings.xml file
+# above, or defaulted to:
+#     System.getProperty( "user.home" ) + "/.m2/repository"
+#
+org.ops4j.pax.url.mvn.localRepository=${karaf.home}/${karaf.default.repository}
+
+#
+# Default this to false. It's just weird to use undocumented repos
+#
+org.ops4j.pax.url.mvn.useFallbackRepositories=false
+
+#
+# Uncomment if you don't wanna use the proxy settings
+# from the Maven conf/settings.xml file
+#
+# org.ops4j.pax.url.mvn.proxySupport=false
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# Those repositories will be checked before iterating through the
+#    below list of repositories and even before the local repository
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snaphots
+#    @noreleases : the repository does not contain any released artifacts
+#
+# The following property value will add the system folder as a repo.
+#
+org.ops4j.pax.url.mvn.defaultRepositories=\
+    file:${karaf.home}/${karaf.default.repository}@id=system.repository@snapshots,\
+    file:${karaf.data}/kar@id=kar.repository@multi@snapshots,\
+    file:${karaf.base}/${karaf.default.repository}@id=child.system.repository@snapshots
+
+# Use the default local repo (e.g.~/.m2/repository) as a "remote" repo
+#org.ops4j.pax.url.mvn.defaultLocalRepoAsRemote=false
+
+#
+# Comma separated list of repositories scanned when resolving an artifact.
+# The default list includes the following repositories:
+#    http://repo1.maven.org/maven2@id=central
+#    http://repository.springsource.com/maven/bundles/release@id=spring.ebr
+#    http://repository.springsource.com/maven/bundles/external@id=spring.ebr.external
+#    http://zodiac.springsource.com/maven/bundles/release@id=gemini
+#    http://repository.apache.org/content/groups/snapshots-group@id=apache@snapshots@noreleases
+#    https://oss.sonatype.org/content/repositories/snapshots@id=sonatype.snapshots.deploy@snapshots@noreleases
+#    https://oss.sonatype.org/content/repositories/ops4j-snapshots@id=ops4j.sonatype.snapshots.deploy@snapshots@noreleases
+# To add repositories to the default ones, prepend '+' to the list of repositories
+# to add.
+# A repository url can be appended with zero or more of the following flags:
+#    @snapshots  : the repository contains snapshots
+#    @noreleases : the repository does not contain any released artifacts
+#    @id=repository.id : the id for the repository, just like in the settings.xml this is optional but recommended
+#
+org.ops4j.pax.url.mvn.repositories=
+
+### ^^^ No remote repositories. This is the only ODL change compared to Karaf defaults.
\ No newline at end of file
diff --git a/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/etc/shell.init.script b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/etc/shell.init.script
new file mode 100644
index 0000000..ccc9d2a
--- /dev/null
+++ b/opendaylight/onap-distribution/fluorine/karaf/src/main/assembly/etc/shell.init.script
@@ -0,0 +1,66 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+// This script is run each time a shell is created.
+// You can define here closures or variables that will be available
+// in each session.
+//
+ld = { log:display $args } ;
+lde = { log:exception-display $args } ;
+la = { bundle:list -t 0 $args } ;
+ls = { service:list $args } ;
+cl = { config:list "(service.pid=$args)" } ;
+halt = { system:shutdown -h -f $args } ;
+help = { *:help $args | more } ;
+man = { help $args } ;
+log:list = { log:get ALL } ;
+service:get = { $.context getService ($.context getServiceReference $args) };
+
+env = { shell:set $args }
+edit = { shell:nano $args }
+more = { shell:less -F $args }
+
+// \#prompt = { "${USER}@${APPLICATION}(${SUBSHELL})> "?};
+
+__load_class = {
+  (($.reader class) classLoader) loadClass $1
+}
+
+// make sure that we catch exceptions
+// as they do occur if the session is headless / non-interactive
+jlineReader = $.reader
+if { %(jlineReader != null) } {
+
+  # On 256 colors terminal, add a right prompt
+  max_colors = ($.jline.terminal getNumericCapability max_colors)
+  if { %(max_colors >= 256) } {
+    __rprompt_formatter = (((__load_class java.text.SimpleDateFormat) getConstructor (__load_class java.lang.String)) newInstance \'$'\u001B\[90m'\'HH:mm:ss)
+    __date_class = (__load_class java.util.Date)
+// Do not use right prompt by default
+//    \#rprompt = { $__rprompt_formatter format ($__date_class newInstance) }
+  }
+
+  setopt group
+  setopt auto-fresh-line
+  unsetopt insert-tab
+  keymap "^[OA" up-line-or-search
+  keymap "^[[A" up-line-or-search
+  keymap "^[OB" down-line-or-search
+  keymap "^[[B" down-line-or-search
+
+}
diff --git a/opendaylight/onap-distribution/fluorine/pom.xml b/opendaylight/onap-distribution/fluorine/pom.xml
new file mode 100644
index 0000000..3c592c3
--- /dev/null
+++ b/opendaylight/onap-distribution/fluorine/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onap.ccsdk.distribution</groupId>
+        <artifactId>distribution-opendaylight</artifactId>
+        <version>0.4.1-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>distribution-opendaylight-onap-fluorine-parent</artifactId>
+    <version>0.4.1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>ccsdk-distribution :: onap :: opendaylight :: fluorine :: parent</name>
+    <description>Creates ONAP's OpenDaylight Fluorine container</description>
+
+    <modules>
+        <module>karaf</module>
+    </modules>
+
+    <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-install-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/opendaylight/onap-distribution/pom.xml b/opendaylight/onap-distribution/pom.xml
new file mode 100644
index 0000000..34b8cce
--- /dev/null
+++ b/opendaylight/onap-distribution/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onap.ccsdk.distribution</groupId>
+        <artifactId>distribution-opendaylight</artifactId>
+        <version>0.4.1-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>distribution-opendaylight-onap</artifactId>
+    <version>0.4.1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>ccsdk-distribution :: onap :: opendaylight :: parent</name>
+    <description>Creates ONAP's OpenDaylight distribution</description>
+
+    <modules>
+        <module>fluorine</module>
+    </modules>
+
+    <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build -->
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-install-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>