Repository: grafana/k6-operator
Pull request #135 (2022-08-02 10:41:35)

feat: use name instead of index for instance id tag
Currently,  the tag used for instance id is the index of the job. But, if you run multiple K6 resources at the same time, there is no way to distinguish them.

Here I propose to use the name of the job, instead of the index of the job

CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/grafana/k6-operator?pullRequest=135) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/grafana/k6-operator?pullRequest=135) before we can accept your contribution.<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/grafana/k6-operator?pullRequest=135) it.</sub>
yorugac: Hi @spoukke,
Thanks for the PR and sorry for the delay! We cannot change `instance_id`: the whole point of `instance_id` tag is to distinguish between pods, not jobs. I suggest changing it to `job_name` tag instead and leaving `instance_id` as is. Would it work for your case?

Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml
new file mode 100644
index 0000000..7ee742a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug.yaml
@@ -0,0 +1,44 @@
+---
+name: Bug report
+description: Use this template for reporting bugs. Please search existing issues first.
+labels: bug
+body:
+  - type: textarea
+    attributes:
+      label: Brief summary
+    validations:
+      required: true
+  - type: markdown
+    attributes:
+      value: '## Environment'
+  - type: input
+    attributes:
+      label: k6-operator version or image
+    validations:
+      required: true
+  - type: input
+    attributes:
+      label: K6 YAML
+    validations:
+      required: true
+  - type: input
+    attributes:
+      label: Other environment details (if applicable)
+  - type: markdown
+    attributes:
+      value: '## Detailed issue description'
+  - type: textarea
+    attributes:
+      label: Steps to reproduce the problem
+    validations:
+      required: true
+  - type: textarea
+    attributes:
+      label: Expected behaviour
+    validations:
+      required: true
+  - type: textarea
+    attributes:
+      label: Actual behaviour
+    validations:
+      required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..05a77e7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,6 @@
+---
+blank_issues_enabled: true
+contact_links:
+  - name: k6 Community Forum
+    url: https://community.k6.io/
+    about: Please ask and answer questions here.
diff --git a/.github/ISSUE_TEMPLATE/feat_req.yaml b/.github/ISSUE_TEMPLATE/feat_req.yaml
new file mode 100644
index 0000000..8962b96
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feat_req.yaml
@@ -0,0 +1,19 @@
+---
+name: Feature Request
+description: Use this template for suggesting new features.
+labels: enhancement
+body:
+  - type: textarea
+    attributes:
+      label: Feature Description
+      description: A clear and concise description of the problem or missing capability
+    validations:
+      required: true
+  - type: textarea
+    attributes:
+      label: Suggested Solution (optional)
+      description: If you have a solution in mind, please describe it.
+  - type: textarea
+    attributes:
+      label: Already existing or connected issues / PRs (optional)
+      description: If you have found some issues or pull requests that are related to your new issue, please link them here.
diff --git a/Dockerfile.controller b/Dockerfile.controller
index 77e50ae..b4d5524 100644
--- a/Dockerfile.controller
+++ b/Dockerfile.controller
@@ -1,5 +1,6 @@
+ARG GO_BUILDER_IMG
 # Build the manager binary
-FROM golang:1.17 as builder
+FROM ${GO_BUILDER_IMG} as builder
 
 WORKDIR /workspace
 # Copy the Go Modules manifests
diff --git a/Makefile b/Makefile
index dcae55f..8970099 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,8 @@ BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL)
 endif
 BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)
 
+# Image to use for building Go
+GO_BUILDER_IMG ?= "golang:1.17"
 # Image URL to use all building/pushing image targets
 IMG ?= ghcr.io/grafana/operator:latest
 # Default dockerfile to build
@@ -100,7 +102,7 @@ generate: controller-gen
 
 # Build the docker image
 docker-build: test
-	docker build . -t ${IMG} -f ${DOCKERFILE}
+	docker build . -t ${IMG} -f ${DOCKERFILE} --build-arg GO_BUILDER_IMG=${GO_BUILDER_IMG}
 
 # Push the docker image
 docker-push:
