Migrate Clientset to controller-runtime client.Client
Migrates typed clientset usage in test code to client.Client from sigs.k8s.io/controller-runtime/pkg/client.
Migration Patterns
Import Changes
Remove:
"github.com/openkruise/agents/pkg/sandbox-manager/clients"
// or any other typed clientset packages
Add:
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
Also import and register any custom CRD schemes (e.g. agentsv1alpha1) if needed.
Building a Fake Client
Before (typed clientset):
client := clients.NewFakeClientSet(t)
After (controller-runtime fake client):
// Initialize scheme at the top of the test function (or outside sub-tests for sharing)
scheme := runtime.NewScheme()
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(agentsv1alpha1.AddToScheme(scheme)) // if CRD support needed
// Build fakeClient in each sub-test
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithStatusSubresource(&corev1.Pod{}). // declare types that support status subresource
Build()
Important:
WithStatusSubresourcemust declare every type that needs.Status().Update(), otherwise the status field will not be persisted.
Creating Resources
Before:
createdPod, err := client.K8sClient.CoreV1().Pods("default").Create(ctx, pod, metav1.CreateOptions{})
After:
err := fakeClient.Create(ctx, pod)
Updating Status
Before:
createdPod.Status = pod.Status
_, err = client.K8sClient.CoreV1().Pods("default").UpdateStatus(ctx, createdPod, metav1.UpdateOptions{})
After:
// After Create, the original object already has ResourceVersion populated — update status directly on it
pod.Status = corev1.PodStatus{...}
err = fakeClient.Status().Update(ctx, pod)
Reading Resources
Before:
pod, err := client.K8sClient.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{})
After:
var pod corev1.Pod
err := c.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, &pod)
Important: Avoid naming the parameter
client— it conflicts with theclientpackage name. Usecinstead.
Function Signature Migration
Before:
func waitForXxx(ctx context.Context, client *SomeClientSet, ...) error {
pod, err := client.K8sClient.CoreV1().Pods(ns).Get(ctx, name, metav1.GetOptions{})
After:
func waitForXxx(ctx context.Context, c client.Client, ...) error {
var pod corev1.Pod
if err := c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, &pod); err != nil {
Full Migration Example
Real migration in this project: pkg/sandbox-manager/infra/sandboxcr/claim_test.go
// Before (TestWaitForPodResizeState)
client := clients.NewFakeClientSet(t)
createdPod, err := client.K8sClient.CoreV1().Pods("default").Create(t.Context(), pod, metav1.CreateOptions{})
createdPod.Status = pod.Status
_, err = client.K8sClient.CoreV1().Pods("default").UpdateStatus(t.Context(), createdPod, metav1.UpdateOptions{})
err = waitForPodResizeState(t.Context(), client, ...)
// After
scheme := runtime.NewScheme()
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithStatusSubresource(&corev1.Pod{}).Build()
err := fakeClient.Create(t.Context(), pod)
pod.Status = corev1.PodStatus{...}
err = fakeClient.Status().Update(t.Context(), pod)
err = waitForPodResizeState(t.Context(), fakeClient, ...)
Verification
After migration, run:
go vet ./pkg/...
go test ./pkg/<your-package>/ -count=1 -timeout 120s
Source: openkruise/agents — distributed by TomeVault.