From ae3f6ff9123d1516ba81a19042d62873db7cdd4f Mon Sep 17 00:00:00 2001 From: xdonggao Date: Wed, 14 Sep 2022 18:37:15 +0800 Subject: [PATCH] feat(platform): support workload pods page --- .../proxy/apps/daemonset/storage/pod.go | 87 ++++++++++++++++--- .../proxy/apps/deployment/storage/pod.go | 79 +++++++++++++++-- pkg/platform/proxy/apps/rest/rest.go | 3 +- .../proxy/apps/statefulset/storage/pod.go | 82 +++++++++++++++-- pkg/platform/proxy/batch/job/storage/pod.go | 47 +++++++++- pkg/platform/proxy/batch/rest/rest.go | 3 +- pkg/util/page/continue.go | 53 +++++++++++ 7 files changed, 323 insertions(+), 31 deletions(-) create mode 100644 pkg/util/page/continue.go diff --git a/pkg/platform/proxy/apps/daemonset/storage/pod.go b/pkg/platform/proxy/apps/daemonset/storage/pod.go index 2ad61a8b7..76f33a50b 100644 --- a/pkg/platform/proxy/apps/daemonset/storage/pod.go +++ b/pkg/platform/proxy/apps/daemonset/storage/pod.go @@ -21,9 +21,6 @@ package storage import ( "context" - "tkestack.io/tke/pkg/platform/proxy" - "tkestack.io/tke/pkg/util/apiclient" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" extensionsv1beta1 "k8s.io/api/extensions/v1beta1" @@ -35,6 +32,9 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "k8s.io/client-go/kubernetes" platforminternalclient "tkestack.io/tke/api/client/clientset/internalversion/typed/platform/internalversion" + "tkestack.io/tke/pkg/platform/proxy" + "tkestack.io/tke/pkg/util/apiclient" + "tkestack.io/tke/pkg/util/page" ) // PodREST implements the REST endpoint for find pods by a deployment. @@ -43,7 +43,7 @@ type PodREST struct { platformClient platforminternalclient.PlatformInterface } -var _ rest.Getter = &PodREST{} +var _ rest.GetterWithOptions = &PodREST{} var _ rest.GroupVersionKindProvider = &PodREST{} // GroupVersionKind is used to specify a particular GroupVersionKind to discovery. @@ -57,25 +57,34 @@ func (r *PodREST) New() runtime.Object { return &corev1.PodList{} } +// NewConnectOptions returns versioned resource that represents proxy parameters +func (r *PodREST) NewGetOptions() (runtime.Object, bool, string) { + return &metav1.ListOptions{}, false, "" +} + // Get retrieves the object from the storage. It is required to support Patch. -func (r *PodREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { +func (r *PodREST) Get(ctx context.Context, name string, options runtime.Object) (runtime.Object, error) { client, err := proxy.ClientSet(ctx, r.platformClient) if err != nil { return nil, err } - + listOpts := options.(*metav1.ListOptions) + metaOptions := &metav1.GetOptions{} + if listOpts.ResourceVersion != "" { + metaOptions.ResourceVersion = listOpts.ResourceVersion + } namespaceName, ok := request.NamespaceFrom(ctx) if !ok { return nil, errors.NewBadRequest("a namespace must be specified") } if apiclient.ClusterVersionIsBefore19(client) { - return listPodsByExtensions(ctx, client, namespaceName, name, options) + return listPodsByExtensions(ctx, client, namespaceName, name, metaOptions, listOpts) } - return listPodsByApps(ctx, client, namespaceName, name, options) + return listPodsByApps(ctx, client, namespaceName, name, metaOptions, listOpts) } -func listPodsByExtensions(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions) (runtime.Object, error) { +func listPodsByExtensions(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions, listOpts *metav1.ListOptions) (runtime.Object, error) { daemonSet, err := client.ExtensionsV1beta1().DaemonSets(namespaceName).Get(ctx, name, *options) if err != nil { return nil, errors.NewNotFound(extensionsv1beta1.Resource("daemonSets/pods"), name) @@ -103,10 +112,39 @@ func listPodsByExtensions(ctx context.Context, client *kubernetes.Clientset, nam } } } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "DaemonSet", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "DaemonSet", name, newStart, limit) + if err != nil { + return nil, err + } + items := podList.Items[newStart : newStart+limit] + podList.Items = items + } else { + items := podList.Items[newStart:len(podList.Items)] + podList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "DaemonSet", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := podList.Items[:listOpts.Limit] + podList.Items = items + } + } + return podList, nil } -func listPodsByApps(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions) (runtime.Object, error) { +func listPodsByApps(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions, listOpts *metav1.ListOptions) (runtime.Object, error) { daemonSet, err := client.AppsV1().DaemonSets(namespaceName).Get(ctx, name, *options) if err != nil { return nil, errors.NewNotFound(appsv1.Resource("daemonSets/pods"), name) @@ -134,5 +172,34 @@ func listPodsByApps(ctx context.Context, client *kubernetes.Clientset, namespace } } } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "DaemonSet", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "DaemonSet", name, newStart, limit) + if err != nil { + return nil, err + } + items := podList.Items[newStart : newStart+limit] + podList.Items = items + } else { + items := podList.Items[newStart:len(podList.Items)] + podList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "DaemonSet", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := podList.Items[:listOpts.Limit] + podList.Items = items + } + } + return podList, nil } diff --git a/pkg/platform/proxy/apps/deployment/storage/pod.go b/pkg/platform/proxy/apps/deployment/storage/pod.go index f702ff072..8db8b7f28 100644 --- a/pkg/platform/proxy/apps/deployment/storage/pod.go +++ b/pkg/platform/proxy/apps/deployment/storage/pod.go @@ -23,6 +23,7 @@ import ( "tkestack.io/tke/pkg/platform/proxy" "tkestack.io/tke/pkg/util/apiclient" + "tkestack.io/tke/pkg/util/page" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -43,7 +44,7 @@ type PodREST struct { platformClient platforminternalclient.PlatformInterface } -var _ rest.Getter = &PodREST{} +var _ rest.GetterWithOptions = &PodREST{} var _ rest.GroupVersionKindProvider = &PodREST{} // GroupVersionKind is used to specify a particular GroupVersionKind to discovery. @@ -57,12 +58,22 @@ func (r *PodREST) New() runtime.Object { return &corev1.PodList{} } +// NewConnectOptions returns versioned resource that represents proxy parameters +func (r *PodREST) NewGetOptions() (runtime.Object, bool, string) { + return &metav1.ListOptions{}, false, "" +} + // Get retrieves the object from the storage. It is required to support Patch. -func (r *PodREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { +func (r *PodREST) Get(ctx context.Context, name string, options runtime.Object) (runtime.Object, error) { client, err := proxy.ClientSet(ctx, r.platformClient) if err != nil { return nil, err } + listOpts := options.(*metav1.ListOptions) + metaOptions := &metav1.GetOptions{} + if listOpts.ResourceVersion != "" { + metaOptions.ResourceVersion = listOpts.ResourceVersion + } namespaceName, ok := request.NamespaceFrom(ctx) if !ok { @@ -70,13 +81,13 @@ func (r *PodREST) Get(ctx context.Context, name string, options *metav1.GetOptio } if apiclient.ClusterVersionIsBefore19(client) { - return listPodByExtensions(ctx, client, namespaceName, name, options) + return listPodByExtensions(ctx, client, namespaceName, name, metaOptions, listOpts) } - return listPodByApps(ctx, client, namespaceName, name, options) + return listPodByApps(ctx, client, namespaceName, name, metaOptions, listOpts) } -func listPodByExtensions(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions) (runtime.Object, error) { +func listPodByExtensions(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions, listOpts *metav1.ListOptions) (runtime.Object, error) { deployment, err := client.ExtensionsV1beta1().Deployments(namespaceName).Get(ctx, name, *options) if err != nil { return nil, errors.NewNotFound(extensionsv1beta1.Resource("deployments/pods"), name) @@ -115,10 +126,38 @@ func listPodByExtensions(ctx context.Context, client *kubernetes.Clientset, name } } } + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "Deployment", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "Deployment", name, newStart, limit) + if err != nil { + return nil, err + } + items := podList.Items[newStart : newStart+limit] + podList.Items = items + } else { + items := podList.Items[newStart:len(podList.Items)] + podList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "Deployment", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := podList.Items[:listOpts.Limit] + podList.Items = items + } + } + return podList, nil } -func listPodByApps(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions) (runtime.Object, error) { +func listPodByApps(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions, listOpts *metav1.ListOptions) (runtime.Object, error) { deployment, err := client.AppsV1().Deployments(namespaceName).Get(ctx, name, *options) if err != nil { return nil, errors.NewNotFound(appsv1.Resource("deployments/pods"), name) @@ -157,5 +196,33 @@ func listPodByApps(ctx context.Context, client *kubernetes.Clientset, namespaceN } } } + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "Deployment", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "Deployment", name, newStart, limit) + if err != nil { + return nil, err + } + items := podList.Items[newStart : newStart+limit] + podList.Items = items + } else { + items := podList.Items[newStart:len(podList.Items)] + podList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "Deployment", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := podList.Items[:listOpts.Limit] + podList.Items = items + } + } + return podList, nil } diff --git a/pkg/platform/proxy/apps/rest/rest.go b/pkg/platform/proxy/apps/rest/rest.go index 0c5b554aa..2e43bf295 100644 --- a/pkg/platform/proxy/apps/rest/rest.go +++ b/pkg/platform/proxy/apps/rest/rest.go @@ -22,7 +22,6 @@ import ( appsv1 "k8s.io/api/apps/v1" appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta2 "k8s.io/api/apps/v1beta2" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" genericserver "k8s.io/apiserver/pkg/server" @@ -49,7 +48,7 @@ var _ storage.RESTStorageProvider = &StorageProvider{} // NewRESTStorage is a factory constructor to creates and returns the APIGroupInfo func (s *StorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericserver.APIGroupInfo, bool) { - apiGroupInfo := genericserver.NewDefaultAPIGroupInfo(appsv1.GroupName, platform.Scheme, metav1.ParameterCodec, platform.Codecs) + apiGroupInfo := genericserver.NewDefaultAPIGroupInfo(appsv1.GroupName, platform.Scheme, platform.ParameterCodec, platform.Codecs) if apiResourceConfigSource.VersionEnabled(appsv1.SchemeGroupVersion) { apiGroupInfo.VersionedResourcesStorageMap[appsv1.SchemeGroupVersion.Version] = s.v1Storage(restOptionsGetter, s.LoopbackClientConfig) diff --git a/pkg/platform/proxy/apps/statefulset/storage/pod.go b/pkg/platform/proxy/apps/statefulset/storage/pod.go index 09b13da79..c3a1f207c 100644 --- a/pkg/platform/proxy/apps/statefulset/storage/pod.go +++ b/pkg/platform/proxy/apps/statefulset/storage/pod.go @@ -23,6 +23,7 @@ import ( "tkestack.io/tke/pkg/platform/proxy" "tkestack.io/tke/pkg/util/apiclient" + "tkestack.io/tke/pkg/util/page" appsv1beta1 "k8s.io/api/apps/v1beta1" corev1 "k8s.io/api/core/v1" @@ -42,7 +43,7 @@ type PodREST struct { platformClient platforminternalclient.PlatformInterface } -var _ rest.Getter = &PodREST{} +var _ rest.GetterWithOptions = &PodREST{} var _ rest.GroupVersionKindProvider = &PodREST{} // GroupVersionKind is used to specify a particular GroupVersionKind to discovery. @@ -56,25 +57,34 @@ func (r *PodREST) New() runtime.Object { return &corev1.PodList{} } +// NewConnectOptions returns versioned resource that represents proxy parameters +func (r *PodREST) NewGetOptions() (runtime.Object, bool, string) { + return &metav1.ListOptions{}, false, "" +} + // Get retrieves the object from the storage. It is required to support Patch. -func (r *PodREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { +func (r *PodREST) Get(ctx context.Context, name string, options runtime.Object) (runtime.Object, error) { client, err := proxy.ClientSet(ctx, r.platformClient) if err != nil { return nil, err } - + listOpts := options.(*metav1.ListOptions) + metaOptions := &metav1.GetOptions{} + if listOpts.ResourceVersion != "" { + metaOptions.ResourceVersion = listOpts.ResourceVersion + } namespaceName, ok := request.NamespaceFrom(ctx) if !ok { return nil, errors.NewBadRequest("a namespace must be specified") } if apiclient.ClusterVersionIsBefore19(client) { - return listPodsByAppsBeta(ctx, client, namespaceName, name, options) + return listPodsByAppsBeta(ctx, client, namespaceName, name, metaOptions, listOpts) } - return listPodsByApps(ctx, client, namespaceName, name, options) + return listPodsByApps(ctx, client, namespaceName, name, metaOptions, listOpts) } -func listPodsByAppsBeta(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions) (runtime.Object, error) { +func listPodsByAppsBeta(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions, listOpts *metav1.ListOptions) (runtime.Object, error) { statefulSet, err := client.AppsV1beta1().StatefulSets(namespaceName).Get(ctx, name, *options) if err != nil { return nil, errors.NewNotFound(appsv1beta1.Resource("statefulSet/pods"), name) @@ -102,10 +112,39 @@ func listPodsByAppsBeta(ctx context.Context, client *kubernetes.Clientset, names } } } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "StatefulSet", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "StatefulSet", name, newStart, limit) + if err != nil { + return nil, err + } + items := podList.Items[newStart : newStart+limit] + podList.Items = items + } else { + items := podList.Items[newStart:len(podList.Items)] + podList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "StatefulSet", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := podList.Items[:listOpts.Limit] + podList.Items = items + } + } + return podList, nil } -func listPodsByApps(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions) (runtime.Object, error) { +func listPodsByApps(ctx context.Context, client *kubernetes.Clientset, namespaceName, name string, options *metav1.GetOptions, listOpts *metav1.ListOptions) (runtime.Object, error) { statefulSet, err := client.AppsV1().StatefulSets(namespaceName).Get(ctx, name, *options) if err != nil { return nil, errors.NewNotFound(appsv1beta1.Resource("statefulSet/pods"), name) @@ -133,5 +172,34 @@ func listPodsByApps(ctx context.Context, client *kubernetes.Clientset, namespace } } } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "StatefulSet", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "StatefulSet", name, newStart, limit) + if err != nil { + return nil, err + } + items := podList.Items[newStart : newStart+limit] + podList.Items = items + } else { + items := podList.Items[newStart:len(podList.Items)] + podList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "StatefulSet", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := podList.Items[:listOpts.Limit] + podList.Items = items + } + } + return podList, nil } diff --git a/pkg/platform/proxy/batch/job/storage/pod.go b/pkg/platform/proxy/batch/job/storage/pod.go index a13bb8664..4340d463e 100644 --- a/pkg/platform/proxy/batch/job/storage/pod.go +++ b/pkg/platform/proxy/batch/job/storage/pod.go @@ -31,6 +31,7 @@ import ( "k8s.io/apiserver/pkg/registry/rest" platforminternalclient "tkestack.io/tke/api/client/clientset/internalversion/typed/platform/internalversion" "tkestack.io/tke/pkg/platform/proxy" + "tkestack.io/tke/pkg/util/page" ) // PodREST implements the REST endpoint for find pods by a deployment. @@ -39,7 +40,7 @@ type PodREST struct { platformClient platforminternalclient.PlatformInterface } -var _ rest.Getter = &PodREST{} +var _ rest.GetterWithOptions = &PodREST{} var _ rest.GroupVersionKindProvider = &PodREST{} // GroupVersionKind is used to specify a particular GroupVersionKind to discovery. @@ -53,19 +54,28 @@ func (r *PodREST) New() runtime.Object { return &corev1.PodList{} } +// NewConnectOptions returns versioned resource that represents proxy parameters +func (r *PodREST) NewGetOptions() (runtime.Object, bool, string) { + return &metav1.ListOptions{}, false, "" +} + // Get retrieves the object from the storage. It is required to support Patch. -func (r *PodREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { +func (r *PodREST) Get(ctx context.Context, name string, options runtime.Object) (runtime.Object, error) { client, err := proxy.ClientSet(ctx, r.platformClient) if err != nil { return nil, err } - + listOpts := options.(*metav1.ListOptions) + metaOptions := &metav1.GetOptions{} + if listOpts.ResourceVersion != "" { + metaOptions.ResourceVersion = listOpts.ResourceVersion + } namespaceName, ok := request.NamespaceFrom(ctx) if !ok { return nil, errors.NewBadRequest("a namespace must be specified") } - job, err := client.BatchV1().Jobs(namespaceName).Get(ctx, name, *options) + job, err := client.BatchV1().Jobs(namespaceName).Get(ctx, name, *metaOptions) if err != nil { return nil, errors.NewNotFound(batchV1.Resource("jobs/pods"), name) } @@ -92,5 +102,34 @@ func (r *PodREST) Get(ctx context.Context, name string, options *metav1.GetOptio } } } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "Job", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "Job", name, newStart, limit) + if err != nil { + return nil, err + } + items := podList.Items[newStart : newStart+limit] + podList.Items = items + } else { + items := podList.Items[newStart:len(podList.Items)] + podList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(podList.Items) { + podList.Continue, err = page.EncodeContinue(ctx, "Job", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := podList.Items[:listOpts.Limit] + podList.Items = items + } + } + return podList, nil } diff --git a/pkg/platform/proxy/batch/rest/rest.go b/pkg/platform/proxy/batch/rest/rest.go index 31b08f199..5c073df1a 100644 --- a/pkg/platform/proxy/batch/rest/rest.go +++ b/pkg/platform/proxy/batch/rest/rest.go @@ -21,7 +21,6 @@ package rest import ( v1 "k8s.io/api/batch/v1" "k8s.io/api/batch/v1beta1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/registry/generic" "k8s.io/apiserver/pkg/registry/rest" genericserver "k8s.io/apiserver/pkg/server" @@ -46,7 +45,7 @@ var _ storage.RESTStorageProvider = &StorageProvider{} // NewRESTStorage is a factory constructor to creates and returns the // APIGroupInfo func (s *StorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericserver.APIGroupInfo, bool) { - apiGroupInfo := genericserver.NewDefaultAPIGroupInfo(v1.GroupName, platform.Scheme, metav1.ParameterCodec, platform.Codecs) + apiGroupInfo := genericserver.NewDefaultAPIGroupInfo(v1.GroupName, platform.Scheme, platform.ParameterCodec, platform.Codecs) if apiResourceConfigSource.VersionEnabled(v1.SchemeGroupVersion) { apiGroupInfo.VersionedResourcesStorageMap[v1.SchemeGroupVersion.Version] = s.v1Storage(restOptionsGetter, s.LoopbackClientConfig) diff --git a/pkg/util/page/continue.go b/pkg/util/page/continue.go new file mode 100644 index 000000000..bfd5a9d2a --- /dev/null +++ b/pkg/util/page/continue.go @@ -0,0 +1,53 @@ +package page + +import ( + "context" + "encoding/base64" + "encoding/json" + k8serror "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + "tkestack.io/tke/pkg/platform/apiserver/filter" +) + +type ContinueStruct struct { + ClsName string `json:"clsName,omitempty"` + Resource string `json:"resource,omitempty"` + Name string `json:"name,omitempty"` + Start int64 `json:"start,omitempty"` + Limit int64 `json:"limit,omitempty"` +} + +func EncodeContinue(ctx context.Context, resource, name string, start, limit int64) (string, error) { + clusterName := filter.ClusterFrom(ctx) + continueStruct := &ContinueStruct{ + ClsName: clusterName, + Resource: resource, + Name: name, + Start: start, + Limit: limit, + } + continueJSONByte, err := json.Marshal(continueStruct) + if err != nil { + return "", err + } + continueBase64Str := base64.StdEncoding.EncodeToString(continueJSONByte) + + return continueBase64Str, nil +} + +func DecodeContinue(ctx context.Context, resource, name, continueStr string) (int64, int64, error) { + continueJSONByte, err := base64.StdEncoding.DecodeString(continueStr) + if err != nil { + return 0, 0, err + } + continueStruct := &ContinueStruct{} + err = json.Unmarshal(continueJSONByte, continueStruct) + if err != nil { + return 0, 0, err + } + clusterName := filter.ClusterFrom(ctx) + if continueStruct.ClsName != clusterName || continueStruct.Name != name || continueStruct.Resource != resource { + return 0, 0, k8serror.NewNotFound(schema.GroupResource{Group: "", Resource: "cache"}, "") + } + return continueStruct.Start, continueStruct.Limit, nil +}