kubernetes go/k8s:编译器运行时升级,伪客户端缺少功能

szqfcxe2  于 2023-11-17  发布在  Kubernetes
关注(0)|答案(1)|浏览(116)

我正在尝试将controller-runtime从0.13.0版本升级到0.16.3,由于重大更改,该版本在测试中引入了几个问题。
我已经设法解决了其中的大部分问题,但有一个特定的用例我无法解决。
这段代码创建了一个自定义资源,然后更新了它的状态。虽然一切都按预期工作,但问题出现在测试阶段。测试使用了client/fake包中的假客户端。
问题在于,当在假客户端的内存中创建新的自定义资源(CR)对象时,似乎没有在fakeSubResourceClient下生成相应的对象以进行状态更新。因此,这导致了“未找到错误”,这不应该发生,并且只发生在测试中,而不是生产中。
我曾试图寻求各种AI机器人的帮助,也在公共GitHub存储库中搜索类似的用例,但没有成功。
如有任何帮助,我们将不胜感激。

u2nhd7ah

u2nhd7ah1#

好了,在验证了假客户端确实不支持这种情况后,我想出了一个工作得很好的解决方案,代码如下

type ErrorInjectingFakeClient struct {
    client.WithWatch
    withSubResourceSimulation bool
    withObjects               []client.Object
    withStatusSubresource     []client.Object
    failError                 error
}

func NewErrorInjectingFakeClient(scheme *runtime.Scheme, withSubResourceSimulation bool, initObjects ...client.Object) *ErrorInjectingFakeClient {
    builder := fake.NewClientBuilder().
        WithScheme(scheme).
        WithObjects(initObjects...).
        WithStatusSubresource(initObjects...)
    return &ErrorInjectingFakeClient{
        withSubResourceSimulation: withSubResourceSimulation,
        WithWatch:                 builder.Build(),
        withObjects:               initObjects,
        withStatusSubresource:     initObjects,
    }
}

// Copied from sigs.k8s.io/[email protected]/pkg/client/fake/client.go#1217
var inTreeResourcesWithStatus = []schema.GroupVersionKind{
    {Version: "v1", Kind: "Namespace"},
    {Version: "v1", Kind: "Node"},
    {Version: "v1", Kind: "PersistentVolumeClaim"},
    {Version: "v1", Kind: "PersistentVolume"},
    {Version: "v1", Kind: "Pod"},
    {Version: "v1", Kind: "ReplicationController"},
    {Version: "v1", Kind: "Service"},

    {Group: "apps", Version: "v1", Kind: "Deployment"},
    {Group: "apps", Version: "v1", Kind: "DaemonSet"},
    {Group: "apps", Version: "v1", Kind: "ReplicaSet"},
    {Group: "apps", Version: "v1", Kind: "StatefulSet"},

    {Group: "autoscaling", Version: "v1", Kind: "HorizontalPodAutoscaler"},

    {Group: "batch", Version: "v1", Kind: "CronJob"},
    {Group: "batch", Version: "v1", Kind: "Job"},

    {Group: "certificates.k8s.io", Version: "v1", Kind: "CertificateSigningRequest"},

    {Group: "networking.k8s.io", Version: "v1", Kind: "Ingress"},
    {Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicy"},

    {Group: "policy", Version: "v1", Kind: "PodDisruptionBudget"},

    {Group: "storage.k8s.io", Version: "v1", Kind: "VolumeAttachment"},

    {Group: "apiextensions.k8s.io", Version: "v1", Kind: "CustomResourceDefinition"},

    {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "FlowSchema"},
    {Group: "flowcontrol.apiserver.k8s.io", Version: "v1beta2", Kind: "PriorityLevelConfiguration"},
}

func (c *ErrorInjectingFakeClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
    if c.failError != nil {
        return c.failError
    }

    if err := c.WithWatch.Create(ctx, obj, opts...); err != nil {
        return err
    }
    if !c.withSubResourceSimulation {
        return nil
    }

    c.withObjects = append(c.withObjects, obj)
    err := c.recreateFake(ctx)
    if err != nil {
        return err
    }

    return nil
}

func (c *ErrorInjectingFakeClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
    if c.failError != nil {
        return c.failError
    }

    if err := c.WithWatch.Delete(ctx, obj, opts...); err != nil {
        return err
    }

    return nil
}

func (c *ErrorInjectingFakeClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
    if c.failError != nil {
        return c.failError
    }
    return c.WithWatch.Update(ctx, obj, opts...)
}

// TODO add other K8S client functions you want to inject failures into

func (c *ErrorInjectingFakeClient) SetError(err error) {
    c.failError = err
}

func (c *ErrorInjectingFakeClient) recreateFake(ctx context.Context) error {
    // This is a pretty disgusting hack to get around the fact that the fake client doesn't support creating status subresources
    // Discussed here https://github.com/kubernetes-sigs/controller-runtime/issues/2386#issuecomment-1607768830
    // and here https://github.com/kubernetes-sigs/controller-runtime/issues/2362#issuecomment-1699415588
    // and here https://stackoverflow.com/questions/77489441/go-k8s-controller-runtime-upgrade-fake-client-lacks-functionality

    // We need to collect all the objects from the fake client, and then re-create the fake client with the status subresource for the created object

    gvks := sets.New(inTreeResourcesWithStatus...)
    for _, o := range c.withObjects {
        gvk, err := apiutil.GVKForObject(o, c.Scheme())
        if err != nil {
            return err
        }
        gvks.Insert(gvk)
    }

    var objs []client.Object
    for _, gvk := range gvks.UnsortedList() {
        objList := &unstructured.UnstructuredList{}
        objList.SetGroupVersionKind(schema.GroupVersionKind{Group: gvk.Group, Version: gvk.Version, Kind: gvk.Kind})

        err := c.List(ctx, objList)
        if err != nil {
            return err
        }

        for _, o := range objList.Items {
            objs = append(objs, o.DeepCopy())
        }
    }

    initObjs := sets.New(objs...).UnsortedList()
    c.withObjects = initObjs
    c.withStatusSubresource = initObjs

    c.WithWatch = fake.NewClientBuilder().
        WithScheme(c.Scheme()).
        WithObjects(c.withObjects...).
        WithStatusSubresource(c.withStatusSubresource...).
        Build()
    return nil
}

字符串

相关问题