mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-07 02:07:58 +00:00
Travis seems to be having issues pulling deps, so we'll have to check in the vendor directory and prevent the makefile from trying to regenerate it normally.
117 lines
3.7 KiB
Go
117 lines
3.7 KiB
Go
/*
|
|
Copyright 2017 The Kubernetes Authors.
|
|
|
|
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
|
|
|
|
http://www.apache.org/licenses/LICENSE-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 OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package pager
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
)
|
|
|
|
const defaultPageSize = 500
|
|
|
|
// ListPageFunc returns a list object for the given list options.
|
|
type ListPageFunc func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error)
|
|
|
|
// SimplePageFunc adapts a context-less list function into one that accepts a context.
|
|
func SimplePageFunc(fn func(opts metav1.ListOptions) (runtime.Object, error)) ListPageFunc {
|
|
return func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
|
|
return fn(opts)
|
|
}
|
|
}
|
|
|
|
// ListPager assists client code in breaking large list queries into multiple
|
|
// smaller chunks of PageSize or smaller. PageFn is expected to accept a
|
|
// metav1.ListOptions that supports paging and return a list. The pager does
|
|
// not alter the field or label selectors on the initial options list.
|
|
type ListPager struct {
|
|
PageSize int64
|
|
PageFn ListPageFunc
|
|
|
|
FullListIfExpired bool
|
|
}
|
|
|
|
// New creates a new pager from the provided pager function using the default
|
|
// options. It will fall back to a full list if an expiration error is encountered
|
|
// as a last resort.
|
|
func New(fn ListPageFunc) *ListPager {
|
|
return &ListPager{
|
|
PageSize: defaultPageSize,
|
|
PageFn: fn,
|
|
FullListIfExpired: true,
|
|
}
|
|
}
|
|
|
|
// TODO: introduce other types of paging functions - such as those that retrieve from a list
|
|
// of namespaces.
|
|
|
|
// List returns a single list object, but attempts to retrieve smaller chunks from the
|
|
// server to reduce the impact on the server. If the chunk attempt fails, it will load
|
|
// the full list instead. The Limit field on options, if unset, will default to the page size.
|
|
func (p *ListPager) List(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
|
|
if options.Limit == 0 {
|
|
options.Limit = p.PageSize
|
|
}
|
|
var list *metainternalversion.List
|
|
for {
|
|
obj, err := p.PageFn(ctx, options)
|
|
if err != nil {
|
|
if !errors.IsResourceExpired(err) || !p.FullListIfExpired {
|
|
return nil, err
|
|
}
|
|
// the list expired while we were processing, fall back to a full list
|
|
options.Limit = 0
|
|
options.Continue = ""
|
|
return p.PageFn(ctx, options)
|
|
}
|
|
m, err := meta.ListAccessor(obj)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("returned object must be a list: %v", err)
|
|
}
|
|
|
|
// exit early and return the object we got if we haven't processed any pages
|
|
if len(m.GetContinue()) == 0 && list == nil {
|
|
return obj, nil
|
|
}
|
|
|
|
// initialize the list and fill its contents
|
|
if list == nil {
|
|
list = &metainternalversion.List{Items: make([]runtime.Object, 0, options.Limit+1)}
|
|
list.ResourceVersion = m.GetResourceVersion()
|
|
list.SelfLink = m.GetSelfLink()
|
|
}
|
|
if err := meta.EachListItem(obj, func(obj runtime.Object) error {
|
|
list.Items = append(list.Items, obj)
|
|
return nil
|
|
}); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// if we have no more items, return the list
|
|
if len(m.GetContinue()) == 0 {
|
|
return list, nil
|
|
}
|
|
|
|
// set the next loop up
|
|
options.Continue = m.GetContinue()
|
|
}
|
|
}
|