Skip to content

Commit

Permalink
Add performance test scripts (#1671)
Browse files Browse the repository at this point in the history
* Add performance test scripts

Signed-off-by: Kunal Kotwani <[email protected]>

* Update agent to docker

Signed-off-by: Kunal Kotwani <[email protected]>

* Update parameter descriptions

Signed-off-by: Kunal Kotwani <[email protected]>

* Add parallel stages for performance tests, add tests

Signed-off-by: Kunal Kotwani <[email protected]>

* Update tests as per Python3.7

Signed-off-by: Kunal Kotwani <[email protected]>

* Add conditional stage for performance tests

Signed-off-by: Kunal Kotwani <[email protected]>

* Add detailed job tests for performance tests

Signed-off-by: Kunal Kotwani <[email protected]>

* Fix agent label for notifications

Signed-off-by: Kunal Kotwani <[email protected]>

* Run tests against actual Jenkins perf-test job

Signed-off-by: Kunal Kotwani <[email protected]>

* Update secure mode flag name, pythonify branch code

Signed-off-by: Kunal Kotwani <[email protected]>

* Fix notifications for perf-tests

Signed-off-by: Kunal Kotwani <[email protected]>

* Update perf-test jenkins call stack

Signed-off-by: Kunal Kotwani <[email protected]>
  • Loading branch information
kotwanikunal authored Apr 4, 2022
1 parent c6d41cf commit 8f7ffee
Show file tree
Hide file tree
Showing 17 changed files with 1,149 additions and 109 deletions.
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pytest = "*"
coverage = "~=4.5.4"
pytest-cov = "~=2.10.0"
jproperties = "~=2.1.1"
retry = "~=0.9"
sortedcontainers = "*"
cerberus = "~=1.3.4"
psutil = "~=5.8"
Expand Down
209 changes: 117 additions & 92 deletions Pipfile.lock

Large diffs are not rendered by default.

225 changes: 225 additions & 0 deletions jenkins/opensearch/perf-test.jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
lib = library(identifier: "jenkins@20211118", retriever: legacySCM(scm))

pipeline {
agent none
options {
timeout(time: 10, unit: 'HOURS')
}
environment {
AGENT_LABEL = 'Jenkins-Agent-al2-x64-c54xlarge-Docker-Host'
AGENT_IMAGE = 'opensearchstaging/ci-runner:ci-runner-centos7-v1'
BUNDLE_MANIFEST = 'bundle-manifest.yml'
JOB_NAME = 'perf-test'
}
parameters {
string(
name: 'GITHUB_TOKEN',
description: 'Github token for account access.',
trim: true
)
string(
name: 'BUNDLE_MANIFEST_URL',
description: 'The bundle manifest URL, e.g. https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/1.2.2/98/linux/x64/builds/opensearch/manifest.yml.',
trim: true
)
string(
defaultValue: 'nyc_taxis',
name: 'TEST_WORKLOAD',
description: 'The workload name from OpenSearch Benchmark Workloads for Mensor (internal client).',
trim: true
)
string(
defaultValue: '1',
name: 'TEST_ITERATIONS',
description: 'Number of times to run a workload for Mensor (internal client).',
trim: true
)
string(
defaultValue: '0',
name: 'WARMUP_ITERATIONS',
description: 'Number of times to run a workload before collecting data for Mensor (internal client).',
trim: true
)
}

stages {
stage('validate-and-set-parameters') {
agent {
docker {
label AGENT_LABEL
image AGENT_IMAGE
alwaysPull true
}
}
steps {
script {
if (BUNDLE_MANIFEST_URL == '') {
currentBuild.result = 'ABORTED'
error("Performance Tests failed to start. Missing parameter: BUNDLE_MANIFEST_URL.")
}
if (GITHUB_TOKEN == '') {
currentBuild.result = 'ABORTED'
error("Performance Tests failed to start. Missing parameter: GITHUB_TOKEN.")
}
if (TEST_ITERATIONS != null && !TEST_ITERATIONS.isInteger()) {
currentBuild.result = 'ABORTED'
error("Performance Tests failed to start. Invalid value for parameter: TEST_ITERATIONS. Value should be an integer.")
}
if (WARMUP_ITERATIONS != null && !WARMUP_ITERATIONS.isInteger()) {
currentBuild.result = 'ABORTED'
error("Performance Tests failed to start. Invalid value for parameter: WARMUP_ITERATIONS. Value should be an integer.")
}
def bundleManifestObj = downloadBuildManifest(
url: BUNDLE_MANIFEST_URL,
path: BUNDLE_MANIFEST
)
String buildId = bundleManifestObj.getArtifactBuildId()
env.BUILD_ID = buildId
env.HAS_SECURITY = bundleManifestObj.components.containsKey("security")
env.ARCHITECTURE = bundleManifestObj.getArtifactArchitecture()
echo "HAS_SECURITY: ${env.HAS_SECURITY}"
lib.jenkins.Messages.new(this).add(JOB_NAME, "Performance tests for #${BUILD_ID}")
}
}
}
stage('perf-test') {
parallel {
stage('test-with-security') {
agent {
docker {
label AGENT_LABEL
image AGENT_IMAGE
alwaysPull true
}
}
when {
expression { return env.HAS_SECURITY }
}
steps {
script {
def bundleManifestObj = downloadBuildManifest(
url: BUNDLE_MANIFEST_URL,
path: BUNDLE_MANIFEST
)
echo "BUNDLE_MANIFEST: ${BUNDLE_MANIFEST}"
echo "BUILD_ID: ${BUILD_ID}"
echo "Architecture: ${ARCHITECTURE}"

runPerfTestScript(bundleManifest: BUNDLE_MANIFEST,
buildId: BUILD_ID,
architecture: ARCHITECTURE,
insecure: false,
workload: TEST_WORKLOAD,
testIterations: TEST_ITERATIONS,
warmupIterations: WARMUP_ITERATIONS)

lib.jenkins.Messages.new(this).add(JOB_NAME,
lib.jenkins.Messages.new(this).get([JOB_NAME]) +
"\nPerformance tests with security for ${BUILD_ID} completed")
}
}
post {
success {
script {
uploadTestResults(
buildManifestFileName: BUNDLE_MANIFEST,
jobName: JOB_NAME,
buildNumber: BUILD_ID
)
}
postCleanup()
}
failure {
postCleanup()
}
aborted {
postCleanup()
}
}
}
stage('test-without-security') {
agent {
docker {
label AGENT_LABEL
image AGENT_IMAGE
alwaysPull true
}
}
steps {
script {
def bundleManifestObj = downloadBuildManifest(
url: BUNDLE_MANIFEST_URL,
path: BUNDLE_MANIFEST
)

echo "BUNDLE_MANIFEST: ${BUNDLE_MANIFEST}"
echo "BUILD_ID: ${BUILD_ID}"
echo "Architecture: ${ARCHITECTURE}"

runPerfTestScript(bundleManifest: BUNDLE_MANIFEST,
buildId: BUILD_ID,
architecture: ARCHITECTURE,
insecure: true,
workload: TEST_WORKLOAD,
testIterations: TEST_ITERATIONS,
warmupIterations: WARMUP_ITERATIONS)

lib.jenkins.Messages.new(this).add(JOB_NAME,
lib.jenkins.Messages.new(this).get([JOB_NAME]) +
"\nPerformance tests without security for ${BUILD_ID} completed")
}
}
post {
success {
script {
uploadTestResults(
buildManifestFileName: BUNDLE_MANIFEST,
jobName: JOB_NAME,
buildNumber: BUILD_ID
)
}
postCleanup()
}
failure {
postCleanup()
}
aborted {
postCleanup()
}
}
}
}
}
}

post {
success {
node(AGENT_LABEL) {
script {
def stashed = lib.jenkins.Messages.new(this).get([JOB_NAME])
publishNotification(
icon: ':white_check_mark:',
message: 'Performance Tests Successful',
extra: stashed,
credentialsId: 'INTEG_TEST_WEBHOOK',
)
postCleanup()
}
}
}
failure {
node(AGENT_LABEL) {
script {
def stashed = lib.jenkins.Messages.new(this).get([JOB_NAME])
publishNotification(
icon: ':warning:',
message: 'Failed Performance Tests',
extra: stashed,
credentialsId: 'INTEG_TEST_WEBHOOK',
)
postCleanup()
}
}
}
}
}
21 changes: 17 additions & 4 deletions src/run_perf_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import sys

import yaml
from retry.api import retry_call

from git.git_repository import GitRepository
from manifests.bundle_manifest import BundleManifest
Expand All @@ -35,6 +36,9 @@ def main():
parser.add_argument("--bundle-manifest", type=argparse.FileType("r"), help="Bundle Manifest file.", required=True)
parser.add_argument("--stack", dest="stack", help="Stack name for performance test")
parser.add_argument("--config", type=argparse.FileType("r"), help="Config file.", required=True)
parser.add_argument("--without-security", dest="insecure", action="store_true",
help="Force the security of the cluster to be disabled.",
default=False)
parser.add_argument("--keep", dest="keep", action="store_true", help="Do not delete the working temporary directory.")
parser.add_argument("--workload", default="nyc_taxis", help="Mensor (internal client) param - Workload name from OpenSeach Benchmark Workloads")
parser.add_argument("--workload-options", default="{}", help="Mensor (internal client) param - Json object with OpenSearch Benchmark arguments")
Expand All @@ -45,14 +49,23 @@ def main():
manifest = BundleManifest.from_file(args.bundle_manifest)
config = yaml.safe_load(args.config)

security = "security" in manifest.components and not args.insecure
tests_dir = os.path.join(os.getcwd(), "test-results", "perf-test", f"{'with' if security else 'without'}-security")
os.makedirs(tests_dir, exist_ok=True)

with TemporaryDirectory(keep=args.keep, chdir=True) as work_dir:
current_workspace = os.path.join(work_dir.name, "infra")
with GitRepository(get_infra_repo_url(), "main", current_workspace):
security = "security" in manifest.components
with WorkingDirectory(current_workspace):
with PerfTestCluster.create(manifest, config, args.stack, security, current_workspace) as (test_cluster_endpoint, test_cluster_port):
perf_test_suite = PerfTestSuite(manifest, test_cluster_endpoint, security, current_workspace, args)
perf_test_suite.execute()
with PerfTestCluster.create(
manifest,
config,
args.stack,
security,
current_workspace) as (test_cluster_endpoint, test_cluster_port):
perf_test_suite = PerfTestSuite(manifest, test_cluster_endpoint, security,
current_workspace, tests_dir, args)
retry_call(perf_test_suite.execute, tries=3, delay=60, backoff=2)


if __name__ == "__main__":
Expand Down
17 changes: 7 additions & 10 deletions src/test_workflow/perf_test/perf_test_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ class PerfTestSuite:
"""
Represents a performance test suite. This class runs rally test on the deployed cluster with the provided IP.
"""

def __init__(self, bundle_manifest, endpoint, security, current_workspace, args):
def __init__(self, bundle_manifest, endpoint, security, current_workspace, test_results_path, args):
self.manifest = bundle_manifest
self.work_dir = "mensor/"
self.endpoint = endpoint
Expand All @@ -18,21 +17,19 @@ def __init__(self, bundle_manifest, endpoint, security, current_workspace, args)
self.args = args
self.command = (
f"pipenv run python test_config.py -i {self.endpoint} -b {self.manifest.build.id}"
f" -a {self.manifest.build.architecture} -p {self.current_workspace}"
f" -a {self.manifest.build.architecture} -p {os.getcwd() if test_results_path is None else test_results_path}"
f" --workload {self.args.workload} --workload-options '{self.args.workload_options}'"
f" --warmup-iters {self.args.warmup_iters} --test-iters {self.args.test_iters}"
)

def execute(self):
try:
with WorkingDirectory(self.work_dir):
dir = os.getcwd()
subprocess.check_call("python3 -m pipenv install", cwd=dir, shell=True)
subprocess.check_call("pipenv install", cwd=dir, shell=True)

current_workspace = os.path.join(self.current_workspace, self.work_dir)
with WorkingDirectory(current_workspace):
subprocess.check_call("pipenv install", cwd=current_workspace, shell=True)
if self.security:
subprocess.check_call(f"{self.command} -s", cwd=dir, shell=True)
subprocess.check_call(f"{self.command} -s", cwd=current_workspace, shell=True)
else:
subprocess.check_call(f"{self.command}", cwd=dir, shell=True)
subprocess.check_call(f"{self.command}", cwd=current_workspace, shell=True)
finally:
os.chdir(self.current_workspace)
5 changes: 4 additions & 1 deletion test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ case $1 in
"bwc-test")
"$DIR/run.sh" "$DIR/src/run_bwc_test.py" "${@:2}"
;;
"perf-test")
"$DIR/run.sh" "$DIR/src/run_perf_test.py" "${@:2}"
;;
*)
echo "Invalid test suite, run ./test.sh integ-test|bwc-test."
echo "Invalid test suite, run ./test.sh integ-test|bwc-test|perf-test."
exit 1
;;
esac
Expand Down
9 changes: 9 additions & 0 deletions tests/data/perf-test-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
Description: Configuration file to store contants required to run rally for performance test
Constants:
Repository: https://github.com/opensearch-project/
SecurityGroupId: test-security
VpcId: test-vpc
AccountId: 123456
Region: eu-east-1
Role: test-role-name
Loading

0 comments on commit 8f7ffee

Please sign in to comment.