1
0
記事投稿キャンペーン 「2024年!初アウトプットをしよう」

fake-clientのRESTClientをIndexerInformerに渡すとpanicする

Posted at

Kubernetes client-goのIndexerInformerを使った実装で、以下のようにclientsetからRESTClientを取得してcacheを作成しようとしたところ、go testでfake clientを渡した際にclient内部でパニックが発生していた。

	cachedLw := cache.NewListWatchFromClient(clientset.CoreV1().RESTClient(), resource, "", fields.Everything())
	indexer, informer := cache.NewIndexerInformer(cachedLw, &v1.Pod{}, 0, cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
      // on create...
    },
    UpdateFunc: func(old interface{}, new interface{}) {
      // on update...
    },
		DeleteFunc: func(obj interface{}) {
      // on delete...
    },
  }, cache.Indexers{})

E0119 10:17:45.953340   57221 runtime.go:79] Observed a panic: "invalid memory address or nil pointer dereference" (runtime error: invalid memory address or nil pointer dereference)

fake clientではなく実際のkubernetesに接続すると問題なく動作していた。原因を調べてみると古いissueが見つかった。
どうもfake-clientのRESTClient()メソッドは動作する形では実装されていない模様。以下のような実装で、RESTClient()は常にnilを返す。

// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeCoreV1) RESTClient() rest.Interface {
	var ret *rest.RESTClient
	return ret
}

go testでcacheは必要ないので、cache.ListerWatcherをmockにする形で解決した。

import (
	"context"
	"testing"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/watch"
	k "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/kubernetes/fake"
	"k8s.io/client-go/tools/cache"
)

type podListWatcher struct {
	clientset k.Interface
}

// ListFunc knows how to list resources
func (w *podListWatcher) List(options metav1.ListOptions) (runtime.Object, error) {
	return w.clientset.CoreV1().Pods("").List(context.TODO(), options)
}

// WatchFunc knows how to watch resources
func (w *podListWatcher) Watch(options metav1.ListOptions) (watch.Interface, error) {
	return w.clientset.CoreV1().Pods("").Watch(context.TODO(), options)
}

func Test(t *testing.T) {
	clientset := fake.NewSimpleClientset()
	// prepare fake client...

	lw := &podListWatcher{clientset: clientset}
	indexer, informer := cache.NewIndexerInformer(lw, &v1.Pod{}, 0, cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			// on create...
		},
		UpdateFunc: func(old interface{}, new interface{}) {
			// on update...
		},
		DeleteFunc: func(obj interface{}) {
			// on delete...
		},
	}, cache.Indexers{})
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0