load
Directory actions
More options
Directory actions
More options
load
Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
parent directory.. | ||||
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Performance Testing for StackRox"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"This document is an idea of executable documentation. It can be used with VS Code and `Jupyter` plugin. It's pretty handy because showing `Outline` allows faster document navigation."
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Pre-requirement\n",
"\n",
"There are few unconventional tools used in this notebook\n",
"\n",
"1. `rg` - ripgrep is replacement for `grep`. Installation instructions can be found here: https://github.com/BurntSushi/ripgrep#installation\n",
"2. `yq` - is command line YAML processor. Installation instructions can be found here: https://github.com/mikefarah/yq#install"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Quick start"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Install `k6` tool. To install it, please check the instructions on the project page: https://k6.io/docs/get-started/installation. Below is an example for MacOS."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"brew install k6"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Install required NodeJS development libraries."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"npm install"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Run test directly**"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"export ROX_ADMIN_PASSWORD=$(cat ../../deploy/k8s/central-deploy/password)\n",
"export HOST=\"https://localhost:8000\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"npm run test -- --quiet --out csv=k6-test-result.csv"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After that you can check `k6-test-result.csv` for results."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Run test in docker or kubernetes**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Build a docker image with the following command:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"docker build . -t stackrox/performance-test-runner:latest"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Create a namespace and deploy `performance-test-runner`. The next command uses `yq` to set a password in the YAML file. To install it, please check the instructions on the project page: https://github.com/mikefarah/yq"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"export KUBECONFIG=./artifacts/kubeconfig\n",
"\n",
"export ROX_ADMIN_PASSWORD=$(cat ../../deploy/k8s/central-deploy/password)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"kubectl create namespace performance-test"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"yq e '.spec.template.spec.containers[0].env[0].value = \"'\"${ROX_ADMIN_PASSWORD}\"'\"' ./deploy/test-runner-deployment.yaml | kubectl apply -f -"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To check if everything is working, you can run the following command."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"kubectl get pods --namespace performance-test"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Collecting results\n",
"\n",
"Get logs because results will be output to stdout inside the container."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"export KUBECONFIG=./artifacts/kubeconfig"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"kubectl logs --namespace performance-test test-runner -c test-runner > ./test-runner-result_2022-11-07_19-12.log"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Extract the results of testing in a CSV file. The following line uses the `rg` command. To install it, please check the instructions on the project page: https://github.com/BurntSushi/ripgrep"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"rg 'sac_user=|extra_tags' ./test-runner-result_2022-11-07_19-12.log > ./test-runner-result_2022-11-07_19-12.log.csv"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After that, this file can be imported into some spreadsheet for further processing of the results."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1. Simplest option is to create Google Sheets.\n",
"2. Copy the content of the `.csv` file and paste into the sheet. You will get a pop-up to split a column into multiple columns. By selecting that, multiple columns will be populated with test result data.\n",
"3. From the menu, select `Insert -> Pivot table`. A dialog will automatically select the whole sheet range which we want. Select to create a pivot table on a new sheet.\n",
"4. On the new sheet in the pivot table options, select the following:\n",
" - For rows: `url` and `extra_tags`. Disable `Show totals`.\n",
" - For columns: `metric_name`. Disable `Show totals`.\n",
" - For values: `metric_value`. You can select `MEDIAN` or `AVERAGE` function.\n",
" - For the filter, you can disable everything and enable only `http_req_waiting`. That metric represents how long a request waits for a server response. It does not include sending and receiving times.\n",
"5. Have fun!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### How to create a new test group"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We first need HAR export from requests generated with our browser to create a new test group. The best is to use Firefox because Firefox will export only filtered requests in the `networking` tab. After that, you can execute a conversion from the HAR file into a JavaScript file."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"npm run har-to-k6 -- ~/Downloads/new-test-group.har --output ./groups/awesomeNewPage.js"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After that, some manual steps should be done:\n",
"1. Remove comments above `import`.\n",
"2. Remove the `options` constant.\n",
"3. Replace function declaration to accept 3 arguments. i.e. `export function awesomeNewPage(host, headers, tags)`.\n",
"4. Remove the `response` variable. Declaration and usage of it.\n",
"5. Replace all objects with the `headers` property with the following object `{ headers, tags }`.\n",
"6. Change URLs in to use the `host` variable. i.e. `'https://localhost:8001/api/graphql?opname=cvesCount'` should become `` `${host}/api/graphql?opname=cvesCount` ``.\n",
"7. Remove `sleep` at the end of the function and also its `import`.\n",
"\n",
"The next step is to include the group in a test. i.e. to add a group into the `tests/testSacScopes.js` test, we should do the following.\n",
"1. Import the group into a test file. i.e. `import { awesomeNewPage } from '../groups/awesomeNewPage.js';`\n",
"2. Add function call in `runAllGroups`. i.e. `awesomeNewPage(__ENV.HOST, header, tags);`\n",
"\n",
"With that new group is created and added to the test. And after that, we can build a docker image and run it. You can take a look at **Quick start** for instructions."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### How to fetch logs from a GKE cluster"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Set your `cluster_name` and correct `timestamp`(s) in the logs query below."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"# Query - time is in UTC\n",
"read -r -d '' GC_LOGS_QUERY <<- EOQ\n",
" resource.type=\"k8s_container\"\n",
" labels.k8s-pod/app=\"test-runner\"\n",
" resource.labels.project_id=\"srox-temp-dev-test\"\n",
" resource.labels.location=\"us-central1-a\"\n",
" resource.labels.cluster_name=\"mt-0711\"\n",
" resource.labels.namespace_name=\"performance-test\"\n",
" resource.labels.container_name=\"test-runner\"\n",
" timestamp > \"2022-11-07T20:00:00Z\"\n",
" timestamp < \"2022-11-07T21:00:00Z\"\n",
" severity>=DEFAULT\n",
"EOQ\n",
"\n",
"gcloud logging read \"${GC_LOGS_QUERY}\" --format='csv(textPayload)' --order='asc' > test-runner-result_2022-11-07_21-00.log"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"This file will contain quotes for every line and also extra new lines. That should be cleaned up.\n",
"\n",
"The next command is for MacOS `sed` command. It will remove new lines and quotes around each row."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"cat test-runner-result_2022-11-07_21-00.log | sed -e ':a' -e 'N' -e '$!ba' -e 's/\"\\n\"//g' | sed 's/\"//g' | rg 'sac_user=|extra_tags' > test-runner-result_2022-11-07_21-00.log.csv"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Development"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To check linting and formatting you can run the following commands:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"npm run format:check\n",
"npm run lint:check"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And to automatically fix them, you can run the following commands:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"vscode": {
"languageId": "shellscript"
}
},
"outputs": [],
"source": [
"npm run format:fix\n",
"npm run lint:fix"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Bash",
"language": "bash",
"name": "bash"
},
"language_info": {
"codemirror_mode": "shell",
"file_extension": ".sh",
"mimetype": "text/x-sh",
"name": "bash"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "949777d72b0d2535278d3dc13498b2535136f6dfe0678499012e853ee9abcab1"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}