Skip to content

Commit

Permalink
feat(platform): add pagination for node/pods (#2201)
Browse files Browse the repository at this point in the history
Co-authored-by: richardgu <richardgu@tencent.com>
  • Loading branch information
277631272 and richardgu committed Dec 6, 2022
1 parent 6e1a4a9 commit 09a1df1
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 0 deletions.
168 changes: 168 additions & 0 deletions pkg/platform/proxy/core/node/storage/pod.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* Tencent is pleased to support the open source community by making TKEStack
* available.
*
* Copyright (C) 2012-2019 Tencent. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the
* License at
*
* https://opensource.org/licenses/Apache-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package storage

import (
"context"
"fmt"

"tkestack.io/tke/pkg/platform/proxy"
"tkestack.io/tke/pkg/util/apiclient"
"tkestack.io/tke/pkg/util/page"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/client-go/kubernetes"
platforminternalclient "tkestack.io/tke/api/client/clientset/internalversion/typed/platform/internalversion"
)

// PodREST implements the REST endpoint for find pods by a node.
type PodREST struct {
rest.Storage
platformClient platforminternalclient.PlatformInterface
}

var _ rest.GetterWithOptions = &PodREST{}
var _ rest.GroupVersionKindProvider = &PodREST{}

// GroupVersionKind is used to specify a particular GroupVersionKind to discovery.
func (r *PodREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind {
return corev1.SchemeGroupVersion.WithKind("PodList")
}

// New returns an empty object that can be used with Create and Update after
// request data has been put into it.
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 runtime.Object) (runtime.Object, error) {
client, err := proxy.ClientSet(ctx, r.platformClient)
if err != nil {
return nil, err
}
listOpts := options.(*metav1.ListOptions)

if apiclient.ClusterVersionIsBefore19(client) {
return listPodByExtensions(ctx, client, name, listOpts)
}

return listPodByApps(ctx, client, name, listOpts)
}

func listPodByExtensions(ctx context.Context, client *kubernetes.Clientset, name string, listOpts *metav1.ListOptions) (runtime.Object, error) {
if listOpts.FieldSelector == "" {
listOpts.FieldSelector = fmt.Sprintf("spec.nodeName=%s", name)
} else {
listOpts.FieldSelector = listOpts.FieldSelector + "," + fmt.Sprintf("spec.nodeName=%s", name)
}
option := listOpts.DeepCopy()
option.Limit = 0
option.Continue = ""
podList, err := client.CoreV1().Pods(metav1.NamespaceAll).List(ctx, *option)
if err != nil {
return nil, errors.NewInternalError(err)
}

if listOpts.Continue != "" {
start, limit, err := page.DecodeContinue(ctx, "Node", 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, "Node", 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, "Node", 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, name string, listOpts *metav1.ListOptions) (runtime.Object, error) {
// list all of the pod, by node name
if listOpts.FieldSelector == "" {
listOpts.FieldSelector = fmt.Sprintf("spec.nodeName=%s", name)
} else {
listOpts.FieldSelector = listOpts.FieldSelector + "," + fmt.Sprintf("spec.nodeName=%s", name)
}
option := listOpts.DeepCopy()
option.Limit = 0
option.Continue = ""
podList, err := client.CoreV1().Pods(metav1.NamespaceAll).List(ctx, *option)
if err != nil {
return nil, errors.NewInternalError(err)
}

if listOpts.Continue != "" {
start, limit, err := page.DecodeContinue(ctx, "Node", 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, "Node", 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, "Node", name, 0, listOpts.Limit)
if err != nil {
return nil, err
}
items := podList.Items[:listOpts.Limit]
podList.Items = items
}
}

return podList, nil
}
4 changes: 4 additions & 0 deletions pkg/platform/proxy/core/node/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
// Storage includes storage for resources.
type Storage struct {
Node *REST
Pods *PodREST
Status *StatusREST
}

Expand All @@ -55,6 +56,9 @@ func NewStorage(_ genericregistry.RESTOptionsGetter, platformClient platforminte

return &Storage{
Node: &REST{nodeStore},
Pods: &PodREST{
platformClient: platformClient,
},
Status: &StatusREST{
store: &statusStore,
},
Expand Down
1 change: 1 addition & 0 deletions pkg/platform/proxy/core/rest/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter generi
"namespaces/status": namespaceStore.Status,
"namespaces/finalize": namespaceStore.Finalize,
"nodes": nodeStore.Node,
"nodes/pods": nodeStore.Pods,
"nodes/status": nodeStore.Status,
"events": eventStore.Event,
"secrets": secretStore.Secret,
Expand Down

0 comments on commit 09a1df1

Please sign in to comment.