-#!/usr/bin/python3
-
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# SPDX-License-Identifier: MPL-2.0
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
-# This script is a 'port' broker. It keeps track of ports given to the
-# individual system subtests, so every test is given a unique port range.
-
-import logging
import os
from pathlib import Path
import platform
import random
import subprocess
import time
-from typing import Dict, List, NamedTuple, Union
-
-# Uncomment to enable DEBUG logging
-# logging.basicConfig(
-# format="get_algorithms.py %(levelname)s %(message)s", level=logging.DEBUG
-# )
+from typing import Dict, List, NamedTuple, Optional, Union
+
+from .basic import BASIC_VARS
+from .. import log
+
+# Algorithms are selected randomly at runtime from a list of supported
+# algorithms. The randomization is deterministic and remains stable for a
+# period of time for a given platform.
+ALG_VARS = {
+ # There are multiple algoritms sets to choose from (see ALGORITHM_SETS). To
+ # override the default choice, set the ALGORITHM_SET env var prior to
+ # loading this module or call set_algorithm_set().
+ "ALGORITHM_SET": "none",
+ "DEFAULT_ALGORITHM": "",
+ "DEFAULT_ALGORITHM_NUMBER": "",
+ "DEFAULT_BITS": "",
+ # Alternative algorithm for test cases that require more than one algorithm
+ # (for example algorithm rollover). Must be different from
+ # DEFAULT_ALGORITHM.
+ "ALTERNATIVE_ALGORITHM": "",
+ "ALTERNATIVE_ALGORITHM_NUMBER": "",
+ "ALTERNATIVE_BITS": "",
+ # Algorithm that is used for tests against the "disable-algorithms"
+ # configuration option. Must be different from above algorithms.
+ "DISABLED_ALGORITHM": "",
+ "DISABLED_ALGORITHM_NUMBER": "",
+ "DISABLED_BITS": "",
+ # Default HMAC algorithm. Must match the rndc configuration in
+ # bin/tests/system/_common (rndc.conf, rndc.key)
+ "DEFAULT_HMAC": "hmac-sha256",
+}
STABLE_PERIOD = 3600 * 3
"""number of secs during which algorithm selection remains stable"""
# ),
}
-TESTCRYPTO = Path(__file__).resolve().parent / "testcrypto.sh"
-
-KEYGEN = os.getenv("KEYGEN", "")
-if not KEYGEN:
- raise RuntimeError("KEYGEN environment variable has to be set")
+# TODO rewrite testcrypto.sh to python
+TESTCRYPTO = Path(__file__).resolve().parent.parent.parent / "testcrypto.sh"
-ALGORITHM_SET = os.getenv("ALGORITHM_SET", "stable")
-assert ALGORITHM_SET in ALGORITHM_SETS, f'ALGORITHM_SET "{ALGORITHM_SET}" unknown'
-logging.debug('choosing from ALGORITHM_SET "%s"', ALGORITHM_SET)
-
-def is_supported(alg: Algorithm) -> bool:
+def _is_supported(alg: Algorithm) -> bool:
"""Test whether a given algorithm is supported on the current platform."""
try:
subprocess.run(
f"{TESTCRYPTO} -q {alg.name}",
shell=True,
check=True,
- env={
- "KEYGEN": KEYGEN,
- "TMPDIR": os.getenv("TMPDIR", "/tmp"),
- },
+ env=BASIC_VARS,
stdout=subprocess.DEVNULL,
)
except subprocess.CalledProcessError as exc:
- logging.debug(exc)
- logging.info("algorithm %s not supported", alg.name)
+ log.debug(exc)
+ log.info("algorithm %s not supported", alg.name)
return False
return True
-def filter_supported(algs: AlgorithmSet) -> AlgorithmSet:
+def _filter_supported(algs: AlgorithmSet) -> AlgorithmSet:
"""Select supported algorithms from the set."""
filtered = {}
for alg_type in algs._fields:
candidates = getattr(algs, alg_type)
if isinstance(candidates, Algorithm):
candidates = [candidates]
- supported = list(filter(is_supported, candidates))
+ supported = list(filter(_is_supported, candidates))
if len(supported) == 1:
supported = supported.pop()
elif not supported:
raise RuntimeError(
- f'no {alg_type.upper()} algorithm from "{ALGORITHM_SET}" set '
- "supported on this platform"
+ f"no {alg_type.upper()} algorithm " "supported on this platform"
)
filtered[alg_type] = supported
return AlgorithmSet(**filtered)
-def select_random(algs: AlgorithmSet, stable_period=STABLE_PERIOD) -> AlgorithmSet:
+def _select_random(algs: AlgorithmSet, stable_period=STABLE_PERIOD) -> AlgorithmSet:
"""Select random DEFAULT, ALTERNATIVE and DISABLED algorithms from the set.
The algorithm selection is deterministic for a given time period and
return AlgorithmSet(default, alternative, disabled)
-def algorithms_env(algs: AlgorithmSet) -> Dict[str, str]:
+def _algorithms_env(algs: AlgorithmSet, name: str) -> Dict[str, str]:
"""Return environment variables with selected algorithms as a dict."""
- algs_env: Dict[str, str] = {}
+ algs_env = {
+ "ALGORITHM_SET": name,
+ }
def set_alg_env(alg: Algorithm, prefix):
algs_env[f"{prefix}_ALGORITHM"] = alg.name
set_alg_env(algs.alternative, "ALTERNATIVE")
set_alg_env(algs.disabled, "DISABLED")
- logging.info("selected algorithms: %s", algs_env)
+ log.info("selected algorithms: %s", algs_env)
return algs_env
-def main():
- try:
- algs = ALGORITHM_SETS[ALGORITHM_SET]
- algs = filter_supported(algs)
- algs = select_random(algs)
- algs_env = algorithms_env(algs)
- except Exception:
- # if anything goes wrong, the conf.sh ignores error codes, so make sure
- # we set an environment variable to an error value that can be checked
- # later by the test runner and/or tests themselves
- print("export ALGORITHM_SET=error")
- raise
- for name, value in algs_env.items():
- print(f"export {name}={value}")
-
-
-if __name__ == "__main__":
- main()
+def set_algorithm_set(name: Optional[str]):
+ if name is None:
+ name = "stable"
+ assert name in ALGORITHM_SETS, f'ALGORITHM_SET "{name}" unknown'
+ if name == ALG_VARS["ALGORITHM_SET"]:
+ log.debug('algorithm set already configured: "%s"', name)
+ return
+ log.debug('choosing from ALGORITHM_SET "%s"', name)
+
+ algs = ALGORITHM_SETS[name]
+ algs = _filter_supported(algs)
+ algs = _select_random(algs)
+ algs_env = _algorithms_env(algs, name)
+
+ ALG_VARS.update(algs_env)
+ os.environ.update(algs_env)