diff --git a/README.md b/README.md
index 9f271d6..fff14e2 100644
--- a/README.md
+++ b/README.md
@@ -41,17 +41,59 @@ $ kubectl create configmap my-test --from-file /path/to/my/test.js
 
 #### VolumeClaim
 
-If you have a PVC with the name `stress-test` containing your script and any other supporting file(s), you can pass it to the test like this:
+There is a sample avaiable in `config/samples/k6_v1alpha1_k6_with_volumeClaim.yaml` on how to configure to run a test script with a volumeClaim.
+
+If you have a PVC with the name `stress-test-volumeClaim` containing your script and any other supporting file(s), you can pass it to the test like this:
 
 ```
 spec:
   parallelism: 2
   script:
     volumeClaim:
-      name: "stress-test"
+      name: "stress-test-volumeClaim"
       file: "test.js"
 ```
 
+***Note:*** the pods will expect to find script files in `/test/` folder. If `volumeClaim` fails, it's the first place to check: the latest initializer pod does not generate any logs and when it can't find the file, it will terminate with error. So missing file may not be that obvious and it makes sense to check it manually. See #143 for potential improvements.
+
+##### Example directory structure while using volumeClaim
+
+```
+├── test
+│   ├── requests
+│   │   ├── stress-test.js
+│   ├── test.js
+```
+In the above example, `test.js` imports a function from `stress-test.js` and they would look like this:
+```js
+// stress-test.js
+import stress-test from "./requests/stress-test.js";
+
+export let options = {
+      vus: 50,
+      duration: '10s'
+    };
+
+export default function () {
+      stress-test();
+}
+```
+```js
+// stress-test.js
+import { sleep, check } from 'k6';
+import http from 'k6/http';
+
+
+export default () => {
+  const res = http.get('https://test-api.k6.io');
+  check(res, {
+    'status is 200': () => res.status === 200,
+  });
+  sleep(1);
+};
+
+```
+
 #### LocalFile
 
 There is a sample avaiable in `config/samples/k6_v1alpha1_k6_with_localfile.yaml` on how to configure to run a test script inside the docker image.
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 4164701..778b742 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -211,6 +211,13 @@ func (in *Pod) DeepCopyInto(out *Pod) {
 	}
 	in.Resources.DeepCopyInto(&out.Resources)
 	in.SecurityContext.DeepCopyInto(&out.SecurityContext)
