diff --git a/pkg/platform/proxy/apps/daemonset/storage/pod.go b/pkg/platform/proxy/apps/daemonset/storage/pod.go index 76f33a50b..3a832f57c 100644 --- a/pkg/platform/proxy/apps/daemonset/storage/pod.go +++ b/pkg/platform/proxy/apps/daemonset/storage/pod.go @@ -96,8 +96,15 @@ func listPodsByExtensions(ctx context.Context, client *kubernetes.Clientset, nam } // list all of the pod, by deployment labels - listOptions := metav1.ListOptions{LabelSelector: selector.String()} - podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, listOptions) + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, *listPodsOptions) if err != nil { return nil, errors.NewInternalError(err) } @@ -156,8 +163,15 @@ func listPodsByApps(ctx context.Context, client *kubernetes.Clientset, namespace } // list all of the pod, by deployment labels - listOptions := metav1.ListOptions{LabelSelector: selector.String()} - podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, listOptions) + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, *listPodsOptions) if err != nil { return nil, errors.NewInternalError(err) } diff --git a/pkg/platform/proxy/apps/daemonset/storage/replicasets.go b/pkg/platform/proxy/apps/daemonset/storage/replicasets.go new file mode 100644 index 000000000..a7d61c2f1 --- /dev/null +++ b/pkg/platform/proxy/apps/daemonset/storage/replicasets.go @@ -0,0 +1,215 @@ +/* + * 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" + + appsv1 "k8s.io/api/apps/v1" + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + "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/endpoints/request" + "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" +) + +// ReplicaSetsREST implements the REST endpoint for find replicasets by a deployment. +type ReplicaSetsREST struct { + rest.Storage + platformClient platforminternalclient.PlatformInterface +} + +var _ rest.GetterWithOptions = &ReplicaSetsREST{} +var _ rest.GroupVersionKindProvider = &ReplicaSetsREST{} + +// GroupVersionKind is used to specify a particular GroupVersionKind to discovery. +func (r *ReplicaSetsREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { + return appsv1.SchemeGroupVersion.WithKind("ReplicaSetList") +} + +// New returns an empty object that can be used with Create and Update after +// request data has been put into it. +func (r *ReplicaSetsREST) New() runtime.Object { + return &appsv1.ReplicaSetList{} +} + +// NewConnectOptions returns versioned resource that represents proxy parameters +func (r *ReplicaSetsREST) NewGetOptions() (runtime.Object, bool, string) { + return &metav1.ListOptions{}, false, "" +} + +// Get retrieves the object from the storage. It is required to support Patch. +func (r *ReplicaSetsREST) 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 listReplicaSetsByExtensions(ctx, client, namespaceName, name, metaOptions, listOpts) + } + return listReplicaSetsByApps(ctx, client, namespaceName, name, metaOptions, listOpts) +} + +func listReplicaSetsByExtensions(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/replicasets"), name) + } + + selector, err := metav1.LabelSelectorAsSelector(daemonSet.Spec.Selector) + if err != nil { + return nil, errors.NewInternalError(err) + } + + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + rsAllList, err := client.ExtensionsV1beta1().ReplicaSets(namespaceName).List(ctx, *listPodsOptions) + if err != nil { + return nil, errors.NewInternalError(err) + } + rsList := &extensionsv1beta1.ReplicaSetList{ + Items: make([]extensionsv1beta1.ReplicaSet, 0), + } + for _, rs := range rsAllList.Items { + for _, references := range rs.ObjectMeta.OwnerReferences { + if references.UID == daemonSet.GetUID() { + rsList.Items = append(rsList.Items, rs) + } + } + } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "DaemonSet/ReplicaSets", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "DaemonSet/ReplicaSets", name, newStart, limit) + if err != nil { + return nil, err + } + items := rsList.Items[newStart : newStart+limit] + rsList.Items = items + } else { + items := rsList.Items[newStart:len(rsList.Items)] + rsList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "DaemonSet/ReplicaSets", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := rsList.Items[:listOpts.Limit] + rsList.Items = items + } + } + + return rsList, nil +} + +func listReplicaSetsByApps(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/replicasets"), name) + } + + selector, err := metav1.LabelSelectorAsSelector(daemonSet.Spec.Selector) + if err != nil { + return nil, errors.NewInternalError(err) + } + + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + rsAllList, err := client.AppsV1().ReplicaSets(namespaceName).List(ctx, *listPodsOptions) + if err != nil { + return nil, errors.NewInternalError(err) + } + + rsList := &appsv1.ReplicaSetList{ + Items: make([]appsv1.ReplicaSet, 0), + } + for _, rs := range rsAllList.Items { + for _, references := range rs.ObjectMeta.OwnerReferences { + if references.UID == daemonSet.GetUID() { + rsList.Items = append(rsList.Items, rs) + } + } + } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "DaemonSet/ReplicaSets", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "DaemonSet/ReplicaSets", name, newStart, limit) + if err != nil { + return nil, err + } + items := rsList.Items[newStart : newStart+limit] + rsList.Items = items + } else { + items := rsList.Items[newStart:len(rsList.Items)] + rsList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "DaemonSet/ReplicaSets", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := rsList.Items[:listOpts.Limit] + rsList.Items = items + } + } + + return rsList, nil +} diff --git a/pkg/platform/proxy/apps/daemonset/storage/storage.go b/pkg/platform/proxy/apps/daemonset/storage/storage.go index f24819c3a..fd8d1d1fb 100644 --- a/pkg/platform/proxy/apps/daemonset/storage/storage.go +++ b/pkg/platform/proxy/apps/daemonset/storage/storage.go @@ -34,10 +34,11 @@ import ( // Storage includes storage for resources. type Storage struct { - DaemonSet *REST - Status *StatusREST - Events *EventREST - Pods *PodREST + DaemonSet *REST + Status *StatusREST + Events *EventREST + Pods *PodREST + ReplicaSets *ReplicaSetsREST } // REST implements pkg/api/rest.StandardStorage @@ -67,6 +68,9 @@ func NewStorageV1(_ genericregistry.RESTOptionsGetter, platformClient platformin Events: &EventREST{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } @@ -92,6 +96,9 @@ func NewStorageV1Beta2(_ genericregistry.RESTOptionsGetter, platformClient platf Events: &EventREST{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } @@ -117,6 +124,9 @@ func NewStorageExtensionsV1Beta1(_ genericregistry.RESTOptionsGetter, platformCl Events: &EventREST{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } diff --git a/pkg/platform/proxy/apps/deployment/storage/pod.go b/pkg/platform/proxy/apps/deployment/storage/pod.go index 8db8b7f28..ef76414a3 100644 --- a/pkg/platform/proxy/apps/deployment/storage/pod.go +++ b/pkg/platform/proxy/apps/deployment/storage/pod.go @@ -105,7 +105,15 @@ func listPodByExtensions(ctx context.Context, client *kubernetes.Clientset, name } // list all of the pod, by deployment labels - podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, listOptions) + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, *listPodsOptions) if err != nil { return nil, errors.NewInternalError(err) } @@ -175,7 +183,15 @@ func listPodByApps(ctx context.Context, client *kubernetes.Clientset, namespaceN } // list all of the pod, by deployment labels - podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, listOptions) + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, *listPodsOptions) if err != nil { return nil, errors.NewInternalError(err) } diff --git a/pkg/platform/proxy/apps/deployment/storage/replicasets.go b/pkg/platform/proxy/apps/deployment/storage/replicasets.go new file mode 100644 index 000000000..00e4e51a7 --- /dev/null +++ b/pkg/platform/proxy/apps/deployment/storage/replicasets.go @@ -0,0 +1,217 @@ +/* + * 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" + + appsv1 "k8s.io/api/apps/v1" + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + "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/endpoints/request" + "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" +) + +// ReplicaSetsREST implements the REST endpoint for find replicasets by a deployment. +type ReplicaSetsREST struct { + rest.Storage + platformClient platforminternalclient.PlatformInterface +} + +var _ rest.GetterWithOptions = &ReplicaSetsREST{} +var _ rest.GroupVersionKindProvider = &ReplicaSetsREST{} + +// GroupVersionKind is used to specify a particular GroupVersionKind to discovery. +func (r *ReplicaSetsREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { + return appsv1.SchemeGroupVersion.WithKind("ReplicaSetList") +} + +// New returns an empty object that can be used with Create and Update after +// request data has been put into it. +func (r *ReplicaSetsREST) New() runtime.Object { + return &appsv1.ReplicaSetList{} +} + +// NewConnectOptions returns versioned resource that represents proxy parameters +func (r *ReplicaSetsREST) NewGetOptions() (runtime.Object, bool, string) { + return &metav1.ListOptions{}, false, "" +} + +// Get retrieves the object from the storage. It is required to support Patch. +func (r *ReplicaSetsREST) 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 listReplicaSetsByExtensions(ctx, client, namespaceName, name, metaOptions, listOpts) + } + + return listReplicaSetsByApps(ctx, client, namespaceName, name, metaOptions, listOpts) +} + +func listReplicaSetsByExtensions(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/replicasets"), name) + } + + selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector) + if err != nil { + return nil, errors.NewInternalError(err) + } + + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + rsAllList, err := client.ExtensionsV1beta1().ReplicaSets(namespaceName).List(ctx, *listPodsOptions) + if err != nil { + return nil, errors.NewInternalError(err) + } + rsList := &extensionsv1beta1.ReplicaSetList{ + Items: make([]extensionsv1beta1.ReplicaSet, 0), + } + for _, rs := range rsAllList.Items { + for _, references := range rs.ObjectMeta.OwnerReferences { + if references.UID == deployment.GetUID() { + rsList.Items = append(rsList.Items, rs) + } + } + } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "Deployment/ReplicaSets", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "Deployment/ReplicaSets", name, newStart, limit) + if err != nil { + return nil, err + } + items := rsList.Items[newStart : newStart+limit] + rsList.Items = items + } else { + items := rsList.Items[newStart:len(rsList.Items)] + rsList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "Deployment/ReplicaSets", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := rsList.Items[:listOpts.Limit] + rsList.Items = items + } + } + + return rsList, nil +} + +func listReplicaSetsByApps(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/replicasets"), name) + } + + selector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector) + if err != nil { + return nil, errors.NewInternalError(err) + } + + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + rsAllList, err := client.AppsV1().ReplicaSets(namespaceName).List(ctx, *listPodsOptions) + if err != nil { + return nil, errors.NewInternalError(err) + } + + rsList := &appsv1.ReplicaSetList{ + Items: make([]appsv1.ReplicaSet, 0), + } + for _, rs := range rsAllList.Items { + for _, references := range rs.ObjectMeta.OwnerReferences { + if references.UID == deployment.GetUID() { + rsList.Items = append(rsList.Items, rs) + } + } + } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "Deployment/ReplicaSets", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "Deployment/ReplicaSets", name, newStart, limit) + if err != nil { + return nil, err + } + items := rsList.Items[newStart : newStart+limit] + rsList.Items = items + } else { + items := rsList.Items[newStart:len(rsList.Items)] + rsList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "Deployment/ReplicaSets", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := rsList.Items[:listOpts.Limit] + rsList.Items = items + } + } + + return rsList, nil +} diff --git a/pkg/platform/proxy/apps/deployment/storage/storage.go b/pkg/platform/proxy/apps/deployment/storage/storage.go index 3fd2c77b1..ad2d16d09 100644 --- a/pkg/platform/proxy/apps/deployment/storage/storage.go +++ b/pkg/platform/proxy/apps/deployment/storage/storage.go @@ -49,6 +49,7 @@ type Storage struct { Pods *PodREST HPAs *HPARest Events *EventREST + ReplicaSets *ReplicaSetsREST } // REST implements pkg/api/rest.StandardStorage @@ -87,6 +88,9 @@ func NewStorageV1(_ genericregistry.RESTOptionsGetter, platformClient platformin HPAs: &HPARest{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } @@ -126,6 +130,9 @@ func NewStorageV1Beta1(_ genericregistry.RESTOptionsGetter, platformClient platf HPAs: &HPARest{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } @@ -161,6 +168,9 @@ func NewStorageExtensionsV1Beta1(_ genericregistry.RESTOptionsGetter, platformCl HPAs: &HPARest{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } @@ -192,6 +202,9 @@ func NewStorageV1Beta2(_ genericregistry.RESTOptionsGetter, platformClient platf HPAs: &HPARest{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } diff --git a/pkg/platform/proxy/apps/rest/rest.go b/pkg/platform/proxy/apps/rest/rest.go index 2e43bf295..1ef606968 100644 --- a/pkg/platform/proxy/apps/rest/rest.go +++ b/pkg/platform/proxy/apps/rest/rest.go @@ -83,6 +83,7 @@ func (s *StorageProvider) v1Storage(restOptionsGetter generic.RESTOptionsGetter, "controllerrevisions": controllerRevisionStore.ControllerRevision, "daemonsets": daemonSetStore.DaemonSet, "daemonsets/pods": daemonSetStore.Pods, + "daemonsets/replicasets": daemonSetStore.ReplicaSets, "daemonsets/status": daemonSetStore.Status, "daemonsets/events": daemonSetStore.Events, "deployments": deploymentStore.Deployment, @@ -90,11 +91,13 @@ func (s *StorageProvider) v1Storage(restOptionsGetter generic.RESTOptionsGetter, "deployments/scale": deploymentStore.Scale, "deployments/rollback": deploymentStore.RolloutUndo, "deployments/pods": deploymentStore.Pods, + "deployments/replicasets": deploymentStore.ReplicaSets, "deployments/events": deploymentStore.Events, "deployments/horizontalpodautoscalers": deploymentStore.HPAs, "statefulsets": statefulSetStore.StatefulSet, "statefulsets/status": statefulSetStore.Status, "statefulsets/pods": statefulSetStore.Pods, + "statefulsets/replicasets": statefulSetStore.ReplicaSets, "statefulsets/scale": statefulSetStore.Scale, "statefulsets/events": statefulSetStore.Events, "statefulsets/horizontalpodautoscalers": statefulSetStore.HPAs, @@ -122,11 +125,13 @@ func (s *StorageProvider) v1Beta1Storage(restOptionsGetter generic.RESTOptionsGe "deployments/scale": deploymentStore.Scale, "deployments/rollback": deploymentStore.Rollback, "deployments/pods": deploymentStore.Pods, + "deployments/replicasets": deploymentStore.ReplicaSets, "deployments/events": deploymentStore.Events, "deployments/horizontalpodautoscalers": deploymentStore.HPAs, "statefulsets": statefulSetStore.StatefulSet, "statefulsets/status": statefulSetStore.Status, "statefulsets/pods": statefulSetStore.Pods, + "statefulsets/replicasets": statefulSetStore.ReplicaSets, "statefulsets/scale": statefulSetStore.Scale, "statefulsets/events": statefulSetStore.Events, "statefulsets/horizontalpodautoscalers": statefulSetStore.HPAs, @@ -148,17 +153,20 @@ func (s *StorageProvider) v1Beta2Storage(restOptionsGetter generic.RESTOptionsGe "controllerrevisions": controllerRevisionStore.ControllerRevision, "daemonsets": daemonSetStore.DaemonSet, "daemonsets/pods": daemonSetStore.Pods, + "daemonsets/replicasets": daemonSetStore.ReplicaSets, "daemonsets/status": daemonSetStore.Status, "daemonsets/events": daemonSetStore.Events, "deployments": deploymentStore.Deployment, "deployments/status": deploymentStore.Status, "deployments/scale": deploymentStore.Scale, "deployments/pods": deploymentStore.Pods, + "deployments/replicasets": deploymentStore.ReplicaSets, "deployments/events": deploymentStore.Events, "deployments/horizontalpodautoscalers": deploymentStore.HPAs, "statefulsets": statefulSetStore.StatefulSet, "statefulsets/status": statefulSetStore.Status, "statefulsets/pods": statefulSetStore.Pods, + "statefulsets/replicasets": statefulSetStore.ReplicaSets, "statefulsets/scale": statefulSetStore.Scale, "statefulsets/events": statefulSetStore.Events, "statefulsets/horizontalpodautoscalers": statefulSetStore.HPAs, diff --git a/pkg/platform/proxy/apps/statefulset/storage/pod.go b/pkg/platform/proxy/apps/statefulset/storage/pod.go index c3a1f207c..26a8aef8e 100644 --- a/pkg/platform/proxy/apps/statefulset/storage/pod.go +++ b/pkg/platform/proxy/apps/statefulset/storage/pod.go @@ -96,8 +96,15 @@ func listPodsByAppsBeta(ctx context.Context, client *kubernetes.Clientset, names } // list all of the pod, by stateful set labels - listOptions := metav1.ListOptions{LabelSelector: selector.String()} - podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, listOptions) + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, *listPodsOptions) if err != nil { return nil, errors.NewInternalError(err) } @@ -156,8 +163,15 @@ func listPodsByApps(ctx context.Context, client *kubernetes.Clientset, namespace } // list all of the pod, by stateful set labels - listOptions := metav1.ListOptions{LabelSelector: selector.String()} - podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, listOptions) + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, *listPodsOptions) if err != nil { return nil, errors.NewInternalError(err) } diff --git a/pkg/platform/proxy/apps/statefulset/storage/replicasets.go b/pkg/platform/proxy/apps/statefulset/storage/replicasets.go new file mode 100644 index 000000000..54aead6d3 --- /dev/null +++ b/pkg/platform/proxy/apps/statefulset/storage/replicasets.go @@ -0,0 +1,215 @@ +/* + * 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" + + appsv1 "k8s.io/api/apps/v1" + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + "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/endpoints/request" + "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" +) + +// ReplicaSetsREST implements the REST endpoint for find replicasets by a deployment. +type ReplicaSetsREST struct { + rest.Storage + platformClient platforminternalclient.PlatformInterface +} + +var _ rest.GetterWithOptions = &ReplicaSetsREST{} +var _ rest.GroupVersionKindProvider = &ReplicaSetsREST{} + +// GroupVersionKind is used to specify a particular GroupVersionKind to discovery. +func (r *ReplicaSetsREST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { + return appsv1.SchemeGroupVersion.WithKind("ReplicaSetList") +} + +// New returns an empty object that can be used with Create and Update after +// request data has been put into it. +func (r *ReplicaSetsREST) New() runtime.Object { + return &appsv1.ReplicaSetList{} +} + +// NewConnectOptions returns versioned resource that represents proxy parameters +func (r *ReplicaSetsREST) NewGetOptions() (runtime.Object, bool, string) { + return &metav1.ListOptions{}, false, "" +} + +// Get retrieves the object from the storage. It is required to support Patch. +func (r *ReplicaSetsREST) 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 listReplicaSetsByAppsBeta(ctx, client, namespaceName, name, metaOptions, listOpts) + } + return listReplicaSetsByApps(ctx, client, namespaceName, name, metaOptions, listOpts) +} + +func listReplicaSetsByAppsBeta(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(extensionsv1beta1.Resource("statefulSets/replicasets"), name) + } + + selector, err := metav1.LabelSelectorAsSelector(statefulSet.Spec.Selector) + if err != nil { + return nil, errors.NewInternalError(err) + } + + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + rsAllList, err := client.ExtensionsV1beta1().ReplicaSets(namespaceName).List(ctx, *listPodsOptions) + if err != nil { + return nil, errors.NewInternalError(err) + } + rsList := &extensionsv1beta1.ReplicaSetList{ + Items: make([]extensionsv1beta1.ReplicaSet, 0), + } + for _, rs := range rsAllList.Items { + for _, references := range rs.ObjectMeta.OwnerReferences { + if references.UID == statefulSet.GetUID() { + rsList.Items = append(rsList.Items, rs) + } + } + } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "StatefulSet/ReplicaSets", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "StatefulSet/ReplicaSets", name, newStart, limit) + if err != nil { + return nil, err + } + items := rsList.Items[newStart : newStart+limit] + rsList.Items = items + } else { + items := rsList.Items[newStart:len(rsList.Items)] + rsList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "StatefulSet/ReplicaSets", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := rsList.Items[:listOpts.Limit] + rsList.Items = items + } + } + + return rsList, nil +} + +func listReplicaSetsByApps(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(appsv1.Resource("statefulSets/replicasets"), name) + } + + selector, err := metav1.LabelSelectorAsSelector(statefulSet.Spec.Selector) + if err != nil { + return nil, errors.NewInternalError(err) + } + + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + rsAllList, err := client.AppsV1().ReplicaSets(namespaceName).List(ctx, *listPodsOptions) + if err != nil { + return nil, errors.NewInternalError(err) + } + + rsList := &appsv1.ReplicaSetList{ + Items: make([]appsv1.ReplicaSet, 0), + } + for _, rs := range rsAllList.Items { + for _, references := range rs.ObjectMeta.OwnerReferences { + if references.UID == statefulSet.GetUID() { + rsList.Items = append(rsList.Items, rs) + } + } + } + + if listOpts.Continue != "" { + start, limit, err := page.DecodeContinue(ctx, "StatefulSet/ReplicaSets", name, listOpts.Continue) + if err != nil { + return nil, err + } + newStart := start + limit + if int(newStart+limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "StatefulSet/ReplicaSets", name, newStart, limit) + if err != nil { + return nil, err + } + items := rsList.Items[newStart : newStart+limit] + rsList.Items = items + } else { + items := rsList.Items[newStart:len(rsList.Items)] + rsList.Items = items + } + } else if listOpts.Limit != 0 { + if int(listOpts.Limit) < len(rsList.Items) { + rsList.Continue, err = page.EncodeContinue(ctx, "StatefulSet/ReplicaSets", name, 0, listOpts.Limit) + if err != nil { + return nil, err + } + items := rsList.Items[:listOpts.Limit] + rsList.Items = items + } + } + + return rsList, nil +} diff --git a/pkg/platform/proxy/apps/statefulset/storage/storage.go b/pkg/platform/proxy/apps/statefulset/storage/storage.go index b98171776..502bc9242 100644 --- a/pkg/platform/proxy/apps/statefulset/storage/storage.go +++ b/pkg/platform/proxy/apps/statefulset/storage/storage.go @@ -42,6 +42,7 @@ import ( type Storage struct { StatefulSet *REST Pods *PodREST + ReplicaSets *ReplicaSetsREST Status *StatusREST Scale *ScaleREST Events *EventREST @@ -81,6 +82,9 @@ func NewStorageV1(_ genericregistry.RESTOptionsGetter, platformClient platformin HPAs: &HPARest{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } @@ -112,6 +116,9 @@ func NewStorageV1Beta1(_ genericregistry.RESTOptionsGetter, platformClient platf HPAs: &HPARest{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } @@ -143,6 +150,9 @@ func NewStorageV1Beta2(_ genericregistry.RESTOptionsGetter, platformClient platf HPAs: &HPARest{ platformClient: platformClient, }, + ReplicaSets: &ReplicaSetsREST{ + platformClient: platformClient, + }, } } diff --git a/pkg/platform/proxy/batch/job/storage/pod.go b/pkg/platform/proxy/batch/job/storage/pod.go index 4340d463e..82e17e8ce 100644 --- a/pkg/platform/proxy/batch/job/storage/pod.go +++ b/pkg/platform/proxy/batch/job/storage/pod.go @@ -86,8 +86,15 @@ func (r *PodREST) Get(ctx context.Context, name string, options runtime.Object) } // list all of the pod, by deployment labels - listOptions := metav1.ListOptions{LabelSelector: selector.String()} - podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, listOptions) + listPodsOptions := listOpts.DeepCopy() + listPodsOptions.Continue = "" + listPodsOptions.Limit = 0 + if listPodsOptions.LabelSelector == "" { + listPodsOptions.LabelSelector = selector.String() + } else { + listPodsOptions.LabelSelector = listPodsOptions.LabelSelector + "," + selector.String() + } + podAllList, err := client.CoreV1().Pods(namespaceName).List(ctx, *listPodsOptions) if err != nil { return nil, errors.NewInternalError(err) }