mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
rebase: update controller-runtime package to v0.9.2
This commit updates controller-runtime to v0.9.2 and makes changes in persistentvolume.go to add context to various functions and function calls made here instead of context.TODO(). Signed-off-by: Rakshith R <rar@redhat.com>
This commit is contained in:
92
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
generated
vendored
92
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
generated
vendored
@ -21,16 +21,41 @@ package apiutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/discovery"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/restmapper"
|
||||
)
|
||||
|
||||
var (
|
||||
protobufScheme = runtime.NewScheme()
|
||||
protobufSchemeLock sync.RWMutex
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Currently only enabled for built-in resources which are guaranteed to implement Protocol Buffers.
|
||||
// For custom resources, CRDs can not support Protocol Buffers but Aggregated API can.
|
||||
// See doc: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#advanced-features-and-flexibility
|
||||
if err := clientgoscheme.AddToScheme(protobufScheme); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// AddToProtobufScheme add the given SchemeBuilder into protobufScheme, which should
|
||||
// be additional types that do support protobuf.
|
||||
func AddToProtobufScheme(addToScheme func(*runtime.Scheme) error) error {
|
||||
protobufSchemeLock.Lock()
|
||||
defer protobufSchemeLock.Unlock()
|
||||
return addToScheme(protobufScheme)
|
||||
}
|
||||
|
||||
// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery
|
||||
// information fetched by a new client with the given config.
|
||||
func NewDiscoveryRESTMapper(c *rest.Config) (meta.RESTMapper, error) {
|
||||
@ -48,12 +73,33 @@ func NewDiscoveryRESTMapper(c *rest.Config) (meta.RESTMapper, error) {
|
||||
|
||||
// GVKForObject finds the GroupVersionKind associated with the given object, if there is only a single such GVK.
|
||||
func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionKind, error) {
|
||||
// TODO(directxman12): do we want to generalize this to arbitrary container types?
|
||||
// I think we'd need a generalized form of scheme or something. It's a
|
||||
// shame there's not a reliable "GetGVK" interface that works by default
|
||||
// for unpopulated static types and populated "dynamic" types
|
||||
// (unstructured, partial, etc)
|
||||
|
||||
// check for PartialObjectMetadata, which is analogous to unstructured, but isn't handled by ObjectKinds
|
||||
_, isPartial := obj.(*metav1.PartialObjectMetadata) //nolint:ifshort
|
||||
_, isPartialList := obj.(*metav1.PartialObjectMetadataList)
|
||||
if isPartial || isPartialList {
|
||||
// we require that the GVK be populated in order to recognize the object
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
if len(gvk.Kind) == 0 {
|
||||
return schema.GroupVersionKind{}, runtime.NewMissingKindErr("unstructured object has no kind")
|
||||
}
|
||||
if len(gvk.Version) == 0 {
|
||||
return schema.GroupVersionKind{}, runtime.NewMissingVersionErr("unstructured object has no version")
|
||||
}
|
||||
return gvk, nil
|
||||
}
|
||||
|
||||
gvks, isUnversioned, err := scheme.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
if isUnversioned {
|
||||
return schema.GroupVersionKind{}, fmt.Errorf("cannot create a new informer for the unversioned type %T", obj)
|
||||
return schema.GroupVersionKind{}, fmt.Errorf("cannot create group-version-kind for unversioned type %T", obj)
|
||||
}
|
||||
|
||||
if len(gvks) < 1 {
|
||||
@ -71,16 +117,25 @@ func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersi
|
||||
// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated
|
||||
// with the given GroupVersionKind. The REST client will be configured to use the negotiated serializer from
|
||||
// baseConfig, if set, otherwise a default serializer will be set.
|
||||
func RESTClientForGVK(gvk schema.GroupVersionKind, baseConfig *rest.Config, codecs serializer.CodecFactory) (rest.Interface, error) {
|
||||
cfg := createRestConfig(gvk, baseConfig)
|
||||
if cfg.NegotiatedSerializer == nil {
|
||||
cfg.NegotiatedSerializer = serializer.WithoutConversionCodecFactory{CodecFactory: codecs}
|
||||
}
|
||||
return rest.RESTClientFor(cfg)
|
||||
func RESTClientForGVK(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory) (rest.Interface, error) {
|
||||
return rest.RESTClientFor(createRestConfig(gvk, isUnstructured, baseConfig, codecs))
|
||||
}
|
||||
|
||||
//createRestConfig copies the base config and updates needed fields for a new rest config
|
||||
func createRestConfig(gvk schema.GroupVersionKind, baseConfig *rest.Config) *rest.Config {
|
||||
// serializerWithDecodedGVK is a CodecFactory that overrides the DecoderToVersion of a WithoutConversionCodecFactory
|
||||
// in order to avoid clearing the GVK from the decoded object.
|
||||
//
|
||||
// See https://github.com/kubernetes/kubernetes/issues/80609.
|
||||
type serializerWithDecodedGVK struct {
|
||||
serializer.WithoutConversionCodecFactory
|
||||
}
|
||||
|
||||
// DecoderToVersion returns an decoder that does not do conversion.
|
||||
func (f serializerWithDecodedGVK) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder {
|
||||
return serializer
|
||||
}
|
||||
|
||||
// createRestConfig copies the base config and updates needed fields for a new rest config.
|
||||
func createRestConfig(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory) *rest.Config {
|
||||
gv := gvk.GroupVersion()
|
||||
|
||||
cfg := rest.CopyConfig(baseConfig)
|
||||
@ -93,5 +148,24 @@ func createRestConfig(gvk schema.GroupVersionKind, baseConfig *rest.Config) *res
|
||||
if cfg.UserAgent == "" {
|
||||
cfg.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
// TODO(FillZpp): In the long run, we want to check discovery or something to make sure that this is actually true.
|
||||
if cfg.ContentType == "" && !isUnstructured {
|
||||
protobufSchemeLock.RLock()
|
||||
if protobufScheme.Recognizes(gvk) {
|
||||
cfg.ContentType = runtime.ContentTypeProtobuf
|
||||
}
|
||||
protobufSchemeLock.RUnlock()
|
||||
}
|
||||
|
||||
if cfg.NegotiatedSerializer == nil {
|
||||
if isUnstructured {
|
||||
// If the object is unstructured, we need to preserve the GVK information.
|
||||
// Use our own custom serializer.
|
||||
cfg.NegotiatedSerializer = serializerWithDecodedGVK{serializer.WithoutConversionCodecFactory{CodecFactory: codecs}}
|
||||
} else {
|
||||
cfg.NegotiatedSerializer = serializer.WithoutConversionCodecFactory{CodecFactory: codecs}
|
||||
}
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
60
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go
generated
vendored
60
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go
generated
vendored
@ -19,7 +19,6 @@ package apiutil
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
@ -29,34 +28,12 @@ import (
|
||||
"k8s.io/client-go/restmapper"
|
||||
)
|
||||
|
||||
// ErrRateLimited is returned by a RESTMapper method if the number of API
|
||||
// calls has exceeded a limit within a certain time period.
|
||||
type ErrRateLimited struct {
|
||||
// Duration to wait until the next API call can be made.
|
||||
Delay time.Duration
|
||||
}
|
||||
|
||||
func (e ErrRateLimited) Error() string {
|
||||
return "too many API calls to the RESTMapper within a timeframe"
|
||||
}
|
||||
|
||||
// DelayIfRateLimited returns the delay time until the next API call is
|
||||
// allowed and true if err is of type ErrRateLimited. The zero
|
||||
// time.Duration value and false are returned if err is not a ErrRateLimited.
|
||||
func DelayIfRateLimited(err error) (time.Duration, bool) {
|
||||
var rlerr ErrRateLimited
|
||||
if errors.As(err, &rlerr) {
|
||||
return rlerr.Delay, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// dynamicRESTMapper is a RESTMapper that dynamically discovers resource
|
||||
// types at runtime.
|
||||
type dynamicRESTMapper struct {
|
||||
mu sync.RWMutex // protects the following fields
|
||||
staticMapper meta.RESTMapper
|
||||
limiter *dynamicLimiter
|
||||
limiter *rate.Limiter
|
||||
newMapper func() (meta.RESTMapper, error)
|
||||
|
||||
lazy bool
|
||||
@ -64,13 +41,13 @@ type dynamicRESTMapper struct {
|
||||
initOnce sync.Once
|
||||
}
|
||||
|
||||
// DynamicRESTMapperOption is a functional option on the dynamicRESTMapper
|
||||
// DynamicRESTMapperOption is a functional option on the dynamicRESTMapper.
|
||||
type DynamicRESTMapperOption func(*dynamicRESTMapper) error
|
||||
|
||||
// WithLimiter sets the RESTMapper's underlying limiter to lim.
|
||||
func WithLimiter(lim *rate.Limiter) DynamicRESTMapperOption {
|
||||
return func(drm *dynamicRESTMapper) error {
|
||||
drm.limiter = &dynamicLimiter{lim}
|
||||
drm.limiter = lim
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -103,9 +80,7 @@ func NewDynamicRESTMapper(cfg *rest.Config, opts ...DynamicRESTMapperOption) (me
|
||||
return nil, err
|
||||
}
|
||||
drm := &dynamicRESTMapper{
|
||||
limiter: &dynamicLimiter{
|
||||
rate.NewLimiter(rate.Limit(defaultRefillRate), defaultLimitSize),
|
||||
},
|
||||
limiter: rate.NewLimiter(rate.Limit(defaultRefillRate), defaultLimitSize),
|
||||
newMapper: func() (meta.RESTMapper, error) {
|
||||
groupResources, err := restmapper.GetAPIGroupResources(client)
|
||||
if err != nil {
|
||||
@ -161,12 +136,13 @@ func (drm *dynamicRESTMapper) init() (err error) {
|
||||
// checkAndReload attempts to call the given callback, which is assumed to be dependent
|
||||
// on the data in the restmapper.
|
||||
//
|
||||
// If the callback returns a NoKindMatchError, it will attempt to reload
|
||||
// If the callback returns an error that matches the given error, it will attempt to reload
|
||||
// the RESTMapper's data and re-call the callback once that's occurred.
|
||||
// If the callback returns any other error, the function will return immediately regardless.
|
||||
//
|
||||
// It will take care
|
||||
// ensuring that reloads are rate-limitted and that extraneous calls aren't made.
|
||||
// It will take care of ensuring that reloads are rate-limited and that extraneous calls
|
||||
// aren't made. If a reload would exceed the limiters rate, it returns the error return by
|
||||
// the callback.
|
||||
// It's thread-safe, and worries about thread-safety for the callback (so the callback does
|
||||
// not need to attempt to lock the restmapper).
|
||||
func (drm *dynamicRESTMapper) checkAndReload(needsReloadErr error, checkNeedsReload func() error) error {
|
||||
@ -199,7 +175,9 @@ func (drm *dynamicRESTMapper) checkAndReload(needsReloadErr error, checkNeedsRel
|
||||
}
|
||||
|
||||
// we're still stale, so grab a rate-limit token if we can...
|
||||
if err := drm.limiter.checkRate(); err != nil {
|
||||
if !drm.limiter.Allow() {
|
||||
// return error from static mapper here, we have refreshed often enough (exceeding rate of provided limiter)
|
||||
// so that client's can handle this the same way as a "normal" NoResourceMatchError / NoKindMatchError
|
||||
return err
|
||||
}
|
||||
|
||||
@ -305,19 +283,3 @@ func (drm *dynamicRESTMapper) ResourceSingularizer(resource string) (string, err
|
||||
})
|
||||
return singular, err
|
||||
}
|
||||
|
||||
// dynamicLimiter holds a rate limiter used to throttle chatty RESTMapper users.
|
||||
type dynamicLimiter struct {
|
||||
*rate.Limiter
|
||||
}
|
||||
|
||||
// checkRate returns an ErrRateLimited if too many API calls have been made
|
||||
// within the set limit.
|
||||
func (b *dynamicLimiter) checkRate() error {
|
||||
res := b.Reserve()
|
||||
if res.Delay() == 0 {
|
||||
return nil
|
||||
}
|
||||
res.Cancel()
|
||||
return ErrRateLimited{res.Delay()}
|
||||
}
|
||||
|
230
vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
generated
vendored
230
vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
generated
vendored
@ -19,24 +19,47 @@ package client
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/metadata"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
// Options are creation options for a Client
|
||||
// WarningHandlerOptions are options for configuring a
|
||||
// warning handler for the client which is responsible
|
||||
// for surfacing API Server warnings.
|
||||
type WarningHandlerOptions struct {
|
||||
// SuppressWarnings decides if the warnings from the
|
||||
// API server are suppressed or surfaced in the client.
|
||||
SuppressWarnings bool
|
||||
// AllowDuplicateLogs does not deduplicate the to-be
|
||||
// logged surfaced warnings messages. See
|
||||
// log.WarningHandlerOptions for considerations
|
||||
// regarding deuplication
|
||||
AllowDuplicateLogs bool
|
||||
}
|
||||
|
||||
// Options are creation options for a Client.
|
||||
type Options struct {
|
||||
// Scheme, if provided, will be used to map go structs to GroupVersionKinds
|
||||
Scheme *runtime.Scheme
|
||||
|
||||
// Mapper, if provided, will be used to map GroupVersionKinds to Resources
|
||||
Mapper meta.RESTMapper
|
||||
|
||||
// Opts is used to configure the warning handler responsible for
|
||||
// surfacing and handling warnings messages sent by the API server.
|
||||
Opts WarningHandlerOptions
|
||||
}
|
||||
|
||||
// New returns a new Client using the provided config and Options.
|
||||
@ -50,10 +73,31 @@ type Options struct {
|
||||
// case of unstructured types, the group, version, and kind will be extracted
|
||||
// from the corresponding fields on the object.
|
||||
func New(config *rest.Config, options Options) (Client, error) {
|
||||
return newClient(config, options)
|
||||
}
|
||||
|
||||
func newClient(config *rest.Config, options Options) (*client, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("must provide non-nil rest.Config to client.New")
|
||||
}
|
||||
|
||||
if !options.Opts.SuppressWarnings {
|
||||
// surface warnings
|
||||
logger := log.Log.WithName("KubeAPIWarningLogger")
|
||||
// Set a WarningHandler, the default WarningHandler
|
||||
// is log.KubeAPIWarningLogger with deduplication enabled.
|
||||
// See log.KubeAPIWarningLoggerOptions for considerations
|
||||
// regarding deduplication.
|
||||
rest.SetDefaultWarningHandler(
|
||||
log.NewKubeAPIWarningLogger(
|
||||
logger,
|
||||
log.KubeAPIWarningLoggerOptions{
|
||||
Deduplicate: !options.Opts.AllowDuplicateLogs,
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Init a scheme if none provided
|
||||
if options.Scheme == nil {
|
||||
options.Scheme = scheme.Scheme
|
||||
@ -69,11 +113,18 @@ func New(config *rest.Config, options Options) (Client, error) {
|
||||
}
|
||||
|
||||
clientcache := &clientCache{
|
||||
config: config,
|
||||
scheme: options.Scheme,
|
||||
mapper: options.Mapper,
|
||||
codecs: serializer.NewCodecFactory(options.Scheme),
|
||||
resourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
|
||||
config: config,
|
||||
scheme: options.Scheme,
|
||||
mapper: options.Mapper,
|
||||
codecs: serializer.NewCodecFactory(options.Scheme),
|
||||
|
||||
structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
|
||||
unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
|
||||
}
|
||||
|
||||
rawMetaClient, err := metadata.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to construct metadata-only client for use as part of client: %w", err)
|
||||
}
|
||||
|
||||
c := &client{
|
||||
@ -85,6 +136,12 @@ func New(config *rest.Config, options Options) (Client, error) {
|
||||
cache: clientcache,
|
||||
paramCodec: noConversionParamCodec{},
|
||||
},
|
||||
metadataClient: metadataClient{
|
||||
client: rawMetaClient,
|
||||
restMapper: options.Mapper,
|
||||
},
|
||||
scheme: options.Scheme,
|
||||
mapper: options.Mapper,
|
||||
}
|
||||
|
||||
return c, nil
|
||||
@ -97,10 +154,12 @@ var _ Client = &client{}
|
||||
type client struct {
|
||||
typedClient typedClient
|
||||
unstructuredClient unstructuredClient
|
||||
metadataClient metadataClient
|
||||
scheme *runtime.Scheme
|
||||
mapper meta.RESTMapper
|
||||
}
|
||||
|
||||
// resetGroupVersionKind is a helper function to restore and preserve GroupVersionKind on an object.
|
||||
// TODO(vincepri): Remove this function and its calls once controller-runtime dependencies are upgraded to 1.16?
|
||||
func (c *client) resetGroupVersionKind(obj runtime.Object, gvk schema.GroupVersionKind) {
|
||||
if gvk != schema.EmptyObjectKind.GroupVersionKind() {
|
||||
if v, ok := obj.(schema.ObjectKind); ok {
|
||||
@ -109,100 +168,161 @@ func (c *client) resetGroupVersionKind(obj runtime.Object, gvk schema.GroupVersi
|
||||
}
|
||||
}
|
||||
|
||||
// Create implements client.Client
|
||||
func (c *client) Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error {
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
// Scheme returns the scheme this client is using.
|
||||
func (c *client) Scheme() *runtime.Scheme {
|
||||
return c.scheme
|
||||
}
|
||||
|
||||
// RESTMapper returns the scheme this client is using.
|
||||
func (c *client) RESTMapper() meta.RESTMapper {
|
||||
return c.mapper
|
||||
}
|
||||
|
||||
// Create implements client.Client.
|
||||
func (c *client) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return c.unstructuredClient.Create(ctx, obj, opts...)
|
||||
case *metav1.PartialObjectMetadata:
|
||||
return fmt.Errorf("cannot create using only metadata")
|
||||
default:
|
||||
return c.typedClient.Create(ctx, obj, opts...)
|
||||
}
|
||||
return c.typedClient.Create(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Update implements client.Client
|
||||
func (c *client) Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
|
||||
// Update implements client.Client.
|
||||
func (c *client) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return c.unstructuredClient.Update(ctx, obj, opts...)
|
||||
case *metav1.PartialObjectMetadata:
|
||||
return fmt.Errorf("cannot update using only metadata -- did you mean to patch?")
|
||||
default:
|
||||
return c.typedClient.Update(ctx, obj, opts...)
|
||||
}
|
||||
return c.typedClient.Update(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Delete implements client.Client
|
||||
func (c *client) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOption) error {
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
// Delete implements client.Client.
|
||||
func (c *client) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return c.unstructuredClient.Delete(ctx, obj, opts...)
|
||||
case *metav1.PartialObjectMetadata:
|
||||
return c.metadataClient.Delete(ctx, obj, opts...)
|
||||
default:
|
||||
return c.typedClient.Delete(ctx, obj, opts...)
|
||||
}
|
||||
return c.typedClient.Delete(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// DeleteAllOf implements client.Client
|
||||
func (c *client) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...DeleteAllOfOption) error {
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
// DeleteAllOf implements client.Client.
|
||||
func (c *client) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return c.unstructuredClient.DeleteAllOf(ctx, obj, opts...)
|
||||
case *metav1.PartialObjectMetadata:
|
||||
return c.metadataClient.DeleteAllOf(ctx, obj, opts...)
|
||||
default:
|
||||
return c.typedClient.DeleteAllOf(ctx, obj, opts...)
|
||||
}
|
||||
return c.typedClient.DeleteAllOf(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Patch implements client.Client
|
||||
func (c *client) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
// Patch implements client.Client.
|
||||
func (c *client) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return c.unstructuredClient.Patch(ctx, obj, patch, opts...)
|
||||
case *metav1.PartialObjectMetadata:
|
||||
return c.metadataClient.Patch(ctx, obj, patch, opts...)
|
||||
default:
|
||||
return c.typedClient.Patch(ctx, obj, patch, opts...)
|
||||
}
|
||||
return c.typedClient.Patch(ctx, obj, patch, opts...)
|
||||
}
|
||||
|
||||
// Get implements client.Client
|
||||
func (c *client) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
// Get implements client.Client.
|
||||
func (c *client) Get(ctx context.Context, key ObjectKey, obj Object) error {
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return c.unstructuredClient.Get(ctx, key, obj)
|
||||
case *metav1.PartialObjectMetadata:
|
||||
// Metadata only object should always preserve the GVK coming in from the caller.
|
||||
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
||||
return c.metadataClient.Get(ctx, key, obj)
|
||||
default:
|
||||
return c.typedClient.Get(ctx, key, obj)
|
||||
}
|
||||
return c.typedClient.Get(ctx, key, obj)
|
||||
}
|
||||
|
||||
// List implements client.Client
|
||||
func (c *client) List(ctx context.Context, obj runtime.Object, opts ...ListOption) error {
|
||||
_, ok := obj.(*unstructured.UnstructuredList)
|
||||
if ok {
|
||||
// List implements client.Client.
|
||||
func (c *client) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
||||
switch x := obj.(type) {
|
||||
case *unstructured.UnstructuredList:
|
||||
return c.unstructuredClient.List(ctx, obj, opts...)
|
||||
case *metav1.PartialObjectMetadataList:
|
||||
// Metadata only object should always preserve the GVK.
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
defer c.resetGroupVersionKind(obj, gvk)
|
||||
|
||||
// Call the list client.
|
||||
if err := c.metadataClient.List(ctx, obj, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Restore the GVK for each item in the list.
|
||||
itemGVK := schema.GroupVersionKind{
|
||||
Group: gvk.Group,
|
||||
Version: gvk.Version,
|
||||
// TODO: this is producing unsafe guesses that don't actually work,
|
||||
// but it matches ~99% of the cases out there.
|
||||
Kind: strings.TrimSuffix(gvk.Kind, "List"),
|
||||
}
|
||||
for i := range x.Items {
|
||||
item := &x.Items[i]
|
||||
item.SetGroupVersionKind(itemGVK)
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
return c.typedClient.List(ctx, obj, opts...)
|
||||
}
|
||||
return c.typedClient.List(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Status implements client.StatusClient
|
||||
// Status implements client.StatusClient.
|
||||
func (c *client) Status() StatusWriter {
|
||||
return &statusWriter{client: c}
|
||||
}
|
||||
|
||||
// statusWriter is client.StatusWriter that writes status subresource
|
||||
// statusWriter is client.StatusWriter that writes status subresource.
|
||||
type statusWriter struct {
|
||||
client *client
|
||||
}
|
||||
|
||||
// ensure statusWriter implements client.StatusWriter
|
||||
// ensure statusWriter implements client.StatusWriter.
|
||||
var _ StatusWriter = &statusWriter{}
|
||||
|
||||
// Update implements client.StatusWriter
|
||||
func (sw *statusWriter) Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
|
||||
// Update implements client.StatusWriter.
|
||||
func (sw *statusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return sw.client.unstructuredClient.UpdateStatus(ctx, obj, opts...)
|
||||
case *metav1.PartialObjectMetadata:
|
||||
return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?")
|
||||
default:
|
||||
return sw.client.typedClient.UpdateStatus(ctx, obj, opts...)
|
||||
}
|
||||
return sw.client.typedClient.UpdateStatus(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Patch implements client.Client
|
||||
func (sw *statusWriter) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
// Patch implements client.Client.
|
||||
func (sw *statusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if ok {
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return sw.client.unstructuredClient.PatchStatus(ctx, obj, patch, opts...)
|
||||
case *metav1.PartialObjectMetadata:
|
||||
return sw.client.metadataClient.PatchStatus(ctx, obj, patch, opts...)
|
||||
default:
|
||||
return sw.client.typedClient.PatchStatus(ctx, obj, patch, opts...)
|
||||
}
|
||||
return sw.client.typedClient.PatchStatus(ctx, obj, patch, opts...)
|
||||
}
|
||||
|
38
vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go
generated
vendored
38
vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go
generated
vendored
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
@ -29,7 +30,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
)
|
||||
|
||||
// clientCache creates and caches rest clients and metadata for Kubernetes types
|
||||
// clientCache creates and caches rest clients and metadata for Kubernetes types.
|
||||
type clientCache struct {
|
||||
// config is the rest.Config to talk to an apiserver
|
||||
config *rest.Config
|
||||
@ -43,20 +44,22 @@ type clientCache struct {
|
||||
// codecs are used to create a REST client for a gvk
|
||||
codecs serializer.CodecFactory
|
||||
|
||||
// resourceByType caches type metadata
|
||||
resourceByType map[schema.GroupVersionKind]*resourceMeta
|
||||
mu sync.RWMutex
|
||||
// structuredResourceByType caches structured type metadata
|
||||
structuredResourceByType map[schema.GroupVersionKind]*resourceMeta
|
||||
// unstructuredResourceByType caches unstructured type metadata
|
||||
unstructuredResourceByType map[schema.GroupVersionKind]*resourceMeta
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// newResource maps obj to a Kubernetes Resource and constructs a client for that Resource.
|
||||
// If the object is a list, the resource represents the item's type instead.
|
||||
func (c *clientCache) newResource(gvk schema.GroupVersionKind, isList bool) (*resourceMeta, error) {
|
||||
func (c *clientCache) newResource(gvk schema.GroupVersionKind, isList, isUnstructured bool) (*resourceMeta, error) {
|
||||
if strings.HasSuffix(gvk.Kind, "List") && isList {
|
||||
// if this was a list, treat it as a request for the item's resource
|
||||
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
||||
}
|
||||
|
||||
client, err := apiutil.RESTClientForGVK(gvk, c.config, c.codecs)
|
||||
client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -75,10 +78,18 @@ func (c *clientCache) getResource(obj runtime.Object) (*resourceMeta, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, isUnstructured := obj.(*unstructured.Unstructured)
|
||||
_, isUnstructuredList := obj.(*unstructured.UnstructuredList)
|
||||
isUnstructured = isUnstructured || isUnstructuredList
|
||||
|
||||
// It's better to do creation work twice than to not let multiple
|
||||
// people make requests at once
|
||||
c.mu.RLock()
|
||||
r, known := c.resourceByType[gvk]
|
||||
resourceByType := c.structuredResourceByType
|
||||
if isUnstructured {
|
||||
resourceByType = c.unstructuredResourceByType
|
||||
}
|
||||
r, known := resourceByType[gvk]
|
||||
c.mu.RUnlock()
|
||||
|
||||
if known {
|
||||
@ -88,15 +99,15 @@ func (c *clientCache) getResource(obj runtime.Object) (*resourceMeta, error) {
|
||||
// Initialize a new Client
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
r, err = c.newResource(gvk, meta.IsListType(obj))
|
||||
r, err = c.newResource(gvk, meta.IsListType(obj), isUnstructured)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.resourceByType[gvk] = r
|
||||
resourceByType[gvk] = r
|
||||
return r, err
|
||||
}
|
||||
|
||||
// getObjMeta returns objMeta containing both type and object metadata and state
|
||||
// getObjMeta returns objMeta containing both type and object metadata and state.
|
||||
func (c *clientCache) getObjMeta(obj runtime.Object) (*objMeta, error) {
|
||||
r, err := c.getResource(obj)
|
||||
if err != nil {
|
||||
@ -119,18 +130,17 @@ type resourceMeta struct {
|
||||
mapping *meta.RESTMapping
|
||||
}
|
||||
|
||||
// isNamespaced returns true if the type is namespaced
|
||||
// isNamespaced returns true if the type is namespaced.
|
||||
func (r *resourceMeta) isNamespaced() bool {
|
||||
return r.mapping.Scope.Name() != meta.RESTScopeNameRoot
|
||||
|
||||
}
|
||||
|
||||
// resource returns the resource name of the type
|
||||
// resource returns the resource name of the type.
|
||||
func (r *resourceMeta) resource() string {
|
||||
return r.mapping.Resource.Resource
|
||||
}
|
||||
|
||||
// objMeta stores type and object information about a Kubernetes type
|
||||
// objMeta stores type and object information about a Kubernetes type.
|
||||
type objMeta struct {
|
||||
// resourceMeta contains type information for the object
|
||||
*resourceMeta
|
||||
|
18
vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go
generated
vendored
18
vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go
generated
vendored
@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2021 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 client
|
||||
|
||||
import (
|
||||
@ -12,7 +28,7 @@ import (
|
||||
var _ runtime.ParameterCodec = noConversionParamCodec{}
|
||||
|
||||
// noConversionParamCodec is a no-conversion codec for serializing parameters into URL query strings.
|
||||
// it's useful in scenarios with the unstructured client and arbitrary resouces.
|
||||
// it's useful in scenarios with the unstructured client and arbitrary resources.
|
||||
type noConversionParamCodec struct{}
|
||||
|
||||
func (noConversionParamCodec) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) {
|
||||
|
20
vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
generated
vendored
20
vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
generated
vendored
@ -30,19 +30,14 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
kubeconfig, apiServerURL string
|
||||
log = logf.RuntimeLog.WithName("client").WithName("config")
|
||||
kubeconfig string
|
||||
log = logf.RuntimeLog.WithName("client").WithName("config")
|
||||
)
|
||||
|
||||
func init() {
|
||||
// TODO: Fix this to allow double vendoring this library but still register flags on behalf of users
|
||||
flag.StringVar(&kubeconfig, "kubeconfig", "",
|
||||
"Paths to a kubeconfig. Only required if out-of-cluster.")
|
||||
|
||||
// This flag is deprecated, it'll be removed in a future iteration, please switch to --kubeconfig.
|
||||
flag.StringVar(&apiServerURL, "master", "",
|
||||
"(Deprecated: switch to `--kubeconfig`) The address of the Kubernetes API server. Overrides any value in kubeconfig. "+
|
||||
"Only required if out-of-cluster.")
|
||||
}
|
||||
|
||||
// GetConfig creates a *rest.Config for talking to a Kubernetes API server.
|
||||
@ -60,7 +55,7 @@ func init() {
|
||||
//
|
||||
// * In-cluster config if running in cluster
|
||||
//
|
||||
// * $HOME/.kube/config if exists
|
||||
// * $HOME/.kube/config if exists.
|
||||
func GetConfig() (*rest.Config, error) {
|
||||
return GetConfigWithContext("")
|
||||
}
|
||||
@ -80,7 +75,7 @@ func GetConfig() (*rest.Config, error) {
|
||||
//
|
||||
// * In-cluster config if running in cluster
|
||||
//
|
||||
// * $HOME/.kube/config if exists
|
||||
// * $HOME/.kube/config if exists.
|
||||
func GetConfigWithContext(context string) (*rest.Config, error) {
|
||||
cfg, err := loadConfig(context)
|
||||
if err != nil {
|
||||
@ -100,12 +95,11 @@ func GetConfigWithContext(context string) (*rest.Config, error) {
|
||||
// test the precedence of loading the config.
|
||||
var loadInClusterConfig = rest.InClusterConfig
|
||||
|
||||
// loadConfig loads a REST Config as per the rules specified in GetConfig
|
||||
// loadConfig loads a REST Config as per the rules specified in GetConfig.
|
||||
func loadConfig(context string) (*rest.Config, error) {
|
||||
|
||||
// If a flag is specified with the config location, use that
|
||||
if len(kubeconfig) > 0 {
|
||||
return loadConfigWithContext(apiServerURL, &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig}, context)
|
||||
return loadConfigWithContext("", &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig}, context)
|
||||
}
|
||||
|
||||
// If the recommended kubeconfig env variable is not specified,
|
||||
@ -134,7 +128,7 @@ func loadConfig(context string) (*rest.Config, error) {
|
||||
loadingRules.Precedence = append(loadingRules.Precedence, path.Join(u.HomeDir, clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName))
|
||||
}
|
||||
|
||||
return loadConfigWithContext(apiServerURL, loadingRules, context)
|
||||
return loadConfigWithContext("", loadingRules, context)
|
||||
}
|
||||
|
||||
func loadConfigWithContext(apiServerURL string, loader clientcmd.ClientConfigLoader, context string) (*rest.Config, error) {
|
||||
|
51
vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
generated
vendored
51
vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
generated
vendored
@ -19,6 +19,7 @@ package client
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
@ -35,47 +36,57 @@ type dryRunClient struct {
|
||||
client Client
|
||||
}
|
||||
|
||||
// Create implements client.Client
|
||||
func (c *dryRunClient) Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error {
|
||||
// Scheme returns the scheme this client is using.
|
||||
func (c *dryRunClient) Scheme() *runtime.Scheme {
|
||||
return c.client.Scheme()
|
||||
}
|
||||
|
||||
// RESTMapper returns the rest mapper this client is using.
|
||||
func (c *dryRunClient) RESTMapper() meta.RESTMapper {
|
||||
return c.client.RESTMapper()
|
||||
}
|
||||
|
||||
// Create implements client.Client.
|
||||
func (c *dryRunClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||
return c.client.Create(ctx, obj, append(opts, DryRunAll)...)
|
||||
}
|
||||
|
||||
// Update implements client.Client
|
||||
func (c *dryRunClient) Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
|
||||
// Update implements client.Client.
|
||||
func (c *dryRunClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
return c.client.Update(ctx, obj, append(opts, DryRunAll)...)
|
||||
}
|
||||
|
||||
// Delete implements client.Client
|
||||
func (c *dryRunClient) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOption) error {
|
||||
// Delete implements client.Client.
|
||||
func (c *dryRunClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||
return c.client.Delete(ctx, obj, append(opts, DryRunAll)...)
|
||||
}
|
||||
|
||||
// DeleteAllOf implements client.Client
|
||||
func (c *dryRunClient) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...DeleteAllOfOption) error {
|
||||
// DeleteAllOf implements client.Client.
|
||||
func (c *dryRunClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||
return c.client.DeleteAllOf(ctx, obj, append(opts, DryRunAll)...)
|
||||
}
|
||||
|
||||
// Patch implements client.Client
|
||||
func (c *dryRunClient) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
// Patch implements client.Client.
|
||||
func (c *dryRunClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
return c.client.Patch(ctx, obj, patch, append(opts, DryRunAll)...)
|
||||
}
|
||||
|
||||
// Get implements client.Client
|
||||
func (c *dryRunClient) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
|
||||
// Get implements client.Client.
|
||||
func (c *dryRunClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
|
||||
return c.client.Get(ctx, key, obj)
|
||||
}
|
||||
|
||||
// List implements client.Client
|
||||
func (c *dryRunClient) List(ctx context.Context, obj runtime.Object, opts ...ListOption) error {
|
||||
// List implements client.Client.
|
||||
func (c *dryRunClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
||||
return c.client.List(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Status implements client.StatusClient
|
||||
// Status implements client.StatusClient.
|
||||
func (c *dryRunClient) Status() StatusWriter {
|
||||
return &dryRunStatusWriter{client: c.client.Status()}
|
||||
}
|
||||
|
||||
// ensure dryRunStatusWriter implements client.StatusWriter
|
||||
// ensure dryRunStatusWriter implements client.StatusWriter.
|
||||
var _ StatusWriter = &dryRunStatusWriter{}
|
||||
|
||||
// dryRunStatusWriter is client.StatusWriter that writes status subresource with dryRun mode
|
||||
@ -84,12 +95,12 @@ type dryRunStatusWriter struct {
|
||||
client StatusWriter
|
||||
}
|
||||
|
||||
// Update implements client.StatusWriter
|
||||
func (sw *dryRunStatusWriter) Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
|
||||
// Update implements client.StatusWriter.
|
||||
func (sw *dryRunStatusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
return sw.client.Update(ctx, obj, append(opts, DryRunAll)...)
|
||||
}
|
||||
|
||||
// Patch implements client.StatusWriter
|
||||
func (sw *dryRunStatusWriter) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
// Patch implements client.StatusWriter.
|
||||
func (sw *dryRunStatusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
return sw.client.Patch(ctx, obj, patch, append(opts, DryRunAll)...)
|
||||
}
|
||||
|
48
vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
generated
vendored
48
vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
generated
vendored
@ -24,18 +24,15 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
)
|
||||
|
||||
// ObjectKey identifies a Kubernetes Object.
|
||||
type ObjectKey = types.NamespacedName
|
||||
|
||||
// ObjectKeyFromObject returns the ObjectKey given a runtime.Object
|
||||
func ObjectKeyFromObject(obj runtime.Object) (ObjectKey, error) {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return ObjectKey{}, err
|
||||
}
|
||||
return ObjectKey{Namespace: accessor.GetNamespace(), Name: accessor.GetName()}, nil
|
||||
// ObjectKeyFromObject returns the ObjectKey given a runtime.Object.
|
||||
func ObjectKeyFromObject(obj Object) ObjectKey {
|
||||
return ObjectKey{Namespace: obj.GetNamespace(), Name: obj.GetName()}
|
||||
}
|
||||
|
||||
// Patch is a patch that can be applied to a Kubernetes object.
|
||||
@ -43,7 +40,7 @@ type Patch interface {
|
||||
// Type is the PatchType of the patch.
|
||||
Type() types.PatchType
|
||||
// Data is the raw data representing the patch.
|
||||
Data(obj runtime.Object) ([]byte, error)
|
||||
Data(obj Object) ([]byte, error)
|
||||
}
|
||||
|
||||
// TODO(directxman12): is there a sane way to deal with get/delete options?
|
||||
@ -53,32 +50,32 @@ type Reader interface {
|
||||
// Get retrieves an obj for the given object key from the Kubernetes Cluster.
|
||||
// obj must be a struct pointer so that obj can be updated with the response
|
||||
// returned by the Server.
|
||||
Get(ctx context.Context, key ObjectKey, obj runtime.Object) error
|
||||
Get(ctx context.Context, key ObjectKey, obj Object) error
|
||||
|
||||
// List retrieves list of objects for a given namespace and list options. On a
|
||||
// successful call, Items field in the list will be populated with the
|
||||
// result returned from the server.
|
||||
List(ctx context.Context, list runtime.Object, opts ...ListOption) error
|
||||
List(ctx context.Context, list ObjectList, opts ...ListOption) error
|
||||
}
|
||||
|
||||
// Writer knows how to create, delete, and update Kubernetes objects.
|
||||
type Writer interface {
|
||||
// Create saves the object obj in the Kubernetes cluster.
|
||||
Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error
|
||||
Create(ctx context.Context, obj Object, opts ...CreateOption) error
|
||||
|
||||
// Delete deletes the given obj from Kubernetes cluster.
|
||||
Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOption) error
|
||||
Delete(ctx context.Context, obj Object, opts ...DeleteOption) error
|
||||
|
||||
// Update updates the given obj in the Kubernetes cluster. obj must be a
|
||||
// struct pointer so that obj can be updated with the content returned by the Server.
|
||||
Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error
|
||||
Update(ctx context.Context, obj Object, opts ...UpdateOption) error
|
||||
|
||||
// Patch patches the given obj in the Kubernetes cluster. obj must be a
|
||||
// struct pointer so that obj can be updated with the content returned by the Server.
|
||||
Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error
|
||||
Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error
|
||||
|
||||
// DeleteAllOf deletes all objects of the given type matching the given options.
|
||||
DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...DeleteAllOfOption) error
|
||||
DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error
|
||||
}
|
||||
|
||||
// StatusClient knows how to create a client which can update status subresource
|
||||
@ -92,12 +89,12 @@ type StatusWriter interface {
|
||||
// Update updates the fields corresponding to the status subresource for the
|
||||
// given obj. obj must be a struct pointer so that obj can be updated
|
||||
// with the content returned by the Server.
|
||||
Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error
|
||||
Update(ctx context.Context, obj Object, opts ...UpdateOption) error
|
||||
|
||||
// Patch patches the given object's subresource. obj must be a struct
|
||||
// pointer so that obj can be updated with the content returned by the
|
||||
// Server.
|
||||
Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error
|
||||
Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error
|
||||
}
|
||||
|
||||
// Client knows how to perform CRUD operations on Kubernetes objects.
|
||||
@ -105,12 +102,25 @@ type Client interface {
|
||||
Reader
|
||||
Writer
|
||||
StatusClient
|
||||
|
||||
// Scheme returns the scheme this client is using.
|
||||
Scheme() *runtime.Scheme
|
||||
// RESTMapper returns the rest this client is using.
|
||||
RESTMapper() meta.RESTMapper
|
||||
}
|
||||
|
||||
// WithWatch supports Watch on top of the CRUD operations supported by
|
||||
// the normal Client. Its intended use-case are CLI apps that need to wait for
|
||||
// events.
|
||||
type WithWatch interface {
|
||||
Client
|
||||
Watch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// IndexerFunc knows how to take an object and turn it into a series
|
||||
// of non-namespaced keys. Namespaced objects are automatically given
|
||||
// namespaced and non-spaced variants, so keys do not need to include namespace.
|
||||
type IndexerFunc func(runtime.Object) []string
|
||||
type IndexerFunc func(Object) []string
|
||||
|
||||
// FieldIndexer knows how to index over a particular "field" such that it
|
||||
// can later be used by a field selector.
|
||||
@ -122,7 +132,7 @@ type FieldIndexer interface {
|
||||
// and "equality" in the field selector means that at least one key matches the value.
|
||||
// The FieldIndexer will automatically take care of indexing over namespace
|
||||
// and supporting efficient all-namespace queries.
|
||||
IndexField(ctx context.Context, obj runtime.Object, field string, extractValue IndexerFunc) error
|
||||
IndexField(ctx context.Context, obj Object, field string, extractValue IndexerFunc) error
|
||||
}
|
||||
|
||||
// IgnoreNotFound returns nil on NotFound errors.
|
||||
|
195
vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
generated
vendored
Normal file
195
vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
generated
vendored
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
Copyright 2020 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 client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/metadata"
|
||||
)
|
||||
|
||||
// TODO(directxman12): we could rewrite this on top of the low-level REST
|
||||
// client to avoid the extra shallow copy at the end, but I'm not sure it's
|
||||
// worth it -- the metadata client deals with falling back to loading the whole
|
||||
// object on older API servers, etc, and we'd have to reproduce that.
|
||||
|
||||
// metadataClient is a client that reads & writes metadata-only requests to/from the API server.
|
||||
type metadataClient struct {
|
||||
client metadata.Interface
|
||||
restMapper meta.RESTMapper
|
||||
}
|
||||
|
||||
func (mc *metadataClient) getResourceInterface(gvk schema.GroupVersionKind, ns string) (metadata.ResourceInterface, error) {
|
||||
mapping, err := mc.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if mapping.Scope.Name() == meta.RESTScopeNameRoot {
|
||||
return mc.client.Resource(mapping.Resource), nil
|
||||
}
|
||||
return mc.client.Resource(mapping.Resource).Namespace(ns), nil
|
||||
}
|
||||
|
||||
// Delete implements client.Client.
|
||||
func (mc *metadataClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||
metadata, ok := obj.(*metav1.PartialObjectMetadata)
|
||||
if !ok {
|
||||
return fmt.Errorf("metadata client did not understand object: %T", obj)
|
||||
}
|
||||
|
||||
resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), metadata.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deleteOpts := DeleteOptions{}
|
||||
deleteOpts.ApplyOptions(opts)
|
||||
|
||||
return resInt.Delete(ctx, metadata.Name, *deleteOpts.AsDeleteOptions())
|
||||
}
|
||||
|
||||
// DeleteAllOf implements client.Client.
|
||||
func (mc *metadataClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||
metadata, ok := obj.(*metav1.PartialObjectMetadata)
|
||||
if !ok {
|
||||
return fmt.Errorf("metadata client did not understand object: %T", obj)
|
||||
}
|
||||
|
||||
deleteAllOfOpts := DeleteAllOfOptions{}
|
||||
deleteAllOfOpts.ApplyOptions(opts)
|
||||
|
||||
resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), deleteAllOfOpts.ListOptions.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return resInt.DeleteCollection(ctx, *deleteAllOfOpts.AsDeleteOptions(), *deleteAllOfOpts.AsListOptions())
|
||||
}
|
||||
|
||||
// Patch implements client.Client.
|
||||
func (mc *metadataClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
metadata, ok := obj.(*metav1.PartialObjectMetadata)
|
||||
if !ok {
|
||||
return fmt.Errorf("metadata client did not understand object: %T", obj)
|
||||
}
|
||||
|
||||
gvk := metadata.GroupVersionKind()
|
||||
resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := patch.Data(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
patchOpts := &PatchOptions{}
|
||||
patchOpts.ApplyOptions(opts)
|
||||
|
||||
res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*metadata = *res
|
||||
metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get implements client.Client.
|
||||
func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
|
||||
metadata, ok := obj.(*metav1.PartialObjectMetadata)
|
||||
if !ok {
|
||||
return fmt.Errorf("metadata client did not understand object: %T", obj)
|
||||
}
|
||||
|
||||
gvk := metadata.GroupVersionKind()
|
||||
|
||||
resInt, err := mc.getResourceInterface(gvk, key.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := resInt.Get(ctx, key.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*metadata = *res
|
||||
metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
|
||||
return nil
|
||||
}
|
||||
|
||||
// List implements client.Client.
|
||||
func (mc *metadataClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
||||
metadata, ok := obj.(*metav1.PartialObjectMetadataList)
|
||||
if !ok {
|
||||
return fmt.Errorf("metadata client did not understand object: %T", obj)
|
||||
}
|
||||
|
||||
gvk := metadata.GroupVersionKind()
|
||||
if strings.HasSuffix(gvk.Kind, "List") {
|
||||
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
||||
}
|
||||
|
||||
listOpts := ListOptions{}
|
||||
listOpts.ApplyOptions(opts)
|
||||
|
||||
resInt, err := mc.getResourceInterface(gvk, listOpts.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := resInt.List(ctx, *listOpts.AsListOptions())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*metadata = *res
|
||||
metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mc *metadataClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
metadata, ok := obj.(*metav1.PartialObjectMetadata)
|
||||
if !ok {
|
||||
return fmt.Errorf("metadata client did not understand object: %T", obj)
|
||||
}
|
||||
|
||||
gvk := metadata.GroupVersionKind()
|
||||
resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := patch.Data(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
patchOpts := &PatchOptions{}
|
||||
res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions(), "status")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*metadata = *res
|
||||
metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
|
||||
return nil
|
||||
}
|
254
vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
generated
vendored
Normal file
254
vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
generated
vendored
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
Copyright 2020 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 client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
)
|
||||
|
||||
// NewNamespacedClient wraps an existing client enforcing the namespace value.
|
||||
// All functions using this client will have the same namespace declared here.
|
||||
func NewNamespacedClient(c Client, ns string) Client {
|
||||
return &namespacedClient{
|
||||
client: c,
|
||||
namespace: ns,
|
||||
}
|
||||
}
|
||||
|
||||
var _ Client = &namespacedClient{}
|
||||
|
||||
// namespacedClient is a Client that wraps another Client in order to enforce the specified namespace value.
|
||||
type namespacedClient struct {
|
||||
namespace string
|
||||
client Client
|
||||
}
|
||||
|
||||
// Scheme returns the scheme this client is using.
|
||||
func (n *namespacedClient) Scheme() *runtime.Scheme {
|
||||
return n.client.Scheme()
|
||||
}
|
||||
|
||||
// RESTMapper returns the scheme this client is using.
|
||||
func (n *namespacedClient) RESTMapper() meta.RESTMapper {
|
||||
return n.client.RESTMapper()
|
||||
}
|
||||
|
||||
// isNamespaced returns true if the object is namespace scoped.
|
||||
// For unstructured objects the gvk is found from the object itself.
|
||||
// TODO: this is repetitive code. Remove this and use ojectutil.IsNamespaced.
|
||||
func isNamespaced(c Client, obj runtime.Object) (bool, error) {
|
||||
var gvk schema.GroupVersionKind
|
||||
var err error
|
||||
|
||||
_, isUnstructured := obj.(*unstructured.Unstructured)
|
||||
_, isUnstructuredList := obj.(*unstructured.UnstructuredList)
|
||||
|
||||
isUnstructured = isUnstructured || isUnstructuredList
|
||||
if isUnstructured {
|
||||
gvk = obj.GetObjectKind().GroupVersionKind()
|
||||
} else {
|
||||
gvk, err = apiutil.GVKForObject(obj, c.Scheme())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
gk := schema.GroupKind{
|
||||
Group: gvk.Group,
|
||||
Kind: gvk.Kind,
|
||||
}
|
||||
restmapping, err := c.RESTMapper().RESTMapping(gk)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get restmapping: %w", err)
|
||||
}
|
||||
scope := restmapping.Scope.Name()
|
||||
|
||||
if scope == "" {
|
||||
return false, errors.New("scope cannot be identified, empty scope returned")
|
||||
}
|
||||
|
||||
if scope != meta.RESTScopeNameRoot {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Create implements clinet.Client.
|
||||
func (n *namespacedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||
isNamespaceScoped, err := isNamespaced(n.client, obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding the scope of the object: %v", err)
|
||||
}
|
||||
|
||||
objectNamespace := obj.GetNamespace()
|
||||
if objectNamespace != n.namespace && objectNamespace != "" {
|
||||
return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
|
||||
}
|
||||
|
||||
if isNamespaceScoped && objectNamespace == "" {
|
||||
obj.SetNamespace(n.namespace)
|
||||
}
|
||||
return n.client.Create(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Update implements client.Client.
|
||||
func (n *namespacedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
isNamespaceScoped, err := isNamespaced(n.client, obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding the scope of the object: %v", err)
|
||||
}
|
||||
|
||||
objectNamespace := obj.GetNamespace()
|
||||
if objectNamespace != n.namespace && objectNamespace != "" {
|
||||
return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
|
||||
}
|
||||
|
||||
if isNamespaceScoped && objectNamespace == "" {
|
||||
obj.SetNamespace(n.namespace)
|
||||
}
|
||||
return n.client.Update(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Delete implements client.Client.
|
||||
func (n *namespacedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||
isNamespaceScoped, err := isNamespaced(n.client, obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding the scope of the object: %v", err)
|
||||
}
|
||||
|
||||
objectNamespace := obj.GetNamespace()
|
||||
if objectNamespace != n.namespace && objectNamespace != "" {
|
||||
return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
|
||||
}
|
||||
|
||||
if isNamespaceScoped && objectNamespace == "" {
|
||||
obj.SetNamespace(n.namespace)
|
||||
}
|
||||
return n.client.Delete(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// DeleteAllOf implements client.Client.
|
||||
func (n *namespacedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||
isNamespaceScoped, err := isNamespaced(n.client, obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding the scope of the object: %v", err)
|
||||
}
|
||||
|
||||
if isNamespaceScoped {
|
||||
opts = append(opts, InNamespace(n.namespace))
|
||||
}
|
||||
return n.client.DeleteAllOf(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Patch implements client.Client.
|
||||
func (n *namespacedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
isNamespaceScoped, err := isNamespaced(n.client, obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding the scope of the object: %v", err)
|
||||
}
|
||||
|
||||
objectNamespace := obj.GetNamespace()
|
||||
if objectNamespace != n.namespace && objectNamespace != "" {
|
||||
return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
|
||||
}
|
||||
|
||||
if isNamespaceScoped && objectNamespace == "" {
|
||||
obj.SetNamespace(n.namespace)
|
||||
}
|
||||
return n.client.Patch(ctx, obj, patch, opts...)
|
||||
}
|
||||
|
||||
// Get implements client.Client.
|
||||
func (n *namespacedClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
|
||||
isNamespaceScoped, err := isNamespaced(n.client, obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding the scope of the object: %v", err)
|
||||
}
|
||||
if isNamespaceScoped {
|
||||
if key.Namespace != "" && key.Namespace != n.namespace {
|
||||
return fmt.Errorf("namespace %s provided for the object %s does not match the namesapce %s on the client", key.Namespace, obj.GetName(), n.namespace)
|
||||
}
|
||||
key.Namespace = n.namespace
|
||||
}
|
||||
return n.client.Get(ctx, key, obj)
|
||||
}
|
||||
|
||||
// List implements client.Client.
|
||||
func (n *namespacedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
||||
if n.namespace != "" {
|
||||
opts = append(opts, InNamespace(n.namespace))
|
||||
}
|
||||
return n.client.List(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Status implements client.StatusClient.
|
||||
func (n *namespacedClient) Status() StatusWriter {
|
||||
return &namespacedClientStatusWriter{StatusClient: n.client.Status(), namespace: n.namespace, namespacedclient: n}
|
||||
}
|
||||
|
||||
// ensure namespacedClientStatusWriter implements client.StatusWriter.
|
||||
var _ StatusWriter = &namespacedClientStatusWriter{}
|
||||
|
||||
type namespacedClientStatusWriter struct {
|
||||
StatusClient StatusWriter
|
||||
namespace string
|
||||
namespacedclient Client
|
||||
}
|
||||
|
||||
// Update implements client.StatusWriter.
|
||||
func (nsw *namespacedClientStatusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
isNamespaceScoped, err := isNamespaced(nsw.namespacedclient, obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding the scope of the object: %v", err)
|
||||
}
|
||||
|
||||
objectNamespace := obj.GetNamespace()
|
||||
if objectNamespace != nsw.namespace && objectNamespace != "" {
|
||||
return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
|
||||
}
|
||||
|
||||
if isNamespaceScoped && objectNamespace == "" {
|
||||
obj.SetNamespace(nsw.namespace)
|
||||
}
|
||||
return nsw.StatusClient.Update(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
// Patch implements client.StatusWriter.
|
||||
func (nsw *namespacedClientStatusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
isNamespaceScoped, err := isNamespaced(nsw.namespacedclient, obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding the scope of the object: %v", err)
|
||||
}
|
||||
|
||||
objectNamespace := obj.GetNamespace()
|
||||
if objectNamespace != nsw.namespace && objectNamespace != "" {
|
||||
return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
|
||||
}
|
||||
|
||||
if isNamespaceScoped && objectNamespace == "" {
|
||||
obj.SetNamespace(nsw.namespace)
|
||||
}
|
||||
return nsw.StatusClient.Patch(ctx, obj, patch, opts...)
|
||||
}
|
77
vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go
generated
vendored
Normal file
77
vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright 2020 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 client
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Object is a Kubernetes object, allows functions to work indistinctly with
|
||||
// any resource that implements both Object interfaces.
|
||||
//
|
||||
// Semantically, these are objects which are both serializable (runtime.Object)
|
||||
// and identifiable (metav1.Object) -- think any object which you could write
|
||||
// as YAML or JSON, and then `kubectl create`.
|
||||
//
|
||||
// Code-wise, this means that any object which embeds both ObjectMeta (which
|
||||
// provides metav1.Object) and TypeMeta (which provides half of runtime.Object)
|
||||
// and has a `DeepCopyObject` implementation (the other half of runtime.Object)
|
||||
// will implement this by default.
|
||||
//
|
||||
// For example, nearly all the built-in types are Objects, as well as all
|
||||
// KubeBuilder-generated CRDs (unless you do something real funky to them).
|
||||
//
|
||||
// By and large, most things that implement runtime.Object also implement
|
||||
// Object -- it's very rare to have *just* a runtime.Object implementation (the
|
||||
// cases tend to be funky built-in types like Webhook payloads that don't have
|
||||
// a `metadata` field).
|
||||
//
|
||||
// Notice that XYZList types are distinct: they implement ObjectList instead.
|
||||
type Object interface {
|
||||
metav1.Object
|
||||
runtime.Object
|
||||
}
|
||||
|
||||
// ObjectList is a Kubernetes object list, allows functions to work
|
||||
// indistinctly with any resource that implements both runtime.Object and
|
||||
// metav1.ListInterface interfaces.
|
||||
//
|
||||
// Semantically, this is any object which may be serialized (ObjectMeta), and
|
||||
// is a kubernetes list wrapper (has items, pagination fields, etc) -- think
|
||||
// the wrapper used in a response from a `kubectl list --output yaml` call.
|
||||
//
|
||||
// Code-wise, this means that any object which embedds both ListMeta (which
|
||||
// provides metav1.ListInterface) and TypeMeta (which provides half of
|
||||
// runtime.Object) and has a `DeepCopyObject` implementation (the other half of
|
||||
// runtime.Object) will implement this by default.
|
||||
//
|
||||
// For example, nearly all the built-in XYZList types are ObjectLists, as well
|
||||
// as the XYZList types for all KubeBuilder-generated CRDs (unless you do
|
||||
// something real funky to them).
|
||||
//
|
||||
// By and large, most things that are XYZList and implement runtime.Object also
|
||||
// implement ObjectList -- it's very rare to have *just* a runtime.Object
|
||||
// implementation (the cases tend to be funky built-in types like Webhook
|
||||
// payloads that don't have a `metadata` field).
|
||||
//
|
||||
// This is similar to Object, which is almost always implemented by the items
|
||||
// in the list themselves.
|
||||
type ObjectList interface {
|
||||
metav1.ListInterface
|
||||
runtime.Object
|
||||
}
|
35
vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
generated
vendored
35
vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
generated
vendored
@ -158,7 +158,7 @@ func (o *CreateOptions) ApplyOptions(opts []CreateOption) *CreateOptions {
|
||||
return o
|
||||
}
|
||||
|
||||
// ApplyToCreate implements CreateOption
|
||||
// ApplyToCreate implements CreateOption.
|
||||
func (o *CreateOptions) ApplyToCreate(co *CreateOptions) {
|
||||
if o.DryRun != nil {
|
||||
co.DryRun = o.DryRun
|
||||
@ -173,11 +173,6 @@ func (o *CreateOptions) ApplyToCreate(co *CreateOptions) {
|
||||
|
||||
var _ CreateOption = &CreateOptions{}
|
||||
|
||||
// CreateDryRunAll sets the "dry run" option to "all".
|
||||
//
|
||||
// Deprecated: Use DryRunAll
|
||||
var CreateDryRunAll = DryRunAll
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ Delete Options
|
||||
@ -244,7 +239,7 @@ func (o *DeleteOptions) ApplyOptions(opts []DeleteOption) *DeleteOptions {
|
||||
|
||||
var _ DeleteOption = &DeleteOptions{}
|
||||
|
||||
// ApplyToDelete implements DeleteOption
|
||||
// ApplyToDelete implements DeleteOption.
|
||||
func (o *DeleteOptions) ApplyToDelete(do *DeleteOptions) {
|
||||
if o.GracePeriodSeconds != nil {
|
||||
do.GracePeriodSeconds = o.GracePeriodSeconds
|
||||
@ -354,7 +349,7 @@ type ListOptions struct {
|
||||
|
||||
var _ ListOption = &ListOptions{}
|
||||
|
||||
// ApplyToList implements ListOption for ListOptions
|
||||
// ApplyToList implements ListOption for ListOptions.
|
||||
func (o *ListOptions) ApplyToList(lo *ListOptions) {
|
||||
if o.LabelSelector != nil {
|
||||
lo.LabelSelector = o.LabelSelector
|
||||
@ -460,14 +455,6 @@ func (m MatchingLabelsSelector) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
|
||||
m.ApplyToList(&opts.ListOptions)
|
||||
}
|
||||
|
||||
// MatchingField filters the list operation on the given field selector
|
||||
// (or index in the case of cached lists).
|
||||
//
|
||||
// Deprecated: Use MatchingFields
|
||||
func MatchingField(name, val string) MatchingFields {
|
||||
return MatchingFields{name: val}
|
||||
}
|
||||
|
||||
// MatchingFields filters the list/delete operation on the given field Set
|
||||
// (or index in the case of cached lists).
|
||||
type MatchingFields fields.Set
|
||||
@ -582,7 +569,7 @@ func (o *UpdateOptions) ApplyOptions(opts []UpdateOption) *UpdateOptions {
|
||||
|
||||
var _ UpdateOption = &UpdateOptions{}
|
||||
|
||||
// ApplyToUpdate implements UpdateOption
|
||||
// ApplyToUpdate implements UpdateOption.
|
||||
func (o *UpdateOptions) ApplyToUpdate(uo *UpdateOptions) {
|
||||
if o.DryRun != nil {
|
||||
uo.DryRun = o.DryRun
|
||||
@ -595,11 +582,6 @@ func (o *UpdateOptions) ApplyToUpdate(uo *UpdateOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateDryRunAll sets the "dry run" option to "all".
|
||||
//
|
||||
// Deprecated: Use DryRunAll
|
||||
var UpdateDryRunAll = DryRunAll
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ Patch Options
|
||||
@ -654,7 +636,7 @@ func (o *PatchOptions) AsPatchOptions() *metav1.PatchOptions {
|
||||
|
||||
var _ PatchOption = &PatchOptions{}
|
||||
|
||||
// ApplyToPatch implements PatchOptions
|
||||
// ApplyToPatch implements PatchOptions.
|
||||
func (o *PatchOptions) ApplyToPatch(po *PatchOptions) {
|
||||
if o.DryRun != nil {
|
||||
po.DryRun = o.DryRun
|
||||
@ -682,11 +664,6 @@ func (forceOwnership) ApplyToPatch(opts *PatchOptions) {
|
||||
opts.Force = &definitelyTrue
|
||||
}
|
||||
|
||||
// PatchDryRunAll sets the "dry run" option to "all".
|
||||
//
|
||||
// Deprecated: Use DryRunAll
|
||||
var PatchDryRunAll = DryRunAll
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ DeleteAllOf Options
|
||||
@ -711,7 +688,7 @@ func (o *DeleteAllOfOptions) ApplyOptions(opts []DeleteAllOfOption) *DeleteAllOf
|
||||
|
||||
var _ DeleteAllOfOption = &DeleteAllOfOptions{}
|
||||
|
||||
// ApplyToDeleteAllOf implements DeleteAllOfOption
|
||||
// ApplyToDeleteAllOf implements DeleteAllOfOption.
|
||||
func (o *DeleteAllOfOptions) ApplyToDeleteAllOf(do *DeleteAllOfOptions) {
|
||||
o.ApplyToList(&do.ListOptions)
|
||||
o.ApplyToDelete(&do.DeleteOptions)
|
||||
|
126
vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go
generated
vendored
126
vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go
generated
vendored
@ -17,19 +17,21 @@ limitations under the License.
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
)
|
||||
|
||||
var (
|
||||
// Apply uses server-side apply to patch the given object.
|
||||
Apply = applyPatch{}
|
||||
Apply Patch = applyPatch{}
|
||||
|
||||
// Merge uses the raw object as a merge patch, without modifications.
|
||||
// Use MergeFrom if you wish to compute a diff instead.
|
||||
Merge = mergePatch{}
|
||||
Merge Patch = mergePatch{}
|
||||
)
|
||||
|
||||
type patch struct {
|
||||
@ -43,7 +45,7 @@ func (s *patch) Type() types.PatchType {
|
||||
}
|
||||
|
||||
// Data implements Patch.
|
||||
func (s *patch) Data(obj runtime.Object) ([]byte, error) {
|
||||
func (s *patch) Data(obj Object) ([]byte, error) {
|
||||
return s.data, nil
|
||||
}
|
||||
|
||||
@ -52,40 +54,128 @@ func RawPatch(patchType types.PatchType, data []byte) Patch {
|
||||
return &patch{patchType, data}
|
||||
}
|
||||
|
||||
// ConstantPatch constructs a new Patch with the given PatchType and data.
|
||||
// MergeFromWithOptimisticLock can be used if clients want to make sure a patch
|
||||
// is being applied to the latest resource version of an object.
|
||||
//
|
||||
// Deprecated: use RawPatch instead
|
||||
func ConstantPatch(patchType types.PatchType, data []byte) Patch {
|
||||
return RawPatch(patchType, data)
|
||||
// The behavior is similar to what an Update would do, without the need to send the
|
||||
// whole object. Usually this method is useful if you might have multiple clients
|
||||
// acting on the same object and the same API version, but with different versions of the Go structs.
|
||||
//
|
||||
// For example, an "older" copy of a Widget that has fields A and B, and a "newer" copy with A, B, and C.
|
||||
// Sending an update using the older struct definition results in C being dropped, whereas using a patch does not.
|
||||
type MergeFromWithOptimisticLock struct{}
|
||||
|
||||
// ApplyToMergeFrom applies this configuration to the given patch options.
|
||||
func (m MergeFromWithOptimisticLock) ApplyToMergeFrom(in *MergeFromOptions) {
|
||||
in.OptimisticLock = true
|
||||
}
|
||||
|
||||
// MergeFromOption is some configuration that modifies options for a merge-from patch data.
|
||||
type MergeFromOption interface {
|
||||
// ApplyToMergeFrom applies this configuration to the given patch options.
|
||||
ApplyToMergeFrom(*MergeFromOptions)
|
||||
}
|
||||
|
||||
// MergeFromOptions contains options to generate a merge-from patch data.
|
||||
type MergeFromOptions struct {
|
||||
// OptimisticLock, when true, includes `metadata.resourceVersion` into the final
|
||||
// patch data. If the `resourceVersion` field doesn't match what's stored,
|
||||
// the operation results in a conflict and clients will need to try again.
|
||||
OptimisticLock bool
|
||||
}
|
||||
|
||||
type mergeFromPatch struct {
|
||||
from runtime.Object
|
||||
patchType types.PatchType
|
||||
createPatch func(originalJSON, modifiedJSON []byte, dataStruct interface{}) ([]byte, error)
|
||||
from Object
|
||||
opts MergeFromOptions
|
||||
}
|
||||
|
||||
// Type implements patch.
|
||||
// Type implements Patch.
|
||||
func (s *mergeFromPatch) Type() types.PatchType {
|
||||
return types.MergePatchType
|
||||
return s.patchType
|
||||
}
|
||||
|
||||
// Data implements Patch.
|
||||
func (s *mergeFromPatch) Data(obj runtime.Object) ([]byte, error) {
|
||||
originalJSON, err := json.Marshal(s.from)
|
||||
func (s *mergeFromPatch) Data(obj Object) ([]byte, error) {
|
||||
original := s.from
|
||||
modified := obj
|
||||
|
||||
if s.opts.OptimisticLock {
|
||||
version := original.GetResourceVersion()
|
||||
if len(version) == 0 {
|
||||
return nil, fmt.Errorf("cannot use OptimisticLock, object %q does not have any resource version we can use", original)
|
||||
}
|
||||
|
||||
original = original.DeepCopyObject().(Object)
|
||||
original.SetResourceVersion("")
|
||||
|
||||
modified = modified.DeepCopyObject().(Object)
|
||||
modified.SetResourceVersion(version)
|
||||
}
|
||||
|
||||
originalJSON, err := json.Marshal(original)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modifiedJSON, err := json.Marshal(obj)
|
||||
modifiedJSON, err := json.Marshal(modified)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := s.createPatch(originalJSON, modifiedJSON, obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func createMergePatch(originalJSON, modifiedJSON []byte, _ interface{}) ([]byte, error) {
|
||||
return jsonpatch.CreateMergePatch(originalJSON, modifiedJSON)
|
||||
}
|
||||
|
||||
func createStrategicMergePatch(originalJSON, modifiedJSON []byte, dataStruct interface{}) ([]byte, error) {
|
||||
return strategicpatch.CreateTwoWayMergePatch(originalJSON, modifiedJSON, dataStruct)
|
||||
}
|
||||
|
||||
// MergeFrom creates a Patch that patches using the merge-patch strategy with the given object as base.
|
||||
func MergeFrom(obj runtime.Object) Patch {
|
||||
return &mergeFromPatch{obj}
|
||||
// The difference between MergeFrom and StrategicMergeFrom lays in the handling of modified list fields.
|
||||
// When using MergeFrom, existing lists will be completely replaced by new lists.
|
||||
// When using StrategicMergeFrom, the list field's `patchStrategy` is respected if specified in the API type,
|
||||
// e.g. the existing list is not replaced completely but rather merged with the new one using the list's `patchMergeKey`.
|
||||
// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ for more details on
|
||||
// the difference between merge-patch and strategic-merge-patch.
|
||||
func MergeFrom(obj Object) Patch {
|
||||
return &mergeFromPatch{patchType: types.MergePatchType, createPatch: createMergePatch, from: obj}
|
||||
}
|
||||
|
||||
// MergeFromWithOptions creates a Patch that patches using the merge-patch strategy with the given object as base.
|
||||
// See MergeFrom for more details.
|
||||
func MergeFromWithOptions(obj Object, opts ...MergeFromOption) Patch {
|
||||
options := &MergeFromOptions{}
|
||||
for _, opt := range opts {
|
||||
opt.ApplyToMergeFrom(options)
|
||||
}
|
||||
return &mergeFromPatch{patchType: types.MergePatchType, createPatch: createMergePatch, from: obj, opts: *options}
|
||||
}
|
||||
|
||||
// StrategicMergeFrom creates a Patch that patches using the strategic-merge-patch strategy with the given object as base.
|
||||
// The difference between MergeFrom and StrategicMergeFrom lays in the handling of modified list fields.
|
||||
// When using MergeFrom, existing lists will be completely replaced by new lists.
|
||||
// When using StrategicMergeFrom, the list field's `patchStrategy` is respected if specified in the API type,
|
||||
// e.g. the existing list is not replaced completely but rather merged with the new one using the list's `patchMergeKey`.
|
||||
// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ for more details on
|
||||
// the difference between merge-patch and strategic-merge-patch.
|
||||
// Please note, that CRDs don't support strategic-merge-patch, see
|
||||
// https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#advanced-features-and-flexibility
|
||||
func StrategicMergeFrom(obj Object, opts ...MergeFromOption) Patch {
|
||||
options := &MergeFromOptions{}
|
||||
for _, opt := range opts {
|
||||
opt.ApplyToMergeFrom(options)
|
||||
}
|
||||
return &mergeFromPatch{patchType: types.StrategicMergePatchType, createPatch: createStrategicMergePatch, from: obj, opts: *options}
|
||||
}
|
||||
|
||||
// mergePatch uses a raw merge strategy to patch the object.
|
||||
@ -97,7 +187,7 @@ func (p mergePatch) Type() types.PatchType {
|
||||
}
|
||||
|
||||
// Data implements Patch.
|
||||
func (p mergePatch) Data(obj runtime.Object) ([]byte, error) {
|
||||
func (p mergePatch) Data(obj Object) ([]byte, error) {
|
||||
// NB(directxman12): we might technically want to be using an actual encoder
|
||||
// here (in case some more performant encoder is introduced) but this is
|
||||
// correct and sufficient for our uses (it's what the JSON serializer in
|
||||
@ -114,7 +204,7 @@ func (p applyPatch) Type() types.PatchType {
|
||||
}
|
||||
|
||||
// Data implements Patch.
|
||||
func (p applyPatch) Data(obj runtime.Object) ([]byte, error) {
|
||||
func (p applyPatch) Data(obj Object) ([]byte, error) {
|
||||
// NB(directxman12): we might technically want to be using an actual encoder
|
||||
// here (in case some more performant encoder is introduced) but this is
|
||||
// correct and sufficient for our uses (it's what the JSON serializer in
|
||||
|
100
vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go
generated
vendored
100
vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go
generated
vendored
@ -18,43 +18,123 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
)
|
||||
|
||||
// DelegatingClient forms a Client by composing separate reader, writer and
|
||||
// NewDelegatingClientInput encapsulates the input parameters to create a new delegating client.
|
||||
type NewDelegatingClientInput struct {
|
||||
CacheReader Reader
|
||||
Client Client
|
||||
UncachedObjects []Object
|
||||
CacheUnstructured bool
|
||||
}
|
||||
|
||||
// NewDelegatingClient creates a new delegating client.
|
||||
//
|
||||
// A delegating client forms a Client by composing separate reader, writer and
|
||||
// statusclient interfaces. This way, you can have an Client that reads from a
|
||||
// cache and writes to the API server.
|
||||
type DelegatingClient struct {
|
||||
func NewDelegatingClient(in NewDelegatingClientInput) (Client, error) {
|
||||
uncachedGVKs := map[schema.GroupVersionKind]struct{}{}
|
||||
for _, obj := range in.UncachedObjects {
|
||||
gvk, err := apiutil.GVKForObject(obj, in.Client.Scheme())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uncachedGVKs[gvk] = struct{}{}
|
||||
}
|
||||
|
||||
return &delegatingClient{
|
||||
scheme: in.Client.Scheme(),
|
||||
mapper: in.Client.RESTMapper(),
|
||||
Reader: &delegatingReader{
|
||||
CacheReader: in.CacheReader,
|
||||
ClientReader: in.Client,
|
||||
scheme: in.Client.Scheme(),
|
||||
uncachedGVKs: uncachedGVKs,
|
||||
cacheUnstructured: in.CacheUnstructured,
|
||||
},
|
||||
Writer: in.Client,
|
||||
StatusClient: in.Client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type delegatingClient struct {
|
||||
Reader
|
||||
Writer
|
||||
StatusClient
|
||||
|
||||
scheme *runtime.Scheme
|
||||
mapper meta.RESTMapper
|
||||
}
|
||||
|
||||
// DelegatingReader forms a Reader that will cause Get and List requests for
|
||||
// Scheme returns the scheme this client is using.
|
||||
func (d *delegatingClient) Scheme() *runtime.Scheme {
|
||||
return d.scheme
|
||||
}
|
||||
|
||||
// RESTMapper returns the rest mapper this client is using.
|
||||
func (d *delegatingClient) RESTMapper() meta.RESTMapper {
|
||||
return d.mapper
|
||||
}
|
||||
|
||||
// delegatingReader forms a Reader that will cause Get and List requests for
|
||||
// unstructured types to use the ClientReader while requests for any other type
|
||||
// of object with use the CacheReader. This avoids accidentally caching the
|
||||
// entire cluster in the common case of loading arbitrary unstructured objects
|
||||
// (e.g. from OwnerReferences).
|
||||
type DelegatingReader struct {
|
||||
type delegatingReader struct {
|
||||
CacheReader Reader
|
||||
ClientReader Reader
|
||||
|
||||
uncachedGVKs map[schema.GroupVersionKind]struct{}
|
||||
scheme *runtime.Scheme
|
||||
cacheUnstructured bool
|
||||
}
|
||||
|
||||
func (d *delegatingReader) shouldBypassCache(obj runtime.Object) (bool, error) {
|
||||
gvk, err := apiutil.GVKForObject(obj, d.scheme)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// TODO: this is producing unsafe guesses that don't actually work,
|
||||
// but it matches ~99% of the cases out there.
|
||||
if meta.IsListType(obj) {
|
||||
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
|
||||
}
|
||||
if _, isUncached := d.uncachedGVKs[gvk]; isUncached {
|
||||
return true, nil
|
||||
}
|
||||
if !d.cacheUnstructured {
|
||||
_, isUnstructured := obj.(*unstructured.Unstructured)
|
||||
_, isUnstructuredList := obj.(*unstructured.UnstructuredList)
|
||||
return isUnstructured || isUnstructuredList, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Get retrieves an obj for a given object key from the Kubernetes Cluster.
|
||||
func (d *DelegatingReader) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
|
||||
_, isUnstructured := obj.(*unstructured.Unstructured)
|
||||
if isUnstructured {
|
||||
func (d *delegatingReader) Get(ctx context.Context, key ObjectKey, obj Object) error {
|
||||
if isUncached, err := d.shouldBypassCache(obj); err != nil {
|
||||
return err
|
||||
} else if isUncached {
|
||||
return d.ClientReader.Get(ctx, key, obj)
|
||||
}
|
||||
return d.CacheReader.Get(ctx, key, obj)
|
||||
}
|
||||
|
||||
// List retrieves list of objects for a given namespace and list options.
|
||||
func (d *DelegatingReader) List(ctx context.Context, list runtime.Object, opts ...ListOption) error {
|
||||
_, isUnstructured := list.(*unstructured.UnstructuredList)
|
||||
if isUnstructured {
|
||||
func (d *delegatingReader) List(ctx context.Context, list ObjectList, opts ...ListOption) error {
|
||||
if isUncached, err := d.shouldBypassCache(list); err != nil {
|
||||
return err
|
||||
} else if isUncached {
|
||||
return d.ClientReader.List(ctx, list, opts...)
|
||||
}
|
||||
return d.CacheReader.List(ctx, list, opts...)
|
||||
|
36
vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
generated
vendored
36
vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
generated
vendored
@ -22,6 +22,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var _ Reader = &typedClient{}
|
||||
var _ Writer = &typedClient{}
|
||||
var _ StatusWriter = &typedClient{}
|
||||
|
||||
// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes
|
||||
// new clients at the time they are used, and caches the client.
|
||||
type typedClient struct {
|
||||
@ -29,8 +33,8 @@ type typedClient struct {
|
||||
paramCodec runtime.ParameterCodec
|
||||
}
|
||||
|
||||
// Create implements client.Client
|
||||
func (c *typedClient) Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error {
|
||||
// Create implements client.Client.
|
||||
func (c *typedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||
o, err := c.cache.getObjMeta(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -47,8 +51,8 @@ func (c *typedClient) Create(ctx context.Context, obj runtime.Object, opts ...Cr
|
||||
Into(obj)
|
||||
}
|
||||
|
||||
// Update implements client.Client
|
||||
func (c *typedClient) Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
|
||||
// Update implements client.Client.
|
||||
func (c *typedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
o, err := c.cache.getObjMeta(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -66,8 +70,8 @@ func (c *typedClient) Update(ctx context.Context, obj runtime.Object, opts ...Up
|
||||
Into(obj)
|
||||
}
|
||||
|
||||
// Delete implements client.Client
|
||||
func (c *typedClient) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOption) error {
|
||||
// Delete implements client.Client.
|
||||
func (c *typedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||
o, err := c.cache.getObjMeta(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -85,8 +89,8 @@ func (c *typedClient) Delete(ctx context.Context, obj runtime.Object, opts ...De
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteAllOf implements client.Client
|
||||
func (c *typedClient) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...DeleteAllOfOption) error {
|
||||
// DeleteAllOf implements client.Client.
|
||||
func (c *typedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||
o, err := c.cache.getObjMeta(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -104,8 +108,8 @@ func (c *typedClient) DeleteAllOf(ctx context.Context, obj runtime.Object, opts
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch implements client.Client
|
||||
func (c *typedClient) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
// Patch implements client.Client.
|
||||
func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
o, err := c.cache.getObjMeta(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -127,8 +131,8 @@ func (c *typedClient) Patch(ctx context.Context, obj runtime.Object, patch Patch
|
||||
Into(obj)
|
||||
}
|
||||
|
||||
// Get implements client.Client
|
||||
func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
|
||||
// Get implements client.Client.
|
||||
func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
|
||||
r, err := c.cache.getResource(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -139,8 +143,8 @@ func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj runtime.Object
|
||||
Name(key.Name).Do(ctx).Into(obj)
|
||||
}
|
||||
|
||||
// List implements client.Client
|
||||
func (c *typedClient) List(ctx context.Context, obj runtime.Object, opts ...ListOption) error {
|
||||
// List implements client.Client.
|
||||
func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
||||
r, err := c.cache.getResource(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -156,7 +160,7 @@ func (c *typedClient) List(ctx context.Context, obj runtime.Object, opts ...List
|
||||
}
|
||||
|
||||
// UpdateStatus used by StatusWriter to write status.
|
||||
func (c *typedClient) UpdateStatus(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
|
||||
func (c *typedClient) UpdateStatus(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
o, err := c.cache.getObjMeta(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -177,7 +181,7 @@ func (c *typedClient) UpdateStatus(ctx context.Context, obj runtime.Object, opts
|
||||
}
|
||||
|
||||
// PatchStatus used by StatusWriter to write status.
|
||||
func (c *typedClient) PatchStatus(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
func (c *typedClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
o, err := c.cache.getObjMeta(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
|
36
vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
generated
vendored
36
vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
generated
vendored
@ -25,6 +25,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var _ Reader = &unstructuredClient{}
|
||||
var _ Writer = &unstructuredClient{}
|
||||
var _ StatusWriter = &unstructuredClient{}
|
||||
|
||||
// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes
|
||||
// new clients at the time they are used, and caches the client.
|
||||
type unstructuredClient struct {
|
||||
@ -32,8 +36,8 @@ type unstructuredClient struct {
|
||||
paramCodec runtime.ParameterCodec
|
||||
}
|
||||
|
||||
// Create implements client.Client
|
||||
func (uc *unstructuredClient) Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error {
|
||||
// Create implements client.Client.
|
||||
func (uc *unstructuredClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||
u, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||
@ -60,8 +64,8 @@ func (uc *unstructuredClient) Create(ctx context.Context, obj runtime.Object, op
|
||||
return result
|
||||
}
|
||||
|
||||
// Update implements client.Client
|
||||
func (uc *unstructuredClient) Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
|
||||
// Update implements client.Client.
|
||||
func (uc *unstructuredClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
u, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||
@ -89,8 +93,8 @@ func (uc *unstructuredClient) Update(ctx context.Context, obj runtime.Object, op
|
||||
return result
|
||||
}
|
||||
|
||||
// Delete implements client.Client
|
||||
func (uc *unstructuredClient) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOption) error {
|
||||
// Delete implements client.Client.
|
||||
func (uc *unstructuredClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||
@ -112,8 +116,8 @@ func (uc *unstructuredClient) Delete(ctx context.Context, obj runtime.Object, op
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteAllOf implements client.Client
|
||||
func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...DeleteAllOfOption) error {
|
||||
// DeleteAllOf implements client.Client.
|
||||
func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||
@ -135,8 +139,8 @@ func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj runtime.Objec
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch implements client.Client
|
||||
func (uc *unstructuredClient) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
// Patch implements client.Client.
|
||||
func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||
@ -163,8 +167,8 @@ func (uc *unstructuredClient) Patch(ctx context.Context, obj runtime.Object, pat
|
||||
Into(obj)
|
||||
}
|
||||
|
||||
// Get implements client.Client
|
||||
func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
|
||||
// Get implements client.Client.
|
||||
func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
|
||||
u, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||
@ -189,8 +193,8 @@ func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj runtim
|
||||
return result
|
||||
}
|
||||
|
||||
// List implements client.Client
|
||||
func (uc *unstructuredClient) List(ctx context.Context, obj runtime.Object, opts ...ListOption) error {
|
||||
// List implements client.Client.
|
||||
func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
||||
u, ok := obj.(*unstructured.UnstructuredList)
|
||||
if !ok {
|
||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||
@ -217,7 +221,7 @@ func (uc *unstructuredClient) List(ctx context.Context, obj runtime.Object, opts
|
||||
Into(obj)
|
||||
}
|
||||
|
||||
func (uc *unstructuredClient) UpdateStatus(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error {
|
||||
func (uc *unstructuredClient) UpdateStatus(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
_, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||
@ -239,7 +243,7 @@ func (uc *unstructuredClient) UpdateStatus(ctx context.Context, obj runtime.Obje
|
||||
Into(obj)
|
||||
}
|
||||
|
||||
func (uc *unstructuredClient) PatchStatus(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
func (uc *unstructuredClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
u, ok := obj.(*unstructured.Unstructured)
|
||||
if !ok {
|
||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||
|
118
vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go
generated
vendored
Normal file
118
vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright 2020 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 client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// NewWithWatch returns a new WithWatch.
|
||||
func NewWithWatch(config *rest.Config, options Options) (WithWatch, error) {
|
||||
client, err := newClient(config, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &watchingClient{client: client, dynamic: dynamicClient}, nil
|
||||
}
|
||||
|
||||
type watchingClient struct {
|
||||
*client
|
||||
dynamic dynamic.Interface
|
||||
}
|
||||
|
||||
func (w *watchingClient) Watch(ctx context.Context, list ObjectList, opts ...ListOption) (watch.Interface, error) {
|
||||
switch l := list.(type) {
|
||||
case *unstructured.UnstructuredList:
|
||||
return w.unstructuredWatch(ctx, l, opts...)
|
||||
case *metav1.PartialObjectMetadataList:
|
||||
return w.metadataWatch(ctx, l, opts...)
|
||||
default:
|
||||
return w.typedWatch(ctx, l, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watchingClient) listOpts(opts ...ListOption) ListOptions {
|
||||
listOpts := ListOptions{}
|
||||
listOpts.ApplyOptions(opts)
|
||||
if listOpts.Raw == nil {
|
||||
listOpts.Raw = &metav1.ListOptions{}
|
||||
}
|
||||
listOpts.Raw.Watch = true
|
||||
|
||||
return listOpts
|
||||
}
|
||||
|
||||
func (w *watchingClient) metadataWatch(ctx context.Context, obj *metav1.PartialObjectMetadataList, opts ...ListOption) (watch.Interface, error) {
|
||||
gvk := obj.GroupVersionKind()
|
||||
if strings.HasSuffix(gvk.Kind, "List") {
|
||||
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
||||
}
|
||||
|
||||
listOpts := w.listOpts(opts...)
|
||||
|
||||
resInt, err := w.client.metadataClient.getResourceInterface(gvk, listOpts.Namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resInt.Watch(ctx, *listOpts.AsListOptions())
|
||||
}
|
||||
|
||||
func (w *watchingClient) unstructuredWatch(ctx context.Context, obj *unstructured.UnstructuredList, opts ...ListOption) (watch.Interface, error) {
|
||||
gvk := obj.GroupVersionKind()
|
||||
if strings.HasSuffix(gvk.Kind, "List") {
|
||||
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
||||
}
|
||||
|
||||
r, err := w.client.unstructuredClient.cache.getResource(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
listOpts := w.listOpts(opts...)
|
||||
|
||||
if listOpts.Namespace != "" && r.isNamespaced() {
|
||||
return w.dynamic.Resource(r.mapping.Resource).Namespace(listOpts.Namespace).Watch(ctx, *listOpts.AsListOptions())
|
||||
}
|
||||
return w.dynamic.Resource(r.mapping.Resource).Watch(ctx, *listOpts.AsListOptions())
|
||||
}
|
||||
|
||||
func (w *watchingClient) typedWatch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error) {
|
||||
r, err := w.client.typedClient.cache.getResource(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
listOpts := w.listOpts(opts...)
|
||||
|
||||
return r.Get().
|
||||
NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
|
||||
Resource(r.resource()).
|
||||
VersionedParams(listOpts.AsListOptions(), w.client.typedClient.paramCodec).
|
||||
Watch(ctx)
|
||||
}
|
Reference in New Issue
Block a user