+	if in.EnvFrom != nil {
+		in, out := &in.EnvFrom, &out.EnvFrom
+		*out = make([]v1.EnvFromSource, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Pod.
diff --git a/config/crd/bases/k6.io_k6s.yaml b/config/crd/bases/k6.io_k6s.yaml
index 88c6665..bb090d2 100644
--- a/config/crd/bases/k6.io_k6s.yaml
+++ b/config/crd/bases/k6.io_k6s.yaml
@@ -813,7 +813,6 @@ spec:
                       - name
                       type: object
                     type: array
-                  # ref: https://github.com/kubernetes/kubernetes/blob/7e2c02d4c86d73051b6d4f47298d35a7ffb42b6a/api/openapi-spec/v3/apis__apps__v1_openapi.json#L1681
                   envFrom:
                     items:
                       description: EnvFromSource represents the source of a set of
diff --git a/config/samples/k6_v1alpha1_k6_with_volumeClaim.yaml b/config/samples/k6_v1alpha1_k6_with_volumeClaim.yaml
new file mode 100644
index 0000000..653a23c
--- /dev/null
+++ b/config/samples/k6_v1alpha1_k6_with_volumeClaim.yaml
@@ -0,0 +1,14 @@
+apiVersion: k6.io/v1alpha1
+kind: K6
+metadata:
+  name: k6-sample
+  namespace: load-test
+spec:
+  parallelism: 4
+  script:
+    volumeClaim:
+      name: stress-test-volumeClaim
+      # test.js should exist inside /test/ folder.
+      # And, All the js files and directories test.js
+      # is importing from should be inside the same directory as well.
+      file: test.js
diff --git a/controllers/k6_start.go b/controllers/k6_start.go
index 4cc90f1..8355efe 100644
--- a/controllers/k6_start.go
+++ b/controllers/k6_start.go
@@ -69,7 +69,7 @@ func StartJobs(ctx context.Context, log logr.Logger, k6 *v1alpha1.K6, r *K6Recon
 		}
 
 		for _, service := range sl.Items {
-			hostnames = append(hostnames, service.ObjectMeta.Name)
+			hostnames = append(hostnames, service.Spec.ClusterIP)
 
 			if !isServiceReady(log, &service) {
 				log.Info(fmt.Sprintf("%v service is not ready, aborting", service.ObjectMeta.Name))
diff --git a/pkg/resources/containers/curl.go b/pkg/resources/containers/curl.go
index f8e8bd4..d3fcf34 100644
--- a/pkg/resources/containers/curl.go
+++ b/pkg/resources/containers/curl.go
@@ -38,6 +38,7 @@ func NewCurlContainer(hostnames []string, image string, command []string, env []
 				corev1.ResourceMemory: *resource.NewQuantity(2097152, resource.BinarySI),
 			},
 			Limits: corev1.ResourceList{
+				corev1.ResourceCPU:    *resource.NewMilliQuantity(100, resource.DecimalSI),
 				corev1.ResourceMemory: *resource.NewQuantity(209715200, resource.BinarySI),
 			},
 		},
diff --git a/pkg/resources/jobs/runner.go b/pkg/resources/jobs/runner.go
index acf5451..86b6c1d 100644
--- a/pkg/resources/jobs/runner.go
+++ b/pkg/resources/jobs/runner.go
@@ -68,6 +68,9 @@ func NewRunnerJob(k6 *v1alpha1.K6, index int, testRunId, token string) (*batchv1
 	// Add an instance tag: in case metrics are stored, they need to be distinguished by instance
 	command = append(command, "--tag", fmt.Sprintf("instance_id=%d", index))
 
+	// Add an job tag: in case metrics are stored, they need to be distinguished by job
+	command = append(command, "--tag", fmt.Sprintf("job_name=%s", name))
+
 	command = script.UpdateCommand(command)
 
 	var (


Test patch:
diff --git a/.github/workflows/e2e-test.yaml b/.github/workflows/e2e-test.yaml
index b2b36a6..6dec237 100644
--- a/.github/workflows/e2e-test.yaml
+++ b/.github/workflows/e2e-test.yaml
@@ -22,6 +22,8 @@ jobs:
           context: .
           file: Dockerfile.controller
           push: true
+          build-args: |
+            GO_BUILDER_IMG=golang:1.17
           tags: |
             ghcr.io/grafana/operator:${{ github.sha }}
   kind:
diff --git a/pkg/resources/jobs/runner_test.go b/pkg/resources/jobs/runner_test.go
index 2ba36de..9aa3011 100644
--- a/pkg/resources/jobs/runner_test.go
+++ b/pkg/resources/jobs/runner_test.go
@@ -289,7 +289,7 @@ func TestNewRunnerJob(t *testing.T) {
 					Containers: []corev1.Container{{
 						Image:        "ghcr.io/grafana/operator:latest-runner",
 						Name:         "k6",
-						Command:      []string{"k6", "run", "--quiet", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1"},
+						Command:      []string{"k6", "run", "--quiet", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1", "--tag", "job_name=test-1"},
 						Env:          []corev1.EnvVar{},
 						Resources:    corev1.ResourceRequirements{},
 						VolumeMounts: script.VolumeMount(),
@@ -399,7 +399,7 @@ func TestNewRunnerJobNoisy(t *testing.T) {
 					Containers: []corev1.Container{{
 						Image:        "ghcr.io/grafana/operator:latest-runner",
 						Name:         "k6",
-						Command:      []string{"k6", "run", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1"},
+						Command:      []string{"k6", "run", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1", "--tag", "job_name=test-1"},
 						Env:          []corev1.EnvVar{},
 						Resources:    corev1.ResourceRequirements{},
 						VolumeMounts: script.VolumeMount(),
@@ -492,7 +492,7 @@ func TestNewRunnerJobUnpaused(t *testing.T) {
 					Containers: []corev1.Container{{
 						Image:        "ghcr.io/grafana/operator:latest-runner",
 						Name:         "k6",
-						Command:      []string{"k6", "run", "--quiet", "/test/test.js", "--address=0.0.0.0:6565", "--tag", "instance_id=1"},
+						Command:      []string{"k6", "run", "--quiet", "/test/test.js", "--address=0.0.0.0:6565", "--tag", "instance_id=1", "--tag", "job_name=test-1"},
 						Env:          []corev1.EnvVar{},
 						Resources:    corev1.ResourceRequirements{},
 						VolumeMounts: script.VolumeMount(),
@@ -585,7 +585,7 @@ func TestNewRunnerJobArguments(t *testing.T) {
 					Containers: []corev1.Container{{
 						Image:        "ghcr.io/grafana/operator:latest-runner",
 						Name:         "k6",
-						Command:      []string{"k6", "run", "--quiet", "--cool-thing", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1"},
+						Command:      []string{"k6", "run", "--quiet", "--cool-thing", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1", "--tag", "job_name=test-1"},
 						Env:          []corev1.EnvVar{},
 						Resources:    corev1.ResourceRequirements{},
 						VolumeMounts: script.VolumeMount(),
@@ -679,7 +679,7 @@ func TestNewRunnerJobServiceAccount(t *testing.T) {
 					Containers: []corev1.Container{{
 						Image:        "ghcr.io/grafana/operator:latest-runner",
 						Name:         "k6",
-						Command:      []string{"k6", "run", "--quiet", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1"},
+						Command:      []string{"k6", "run", "--quiet", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1", "--tag", "job_name=test-1"},
 						Env:          []corev1.EnvVar{},
 						Resources:    corev1.ResourceRequirements{},
 						VolumeMounts: script.VolumeMount(),
@@ -774,7 +774,7 @@ func TestNewRunnerJobIstio(t *testing.T) {
 					Containers: []corev1.Container{{
 						Image:   "ghcr.io/grafana/operator:latest-runner",
 						Name:    "k6",
-						Command: []string{"scuttle", "k6", "run", "--quiet", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1"},
+						Command: []string{"scuttle", "k6", "run", "--quiet", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1", "--tag", "job_name=test-1"},
 						Env: []corev1.EnvVar{
 							{
 								Name:  "ENVOY_ADMIN_API",
@@ -881,7 +881,7 @@ func TestNewRunnerJobCloud(t *testing.T) {
 					Containers: []corev1.Container{{
 						Image:   "ghcr.io/grafana/operator:latest-runner",
 						Name:    "k6",
-						Command: []string{"k6", "run", "--quiet", "--out", "cloud", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1"},
+						Command: []string{"k6", "run", "--quiet", "--out", "cloud", "/test/test.js", "--address=0.0.0.0:6565", "--paused", "--tag", "instance_id=1", "--tag", "job_name=test-1"},
 						Env: []corev1.EnvVar{
 							{
 								Name:  "K6_CLOUD_PUSH_REF_ID",
@@ -979,7 +979,7 @@ func TestNewRunnerJobLocalFile(t *testing.T) {
 					Containers: []corev1.Container{{
 						Image:        "ghcr.io/grafana/operator:latest-runner",
 						Name:         "k6",
-						Command:      []string{"sh", "-c", "if [ ! -f /test/test.js ]; then echo \"LocalFile not found exiting...\"; exit 1; fi;\nk6 run --quiet /test/test.js --address=0.0.0.0:6565 --paused --tag instance_id=1"},
+						Command:      []string{"sh", "-c", "if [ ! -f /test/test.js ]; then echo \"LocalFile not found exiting...\"; exit 1; fi;\nk6 run --quiet /test/test.js --address=0.0.0.0:6565 --paused --tag instance_id=1 --tag job_name=test-1"},
 						Env:          []corev1.EnvVar{},
 						Resources:    corev1.ResourceRequirements{},
 						VolumeMounts: script.VolumeMount(),