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 2021/02/01 07:41:42 UTC
[ignite] branch ignite-ducktape updated: IGNITE-13895: SSL usage in
ducktape tests (#8623)
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
The following commit(s) were added to refs/heads/ignite-ducktape by this push:
new c35850e IGNITE-13895: SSL usage in ducktape tests (#8623)
c35850e is described below
commit c35850e30df5a22ab90877d1dd6aa4b341a72900
Author: Sergei Ryzhov <s....@gmail.com>
AuthorDate: Mon Feb 1 10:41:14 2021 +0300
IGNITE-13895: SSL usage in ducktape tests (#8623)
---
modules/ducktests/tests/certs/functions.sh | 110 +++++++++++++++++++++
.../utils/__init__.py => certs/mkcerts.sh} | 24 ++++-
.../tests/checks/utils/check_parametrized.py | 9 +-
modules/ducktests/tests/docker/run_tests.sh | 2 +
.../ducktests/tests/ignitetest/services/ignite.py | 5 +
.../tests/ignitetest/services/ignite_app.py | 6 +-
.../ignitetest/services/utils/control_utility.py | 40 +++++++-
.../ignitetest/services/utils/ignite_aware.py | 26 +++++
.../utils/ignite_configuration/__init__.py | 4 +
.../tests/ignitetest/services/utils/path.py | 9 ++
.../{utils => services/utils/ssl}/__init__.py | 8 --
.../utils/ssl/connector_configuration.py} | 17 +++-
.../ignitetest/services/utils/ssl/ssl_factory.py | 45 +++++++++
.../utils/templates/connector_configuration.j2 | 29 ++++++
.../services/utils/templates/ignite.xml.j2 | 13 +++
.../services/utils/templates/ssl_factory_macro.j2 | 25 +++++
.../ignitetest/tests/cellular_affinity_test.py | 10 +-
.../tests/ignitetest/tests/client_test.py | 2 +-
.../tests/control_utility/baseline_test.py | 12 +--
.../ignitetest/tests/control_utility/tx_test.py | 6 +-
.../tests/ignitetest/tests/discovery_test.py | 6 +-
.../tests/ignitetest/tests/pme_free_switch_test.py | 7 +-
.../ducktests/tests/ignitetest/tests/ssl_test.py | 71 +++++++++++++
.../ducktests/tests/ignitetest/utils/__init__.py | 4 +-
modules/ducktests/tests/ignitetest/utils/_mark.py | 16 +--
25 files changed, 449 insertions(+), 57 deletions(-)
diff --git a/modules/ducktests/tests/certs/functions.sh b/modules/ducktests/tests/certs/functions.sh
new file mode 100644
index 0000000..ffe07e0
--- /dev/null
+++ b/modules/ducktests/tests/certs/functions.sh
@@ -0,0 +1,110 @@
+#!/usr/bin/env bash
+
+# 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.
+
+function makeRoot() {
+ ALIAS=$1
+ DNAME=$2
+ PSWD=$3
+
+ if [[ ${ALIAS} == "" ]] || [[ ${DNAME} == "" ]] || [[ ${PSWD} == "" ]]
+ then
+ error "makeRoot: Need ALIAS, DNAME, PSWD"
+ fi
+
+ rm -f "${ALIAS}.jks"
+ rm -f "${ALIAS}.pem"
+
+ keytool -genkeypair -keystore "${ALIAS}.jks" -alias "${ALIAS}" -dname "${DNAME}" -ext bc:c -storepass "${PSWD}" \
+ -keypass "${PSWD}" -noprompt -v
+
+ keytool -keystore "${ALIAS}.jks" -storepass "${PSWD}" -keypass "${PSWD}" -alias "${ALIAS}" -exportcert \
+ -rfc -file "${ALIAS}.pem" -v
+}
+
+function makeCA() {
+ ROOT=$1
+ ALIAS=$2
+ DNAME=$3
+ PSWD=$4
+
+ if [[ "${ROOT}" == "" ]] || [[ "${ALIAS}" == "" ]] || [[ "${DNAME}" == "" ]] || [[ "${PSWD}" == "" ]]
+ then
+ error "makeCA: Need CA, ALIAS, DNAME, PSWD"
+ fi
+
+ rm -f "${ALIAS}.jks"
+ rm -f "${ALIAS}.pem"
+
+ keytool -genkeypair -keystore "${ALIAS}.jks" -alias "${ALIAS}" -dname "${DNAME}" -ext bc:c -storepass "${PSWD}" \
+ -keypass "${PSWD}" -noprompt -v
+
+ keytool -storepass "${PSWD}" -keypass "${PSWD}" -keystore "${ALIAS}.jks" -certreq -alias "${ALIAS}" \
+ | keytool -storepass "${PSWD}" -keypass "${PSWD}" -keystore "${ROOT}.jks" -gencert -alias "${ROOT}" \
+ -ext BC=0 -rfc -outfile "${ALIAS}.pem" -v
+
+ keytool -keystore "${ALIAS}.jks" -storepass "${PSWD}" -keypass "${PSWD}" -importcert -alias "${ROOT}" \
+ -file "${ROOT}.pem" -noprompt -v
+ keytool -keystore "${ALIAS}.jks" -storepass "${PSWD}" -keypass "${PSWD}" -importcert -alias "${ALIAS}" \
+ -file "${ALIAS}.pem" -noprompt -v
+}
+
+function mkCert() {
+ CA=$1
+ ALIAS=$2
+ DNAME=$3
+ PSWD=$4
+
+ if [[ ${CA} == "" ]] || [[ ${ALIAS} == "" ]] || [[ ${DNAME} == "" ]] || [[ ${PSWD} == "" ]]
+ then
+ error "mkCert: Need CA, ALIAS, DNAME, PSWD"
+ fi
+
+ rm -f "${ALIAS}.jks"
+ rm -f "${ALIAS}.pem"
+ rm -f "${ALIAS}.csr"
+
+ keytool -genkeypair -keystore "${ALIAS}.jks" -alias "${ALIAS}" -dname "${DNAME}" -keyalg RSA -keysize 2048 \
+ -keypass "${PSWD}" -storepass "${PSWD}" -noprompt -v || error
+
+ keytool -storepass "${PSWD}" -keystore "${ALIAS}.jks" -certreq -alias "${ALIAS}" -file "${ALIAS}.csr" -v || error
+
+ keytool -gencert -infile "${ALIAS}.csr" -keystore "${CA}.jks" -alias "${CA}" -storepass "${PSWD}" -rfc \
+ -outfile "${ALIAS}.pem" -v || error
+
+ keytool -keystore "${ALIAS}.jks" -importcert -alias "${ALIAS}" -storepass "${PSWD}" -file "${ALIAS}.pem" \
+ -noprompt -v || error
+
+ rm -f "${ALIAS}.csr"
+ rm -f "${ALIAS}.pem"
+}
+
+function makeTruststore() {
+ rm -f truststore.jks
+
+ # shellcheck disable=SC2068
+ for cert in $@ ; do
+ keytool -keystore truststore.jks -importcert -alias "${cert}" -storepass 123456 -file "${cert}.pem" \
+ -noprompt -v || error
+
+ done
+}
+
+function error() {
+ # shellcheck disable=SC2145
+ echo "¯\_(ツ)_/¯ Something went wrong: $@"
+ exit 1
+}
diff --git a/modules/ducktests/tests/ignitetest/utils/__init__.py b/modules/ducktests/tests/certs/mkcerts.sh
old mode 100644
new mode 100755
similarity index 67%
copy from modules/ducktests/tests/ignitetest/utils/__init__.py
copy to modules/ducktests/tests/certs/mkcerts.sh
index a400779..222f3d7
--- a/modules/ducktests/tests/ignitetest/utils/__init__.py
+++ b/modules/ducktests/tests/certs/mkcerts.sh
@@ -1,3 +1,5 @@
+#!/usr/bin/env bash
+
# 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.
@@ -13,10 +15,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""
-This module contains convenient utils for test.
-"""
+CERTS_DIR="$(dirname "$0")"
+
+cd "${CERTS_DIR}" || exit 1
+
+source ./functions.sh
+
+PSWD=123456
+
+makeRoot root "CN=Ignite Root" "${PSWD}"
+
+makeCA root ca "CN=Ignite CA" "${PSWD}"
+
+makeTruststore root ca
-from ._mark import version_if, ignite_versions, cluster
+mkCert ca server "CN=Ignite Server" "${PSWD}"
+mkCert ca client "CN=Ignite Client" "${PSWD}"
+mkCert ca admin "CN=Ignite Admin" "${PSWD}"
-__all__ = ['version_if', 'ignite_versions', 'cluster']
+cd - || exit 1
diff --git a/modules/ducktests/tests/checks/utils/check_parametrized.py b/modules/ducktests/tests/checks/utils/check_parametrized.py
index 5eddb3f..dd87907a 100644
--- a/modules/ducktests/tests/checks/utils/check_parametrized.py
+++ b/modules/ducktests/tests/checks/utils/check_parametrized.py
@@ -23,8 +23,9 @@ from unittest.mock import Mock
import pytest
from ducktape.mark import parametrized, parametrize, matrix, ignore
from ducktape.mark.mark_expander import MarkedFunctionExpander
+from ignitetest.utils import ignite_versions, ignore_if
-from ignitetest.utils._mark import IgniteVersionParametrize, ignite_versions, version_if
+from ignitetest.utils._mark import IgniteVersionParametrize
from ignitetest.utils.version import IgniteVersion, V_2_8_0, V_2_8_1, V_2_7_6, DEV_BRANCH
@@ -213,13 +214,13 @@ class CheckVersionIf:
"""
Check common scenarios with @ignite_versions parametrization.
"""
- @version_if(lambda ver: ver != V_2_8_0, variable_name='ver')
+ @ignore_if(lambda version, globals: version == V_2_8_0, variable_name='ver')
@ignite_versions(str(DEV_BRANCH), str(V_2_8_0), version_prefix='ver')
def function_1(ver):
return IgniteVersion(ver)
- @version_if(lambda ver: ver > V_2_7_6, variable_name='ver_1')
- @version_if(lambda ver: ver < V_2_8_0, variable_name='ver_2')
+ @ignore_if(lambda ver, globals: ver == V_2_7_6, variable_name='ver_1')
+ @ignore_if(lambda ver, globals: ver >= V_2_8_0, variable_name='ver_2')
@ignite_versions((str(V_2_8_1), str(V_2_8_0)), (str(V_2_8_0), str(V_2_7_6)), version_prefix='ver')
def function_2(ver_1, ver_2):
return IgniteVersion(ver_1), IgniteVersion(ver_2)
diff --git a/modules/ducktests/tests/docker/run_tests.sh b/modules/ducktests/tests/docker/run_tests.sh
index 5facd8a..6ff723c 100755
--- a/modules/ducktests/tests/docker/run_tests.sh
+++ b/modules/ducktests/tests/docker/run_tests.sh
@@ -167,5 +167,7 @@ if [[ -n "$MAX_PARALLEL" ]]; then
DUCKTAPE_OPTIONS="$DUCKTAPE_OPTIONS --max-parallel $MAX_PARALLEL"
fi
+"$SCRIPT_DIR"/../certs/mkcerts.sh
+
"$SCRIPT_DIR"/ducker-ignite test "$TC_PATHS" "$DUCKTAPE_OPTIONS" \
|| die "ducker-ignite test failed"
diff --git a/modules/ducktests/tests/ignitetest/services/ignite.py b/modules/ducktests/tests/ignitetest/services/ignite.py
index 483ef2c..059b249 100644
--- a/modules/ducktests/tests/ignitetest/services/ignite.py
+++ b/modules/ducktests/tests/ignitetest/services/ignite.py
@@ -24,6 +24,7 @@ from datetime import datetime
from ducktape.cluster.remoteaccount import RemoteCommandError
from ignitetest.services.utils.ignite_aware import IgniteAwareService
+from ignitetest.services.utils.ssl.ssl_factory import DEFAULT_SERVER_KEYSTORE
class IgniteService(IgniteAwareService):
@@ -61,6 +62,10 @@ class IgniteService(IgniteAwareService):
except (RemoteCommandError, ValueError):
return []
+ def update_config_with_globals(self):
+ if self.globals.get("use_ssl", False):
+ self._update_ssl_config_with_globals("server", DEFAULT_SERVER_KEYSTORE)
+
def node_failed_event_pattern(failed_node_id=None):
"""Failed node pattern in log."""
diff --git a/modules/ducktests/tests/ignitetest/services/ignite_app.py b/modules/ducktests/tests/ignitetest/services/ignite_app.py
index 277724b..7414afc 100644
--- a/modules/ducktests/tests/ignitetest/services/ignite_app.py
+++ b/modules/ducktests/tests/ignitetest/services/ignite_app.py
@@ -16,7 +16,6 @@
"""
This module contains the base class to build Ignite aware application written on java.
"""
-
import re
# pylint: disable=W0622
@@ -24,6 +23,7 @@ from ducktape.errors import TimeoutError
from ignitetest.services.ignite_execution_exception import IgniteExecutionException
from ignitetest.services.utils.ignite_aware import IgniteAwareService
+from ignitetest.services.utils.ssl.ssl_factory import DEFAULT_CLIENT_KEYSTORE
class IgniteApplicationService(IgniteAwareService):
@@ -107,3 +107,7 @@ class IgniteApplicationService(IgniteAwareService):
res.append(re.search("%s(.*)%s" % (name + "->", "<-"), line).group(1))
return res
+
+ def update_config_with_globals(self):
+ if self.globals.get("use_ssl", False):
+ self._update_ssl_config_with_globals("client", DEFAULT_CLIENT_KEYSTORE)
diff --git a/modules/ducktests/tests/ignitetest/services/utils/control_utility.py b/modules/ducktests/tests/ignitetest/services/utils/control_utility.py
index 9b1a9ea..9f04b96 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/control_utility.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/control_utility.py
@@ -16,7 +16,7 @@
"""
This module contains control utility wrapper.
"""
-
+import os
import random
import re
import time
@@ -24,6 +24,8 @@ from typing import NamedTuple
from ducktape.cluster.remoteaccount import RemoteCommandError
+from ignitetest.services.utils.ssl.ssl_factory import DEFAULT_PASSWORD, DEFAULT_TRUSTSTORE, DEFAULT_ADMIN_KEYSTORE
+
class ControlUtility:
"""
@@ -31,9 +33,34 @@ class ControlUtility:
"""
BASE_COMMAND = "control.sh"
- def __init__(self, cluster, text_context):
+ # pylint: disable=R0913
+ def __init__(self, cluster,
+ key_store_jks: str = None, key_store_password: str = DEFAULT_PASSWORD,
+ trust_store_jks: str = DEFAULT_TRUSTSTORE, trust_store_password: str = DEFAULT_PASSWORD):
self._cluster = cluster
- self.logger = text_context.logger
+ self.logger = cluster.context.logger
+
+ if cluster.context.globals.get("use_ssl", False):
+ admin_dict = cluster.globals.get("admin", dict())
+
+ self.key_store_path = admin_dict.get("key_store_path",
+ self.jks_path(admin_dict.get('key_store_jks', DEFAULT_ADMIN_KEYSTORE)))
+ self.key_store_password = admin_dict.get('key_store_password', DEFAULT_PASSWORD)
+ self.trust_store_path = admin_dict.get("trust_store_path",
+ self.jks_path(admin_dict.get('trust_store_jks', DEFAULT_TRUSTSTORE)))
+ self.trust_store_password = admin_dict.get('trust_store_password', DEFAULT_PASSWORD)
+
+ elif key_store_jks is not None:
+ self.key_store_path = self.jks_path(key_store_jks)
+ self.key_store_password = key_store_password
+ self.trust_store_path = self.jks_path(trust_store_jks)
+ self.trust_store_password = trust_store_password
+
+ def jks_path(self, jks_name: str):
+ """
+ :return Path to jks file.
+ """
+ return os.path.join(self._cluster.certificate_dir, jks_name)
def baseline(self):
"""
@@ -264,7 +291,12 @@ class ControlUtility:
return output
def __form_cmd(self, node, cmd):
- return self._cluster.script(f"{self.BASE_COMMAND} --host {node.account.externally_routable_ip} {cmd}")
+ ssl = ""
+ if hasattr(self, 'key_store_path'):
+ ssl = f" --keystore {self.key_store_path} --keystore-password {self.key_store_password} " \
+ f"--truststore {self.trust_store_path} --truststore-password {self.trust_store_password}"
+
+ return self._cluster.script(f"{self.BASE_COMMAND} --host {node.account.externally_routable_ip} {cmd} {ssl}")
@staticmethod
def __parse_output(raw_output):
diff --git a/modules/ducktests/tests/ignitetest/services/utils/ignite_aware.py b/modules/ducktests/tests/ignitetest/services/utils/ignite_aware.py
index d1a3a38..bc275ce 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/ignite_aware.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/ignite_aware.py
@@ -38,6 +38,10 @@ from ignitetest.utils.enum import constructible
# pylint: disable=too-many-public-methods
+from ignitetest.services.utils.ssl.connector_configuration import ConnectorConfiguration
+from ignitetest.services.utils.ssl.ssl_factory import SslContextFactory
+
+
class IgniteAwareService(BackgroundThreadService, IgnitePathAware, metaclass=ABCMeta):
"""
The base class to build services aware of Ignite.
@@ -88,12 +92,19 @@ class IgniteAwareService(BackgroundThreadService, IgnitePathAware, metaclass=ABC
"""
Starts in async way.
"""
+ self.update_config_with_globals()
super().start(**kwargs)
def start(self, **kwargs):
self.start_async(**kwargs)
self.await_started()
+ @abstractmethod
+ def update_config_with_globals(self):
+ """
+ Update configuration with global parameters.
+ """
+
def await_started(self):
"""
Awaits start finished.
@@ -404,3 +415,18 @@ class IgniteAwareService(BackgroundThreadService, IgnitePathAware, metaclass=ABC
rotated_log = os.path.join(self.log_dir, f"console.log.{cnt}")
self.logger.debug(f"rotating {node.log_file} to {rotated_log} on {node.name}")
node.account.ssh(f"mv {node.log_file} {rotated_log}")
+
+ def _update_ssl_config_with_globals(self, dict_name: str, default_jks: str):
+ """
+ Update ssl configuration.
+ """
+ _dict = self.globals.get(dict_name)
+
+ if _dict is not None:
+ ssl_context_factory = SslContextFactory(self.install_root, **_dict)
+ else:
+ ssl_context_factory = SslContextFactory(self.install_root, default_jks)
+
+ self.config = self.config._replace(ssl_context_factory=ssl_context_factory)
+ self.config = self.config._replace(connector_configuration=ConnectorConfiguration(
+ ssl_enabled=True, ssl_context_factory=ssl_context_factory))
diff --git a/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py b/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py
index fbf3cd6..7799288 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py
@@ -20,8 +20,10 @@ This module contains IgniteConfiguration classes and utilities.
from typing import NamedTuple
from ignitetest.services.utils.ignite_configuration.communication import CommunicationSpi, TcpCommunicationSpi
+from ignitetest.services.utils.ssl.connector_configuration import ConnectorConfiguration
from ignitetest.services.utils.ignite_configuration.data_storage import DataStorageConfiguration
from ignitetest.services.utils.ignite_configuration.discovery import DiscoverySpi, TcpDiscoverySpi
+from ignitetest.services.utils.ssl.ssl_factory import SslContextFactory
from ignitetest.utils.version import IgniteVersion, DEV_BRANCH
@@ -41,6 +43,8 @@ class IgniteConfiguration(NamedTuple):
data_storage: DataStorageConfiguration = None
caches: list = []
local_host: str = None
+ ssl_context_factory: SslContextFactory = None
+ connector_configuration: ConnectorConfiguration = None
class IgniteClientConfiguration(IgniteConfiguration):
diff --git a/modules/ducktests/tests/ignitetest/services/utils/path.py b/modules/ducktests/tests/ignitetest/services/utils/path.py
index 9cab69d..7747568 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/path.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/path.py
@@ -21,6 +21,7 @@ import os
from abc import abstractmethod, ABCMeta
from ignitetest.services.utils.config_template import IgniteLoggerConfigTemplate
+from ignitetest.utils.version import DEV_BRANCH
def get_home_dir(install_root, project, version):
@@ -165,6 +166,14 @@ class IgnitePathAware(PathAware, metaclass=ABCMeta):
def log_config_file(self):
return os.path.join(self.persistent_root, "ignite-log4j.xml")
+ @property
+ def certificate_dir(self):
+ """
+ :return: path to the certificate directory.
+ """
+ return os.path.join(get_home_dir(self.install_root, self.project, DEV_BRANCH),
+ "modules", "ducktests", "tests", "certs")
+
def script(self, script_name):
"""
:param script_name: name of Ignite script
diff --git a/modules/ducktests/tests/ignitetest/utils/__init__.py b/modules/ducktests/tests/ignitetest/services/utils/ssl/__init__.py
similarity index 82%
copy from modules/ducktests/tests/ignitetest/utils/__init__.py
copy to modules/ducktests/tests/ignitetest/services/utils/ssl/__init__.py
index a400779..ec20143 100644
--- a/modules/ducktests/tests/ignitetest/utils/__init__.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/ssl/__init__.py
@@ -12,11 +12,3 @@
# 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 module contains convenient utils for test.
-"""
-
-from ._mark import version_if, ignite_versions, cluster
-
-__all__ = ['version_if', 'ignite_versions', 'cluster']
diff --git a/modules/ducktests/tests/ignitetest/utils/__init__.py b/modules/ducktests/tests/ignitetest/services/utils/ssl/connector_configuration.py
similarity index 63%
copy from modules/ducktests/tests/ignitetest/utils/__init__.py
copy to modules/ducktests/tests/ignitetest/services/utils/ssl/connector_configuration.py
index a400779..4d75b78 100644
--- a/modules/ducktests/tests/ignitetest/utils/__init__.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/ssl/connector_configuration.py
@@ -11,12 +11,21 @@
# 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.
+# limitations under the License
"""
-This module contains convenient utils for test.
+This module contains classes and utilities for Ignite ConnectorConfiguration.
"""
-from ._mark import version_if, ignite_versions, cluster
+from typing import NamedTuple
-__all__ = ['version_if', 'ignite_versions', 'cluster']
+from ignitetest.services.utils.ssl.ssl_factory import SslContextFactory
+
+
+class ConnectorConfiguration(NamedTuple):
+ """
+ Ignite ConnectorConfiguration.
+ Used to connect from ControlUtility (control.sh).
+ """
+ ssl_enabled: bool = False
+ ssl_context_factory: SslContextFactory = None
diff --git a/modules/ducktests/tests/ignitetest/services/utils/ssl/ssl_factory.py b/modules/ducktests/tests/ignitetest/services/utils/ssl/ssl_factory.py
new file mode 100644
index 0000000..51468aa
--- /dev/null
+++ b/modules/ducktests/tests/ignitetest/services/utils/ssl/ssl_factory.py
@@ -0,0 +1,45 @@
+# 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 module contains classes and utilities for SslContextFactory.
+"""
+import os
+
+DEFAULT_PASSWORD = "123456"
+DEFAULT_SERVER_KEYSTORE = "server.jks"
+DEFAULT_CLIENT_KEYSTORE = "client.jks"
+DEFAULT_ADMIN_KEYSTORE = "admin.jks"
+DEFAULT_TRUSTSTORE = "truststore.jks"
+
+
+class SslContextFactory:
+ """
+ Ignite SslContextFactory.
+ """
+
+ # pylint: disable=R0913
+ def __init__(self, root_dir: str = "/opt",
+ key_store_jks: str = DEFAULT_SERVER_KEYSTORE, key_store_password: str = DEFAULT_PASSWORD,
+ trust_store_jks: str = DEFAULT_TRUSTSTORE, trust_store_password: str = DEFAULT_PASSWORD,
+ key_store_path: str = None, trust_store_path: str = None):
+ certificate_dir = os.path.join(root_dir, "ignite-dev", "modules", "ducktests", "tests", "certs")
+
+ self.key_store_path = key_store_path if key_store_path is not None \
+ else os.path.join(certificate_dir, key_store_jks)
+ self.key_store_password = key_store_password
+ self.trust_store_path = trust_store_path if trust_store_path is not None \
+ else os.path.join(certificate_dir, trust_store_jks)
+ self.trust_store_password = trust_store_password
diff --git a/modules/ducktests/tests/ignitetest/services/utils/templates/connector_configuration.j2 b/modules/ducktests/tests/ignitetest/services/utils/templates/connector_configuration.j2
new file mode 100644
index 0000000..7a43f99
--- /dev/null
+++ b/modules/ducktests/tests/ignitetest/services/utils/templates/connector_configuration.j2
@@ -0,0 +1,29 @@
+{#
+ 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.
+#}
+
+{% import 'ssl_factory_macro.j2' as ssl_factory_util %}
+
+{% macro connector_configuration(config) %}
+ <bean class="org.apache.ignite.configuration.ConnectorConfiguration">
+ <property name="sslEnabled" value="{{ config.ssl_enabled }}"/>
+ {% if config.ssl_enabled %}
+ <property name="sslFactory">
+ {{ ssl_factory_util.ssl_factory(config.ssl_context_factory) }}
+ </property>
+ {% endif %}
+ </bean>
+{% endmacro %}
diff --git a/modules/ducktests/tests/ignitetest/services/utils/templates/ignite.xml.j2 b/modules/ducktests/tests/ignitetest/services/utils/templates/ignite.xml.j2
index cfed0a7..8bbff0f 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/templates/ignite.xml.j2
+++ b/modules/ducktests/tests/ignitetest/services/utils/templates/ignite.xml.j2
@@ -22,6 +22,8 @@
{% import 'cache_macro.j2' as cache_utils %}
{% import 'datastorage_macro.j2' as datastorage_utils %}
{% import 'misc_macro.j2' as misc_utils %}
+{% import 'ssl_factory_macro.j2' as ssl_factory_util %}
+{% import 'connector_configuration.j2' as connector_configuration_util %}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -57,5 +59,16 @@
{% if config.properties %}
{{ config.properties }}
{% endif %}
+
+ {% if config.ssl_context_factory %}
+ <property name="sslContextFactory">
+ {{ ssl_factory_util.ssl_factory(config.ssl_context_factory) }}
+ </property>
+ {% endif %}
+ {% if config.connector_configuration %}
+ <property name="connectorConfiguration">
+ {{ connector_configuration_util.connector_configuration(config.connector_configuration) }}
+ </property>
+ {% endif %}
</bean>
</beans>
diff --git a/modules/ducktests/tests/ignitetest/services/utils/templates/ssl_factory_macro.j2 b/modules/ducktests/tests/ignitetest/services/utils/templates/ssl_factory_macro.j2
new file mode 100644
index 0000000..2f8878c
--- /dev/null
+++ b/modules/ducktests/tests/ignitetest/services/utils/templates/ssl_factory_macro.j2
@@ -0,0 +1,25 @@
+{#
+ 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.
+#}
+
+{% macro ssl_factory(factory) %}
+<bean class="org.apache.ignite.ssl.SslContextFactory">
+ <property name="keyStoreFilePath" value="{{ factory.key_store_path }}"/>
+ <property name="keyStorePassword" value="{{ factory.key_store_password }}"/>
+ <property name="trustStoreFilePath" value="{{ factory.trust_store_path }}"/>
+ <property name="trustStorePassword" value="{{ factory.trust_store_password }}"/>
+</bean>
+{% endmacro %}
diff --git a/modules/ducktests/tests/ignitetest/tests/cellular_affinity_test.py b/modules/ducktests/tests/ignitetest/tests/cellular_affinity_test.py
index e6541fa..a8aa393 100644
--- a/modules/ducktests/tests/ignitetest/tests/cellular_affinity_test.py
+++ b/modules/ducktests/tests/ignitetest/tests/cellular_affinity_test.py
@@ -29,7 +29,7 @@ from ignitetest.services.utils.ignite_configuration import IgniteConfiguration,
from ignitetest.services.utils.ignite_configuration.discovery import from_ignite_cluster, from_zookeeper_cluster, \
TcpDiscoverySpi
from ignitetest.services.zk.zookeeper import ZookeeperSettings, ZookeeperService
-from ignitetest.utils import ignite_versions, version_if, cluster
+from ignitetest.utils import ignite_versions, cluster, ignore_if
from ignitetest.utils.enum import constructible
from ignitetest.utils.ignite_test import IgniteTest
from ignitetest.utils.version import DEV_BRANCH, IgniteVersion, LATEST_2_8
@@ -104,7 +104,7 @@ class CellularAffinity(IgniteTest):
cacheName=CellularAffinity.CACHE_NAME)
@cluster(num_nodes=NODES_PER_CELL * 3 + 1)
- @version_if(lambda version: version >= DEV_BRANCH)
+ @ignore_if(lambda version, globals: version < DEV_BRANCH)
@ignite_versions(str(DEV_BRANCH))
def test_distribution(self, ignite_version):
"""
@@ -121,7 +121,7 @@ class CellularAffinity(IgniteTest):
for cell in [cell1, cell2, cell3]:
cell.await_started()
- ControlUtility(cell1, self.test_context).activate()
+ ControlUtility(cell1).activate()
checker = IgniteApplicationService(
self.test_context,
@@ -203,8 +203,8 @@ class CellularAffinity(IgniteTest):
for streamer in streamers:
streamer.await_started()
- ControlUtility(cell0, self.test_context).disable_baseline_auto_adjust() # baseline set.
- ControlUtility(cell0, self.test_context).activate()
+ ControlUtility(cell0).disable_baseline_auto_adjust() # baseline set.
+ ControlUtility(cell0).activate()
for loader in loaders:
loader.await_event("ALL_TRANSACTIONS_PREPARED", 180, from_the_beginning=True)
diff --git a/modules/ducktests/tests/ignitetest/tests/client_test.py b/modules/ducktests/tests/ignitetest/tests/client_test.py
index 28b1213..fa5cf44 100644
--- a/modules/ducktests/tests/ignitetest/tests/client_test.py
+++ b/modules/ducktests/tests/ignitetest/tests/client_test.py
@@ -91,7 +91,7 @@ class ClientTest(IgniteTest):
ignite = IgniteService(self.test_context, server_cfg, num_nodes=servers_count)
- control_utility = ControlUtility(ignite, self.test_context)
+ control_utility = ControlUtility(ignite)
client_cfg = server_cfg._replace(client_mode=True)
diff --git a/modules/ducktests/tests/ignitetest/tests/control_utility/baseline_test.py b/modules/ducktests/tests/ignitetest/tests/control_utility/baseline_test.py
index 8951006..281c91f 100644
--- a/modules/ducktests/tests/ignitetest/tests/control_utility/baseline_test.py
+++ b/modules/ducktests/tests/ignitetest/tests/control_utility/baseline_test.py
@@ -24,7 +24,7 @@ from ignitetest.services.utils.control_utility import ControlUtility, ControlUti
from ignitetest.services.utils.ignite_configuration import IgniteConfiguration, DataStorageConfiguration
from ignitetest.services.utils.ignite_configuration.data_storage import DataRegionConfiguration
from ignitetest.services.utils.ignite_configuration.discovery import from_ignite_cluster
-from ignitetest.utils import version_if, ignite_versions, cluster
+from ignitetest.utils import ignore_if, ignite_versions, cluster
from ignitetest.utils.ignite_test import IgniteTest
from ignitetest.utils.version import DEV_BRANCH, LATEST, IgniteVersion, V_2_8_0
@@ -45,7 +45,7 @@ class BaselineTests(IgniteTest):
blt_size = self.NUM_NODES - 2
servers = self.__start_ignite_nodes(ignite_version, blt_size)
- control_utility = ControlUtility(servers, self.test_context)
+ control_utility = ControlUtility(servers)
control_utility.activate()
# Check baseline of activated cluster.
@@ -81,7 +81,7 @@ class BaselineTests(IgniteTest):
blt_size = self.NUM_NODES - 1
servers = self.__start_ignite_nodes(ignite_version, blt_size)
- control_utility = ControlUtility(servers, self.test_context)
+ control_utility = ControlUtility(servers)
control_utility.activate()
@@ -122,7 +122,7 @@ class BaselineTests(IgniteTest):
"""
servers = self.__start_ignite_nodes(ignite_version, self.NUM_NODES)
- control_utility = ControlUtility(servers, self.test_context)
+ control_utility = ControlUtility(servers)
control_utility.activate()
@@ -137,7 +137,7 @@ class BaselineTests(IgniteTest):
assert state.lower() == 'inactive', 'Unexpected state %s' % state
@cluster(num_nodes=NUM_NODES)
- @version_if(lambda version: version >= V_2_8_0)
+ @ignore_if(lambda version, globals: version < V_2_8_0)
@ignite_versions(str(DEV_BRANCH), str(LATEST))
def test_baseline_autoadjust(self, ignite_version):
"""
@@ -146,7 +146,7 @@ class BaselineTests(IgniteTest):
blt_size = self.NUM_NODES - 2
servers = self.__start_ignite_nodes(ignite_version, blt_size)
- control_utility = ControlUtility(servers, self.test_context)
+ control_utility = ControlUtility(servers)
control_utility.activate()
# Add node.
diff --git a/modules/ducktests/tests/ignitetest/tests/control_utility/tx_test.py b/modules/ducktests/tests/ignitetest/tests/control_utility/tx_test.py
index bc059e5..2e962b9 100644
--- a/modules/ducktests/tests/ignitetest/tests/control_utility/tx_test.py
+++ b/modules/ducktests/tests/ignitetest/tests/control_utility/tx_test.py
@@ -52,7 +52,7 @@ class TransactionsTests(IgniteTest):
wait_for_key_locked(long_tx)
- control_utility = ControlUtility(servers, self.test_context)
+ control_utility = ControlUtility(servers)
transactions = control_utility.tx()
@@ -83,7 +83,7 @@ class TransactionsTests(IgniteTest):
wait_for_key_locked(long_tx_1, long_tx_2)
- control_utility = ControlUtility(servers, self.test_context)
+ control_utility = ControlUtility(servers)
# check kill with specific xid.
transactions = control_utility.tx(label_pattern='TX_1')
@@ -115,7 +115,7 @@ class TransactionsTests(IgniteTest):
wait_for_topology_version=4)
wait_for_key_locked(clients, servers)
- control_utility = ControlUtility(servers, self.test_context)
+ control_utility = ControlUtility(servers)
start_check = self.monotonic()
assert len(control_utility.tx(clients=True, label_pattern='LBL_.*')) == client_tx_count
diff --git a/modules/ducktests/tests/ignitetest/tests/discovery_test.py b/modules/ducktests/tests/ignitetest/tests/discovery_test.py
index 6ce08a0..17bfdc4 100644
--- a/modules/ducktests/tests/ignitetest/tests/discovery_test.py
+++ b/modules/ducktests/tests/ignitetest/tests/discovery_test.py
@@ -34,7 +34,7 @@ from ignitetest.services.utils.ignite_configuration.discovery import from_zookee
TcpDiscoverySpi
from ignitetest.services.utils.time_utils import epoch_mills
from ignitetest.services.zk.zookeeper import ZookeeperService, ZookeeperSettings
-from ignitetest.utils import ignite_versions, version_if, cluster
+from ignitetest.utils import ignite_versions, ignore_if, cluster
from ignitetest.utils.ignite_test import IgniteTest
from ignitetest.utils.version import DEV_BRANCH, LATEST, LATEST_2_7, V_2_8_0, V_2_9_0, IgniteVersion
from ignitetest.utils.enum import constructible
@@ -123,7 +123,7 @@ class DiscoveryTest(IgniteTest):
return self._perform_node_fail_scenario(test_config)
@cluster(num_nodes=MAX_CONTAINERS)
- @version_if(lambda version: version != V_2_8_0) # ignite-zookeeper package is broken in 2.8.0
+ @ignore_if(lambda version, globals: version == V_2_8_0) # ignite-zookeeper package is broken in 2.8.0
@ignite_versions(str(DEV_BRANCH), str(LATEST))
@matrix(nodes_to_kill=[1, 2], failure_detection_timeout=[FAILURE_TIMEOUT],
load_type=[ClusterLoad.NONE, ClusterLoad.ATOMIC, ClusterLoad.TRANSACTIONAL])
@@ -138,7 +138,7 @@ class DiscoveryTest(IgniteTest):
return self._perform_node_fail_scenario(test_config)
@cluster(num_nodes=MAX_CONTAINERS)
- @version_if(lambda version: version != V_2_8_0) # ignite-zookeeper package is broken in 2.8.0
+ @ignore_if(lambda version, globals: version == V_2_8_0) # ignite-zookeeper package is broken in 2.8.0
@ignite_versions(str(DEV_BRANCH), str(LATEST))
@matrix(load_type=[ClusterLoad.NONE, ClusterLoad.ATOMIC, ClusterLoad.TRANSACTIONAL],
failure_detection_timeout=[FAILURE_TIMEOUT])
diff --git a/modules/ducktests/tests/ignitetest/tests/pme_free_switch_test.py b/modules/ducktests/tests/ignitetest/tests/pme_free_switch_test.py
index 08a43bf..2109490 100644
--- a/modules/ducktests/tests/ignitetest/tests/pme_free_switch_test.py
+++ b/modules/ducktests/tests/ignitetest/tests/pme_free_switch_test.py
@@ -28,7 +28,7 @@ from ignitetest.services.utils.control_utility import ControlUtility
from ignitetest.services.utils.ignite_configuration import IgniteConfiguration
from ignitetest.services.utils.ignite_configuration.cache import CacheConfiguration
from ignitetest.services.utils.ignite_configuration.discovery import from_ignite_cluster
-from ignitetest.utils import ignite_versions, cluster
+from ignitetest.utils import ignite_versions, cluster, ignore_if
from ignitetest.utils.enum import constructible
from ignitetest.utils.ignite_test import IgniteTest
from ignitetest.utils.version import DEV_BRANCH, LATEST_2_7, V_2_8_0, IgniteVersion
@@ -54,6 +54,7 @@ class PmeFreeSwitchTest(IgniteTest):
EXTRA_CACHES_AMOUNT = 100
@cluster(num_nodes=NUM_NODES + 2)
+ @ignore_if(lambda version, globals: version <= V_2_8_0 or not globals.get("use_ssl"))
@ignite_versions(str(DEV_BRANCH), str(LATEST_2_7))
@matrix(load_type=[LoadType.NONE, LoadType.EXTRA_CACHES, LoadType.LONG_TXS])
def test(self, ignite_version, load_type):
@@ -84,9 +85,9 @@ class PmeFreeSwitchTest(IgniteTest):
ignites.start()
if IgniteVersion(ignite_version) >= V_2_8_0:
- ControlUtility(ignites, self.test_context).disable_baseline_auto_adjust()
+ ControlUtility(ignites).disable_baseline_auto_adjust()
- ControlUtility(ignites, self.test_context).activate()
+ ControlUtility(ignites).activate()
client_config = config._replace(client_mode=True,
discovery_spi=from_ignite_cluster(ignites, slice(0, num_nodes - 1)))
diff --git a/modules/ducktests/tests/ignitetest/tests/ssl_test.py b/modules/ducktests/tests/ignitetest/tests/ssl_test.py
new file mode 100644
index 0000000..4df3180
--- /dev/null
+++ b/modules/ducktests/tests/ignitetest/tests/ssl_test.py
@@ -0,0 +1,71 @@
+# 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 module contains ssl tests.
+"""
+from ignitetest.services.ignite import IgniteService
+from ignitetest.services.ignite_app import IgniteApplicationService
+from ignitetest.services.utils.control_utility import ControlUtility
+from ignitetest.services.utils.ignite_configuration import IgniteConfiguration
+from ignitetest.services.utils.ssl.connector_configuration import ConnectorConfiguration
+from ignitetest.services.utils.ssl.ssl_factory import SslContextFactory
+from ignitetest.utils import ignite_versions, cluster
+from ignitetest.utils.ignite_test import IgniteTest
+from ignitetest.utils.version import IgniteVersion, DEV_BRANCH, LATEST_2_9, LATEST_2_8
+
+
+# pylint: disable=W0223
+class SslTest(IgniteTest):
+ """
+ Ssl test.
+ """
+ @cluster(num_nodes=3)
+ @ignite_versions(str(DEV_BRANCH), str(LATEST_2_9), str(LATEST_2_8))
+ def test_ssl_connection(self, ignite_version):
+ """
+ Test that IgniteService, IgniteApplicationService correctly start and stop with ssl configurations.
+ And check ControlUtility with ssl arguments.
+ """
+ root_dir = self.test_context.globals.get("install_root", "/opt")
+
+ server_ssl = SslContextFactory(root_dir=root_dir)
+
+ server_configuration = IgniteConfiguration(
+ version=IgniteVersion(ignite_version), ssl_context_factory=server_ssl,
+ connector_configuration=ConnectorConfiguration(ssl_enabled=True, ssl_context_factory=server_ssl))
+
+ ignite = IgniteService(self.test_context, server_configuration, num_nodes=2,
+ startup_timeout_sec=180)
+
+ client_configuration = server_configuration._replace(
+ client_mode=True,
+ ssl_context_factory=SslContextFactory(root_dir, key_store_jks="client.jks"))
+
+ app = IgniteApplicationService(
+ self.test_context,
+ client_configuration,
+ java_class_name="org.apache.ignite.internal.ducktest.tests.smoke_test.SimpleApplication",
+ startup_timeout_sec=180)
+
+ control_utility = ControlUtility(cluster=ignite, key_store_jks="admin.jks")
+
+ ignite.start()
+ app.start()
+
+ control_utility.cluster_state()
+
+ app.stop()
+ ignite.stop()
diff --git a/modules/ducktests/tests/ignitetest/utils/__init__.py b/modules/ducktests/tests/ignitetest/utils/__init__.py
index a400779..6d6da0d 100644
--- a/modules/ducktests/tests/ignitetest/utils/__init__.py
+++ b/modules/ducktests/tests/ignitetest/utils/__init__.py
@@ -17,6 +17,6 @@
This module contains convenient utils for test.
"""
-from ._mark import version_if, ignite_versions, cluster
+from ._mark import ignore_if, ignite_versions, cluster
-__all__ = ['version_if', 'ignite_versions', 'cluster']
+__all__ = ['ignore_if', 'ignite_versions', 'cluster']
diff --git a/modules/ducktests/tests/ignitetest/utils/_mark.py b/modules/ducktests/tests/ignitetest/utils/_mark.py
index d6d0bdb..69bb685 100644
--- a/modules/ducktests/tests/ignitetest/utils/_mark.py
+++ b/modules/ducktests/tests/ignitetest/utils/_mark.py
@@ -26,9 +26,9 @@ from ducktape.mark._mark import Ignore, Mark, _inject
from ignitetest.utils.version import IgniteVersion
-class VersionIf(Ignore):
+class IgnoreIf(Ignore):
"""
- Ignore test if version doesn't corresponds to condition.
+ Ignore test if version or global parameters correspond to condition.
"""
def __init__(self, condition, variable_name):
super().__init__()
@@ -36,13 +36,13 @@ class VersionIf(Ignore):
self.variable_name = variable_name
def apply(self, seed_context, context_list):
- assert len(context_list) > 0, "ignore_if decorator is not being applied to any test cases"
+ assert len(context_list) > 0, "ignore if decorator is not being applied to any test cases"
for ctx in context_list:
if self.variable_name in ctx.injected_args:
version = ctx.injected_args[self.variable_name]
assert isinstance(version, str), "'%s'n injected args must be a string" % (self.variable_name,)
- ctx.ignore = ctx.ignore or not self.condition(IgniteVersion(version))
+ ctx.ignore = ctx.ignore or self.condition(IgniteVersion(version), ctx.globals)
return context_list
@@ -192,15 +192,15 @@ def ignite_versions(*args, version_prefix="ignite_version"):
return parametrizer
-def version_if(condition, *, variable_name='ignite_version'):
+def ignore_if(condition, *, variable_name='ignite_version'):
"""
- Mark decorated test method as IGNORE if version doesn't corresponds to condition.
+ Mark decorated test method as IGNORE if version or global parameters correspond to condition.
- :param condition: function(IgniteVersion) -> bool
+ :param condition: function(IgniteVersion, Globals) -> bool
:param variable_name: version variable name
"""
def ignorer(func):
- Mark.mark(func, VersionIf(condition, variable_name))
+ Mark.mark(func, IgnoreIf(condition, variable_name))
return func
return ignorer