harness-mcp-v2 3.2.19 → 3.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -75
- package/build/client/harness-client.d.ts.map +1 -1
- package/build/client/harness-client.js +32 -6
- package/build/client/harness-client.js.map +1 -1
- package/build/config.d.ts +10 -0
- package/build/config.d.ts.map +1 -1
- package/build/config.js +15 -0
- package/build/config.js.map +1 -1
- package/build/data/schemas/v0/pipeline.d.ts.map +1 -1
- package/build/data/schemas/v0/pipeline.js +1388 -580
- package/build/data/schemas/v0/pipeline.js.map +1 -1
- package/build/data/schemas/v0/template.d.ts.map +1 -1
- package/build/data/schemas/v0/template.js +1142 -166
- package/build/data/schemas/v0/template.js.map +1 -1
- package/build/data/schemas/v1/pipeline.d.ts.map +1 -1
- package/build/data/schemas/v1/pipeline.js +302 -90
- package/build/data/schemas/v1/pipeline.js.map +1 -1
- package/build/data/schemas/v1/template.d.ts.map +1 -1
- package/build/data/schemas/v1/template.js +708 -488
- package/build/data/schemas/v1/template.js.map +1 -1
- package/build/prompts/deploy-ai-agent.d.ts +3 -0
- package/build/prompts/deploy-ai-agent.d.ts.map +1 -0
- package/build/prompts/deploy-ai-agent.js +300 -0
- package/build/prompts/deploy-ai-agent.js.map +1 -0
- package/build/prompts/feature-flag-rollout.d.ts.map +1 -1
- package/build/prompts/feature-flag-rollout.js +19 -8
- package/build/prompts/feature-flag-rollout.js.map +1 -1
- package/build/prompts/index.d.ts.map +1 -1
- package/build/prompts/index.js +2 -0
- package/build/prompts/index.js.map +1 -1
- package/build/registry/extractors.d.ts +87 -10
- package/build/registry/extractors.d.ts.map +1 -1
- package/build/registry/extractors.js +426 -26
- package/build/registry/extractors.js.map +1 -1
- package/build/registry/index.d.ts.map +1 -1
- package/build/registry/index.js +34 -15
- package/build/registry/index.js.map +1 -1
- package/build/registry/scope-utils.d.ts +45 -0
- package/build/registry/scope-utils.d.ts.map +1 -1
- package/build/registry/scope-utils.js +78 -0
- package/build/registry/scope-utils.js.map +1 -1
- package/build/registry/toolsets/chaos-descriptions.d.ts +72 -20
- package/build/registry/toolsets/chaos-descriptions.d.ts.map +1 -1
- package/build/registry/toolsets/chaos-descriptions.js +435 -140
- package/build/registry/toolsets/chaos-descriptions.js.map +1 -1
- package/build/registry/toolsets/chaos.d.ts.map +1 -1
- package/build/registry/toolsets/chaos.js +967 -193
- package/build/registry/toolsets/chaos.js.map +1 -1
- package/build/registry/toolsets/feature-flags.d.ts.map +1 -1
- package/build/registry/toolsets/feature-flags.js +888 -85
- package/build/registry/toolsets/feature-flags.js.map +1 -1
- package/build/registry/toolsets/governance.d.ts.map +1 -1
- package/build/registry/toolsets/governance.js +4 -0
- package/build/registry/toolsets/governance.js.map +1 -1
- package/build/registry/toolsets/iacm.d.ts.map +1 -1
- package/build/registry/toolsets/iacm.js +787 -11
- package/build/registry/toolsets/iacm.js.map +1 -1
- package/build/registry/toolsets/infrastructure.d.ts.map +1 -1
- package/build/registry/toolsets/infrastructure.js +30 -5
- package/build/registry/toolsets/infrastructure.js.map +1 -1
- package/build/registry/toolsets/pipelines.d.ts.map +1 -1
- package/build/registry/toolsets/pipelines.js +208 -5
- package/build/registry/toolsets/pipelines.js.map +1 -1
- package/build/registry/toolsets/release-management.d.ts +8 -0
- package/build/registry/toolsets/release-management.d.ts.map +1 -0
- package/build/registry/toolsets/release-management.js +783 -0
- package/build/registry/toolsets/release-management.js.map +1 -0
- package/build/registry/toolsets/sto.d.ts.map +1 -1
- package/build/registry/toolsets/sto.js +93 -17
- package/build/registry/toolsets/sto.js.map +1 -1
- package/build/registry/types.d.ts +52 -4
- package/build/registry/types.d.ts.map +1 -1
- package/build/resources/harness-schema.d.ts.map +1 -1
- package/build/resources/harness-schema.js +2 -1
- package/build/resources/harness-schema.js.map +1 -1
- package/build/tools/entity-schema/live.d.ts +6 -5
- package/build/tools/entity-schema/live.d.ts.map +1 -1
- package/build/tools/entity-schema/live.js +114 -10
- package/build/tools/entity-schema/live.js.map +1 -1
- package/build/tools/entity-schema/types.d.ts +7 -1
- package/build/tools/entity-schema/types.d.ts.map +1 -1
- package/build/tools/harness-create.d.ts.map +1 -1
- package/build/tools/harness-create.js +5 -1
- package/build/tools/harness-create.js.map +1 -1
- package/build/tools/harness-delete.d.ts.map +1 -1
- package/build/tools/harness-delete.js +5 -1
- package/build/tools/harness-delete.js.map +1 -1
- package/build/tools/harness-execute.d.ts.map +1 -1
- package/build/tools/harness-execute.js +15 -9
- package/build/tools/harness-execute.js.map +1 -1
- package/build/tools/harness-get.d.ts.map +1 -1
- package/build/tools/harness-get.js +5 -1
- package/build/tools/harness-get.js.map +1 -1
- package/build/tools/harness-list.d.ts.map +1 -1
- package/build/tools/harness-list.js +18 -2
- package/build/tools/harness-list.js.map +1 -1
- package/build/tools/harness-schema.d.ts +2 -1
- package/build/tools/harness-schema.d.ts.map +1 -1
- package/build/tools/harness-schema.js +10 -8
- package/build/tools/harness-schema.js.map +1 -1
- package/build/tools/harness-update.d.ts.map +1 -1
- package/build/tools/harness-update.js +5 -1
- package/build/tools/harness-update.js.map +1 -1
- package/build/tools/index.js +1 -1
- package/build/tools/index.js.map +1 -1
- package/build/utils/url-parser.d.ts +2 -0
- package/build/utils/url-parser.d.ts.map +1 -1
- package/build/utils/url-parser.js +55 -0
- package/build/utils/url-parser.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -94,43 +94,131 @@ Workflow: list templates → get_variables to discover required inputs → creat
|
|
|
94
94
|
Supports list, get, delete, plus execute actions: list_revisions, get_variables, get_yaml, compare_revisions, and create_from_template.`;
|
|
95
95
|
export const descChaosExperimentVariable = `Variables for a chaos experiment. List variables to discover required runtime inputs before running an experiment.`;
|
|
96
96
|
export const descChaosInfrastructure = `Linux/machine infrastructure registered for chaos experiments and load testing. For Kubernetes infrastructure, use chaos_k8s_infrastructure. Supports list.`;
|
|
97
|
+
export const descChaosService = `Chaos Service (Service Management) — a logical service onboarded into Harness Chaos Engineering with an associated Service Discovery agent, environment, infrastructure, and probe associations. Distinct from harness_service (CD service) and from chaos_loadtest. Supports list, get, create, update, and delete.`;
|
|
98
|
+
export const descChaosServiceEnvironmentIds = `Filter by one or more environment identifiers. Comma-separated string for multiple values (e.g. "prodEnv,stagingEnv"). Matches the chaos service's environmentId exactly.`;
|
|
99
|
+
export const descChaosServiceInfrastructureIds = `Filter by one or more chaos infrastructure identifiers, each in "<environment_id>/<infrastructure_id>" form. Comma-separated string for multiple values (e.g. "env1/infra1,env2/infra2"). IMPORTANT: the 'infrastructureId' field returned by chaos_service list/get is the BARE infra ID only (the environment prefix is stripped server-side before it is returned) — do NOT pass that value alone. Build the filter value by combining that same response's 'environmentId' + "/" + 'infrastructureId'.`;
|
|
100
|
+
export const descChaosServiceTags = `Filter by tags. Comma-separated string; matches services that carry ALL of the listed tags.`;
|
|
101
|
+
export const descChaosServiceIncludeAllScope = `When true, include chaos services from all descendant scopes (org + all projects when scoped at org, or account + all orgs/projects when scoped at account). Defaults to false (strict scope match).`;
|
|
102
|
+
export const descChaosServiceProbeIds = `Filter by one or more probe identities associated with the chaos service. Comma-separated string for multiple values.`;
|
|
103
|
+
export const descChaosServiceOnboardingIdFilter = `Filter by the onboarding batch identifier the chaos service was created under (set during bulk/discovery onboarding).`;
|
|
104
|
+
export const descChaosServiceIdentity = `Chaos service identity (slug). Use the 'identity' field returned by chaos_service list.`;
|
|
105
|
+
export const descChaosServiceSearch = `Search chaos services by name or identity (case-insensitive regex).`;
|
|
106
|
+
export const descListChaosServices = `List chaos services in the given account/org/project scope. Supports pagination (page, limit; default limit 15, max 100), search, sort (sortField: name|lastUpdated|experimentName|lastExecuted with sortAscending), tag filter, and filters by environmentIds / infrastructureIds. Set include_all_scope=true to include descendant scopes.`;
|
|
107
|
+
export const descGetChaosService = `Get a single chaos service by its identity slug within the given account/org/project scope.`;
|
|
108
|
+
export const descDeleteChaosService = `Delete a chaos service by its identity slug within the given account/org/project scope. Soft-deletes the service record and purges its probe mapping associations in a single transaction. Destructive and not reversible via API. Returns { success, correlationID } on 200; does not return the deleted resource.`;
|
|
109
|
+
export const descListChaosServiceExperimentRuns = `List the experiment runs in which this chaos service was executed (service→run linkage resolved via execution nodes). Supports pagination (page, limit), search, sort (sortField: name|lastUpdated with sortAscending), and filters by infra_ids / statuses / step_types. Set include_all_scope=true to include descendant scopes.`;
|
|
110
|
+
export const descListChaosServiceLoadTests = `List the load tests whose serviceReferences include this chaos service. Supports pagination (page, limit), search, sort, and filters by tool_type / environment_ids / infra_ids / tags. Set include_all_scope=true to include descendant scopes.`;
|
|
111
|
+
export const descCreateChaosService = `Onboard (create) a chaos service. This is a GUIDED, ORDERED workflow — do NOT skip ahead or invent identifiers; each step depends on the selection made in the previous one. Do NOT advance to the next step until the current step's selection is made, and NEVER call harness_create(chaos_service) until every step below is resolved and the user has confirmed.
|
|
112
|
+
|
|
113
|
+
STEP 1 — Select a Discovery Agent (REQUIRED FIRST; gate: do not continue without a chosen agent).
|
|
114
|
+
Call harness_list(resource_type='discovered_agent', org_id, project_id). Show each agent's name, identity, serviceCount, and installationType. Ask the user to pick one.
|
|
115
|
+
From the chosen agent capture: agent_id = agent.identity; environment_id = agent.environmentIdentifier. For SD Kubernetes agents set infrastructure_id = agent.identity (BARE, not env-prefixed) and infrastructure_type = "KubernetesV2".
|
|
116
|
+
|
|
117
|
+
STEP 2 — Select the Service to onboard (REQUIRED, only after STEP 1; gate: do not continue without a chosen service).
|
|
118
|
+
2a. (Optional namespace narrowing) harness_list(resource_type='discovered_namespace', agent_identity=<agent.identity>, environment_id=<environment_id>, all=true). Ask the user to pick a namespace, or skip to list all services.
|
|
119
|
+
2b. harness_list(resource_type='discovered_service', agent_identity=<agent.identity>, environment_id=<environment_id>, compact=false[, namespace=<picked namespace>]). For each service show: name; namespace = spec.kubernetes.namespace; IP = spec.kubernetes.service.clusterIP (fallback spec.ip[0]); port = spec.kubernetes.service.ports[0].port (fallback spec.port[0]). Ask the user to pick a service.
|
|
120
|
+
Capture external_service_id = <selected discovered service>.id.
|
|
121
|
+
|
|
122
|
+
STEP 3 — Configure Metadata (REQUIRED, only after STEP 2).
|
|
123
|
+
Ask the user for name (REQUIRED), description (optional), and tags (optional). Derive identity as a slug of name unless the user supplies one. identity must be unique in scope — create fails on a duplicate identity or a duplicate external_service_id.
|
|
124
|
+
|
|
125
|
+
STEP 4 — Associate Probes (REQUIRED DECISION, only after STEP 3).
|
|
126
|
+
Explicitly ask the user: attach one or more health-check probes now, or create the service with no probes? Do not assume.
|
|
127
|
+
- If none: probes = [].
|
|
128
|
+
- If attaching: harness_list(resource_type='chaos_probe', infra_type='KubernetesV2'[, entity_type='httpProbe'|'cmdProbe'|'datadogProbe'|... to filter by probe type]). For EACH probe the user selects, read its inputs[] array (from the list item, or harness_get chaos_probe). For every input, prompt the user for a value — MANDATORY when required=true — and REPLACE the placeholder value "<+input>" with the user's value while keeping the rest of the input object (name, path, category, type, reference, ...) unchanged. Build probes = [{ probeId: <probe.identity>, inputs: [<full input objects with the user's values>] }, ...].
|
|
129
|
+
|
|
130
|
+
STEP 5 — Create. Only now call harness_create(resource_type='chaos_service', org_id, project_id, body={ identity, name, description?, tags?, external_service_id, agent_id, environment_id, infrastructure_id, infrastructure_type, probes }). The server re-resolves serviceType and namespace from external_service_id and stores infrastructureId as "<environment_id>/<infrastructure_id>". Returns the full ChaosServiceResponse on 200.
|
|
131
|
+
|
|
132
|
+
Never fabricate external_service_id, agent_id, or probe inputs — always source them from the discovered_agent / discovered_service / chaos_probe responses above.`;
|
|
133
|
+
export const descBodyChaosServiceCreate = `Chaos service create body. Required: identity, name, external_service_id, agent_id, environment_id, infrastructure_id. Optional: description, tags, infrastructure_type, onboarding_id, probes.`;
|
|
134
|
+
export const descChaosServiceName = `Human-readable name for the chaos service. Required.`;
|
|
135
|
+
export const descChaosServiceDescription = `Optional free-form description for the chaos service.`;
|
|
136
|
+
export const descChaosServiceTagsBody = `Optional tags for the chaos service. Accepts a JSON array of strings or a comma-separated string; normalised to string[] before sending.`;
|
|
137
|
+
export const descChaosServiceExternalServiceId = `External service ID (maps to externalServiceId). Required. This is the 'id' field of the chosen record from discovered_service list (STEP 2 of create) — NOT the service name. The server treats it as authoritative and re-resolves the service type and namespace from it, so it must reference a real discovered service under the same agent + environment.`;
|
|
138
|
+
export const descChaosServiceAgentId = `Service Discovery agent identity (maps to agentId). Required. Use the 'identity' field of the agent chosen from discovered_agent list (STEP 1 of create). The agent's environmentIdentifier becomes environment_id, and for SD Kubernetes agents its identity is also the bare infrastructure_id.`;
|
|
139
|
+
export const descChaosServiceEnvironmentId = `Harness environment identifier the service lives in (maps to environmentId). Required.`;
|
|
140
|
+
export const descChaosServiceInfrastructureId = `Chaos infrastructure identifier (maps to infrastructureId). Required. Pass the BARE infra id (NOT env-prefixed) — for SD-onboarded Kubernetes this equals the Discovery agent's identity. The server stores it as "<environment_id>/<infrastructure_id>", so do not pre-prefix it yourself.`;
|
|
141
|
+
export const descChaosServiceInfrastructureType = `Infrastructure type of the underlying chaos infra. Enum: Kubernetes | KubernetesV2 | Windows | Linux | CloudFoundry | Container. Use KubernetesV2 for Service Discovery agents (the modern SD-based Kubernetes chaos infrastructure) — this is the value for services onboarded via the discovered_agent/discovered_service flow. Optional; values are the canonical PascalCase forms.`;
|
|
142
|
+
export const descChaosServiceOnboardingId = `Optional onboarding batch identifier — set when this service is created as part of a multi-service onboarding flow so downstream tools can correlate the batch.`;
|
|
143
|
+
export const descChaosServiceProbes = `Optional probe associations. Array of { probeId, inputs? }. probeId is the identity of an existing chaos probe (from chaos_probe list, filter infra_type='KubernetesV2'). inputs is the probe's own inputs[] array (read it from the chaos_probe list item or harness_get chaos_probe): pass each input object back intact (name, path, category, type, reference, required, ...) but REPLACE its placeholder value "<+input>" with the user-supplied value. Values for inputs marked required=true are mandatory. Do not fabricate or drop input objects — the backend uses each input's path/category to place the value.`;
|
|
144
|
+
export const descChaosServiceProbesUpdate = `Required — full replacement of every probe association (desired-state reconcile; any existing probe omitted here is removed). Array of { probeId, inputs? }, same shape as create's 'probes'. To keep current probes, call harness_get first and resupply its 'probes' array unchanged; pass [] to explicitly detach all probes.`;
|
|
145
|
+
export const descUpdateChaosService = `Update an existing chaos service, identified by the path 'identity' (identity is not renameable — do not put it in the body). This is a FULL REPLACE of the mutable fields (name, description, tags, external_service_id, agent_id, environment_id, infrastructure_id), not a partial patch: description and tags are overwritten with exactly what you send, including being cleared to empty if you omit them — there is no "leave unchanged" behavior for these two fields. To preserve the current description/tags, fetch the service first (harness_get) and re-supply its current values. Probes is a REQUIRED desired-state array: it is reconciled atomically with the field update, and any probe present on the service but not in the array is removed. To keep the current probes, harness_get first and resupply the 'probes' array unchanged; pass [] to intentionally detach every probe. Returns the full ChaosServiceResponse on 200.`;
|
|
146
|
+
export const descBodyChaosServiceUpdate = `Chaos service update body. Required: name, external_service_id, agent_id, environment_id, infrastructure_id (the last four are re-validated server-side via a Service Discovery lookup), and probes (a full desired-state array — see below). Optional (schema-wise): description, tags — but "optional" only means the request validates without them. Omitting description or tags CLEARS them server-side (full replace, no partial patch); re-supply the current value from a prior harness_get if you want it preserved. probes is required precisely because it is a full replace: supply the complete desired set (harness_get first to keep existing ones), or [] to detach all probes. Do NOT include 'identity' — pass it at the top level so it goes on the URL.`;
|
|
97
147
|
export const descChaosLoadtest = `Load test (Resilience Testing) instance. Supports list, get, create, delete; run/stop via execute actions.
|
|
98
|
-
Locust is supported on Linux VM and Kubernetes (script + image modes). K6 is
|
|
99
|
-
To create one,
|
|
148
|
+
Locust is supported on Linux VM and Kubernetes (script + image modes). K6 is genuinely Kubernetes-only at the backend. JMeter is restricted to Kubernetes by MCP for parity with the Harness UI (the backend itself does not enforce this for JMeter) — Linux VM supports Locust only; MCP rejects K6/JMeter with a Linux target_type at create time. JMeter accepts script/script_image scalars like Locust/K6 (plus properties/env_vars/thresholds/worker_count); 'tool_config' remains available as an advanced escape hatch (e.g. .zip bundles).
|
|
149
|
+
To create one, follow the prerequisite chain declared in relatedResources: (1) pick a load-runner infra via chaos_infrastructure (Linux VM) or chaos_enabled_infrastructure (Kubernetes), then (2) list chaos_service with infrastructure_ids='<environment_id>/<infra_id>' and pick one — or create a chaos_service if the list is empty — feeding its identity into service_references. When picking a Kubernetes infra, remember to set target_type='kubernetes' explicitly; it is not derived from the infra you chose.
|
|
100
150
|
|
|
101
151
|
Response / read schema (what list/get returns — agents NEVER need to construct these on create; MCP builds them automatically):
|
|
102
|
-
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
152
|
+
- toolConfig.<tool> (canonical, per loadTestManager LocustSpec / K6Spec / JMeterSpec):
|
|
153
|
+
mode: "script" | "image"
|
|
154
|
+
script: { content? (base64), image?, entrypoint?, loadArgs?, imagePullSecret? }
|
|
155
|
+
tunables: { targetUrl?, targetUsers?, spawnRate? (Locust), rampUpTimeSec? (Locust), durationSeconds? (Locust/K6), workerCount?, hostUrl? (K6), iterations? (K6), rpsLimit? (K6) }
|
|
156
|
+
envVars?: [{key, value, secret?}] (K6/JMeter)
|
|
157
|
+
variables?: template.VariableList (currently always empty; custom variables are a deferred feature)
|
|
158
|
+
properties?: [{key, value, sendToEngines?}] (JMeter)
|
|
159
|
+
thresholds?: [{metric, stat?, operator, value, abortOnFail?}] (JMeter)
|
|
108
160
|
- yaml: base64-encoded LoadTest manifest. Decoded shape:
|
|
109
161
|
kind: LoadTest
|
|
110
162
|
apiVersion: v1alpha1
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
163
|
+
metadata:
|
|
164
|
+
name: <name>
|
|
165
|
+
description?: <string>
|
|
166
|
+
tags?: [<string>]
|
|
167
|
+
serviceReferences?: [<chaosService identity>]
|
|
114
168
|
spec:
|
|
115
169
|
identity: <slug>
|
|
116
|
-
toolType: Locust
|
|
170
|
+
toolType: Locust | K6 | JMeter
|
|
117
171
|
infraType: kubernetes | linux # derived from targetType
|
|
118
172
|
targetType: kubernetes | machine-chaos-linux | linux-chaos
|
|
119
|
-
|
|
120
|
-
scriptContent: <PLAIN TEXT inside YAML; inline mode only>
|
|
173
|
+
cleanupPolicy: delete | retain
|
|
121
174
|
infraId: <id>
|
|
122
175
|
envId: <id>
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
export const descChaosK8sInfrastructure = `Kubernetes chaos infrastructure available for running experiments.
|
|
176
|
+
toolConfig: { <tool>: { mode, script, tunables, ... } }
|
|
177
|
+
- Derived convenience scalars (read-side projection of toolConfig.<tool> by MCP, matching the create-side scalars):
|
|
178
|
+
target_url, users, duration_sec, ramp_up_sec, worker_count, spawn_rate, host_url, iterations, rps_limit,
|
|
179
|
+
script_image, script_entrypoint, load_args, image_pull_secret.`;
|
|
180
|
+
export const descChaosK8sInfrastructure = `Kubernetes chaos infrastructure (chaos server) available for running experiments.
|
|
128
181
|
Use chaos_environment list first to get an environmentId, then pass it here to filter infrastructures for that environment.
|
|
129
182
|
Returns infrastructure details including identity, infraID, name, environmentID, status, infraType, infraScope, and isChaosEnabled.
|
|
130
183
|
The infraID is used as the infra_ref parameter in create_from_template.
|
|
131
184
|
IMPORTANT: Only infrastructures with status=ACTIVE AND isChaosEnabled=true can be used to create chaos experiments. Always check both fields before selecting an infrastructure.
|
|
185
|
+
Supports list, get, create, plus check_health execute action.
|
|
132
186
|
Supports filtering by status (ACTIVE, INACTIVE, PENDING), search, and optional inclusion of legacy V1 infrastructures.
|
|
133
187
|
To list ONLY infrastructures that are ready to run experiments (chaos-enabled AND ACTIVE) with correct totals/pagination, use chaos_enabled_infrastructure instead.`;
|
|
188
|
+
export const descCreateK8sInfra = `Register a new Kubernetes chaos infrastructure (chaos server) in the given Harness project.
|
|
189
|
+
|
|
190
|
+
This registers the chaos agent/delegate metadata in Harness and returns an access token plus Helm/manifest instructions for installing the chaos server in your cluster.
|
|
191
|
+
|
|
192
|
+
GUIDED workflow — resolve each step before calling harness_create:
|
|
193
|
+
|
|
194
|
+
STEP 1 — Select environment (REQUIRED):
|
|
195
|
+
harness_list resource_type=chaos_environment (or resource_type=environment). Ask the user to pick one.
|
|
196
|
+
Capture environment_id = chosen environment identifier.
|
|
197
|
+
|
|
198
|
+
STEP 2 — Select backing CD infrastructure (REQUIRED for standard onboarding):
|
|
199
|
+
harness_list resource_type=infrastructure with environment_id=<env from Step 1>.
|
|
200
|
+
Ask the user which Kubernetes infrastructure definition to attach. Capture infra_id = infrastructure identifier.
|
|
201
|
+
The backend validates this Harness CD infra exists in the selected environment.
|
|
202
|
+
|
|
203
|
+
STEP 3 — Configure chaos server metadata (REQUIRED):
|
|
204
|
+
Ask for name and identity (slug). identity must be unique in scope; infra_id defaults to identity when omitted.
|
|
205
|
+
Defaults (override only if user asks): infra_namespace=hce, service_account=litmus, infra_scope=CLUSTER, infra_type=KUBERNETES.
|
|
206
|
+
|
|
207
|
+
STEP 4 — Create:
|
|
208
|
+
harness_create(resource_type='chaos_k8s_infrastructure', org_id, project_id, body={ identity, name, environment_id, infra_id?, k8s_connector_id?, infra_namespace?, service_account?, infra_scope?, infra_type?, description?, tags?, ai_enabled? })
|
|
209
|
+
|
|
210
|
+
Returns identity, name, token (for agent install), and uniqueId. After create, apply the returned manifest/Helm chart in the target cluster and wait for status=ACTIVE + isChaosEnabled=true before running experiments.`;
|
|
211
|
+
export const descBodyK8sInfraCreate = `Chaos K8s infrastructure (chaos server) registration body. Required: identity, name, environment_id. infra_id defaults to identity when omitted.`;
|
|
212
|
+
export const descK8sInfraIdentityCreate = `Unique slug for the chaos infrastructure. Also used as infraID when infra_id is omitted. Must be unique within the project scope.`;
|
|
213
|
+
export const descK8sInfraNameCreate = `Human-readable display name for the chaos server.`;
|
|
214
|
+
export const descK8sInfraEnvironmentIdCreate = `Harness environment identifier where the chaos server will run. Use chaos_environment or environment list to find valid IDs.`;
|
|
215
|
+
export const descK8sInfraInfraIdCreate = `Harness CD infrastructure definition identifier in the selected environment. Defaults to identity when omitted. The backend verifies this infra exists.`;
|
|
216
|
+
export const descK8sInfraConnectorIdCreate = `Optional Kubernetes connector identifier when required by your onboarding flow.`;
|
|
217
|
+
export const descK8sInfraNamespaceCreate = `Kubernetes namespace where chaos components are installed. Default: hce.`;
|
|
218
|
+
export const descK8sInfraServiceAccountCreate = `Kubernetes service account for the chaos server. Default: litmus.`;
|
|
219
|
+
export const descK8sInfraScopeCreate = `Installation scope. CLUSTER (default) or NAMESPACE.`;
|
|
220
|
+
export const descK8sInfraTypeCreate = `Infrastructure type. KUBERNETES (default) or KUBERNETESV2.`;
|
|
221
|
+
export const descK8sInfraAiEnabledCreate = `Enable AI recommendations for this infrastructure. Default: false.`;
|
|
134
222
|
export const descChaosHub = `ChaosHub — a Git-backed repository that provides version-controlled chaos fault, experiment, probe, and action templates.
|
|
135
223
|
Every project includes a default Enterprise ChaosHub with pre-built templates; custom hubs can be created to bring in organization-specific chaos artifacts.
|
|
136
224
|
Supports list, get, create, update, and delete.
|
|
@@ -357,112 +445,306 @@ Requires hub_identity to identify which chaos hub owns the template.
|
|
|
357
445
|
Returns a success confirmation on completion.`;
|
|
358
446
|
export const descListExperimentVariables = `List variables for a chaos experiment (experiment-level and task-level). By default treats experiment_id as a human-readable identity slug (e.g. "exp-without-runtime"); pass is_identity=false to use the internal UUID instead.`;
|
|
359
447
|
export const descListLinuxInfra = `List chaos Linux infrastructures (load runners)`;
|
|
360
|
-
export const descListLoadtests = `List load test instances
|
|
448
|
+
export const descListLoadtests = `List load test instances.
|
|
449
|
+
|
|
450
|
+
Pagination: use the top-level harness_list 'page' / 'size' arguments (0-indexed page, size 1-100) -- NOT 'limit'; a top-level 'limit' argument is silently dropped and the default size (20) applies instead.
|
|
451
|
+
Filters (tool_type, environment_id, tags, sort_field, sort_ascending, search) must be passed inside harness_list's 'filters' object, e.g. filters: { tool_type: "Locust" }.
|
|
452
|
+
KNOWN LIMITATION: 'search' matches only the load test's display name (case-insensitive substring) -- it does NOT match identity/slug, and is not fuzzy or prefix-tolerant. Use an exact or partial name substring, not an identity-style term.
|
|
453
|
+
compact:true (the harness_list default) strips toolType/targetType/scriptSource/toolConfig/recentRuns from each item to keep responses lean -- pass compact:false, or call harness_get on a specific loadtest_id, for full tool config and run history.`;
|
|
361
454
|
export const descGetLoadtest = `Get load test instance details`;
|
|
455
|
+
// Shared, tool-agnostic map of scalar body fields -> toolConfig.<tool>.* wire paths.
|
|
456
|
+
// Referenced verbatim by both descCreateLoadtest (Step 6 taxonomy) and
|
|
457
|
+
// descUpdateLoadtest (scalar-edit path 1). The mapping is identical on create
|
|
458
|
+
// and update -- callers pass the same scalars either way; MCP builds
|
|
459
|
+
// toolConfig.<tool> from them via buildLocustToolConfig / buildK6ToolConfig /
|
|
460
|
+
// buildJMeterToolConfig.
|
|
461
|
+
export const descLoadtestFieldTaxonomy = ` (a) Script file / Custom image -> script | script_image (+script_entrypoint, load_args, image_pull_secret) -> toolConfig.<tool>.script.{content|image|entrypoint|loadArgs|imagePullSecret}. ALL tools; script_image is the only mandatory field in Custom Image mode; script_entrypoint, load_args and image_pull_secret are optional (image_pull_secret only for Private registries; the backend falls back to a tool-specific default entrypoint when omitted).
|
|
462
|
+
(b) Host / Target URL -> target_url (fixed|<+input>) -> toolConfig.<tool>.tunables.targetUrl. LOCUST + K6 ONLY (not exposed for JMeter -- see JMeter step notes), optional. K6 additionally derives tunables.hostUrl from the URL's origin (feeds the script as __ENV.HOST_URL); leave blank if the script/locustfile declares its own host.
|
|
463
|
+
(c) Users -> users (fixed|<+input>) -> toolConfig.<tool>.tunables.targetUsers. LOCUST + K6 ONLY (not exposed for JMeter -- see JMeter step notes).
|
|
464
|
+
(d) Duration (seconds) -> duration_sec (fixed|<+input>) -> toolConfig.<tool>.tunables.durationSeconds. LOCUST + K6 ONLY (not exposed for JMeter -- see JMeter step notes).
|
|
465
|
+
(e) Ramp Up Duration (seconds) -> ramp_up_sec (fixed|<+input>) -> toolConfig.<tool>.tunables.rampUpTimeSec. LOCUST ONLY (no Ramp Up field in the K6 UI form or for JMeter). Must not exceed Duration when both are fixed values.
|
|
466
|
+
(f) Iterations (cap) -> iterations (fixed|<+input>) -> toolConfig.k6.tunables.iterations. K6 ONLY. Duration takes precedence when both are set.
|
|
467
|
+
(g) RPS Limit -> rps_limit (fixed|<+input>) -> toolConfig.k6.tunables.rpsLimit. K6 ONLY. Global cap, split evenly across replicas; always applies (unlike (c)/(d)/(f), which k6 ignores once the script declares its own scenarios/stages).
|
|
468
|
+
(h) Worker Count / Replicas -> worker_count (fixed|<+input>) -> toolConfig.<tool>.tunables.workerCount. LOCUST + K6 + JMETER, Kubernetes only (VM always runs a single worker/pod -- skip entirely for target_type='machine-chaos-linux'). Locust: Users are DISTRIBUTED across workers, not multiplied. K6: <=1 = single pod; higher values fan out to multiple runner pods via --execution-segment. JMeter: workers MULTIPLY load -- each injector runs the FULL uploaded plan unchanged; thread counts inside the file are NOT sliced across workers.
|
|
469
|
+
(i) Environment Variables -> env_vars -> toolConfig.<tool>.envVars[]. K6 + JMETER. Structured array; each entry is a literal {key, value}, a runtime {key, value: "<+input>"}, or a secret reference {key, secret_id, secret_scope?}. See the env_vars field's own description (descLoadtestEnvVars) for the full validator, reserved-name list, and secret_scope discovery flow (harness_list resource_type=secret type=SecretText) -- not repeated here. K6 additionally rejects HOST_URL/K6_VUS/K6_DURATION/K6_ITERATIONS/K6_STAGES/K6_RPS (tool-specific reserved names on top of the shared list).
|
|
470
|
+
(j) Property Overrides -> properties -> toolConfig.jmeter.properties[]. JMETER ONLY. Array of {key, value, send_to_engines?}; injects/overrides JMeter properties at run time without editing the uploaded plan -- reference as \${__P(NAME)} inside the plan. send_to_engines (-G) controls whether the property also reaches remote workers in Distributed Execution; omit for controller-only properties.
|
|
471
|
+
(k) Thresholds -> thresholds -> toolConfig.jmeter.thresholds[]. JMETER ONLY. Array of {metric, stat?, operator, value, abort_on_fail?}; pass/fail criteria evaluated against the run's .jtl results AFTER the test (the uploaded plan's own Assertions still apply per-request during the run). metric one of response_time_ms|error_rate_pct|throughput_rps|latency_ms; operator one of < <= > >= == !=; stat (e.g. p95/p99/avg/median/max) is REQUIRED when metric is response_time_ms or latency_ms.`;
|
|
362
472
|
export const descCreateLoadtest = `Creates a Locust load test (Resilience Testing) on a Linux VM or Kubernetes load-runner infrastructure.
|
|
363
|
-
|
|
364
473
|
IMPORTANT: You MUST NOT auto-select, assume, or pre-fill any value on behalf of the user.
|
|
365
474
|
At every step below, present the options / ask for the value and wait for explicit user confirmation before proceeding.
|
|
366
475
|
Do NOT assume org/project/infrastructure/script/URL based on previous activity — the user may choose differently each time.
|
|
367
|
-
Locust (Python)
|
|
476
|
+
Locust (Python), K6 (JavaScript), and JMeter (Java) are supported. K6 and JMeter are Kubernetes-only; Linux VM supports Locust only. All three tools support "Upload script" and "Using Custom Image" via scalar inputs (script, script_image, script_entrypoint, load_args, image_pull_secret) plus tool-specific extras (properties/thresholds for JMeter; env_vars for K6/JMeter). The 'tool_config' body field remains available as an advanced escape hatch (e.g. JMeter .zip bundles pre-base64'd into tool_config.jmeter.script.content). For K6, "Define test via UI" is deferred.
|
|
477
|
+
Required workflow -- follow in order, pausing for user input after each step.
|
|
478
|
+
COMMON STEPS (identical for Locust, K6, and JMeter):
|
|
479
|
+
Each step below shows the slice of the canonical stored LoadTest YAML that its inputs populate (what the user sees in the Harness UI YAML view). You NEVER hand-write this YAML -- MCP synthesizes it from the scalars/objects you pass to harness_create; the slices exist only so you can reason about which of your inputs affects which YAML path and echo an accurate preview back to the user.
|
|
480
|
+
Two paths of the stored YAML are set from top-level body fields rather than the MCP-built manifest itself and are merged by the backend: metadata.serviceReferences (from body.service_references) and spec.cleanupPolicy (from body.cleanup_policy). All other YAML paths below correspond 1:1 to what MCP writes into body.yaml.
|
|
481
|
+
|
|
482
|
+
Step 1 -- Name / description / tags:
|
|
483
|
+
Ask for a name (any non-empty string) -> name. identity is auto-derived from name by stripping non-alphanumerics unless the user supplies one (letters / numbers / underscores).
|
|
484
|
+
description and tags are optional -- ask, but do not require them.
|
|
485
|
+
YAML populated after this step:
|
|
486
|
+
kind: LoadTest
|
|
487
|
+
apiVersion: v1alpha1
|
|
488
|
+
metadata:
|
|
489
|
+
name: <name>
|
|
490
|
+
description: <description> # omitted when empty
|
|
491
|
+
tags: # omitted when empty
|
|
492
|
+
- <tag>
|
|
493
|
+
spec:
|
|
494
|
+
identity: <identity> # auto-derived slug from name unless user supplies one
|
|
368
495
|
|
|
369
|
-
|
|
496
|
+
Step 2 -- Execution environment target type:
|
|
497
|
+
Ask "Linux VM" (target_type=machine-chaos-linux) or "Kubernetes" (target_type=kubernetes). Wait for the user to choose.
|
|
498
|
+
Linux VM supports Locust only. Kubernetes supports Locust, K6, or JMeter.
|
|
499
|
+
YAML populated after this step (delta only):
|
|
500
|
+
spec:
|
|
501
|
+
targetType: kubernetes | machine-chaos-linux
|
|
502
|
+
infraType: kubernetes | linux # derived from targetType, not user-supplied
|
|
503
|
+
|
|
504
|
+
Step 3 -- Load-runner infrastructure (see chaos_loadtest.relatedResources for canonical guidance):
|
|
505
|
+
Linux VM -> harness_list resource_type=chaos_infrastructure (loadEnabled + ACTIVE only).
|
|
506
|
+
Kubernetes -> harness_list resource_type=chaos_enabled_infrastructure (already ACTIVE + chaos-enabled).
|
|
507
|
+
From the chosen row: environmentID -> environment_id, infraID -> infra_id. Do NOT choose an infra yourself.
|
|
508
|
+
If NO eligible infra is returned (empty list, or every row fails the eligibility filter above), STOP and tell the user no eligible load-runner infra exists in the current scope. Ask them to (a) switch org/project scope, (b) pick a different target type at Step 2 (Linux VM <-> Kubernetes), or (c) exit/stop. Do NOT fall back to an ineligible infra and do NOT proceed to Step 4 -- a load test cannot be created without an eligible infra.
|
|
509
|
+
YAML populated after this step (delta only):
|
|
510
|
+
spec:
|
|
511
|
+
infraId: <infraID from the chosen infra row>
|
|
512
|
+
envId: <environmentID from the chosen infra row>
|
|
513
|
+
|
|
514
|
+
Step 4 -- Resilience Testing Services (chaos_service):
|
|
515
|
+
Call harness_list resource_type=chaos_service with infrastructure_ids='<environment_id>/<infra_id>'. Show the list to the user.
|
|
516
|
+
The user may (a) pick one or more identities from the list, OR (b) onboard a brand-new service via chaos_service's create flow -- offer BOTH options regardless of whether the list is empty. Pass the chosen identity/identities as service_references.
|
|
517
|
+
YAML populated after this step (delta only):
|
|
518
|
+
metadata:
|
|
519
|
+
serviceReferences: # merged in by backend from the top-level service_references body field
|
|
520
|
+
- <chaos_service identity>
|
|
521
|
+
- ...
|
|
522
|
+
Passed on the wire as body.service_references (snake_case scalar), NOT as part of the yaml manifest MCP builds -- the backend writes it into the stored YAML at metadata.serviceReferences.
|
|
523
|
+
|
|
524
|
+
Step 5 -- Tool type:
|
|
525
|
+
Linux VM: Locust only. Kubernetes: ask Locust / K6 / JMeter.
|
|
526
|
+
Pass tool_type='Locust' | 'K6' | 'JMeter'. K6 and JMeter with a non-Kubernetes target_type will be rejected by MCP.
|
|
527
|
+
YAML populated after this step (delta only):
|
|
528
|
+
spec:
|
|
529
|
+
toolType: Locust | K6 | JMeter
|
|
530
|
+
cleanupPolicy: delete # default; see Step 7a to override or add spec.resources (Step 7b)
|
|
531
|
+
toolConfig:
|
|
532
|
+
<lowercase(toolType)>: # e.g. locust / k6 / jmeter
|
|
533
|
+
mode: script | image # tool_config detail filled in Step 6
|
|
534
|
+
script:
|
|
535
|
+
content: "" # base64 on the wire, decoded plain-text in the YAML view; filled in Step 6
|
|
536
|
+
tunables: # filled in Step 8 (load configuration)
|
|
537
|
+
targetUsers: <int>
|
|
538
|
+
durationSeconds: <int>
|
|
539
|
+
rampUpTimeSec: <int>
|
|
540
|
+
workerCount: <int> # Kubernetes only
|
|
541
|
+
Notes:
|
|
542
|
+
- All three tools (Locust / K6 / JMeter) populate toolConfig.<tool> from Step-6 scalars -- no hand-built tool_config needed for standard flows. JMeter's tool_config remains available only as an advanced escape hatch (e.g. pre-base64'd .zip bundles).
|
|
543
|
+
- JMeter has no target_url / users / duration / ramp_up scalar surface -- load shape is baked into the uploaded plan (script mode) or the container image (custom image mode). Server defaults 100/600/30 for missing tunables on save.
|
|
544
|
+
|
|
545
|
+
Step 6 -- Tool-specific configuration (branch on tool_type from Step 5):
|
|
546
|
+
Every tool type supports two authoring modes:
|
|
547
|
+
(a) Upload script (script_source='inline', mode='script') -- paste the raw script; MCP base64-encodes it into toolConfig.<tool>.script.content.
|
|
548
|
+
(b) Using Custom Image (script_source='image', mode='image') -- point at a prebuilt container image; no script is uploaded.
|
|
549
|
+
Mode lives at toolConfig.<tool>.mode; script_source on the wire body mirrors it ('inline' <-> 'script', 'image' <-> 'image').
|
|
550
|
+
Fields marked (*) in a branch below are MANDATORY for that branch -- the UI (and MCP validation) reject creation with any '*' field empty. Unmarked fields are OPTIONAL.
|
|
551
|
+
Fixed vs runtime input: fields noted "(fixed|<+input>)" below accept EITHER a concrete value NOW, OR the literal string '<+input>' meaning "prompt for this value at run time". Pass the placeholder verbatim -- MCP forwards it as-is into the tunables and into the base64 YAML manifest.
|
|
552
|
+
Shared field taxonomy -- each branch below references these by letter instead of restating them:
|
|
553
|
+
${descLoadtestFieldTaxonomy}
|
|
554
|
+
|
|
555
|
+
Step 6.LocustScript -- Locust + Upload Python script (mode='script'):
|
|
556
|
+
|
|
557
|
+
Ask, in order: (*)(a) Script file, (b) Host URL, (*)(c) Users, (*)(d) Duration, (*)(e) Ramp Up, (h) Worker Count [Kubernetes only].
|
|
558
|
+
YAML populated after this step (delta only):
|
|
559
|
+
spec:
|
|
560
|
+
toolConfig:
|
|
561
|
+
locust:
|
|
562
|
+
mode: script
|
|
563
|
+
script:
|
|
564
|
+
content: | # plain text in YAML view; base64 on wire
|
|
565
|
+
<the Python locust script>
|
|
566
|
+
tunables: # omit keys the user left blank
|
|
567
|
+
targetUrl: http://www.example.com
|
|
568
|
+
targetUsers: 100
|
|
569
|
+
durationSeconds: 600
|
|
570
|
+
rampUpTimeSec: 120
|
|
571
|
+
workerCount: 1 # Kubernetes only
|
|
572
|
+
|
|
573
|
+
Step 6.LocustImage -- Locust + Using Custom Image (mode='image'):
|
|
574
|
+
Kubernetes only (script_source=image, or inferred when script_image is set). VM is always inline.
|
|
575
|
+
Ask, in order:
|
|
576
|
+
(b) Host URL -> target_url (optional; Locust --host; leave blank if the locustfile sets host in code)
|
|
577
|
+
(a) Load Test Image* -> script_image (required; container image, e.g. my-registry/my-load-test:latest)
|
|
578
|
+
(a) Entrypoint -> script_entrypoint (optional; path inside the image, e.g. /scripts/locustfile.py; passed to locust -f; backend falls back to a default when omitted)
|
|
579
|
+
(a) Load args -> load_args (optional; semicolon-separated k=v pairs, e.g. "tags=smoke,fast;headless=true" -- NOT bare CLI flags)
|
|
580
|
+
(a) Image Registry Type -> Public: omit image_pull_secret
|
|
581
|
+
Private: image_pull_secret (name of the Kubernetes image-pull secret)
|
|
582
|
+
(c) Users* -> users
|
|
583
|
+
(d) Duration* -> duration_sec
|
|
584
|
+
(e) Ramp Up* -> ramp_up_sec
|
|
585
|
+
(h) Worker Count -> worker_count (K8s; 0/omit = standalone)
|
|
586
|
+
YAML populated after this step (delta only):
|
|
587
|
+
spec:
|
|
588
|
+
toolConfig:
|
|
589
|
+
locust:
|
|
590
|
+
mode: image
|
|
591
|
+
script:
|
|
592
|
+
image: my-registry/my-load-test:latest
|
|
593
|
+
entrypoint: /scripts/locustfile.py
|
|
594
|
+
loadArgs: tags=smoke # omit when blank
|
|
595
|
+
imagePullSecret: my-pull-secret # omit when Public
|
|
596
|
+
tunables: # omit keys the user left blank
|
|
597
|
+
targetUrl: https://www.google.com
|
|
598
|
+
targetUsers: 100
|
|
599
|
+
durationSeconds: 600
|
|
600
|
+
rampUpTimeSec: 120
|
|
601
|
+
workerCount: 1
|
|
602
|
+
|
|
603
|
+
Step 6.K6Script -- K6 + Upload K6 script (mode='script'):
|
|
604
|
+
Kubernetes-only: MCP rejects K6 with target_type='machine-chaos-linux' at create time.
|
|
605
|
+
Ask, in order: (*)(a) Script file [MANDATORY: script MUST contain 'export default function ...' -- reject before calling MCP if missing, matching Harness UI validateScriptContent], (b) Host URL, (c) Users, (d) Duration, (f) Iterations, (g) RPS Limit, (i) Environment Variables, (h) Replicas.
|
|
606
|
+
Load-profile semantics reminder: (c)/(d)/(f) are ignored by k6 once the script declares its own scenarios/stages -- leave them blank for scripted scenarios. (g) RPS Limit always applies.
|
|
607
|
+
YAML populated after this step (delta only):
|
|
608
|
+
spec:
|
|
609
|
+
toolConfig:
|
|
610
|
+
k6:
|
|
611
|
+
mode: script
|
|
612
|
+
script:
|
|
613
|
+
content: | # plain text in YAML view; base64 on wire
|
|
614
|
+
<the K6 JavaScript source>
|
|
615
|
+
tunables: # omit keys the user left blank
|
|
616
|
+
targetUrl: https://www.examplek6.com
|
|
617
|
+
targetUsers: <+input>
|
|
618
|
+
durationSeconds: <+input>
|
|
619
|
+
iterations: <+input>
|
|
620
|
+
workerCount: 1
|
|
621
|
+
rpsLimit: 100
|
|
622
|
+
envVars: # omit entirely when no env vars are set
|
|
623
|
+
- { key: env_var_1, value: some_val_1, secret: false }
|
|
624
|
+
- { key: env_var_2, value: <+input>, secret: false }
|
|
625
|
+
- { key: somekey, value: secrets.getValue("account.gcp-ca-cert"), secret: true } # scope prefix per env_vars docs: account./org./none for project
|
|
626
|
+
|
|
627
|
+
Step 6.K6Image -- K6 + Using Custom Image (mode='image'):
|
|
628
|
+
Kubernetes only (script_source=image, or inferred when script_image is set).
|
|
629
|
+
Ask, in order:
|
|
630
|
+
(b) Host URL -> target_url (optional; MCP derives toolConfig.k6.tunables.hostUrl from its origin)
|
|
631
|
+
(a) Load Test Image* -> script_image (required; container image, e.g. my-registry/my-load-test:latest)
|
|
632
|
+
(a) Entrypoint -> script_entrypoint (optional; path inside the image, e.g. /script.js; backend falls back to a default when omitted)
|
|
633
|
+
(a) Load args -> load_args (optional; semicolon-separated k=v pairs, e.g. "tags=smoke,fast;headless=true" -- NOT bare CLI flags)
|
|
634
|
+
(a) Image Registry Type -> Public: omit image_pull_secret
|
|
635
|
+
Private: image_pull_secret (name of the Kubernetes image-pull secret)
|
|
636
|
+
(h) Worker Count -> worker_count (K8s; 0/omit = standalone)
|
|
637
|
+
(g) RPS Limit -> rps_limit (optional; toolConfig.k6.tunables.rpsLimit when > 0)
|
|
638
|
+
(i) Environment Variables -> env_vars (see Step 4c)
|
|
639
|
+
Note: Users/Duration/Iterations tunables are meaningless for image mode -- the bundled script controls its own scenarios/stages. Do not ask for them here.
|
|
640
|
+
YAML populated after this step (delta only):
|
|
641
|
+
spec:
|
|
642
|
+
toolConfig:
|
|
643
|
+
k6:
|
|
644
|
+
mode: image
|
|
645
|
+
script:
|
|
646
|
+
image: my-registry/my-load-test:latest # or <+input>
|
|
647
|
+
entrypoint: /script.js # or <+input>
|
|
648
|
+
loadArgs: tags=smoke # omit when blank
|
|
649
|
+
imagePullSecret: my-pull-secret # omit when Public
|
|
650
|
+
tunables:
|
|
651
|
+
workerCount: 1
|
|
652
|
+
rpsLimit: 100 # omit when rps_limit is unset
|
|
653
|
+
envVars: # omit entirely when no env vars are set
|
|
654
|
+
- { key: someKey, value: someValue, secret: false }
|
|
655
|
+
|
|
656
|
+
Step 6.JMeterScript -- JMeter + Upload JMX / XML / ZIP (mode='script'):
|
|
657
|
+
Kubernetes-only: MCP rejects JMeter with target_type='machine-chaos-linux' at create time.
|
|
658
|
+
Ask, in order: (*)(a) Test Plan file [.jmx/.xml -- raw plan text, verbatim; do NOT parse, modify, or pre-encode. A .zip bundle (plan + CSV data/dependencies) is also accepted but must be supplied pre-base64'd via tool_config.jmeter.script.content instead of the scalar 'script' field], (j) Property Overrides, (i) Environment Variables, (k) Thresholds, (h) Workers.
|
|
659
|
+
Notes: (b)/(c)/(d)/(e)/(f)/(g) do not apply to JMeter -- thread count, ramp-up, and duration live inside the uploaded plan's ThreadGroup elements, not as separate MCP inputs. If the user wants to change load shape, tell them to edit the .jmx and re-upload (or use tool_config.jmeter.tunables.{targetUsers,durationSeconds,rampUpTimeSec} as an advanced override -- backend-accepted but not exposed as a scalar here since the Harness UI does not expose it either).
|
|
660
|
+
YAML populated after this step (delta only):
|
|
661
|
+
spec:
|
|
662
|
+
toolConfig:
|
|
663
|
+
jmeter:
|
|
664
|
+
mode: script
|
|
665
|
+
script:
|
|
666
|
+
content: | # plain text in YAML view; base64 on wire
|
|
667
|
+
<the .jmx/.xml plan>
|
|
668
|
+
tunables:
|
|
669
|
+
workerCount: 1 # Kubernetes only
|
|
670
|
+
properties: # omit entirely when no property overrides are set
|
|
671
|
+
- { key: someProperty, value: someValue, sendToEngines: true }
|
|
672
|
+
envVars: # omit entirely when no env vars are set
|
|
673
|
+
- { key: secretKeyAtProject, value: secrets.getValue("datat-api"), secret: true }
|
|
674
|
+
- { key: fixedKey, value: fixedValue }
|
|
675
|
+
- { key: RuntimeKey, value: <+input> }
|
|
676
|
+
thresholds: # omit entirely when no thresholds are set
|
|
677
|
+
- { metric: response_time_ms, stat: p95, operator: <, value: 5000, abortOnFail: false }
|
|
678
|
+
|
|
679
|
+
Step 6.JMeterImage -- JMeter + Using Custom Image (mode='image'):
|
|
680
|
+
Kubernetes-only (script_source=image, or inferred when script_image is set). Custom Image does NOT slice load -- each worker runs the full command independently, so total load ~= plan threads * injectors. Users/Duration/Ramp-up are baked into the image's plan and are NOT asked here (server defaults 100/600/30 when omitted; do not surface them).
|
|
681
|
+
Ask, in order:
|
|
682
|
+
(a) Load Test Image* -> script_image (required; cluster-reachable container image, e.g. my-registry/jmeter:5.6; may be '<+input>')
|
|
683
|
+
(a) Entrypoint -> script_entrypoint (optional; path to the .jmx/.xml test plan inside the image, e.g. /test/plan.jmx; may be '<+input>'; backend falls back to a default plan-file name when omitted)
|
|
684
|
+
(a) Load args -> load_args (optional; JMeter GNU-style long options as semicolon-separated key=value pairs OR bare flags, e.g. "proxyHost=10.0.0.1;forceDeleteResultFile". Each becomes --key=value. Do NOT put JMeter properties (jmeter.save.saveservice.* or \${__P(...)} vars) here -- those go in Property Overrides / -J / -G. Keys must be non-empty, contain no whitespace, and must NOT start with '-')
|
|
685
|
+
(a) Image Registry Type -> Public: omit image_pull_secret
|
|
686
|
+
Private: image_pull_secret (name of the Kubernetes image-pull secret)
|
|
687
|
+
(j) Property Overrides -> properties (optional; array of {key, value, send_to_engines?}. send_to_engines=true adds -G so the property reaches remote workers in Distributed Execution)
|
|
688
|
+
(i) Environment Variables -> env_vars (optional; fixed / '<+input>' runtime / secret via {secret_id, secret_scope?}. See descLoadtestEnvVars for the full reserved-name list and secret discovery flow)
|
|
689
|
+
(k) Thresholds -> thresholds (optional; array of {metric, stat?, operator, value, abort_on_fail?}. metric one of response_time_ms|error_rate_pct|throughput_rps|latency_ms; operator one of < <= > >= == !=; stat REQUIRED for response_time_ms / latency_ms. value is a number -- runtime '<+input>' is NOT supported for thresholds)
|
|
690
|
+
(h) Workers -> worker_count (optional; number of load injectors. Each injector runs the FULL plan unchanged -- workers MULTIPLY load. 0/omit = single standalone injector)
|
|
691
|
+
YAML populated after this step (delta only):
|
|
692
|
+
spec:
|
|
693
|
+
toolConfig:
|
|
694
|
+
jmeter:
|
|
695
|
+
mode: image
|
|
696
|
+
script:
|
|
697
|
+
image: my-registry/jmeter:5.6 # or <+input>
|
|
698
|
+
entrypoint: /test/plan.jmx # or <+input>
|
|
699
|
+
loadArgs: proxyHost=10.0.0.1 # omit when blank
|
|
700
|
+
imagePullSecret: my-pull-secret # omit when Public
|
|
701
|
+
tunables:
|
|
702
|
+
workerCount: 1 # omit when 0/unset
|
|
703
|
+
properties: # omit entirely when no property overrides are set
|
|
704
|
+
- { key: threads1, value: "100", sendToEngines: true }
|
|
705
|
+
- { key: someProperty, value: "200", sendToEngines: false }
|
|
706
|
+
envVars: # omit entirely when no env vars are set
|
|
707
|
+
- { key: somekey, value: secrets.getValue("datat-api"), secret: true }
|
|
708
|
+
- { key: runtime, value: <+input> }
|
|
709
|
+
- { key: fixed, value: somefixed }
|
|
710
|
+
thresholds: # omit entirely when no thresholds are set
|
|
711
|
+
- { metric: response_time_ms, stat: p95, operator: <, value: 5000, abortOnFail: false }
|
|
712
|
+
- { metric: error_rate_pct, stat: avg, operator: <=, value: 50, abortOnFail: true }
|
|
713
|
+
- { metric: throughput_rps, stat: p99, operator: '>', value: 5000, abortOnFail: false }
|
|
714
|
+
|
|
715
|
+
Step 7 -- Advanced Options (all tool types; identical for Locust/K6/JMeter):
|
|
716
|
+
|
|
717
|
+
Step 7a -- Cleanup Policy:
|
|
718
|
+
Ask whether to keep the default -> cleanup_policy='delete' (removes run pods/configmaps/secrets after each execution), or retain them for debugging -> cleanup_policy='retain'. Maps to spec.cleanupPolicy. Mirrors the UI's Advanced Options "Clean-up Load Resources" toggle (ON = delete, OFF = retain).
|
|
719
|
+
|
|
720
|
+
Step 7b -- Resource Requirements (Kubernetes only; OFF by default -- skip unless the user opts in):
|
|
721
|
+
If the user wants to set CPU/memory limits and requests, ask for any of: limits.cpu, limits.memory, requests.cpu, requests.memory (all optional individually). Pass resources={ limits?: {cpu?, memory?}, requests?: {cpu?, memory?} }. cpu is cores/millicores (e.g. "100m", "0.5", "2"); memory is a whole-byte quantity (e.g. "128Mi", "1Gi", "134217728"). Per resource, requests must not exceed limits. Maps to spec.resources. If the user declines, omit 'resources' entirely.
|
|
722
|
+
YAML populated after Step 7 (delta only):
|
|
723
|
+
spec:
|
|
724
|
+
cleanupPolicy: retain # 'delete' when omitted/unset
|
|
725
|
+
resources: # omitted entirely when the user declines Step 7b
|
|
726
|
+
limits:
|
|
727
|
+
cpu: "0.5"
|
|
728
|
+
memory: 1Gi
|
|
729
|
+
requests:
|
|
730
|
+
cpu: 100m
|
|
731
|
+
memory: 128Mi
|
|
732
|
+
Only after the user confirms all of the above (across Steps 1-7) should you call harness_create resource_type=chaos_loadtest. The full input-field reference lives on each field's own description (bodySchema.fields) -- do NOT restate it here.
|
|
733
|
+
Returns the created load test, including the full toolConfig echo (script/tunables/options/envVars as stored), serviceReferences, cleanupPolicy, resources, the base64 canonical yaml, createdAt/updatedAt, and an openInHarness deep link.`;
|
|
734
|
+
export const descDeleteLoadtest = `Delete a load test instance`;
|
|
735
|
+
export const descUpdateLoadtest = `Update fields on an existing load test (PUT -- partial by field, full-replace within a field). Omit a field entirely to leave it unchanged.
|
|
370
736
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
K6 is JavaScript; Locust is Python. K6 currently supports script-mode only (Custom Image and UI are deferred).
|
|
377
|
-
|
|
378
|
-
Step 2 — Select a load-runner infrastructure:
|
|
379
|
-
Linux VM: call harness_list resource_type=chaos_infrastructure, show the list, wait for the user to pick one. Only infras with loadEnabled=true and status ACTIVE can run load tests.
|
|
380
|
-
Kubernetes: call harness_list resource_type=chaos_enabled_infrastructure, show the list, wait for the user to pick one (results are always ACTIVE and chaos-enabled).
|
|
381
|
-
From the chosen row take environmentID -> environment_id and infraID -> infra_id. Do NOT choose an infrastructure yourself.
|
|
382
|
-
|
|
383
|
-
Step 3 — Collect the target (host) URL:
|
|
384
|
-
Ask for the base URL of the application under test (e.g. https://www.google.com) -> target_url. Do NOT assume it.
|
|
385
|
-
|
|
386
|
-
Step 4 — Test configuration (branch on tool_type from Step 1b):
|
|
387
|
-
Locust (Linux VM or Kubernetes):
|
|
388
|
-
(a) Upload Python script (script_source=inline): ask for the raw Python locust script -> script (verbatim; do NOT generate or pre-encode). MCP base64-encodes it into top-level scriptContent.
|
|
389
|
-
(b) Custom Image (script_source=image, Kubernetes only): ask for script_image (+ optional script_entrypoint, load_args).
|
|
390
|
-
K6 (Kubernetes only):
|
|
391
|
-
(a) Upload K6 script (script_source=inline): ask the user to paste the raw K6 JavaScript source. Pass it verbatim in 'script'. MANDATORY rule: the script MUST contain 'export default function ...'. If it does not, REJECT before calling MCP — MCP will throw and no load test will be created. MCP base64-encodes the script into toolConfig.scriptContent; do NOT pre-encode.
|
|
392
|
-
(b) Custom Image (script_source=image): ask for the container image -> script_image (e.g. my-registry/my-load-test:latest); optionally an entrypoint inside the image -> script_entrypoint (e.g. /script.js); optional container args -> load_args. MCP routes script_image and script_entrypoint into BOTH toolConfig.customImage (image, entrypoint) AND inputs[] (scriptImage required:true, scriptEntrypoint required:true); load_args rides ONLY in inputs[name=loadArgs]. No script is needed.
|
|
393
|
-
(c) Define test via UI: NOT YET SUPPORTED via MCP. Inform the user it is deferred and stop.
|
|
394
|
-
Optional K6-only knobs to ask the user about (skip if user says no):
|
|
395
|
-
- host_url: origin of the target system (protocol+host, no path). Defaults to the origin of target_url.
|
|
396
|
-
- rps_limit: requests-per-second cap (toolConfig.options.rpsLimit). Optional.
|
|
397
|
-
- iterations: total iteration cap (toolConfig.iterations). Optional.
|
|
398
|
-
- env_vars: see Step 4c.
|
|
399
|
-
|
|
400
|
-
Step 4c — Optional K6 environment variables (env_vars):
|
|
401
|
-
The env_vars param is a structured array. Each entry sets EITHER a literal value OR a secret reference:
|
|
402
|
-
- Literal: {key: "FOO", value: "bar"}
|
|
403
|
-
- Secret reference: {key: "TOKEN", secret_id: "<harness-secret-identifier>", secret_scope: "account"|"org"|"project"}
|
|
404
|
-
To discover available secrets, call harness_list resource_type=secret type=SecretText. Each list item has
|
|
405
|
-
a nested secret.{identifier, orgIdentifier?, projectIdentifier?}. Derive secret_scope from the response:
|
|
406
|
-
- no orgIdentifier AND no projectIdentifier → secret_scope: "account"
|
|
407
|
-
- orgIdentifier only → secret_scope: "org"
|
|
408
|
-
- both orgIdentifier AND projectIdentifier → secret_scope: "project"
|
|
409
|
-
MCP builds the wire string 'secrets.getValue("<prefix><id>")' (account.<id> / org.<id> / <id>) and sets
|
|
410
|
-
secret: true automatically — do NOT construct the secrets.getValue(...) string yourself.
|
|
411
|
-
Disallowed keys (reserved, case-insensitive): RUN_ID, LOAD_TEST_ID, TARGET_USERS, SPAWN_RATE,
|
|
412
|
-
SCRIPT_CONTENT_BASE64, TARGET_URL, ACCOUNT_ID, ORG_ID, PROJECT_ID, ENV_ID, DURATION_SECONDS,
|
|
413
|
-
CONTROL_PLANE_URL, CONTROL_PLANE_TOKEN, HARNESS_CUSTOM_VAR_NAMES, METRICS_PUSH_INTERVAL, INFRA_ID,
|
|
414
|
-
ACCESS_KEY, TENANT_ID, PYTHONPATH, PATH, HOME, USER, SHELL, LANG, TERM, HOSTNAME, PWD,
|
|
415
|
-
LD_LIBRARY_PATH, LD_PRELOAD, TMPDIR, TMP, TEMP.
|
|
416
|
-
Key pattern: /^[A-Za-z_][A-Za-z0-9_]*$/.
|
|
417
|
-
|
|
418
|
-
Step 5 — Load configuration:
|
|
419
|
-
Ask users, duration_sec, ramp_up_sec (defaults 100 / 600 / 120 only if user accepts).
|
|
420
|
-
K8s: also ask worker_count — do NOT skip (default 0). VM: skip worker_count.
|
|
421
|
-
|
|
422
|
-
Step 6 — Collect name and optional metadata:
|
|
423
|
-
Ask for a name (any non-empty string). identity is auto-derived from name by stripping non-alphanumerics unless the user provides one (must be letters/numbers/underscores). description and tags are optional — ask, but do not require them.
|
|
424
|
-
|
|
425
|
-
Only after the user confirms all of the above should you call harness_create resource_type=chaos_loadtest.
|
|
426
|
-
|
|
427
|
-
HOW THE BODY IS BUILT (you do NOT construct any of this — MCP handles it):
|
|
428
|
-
- Your scalars (users / duration_sec / ramp_up_sec / worker_count / target_url / script_image / script_entrypoint / load_args)
|
|
429
|
-
are translated into a canonical inputs[] array with backend-wire names
|
|
430
|
-
(targetUsers / durationSeconds / rampUpTimeSec / workerCount / targetUrl / scriptImage / scriptEntrypoint / loadArgs).
|
|
431
|
-
- Inline mode (Locust): your raw 'script' is base64-encoded into top-level scriptContent.
|
|
432
|
-
- Image mode (Locust): scriptContent is omitted; script_image / script_entrypoint / load_args ride in inputs[].
|
|
433
|
-
- K6 script mode: top-level scriptContent is OMITTED. The base64 script lives in toolConfig.scriptContent only.
|
|
434
|
-
toolConfig also carries hostUrl, optional options.rpsLimit, optional iterations, and optional envVars.
|
|
435
|
-
- env_vars (K6): structured only. {key, value} for literals; {key, secret_id, secret_scope?} for secrets —
|
|
436
|
-
MCP builds the wire 'secrets.getValue("<prefix><id>")' string and sets secret: true automatically.
|
|
437
|
-
- A canonical LoadTest YAML manifest is synthesized and base64-encoded into the 'yaml' request field.
|
|
438
|
-
- description defaults to "", tags defaults to []. tool_type is fixed to "Locust" server-side (K6/JMeter coming).
|
|
737
|
+
- name / description / tags / environment_id / infra_id / target_type / max_duration_sec: simple scalar replace when supplied.
|
|
738
|
+
- service_references / variables: replace the ENTIRE list when non-null (a non-null service_references must still be non-empty); there is no per-item merge.
|
|
739
|
+
- cleanup_policy / resources: identical top-level spec fields to create -- see their own field descriptions (descLoadtestCleanupPolicy / descLoadtestResources). Not repeated here.
|
|
740
|
+
- Editing the script, image, tunables, properties, thresholds, or env vars (toolConfig.<tool>) requires resupplying the FULL desired sub-object -- the backend overwrites toolConfig.<tool> wholesale on any non-null write (no per-field merge server-side, except variables and JMeter's masked-.zip workspace preservation). You have two ways to do this:
|
|
741
|
+
1. Scalar fields (recommended, mirrors create): supply 'tool_type' (Locust/K6/JMeter -- required, NOT itself sent to the API since tool_type is immutable after creation; used only so MCP picks the right builder) plus any of the same scalar fields create accepts (target_url, script_source, script, script_image, script_entrypoint, load_args, image_pull_secret, users, spawn_rate, duration_sec, ramp_up_sec, worker_count, host_url, rps_limit, iterations, env_vars, properties, thresholds). MCP rebuilds the complete toolConfig.<tool> object from these exactly as it does on create -- you must resupply every scalar that should remain set, not just the ones changing. Field-to-path mapping:
|
|
439
742
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
script (string): Raw Python locust script. VM always requires this; K8s when inline. MCP base64-encodes it into the top-level scriptContent field — do NOT pre-encode.
|
|
446
|
-
script_source (string): "inline" (default) or "image". "image" is K8s-only; VM is always "inline". Inferred as "image" when script_image is set.
|
|
447
|
-
script_image (string): K8s + image mode only — prebuilt container image. Required when script_source=image. Goes into inputs[name=scriptImage, required:true].
|
|
448
|
-
script_entrypoint (string): Custom Image mode — entrypoint file inside the image. Goes into inputs[name=scriptEntrypoint, required:true] when provided.
|
|
449
|
-
load_args (string): Custom Image mode — container args as "k=v,v2;k2=v" pairs. Goes into inputs[name=loadArgs] when provided.
|
|
450
|
-
target_type (string): machine-chaos-linux (Linux VM, default), linux-chaos, or kubernetes.
|
|
451
|
-
users (number, default 100): Number of simulated users. Goes into inputs[name=targetUsers, required:true].
|
|
452
|
-
duration_sec (number, default 600): Total test duration in seconds. Goes into inputs[name=durationSeconds].
|
|
453
|
-
ramp_up_sec (number, default 120): Ramp-up duration in seconds. Goes into inputs[name=rampUpTimeSec].
|
|
454
|
-
worker_count (number, default 0): K8s — agent must ask; default 0. VM: N/A. Goes into inputs[name=workerCount].
|
|
455
|
-
tool_type (string, default "Locust"): "Locust" or "K6". K6 requires target_type=kubernetes.
|
|
456
|
-
host_url (string, K6 only): K6 host origin (protocol://host, no path). Defaults to origin of target_url. Goes into toolConfig.hostUrl.
|
|
457
|
-
rps_limit (number, K6 only): requests-per-second cap. Goes into toolConfig.options.rpsLimit when > 0.
|
|
458
|
-
iterations (number, K6 only): total iteration cap. Goes into toolConfig.iterations when > 0.
|
|
459
|
-
env_vars (array, K6 only): environment variables. Array of {key, value} (literal) or {key, secret_id, secret_scope?} (secret reference). See Step 4c.
|
|
460
|
-
identity (string): Stable slug-safe identifier (letters / numbers / underscores). Auto-derived from name by stripping non-alphanumerics when omitted.
|
|
461
|
-
description (string): Optional human-readable description. Defaults to "".
|
|
462
|
-
tags (string[]): Optional tags. Defaults to [].
|
|
463
|
-
|
|
464
|
-
Returns the created load test (identity, name, environment/infra, targetType, toolType, scriptSource, inputs[], plus derived target_url/users/duration_sec/ramp_up_sec/worker_count convenience scalars) and an openInHarness deep link.`;
|
|
465
|
-
export const descDeleteLoadtest = `Delete a load test instance`;
|
|
743
|
+
${descLoadtestFieldTaxonomy}
|
|
744
|
+
2. 'tool_config' escape hatch: hand-construct the object yourself (e.g. to preserve a JMeter .zip workspace or other advanced shape not covered by scalars). Pass 'tool_type' alongside it so MCP wraps/unwraps consistently with create; omitting 'tool_type' falls back to legacy behavior where 'tool_config' is sent to the API completely as-is (must already be the full \`{ <tool>: {...} }\` wire shape).
|
|
745
|
+
- No 'yaml' manifest is sent on update (unlike create) -- the typed JSON fields above (cleanupPolicy, resources, toolConfig) are authoritative since the backend falls back to them whenever no yaml body is supplied.
|
|
746
|
+
|
|
747
|
+
Returns the updated load test (same shape as harness_get resource_type=chaos_loadtest).`;
|
|
466
748
|
export const descListK8sInfra = `List Kubernetes chaos infrastructures available for running experiments.
|
|
467
749
|
Use chaos_environment list first to get an environmentId, then pass it here to filter infrastructures for that environment.
|
|
468
750
|
Returns infrastructure details including identity, infraID, name, environmentID, status, infraType, infraScope, and isChaosEnabled.
|
|
@@ -801,15 +1083,18 @@ Requires the template identity, hub identity, and two revision numbers.`;
|
|
|
801
1083
|
export const descBodyExperimentRun = `Optional runtime inputs for the chaos experiment. Use chaos_experiment_variable list to discover required variables first.`;
|
|
802
1084
|
export const descBodyNoBody = `No body required. Resource identified by path parameter.`;
|
|
803
1085
|
export const descBodyCreateFromTemplate = `Chaos experiment from template`;
|
|
804
|
-
export const descBodyLoadtestDefinition = `Locust
|
|
805
|
-
MCP translates your scalars into the wire shape automatically:
|
|
806
|
-
- users / duration_sec / ramp_up_sec
|
|
807
|
-
|
|
808
|
-
-
|
|
809
|
-
- script_image / script_entrypoint / load_args
|
|
810
|
-
|
|
1086
|
+
export const descBodyLoadtestDefinition = `Load test definition (Locust / K6 / JMeter). Required: name, environment_id, infra_id, target_url. Mode: 'inline' (upload raw script, default) or 'image' (Custom Image via script_image; Kubernetes only).
|
|
1087
|
+
MCP translates your scalars into the canonical toolConfig.<tool> wire shape automatically:
|
|
1088
|
+
- users / duration_sec / ramp_up_sec / worker_count / target_url
|
|
1089
|
+
→ toolConfig.<tool>.tunables.{targetUsers, durationSeconds, rampUpTimeSec, workerCount, targetUrl}
|
|
1090
|
+
- script (raw Python/JS/JMX) → toolConfig.<tool>.script.content (base64)
|
|
1091
|
+
- script_image / script_entrypoint / load_args / image_pull_secret (image mode)
|
|
1092
|
+
→ toolConfig.<tool>.script.{image, entrypoint, loadArgs, imagePullSecret}
|
|
1093
|
+
- K6 host_url / iterations → toolConfig.k6.tunables.{hostUrl, iterations}
|
|
1094
|
+
- K6 rps_limit → toolConfig.k6.tunables.rpsLimit
|
|
1095
|
+
- env_vars (K6/JMeter) → toolConfig.<tool>.envVars
|
|
811
1096
|
- A canonical LoadTest YAML manifest is built and base64-encoded into a 'yaml' field.
|
|
812
|
-
You never construct
|
|
1097
|
+
You never construct toolConfig, script.content base64, or the yaml field — pass scalars only.`;
|
|
813
1098
|
// ── Field Descriptions ───────────────────────────────────────────────
|
|
814
1099
|
export const descInputsetIdentity = `Optional inputset identity to use for the experiment run`;
|
|
815
1100
|
export const descRuntimeInputs = `Runtime input variables: { experiment: [{name, value}], tasks: { taskName: [{name, value}] } }`;
|
|
@@ -820,27 +1105,32 @@ export const descInfraRef = `Infrastructure reference in format: environmentId/i
|
|
|
820
1105
|
export const descExperimentId = `Chaos experiment identifier. Accepts either the internal UUID (default, with is_identity=false) or the human-readable identity slug (set is_identity=true). Use harness_list with resource_type=chaos_experiment to find experiment IDs.`;
|
|
821
1106
|
export const descInfraStatus = `Filter by infra status: Active (default) or All`;
|
|
822
1107
|
export const descLoadtestName = `Display name for the load test. Any non-empty string (e.g. "My Load Test", "locust-1"). The slug-safe identifier rule applies to 'identity' (auto-derived from name) — not to name.`;
|
|
823
|
-
export const descLoadtestType = `Load test tool type: "Locust" (default; Python on Linux VM or Kubernetes)
|
|
1108
|
+
export const descLoadtestType = `Load test tool type: "Locust" (default; Python on Linux VM or Kubernetes), "K6" (JavaScript, Kubernetes only), or "JMeter" (Java, Kubernetes only in MCP/UI; not a backend restriction). All three support "Upload script" (script mode) and "Using Custom Image" (image mode) as first-class scalar flows; "Define test via UI" is deferred for K6/Locust and does not apply to JMeter.`;
|
|
824
1109
|
export const descLoadtestIdentity = `Stable identifier (letters, numbers and underscores). Auto-derived from name by stripping non-alphanumerics when omitted.`;
|
|
825
1110
|
export const descLoadtestDescription = `Optional human-readable description. Defaults to "".`;
|
|
826
1111
|
export const descLoadtestTags = `Optional tags (array of strings, or comma-separated string). Defaults to [].`;
|
|
827
1112
|
export const descLoadtestEnvId = `Environment identifier of the load-runner infrastructure. Use the 'environmentID' from chaos_infrastructure (Linux VM) or chaos_enabled_infrastructure (Kubernetes).`;
|
|
828
1113
|
export const descLoadtestInfraId = `Load-runner infrastructure identifier. Use the 'infraID' from chaos_infrastructure (Linux VM) or chaos_enabled_infrastructure (Kubernetes).`;
|
|
829
|
-
export const descLoadtestTargetType = `Execution environment target type: "machine-chaos-linux" (Linux VM, default), "linux-chaos", or "kubernetes". "workerCount" is only
|
|
830
|
-
export const descLoadtestTargetUrl = `Base URL of the application under test (e.g. https://www.google.com).
|
|
831
|
-
export const descLoadtestScript = `Raw script contents for inline mode (script_source=inline). Locust expects Python (locustfile.py); K6 expects JavaScript and MUST contain 'export default function ...' (mandatory — MCP rejects scripts without it). MCP base64-encodes onto the wire — do NOT pre-encode.
|
|
832
|
-
export const descLoadtestScriptSource = `Test definition source: "inline" (default — upload a raw
|
|
833
|
-
export const descLoadtestScriptImage = `Custom Image mode (
|
|
834
|
-
export const descLoadtestScriptEntrypoint = `Custom Image mode
|
|
835
|
-
export const descLoadtestLoadArgs = `Custom Image mode (optional
|
|
836
|
-
export const
|
|
837
|
-
export const
|
|
838
|
-
export const
|
|
839
|
-
export const
|
|
1114
|
+
export const descLoadtestTargetType = `Execution environment target type: "machine-chaos-linux" (Linux VM, default), "linux-chaos", or "kubernetes". "workerCount" is only honoured for "kubernetes".`;
|
|
1115
|
+
export const descLoadtestTargetUrl = `Base URL of the application under test (e.g. https://www.google.com). Maps to toolConfig.<tool>.tunables.targetUrl. For Locust it is passed as --host; leave blank if the locustfile sets host in code.`;
|
|
1116
|
+
export const descLoadtestScript = `Raw script contents for inline mode (script_source=inline). Locust expects Python (locustfile.py); K6 expects JavaScript and MUST contain 'export default function ...' (mandatory — MCP rejects scripts without it); JMeter expects the raw .jmx/.xml test plan text (verbatim; for a .zip bundle use tool_config.jmeter.script.content with a pre-computed base64 string instead). MCP base64-encodes onto the wire — do NOT pre-encode. Lands at toolConfig.<tool>.script.content for all three tools. Required for inline mode; omit for Custom Image mode.`;
|
|
1117
|
+
export const descLoadtestScriptSource = `Test definition source: "inline" (default — upload a raw script via 'script') or "image" (use a prebuilt container image via 'script_image'). "image" is K8s-only; VM is always "inline". Inferred as "image" when script_image is set, otherwise "inline".`;
|
|
1118
|
+
export const descLoadtestScriptImage = `Custom Image mode (Locust/K6/JMeter, Kubernetes only): prebuilt container image used as the load test source, e.g. "my-registry/my-load-test:latest". Required when script_source=image. Maps to toolConfig.<tool>.script.image.`;
|
|
1119
|
+
export const descLoadtestScriptEntrypoint = `Custom Image mode: entrypoint file inside the image. Locust: locustfile path (optional; passed to locust -f), e.g. "locustfile.py". K6: script path (optional; passed to k6 run), e.g. "/script.js". JMeter: path to the .jmx/.xml test plan (optional; backend uses a default plan-file name when omitted), e.g. "/test/plan.jmx". Runtime placeholder '<+input>' is accepted verbatim. Maps to toolConfig.<tool>.script.entrypoint.`;
|
|
1120
|
+
export const descLoadtestLoadArgs = `Custom Image mode (optional): container args as semicolon-separated key=value pairs (commas allowed inside a value). Keys must be non-empty, contain no whitespace, and must NOT start with '-' (bare CLI flags like "--headless" are rejected -- mirrors loadTestManager ValidateLoadArgs). Locust/K6: passed to the tool as CLI args (e.g. "tags=smoke,fast;headless=true"). JMeter: GNU-style long options -- each pair becomes --key=value (e.g. "proxyHost=10.0.0.1;forceDeleteResultFile"). Do NOT put JMeter properties (jmeter.save.saveservice.* or \${__P(...)} plan variables) here -- use 'properties' (which become -J/-G). Maps to toolConfig.<tool>.script.loadArgs.`;
|
|
1121
|
+
export const descLoadtestImagePullSecret = `Custom Image mode (Kubernetes, private registry only): name of the Kubernetes image-pull secret used to pull script_image. Maps to toolConfig.<tool>.script.imagePullSecret. Omit for public images (UI "Image Registry Type = Public"); there is no separate Public/Private field on the wire — presence of this scalar is the private signal.`;
|
|
1122
|
+
export const descLoadtestUsers = `Number of simulated users. Default: 100. Maps to toolConfig.<tool>.tunables.targetUsers.`;
|
|
1123
|
+
export const descLoadtestDurationSec = `Total test duration in seconds. Default: 600. Maps to toolConfig.<tool>.tunables.durationSeconds.`;
|
|
1124
|
+
export const descLoadtestRampUpSec = `Ramp-up duration in seconds. Default: 120. Maps to toolConfig.<tool>.tunables.rampUpTimeSec.`;
|
|
1125
|
+
export const descLoadtestWorkerCount = `K8s: agent must ask; default 0 (0 = standalone). VM: N/A (ignored for Linux target types). Goes to toolConfig.<tool>.tunables.workerCount. Semantics differ per tool: Locust DISTRIBUTES users across workers (load not multiplied); K6 <=1 is a single pod and higher values fan out via --execution-segment; JMeter MULTIPLIES load -- each worker runs the full uploaded plan unchanged.`;
|
|
840
1126
|
export const descLoadtestHostUrl = `K6 only: host origin (protocol+host with no path, e.g. https://api.example.com). Defaults to the origin parsed from target_url when omitted. Goes into toolConfig.hostUrl.`;
|
|
841
|
-
export const descLoadtestRpsLimit = `K6 only: requests-per-second cap. Goes into toolConfig.
|
|
1127
|
+
export const descLoadtestRpsLimit = `K6 only: requests-per-second cap. Goes into toolConfig.k6.tunables.rpsLimit when > 0. Omitted from the wire when unset or 0.`;
|
|
842
1128
|
export const descLoadtestIterations = `K6 only: total iteration cap. Goes into toolConfig.iterations when > 0. Omitted from the wire when unset or 0.`;
|
|
843
|
-
export const descLoadtestEnvVars = `K6 only: environment variables for the
|
|
1129
|
+
export const descLoadtestEnvVars = `K6 and JMeter only: environment variables for the runner. Array of entries — each sets EITHER {key, value} for a literal OR {key, secret_id, secret_scope?: "account"|"org"|"project"} for a Harness secret (default secret_scope = "project"). MCP builds the wire 'secrets.getValue("<prefix><id>")' string and sets secret: true automatically — do NOT construct that string yourself. Discover secrets via harness_list resource_type=secret type=SecretText and read each item's secret.{identifier, orgIdentifier?, projectIdentifier?} to derive scope. Key pattern: /^[A-Za-z_][A-Za-z0-9_]*$/. Reserved names (case-insensitive), rejected for BOTH tools: RUN_ID, LOAD_TEST_ID, TARGET_USERS, SPAWN_RATE, SCRIPT_CONTENT_BASE64, TARGET_URL, ACCOUNT_ID, ORG_ID, PROJECT_ID, ENV_ID, DURATION_SECONDS, CONTROL_PLANE_URL, CONTROL_PLANE_TOKEN, HARNESS_CUSTOM_VAR_NAMES, METRICS_PUSH_INTERVAL, INFRA_ID, ACCESS_KEY, TENANT_ID, PYTHONPATH, PATH, HOME, USER, SHELL, LANG, TERM, HOSTNAME, PWD, LD_LIBRARY_PATH, LD_PRELOAD, TMPDIR, TMP, TEMP. K6 ALSO rejects: HOST_URL, K6_VUS, K6_DURATION, K6_ITERATIONS, K6_STAGES, K6_RPS.`;
|
|
1130
|
+
export const descLoadtestCleanupPolicy = `'delete' (default) or 'retain' -- controls whether run resources (pods, configmaps, secrets) are removed after each execution. Choose 'retain' to keep them around for debugging. Maps to spec.cleanupPolicy. Identical field for Locust/K6/JMeter. Mirrors the UI's Advanced Options "Clean-up Load Resources" toggle (ON = delete, OFF = retain).`;
|
|
1131
|
+
export const descLoadtestResources = `Kubernetes-only per-pod resource limits and requests (UI: Advanced Options > Resource Requirements; OFF by default -- omit entirely unless the user opts in). Object shape: { limits?: { cpu?, memory? }, requests?: { cpu?, memory? } }. cpu is cores/millicores (e.g. "100m", "0.5", "2"); memory is a whole-byte quantity (e.g. "128Mi", "1Gi", "134217728"). Only 'cpu' and 'memory' keys are allowed in each section. Per resource, requests must not exceed limits. Maps to spec.resources. Identical field for Locust/K6/JMeter.`;
|
|
1132
|
+
export const descLoadtestProperties = "JMeter only: runtime property overrides injected into the plan without editing the uploaded file -- reference as ${__P(NAME)} in the .jmx. Array of {key, value, send_to_engines?}. send_to_engines (maps to sendToEngines / the JMeter -G flag) controls whether the property also reaches remote Distributed Execution workers; omit (false) for controller-only properties.";
|
|
1133
|
+
export const descLoadtestThresholds = "JMeter only: pass/fail criteria evaluated against the run's .jtl results after the test completes (the uploaded plan's own Assertions still apply per-request during the run). Array of {metric, stat?, operator, value, abort_on_fail?}. metric: one of response_time_ms | error_rate_pct | throughput_rps | latency_ms. operator: one of < | <= | > | >= | == | !=. stat (e.g. p95, p99, avg, median, max) is REQUIRED when metric is response_time_ms or latency_ms. abort_on_fail (maps to abortOnFail) marks the threshold as run-aborting on failure.";
|
|
844
1134
|
export const descHubIdentityExact = `The unique identity of the ChaosHub. Use harness_list with resource_type=chaos_hub to find hub identities.`;
|
|
845
1135
|
export const descHubName = `Display name for the ChaosHub.`;
|
|
846
1136
|
export const descHubNameUpdate = `Updated display name for the ChaosHub.`;
|
|
@@ -1285,8 +1575,13 @@ export const descExperimentCronSyntax = `Optional cron expression for scheduling
|
|
|
1285
1575
|
// Shared filter / behavior descriptions
|
|
1286
1576
|
export const descSDAgentIdentity = `Service Discovery agent identity — the path segment shown in the SD UI URL (e.g. 'chaosinfra'). Each agent is bound to one Harness environment and one Kubernetes cluster.`;
|
|
1287
1577
|
export const descSDEnvironmentId = `Harness environment identifier the SD agent is bound to (e.g. 'dev'). Required by SD's AgentAccessCheck middleware to resolve the agent — the same agent identity may exist in multiple environments.`;
|
|
1578
|
+
export const descSDAgentListEnvironmentId = `Optional narrowing filter — the LIST agents endpoint does not require it (unlike discovered_namespace/discovered_service/discovered_network_map, which use AgentAccessCheck and require both agent_identity + environment_id). Omit to list agents across every environment in scope.`;
|
|
1288
1579
|
export const descSDFetchAll = `When true, fetch every result and ignore page/limit (the API returns the full unpaginated list). Useful for small/medium clusters; avoid on very large clusters.`;
|
|
1289
|
-
export const descSDAgentDiagnostic = `404 from SD endpoints almost always means agent_identity or environment_id is wrong — both are required for AgentAccessCheck to resolve the agent. Both can be confirmed from the SD UI URL or
|
|
1580
|
+
export const descSDAgentDiagnostic = `404 from SD endpoints almost always means agent_identity or environment_id is wrong — both are required for AgentAccessCheck to resolve the agent. Both can be confirmed from the SD UI URL or via discovered_agent list.`;
|
|
1581
|
+
// discovered_agent
|
|
1582
|
+
export const descDiscoveredAgent = `Service Discovery agent — one SD deployment running inside a customer's Kubernetes cluster, bound to a single Harness environment. Its 'identity' field is the value other resources take as 'agent_identity' (discovered_namespace / discovered_service / discovered_network_map) and as 'agent_id' (chaos_service create/update). Soft-deleted agents are hidden from list results. The token field is never returned.`;
|
|
1583
|
+
export const descListDiscoveredAgents = `List Service Discovery agents in the given account/org/project scope. Use this to look up the 'identity' value required by other Service Discovery resources and by chaos_service create/update. Optional environment_id narrows to one environment; omit to list agents across all environments in scope. Optional search does a case-insensitive regex match on the agent name. Supports page/limit pagination or all=true to fetch everything (all=true also skips per-agent installation/service/network-map count enrichment, so responses are lighter).`;
|
|
1584
|
+
export const descDiscoveredAgentSearch = `Case-insensitive substring match against the SD agent name field.`;
|
|
1290
1585
|
// discovered_namespace
|
|
1291
1586
|
export const descDiscoveredNamespace = `Read-only snapshot of a Kubernetes Namespace recorded by a Service Discovery agent — includes the namespace name, UID, resource version, labels, annotations, owner references, and the full corev1.NamespaceSpec/Status from the cluster's last sync. Use namespaces as the scope boundary when listing discovered_service or future discovered_workload/discovered_connection resources for the same agent.`;
|
|
1292
1587
|
export const descListDiscoveredNamespaces = `List Kubernetes namespaces snapshotted by a Service Discovery agent. Requires agent_identity (path) and environment_id (query). Returns soft-deleted-aware results (only live namespaces). Optional name filter (exact match, NOT substring — see name field doc). Supports page/limit pagination or all=true to fetch everything.`;
|