Skip to content

Conversation

@Kristina-Pianykh
Copy link
Contributor

@Kristina-Pianykh Kristina-Pianykh commented Nov 16, 2025

This PR introduces an option to disable the initializer phase in a TestRun, allowing users to skip creating the initializer Job.

Key Changes

  1. spec.initializer.disabled added to the CRD with the default False value

Why use disabled instead of enabled?
To preserve backward compatibility.
If we introduced enabled, omitting it would default to false and unintentionally disable the initializer for existing users. Using disabled avoids this problem: omitting the field preserves the current behavior.

  1. New field Disabled added to the Pod struct

The initializer, starter, and runner are all represented using the same Pod type. Adding the field directly to this type ensures the API remains backward-compatible.

Why store it on Pod instead of creating a new InitializerPod type?
I explored creating a dedicated struct to have the new field for the initializer only like so:

type InitializerPod struct {
	Disabled bool `json:"disabled,omitempty"`
	Pod      `json:",inline"`
}

but this approach introduced several issues:

  • The initializer would become a different Go type, requiring changes across API usage.
  • Existing client code instantiating a TestRun in Go would break since initializer would no longer be a simple Pod:
&v1alpha1.TestRun{
    Spec: v1alpha1.TestRunSpec{
        Initializer: v1alpha1.InitializerSpec{
            Pod: v1alpha1.Pod{
                Image: "grafana/k6:latest",
            },
            Disable: false,
        },
...
}

For these reasons, I considered extending the existing Pod type as the least disruptive option.

  1. Updated TestRun lifecycle when initializer is disabled

When the initializer is disabled, stage transitions skip "initialization". The lifecycle becomes:
"""initialized" → …

  1. New condition: InitializerSkipped

A new condition type is introduced to explicitly record whether the initializer was skipped. Both True and False states are used to differentiate intentional skipping from default behavior.

  1. CRD schema and generated documentation updated

e2e Test

I've tried the e2e setup following the instructions in e2e/README.md but the first test run gets stuck with no logs to troubleshoot. For this reason, I provide my own scripts to test:

Initializer skipped
#!/usr/bin/env bash

kind create cluster

# build docker image from the k6-operator directory, load into the cluster and deploy the controller
IMG_NAME=k6operator IMG_TAG=foo make docker-build
kind load docker-image k6operator:foo
IMG_NAME=k6operator IMG_TAG=foo make deploy

# create a minimal k6 script `test.js`
rm test.js
cat <<'EOF' > test.js
import http from 'k6/http';

export default function () {
  const url = 'https://quickpizza.grafana.com/api/users/token/login';
  const payload = JSON.stringify({
    username: 'default',
    password: '12345678',
  });

  const params = {
    headers: {
      'Content-Type': 'application/json',
    },
  };

  // send a post request and save response as a variable
  const res = http.post(url, payload, params);
  sleep(5);
}
EOF

# create a configmap from the k6 script
kubectl create configmap my-k6 --from-file test.js -o yaml --dry-run=client | kubectl apply -f -

rm testrun.yaml
cat <<'EOF' > testrun.yaml
apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
  name: my-k6-test
  namespace: default
spec:
  initializer:
    disabled: true
  parallelism: 1
  script:
    configMap:
      name: my-k6
      file: test.js
  quiet: "false"    # get full logs
EOF

# apply the testrun
kubectl apply -f testrun.yaml
Backward compatible initialization
#!/usr/bin/env bash

kind create cluster

# build docker image from the k6-operator directory, load into the cluster and deploy the controller
IMG_NAME=k6operator IMG_TAG=foo make docker-build
kind load docker-image k6operator:foo
IMG_NAME=k6operator IMG_TAG=foo make deploy

# create a minimal k6 script `test.js`
rm test.js
cat <<'EOF' > test.js
import http from 'k6/http';

export default function () {
  const url = 'https://quickpizza.grafana.com/api/users/token/login';
  const payload = JSON.stringify({
    username: 'default',
    password: '12345678',
  });

  const params = {
    headers: {
      'Content-Type': 'application/json',
    },
  };

  // send a post request and save response as a variable
  const res = http.post(url, payload, params);
  sleep(5);
}
EOF

# create a configmap from the k6 script
kubectl create configmap my-k6 --from-file test.js -o yaml --dry-run=client | kubectl apply -f -

rm testrun.yaml
cat <<'EOF' > testrun.yaml
apiVersion: k6.io/v1alpha1
kind: TestRun
metadata:
  name: my-k6-test
  namespace: default
spec:
  parallelism: 1
  script:
    configMap:
      name: my-k6
      file: test.js
  quiet: "false"    # get full logs
EOF

# apply the testrun
kubectl apply -f testrun.yaml

Resolves #657

@Kristina-Pianykh Kristina-Pianykh force-pushed the allow-disabling-initializer branch from 0b9c270 to e456acd Compare November 16, 2025 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Option in TestRun CRD to switch off initializer

1 participant