Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[nodejs] add nodejs docker_ssi test app #3530

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion lib-injection/build/docker/nodejs/sample-app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ process.on('SIGTERM', (signal) => {
process.exit(0);
});

function crashme(req, res) {
setTimeout(() => {
process.kill(process.pid, 'SIGSEGV');

res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`Crashing process ${process.pid}`);
}, 2000); // Add a delay before crashing otherwise the telemetry forwarder leaves a zombie behind
}

function forkAndCrash(req, res) {
const child = fork('child.js');

Expand Down Expand Up @@ -105,7 +114,9 @@ function getZombies(req, res) {
}

require('http').createServer((req, res) => {
if (req.url === '/fork_and_crash') {
if (req.url === '/crashme') {
crashme(req, res);
} else if (req.url === '/fork_and_crash') {
forkAndCrash(req, res);
} else if (req.url === '/child_pids') {
getChildPids(req, res);
Expand Down
5 changes: 4 additions & 1 deletion tests/docker_ssi/test_docker_ssi.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from urllib.parse import urlparse

from utils import scenarios, features, context, irrelevant, bug, interfaces, missing_feature
from utils import scenarios, features, context, irrelevant, bug, interfaces
from utils import weblog
from utils.tools import logger, get_rid_from_request

Expand Down Expand Up @@ -34,6 +34,7 @@ def setup_install_supported_runtime(self):
@bug(condition=context.library == "python", reason="INPLAT-11")
@irrelevant(context.library == "java" and context.installed_language_runtime < "1.8.0_0")
@irrelevant(context.library == "php" and context.installed_language_runtime < "7.0")
@irrelevant(context.library == "nodejs" and context.installed_language_runtime < "16.0")
def test_install_supported_runtime(self):
logger.info(f"Testing Docker SSI installation on supported lang runtime: {context.scenario.library.library}")
assert self.r.status_code == 200, f"Failed to get response from {context.scenario.weblog_url}"
Expand Down Expand Up @@ -69,6 +70,7 @@ def test_install_weblog_running(self):
@irrelevant(context.library == "java" and context.installed_language_runtime < "1.8.0_0")
@irrelevant(context.library == "php" and context.installed_language_runtime < "7.0")
@irrelevant(context.library == "python" and context.installed_language_runtime < "3.7.0")
@irrelevant(context.library == "nodejs" and context.installed_language_runtime < "16.0")
def test_telemetry(self):
# There is telemetry data about the auto instrumentation injector. We only validate there is data
telemetry_autoinject_data = interfaces.test_agent.get_telemetry_for_autoinject()
Expand All @@ -95,6 +97,7 @@ def test_telemetry(self):
@irrelevant(context.library == "php" and context.installed_language_runtime >= "7.0")
@bug(condition=context.library == "python" and context.installed_language_runtime < "3.7.0", reason="INPLAT-181")
@irrelevant(context.library == "python" and context.installed_language_runtime >= "3.7.0")
@irrelevant(context.library == "nodejs" and context.installed_language_runtime >= "16.0")
def test_telemetry_abort(self):
# There is telemetry data about the auto instrumentation injector. We only validate there is data
telemetry_autoinject_data = interfaces.test_agent.get_telemetry_for_autoinject()
Expand Down
3 changes: 2 additions & 1 deletion tests/docker_ssi/test_docker_ssi_crash.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ def setup_crash(self):
self.r = TestDockerSSICrash._r

@features.ssi_crashtracking
@bug(condition=context.library != "python", reason="INPLAT-11")
@bug(condition=context.library not in ("python", "nodejs"), reason="INPLAT-11")
@irrelevant(context.library == "python" and context.installed_language_runtime < "3.7.0")
@irrelevant(context.library == "nodejs" and context.installed_language_runtime < "16.0")
def test_crash(self):
"""Validate that a crash report is generated when the application crashes"""
logger.info(f"Testing Docker SSI crash tracking: {context.scenario.library.library}")
Expand Down
10 changes: 7 additions & 3 deletions utils/_context/_scenarios/docker_ssi.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ def __init__(
self.should_push_base_images = False
self._weblog_docker_image = None

@property
def dd_lang(self) -> str:
return "js" if self._library == "nodejs" else self._library

def configure(self):
self.docker_tag = self.get_base_docker_tag()
self._docker_registry_tag = f"ghcr.io/datadog/system-tests/ssi_installer_{self.docker_tag}:latest"
Expand Down Expand Up @@ -309,7 +313,7 @@ def build_lang_deps_image(self):
nocache=self._force_build or self.should_push_base_images,
buildargs={
"ARCH": self._arch,
"DD_LANG": self._library,
"DD_LANG": self.dd_lang,
"RUNTIME_VERSIONS": self._installable_runtime,
"BASE_IMAGE": self._base_image,
},
Expand Down Expand Up @@ -363,7 +367,7 @@ def build_weblog_image(self, ssi_installer_docker_tag):
platform=self._arch,
nocache=self._force_build or self.should_push_base_images,
tag=self.ssi_all_docker_tag,
buildargs={"DD_LANG": self._library, "BASE_IMAGE": ssi_installer_docker_tag},
buildargs={"DD_LANG": self.dd_lang, "BASE_IMAGE": ssi_installer_docker_tag},
)
self.print_docker_build_logs(self.ssi_all_docker_tag, build_logs)
logger.stdout(f"[tag:{weblog_docker_tag}] Building weblog app on base image [{self.ssi_all_docker_tag}].")
Expand All @@ -390,7 +394,7 @@ def tested_components(self):
Return json with the data"""
logger.info("Weblog extract tested components")
result = get_docker_client().containers.run(
image=self._weblog_docker_image, command=f"/tested_components.sh {self._library}", remove=True
image=self._weblog_docker_image, command=f"/tested_components.sh {self.dd_lang}", remove=True
)
logger.info(f"Testes components: {result.decode('utf-8')}")
return json.loads(result.decode("utf-8").replace("'", '"'))
Expand Down
2 changes: 1 addition & 1 deletion utils/build/ssi/base/healthcheck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ if [ -z "${WEBLOG_URL-}" ]; then
WEBLOG_URL="http://localhost:18080"
fi

curl --fail --silent --show-error ${WEBLOG_URL}
curl --fail --silent --show-error "${WEBLOG_URL}"
36 changes: 36 additions & 0 deletions utils/build/ssi/base/js_install_runtimes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash
# shellcheck disable=SC1091

export NODEJS_VERSION=$1

if [ -f /etc/debian_version ] || [ "$DISTRIBUTION" = "Debian" ] || [ "$DISTRIBUTION" = "Ubuntu" ]; then
OS="Debian"
elif [ -f /etc/redhat-release ] || [ "$DISTRIBUTION" = "RedHat" ] || [ "$DISTRIBUTION" = "CentOS" ] || [ "$DISTRIBUTION" = "Amazon" ] || [ "$DISTRIBUTION" = "Rocky" ] || [ "$DISTRIBUTION" = "AlmaLinux" ]; then
OS="RedHat"
elif [ -f /etc/system-release ] || [ "$DISTRIBUTION" = "Amazon" ]; then
OS="RedHat"
elif [ -f /etc/Eos-release ] || [ "$DISTRIBUTION" = "Arista" ]; then
OS="RedHat"
elif [ -f /etc/SuSE-release ] || [ "$DISTRIBUTION" = "SUSE" ] || [ "$DISTRIBUTION" = "openSUSE" ]; then
OS="SUSE"
elif [ -f /etc/alpine-release ]; then
OS="Alpine"
fi

if [ "$OS" = "Debian" ]; then
apt-get update
ln -fs /usr/share/zoneinfo/America/New_York /etc/localtime
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends git curl
elif [ "$OS" = "RedHat" ]; then
yum install -y git curl
else
echo "Unknown OS"
exit 1
fi

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
export NVM_DIR="/root/.nvm"
. "$NVM_DIR/nvm.sh"
nvm install "${NODEJS_VERSION}"
nvm alias default "${NODEJS_VERSION}"
node --version
10 changes: 8 additions & 2 deletions utils/build/ssi/base/tested_components.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/bin/bash
# shellcheck disable=SC2116,SC2086
# shellcheck disable=SC2116,SC2086,SC1091

export DD_APM_INSTRUMENTATION_DEBUG=false
DD_LANG=$1

Expand All @@ -10,6 +11,11 @@ elif [ "$DD_LANG" == "php" ]; then
runtime_version=$(php -v | grep -oP 'PHP \K[0-9]+\.[0-9]+\.[0-9]+')
elif [ "$DD_LANG" == "python" ]; then
runtime_version=$(python --version | grep -oP 'Python \K[0-9]+\.[0-9]+\.[0-9]+')
elif [ "$DD_LANG" == "js" ]; then
export NVM_DIR="/root/.nvm"
. "$NVM_DIR/nvm.sh"

runtime_version=$(node --version | tr -d 'v')
fi

if [ -f /etc/debian_version ] || [ "$DISTRIBUTION" = "Debian" ] || [ "$DISTRIBUTION" = "Ubuntu" ]; then
Expand Down Expand Up @@ -86,4 +92,4 @@ elif [ -f /etc/redhat-release ] || [ "$DISTRIBUTION" = "RedHat" ] || [ "$DISTRIB
echo "{'weblog_url':'$(echo $WEBLOG_URL)','runtime_version':'$(echo $runtime_version)','agent':'$(echo $agent_version)','datadog-apm-inject':'$(echo $inject_version)','datadog-apm-library-$DD_LANG': '$(echo $tracer_version)','docker':'$(docker -v || true)','datadog-installer':'$(echo $installer_version)'}"
else
echo "NO_SUPPORTED"
fi
fi
19 changes: 13 additions & 6 deletions utils/build/ssi/build_local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ while [[ "$#" -gt 0 ]]; do
case $1 in
dotnet|java|nodejs|php|python|ruby) TEST_LIBRARY="$1";;
-l|--library) TEST_LIBRARY="$2"; shift ;;
-r|--installable-runtime) INSTALLABLE_RUNTIME="$2"; shift ;;
-w|--weblog-variant) WEBLOG_VARIANT="$2"; shift ;;
-a|--arch) ARCH="$2"; shift ;;
-f|--force-build) FORCE_BUILD="$2"; shift ;;
Expand Down Expand Up @@ -64,11 +65,17 @@ do
base_image=$(echo "$row" | jq -r .base_image)
arch=$(echo "$row" | jq -r .arch)
installable_runtime=$(echo "$row" | jq -r .installable_runtime)
if [ -z "$WEBLOG_VARIANT" ] || [ "$WEBLOG_VARIANT" = "$weblog" ]; then
if [ -z "$ARCH" ] || [ "$ARCH" = "$arch" ]; then
echo "Runing test scenario for weblog [${weblog}], base_image [${base_image}], arch [${arch}], installable_runtime [${installable_runtime}], extra_args: [${extra_args}]"
./run.sh DOCKER_SSI --ssi-weblog "$weblog" --ssi-library "$TEST_LIBRARY" --ssi-base-image "$base_image" --ssi-arch "$arch" --ssi-installable-runtime "$installable_runtime" "$extra_args"
fi
fi
if [ -n "$INSTALLABLE_RUNTIME" ] && [ "$INSTALLABLE_RUNTIME" != "$installable_runtime" ]; then
continue
fi
if [ -n "$WEBLOG_VARIANT" ] && [ "$WEBLOG_VARIANT" != "$weblog" ]; then
continue
fi
if [ -n "$ARCH" ] && [ "$ARCH" != "$arch" ]; then
continue
fi

echo "Runing test scenario for weblog [${weblog}], base_image [${base_image}], arch [${arch}], installable_runtime [${installable_runtime}], extra_args: [${extra_args}]"
./run.sh DOCKER_SSI --ssi-weblog "$weblog" --ssi-library "$TEST_LIBRARY" --ssi-base-image "$base_image" --ssi-arch "$arch" --ssi-installable-runtime "$installable_runtime" "$extra_args"

done < <(echo "$matrix_json" | jq -c ".${TEST_LIBRARY}.parallel.matrix[]")
12 changes: 12 additions & 0 deletions utils/build/ssi/nodejs/js-app.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
ARG BASE_IMAGE

FROM ${BASE_IMAGE}
WORKDIR /app
COPY lib-injection/build/docker/nodejs/sample-app/ .
ENV HOME /root
EXPOSE 18080

# We need pid 1 to be bash and to properly configure nvm
# doing this via `RUN` doesn't seem to work
COPY utils/build/ssi/nodejs/run.sh /app/
CMD /app/run.sh
7 changes: 7 additions & 0 deletions utils/build/ssi/nodejs/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash
# shellcheck disable=SC1091

export NVM_DIR="/root/.nvm"
. "$NVM_DIR/nvm.sh"

node index.js
55 changes: 53 additions & 2 deletions utils/docker_ssi/docker_ssi_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,35 @@ def get_version_id(version):
raise ValueError(f"Python version {version} not supported")


class JSRuntimeInstallableVersions:
"""Node.js runtime versions that can be installed automatically"""

JS12 = RuntimeInstallableVersion("JS12", "12.22.12")
JS14 = RuntimeInstallableVersion("JS14", "14.21.3")
JS16 = RuntimeInstallableVersion("JS16", "16.20.2")
JS18 = RuntimeInstallableVersion("JS18", "18.20.5")
JS20 = RuntimeInstallableVersion("JS20", "20.18.1")
JS22 = RuntimeInstallableVersion("JS22", "22.11.0")

@staticmethod
def get_all_versions():
return [
JSRuntimeInstallableVersions.JS12,
JSRuntimeInstallableVersions.JS14,
JSRuntimeInstallableVersions.JS18,
JSRuntimeInstallableVersions.JS18,
JSRuntimeInstallableVersions.JS20,
JSRuntimeInstallableVersions.JS22,
]

@staticmethod
def get_version_id(version):
for version_check in JSRuntimeInstallableVersions.get_all_versions():
if version_check.version == version:
return version_check.version_id
raise ValueError(f"Node.js version {version} not supported")


# HERE ADD YOUR WEBLOG DEFINITION: SUPPORTED IMAGES AND INSTALABLE RUNTIME VERSIONS
# Maybe a weblog app contains preinstalled language runtime, in this case we define the weblog without runtime version
JETTY_APP = WeblogDescriptor(
Expand Down Expand Up @@ -210,9 +239,31 @@ def get_version_id(version):
[
SupportedImages().UBUNTU_22_ARM64.with_allowed_runtime_versions(
PythonRuntimeInstallableVersions.get_all_versions()
)
),
],
)

JS_APP = WeblogDescriptor(
"js-app",
"nodejs",
[
SupportedImages().UBUNTU_22_AMD64.with_allowed_runtime_versions(
JSRuntimeInstallableVersions.get_all_versions()
),
SupportedImages().UBUNTU_22_ARM64.with_allowed_runtime_versions(
JSRuntimeInstallableVersions.get_all_versions()
),
],
)

# HERE ADD YOUR WEBLOG DEFINITION TO THE LIST
ALL_WEBLOGS = [JETTY_APP, TOMCAT_APP, JAVA7_APP, WEBSPHERE_APP, JBOSS_APP, PHP_APP, PY_APP]
ALL_WEBLOGS = [
JETTY_APP,
TOMCAT_APP,
JAVA7_APP,
WEBSPHERE_APP,
JBOSS_APP,
PHP_APP,
PY_APP,
JS_APP,
]
5 changes: 4 additions & 1 deletion utils/docker_ssi/docker_ssi_matrix_utils.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
from utils.docker_ssi.docker_ssi_definitions import (
JavaRuntimeInstallableVersions,
JSRuntimeInstallableVersions,
PHPRuntimeInstallableVersions,
PythonRuntimeInstallableVersions,
)


def resolve_runtime_version(library, runtime):
""" For installable runtimes, get the version identifier. ie JAVA_11 """
"""For installable runtimes, get the version identifier. ie JAVA_11"""
if library == "java":
return JavaRuntimeInstallableVersions.get_version_id(runtime)
elif library == "php":
return PHPRuntimeInstallableVersions.get_version_id(runtime)
elif library == "python":
return PythonRuntimeInstallableVersions.get_version_id(runtime)
elif library == "nodejs":
return JSRuntimeInstallableVersions.get_version_id(runtime)

raise ValueError(f"Library {library} not supported")