+function installed () {
+
+ # Check if the given utility is installed. Fail if not installed.
+ #
+ # Duplicate of common.sh function, as this file is also used standalone.
+ #
+ # Arguments:
+ # - ${1} - Utility to check.
+ # Returns:
+ # - 0 - If command is installed.
+ # - 1 - If command is not installed.
+
+ set -exuo pipefail
+
+ command -v "${1}"
+}
+
+
+function move_archives () {
+
+ # Move archive directory to top of workspace, if not already there.
+ #
+ # ARCHIVE_DIR is positioned relative to CSIT_DIR,
+ # but in some jobs CSIT_DIR is not same as WORKSPACE
+ # (e.g. under VPP_DIR). To simplify ci-management settings,
+ # we want to move the data to the top. We do not want simple copy,
+ # as ci-management is eager with recursive search.
+ #
+ # As some scripts may call this function multiple times,
+ # the actual implementation use copying and deletion,
+ # so the workspace gets "union" of contents (except overwrites on conflict).
+ # The consequence is empty ARCHIVE_DIR remaining after this call.
+ #
+ # As the source directory is emptied,
+ # the check for dirs being different is essential.
+ #
+ # Variables read:
+ # - WORKSPACE - Jenkins workspace, move only if the value is not empty.
+ # Can be unset, then it speeds up manual testing.
+ # - ARCHIVE_DIR - Path to directory with content to be moved.
+ # Directories updated:
+ # - ${WORKSPACE}/archives/ - Created if does not exist.
+ # Content of ${ARCHIVE_DIR}/ is moved.
+ # Functions called:
+ # - die - Print to stderr and exit.
+
+ set -exuo pipefail
+
+ if [[ -n "${WORKSPACE-}" ]]; then
+ target=$(readlink -f "${WORKSPACE}/archives")
+ if [[ "${target}" != "${ARCHIVE_DIR}" ]]; then
+ mkdir -p "${target}" || die "Archives dir create failed."
+ cp -rf "${ARCHIVE_DIR}"/* "${target}" || die "Copy failed."
+ rm -rf "${ARCHIVE_DIR}"/* || die "Delete failed."
+ fi
+ fi
+}
+
+
+function post_process_robot_outputs () {
+
+ # Generate INFO level output_info.xml by rebot.
+ # Archive UTI raw json outputs.
+ #
+ # Variables read:
+ # - ARCHIVE_DIR - Path to post-processed files.
+
+ set -exuo pipefail
+
+ # Compress raw json outputs, as they will never be post-processed.
+ pushd "${ARCHIVE_DIR}" || die
+ if [ -d "tests" ]; then
+ # Use deterministic order.
+ options+=("--sort=name")
+ # We are keeping info outputs where they are.
+ # Assuming we want to move anything but info files (and dirs).
+ options+=("--exclude=*.info.json")
+ tar czf "generated_output_raw.tar.gz" "${options[@]}" "tests" || true
+ # Tar can remove when archiving, but chokes (not deterministically)
+ # on attempting to remove dirs (not empty as info files are there).
+ # So we need to delete the raw files manually.
+ find "tests" -type f -name "*.raw.json" -delete || true
+ fi
+ popd || die
+
+ # Generate INFO level output_info.xml for post-processing.
+ all_options=("--loglevel" "INFO")
+ all_options+=("--log" "none")
+ all_options+=("--report" "none")
+ all_options+=("--output" "${ARCHIVE_DIR}/output_info.xml")
+ all_options+=("${ARCHIVE_DIR}/output.xml")
+ rebot "${all_options[@]}" || true
+}
+
+
+function prepare_topology () {
+
+ # Prepare virtual testbed topology if needed based on flavor.
+
+ # Variables read:
+ # - TEST_CODE - String affecting test selection, usually jenkins job name.
+ # - NODENESS - Node multiplicity of testbed, either "2n" or "3n".
+ # - FLAVOR - Node flavor string, e.g. "clx" or "skx".
+ # Functions called:
+ # - die - Print to stderr and exit.
+ # - terraform_init - Terraform init topology.
+ # - terraform_apply - Terraform apply topology.
+
+ set -exuo pipefail
+
+ case_text="${NODENESS}_${FLAVOR}"
+ case "${case_text}" in
+ "2n_aws")
+ export TF_VAR_testbed_name="${TEST_CODE}"
+ terraform_init || die "Failed to call terraform init."
+ terraform_apply || die "Failed to call terraform apply."
+ ;;
+ "3n_aws")
+ export TF_VAR_testbed_name="${TEST_CODE}"
+ terraform_init || die "Failed to call terraform init."
+ terraform_apply || die "Failed to call terraform apply."
+ ;;
+ esac
+}
+
+