Upgrade to Atomix 3.0-rc5
* Upgrade Raft primitives to Atomix 3.0
* Replace cluster store and messaging implementations with Atomix cluster management/messaging
* Add test scripts for installing/starting Atomix cluster
* Replace core primitives with Atomix primitives.
Change-Id: I7623653c81292a34f21b01f5f38ca11b5ef15cad
diff --git a/tools/build/bazel/generate_workspace.bzl b/tools/build/bazel/generate_workspace.bzl
index 19232ff..744598a 100644
--- a/tools/build/bazel/generate_workspace.bzl
+++ b/tools/build/bazel/generate_workspace.bzl
@@ -1,4 +1,4 @@
-# ***** This file was auto-generated at Mon, 23 Jul 2018 20:11:05 GMT. Do not edit this file manually. *****
+# ***** This file was auto-generated at Thu, 26 Jul 2018 18:15:57 GMT. Do not edit this file manually. *****
# ***** Use onos-lib-gen *****
load("//tools/build/bazel:variables.bzl", "ONOS_GROUP_ID", "ONOS_VERSION")
@@ -118,6 +118,18 @@
"@javax_ws_rs_api//jar",
"//utils/rest:onlab-rest",
]
+ATOMIX = [
+ "@atomix//jar",
+ "@atomix_cluster//jar",
+ "@atomix_gossip//jar",
+ "@atomix_primary_backup//jar",
+ "@atomix_primitive//jar",
+ "@atomix_raft//jar",
+ "@atomix_storage//jar",
+ "@atomix_utils//jar",
+ "@typesafe_config//jar",
+ "@fast_classpath_scanner//jar",
+]
def generated_maven_jars():
native.maven_jar(
@@ -140,8 +152,50 @@
native.maven_jar(
name = "atomix",
- artifact = "io.atomix:atomix:2.0.23",
- sha1 = "6b41cebf257e0094c2276b6fa589b2c73aff5f99",
+ artifact = "io.atomix:atomix:3.0.0-rc5",
+ sha1 = "0607a760f048f66645a35bcd8d5cfd96634af622",
+ )
+
+ native.maven_jar(
+ name = "atomix_cluster",
+ artifact = "io.atomix:atomix-cluster:3.0.0-rc5",
+ sha1 = "586badbad8e1b7727f260bd53f3c9487eda64191",
+ )
+
+ native.maven_jar(
+ name = "atomix_gossip",
+ artifact = "io.atomix:atomix-gossip:3.0.0-rc5",
+ sha1 = "e168926801b01f6d543ef4232c02b1c798c81edf",
+ )
+
+ native.maven_jar(
+ name = "atomix_primary_backup",
+ artifact = "io.atomix:atomix-primary-backup:3.0.0-rc5",
+ sha1 = "d339992903d53d7608957471ee9c97a45945d730",
+ )
+
+ native.maven_jar(
+ name = "atomix_primitive",
+ artifact = "io.atomix:atomix-primitive:3.0.0-rc5",
+ sha1 = "6606d4619a74b054e58d4478f43616a608803216",
+ )
+
+ native.maven_jar(
+ name = "atomix_raft",
+ artifact = "io.atomix:atomix-raft:3.0.0-rc5",
+ sha1 = "07c64d7be64ba81a4b53a55bf29d415db4998132",
+ )
+
+ native.maven_jar(
+ name = "atomix_storage",
+ artifact = "io.atomix:atomix-storage:3.0.0-rc5",
+ sha1 = "2e093d7d42de9cdf274675358a17c76e1fd36a5e",
+ )
+
+ native.maven_jar(
+ name = "atomix_utils",
+ artifact = "io.atomix:atomix-utils:3.0.0-rc5",
+ sha1 = "3435cf4ad6abfa85db210366bcaf0c6ac0ae7ec2",
)
native.maven_jar(
@@ -187,6 +241,12 @@
)
native.maven_jar(
+ name = "fast_classpath_scanner",
+ artifact = "io.github.lukehutch:fast-classpath-scanner:2.21",
+ sha1 = "0cc8e22b412521480c89ac79194e82bd4471dd75",
+ )
+
+ native.maven_jar(
name = "jdom",
artifact = "jdom:jdom:1.0",
sha1 = "a2ac1cd690ab4c80defe7f9bce14d35934c35cec",
@@ -800,8 +860,8 @@
native.maven_jar(
name = "typesafe_config",
- artifact = "com.typesafe:config:1.2.1",
- sha1 = "f771f71fdae3df231bcd54d5ca2d57f0bf93f467",
+ artifact = "com.typesafe:config:1.3.2",
+ sha1 = "d6ac0ce079f114adce620f2360c92a70b2cb36dc",
)
native.maven_jar(
@@ -1185,6 +1245,48 @@
)
native.java_library(
+ name = "atomix_cluster",
+ visibility = ["//visibility:public"],
+ exports = ["@atomix_cluster//jar"],
+ )
+
+ native.java_library(
+ name = "atomix_gossip",
+ visibility = ["//visibility:public"],
+ exports = ["@atomix_gossip//jar"],
+ )
+
+ native.java_library(
+ name = "atomix_primary_backup",
+ visibility = ["//visibility:public"],
+ exports = ["@atomix_primary_backup//jar"],
+ )
+
+ native.java_library(
+ name = "atomix_primitive",
+ visibility = ["//visibility:public"],
+ exports = ["@atomix_primitive//jar"],
+ )
+
+ native.java_library(
+ name = "atomix_raft",
+ visibility = ["//visibility:public"],
+ exports = ["@atomix_raft//jar"],
+ )
+
+ native.java_library(
+ name = "atomix_storage",
+ visibility = ["//visibility:public"],
+ exports = ["@atomix_storage//jar"],
+ )
+
+ native.java_library(
+ name = "atomix_utils",
+ visibility = ["//visibility:public"],
+ exports = ["@atomix_utils//jar"],
+ )
+
+ native.java_library(
name = "commons_codec",
visibility = ["//visibility:public"],
exports = ["@commons_codec//jar"],
@@ -1227,6 +1329,12 @@
)
native.java_library(
+ name = "fast_classpath_scanner",
+ visibility = ["//visibility:public"],
+ exports = ["@fast_classpath_scanner//jar"],
+ )
+
+ native.java_library(
name = "jdom",
visibility = ["//visibility:public"],
exports = ["@jdom//jar"],
@@ -2190,7 +2298,14 @@
artifact_map["@aopalliance_repackaged//jar"] = "mvn:org.glassfish.hk2.external:aopalliance-repackaged:jar:2.5.0-b42"
artifact_map["@amqp_client//jar"] = "mvn:com.rabbitmq:amqp-client:jar:3.6.1"
artifact_map["@asm//jar"] = "mvn:org.ow2.asm:asm:jar:5.0.4"
-artifact_map["@atomix//jar"] = "mvn:io.atomix:atomix:jar:2.0.23"
+artifact_map["@atomix//jar"] = "mvn:io.atomix:atomix:jar:3.0.0-rc5"
+artifact_map["@atomix_cluster//jar"] = "mvn:io.atomix:atomix-cluster:jar:3.0.0-rc5"
+artifact_map["@atomix_gossip//jar"] = "mvn:io.atomix:atomix-gossip:jar:3.0.0-rc5"
+artifact_map["@atomix_primary_backup//jar"] = "mvn:io.atomix:atomix-primary-backup:jar:3.0.0-rc5"
+artifact_map["@atomix_primitive//jar"] = "mvn:io.atomix:atomix-primitive:jar:3.0.0-rc5"
+artifact_map["@atomix_raft//jar"] = "mvn:io.atomix:atomix-raft:jar:3.0.0-rc5"
+artifact_map["@atomix_storage//jar"] = "mvn:io.atomix:atomix-storage:jar:3.0.0-rc5"
+artifact_map["@atomix_utils//jar"] = "mvn:io.atomix:atomix-utils:jar:3.0.0-rc5"
artifact_map["@commons_codec//jar"] = "mvn:commons-codec:commons-codec:jar:1.10"
artifact_map["@commons_cli//jar"] = "mvn:commons-cli:commons-cli:jar:1.3"
artifact_map["@commons_collections//jar"] = "mvn:commons-collections:commons-collections:jar:3.2.2"
@@ -2198,6 +2313,7 @@
artifact_map["@commons_io//jar"] = "mvn:commons-io:commons-io:jar:2.6"
artifact_map["@commons_jxpath//jar"] = "mvn:commons-jxpath:commons-jxpath:jar:1.3"
artifact_map["@commons_beanutils//jar"] = "mvn:commons-beanutils:commons-beanutils:jar:1.9.3"
+artifact_map["@fast_classpath_scanner//jar"] = "mvn:io.github.lukehutch:fast-classpath-scanner:jar:2.21"
artifact_map["@jdom//jar"] = "mvn:jdom:jdom:jar:NON-OSGI:1.0"
artifact_map["@commons_lang//jar"] = "mvn:commons-lang:commons-lang:jar:2.6"
artifact_map["@commons_lang3//jar"] = "mvn:org.apache.commons:commons-lang3:jar:3.7"
@@ -2300,7 +2416,7 @@
artifact_map["@slf4j_api//jar"] = "mvn:org.slf4j:slf4j-api:jar:1.7.25"
artifact_map["@slf4j_jdk14//jar"] = "mvn:org.slf4j:slf4j-jdk14:jar:1.7.25"
artifact_map["@slf4j_nop//jar"] = "mvn:org.slf4j:slf4j-nop:jar:1.7.25"
-artifact_map["@typesafe_config//jar"] = "mvn:com.typesafe:config:jar:1.2.1"
+artifact_map["@typesafe_config//jar"] = "mvn:com.typesafe:config:jar:1.3.2"
artifact_map["@validation_api//jar"] = "mvn:javax.validation:validation-api:jar:1.1.0.Final"
artifact_map["@checkstyle//jar"] = "mvn:com.puppycrawl.tools:checkstyle:jar:NON-OSGI:8.10"
artifact_map["@apache_karaf//jar"] = "http://repo1.maven.org/maven2/org/onosproject/apache-karaf-offline/3.0.8/apache-karaf-offline-3.0.8.tar.gz"
diff --git a/tools/build/envDefaults b/tools/build/envDefaults
index 190f7de..d76bb52 100644
--- a/tools/build/envDefaults
+++ b/tools/build/envDefaults
@@ -53,6 +53,7 @@
export ONOS_ADMIN_TAR=$ONOS_STAGE_ROOT/$ONOS_ADMIN_BITS.tar.gz
export ONOS_INSTALL_DIR="/opt/onos" # Installation directory on remote
+export ATOMIX_INSTALL_DIR="/opt/atomix" # Installation directory for Atomix
export OCI="${OCI:-localhost}" # ONOS Controller Instance
export ONOS_USER="${ONOS_USER:-sdn}" # ONOS user on remote system
export ONOS_GROUP="${ONOS_GROUP:-sdn}" # ONOS group on remote system
diff --git a/tools/package/features/BUCK b/tools/package/features/BUCK
index 479d488..8bbf94a 100644
--- a/tools/package/features/BUCK
+++ b/tools/package/features/BUCK
@@ -4,10 +4,18 @@
required_features = [],
included_bundles = [
'//lib:atomix',
+ '//lib:atomix-cluster',
+ '//lib:atomix-gossip',
+ '//lib:atomix-primary-backup',
+ '//lib:atomix-primitive',
+ '//lib:atomix-raft',
+ '//lib:atomix-storage',
+ '//lib:atomix-utils',
'//lib:commons-lang',
'//lib:commons-lang3',
'//lib:commons-text',
'//lib:commons-configuration',
+ '//lib:fast-classpath-scanner',
'//lib:guava',
'//lib:netty',
'//lib:netty-common',
diff --git a/tools/package/features/features.xml b/tools/package/features/features.xml
index a89555d..1c49602 100644
--- a/tools/package/features/features.xml
+++ b/tools/package/features/features.xml
@@ -21,7 +21,7 @@
<feature name="onos-thirdparty-base" version="@FEATURE-VERSION"
description="ONOS 3rd party dependencies">
<bundle>mvn:commons-lang/commons-lang/2.6</bundle>
- <bundle>mvn:org.apache.commons/commons-lang3/3.5</bundle>
+ <bundle>mvn:org.apache.commons/commons-lang3/3.7</bundle>
<bundle>mvn:commons-configuration/commons-configuration/1.10</bundle>
<bundle>mvn:com.google.guava/guava/22.0</bundle>
<bundle>mvn:io.netty/netty/3.10.5.Final</bundle>
@@ -56,10 +56,20 @@
<bundle>mvn:commons-configuration/commons-configuration/1.10</bundle>
<bundle>mvn:commons-collections/commons-collections/3.2.2</bundle>
- <bundle>mvn:com.typesafe/config/1.2.1</bundle>
+ <bundle>mvn:com.typesafe/config/1.3.2</bundle>
<bundle>mvn:com.googlecode.concurrent-trees/concurrent-trees/2.6.0</bundle>
<bundle>mvn:commons-io/commons-io/2.4</bundle>
- <bundle>mvn:io.atomix/atomix/2.0.23</bundle>
+ <bundle>mvn:io.atomix/atomix/3.0.0-rc5</bundle>
+ <bundle>mvn:io.atomix/atomix-cluster/3.0.0-rc5</bundle>
+ <bundle>mvn:io.atomix/atomix-gossip/3.0.0-rc5</bundle>
+ <bundle>mvn:io.atomix/atomix-primary-backup/3.0.0-rc5</bundle>
+ <bundle>mvn:io.atomix/atomix-primitive/3.0.0-rc5</bundle>
+ <bundle>mvn:io.atomix/atomix-raft/3.0.0-rc5</bundle>
+ <bundle>mvn:io.atomix/atomix-storage/3.0.0-rc5</bundle>
+ <bundle>mvn:io.atomix/atomix-utils/3.0.0-rc5</bundle>
+
+ <bundle>mvn:com.typesafe/config/1.3.2</bundle>
+ <bundle>mvn:io.github.lukehutch/fast-classpath-scanner/2.21</bundle>
<bundle>mvn:org.glassfish.jersey.core/jersey-client/2.26</bundle>
diff --git a/tools/package/onos-run-karaf b/tools/package/onos-run-karaf
index 1b53640..d35468a 100755
--- a/tools/package/onos-run-karaf
+++ b/tools/package/onos-run-karaf
@@ -55,8 +55,7 @@
cat > $ONOS_DIR/config/cluster.json <<-EOF
{
"name": "default",
- "nodes": [ {"id": "$IP", "ip": "$IP", "port": 9876 } ],
- "partitions": [ { "id": 1, "members": [ "$IP" ] } ]
+ "cluster": [ {"id": "$IP", "ip": "$IP", "port": 9876 } ]
}
EOF
diff --git a/tools/test/bin/atomix-config b/tools/test/bin/atomix-config
new file mode 100755
index 0000000..0cc2954
--- /dev/null
+++ b/tools/test/bin/atomix-config
@@ -0,0 +1,41 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Remotely configures & starts Atomix for the first time.
+# -----------------------------------------------------------------------------
+
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [node]
+
+options:
+- [node] : The node to configure
+
+summary:
+ Remotely configures and starts Atomix for the first time.
+
+ The procedure for configuring a node includes determining base features,
+ applications to load at startup, and clustering and logical network view
+ configurations, among others.
+
+ If [node] isn't specified, the default target becomes \$OCI.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
+
+[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
+. $ONOS_ROOT/tools/build/envDefaults
+
+node=${1:-$OCI}
+remote=$ONOS_USER@$node
+
+# Generate a default cluster.json from the ON* environment variables
+CDEF_FILE=/tmp/${remote}.atomix.json
+atomix-gen-config $node $CDEF_FILE
+scp -q $CDEF_FILE $remote:$ATOMIX_INSTALL_DIR/atomix.json
+
+ssh -tt $ONOS_USER@$node "
+ echo \"cd $ATOMIX_INSTALL_DIR && java -Xms4G -Xmx4G -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -cp .:$ATOMIX_INSTALL_DIR/atomix.json:$ATOMIX_INSTALL_DIR/atomix-agent.jar -Datomix.logging.level=DEBUG io.atomix.agent.AtomixAgent\" > $ATOMIX_INSTALL_DIR/atomix && sudo chmod u+x $ATOMIX_INSTALL_DIR/atomix
+"
diff --git a/tools/test/bin/atomix-gen-config b/tools/test/bin/atomix-gen-config
new file mode 100755
index 0000000..5e42dfc
--- /dev/null
+++ b/tools/test/bin/atomix-gen-config
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+"""
+usage: atomix-gen-config [-h] [-s PARTITION_SIZE] [-n NUM_PARTITIONS]
+ [node_ip] [filename] [node_ip [node_ip ...]]
+
+Generate the partitions json file given a list of IPs or from the $OCC*
+environment variables.
+
+positional arguments:
+ filename File to write output to. If none is provided, output
+ is written to stdout.
+ node_ip IP Address(es) of the node(s) in the cluster. If no
+ IPs are given, will use the $OCC* environment
+ variables. NOTE: these arguemnts are only processed
+ after the filename argument.
+
+optional arguments:
+ -h, --help show this help message and exit
+ -s PARTITION_SIZE, --partition-size PARTITION_SIZE
+ Number of nodes per partition. Note that partition
+ sizes smaller than 3 are not fault tolerant. Defaults
+ to 3.
+ -n NUM_PARTITIONS, --num-partitions NUM_PARTITIONS
+ Number of partitions. Defaults to the number of nodes
+ in the cluster.
+"""
+
+from os import environ
+import argparse
+import re
+import json
+
+convert = lambda text: int(text) if text.isdigit() else text.lower()
+alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
+
+def get_OCC_vars():
+ vars = []
+ for var in environ:
+ if re.match(r"OCC[0-9]+", var):
+ vars.append(var)
+ return sorted(vars, key=alphanum_key)
+
+def get_local_node(node, ips=None):
+ if not ips:
+ ips = [ environ[v] for v in get_OCC_vars() ]
+ return 'atomix-{}'.format(ips.index(node) + 1)
+
+def get_nodes(ips=None, default_port=5679):
+ node = lambda id, ip, port: {'id': id, 'address': '{}:{}'.format(ip, port)}
+ result = []
+ if not ips:
+ ips = [ environ[v] for v in get_OCC_vars() ]
+ i = 1
+ for ip_string in ips:
+ address_tuple = ip_string.split(":")
+ if len(address_tuple) == 3:
+ id=address_tuple[0]
+ ip=address_tuple[1]
+ port=int(address_tuple[2])
+ else:
+ id='atomix-{}'.format(i)
+ i += 1
+ ip=ip_string
+ port=default_port
+ result.append(node(id, ip, port))
+ return result
+
+def get_local_address(node, ips=None, default_port=5679):
+ result = []
+ if not ips:
+ ips = [ environ[v] for v in get_OCC_vars() ]
+ i = 1
+ for ip_string in ips:
+ address_tuple = ip_string.split(":")
+ if len(address_tuple) == 3:
+ id=address_tuple[0]
+ ip=address_tuple[1]
+ port=int(address_tuple[2])
+ if node == id or node == ip:
+ return '{}:{}'.format(ip, port)
+ return '{}:{}'.format(node, default_port)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(
+ description="Generate the partitions json file given a list of IPs or from the $OCC* environment variables.")
+ parser.add_argument(
+ '-s', '--partition-size', type=int, default=3,
+ help="Number of nodes per partition. Note that partition sizes smaller than 3 are not fault tolerant. Defaults to 3." )
+ parser.add_argument(
+ '-n', '--num-partitions', type=int,
+ help="Number of partitions. Defaults to the number of nodes in the cluster." )
+ # TODO: make filename and nodes independent. This will break backwards compatibility with existing usage.
+ parser.add_argument(
+ 'node', metavar='node_ip', type=str, help='IP address of the node for which to generate the configuration')
+ parser.add_argument(
+ 'filename', metavar='filename', type=str, nargs='?',
+ help='File to write output to. If none is provided, output is written to stdout.')
+ parser.add_argument(
+ 'nodes', metavar='node_ip', type=str, nargs='*',
+ help='IP Address(es) of the node(s) in the cluster. If no IPs are given, ' +
+ 'will use the $OCC* environment variables. NOTE: these arguemnts' +
+ ' are only processed after the filename argument.')
+
+ args = parser.parse_args()
+ filename = args.filename
+ partition_size = args.partition_size
+ local_member_id = get_local_node(args.node)
+ local_member_address = get_local_address(args.node, args.nodes)
+ nodes = get_nodes(args.nodes)
+ num_partitions = args.num_partitions
+ if not num_partitions:
+ num_partitions = len(nodes)
+
+ data = {
+ 'cluster': {
+ 'clusterId': 'onos',
+ 'node': {
+ 'id': local_member_id,
+ 'address': local_member_address
+ },
+ 'discovery': {
+ 'type': 'bootstrap',
+ 'nodes': nodes
+ }
+ },
+ 'managementGroup': {
+ 'type': 'raft',
+ 'partitions': 1,
+ 'partitionSize': len(nodes),
+ 'members': [node['id'] for node in nodes]
+ },
+ 'partitionGroups': {
+ 'raft': {
+ 'type': 'raft',
+ 'partitions': num_partitions,
+ 'partitionSize': partition_size,
+ 'members': [node['id'] for node in nodes]
+ }
+ }
+ }
+ output = json.dumps(data, indent=4)
+
+ if filename:
+ with open(filename, 'w') as f:
+ f.write(output)
+ else:
+ print output
diff --git a/tools/test/bin/atomix-install b/tools/test/bin/atomix-install
new file mode 100755
index 0000000..2a361b1
--- /dev/null
+++ b/tools/test/bin/atomix-install
@@ -0,0 +1,60 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Remotely pushes bits to a remote node and installs ONOS on it.
+# -----------------------------------------------------------------------------
+
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [-fn] [-m] <settings> [node]
+
+options:
+- [node] : remote node to install ONOS on.
+
+summary:
+ Downloads Atomix bits to a remote node and installs Atomix on it.
+
+ The -u should be used on upstart-based systems.
+
+ If [node] is not specified the default target is \$OCI.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
+
+[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
+. $ONOS_ROOT/tools/build/envDefaults
+
+onos-check-bits
+
+while getopts fnvm: o; do
+ case "$o" in
+ f) uninstall=true;;
+ n) nostart=true;;
+ esac
+done
+let OPC=$OPTIND-1
+shift $OPC
+
+# If the -f was given, attempt uninstall first.
+[ -n "$uninstall" ] && atomix-uninstall ${1:-$OCI}
+
+node=${1:-$OCI}
+remote=$ONOS_USER@$node
+
+ssh -tt $remote "
+ [ -f $ATOMIX_INSTALL_DIR/atomix-agent.jar ] && echo \"Atomix is already installed\" && exit 1
+
+ sudo mkdir -p $ATOMIX_INSTALL_DIR && sudo chown ${ONOS_USER}:${ONOS_GROUP} $ATOMIX_INSTALL_DIR
+ sudo wget -O $ATOMIX_INSTALL_DIR/atomix-agent.jar https://oss.sonatype.org/content/repositories/releases/io/atomix/atomix-agent/3.0.0-rc4/atomix-agent-3.0.0-rc4-shaded.jar
+"
+
+# Configure the ONOS installation
+atomix-config $node
+
+# Upload the shared cluster key if present
+[ -f "$ONOS_CLUSTER_KEY_FILE" ] && onos-push-cluster-key $1
+
+# Unless -n option was given, attempt to ignite the ONOS service.
+[ -z "$nostart" ] && atomix-service $node start || true
\ No newline at end of file
diff --git a/tools/test/bin/atomix-kill b/tools/test/bin/atomix-kill
new file mode 100755
index 0000000..8238fd3
--- /dev/null
+++ b/tools/test/bin/atomix-kill
@@ -0,0 +1,18 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Remotely kills the Atomix service on the specified node.
+# -----------------------------------------------------------------------------
+
+[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
+. $ONOS_ROOT/tools/build/envDefaults
+
+ssh $ONOS_USER@${1:-$OCI} "
+ pid=\$(ps -ef | grep atomix-agent.jar | grep -v grep | cut -c10-15 | tr -d ' ')
+ if [ -n \"\$pid\" ]; then
+ echo \"Killing Atomix process \$pid on \$(hostname)...\"
+ kill -9 \$pid
+ else
+ echo \"Atomix process is not running...\"
+ exit 1
+ fi
+"
diff --git a/tools/test/bin/atomix-service b/tools/test/bin/atomix-service
new file mode 100755
index 0000000..0c70b0f
--- /dev/null
+++ b/tools/test/bin/atomix-service
@@ -0,0 +1,69 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Remotely administers the ONOS service on the specified node.
+# -----------------------------------------------------------------------------
+
+[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
+. $ONOS_ROOT/tools/build/envDefaults
+. $ONOS_ROOT/tools/test/bin/find-node.sh
+
+function print_usage {
+ command_name=`basename $0`
+ echo "Remotely administer the ONOS service on a single node or the current ONOS cell."
+ echo
+ echo "Usage: $command_name <TARGET> [COMMAND]"
+ echo " $command_name [-h | --help]"
+ echo "Options:"
+ echo " TARGET The target of the command"
+ echo " COMMAND The command to execute. Default value is 'status'"
+ echo " [-h | --help] Print this help"
+ echo ""
+ echo "TARGET: <hostname | --cell>"
+ echo " hostname Execute on the specified host name"
+ echo " --cell Execute on the current ONOS cell"
+ echo ""
+ echo "COMMAND: [start|stop|restart|status]"
+ echo ""
+}
+
+# Print usage
+if [ "${1}" = "-h" -o "${1}" = "--help" ]; then
+ print_usage
+ exit 0
+fi
+
+# Select the target
+if [ "${1}" = "--cell" ]; then
+ nodes=$(env | sort | egrep "^OCC[0-9]+" | cut -d= -f2)
+else
+ nodes=$(find_node ${1:-$OCI})
+fi
+
+case $2 in
+ start)
+ # Execute the remote commands
+ for node in $nodes; do
+ ssh $ONOS_USER@${node} "nohup $ATOMIX_INSTALL_DIR/atomix >> $ATOMIX_INSTALL_DIR/log 2>&1 &"
+ done
+ ;;
+ stop)
+ # Execute the remote commands
+ for node in $nodes; do
+ ssh -tt $ONOS_USER@${node} "
+ pid=\$(ps -ef | grep atomix-agent.jar | grep -v grep | cut -c10-15 | tr -d ' ')
+ if [ -n \"\$pid\" ]; then
+ echo \"Killing Atomix process \$pid on \$(hostname)...\"
+ kill -9 \$pid
+ else
+ echo \"Atomix process is not running...\"
+ exit 1
+ fi
+ "
+ done
+ ;;
+ *)
+ echo "error: $2 is not a valid command"
+ echo ""
+ print_usage
+ ;;
+esac
diff --git a/tools/test/bin/atomix-uninstall b/tools/test/bin/atomix-uninstall
new file mode 100755
index 0000000..c1ca86d
--- /dev/null
+++ b/tools/test/bin/atomix-uninstall
@@ -0,0 +1,42 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Remotely stops & uninstalls ONOS on the specified node.
+# -----------------------------------------------------------------------------
+
+function _usage () {
+cat << _EOF_
+usage:
+ $(basename $0) [node]
+
+options:
+- [node] : The remote instance to uninstall Atomix from.
+
+summary:
+ Remotely stops and uninstalls Atomix on the specified node.
+
+ If [node] isn't specified, \$OCI becomes the target.
+
+_EOF_
+}
+
+[ "$1" = "-h" ] && _usage && exit 0
+
+[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
+. $ONOS_ROOT/tools/build/envDefaults
+
+remote=$ONOS_USER@${1:-$OCI}
+
+ssh -tt $remote "
+ pid=\$(ps -ef | grep atomix-agent.jar | grep -v grep | cut -c10-15 | tr -d ' ')
+ if [ -n \"\$pid\" ]; then
+ echo \"Killing Atomix process \$pid on \$(hostname)...\"
+ kill -9 \$pid
+ else
+ echo \"Atomix process is not running...\"
+ fi
+
+ # Remove Atomix directory
+ [ -d $ATOMIX_INSTALL_DIR ] && sudo rm -fr $ATOMIX_INSTALL_DIR
+
+ exit \${status:-0};
+"
diff --git a/tools/test/bin/onos-config b/tools/test/bin/onos-config
index 97519b8..772df3a 100755
--- a/tools/test/bin/onos-config
+++ b/tools/test/bin/onos-config
@@ -43,7 +43,9 @@
>> $ONOS_INSTALL_DIR/$KARAF_DIST/etc/system.properties
# Drop copycat related log level for the console
- echo "log4j.logger.net.kuujo.copycat= INFO" \
+ echo "log4j.logger.io.atomix=INFO" \
+ >> $ONOS_INSTALL_DIR/$KARAF_DIST/etc/org.ops4j.pax.logging.cfg
+ echo "log4j.logger.io.atomix.cluster.messaging=ERROR" \
>> $ONOS_INSTALL_DIR/$KARAF_DIST/etc/org.ops4j.pax.logging.cfg
# Patch the Apache Karaf distribution file to load ONOS boot features
@@ -64,7 +66,7 @@
# Generate a default cluster.json from the ON* environment variables
CDEF_FILE=/tmp/${remote}.cluster.json
-onos-gen-partitions $CDEF_FILE
+onos-gen-config $CDEF_FILE
scp -q $CDEF_FILE $remote_scp:$ONOS_INSTALL_DIR/config/cluster.json
# Copy tools/package/config/ to remote
diff --git a/tools/test/bin/onos-gen-partitions b/tools/test/bin/onos-gen-config
similarity index 74%
rename from tools/test/bin/onos-gen-partitions
rename to tools/test/bin/onos-gen-config
index a982c36..ef8f2f0 100755
--- a/tools/test/bin/onos-gen-partitions
+++ b/tools/test/bin/onos-gen-config
@@ -1,9 +1,9 @@
#!/usr/bin/env python
"""
-usage: onos-gen-partitions [-h] [-s PARTITION_SIZE] [-n NUM_PARTITIONS]
- [filename] [node_ip [node_ip ...]]
+usage: onos-gen-config [-h] [-s PARTITION_SIZE] [-n NUM_PARTITIONS]
+ [filename] [node_ip [node_ip ...]]
-Generate the partitions json file given a list of IPs or from the $OC*
+Generate the partitions json file given a list of IPs or from the $OCC*
environment variables.
positional arguments:
@@ -11,7 +11,7 @@
is written to stdout.
node_ip IP Address(es) of the node(s) in the cluster. If no
IPs are given, will use the $OC* environment
- variables. NOTE: these arguemnts are only processed
+ variables. NOTE: these arguments are only processed
after the filename argument.
optional arguments:
@@ -26,27 +26,26 @@
"""
from os import environ
-from collections import deque
import argparse
import re
import json
-import hashlib
convert = lambda text: int(text) if text.isdigit() else text.lower()
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
-def get_OC_vars():
+def get_OCC_vars():
vars = []
for var in environ:
- if re.match(r"OC[0-9]+", var):
+ if re.match(r"OCC[0-9]+", var):
vars.append(var)
return sorted(vars, key=alphanum_key)
-def get_nodes(ips=None, default_port=9876):
+def get_nodes(ips=None, default_port=5679):
node = lambda id, ip, port : { 'id': id, 'ip': ip, 'port': port }
result = []
if not ips:
- ips = [ environ[v] for v in get_OC_vars() ]
+ ips = [ environ[v] for v in get_OCC_vars() ]
+ i = 1
for ip_string in ips:
address_tuple = ip_string.split(":")
if len(address_tuple) == 3:
@@ -54,24 +53,13 @@
ip=address_tuple[1]
port=int(address_tuple[2])
else:
- id=ip_string
+ id='atomix-{}'.format(i)
+ i += 1
ip=ip_string
port=default_port
result.append(node(id, ip, port))
return result
-def generate_partitions(nodes, k, n):
- l = deque(nodes)
- perms = []
- for i in range(1, n+1):
- part = {
- 'id': i,
- 'members': list(l)[:k]
- }
- perms.append(part)
- l.rotate(-1)
- return perms
-
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description="Generate the partitions json file given a list of IPs or from the $OC* environment variables.")
@@ -94,20 +82,14 @@
args = parser.parse_args()
filename = args.filename
partition_size = args.partition_size
- nodes = get_nodes(args.nodes)
+ cluster = get_nodes(args.nodes)
num_partitions = args.num_partitions
if not num_partitions:
- num_partitions = len(nodes)
+ num_partitions = len(cluster)
- partitions = generate_partitions([v.get('id') for v in nodes], partition_size, num_partitions)
- m = hashlib.sha256()
- for node in nodes:
- m.update(node['ip'])
- name = int(m.hexdigest()[:8], base=16) # 32-bit int based on SHA256 digest
data = {
- 'name': name,
- 'nodes': nodes,
- 'partitions': partitions
+ 'name': 'onos',
+ 'cluster': cluster
}
output = json.dumps(data, indent=4)
diff --git a/tools/test/scenarios/setup.xml b/tools/test/scenarios/setup.xml
index e87996d..a3bdf32 100644
--- a/tools/test/scenarios/setup.xml
+++ b/tools/test/scenarios/setup.xml
@@ -27,33 +27,50 @@
<step name="Kill-${#}" env="~" exec="onos-kill ${OC#}"
requires="Uninstall-${#}"/>
</parallel>
+ <parallel var="${OCC#}">
+ <step name="Atomix-Kill-${#}"
+ env="~"
+ exec="atomix-kill ${OCC#}"/>
+ <step name="Atomix-Uninstall-${#}"
+ exec="atomix-uninstall ${OCC#}"
+ requires="Atomix-Kill-${#}"/>
+ </parallel>
</group>
- <group name="Install">
+ <group name="Install-Atomix">
<step name="Generate-Cluster-Key" exec="onos-gen-cluster-key -f" />
- <group name="Sequential-Install" if="${ONOS_STC_SEQ_START}">
- <sequential var="${OC#}"
- starts="Sequential-Install-${#}"
- ends="Sequential-Install-${#-1}">
- <step name="Sequential-Install-${#}" exec="onos-install ${OC#}"
- requires="Generate-Cluster-Key,Push-Bits-${#},Push-Bits,Cleanup"/>
- </sequential>
- </group>
-
- <group name="Parallel-Install" unless="${ONOS_STC_SEQ_START}">
- <parallel var="${OC#}">
- <step name="Parallel-Install-${#}" exec="onos-install ${OC#}"
+ <group name="Parallel-Install-Atomix">
+ <parallel var="${OCC#}">
+ <step name="Parallel-Install-Atomix-${#}" exec="atomix-install ${OCC#}"
requires="Generate-Cluster-Key,Push-Bits-${#},Push-Bits,Cleanup"/>
</parallel>
</group>
</group>
- <group name="Verify" requires="Install">
+ <group name="Install-ONOS">
+ <group name="Sequential-Install-ONOS" if="${ONOS_STC_SEQ_START}">
+ <sequential var="${OC#}"
+ starts="Sequential-Install-${#}"
+ ends="Sequential-Install-${#-1}">
+ <step name="Sequential-Install-${#}" exec="onos-install ${OC#}"
+ requires="Generate-Cluster-Key,Push-Bits-${#},Push-Bits,Cleanup,Install-Atomix"/>
+ </sequential>
+ </group>
+
+ <group name="Parallel-Install-ONOS" unless="${ONOS_STC_SEQ_START}">
+ <parallel var="${OC#}">
+ <step name="Parallel-Install-${#}" exec="onos-install ${OC#}"
+ requires="Generate-Cluster-Key,Push-Bits-${#},Push-Bits,Cleanup,Install-Atomix"/>
+ </parallel>
+ </group>
+ </group>
+
+ <group name="Verify" requires="Install-ONOS">
<parallel var="${OC#}">
<step name="Secure-SSH-${#}"
exec="onos-secure-ssh -u ${ONOS_WEB_USER} -p ${ONOS_WEB_PASS} ${OC#}"
- requires="Install"/>
+ requires="Install-ONOS"/>
<step name="Wait-for-Start-${#}" exec="onos-wait-for-start ${OC#}"
requires="~Secure-SSH-${#}"/>
diff --git a/tools/test/scenarios/teardown.xml b/tools/test/scenarios/teardown.xml
index 3199d25..3d2179e 100644
--- a/tools/test/scenarios/teardown.xml
+++ b/tools/test/scenarios/teardown.xml
@@ -16,7 +16,10 @@
<scenario name="teardown" description="ONOS cluster teardown/uninstall">
<group name="Teardown">
<parallel var="${OC#}">
- <step name="Uninstall-${#}" exec="onos-uninstall ${OC#}"/>
+ <step name="ONOS-Uninstall-${#}" exec="onos-uninstall ${OC#}"/>
+ </parallel>
+ <parallel var="${OCC#}">
+ <step name="Atomix-Uninstall-${#}" exec="atomix-uninstall ${OCC#}"/>
</parallel>
</group>
</scenario>