From 61ddc44e962520eab02c4cd224f9481b1636becb Mon Sep 17 00:00:00 2001 From: Michael Spencer Date: Tue, 7 Oct 2025 11:59:08 -0700 Subject: [PATCH 1/7] Reset branch --- k6/generic/generic_utils.js | 60 +++++++++++- .../load_steve_k8s_pagination_filter_sort.js | 89 ++++++++++++++++++ ...ad_steve_k8s_pagination_storage_classes.js | 91 +++++++++++++++++++ .../load_steve_new_pagination_filter_sort.js | 90 ++++++++++++++++++ ...ad_steve_new_pagination_storage_classes.js | 90 ++++++++++++++++++ 5 files changed, 419 insertions(+), 1 deletion(-) create mode 100644 k6/vai/load_steve_k8s_pagination_filter_sort.js create mode 100644 k6/vai/load_steve_k8s_pagination_storage_classes.js create mode 100644 k6/vai/load_steve_new_pagination_filter_sort.js create mode 100644 k6/vai/load_steve_new_pagination_storage_classes.js diff --git a/k6/generic/generic_utils.js b/k6/generic/generic_utils.js index b4e4ac32..00e50487 100644 --- a/k6/generic/generic_utils.js +++ b/k6/generic/generic_utils.js @@ -31,7 +31,7 @@ export function createConfigMaps(baseUrl, cookies, data, clusterId, namespace, i // Required params: baseurl, cookies, data, clusterId, namespace, iter export function createSecrets(baseUrl, cookies, data, clusterId, namespace, iter) { - const name = `test-secrets-${iter}` + const name = `test-secret-${iter}` const url = clusterId === "local"? `${baseUrl}/v1/secrets` : @@ -58,6 +58,38 @@ export function createSecrets(baseUrl, cookies, data, clusterId, namespace, iter }) } +// Create Secrets with Labels +// Required params: baseurl, coookies, data, cluster, namespace, iter +export function createSecretsWithLabels(baseUrl, cookies, data, clusterId, namespace, iter) { + const name = `test-secret-${iter}` + const key_1 = "cow" + const value = "geeko" + + const url = clusterId === "local"? + `${baseUrl}/v1/secrets` : + `${baseUrl}/k8s/clusters/${clusterId}/v1/secrets` + + const res = http.post(`${url}`, + JSON.stringify({ + "metadata": { + "name": name, + "namespace": namespace, + "labels": {[key_1]:value} + }, + "data": {"data": data}, + "type": "opaque" + }), + { cookies: cookies } + ) + + sleep(0.1) + if (res.status != 201) { + console.log(res) + } + check(res, { + '/v1/secrets returns status 201': (r) => r.status === 201, + }) +} // Required params: baseurl, cookies, clusterId, namespace, iter export function createDeployments(baseUrl, cookies, clusterId, namespace, iter) { @@ -137,3 +169,29 @@ export function getPathBasename(filePath) { // Extract the substring after the last slash return filePath.substring(lastSlashIndex + 1); } + + +export function createStorageClasses(baseUrl, cookies, namespace, iter){ + + const name = `test-storage-class-${iter}` + + const create = http.post(`${baseUrl}/v1/storage.k8s.io.storageclasses`, JSON.stringify({ + "type": "storage.k8s.io.storageclass", + "metadata": { + "name": name, + "namespace": namespace + }, + "provisioner": "driver.longhorn.io", + }), + {cookies: cookies} + ) + + sleep(0.1) + if (res.status != 201) { + console.log(res) + } + check(create, { + '/v1/storage.k8s.io.storageclasses returns status 201': (r) => r.status === 201, + }) + + } \ No newline at end of file diff --git a/k6/vai/load_steve_k8s_pagination_filter_sort.js b/k6/vai/load_steve_k8s_pagination_filter_sort.js new file mode 100644 index 00000000..f75cb01c --- /dev/null +++ b/k6/vai/load_steve_k8s_pagination_filter_sort.js @@ -0,0 +1,89 @@ +import { check, fail } from 'k6'; +import http from 'k6/http'; +import { Gauge } from 'k6/metrics'; + +// Parameters +const vus = __ENV.VUS +const perVuIterations = __ENV.PER_VU_ITERATIONS +const baseUrl = __ENV.BASE_URL +const username = __ENV.USERNAME +const password = __ENV.PASSWORD +const cluster = __ENV.CLUSTER + +// Option setting +export const options = { + insecureSkipTLSVerify: true, + + scenarios: { + list : { + executor: 'per-vu-iterations', + exec: 'list', + vus: vus, + iterations: perVuIterations, + maxDuration: '24h', + } + }, + thresholds: { + checks: ['rate>0.99'] + } +} + +// Custom metrics +const variableMetric = new Gauge('test_variable') + +// Test functions, in order of execution + +export function setup() { + // log in + const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ + "description": "UI session", + "responseType": "cookie", + "username": username, + "password": password + })) + + check(res, { + '/v3-public/localProviders/local?action=login returns status 200': (r) => r.status === 200, + }) + + return http.cookieJar().cookiesForURL(res.url) +} + +export function list(cookies) { + const url = cluster === "local"? + `${baseUrl}/v1/configmaps` : + `${baseUrl}/k8s/clusters/${cluster}/v1/configmaps` + + let revision = null + let continueToken = null + while (true) { + const fullUrl = url + "?limit=100" + "&sort=metadata.name&filter=metadata.labels.blue=green" + + (revision != null ? "&revision=" + revision : "") + + (continueToken != null ? "&continue=" + continueToken : "") + + const res = http.get(fullUrl, {cookies: cookies}) + + check(res, { + '/v1/configmaps returns status 200': (r) => r.status === 200, + }) + + try { + const body = JSON.parse(res.body) + if (body === undefined || body.continue === undefined) { + break + } + if (revision == null) { + revision = body.revision + } + continueToken = body.continue + } + catch (e){ + if (e instanceof SyntaxError) { + fail("Response body does not parse as JSON: " + res.body) + } + throw e + } + } + + variableMetric.add(Number(__ENV.CONFIG_MAP_COUNT)) +} diff --git a/k6/vai/load_steve_k8s_pagination_storage_classes.js b/k6/vai/load_steve_k8s_pagination_storage_classes.js new file mode 100644 index 00000000..f239831c --- /dev/null +++ b/k6/vai/load_steve_k8s_pagination_storage_classes.js @@ -0,0 +1,91 @@ +import { check, fail } from 'k6'; +import * as k8s from './k8s.js' +import http from 'k6/http'; +import { Gauge } from 'k6/metrics'; + +// Parameters +const vus = __ENV.VUS +const perVuIterations = __ENV.PER_VU_ITERATIONS +const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const baseUrl = kubeconfig["url"].replace(":6443", "") +const username = __ENV.USERNAME +const password = __ENV.PASSWORD +const cluster = __ENV.CLUSTER + +// Option setting +export const options = { + insecureSkipTLSVerify: true, + + scenarios: { + list : { + executor: 'per-vu-iterations', + exec: 'list', + vus: vus, + iterations: perVuIterations, + maxDuration: '24h', + } + }, + thresholds: { + checks: ['rate>0.99'] + } +} + +// Custom metrics +const variableMetric = new Gauge('test_variable') + +// Test functions, in order of execution + +export function setup() { + // log in + const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ + "description": "UI session", + "responseType": "cookie", + "username": username, + "password": password + })) + + check(res, { + '/v3-public/localProviders/local?action=login returns status 200': (r) => r.status === 200, + }) + + return http.cookieJar().cookiesForURL(res.url) +} + +export function list(cookies) { + const url = cluster === "local"? + `${baseUrl}/v1/storage.k8s.io.storageclasses` : + `${baseUrl}/k8s/clusters/${cluster}/v1/storage.k8s.io.storageclasses` + + let revision = null + let continueToken = null + while (true) { + const fullUrl = url + "?limit=100" + + (revision != null ? "&revision=" + revision : "") + + (continueToken != null ? "&continue=" + continueToken : "") + + const res = http.get(fullUrl, {cookies: cookies}) + + check(res, { + '/v1/storage.k8s.io.storageclasses returns status 200': (r) => r.status === 200, + }) + + try { + const body = JSON.parse(res.body) + if (body === undefined || body.continue === undefined) { + break + } + if (revision == null) { + revision = body.revision + } + continueToken = body.continue + } + catch (e){ + if (e instanceof SyntaxError) { + fail("Response body does not parse as JSON: " + res.body) + } + throw e + } + } + + variableMetric.add(Number(__ENV.COUNT)) +} diff --git a/k6/vai/load_steve_new_pagination_filter_sort.js b/k6/vai/load_steve_new_pagination_filter_sort.js new file mode 100644 index 00000000..889986ed --- /dev/null +++ b/k6/vai/load_steve_new_pagination_filter_sort.js @@ -0,0 +1,90 @@ +import { check, fail } from 'k6'; +import * as k8s from './k8s.js' +import http from 'k6/http'; +import { Gauge } from 'k6/metrics'; + +// Parameters +const vus = __ENV.VUS +const perVuIterations = __ENV.PER_VU_ITERATIONS +const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const baseUrl = kubeconfig["url"].replace(":6443", "") +const username = __ENV.USERNAME +const password = __ENV.PASSWORD +const cluster = __ENV.CLUSTER + +// Option setting +export const options = { + insecureSkipTLSVerify: true, + + scenarios: { + list : { + executor: 'per-vu-iterations', + exec: 'list', + vus: vus, + iterations: perVuIterations, + maxDuration: '24h', + } + }, + thresholds: { + checks: ['rate>0.99'] + } +} + +// Custom metrics +const variableMetric = new Gauge('test_variable') + +// Test functions, in order of execution + +export function setup() { + // log in + const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ + "description": "UI session", + "responseType": "cookie", + "username": username, + "password": password + })) + + check(res, { + '/v3-public/localProviders/local?action=login returns status 200': (r) => r.status === 200, + }) + + return http.cookieJar().cookiesForURL(res.url) +} + +export function list(cookies) { + const url = cluster === "local"? + `${baseUrl}/v1/configmaps` : + `${baseUrl}/k8s/clusters/${cluster}/v1/configmaps` + + let i = 1 + let revision = null + while (true) { + const fullUrl = url + "?pagesize=100&page=" + i + "&sort=metadata.name&filter=metadata.labels.blue=green" + + (revision != null ? "&revision=" + revision : "") + + const res = http.get(fullUrl, {cookies: cookies}) + + check(res, { + '/v1/configmaps returns status 200': (r) => r.status === 200, + }) + + try { + const body = JSON.parse(res.body) + if (body === undefined || body.data === undefined || body.data.length === 0) { + break + } + if (revision == null) { + revision = body.revision + } + i = i + 1 + } + catch (e){ + if (e instanceof SyntaxError) { + fail("Response body does not parse as JSON: " + res.body) + } + throw e + } + } + + variableMetric.add(Number(__ENV.COUNT)) +} diff --git a/k6/vai/load_steve_new_pagination_storage_classes.js b/k6/vai/load_steve_new_pagination_storage_classes.js new file mode 100644 index 00000000..f6f6ce55 --- /dev/null +++ b/k6/vai/load_steve_new_pagination_storage_classes.js @@ -0,0 +1,90 @@ +import { check, fail } from 'k6'; +import * as k8s from './k8s.js' +import http from 'k6/http'; +import { Gauge } from 'k6/metrics'; + +// Parameters +const vus = __ENV.VUS +const perVuIterations = __ENV.PER_VU_ITERATIONS +const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const baseUrl = kubeconfig["url"].replace(":6443", "") +const username = __ENV.USERNAME +const password = __ENV.PASSWORD +const cluster = __ENV.CLUSTER + +// Option setting +export const options = { + insecureSkipTLSVerify: true, + + scenarios: { + list : { + executor: 'per-vu-iterations', + exec: 'list', + vus: vus, + iterations: perVuIterations, + maxDuration: '24h', + } + }, + thresholds: { + checks: ['rate>0.99'] + } +} + +// Custom metrics +const variableMetric = new Gauge('test_variable') + +// Test functions, in order of execution + +export function setup() { + // log in + const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ + "description": "UI session", + "responseType": "cookie", + "username": username, + "password": password + })) + + check(res, { + '/v3-public/localProviders/local?action=login returns status 200': (r) => r.status === 200, + }) + + return http.cookieJar().cookiesForURL(res.url) +} + +export function list(cookies) { + const url = cluster === "local"? + `${baseUrl}/v1/storage.k8s.io.storageclasses` : + `${baseUrl}/k8s/clusters/${cluster}/v1/storage.k8s.io.storageclasses` + + let i = 1 + let revision = null + while (true) { + const fullUrl = url + "?pagesize=100&page=" + i + + (revision != null ? "&revision=" + revision : "") + + const res = http.get(fullUrl, {cookies: cookies}) + + check(res, { + '/v1/storage.k8s.io.storageclasses returns status 200': (r) => r.status === 200, + }) + + try { + const body = JSON.parse(res.body) + if (body === undefined || body.data === undefined || body.data.length === 0) { + break + } + if (revision == null) { + revision = body.revision + } + i = i + 1 + } + catch (e){ + if (e instanceof SyntaxError) { + fail("Response body does not parse as JSON: " + res.body) + } + throw e + } + } + + variableMetric.add(Number(__ENV.COUNT)) +} From ea87c814f5fde31ef32e1db64878ad3e8b4e79f6 Mon Sep 17 00:00:00 2001 From: Michael Spencer Date: Tue, 4 Nov 2025 16:40:10 -0800 Subject: [PATCH 2/7] Updates for tests, fixes for storage class creation --- k6/generic/create_storage_classes.js | 65 +++++++++++ k6/generic/generic_utils.js | 23 ++-- k6/vai/.env | 28 +++++ .../load_steve_k8s_pagination_filter_sort.js | 108 +++++++++++++----- ...ad_steve_k8s_pagination_storage_classes.js | 100 ++++++++++++---- .../load_steve_new_pagination_filter_sort.js | 90 --------------- ...ad_steve_new_pagination_storage_classes.js | 90 --------------- 7 files changed, 263 insertions(+), 241 deletions(-) create mode 100644 k6/generic/create_storage_classes.js create mode 100644 k6/vai/.env delete mode 100644 k6/vai/load_steve_new_pagination_filter_sort.js delete mode 100644 k6/vai/load_steve_new_pagination_storage_classes.js diff --git a/k6/generic/create_storage_classes.js b/k6/generic/create_storage_classes.js new file mode 100644 index 00000000..fa084dac --- /dev/null +++ b/k6/generic/create_storage_classes.js @@ -0,0 +1,65 @@ +import encoding from 'k6/encoding'; +import exec from 'k6/execution'; +import { createStorageClasses } from '../generic/generic_utils.js'; +import { login, getCookies } from '../rancher/rancher_utils.js'; +import {fail} from 'k6'; +import * as k8s from '../generic/k8s.js' +import { customHandleSummary } from '../generic/k6_utils.js'; + +// Parameters +const namespace = "scalability-test" +const storageClassCount =Number(__ENV.STORAGECLASS_COUNT) +const clusterId = "local" +const vus = __ENV.VUS || 2 + +// Option setting +const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const baseUrl = kubeconfig["url"].replace(":6443", "") +const username = __ENV.USERNAME +const password = __ENV.PASSWORD + +export const handleSummary = customHandleSummary; + +export const options = { + insecureSkipTLSVerify: true, + tlsAuth: [ + { + cert: kubeconfig["cert"], + key: kubeconfig["key"], + }, + ], + + setupTimeout: '8h', + + scenarios: { + createResourcesStorageClasses: { + executor: 'shared-iterations', + exec: 'createResourcesStorageClasses', + vus: vus, + iterations: storageClassCount, + maxDuration: '1h', + }, + }, + thresholds: { + http_req_failed: ['rate<=0.01'], // http errors should be less than 1% + http_req_duration: ['p(99)<=500'], // 99% of requests should be below 500ms + checks: ['rate>0.99'], // the rate of successful checks should be higher than 99% + } +}; + +export function setup() { + + // log in + if (!login(baseUrl, {}, username, password)) { + fail(`could not login into cluster`) + } + const cookies = getCookies(baseUrl) + + return cookies +} + +// create storage classes +export function createResourcesStorageClasses(cookies) { + const iter = exec.scenario.iterationInTest + createStorageClasses(baseUrl, cookies, clusterId, iter) +} diff --git a/k6/generic/generic_utils.js b/k6/generic/generic_utils.js index 00e50487..000cbc02 100644 --- a/k6/generic/generic_utils.js +++ b/k6/generic/generic_utils.js @@ -171,17 +171,23 @@ export function getPathBasename(filePath) { } -export function createStorageClasses(baseUrl, cookies, namespace, iter){ +export function createStorageClasses(baseUrl, cookies, clusterId, iter){ const name = `test-storage-class-${iter}` - const create = http.post(`${baseUrl}/v1/storage.k8s.io.storageclasses`, JSON.stringify({ + const url = clusterId === "local"? + `${baseUrl}/v1/storage.k8s.io.storageclasses` : + `${baseUrl}/k8s/clusters/${clusterId}/v1/storage.k8s.io.storageclasses` + + + const res = http.post( `${url}`, JSON.stringify({ "type": "storage.k8s.io.storageclass", - "metadata": { - "name": name, - "namespace": namespace - }, + "metadata": {"name": name}, + "parameters": { "numberOfReplicas": "3", "staleReplicaTimeout": "2880" }, "provisioner": "driver.longhorn.io", + "allowVolumeExpansion": true, + "reclaimPolicy": "Delete", + "volumeBindingMode": "Immediate" }), {cookies: cookies} ) @@ -190,8 +196,7 @@ export function createStorageClasses(baseUrl, cookies, namespace, iter){ if (res.status != 201) { console.log(res) } - check(create, { + check(res, { '/v1/storage.k8s.io.storageclasses returns status 201': (r) => r.status === 201, }) - - } \ No newline at end of file +} diff --git a/k6/vai/.env b/k6/vai/.env new file mode 100644 index 00000000..37d81cf6 --- /dev/null +++ b/k6/vai/.env @@ -0,0 +1,28 @@ +export VUS=1 +export PER_VU_ITERATIONS=30 +export ITERATIONS=1 +export BASE_URL="https://ms.qa.rancher.space:6443" +export bootstrapPassword="XRi&Vfw8_Qr7*YVh1DE" +export USERNAME="admin" +export PASSOWRD="xQTh4EcXRW9S9kzf" +export TOKEN="token-bvdkn:z6mk5twnjg94s8vrjvb4fc5fzqdbmjp4cstb224sbk9278clgcxz5l" +export KUBECONFIG="/Users/mspencer/Desktop/ms.yaml" +export CONTEXT="default" +export URL_SUFFIX="&exclude=metadata.managedFields" +export PAGINATION_STYLE="k8s" +export FIRST_PAGE_ONLY="false" +export RESOURCE="configmaps" +export ROLE_COUNT=1 +export USER_COUNT=10 +export TOKEN_COUNT=0 +export PROJECT_COUNT=100 +export CONFIG_MAP_COUNT=0 +export CONFIGMAP_COUNT=15000 +export STORAGECLASS_COUNT=250 +export SECRET_COUNT=1000 +export DEPLOYMENT_COUNT=10 +export K6_NO_USAGE_REPORT=true +export ACE_ENABLED=false +export PAUSE_SECONDS=5 +export CLUSTER="local" + diff --git a/k6/vai/load_steve_k8s_pagination_filter_sort.js b/k6/vai/load_steve_k8s_pagination_filter_sort.js index f75cb01c..cf70e31c 100644 --- a/k6/vai/load_steve_k8s_pagination_filter_sort.js +++ b/k6/vai/load_steve_k8s_pagination_filter_sort.js @@ -1,14 +1,24 @@ -import { check, fail } from 'k6'; +import { check, fail, sleep } from 'k6'; +import * as k8s from '../generic/k8s.js' +import { login, getCookies } from '../rancher/rancher_utils.js'; import http from 'k6/http'; -import { Gauge } from 'k6/metrics'; +import { customHandleSummary } from '../generic/k6_utils.js'; // Parameters const vus = __ENV.VUS const perVuIterations = __ENV.PER_VU_ITERATIONS -const baseUrl = __ENV.BASE_URL +const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const baseUrl = kubeconfig["url"].replace(":6443", "") const username = __ENV.USERNAME const password = __ENV.PASSWORD -const cluster = __ENV.CLUSTER +const clusterId = __ENV.CLUSTER || "local" +const paginationStyle = __ENV.PAGINATION_STYLE || "k8s" +const pauseSeconds = parseFloat(__ENV.PAUSE_SECONDS || 0.0) + +const key = __ENV.KEY || "blue" +const value = __ENV.VALUE || "green" + +export const handleSummary = customHandleSummary; // Option setting export const options = { @@ -28,36 +38,41 @@ export const options = { } } -// Custom metrics -const variableMetric = new Gauge('test_variable') - -// Test functions, in order of execution +// Simulate a pause after a click - on average pauseSeconds, +/- a random quantity up to 50% +function pause() { + sleep(pauseSeconds + (Math.random() - 0.5) * 2 * pauseSeconds / 2) +} export function setup() { - // log in - const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ - "description": "UI session", - "responseType": "cookie", - "username": username, - "password": password - })) - - check(res, { - '/v3-public/localProviders/local?action=login returns status 200': (r) => r.status === 200, - }) - - return http.cookieJar().cookiesForURL(res.url) + if (!login(baseUrl, {}, username, password)) { + fail(`could not login into cluster`) + } + const cookies = getCookies(baseUrl) + + return cookies } -export function list(cookies) { - const url = cluster === "local"? - `${baseUrl}/v1/configmaps` : - `${baseUrl}/k8s/clusters/${cluster}/v1/configmaps` +export function list(cookies, filters = "") { + if (paginationStyle === "k8s") { + listFilterSort(cookies) + } + else if (paginationStyle === "steve") { + listFilterSortVai(cookies) + } + else { + fail("Invalid PAGINATION_STYLE value: " + paginationStyle) + } +} + +export function listFilterSort(cookies) { + const url = clusterId === "local"? + `${baseUrl}/v1/secrets` : + `${baseUrl}/k8s/clusters/${clusterId}/v1/secrets` let revision = null let continueToken = null while (true) { - const fullUrl = url + "?limit=100" + "&sort=metadata.name&filter=metadata.labels.blue=green" + + const fullUrl = url + "?limit=100" + "&sort=metadata.name&filter=metadata.labels." + key + "=" + value (revision != null ? "&revision=" + revision : "") + (continueToken != null ? "&continue=" + continueToken : "") @@ -85,5 +100,44 @@ export function list(cookies) { } } - variableMetric.add(Number(__ENV.CONFIG_MAP_COUNT)) + pause() +} + + +export function listFilterSortVai(cookies) { + const url = clusterId === "local"? + `${baseUrl}/v1/configmaps` : + `${baseUrl}/k8s/clusters/${clusterId}/v1/secrets` + + let i = 1 + let revision = null + while (true) { + const fullUrl = url + "?pagesize=100&page=" + i + "&sort=metadata.name&filter=metadata.labels." + key + "=" + value + (revision != null ? "&revision=" + revision : "") + + const res = http.get(fullUrl, {cookies: cookies}) + + check(res, { + '/v1/configmaps returns status 200': (r) => r.status === 200, + }) + + try { + const body = JSON.parse(res.body) + if (body === undefined || body.data === undefined || body.data.length === 0) { + break + } + if (revision == null) { + revision = body.revision + } + i = i + 1 + } + catch (e){ + if (e instanceof SyntaxError) { + fail("Response body does not parse as JSON: " + res.body) + } + throw e + } + } + + pause() } diff --git a/k6/vai/load_steve_k8s_pagination_storage_classes.js b/k6/vai/load_steve_k8s_pagination_storage_classes.js index f239831c..712da1b7 100644 --- a/k6/vai/load_steve_k8s_pagination_storage_classes.js +++ b/k6/vai/load_steve_k8s_pagination_storage_classes.js @@ -1,7 +1,9 @@ -import { check, fail } from 'k6'; -import * as k8s from './k8s.js' +import { check, fail, sleep } from 'k6'; +import * as k8s from '../generic/k8s.js' +import { login, getCookies } from '../rancher/rancher_utils.js'; import http from 'k6/http'; -import { Gauge } from 'k6/metrics'; +import { customHandleSummary } from '../generic/k6_utils.js'; + // Parameters const vus = __ENV.VUS @@ -10,7 +12,11 @@ const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) const baseUrl = kubeconfig["url"].replace(":6443", "") const username = __ENV.USERNAME const password = __ENV.PASSWORD -const cluster = __ENV.CLUSTER +const clusterId = __ENV.CLUSTER || "local" +const paginationStyle = __ENV.PAGINATION_STYLE || "k8s" +const pauseSeconds = parseFloat(__ENV.PAUSE_SECONDS || 0.0) + +export const handleSummary = customHandleSummary; // Option setting export const options = { @@ -30,31 +36,36 @@ export const options = { } } -// Custom metrics -const variableMetric = new Gauge('test_variable') - -// Test functions, in order of execution +// Simulate a pause after a click - on average pauseSeconds, +/- a random quantity up to 50% +function pause() { + sleep(pauseSeconds + (Math.random() - 0.5) * 2 * pauseSeconds / 2) +} export function setup() { - // log in - const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ - "description": "UI session", - "responseType": "cookie", - "username": username, - "password": password - })) - - check(res, { - '/v3-public/localProviders/local?action=login returns status 200': (r) => r.status === 200, - }) - - return http.cookieJar().cookiesForURL(res.url) + if (!login(baseUrl, {}, username, password)) { + fail(`could not login into cluster`) + } + const cookies = getCookies(baseUrl) + + return cookies +} + +export function list(cookies, filters = "") { + if (paginationStyle === "k8s") { + listStorageClasses(cookies) + } + else if (paginationStyle === "steve") { + listStorageClassesVai(cookies) + } + else { + fail("Invalid PAGINATION_STYLE value: " + paginationStyle) + } } -export function list(cookies) { - const url = cluster === "local"? +export function listStorageClasses(cookies) { + const url = clusterId === "local"? `${baseUrl}/v1/storage.k8s.io.storageclasses` : - `${baseUrl}/k8s/clusters/${cluster}/v1/storage.k8s.io.storageclasses` + `${baseUrl}/k8s/clusters/${clusterId}/v1/storage.k8s.io.storageclasses` let revision = null let continueToken = null @@ -87,5 +98,44 @@ export function list(cookies) { } } - variableMetric.add(Number(__ENV.COUNT)) + pause() } + +export function listStorageClassesVai(cookies) { + const url = clusterId === "local"? + `${baseUrl}/v1/storage.k8s.io.storageclasses` : + `${baseUrl}/k8s/clusters/${clusterId}/v1/storage.k8s.io.storageclasses` + + let i = 1 + let revision = null + while (true) { + const fullUrl = url + "?pagesize=100&page=" + i + + (revision != null ? "&revision=" + revision : "") + + const res = http.get(fullUrl, {cookies: cookies}) + + check(res, { + '/v1/storage.k8s.io.storageclasses returns status 200': (r) => r.status === 200, + }) + + try { + const body = JSON.parse(res.body) + if (body === undefined || body.data === undefined || body.data.length === 0) { + break + } + if (revision == null) { + revision = body.revision + } + i = i + 1 + } + catch (e){ + if (e instanceof SyntaxError) { + fail("Response body does not parse as JSON: " + res.body) + } + throw e + } + } + + pause() +} + diff --git a/k6/vai/load_steve_new_pagination_filter_sort.js b/k6/vai/load_steve_new_pagination_filter_sort.js deleted file mode 100644 index 889986ed..00000000 --- a/k6/vai/load_steve_new_pagination_filter_sort.js +++ /dev/null @@ -1,90 +0,0 @@ -import { check, fail } from 'k6'; -import * as k8s from './k8s.js' -import http from 'k6/http'; -import { Gauge } from 'k6/metrics'; - -// Parameters -const vus = __ENV.VUS -const perVuIterations = __ENV.PER_VU_ITERATIONS -const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) -const baseUrl = kubeconfig["url"].replace(":6443", "") -const username = __ENV.USERNAME -const password = __ENV.PASSWORD -const cluster = __ENV.CLUSTER - -// Option setting -export const options = { - insecureSkipTLSVerify: true, - - scenarios: { - list : { - executor: 'per-vu-iterations', - exec: 'list', - vus: vus, - iterations: perVuIterations, - maxDuration: '24h', - } - }, - thresholds: { - checks: ['rate>0.99'] - } -} - -// Custom metrics -const variableMetric = new Gauge('test_variable') - -// Test functions, in order of execution - -export function setup() { - // log in - const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ - "description": "UI session", - "responseType": "cookie", - "username": username, - "password": password - })) - - check(res, { - '/v3-public/localProviders/local?action=login returns status 200': (r) => r.status === 200, - }) - - return http.cookieJar().cookiesForURL(res.url) -} - -export function list(cookies) { - const url = cluster === "local"? - `${baseUrl}/v1/configmaps` : - `${baseUrl}/k8s/clusters/${cluster}/v1/configmaps` - - let i = 1 - let revision = null - while (true) { - const fullUrl = url + "?pagesize=100&page=" + i + "&sort=metadata.name&filter=metadata.labels.blue=green" + - (revision != null ? "&revision=" + revision : "") - - const res = http.get(fullUrl, {cookies: cookies}) - - check(res, { - '/v1/configmaps returns status 200': (r) => r.status === 200, - }) - - try { - const body = JSON.parse(res.body) - if (body === undefined || body.data === undefined || body.data.length === 0) { - break - } - if (revision == null) { - revision = body.revision - } - i = i + 1 - } - catch (e){ - if (e instanceof SyntaxError) { - fail("Response body does not parse as JSON: " + res.body) - } - throw e - } - } - - variableMetric.add(Number(__ENV.COUNT)) -} diff --git a/k6/vai/load_steve_new_pagination_storage_classes.js b/k6/vai/load_steve_new_pagination_storage_classes.js deleted file mode 100644 index f6f6ce55..00000000 --- a/k6/vai/load_steve_new_pagination_storage_classes.js +++ /dev/null @@ -1,90 +0,0 @@ -import { check, fail } from 'k6'; -import * as k8s from './k8s.js' -import http from 'k6/http'; -import { Gauge } from 'k6/metrics'; - -// Parameters -const vus = __ENV.VUS -const perVuIterations = __ENV.PER_VU_ITERATIONS -const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) -const baseUrl = kubeconfig["url"].replace(":6443", "") -const username = __ENV.USERNAME -const password = __ENV.PASSWORD -const cluster = __ENV.CLUSTER - -// Option setting -export const options = { - insecureSkipTLSVerify: true, - - scenarios: { - list : { - executor: 'per-vu-iterations', - exec: 'list', - vus: vus, - iterations: perVuIterations, - maxDuration: '24h', - } - }, - thresholds: { - checks: ['rate>0.99'] - } -} - -// Custom metrics -const variableMetric = new Gauge('test_variable') - -// Test functions, in order of execution - -export function setup() { - // log in - const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ - "description": "UI session", - "responseType": "cookie", - "username": username, - "password": password - })) - - check(res, { - '/v3-public/localProviders/local?action=login returns status 200': (r) => r.status === 200, - }) - - return http.cookieJar().cookiesForURL(res.url) -} - -export function list(cookies) { - const url = cluster === "local"? - `${baseUrl}/v1/storage.k8s.io.storageclasses` : - `${baseUrl}/k8s/clusters/${cluster}/v1/storage.k8s.io.storageclasses` - - let i = 1 - let revision = null - while (true) { - const fullUrl = url + "?pagesize=100&page=" + i + - (revision != null ? "&revision=" + revision : "") - - const res = http.get(fullUrl, {cookies: cookies}) - - check(res, { - '/v1/storage.k8s.io.storageclasses returns status 200': (r) => r.status === 200, - }) - - try { - const body = JSON.parse(res.body) - if (body === undefined || body.data === undefined || body.data.length === 0) { - break - } - if (revision == null) { - revision = body.revision - } - i = i + 1 - } - catch (e){ - if (e instanceof SyntaxError) { - fail("Response body does not parse as JSON: " + res.body) - } - throw e - } - } - - variableMetric.add(Number(__ENV.COUNT)) -} From 58776a8c7358dda1b7c8efc064e9d993ff65ef75 Mon Sep 17 00:00:00 2001 From: Michael Spencer Date: Thu, 6 Nov 2025 08:40:58 -0800 Subject: [PATCH 3/7] refactor tests, add resource creations --- k6/vai/.env | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 k6/vai/.env diff --git a/k6/vai/.env b/k6/vai/.env deleted file mode 100644 index 37d81cf6..00000000 --- a/k6/vai/.env +++ /dev/null @@ -1,28 +0,0 @@ -export VUS=1 -export PER_VU_ITERATIONS=30 -export ITERATIONS=1 -export BASE_URL="https://ms.qa.rancher.space:6443" -export bootstrapPassword="XRi&Vfw8_Qr7*YVh1DE" -export USERNAME="admin" -export PASSOWRD="xQTh4EcXRW9S9kzf" -export TOKEN="token-bvdkn:z6mk5twnjg94s8vrjvb4fc5fzqdbmjp4cstb224sbk9278clgcxz5l" -export KUBECONFIG="/Users/mspencer/Desktop/ms.yaml" -export CONTEXT="default" -export URL_SUFFIX="&exclude=metadata.managedFields" -export PAGINATION_STYLE="k8s" -export FIRST_PAGE_ONLY="false" -export RESOURCE="configmaps" -export ROLE_COUNT=1 -export USER_COUNT=10 -export TOKEN_COUNT=0 -export PROJECT_COUNT=100 -export CONFIG_MAP_COUNT=0 -export CONFIGMAP_COUNT=15000 -export STORAGECLASS_COUNT=250 -export SECRET_COUNT=1000 -export DEPLOYMENT_COUNT=10 -export K6_NO_USAGE_REPORT=true -export ACE_ENABLED=false -export PAUSE_SECONDS=5 -export CLUSTER="local" - From 3023eb4859bafcfa3367a5176eb036404b85c144 Mon Sep 17 00:00:00 2001 From: Michael Spencer Date: Thu, 6 Nov 2025 08:45:58 -0800 Subject: [PATCH 4/7] test updates --- k6/generic/create_secrets_with_labels.js | 89 ++++++++++++++++++++++++ k6/generic/generic_utils.js | 8 +-- 2 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 k6/generic/create_secrets_with_labels.js diff --git a/k6/generic/create_secrets_with_labels.js b/k6/generic/create_secrets_with_labels.js new file mode 100644 index 00000000..739ed06a --- /dev/null +++ b/k6/generic/create_secrets_with_labels.js @@ -0,0 +1,89 @@ +import encoding from 'k6/encoding'; +import exec from 'k6/execution'; +import { createSecretsWithLabels, createStorageClasses } from '../generic/generic_utils.js'; +import { login, getCookies } from '../rancher/rancher_utils.js'; +import {fail} from 'k6'; +import * as k8s from '../generic/k8s.js' +import { customHandleSummary } from '../generic/k6_utils.js'; + +// Parameters +const namespace = "scalability-test" +const secretCount = Number(__ENV.SECRET_COUNT) +const secretData = encoding.b64encode("a".repeat(10*1024)) +const key = __ENV.KEY || "blue" +const value = __ENV.VALUE || "green" +const clusterId = __ENV.CLUSTER || "local" +const vus = __ENV.VUS || 2 + +// Option setting +const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const baseUrl = kubeconfig["url"].replace(":6443", "") +const username = __ENV.USERNAME +const password = __ENV.PASSWORD + +export const handleSummary = customHandleSummary; + +export const options = { + insecureSkipTLSVerify: true, + tlsAuth: [ + { + cert: kubeconfig["cert"], + key: kubeconfig["key"], + }, + ], + + setupTimeout: '8h', + + scenarios: { + createResourceSecretsWithLabels: { + executor: 'shared-iterations', + exec: 'createResourceSecretsWithLabels', + vus: vus, + iterations: secretCount, + maxDuration: '1h', + }, + }, + thresholds: { + http_req_failed: ['rate<=0.01'], // http errors should be less than 1% + http_req_duration: ['p(99)<=500'], // 99% of requests should be below 500ms + checks: ['rate>0.99'], // the rate of successful checks should be higher than 99% + } +}; + +export function setup() { + + // log in + if (!login(baseUrl, {}, username, password)) { + fail(`could not login into cluster`) + } + const cookies = getCookies(baseUrl) + + const del_url = clusterId === "local"? + `${baseUrl}/v1/namespaces/${namespace}` : + `${baseUrl}/k8s/clusters/${clusterId}/v1/namespaces/${namespace}` + + // delete leftovers, if any + k8s.del(`${del_url}`) + + // create empty namespace + const body = { + "metadata": { + "name": namespace, + + }, + } + + const create_url = clusterId === "local"? + `${baseUrl}/v1/namespaces` : + `${baseUrl}/k8s/clusters/${clusterId}/v1/namespaces` + + k8s.create(`${create_url}`, body) + + return cookies +} + +// create storage classes +export function createResourceSecretsWithLabels(cookies) { + const iter = exec.scenario.iterationInTest + createSecretsWithLabels(baseUrl, cookies, secretData, clusterId, namespace, iter, key, value) +} \ No newline at end of file diff --git a/k6/generic/generic_utils.js b/k6/generic/generic_utils.js index 000cbc02..28459fea 100644 --- a/k6/generic/generic_utils.js +++ b/k6/generic/generic_utils.js @@ -60,10 +60,10 @@ export function createSecrets(baseUrl, cookies, data, clusterId, namespace, iter // Create Secrets with Labels // Required params: baseurl, coookies, data, cluster, namespace, iter -export function createSecretsWithLabels(baseUrl, cookies, data, clusterId, namespace, iter) { +export function createSecretsWithLabels(baseUrl, cookies, data, clusterId, namespace, iter, key, value) { const name = `test-secret-${iter}` - const key_1 = "cow" - const value = "geeko" + const key_1 = key + const value_1 = value const url = clusterId === "local"? `${baseUrl}/v1/secrets` : @@ -74,7 +74,7 @@ export function createSecretsWithLabels(baseUrl, cookies, data, clusterId, names "metadata": { "name": name, "namespace": namespace, - "labels": {[key_1]:value} + "labels": {[key_1]:value_1} }, "data": {"data": data}, "type": "opaque" From 52034ced93eba50608ee7b3bd9f6dbc6adc7f572 Mon Sep 17 00:00:00 2001 From: Michael Spencer Date: Fri, 7 Nov 2025 10:30:38 -0800 Subject: [PATCH 5/7] fixes for filter sort test --- k6/vai/load_steve_k8s_pagination_filter_sort.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/k6/vai/load_steve_k8s_pagination_filter_sort.js b/k6/vai/load_steve_k8s_pagination_filter_sort.js index cf70e31c..8e1b07a5 100644 --- a/k6/vai/load_steve_k8s_pagination_filter_sort.js +++ b/k6/vai/load_steve_k8s_pagination_filter_sort.js @@ -72,14 +72,14 @@ export function listFilterSort(cookies) { let revision = null let continueToken = null while (true) { - const fullUrl = url + "?limit=100" + "&sort=metadata.name&filter=metadata.labels." + key + "=" + value + const fullUrl = url + "?limit=100" + "&sort=metadata.name&filter=metadata.labels." + key + "=" + value + (revision != null ? "&revision=" + revision : "") + (continueToken != null ? "&continue=" + continueToken : "") const res = http.get(fullUrl, {cookies: cookies}) check(res, { - '/v1/configmaps returns status 200': (r) => r.status === 200, + '/v1/secrets returns status 200': (r) => r.status === 200, }) try { @@ -106,19 +106,19 @@ export function listFilterSort(cookies) { export function listFilterSortVai(cookies) { const url = clusterId === "local"? - `${baseUrl}/v1/configmaps` : + `${baseUrl}/v1/secrets` : `${baseUrl}/k8s/clusters/${clusterId}/v1/secrets` let i = 1 let revision = null while (true) { - const fullUrl = url + "?pagesize=100&page=" + i + "&sort=metadata.name&filter=metadata.labels." + key + "=" + value + const fullUrl = url + "?pagesize=100&page=" + i + "&sort=metadata.name&filter=metadata.labels." + key + "=" + value + (revision != null ? "&revision=" + revision : "") const res = http.get(fullUrl, {cookies: cookies}) check(res, { - '/v1/configmaps returns status 200': (r) => r.status === 200, + '/v1/secrets returns status 200': (r) => r.status === 200, }) try { From c2ecff901ef792c4d74b8d566bdef1560ec0f53c Mon Sep 17 00:00:00 2001 From: Michael Spencer Date: Mon, 24 Nov 2025 19:25:27 -0800 Subject: [PATCH 6/7] Fixes for test runs --- k6/generic/create_secrets_with_labels.js | 53 ++++++++++++------------ k6/generic/create_storage_classes.js | 34 +++++++++++---- k6/generic/k8s.js | 2 +- 3 files changed, 54 insertions(+), 35 deletions(-) diff --git a/k6/generic/create_secrets_with_labels.js b/k6/generic/create_secrets_with_labels.js index 739ed06a..8ca2a4c6 100644 --- a/k6/generic/create_secrets_with_labels.js +++ b/k6/generic/create_secrets_with_labels.js @@ -3,11 +3,13 @@ import exec from 'k6/execution'; import { createSecretsWithLabels, createStorageClasses } from '../generic/generic_utils.js'; import { login, getCookies } from '../rancher/rancher_utils.js'; import {fail} from 'k6'; +import {loadKubeconfig} from '../generic/k8s.js' import * as k8s from '../generic/k8s.js' import { customHandleSummary } from '../generic/k6_utils.js'; // Parameters -const namespace = "scalability-test" +const namespace = "longhorn-system" +const token = __ENV.TOKEN const secretCount = Number(__ENV.SECRET_COUNT) const secretData = encoding.b64encode("a".repeat(10*1024)) const key = __ENV.KEY || "blue" @@ -16,7 +18,7 @@ const clusterId = __ENV.CLUSTER || "local" const vus = __ENV.VUS || 2 // Option setting -const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const kubeconfig = loadKubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) const baseUrl = kubeconfig["url"].replace(":6443", "") const username = __ENV.USERNAME const password = __ENV.PASSWORD @@ -51,35 +53,32 @@ export const options = { }; export function setup() { + // if session cookie was specified, save it + if (token) { + return { R_SESS: token } + } - // log in - if (!login(baseUrl, {}, username, password)) { - fail(`could not login into cluster`) - } - const cookies = getCookies(baseUrl) + // if credentials were specified, log in + if (username && password) { + const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ + "description": "UI session", + "responseType": "cookie", + "username": username, + "password": password + })) + + check(res, { + 'logging in returns status 200': (r) => r.status === 200, + }) - const del_url = clusterId === "local"? - `${baseUrl}/v1/namespaces/${namespace}` : - `${baseUrl}/k8s/clusters/${clusterId}/v1/namespaces/${namespace}` - - // delete leftovers, if any - k8s.del(`${del_url}`) - - // create empty namespace - const body = { - "metadata": { - "name": namespace, - - }, - } - - const create_url = clusterId === "local"? - `${baseUrl}/v1/namespaces` : - `${baseUrl}/k8s/clusters/${clusterId}/v1/namespaces` - - k8s.create(`${create_url}`, body) + pause() + + const cookies = http.cookieJar().cookiesForURL(res.url) return cookies + } + + return {} } // create storage classes diff --git a/k6/generic/create_storage_classes.js b/k6/generic/create_storage_classes.js index fa084dac..836aec74 100644 --- a/k6/generic/create_storage_classes.js +++ b/k6/generic/create_storage_classes.js @@ -4,16 +4,18 @@ import { createStorageClasses } from '../generic/generic_utils.js'; import { login, getCookies } from '../rancher/rancher_utils.js'; import {fail} from 'k6'; import * as k8s from '../generic/k8s.js' +import {loadKubeconfig} from '../generic/k8s.js' import { customHandleSummary } from '../generic/k6_utils.js'; // Parameters -const namespace = "scalability-test" +//const namespace = "longhorn-system" +const token = __ENV.TOKEN const storageClassCount =Number(__ENV.STORAGECLASS_COUNT) const clusterId = "local" const vus = __ENV.VUS || 2 // Option setting -const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const kubeconfig = loadKubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) const baseUrl = kubeconfig["url"].replace(":6443", "") const username = __ENV.USERNAME const password = __ENV.PASSWORD @@ -48,14 +50,32 @@ export const options = { }; export function setup() { + // if session cookie was specified, save it + if (token) { + return { R_SESS: token } + } - // log in - if (!login(baseUrl, {}, username, password)) { - fail(`could not login into cluster`) - } - const cookies = getCookies(baseUrl) + // if credentials were specified, log in + if (username && password) { + const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ + "description": "UI session", + "responseType": "cookie", + "username": username, + "password": password + })) + + check(res, { + 'logging in returns status 200': (r) => r.status === 200, + }) + + pause() + + const cookies = http.cookieJar().cookiesForURL(res.url) return cookies + } + + return {} } // create storage classes diff --git a/k6/generic/k8s.js b/k6/generic/k8s.js index c90da682..27998194 100644 --- a/k6/generic/k8s.js +++ b/k6/generic/k8s.js @@ -7,7 +7,7 @@ import { URL } from '../lib/url-1.0.0.js'; const timeout = '3600s' -function loadKubeconfig(file, contextName) { +export function loadKubeconfig(file, contextName) { const config = YAML.load(open(file)); console.debug(`Loading kubeconfig from '${file}' using context '${contextName}'.`); From f3e30acd8134c5f7dbc04bdf7734571eefae6bb1 Mon Sep 17 00:00:00 2001 From: Michael Spencer Date: Mon, 24 Nov 2025 19:28:34 -0800 Subject: [PATCH 7/7] Chagnes for test --- k6/generic/create_secrets_with_labels.js | 2 +- .../load_steve_k8s_pagination_filter_sort.js | 32 ++++++++++++++++--- ...ad_steve_k8s_pagination_storage_classes.js | 32 ++++++++++++++++--- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/k6/generic/create_secrets_with_labels.js b/k6/generic/create_secrets_with_labels.js index 8ca2a4c6..4b60b358 100644 --- a/k6/generic/create_secrets_with_labels.js +++ b/k6/generic/create_secrets_with_labels.js @@ -8,7 +8,7 @@ import * as k8s from '../generic/k8s.js' import { customHandleSummary } from '../generic/k6_utils.js'; // Parameters -const namespace = "longhorn-system" +const namespace = "" const token = __ENV.TOKEN const secretCount = Number(__ENV.SECRET_COUNT) const secretData = encoding.b64encode("a".repeat(10*1024)) diff --git a/k6/vai/load_steve_k8s_pagination_filter_sort.js b/k6/vai/load_steve_k8s_pagination_filter_sort.js index 8e1b07a5..988f15dd 100644 --- a/k6/vai/load_steve_k8s_pagination_filter_sort.js +++ b/k6/vai/load_steve_k8s_pagination_filter_sort.js @@ -3,11 +3,13 @@ import * as k8s from '../generic/k8s.js' import { login, getCookies } from '../rancher/rancher_utils.js'; import http from 'k6/http'; import { customHandleSummary } from '../generic/k6_utils.js'; +import {loadKubeconfig} from '../generic/k8s.js' // Parameters const vus = __ENV.VUS const perVuIterations = __ENV.PER_VU_ITERATIONS -const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const token = __ENV.TOKEN +const kubeconfig = loadKubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) const baseUrl = kubeconfig["url"].replace(":6443", "") const username = __ENV.USERNAME const password = __ENV.PASSWORD @@ -44,12 +46,32 @@ function pause() { } export function setup() { - if (!login(baseUrl, {}, username, password)) { - fail(`could not login into cluster`) - } - const cookies = getCookies(baseUrl) + // if session cookie was specified, save it + if (token) { + return { R_SESS: token } + } + + // if credentials were specified, log in + if (username && password) { + const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ + "description": "UI session", + "responseType": "cookie", + "username": username, + "password": password + })) + + check(res, { + 'logging in returns status 200': (r) => r.status === 200, + }) + + pause() + + const cookies = http.cookieJar().cookiesForURL(res.url) return cookies + } + + return {} } export function list(cookies, filters = "") { diff --git a/k6/vai/load_steve_k8s_pagination_storage_classes.js b/k6/vai/load_steve_k8s_pagination_storage_classes.js index 712da1b7..7ed99f1e 100644 --- a/k6/vai/load_steve_k8s_pagination_storage_classes.js +++ b/k6/vai/load_steve_k8s_pagination_storage_classes.js @@ -3,12 +3,14 @@ import * as k8s from '../generic/k8s.js' import { login, getCookies } from '../rancher/rancher_utils.js'; import http from 'k6/http'; import { customHandleSummary } from '../generic/k6_utils.js'; +import {loadKubeconfig} from '../generic/k8s.js' // Parameters const vus = __ENV.VUS const perVuIterations = __ENV.PER_VU_ITERATIONS -const kubeconfig = k8s.kubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) +const token = __ENV.TOKEN +const kubeconfig = loadKubeconfig(__ENV.KUBECONFIG, __ENV.CONTEXT) const baseUrl = kubeconfig["url"].replace(":6443", "") const username = __ENV.USERNAME const password = __ENV.PASSWORD @@ -42,12 +44,32 @@ function pause() { } export function setup() { - if (!login(baseUrl, {}, username, password)) { - fail(`could not login into cluster`) - } - const cookies = getCookies(baseUrl) + // if session cookie was specified, save it + if (token) { + return { R_SESS: token } + } + + // if credentials were specified, log in + if (username && password) { + const res = http.post(`${baseUrl}/v3-public/localProviders/local?action=login`, JSON.stringify({ + "description": "UI session", + "responseType": "cookie", + "username": username, + "password": password + })) + + check(res, { + 'logging in returns status 200': (r) => r.status === 200, + }) + + pause() + + const cookies = http.cookieJar().cookiesForURL(res.url) return cookies + } + + return {} } export function list(cookies, filters = "") {