Skip to content

Commit

Permalink
Merge pull request #93 from grafana/paul/move-helper-apis
Browse files Browse the repository at this point in the history
Migrate the implementation for pods.exec and jobs.wait to helpers
  • Loading branch information
javaducky authored Apr 19, 2023
2 parents 9cc90f2 + 010d4b3 commit 1955c37
Show file tree
Hide file tree
Showing 16 changed files with 313 additions and 135 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,14 @@ export default function () {
### (Deprecated) `Client.jobs`
| Method | Description | Example |
| ------------ | ------ | --------------------------------------- |
| apply | creates the Kubernetes resource given a YAML configuration ||
| create | creates the Kubernetes resource given an object configuration | [create-job-wait.js](./examples/create-job-wait.js) |
| delete | removes the named Job | |
| get | returns the named Jobs | |
| list | returns a collection of Jobs | |
| wait | wait for all Jobs to complete | [wait-job.js](./examples/wait-job.js) |
| Method | Description |
| ------------ | ------ |
| apply | creates the Kubernetes resource given a YAML configuration |
| create | creates the Kubernetes resource given an object configuration |
| delete | removes the named Job |
| get | returns the named Jobs |
| list | returns a collection of Jobs |
| wait | wait for all Jobs to complete |
```javascript
import { Kubernetes } from 'k6/x/kubernetes';
Expand Down
29 changes: 0 additions & 29 deletions examples/create-job-wait.js

This file was deleted.

42 changes: 0 additions & 42 deletions examples/exec-command.js

This file was deleted.

14 changes: 8 additions & 6 deletions examples/job_operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,25 @@ export default function () {
describe('JSON-based resources', () => {
const name = json.metadata.name
const ns = json.metadata.namespace
const helpers = kubernetes.helpers(ns)

let job

describe('Create our job using the JSON definition', () => {
describe('Create our job using the JSON definition and wait until completed', () => {
job = kubernetes.create(json)
expect(job.metadata, 'new job').to.have.property('uid')
})

describe('Retrieve all available jobs', () => {
expect(kubernetes.list("Job.batch", ns).length, 'total jobs').to.be.at.least(1)
})
let timeout = 10
expect(helpers.waitJobCompleted(name, timeout), `job completion within ${timeout}s`).to.be.true

describe('Retrieve our job by name and namespace', () => {
let fetched = kubernetes.get("Job.batch", name, ns)
expect(job.metadata.uid, 'created and fetched uids').to.equal(fetched.metadata.uid)
})

describe('Retrieve all available jobs', () => {
expect(kubernetes.list("Job.batch", ns).length, 'total jobs').to.be.at.least(1)
})

describe('Remove our jobs to cleanup', () => {
kubernetes.delete("Job.batch", name, ns)
})
Expand Down
14 changes: 13 additions & 1 deletion examples/pod_operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,21 @@ export default function () {
expect(kubernetes.list("Pod", ns).length, 'total pods').to.be.at.least(1)
})

describe('Retrieve our pod by name and namespace', () => {
describe('Retrieve our pod by name and namespace, then execute a command within the pod', () => {
let fetched = kubernetes.get("Pod", name, ns)
expect(pod.metadata.uid, 'created and fetched uids').to.equal(fetched.metadata.uid)

let greeting = 'hello xk6-kubernetes'
let exec = {
pod: name,
container: fetched.spec.containers[0].name,
command: ["echo", greeting]
}
let result = helpers.executeInPod(exec)
const stdout = String.fromCharCode(...result.stdout)
const stderr = String.fromCharCode(...result.stderr)
expect(stdout, 'execution result').to.contain(greeting)
expect(stderr, 'execution error').to.be.empty
})

describe('Remove our pods to cleanup', () => {
Expand Down
34 changes: 0 additions & 34 deletions examples/wait-job.js

This file was deleted.

6 changes: 6 additions & 0 deletions internal/testutils/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package testutils

import (
"fmt"
k8s "k8s.io/client-go/kubernetes"

"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
Expand All @@ -10,6 +11,11 @@ import (
"k8s.io/client-go/kubernetes/fake"
)

// NewFakeClientset creates a new instance of a fake Kubernetes clientset
func NewFakeClientset(objs ...runtime.Object) k8s.Interface {
return fake.NewSimpleClientset(objs...)
}

// NewFakeDynamic creates a new instance of a fake dynamic client with a default scheme
func NewFakeDynamic(objs ...runtime.Object) (*dynamicfake.FakeDynamicClient, error) {
scheme := runtime.NewScheme()
Expand Down
12 changes: 7 additions & 5 deletions kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,9 @@ func (mi *ModuleInstance) newClient(c goja.ConstructorCall) *goja.Object {
if mi.dynamic == nil {
k8s, err := api.NewFromConfig(
api.KubernetesConfig{
Config: config,
Context: ctx,
Clientset: obj.client,
Config: config,
Context: ctx,
},
)
if err != nil {
Expand All @@ -147,9 +148,10 @@ func (mi *ModuleInstance) newClient(c goja.ConstructorCall) *goja.Object {
// Pre-configured dynamic client and RESTMapper are injected for unit testing
k8s, err := api.NewFromConfig(
api.KubernetesConfig{
Client: mi.dynamic,
Mapper: mi.mapper,
Context: ctx,
Clientset: obj.client,
Client: mi.dynamic,
Mapper: mi.mapper,
Context: ctx,
},
)
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"go.k6.io/k6/lib/testutils"
"go.k6.io/k6/metrics"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
)

// setupTestEnv should be called from each test to build the execution environment for the test
Expand Down Expand Up @@ -49,7 +48,7 @@ func setupTestEnv(t *testing.T, objs ...runtime.Object) *goja.Runtime {
require.True(t, ok)
require.NoError(t, rt.Set("Kubernetes", m.Exports().Named["Kubernetes"]))

m.clientset = fake.NewSimpleClientset(objs...)
m.clientset = localutils.NewFakeClientset(objs...)

dynamic, err := localutils.NewFakeDynamic()
if err != nil {
Expand Down
15 changes: 12 additions & 3 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package api

import (
"context"
k8s "k8s.io/client-go/kubernetes"

"github.com/grafana/xk6-kubernetes/pkg/helpers"
"github.com/grafana/xk6-kubernetes/pkg/resources"
Expand All @@ -30,6 +31,8 @@ type KubernetesConfig struct {
Context context.Context
// kubernetes rest config
Config *rest.Config
// Clientset provides access to various API-specific clients
Clientset k8s.Interface
// Client is a pre-configured dynamic client. If provided, the rest config is not used
Client dynamic.Interface
// Mapper is a pre-configured RESTMapper. If provided, the rest config is not used
Expand All @@ -38,8 +41,10 @@ type KubernetesConfig struct {

// kubernetes holds references to implementation of the Kubernetes interface
type kubernetes struct {
ctx context.Context
ctx context.Context
Clientset k8s.Interface
*resources.Client
Config *rest.Config
*restmapper.DeferredDiscoveryRESTMapper
}

Expand Down Expand Up @@ -75,8 +80,10 @@ func NewFromConfig(c KubernetesConfig) (Kubernetes, error) {
}

return &kubernetes{
ctx: ctx,
Client: client,
ctx: ctx,
Clientset: c.Clientset,
Client: client,
Config: c.Config,
}, nil
}

Expand All @@ -86,7 +93,9 @@ func (k *kubernetes) Helpers(namespace string) helpers.Helpers {
}
return helpers.NewHelper(
k.ctx,
k.Clientset,
k.Client,
k.Config,
namespace,
)
}
11 changes: 9 additions & 2 deletions pkg/helpers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,34 @@ package helpers

import (
"context"
k8s "k8s.io/client-go/kubernetes"

"github.com/grafana/xk6-kubernetes/pkg/resources"
"k8s.io/client-go/rest"
)

// Helpers offers Helper functions grouped by the objects they handle
type Helpers interface {
JobHelper
PodHelper
ServiceHelper
}

// helpers struct holds the data required by the helpers
type helpers struct {
client *resources.Client
clientset k8s.Interface
config *rest.Config
ctx context.Context
namespace string
}

// NewHelper creates a set of helper functions on the default namespace
func NewHelper(ctx context.Context, client *resources.Client, namespace string) Helpers {
// NewHelper creates a set of helper functions on the specified namespace
func NewHelper(ctx context.Context, clientset k8s.Interface, client *resources.Client, config *rest.Config, namespace string) Helpers {
return &helpers{
client: client,
clientset: clientset,
config: config,
ctx: ctx,
namespace: namespace,
}
Expand Down
Loading

0 comments on commit 1955c37

Please sign in to comment.