You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ni...@apache.org on 2020/05/25 08:08:29 UTC
[ignite] 14/24: ignite-ducktape: IgniteClientApplication added and
working.
This is an automated email from the ASF dual-hosted git repository.
nizhikov pushed a commit to branch ignite-ducktape
in repository https://gitbox.apache.org/repos/asf/ignite.git
commit f8b176a272d1cbdbadb3c6b66ae301b91615f0bc
Author: Nikolay Izhikov <ni...@apache.org>
AuthorDate: Wed May 6 16:05:52 2020 +0300
ignite-ducktape: IgniteClientApplication added and working.
---
.../ignite/internal/test/IgniteApplication.java | 52 ++++++++
tests/docker/build/cluster.json | 11 ++
tests/docker/build/node_hosts | 8 +-
tests/docker/run_tests.sh | 2 +-
tests/ignitetest/ignite_utils/ignite_config.py | 2 +-
tests/ignitetest/ignite_utils/ignite_path.py | 71 ++---------
tests/ignitetest/services/ignite/ignite.py | 10 +-
tests/ignitetest/services/ignite_client_app.py | 137 +++++++++------------
tests/ignitetest/suites/add_node_rebalance_test.py | 6 +-
9 files changed, 143 insertions(+), 156 deletions(-)
diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/test/IgniteApplication.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/test/IgniteApplication.java
new file mode 100644
index 0000000..dffa891
--- /dev/null
+++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/test/IgniteApplication.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.test;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgnitionEx;
+import org.apache.ignite.internal.processors.resource.GridSpringResourceContext;
+import org.apache.ignite.lang.IgniteBiTuple;
+
+public class IgniteApplication {
+ public static final String CONFIG_PATH = "/mnt/client_app/ignite-config.xml";
+
+ public static void main(String[] args) throws IgniteCheckedException {
+ IgniteBiTuple<IgniteConfiguration, GridSpringResourceContext> cfgs = IgnitionEx.loadConfiguration(CONFIG_PATH);
+ IgniteConfiguration cfg = cfgs.get1();
+
+ cfg.setClientMode(true);
+
+ System.out.println("Starting Ignite client...");
+
+ try (Ignite ign = Ignition.start(cfg)) {
+ System.out.println("Creating cache...");
+
+ IgniteCache<Integer, Integer> cache = ign.createCache("test-cache");
+
+ for (int i = 0; i < 1000; i++) {
+ cache.put(i, i);
+ }
+
+ System.out.println("Ignite Client Finish.");
+ }
+ }
+}
diff --git a/tests/docker/build/cluster.json b/tests/docker/build/cluster.json
index 6e5e46e..297d9c4 100644
--- a/tests/docker/build/cluster.json
+++ b/tests/docker/build/cluster.json
@@ -48,6 +48,17 @@
"port": 22,
"user": "ducker"
}
+ },
+ {
+ "externally_routable_ip": "ducker05",
+ "ssh_config": {
+ "host": "ducker05",
+ "hostname": "ducker05",
+ "identityfile": "/home/ducker/.ssh/id_rsa",
+ "password": "",
+ "port": 22,
+ "user": "ducker"
+ }
}
]
}
diff --git a/tests/docker/build/node_hosts b/tests/docker/build/node_hosts
index e1183dd..9da72b8 100644
--- a/tests/docker/build/node_hosts
+++ b/tests/docker/build/node_hosts
@@ -1,7 +1,7 @@
-172.22.0.2 ducker01
-172.22.0.3 ducker02
-172.22.0.4 ducker03
-172.22.0.5 ducker04
+172.26.0.2 ducker01
+172.26.0.3 ducker02
+172.26.0.4 ducker03
+172.26.0.5 ducker04
172.26.0.6 ducker05
172.26.0.7 ducker06
172.26.0.8 ducker07
diff --git a/tests/docker/run_tests.sh b/tests/docker/run_tests.sh
index 653b46a..9de2317 100755
--- a/tests/docker/run_tests.sh
+++ b/tests/docker/run_tests.sh
@@ -16,7 +16,7 @@
# limitations under the License.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-IGNITE_NUM_CONTAINERS=${IGNITE_NUM_CONTAINERS:-4}
+IGNITE_NUM_CONTAINERS=${IGNITE_NUM_CONTAINERS:-5}
TC_PATHS=${TC_PATHS:-./ignitetest/}
die() {
diff --git a/tests/ignitetest/ignite_utils/ignite_config.py b/tests/ignitetest/ignite_utils/ignite_config.py
index b0008a6..534df42 100644
--- a/tests/ignitetest/ignite_utils/ignite_config.py
+++ b/tests/ignitetest/ignite_utils/ignite_config.py
@@ -49,7 +49,7 @@ class IgniteConfig:
<appender name="CONSOLE_ERR" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.err"/>
- <param name="Threshold" value="ERROR"/>
+ <param name="Threshold" value="INFO"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{{ISO8601}}][%-5p][%t][%c{{1}}] %m%n"/>
diff --git a/tests/ignitetest/ignite_utils/ignite_path.py b/tests/ignitetest/ignite_utils/ignite_path.py
index 6b733d6..6307175 100644
--- a/tests/ignitetest/ignite_utils/ignite_path.py
+++ b/tests/ignitetest/ignite_utils/ignite_path.py
@@ -13,60 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import importlib
import os
from ignitetest.version import get_version, IgniteVersion, DEV_BRANCH
-
-"""This module serves a few purposes:
-
-First, it gathers information about path layout in a single place, and second, it
-makes the layout of the Ignite installation pluggable, so that users are not forced
-to use the layout assumed in the IgnitePathResolver class.
+"""
+This module provides Ignite path methods
"""
-SCRATCH_ROOT = "/mnt"
-IGNITE_INSTALL_ROOT = "/opt"
-
-def create_path_resolver(context, project="ignite"):
- """Factory for generating a path resolver class
-
- This will first check for a fully qualified path resolver classname in context.globals.
-
- If present, construct a new instance, else default to IgniteSystemTestPathResolver
- """
- assert project is not None
-
- resolver_fully_qualified_classname = "ignitetest.ignite_utils.ignite_path.IgniteSystemTestPathResolver"
- # Using the fully qualified classname, import the resolver class
- (module_name, resolver_class_name) = resolver_fully_qualified_classname.rsplit('.', 1)
- cluster_mod = importlib.import_module(module_name)
- path_resolver_class = getattr(cluster_mod, resolver_class_name)
- path_resolver = path_resolver_class(context, project)
-
- return path_resolver
-
-
-class IgnitePathResolverMixin(object):
- """Mixin to automatically provide pluggable path resolution functionality to any class using it.
-
- Keep life simple, and don't add a constructor to this class:
- Since use of a mixin entails multiple inheritence, it is *much* simpler to reason about the interaction of this
- class with subclasses if we don't have to worry about method resolution order, constructor signatures etc.
- """
-
- @property
- def path(self):
- if not hasattr(self, "_path"):
- setattr(self, "_path", create_path_resolver(self.context, "ignite"))
- if hasattr(self.context, "logger") and self.context.logger is not None:
- self.context.logger.debug("Using path resolver %s" % self._path.__class__.__name__)
-
- return self._path
+class IgnitePath:
+ SCRATCH_ROOT = "/mnt"
+ IGNITE_INSTALL_ROOT = "/opt"
-class IgniteSystemTestPathResolver(object):
"""Path resolver for Ignite system tests which assumes the following layout:
/opt/ignite-dev # Current version of Ignite under test
@@ -74,8 +33,8 @@ class IgniteSystemTestPathResolver(object):
/opt/ignite-<version> # Other previous versions of Ignite
...
"""
- def __init__(self, context, project="ignite"):
- self.context = context
+
+ def __init__(self, project="ignite"):
self.project = project
def home(self, node_or_version=DEV_BRANCH, project=None):
@@ -84,26 +43,14 @@ class IgniteSystemTestPathResolver(object):
if version is not None:
home_dir += "-%s" % str(version)
- return os.path.join(IGNITE_INSTALL_ROOT, home_dir)
-
- def bin(self, node_or_version=DEV_BRANCH, project=None):
- version = self._version(node_or_version)
- return os.path.join(self.home(version, project=project), "bin")
+ return os.path.join(IgnitePath.IGNITE_INSTALL_ROOT, home_dir)
def script(self, script_name, node_or_version=DEV_BRANCH, project=None):
version = self._version(node_or_version)
- return os.path.join(self.bin(version, project=project), script_name)
-
- def jar(self, jar_name, node_or_version=DEV_BRANCH, project=None):
- version = self._version(node_or_version)
- return os.path.join(self.home(version, project=project), JARS[str(version)][jar_name])
-
- def scratch_space(self, service_instance):
- return os.path.join(SCRATCH_ROOT, service_instance.service_id)
+ return os.path.join(self.home(version, project=project), "bin", script_name)
def _version(self, node_or_version):
if isinstance(node_or_version, IgniteVersion):
return node_or_version
else:
return get_version(node_or_version)
-
diff --git a/tests/ignitetest/services/ignite/ignite.py b/tests/ignitetest/services/ignite/ignite.py
index 1dcdbdc..f8f208a 100644
--- a/tests/ignitetest/services/ignite/ignite.py
+++ b/tests/ignitetest/services/ignite/ignite.py
@@ -18,14 +18,13 @@ import signal
from ducktape.services.service import Service
from ducktape.utils.util import wait_until
-from ducktape.cluster.remoteaccount import RemoteCommandError
from ignitetest.ignite_utils.ignite_config import IgniteConfig
-from ignitetest.ignite_utils.ignite_path import IgnitePathResolverMixin
+from ignitetest.ignite_utils.ignite_path import IgnitePath
from ignitetest.version import DEV_BRANCH
-class IgniteService(IgnitePathResolverMixin, Service):
+class IgniteService(Service):
PERSISTENT_ROOT = "/mnt/ignite"
WORK_DIR = os.path.join(PERSISTENT_ROOT, "work")
CONFIG_FILE = os.path.join(PERSISTENT_ROOT, "ignite-config.xml")
@@ -43,7 +42,7 @@ class IgniteService(IgnitePathResolverMixin, Service):
"collect_default": False}
}
- def __init__(self, context, num_nodes=3, version=DEV_BRANCH):
+ def __init__(self, context, num_nodes=1, version=DEV_BRANCH):
"""
:param context: test context
:param num_nodes: number of Ignite nodes.
@@ -52,6 +51,7 @@ class IgniteService(IgnitePathResolverMixin, Service):
self.log_level = "DEBUG"
self.config = IgniteConfig()
+ self.path = IgnitePath()
for node in self.nodes:
node.version = version
@@ -85,7 +85,7 @@ class IgniteService(IgnitePathResolverMixin, Service):
self.logger.debug("Attempting to start IgniteService on %s with command: %s" % (str(node.account), cmd))
with node.account.monitor_log(IgniteService.STDOUT_STDERR_CAPTURE) as monitor:
node.account.ssh(cmd)
- monitor.wait_until("Topology snapshot", timeout_sec=timeout_sec, backoff_sec=.25,
+ monitor.wait_until("Topology snapshot", timeout_sec=timeout_sec, backoff_sec=5,
err_msg="Ignite server didn't finish startup in %d seconds" % timeout_sec)
if len(self.pids(node)) == 0:
diff --git a/tests/ignitetest/services/ignite_client_app.py b/tests/ignitetest/services/ignite_client_app.py
index 4462e71..82a661a 100644
--- a/tests/ignitetest/services/ignite_client_app.py
+++ b/tests/ignitetest/services/ignite_client_app.py
@@ -15,35 +15,29 @@
import os
-from ducktape.cluster.remoteaccount import RemoteCommandError
from ducktape.services.background_thread import BackgroundThreadService
-from ignitetest.directory_layout.ignite_path import IgnitePathResolverMixin
-
+from ignitetest.ignite_utils.ignite_config import IgniteConfig
+from ignitetest.ignite_utils.ignite_path import IgnitePath
from ignitetest.version import DEV_BRANCH
"""
-The console consumer is a tool that reads data from Kafka and outputs it to standard output.
+The Ignite client application is a main class that implements custom logic.
+First CMD param is an absolute path to the Ignite config file.
"""
-class IgniteClientApp(IgnitePathResolverMixin, BackgroundThreadService):
+class IgniteClientApp(BackgroundThreadService):
# Root directory for persistent output
PERSISTENT_ROOT = "/mnt/client_app"
- STDOUT_CAPTURE = os.path.join(PERSISTENT_ROOT, "client_app.stdout")
- STDERR_CAPTURE = os.path.join(PERSISTENT_ROOT, "client_app.stderr")
- LOG_DIR = os.path.join(PERSISTENT_ROOT, "logs")
- LOG_FILE = os.path.join(LOG_DIR, "client_app.log")
+ STDOUT_STDERR_CAPTURE = os.path.join(PERSISTENT_ROOT, "console.log")
+ WORK_DIR = os.path.join(PERSISTENT_ROOT, "work")
+ CONFIG_FILE = os.path.join(PERSISTENT_ROOT, "ignite-config.xml")
+ LOG4J_CONFIG_FILE = os.path.join(PERSISTENT_ROOT, "ignite-log4j.xml")
logs = {
- "consumer_stdout": {
- "path": STDOUT_CAPTURE,
- "collect_default": False},
- "consumer_stderr": {
- "path": STDERR_CAPTURE,
- "collect_default": False},
- "consumer_log": {
- "path": LOG_FILE,
+ "console_log": {
+ "path": STDOUT_STDERR_CAPTURE,
"collect_default": True}
}
@@ -54,66 +48,30 @@ class IgniteClientApp(IgnitePathResolverMixin, BackgroundThreadService):
"""
BackgroundThreadService.__init__(self, context, num_nodes)
+ self.stop_timeout_sec = 10
+ self.log_level = "DEBUG"
+ self.config = IgniteConfig()
+ self.path = IgnitePath()
+
for node in self.nodes:
node.version = version
def start_cmd(self, node):
"""Return the start command appropriate for the given node."""
- args = self.args.copy()
- args['stdout'] = IgniteClientApp.STDOUT_CAPTURE
- args['stderr'] = IgniteClientApp.STDERR_CAPTURE
- args['log_dir'] = IgniteClientApp.LOG_DIR
- args['config_file'] = IgniteClientApp.CONFIG_FILE
- args['stdout'] = IgniteClientApp.STDOUT_CAPTURE
- args['console_consumer'] = self.path.script("kafka-console-consumer.sh", node)
-
- cmd = "%(console_consumer)s " \
- "--topic %(topic)s " \
- "--consumer.config %(config_file)s " % args
-
- cmd += " 2>> %(stderr)s | tee -a %(stdout)s &" % args
- return cmd
-
- def pids(self, node):
- return node.account.java_pids(self.java_class_name())
- def alive(self, node):
- return len(self.pids(node)) > 0
-
- def _worker(self, idx, node):
- node.account.ssh("mkdir -p %s" % IgniteClientApp.PERSISTENT_ROOT, allow_fail=False)
-
- self.security_config = self.kafka.security_config.client_config(node=node,
- jaas_override_variables=self.jaas_override_variables)
- self.security_config.setup_node(node)
-
- if self.client_prop_file_override:
- prop_file = self.client_prop_file_override
- else:
- prop_file = self.prop_file(node)
-
- # TODO: create ignite config: node.account.create_file(IgniteClientApp.CONFIG_FILE, prop_file)
-
- # Run and capture output
- cmd = self.start_cmd(node)
- self.logger.debug("Console consumer %d command: %s", idx, cmd)
-
- consumer_output = node.account.ssh_capture(cmd, allow_fail=False)
-
- # TODO: create ignite version of waiting for a app finish
- for line in consumer_output:
- msg = line.strip()
- if msg == "shutdown_complete":
- # Note that we can only rely on shutdown_complete message if running 0.10.0 or greater
- if node in self.clean_shutdown_nodes:
- raise Exception(
- "Unexpected shutdown event from consumer, already shutdown. Consumer index: %d" % idx)
- self.clean_shutdown_nodes.add(node)
- else:
- if self.message_validator is not None:
- msg = self.message_validator(msg)
- if msg is not None:
- self.messages_consumed[idx].append(msg)
+ jvm_opts = "-J-DIGNITE_SUCCESS_FILE=" + IgniteClientApp.PERSISTENT_ROOT + "/success_file "
+ jvm_opts += "-J-Dlog4j.configDebug=true"
+
+ cmd = "export MAIN_CLASS={main_class}; ".format(main_class=self.java_class_name())
+ cmd += "export EXCLUDE_TEST_CLASSES=true; "
+ cmd += "export IGNITE_LOG_DIR=" + IgniteClientApp.PERSISTENT_ROOT + "; "
+ cmd += "%s %s %s 1>> %s 2>> %s " % \
+ (self.path.script("ignite.sh", node),
+ jvm_opts,
+ IgniteClientApp.CONFIG_FILE,
+ IgniteClientApp.STDOUT_STDERR_CAPTURE,
+ IgniteClientApp.STDOUT_STDERR_CAPTURE)
+ return cmd
def start_node(self, node):
BackgroundThreadService.start_node(self, node)
@@ -121,7 +79,8 @@ class IgniteClientApp(IgnitePathResolverMixin, BackgroundThreadService):
def stop_node(self, node):
self.logger.info("%s Stopping node %s" % (self.__class__.__name__, str(node.account)))
node.account.kill_java_processes(self.java_class_name(),
- clean_shutdown=True, allow_fail=True)
+ clean_shutdown=True,
+ allow_fail=True)
stopped = self.wait_node(node, timeout_sec=self.stop_timeout_sec)
assert stopped, "Node %s: did not stop within the specified timeout of %s seconds" % \
@@ -131,16 +90,30 @@ class IgniteClientApp(IgnitePathResolverMixin, BackgroundThreadService):
if self.alive(node):
self.logger.warn("%s %s was still alive at cleanup time. Killing forcefully..." %
(self.__class__.__name__, node.account))
- node.account.kill_java_processes(self.java_class_name(), clean_shutdown=False, allow_fail=True)
+
+ node.account.kill_java_processes(self.java_class_name(),
+ clean_shutdown=False,
+ allow_fail=True)
+
node.account.ssh("rm -rf %s" % IgniteClientApp.PERSISTENT_ROOT, allow_fail=False)
- self.security_config.clean_node(node)
+
+ def pids(self, node):
+ return node.account.java_pids(self.java_class_name())
+
+ def alive(self, node):
+ return len(self.pids(node)) > 0
+
+ def _worker(self, idx, node):
+ node.account.mkdirs(IgniteClientApp.PERSISTENT_ROOT)
+ node.account.create_file(IgniteClientApp.CONFIG_FILE,
+ self.config.render(IgniteClientApp.PERSISTENT_ROOT, IgniteClientApp.WORK_DIR))
+ node.account.create_file(IgniteClientApp.LOG4J_CONFIG_FILE,
+ self.config.render_log4j(IgniteClientApp.WORK_DIR))
+
+ # Just run application.
+ cmd = self.start_cmd(node)
+ self.logger.info("Ignite client application command: %s", cmd)
+ node.account.ssh(cmd, allow_fail=False)
def java_class_name(self):
- return "org.apache.ignite.test.IgniteApplication"
-
- def has_log_message(self, node, message):
- try:
- node.account.ssh("grep '%s' %s" % (message, IgniteClientApp.LOG_FILE))
- except RemoteCommandError:
- return False
- return True
+ return "org.apache.ignite.internal.test.IgniteApplication"
diff --git a/tests/ignitetest/suites/add_node_rebalance_test.py b/tests/ignitetest/suites/add_node_rebalance_test.py
index 6b354ce..24ca151 100644
--- a/tests/ignitetest/suites/add_node_rebalance_test.py
+++ b/tests/ignitetest/suites/add_node_rebalance_test.py
@@ -16,6 +16,7 @@
from ducktape.tests.test import Test
from ignitetest.services.ignite.ignite import IgniteService
+from ignitetest.services.ignite_client_app import IgniteClientApp
class AddNodeRebalanceTest(Test):
@@ -41,6 +42,9 @@ class AddNodeRebalanceTest(Test):
* Await for rebalance to finish.
"""
self.logger.info("Start add node rebalance test.")
+ self.client = IgniteClientApp(self.test_context)
+ self.client.start()
+ self.client.wait()
for node in self.ignite.nodes:
- node.account.ssh("touch /opt/hello-from-test.txt")
+ node.account.ssh("touch /opt/hello-from-test-after-client.txt")