70
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
generated
vendored
70
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
generated
vendored
@@ -21,6 +21,7 @@ package apiutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -28,10 +29,33 @@ import (
|
||||
"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) {
|
||||
@@ -56,7 +80,7 @@ func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersi
|
||||
// (unstructured, partial, etc)
|
||||
|
||||
// check for PartialObjectMetadata, which is analogous to unstructured, but isn't handled by ObjectKinds
|
||||
_, isPartial := obj.(*metav1.PartialObjectMetadata)
|
||||
_, 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
|
||||
@@ -93,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)
|
||||
@@ -115,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()}
|
||||
}
|
||||
|
||||
143
vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
generated
vendored
143
vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
generated
vendored
@@ -19,6 +19,7 @@ package client
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -29,16 +30,36 @@ import (
|
||||
"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.
|
||||
@@ -52,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
|
||||
@@ -71,11 +113,13 @@ 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)
|
||||
@@ -96,6 +140,8 @@ func New(config *rest.Config, options Options) (Client, error) {
|
||||
client: rawMetaClient,
|
||||
restMapper: options.Mapper,
|
||||
},
|
||||
scheme: options.Scheme,
|
||||
mapper: options.Mapper,
|
||||
}
|
||||
|
||||
return c, nil
|
||||
@@ -109,10 +155,11 @@ 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 {
|
||||
@@ -121,8 +168,18 @@ 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 {
|
||||
// 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...)
|
||||
@@ -133,8 +190,8 @@ func (c *client) Create(ctx context.Context, obj runtime.Object, opts ...CreateO
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
@@ -146,8 +203,8 @@ func (c *client) Update(ctx context.Context, obj runtime.Object, opts ...UpdateO
|
||||
}
|
||||
}
|
||||
|
||||
// Delete implements client.Client
|
||||
func (c *client) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOption) error {
|
||||
// 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...)
|
||||
@@ -158,8 +215,8 @@ func (c *client) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteO
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteAllOf implements client.Client
|
||||
func (c *client) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...DeleteAllOfOption) error {
|
||||
// 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...)
|
||||
@@ -170,8 +227,8 @@ func (c *client) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...De
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
@@ -183,45 +240,69 @@ func (c *client) Patch(ctx context.Context, obj runtime.Object, patch Patch, opt
|
||||
}
|
||||
}
|
||||
|
||||
// Get implements client.Client
|
||||
func (c *client) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// List implements client.Client
|
||||
func (c *client) List(ctx context.Context, obj runtime.Object, opts ...ListOption) error {
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
// 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:
|
||||
return c.metadataClient.List(ctx, obj, opts...)
|
||||
// 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...)
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
@@ -233,8 +314,8 @@ func (sw *statusWriter) Update(ctx context.Context, obj runtime.Object, 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())
|
||||
switch obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
|
||||
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)...)
|
||||
}
|
||||
|
||||
334
vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go
generated
vendored
334
vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go
generated
vendored
@@ -23,14 +23,17 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"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"
|
||||
utilrand "k8s.io/apimachinery/pkg/util/rand"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/testing"
|
||||
|
||||
@@ -41,14 +44,16 @@ import (
|
||||
|
||||
type versionedTracker struct {
|
||||
testing.ObjectTracker
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
type fakeClient struct {
|
||||
tracker versionedTracker
|
||||
scheme *runtime.Scheme
|
||||
tracker versionedTracker
|
||||
scheme *runtime.Scheme
|
||||
schemeWriteLock sync.Mutex
|
||||
}
|
||||
|
||||
var _ client.Client = &fakeClient{}
|
||||
var _ client.WithWatch = &fakeClient{}
|
||||
|
||||
const (
|
||||
maxNameLength = 63
|
||||
@@ -58,33 +63,124 @@ const (
|
||||
|
||||
// NewFakeClient creates a new fake client for testing.
|
||||
// You can choose to initialize it with a slice of runtime.Object.
|
||||
// Deprecated: use NewFakeClientWithScheme. You should always be
|
||||
// passing an explicit Scheme.
|
||||
func NewFakeClient(initObjs ...runtime.Object) client.Client {
|
||||
return NewFakeClientWithScheme(scheme.Scheme, initObjs...)
|
||||
//
|
||||
// Deprecated: Please use NewClientBuilder instead.
|
||||
func NewFakeClient(initObjs ...runtime.Object) client.WithWatch {
|
||||
return NewClientBuilder().WithRuntimeObjects(initObjs...).Build()
|
||||
}
|
||||
|
||||
// NewFakeClientWithScheme creates a new fake client with the given scheme
|
||||
// for testing.
|
||||
// You can choose to initialize it with a slice of runtime.Object.
|
||||
func NewFakeClientWithScheme(clientScheme *runtime.Scheme, initObjs ...runtime.Object) client.Client {
|
||||
tracker := testing.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder())
|
||||
for _, obj := range initObjs {
|
||||
err := tracker.Add(obj)
|
||||
if err != nil {
|
||||
//
|
||||
// Deprecated: Please use NewClientBuilder instead.
|
||||
func NewFakeClientWithScheme(clientScheme *runtime.Scheme, initObjs ...runtime.Object) client.WithWatch {
|
||||
return NewClientBuilder().WithScheme(clientScheme).WithRuntimeObjects(initObjs...).Build()
|
||||
}
|
||||
|
||||
// NewClientBuilder returns a new builder to create a fake client.
|
||||
func NewClientBuilder() *ClientBuilder {
|
||||
return &ClientBuilder{}
|
||||
}
|
||||
|
||||
// ClientBuilder builds a fake client.
|
||||
type ClientBuilder struct {
|
||||
scheme *runtime.Scheme
|
||||
initObject []client.Object
|
||||
initLists []client.ObjectList
|
||||
initRuntimeObjects []runtime.Object
|
||||
}
|
||||
|
||||
// WithScheme sets this builder's internal scheme.
|
||||
// If not set, defaults to client-go's global scheme.Scheme.
|
||||
func (f *ClientBuilder) WithScheme(scheme *runtime.Scheme) *ClientBuilder {
|
||||
f.scheme = scheme
|
||||
return f
|
||||
}
|
||||
|
||||
// WithObjects can be optionally used to initialize this fake client with client.Object(s).
|
||||
func (f *ClientBuilder) WithObjects(initObjs ...client.Object) *ClientBuilder {
|
||||
f.initObject = append(f.initObject, initObjs...)
|
||||
return f
|
||||
}
|
||||
|
||||
// WithLists can be optionally used to initialize this fake client with client.ObjectList(s).
|
||||
func (f *ClientBuilder) WithLists(initLists ...client.ObjectList) *ClientBuilder {
|
||||
f.initLists = append(f.initLists, initLists...)
|
||||
return f
|
||||
}
|
||||
|
||||
// WithRuntimeObjects can be optionally used to initialize this fake client with runtime.Object(s).
|
||||
func (f *ClientBuilder) WithRuntimeObjects(initRuntimeObjs ...runtime.Object) *ClientBuilder {
|
||||
f.initRuntimeObjects = append(f.initRuntimeObjects, initRuntimeObjs...)
|
||||
return f
|
||||
}
|
||||
|
||||
// Build builds and returns a new fake client.
|
||||
func (f *ClientBuilder) Build() client.WithWatch {
|
||||
if f.scheme == nil {
|
||||
f.scheme = scheme.Scheme
|
||||
}
|
||||
|
||||
tracker := versionedTracker{ObjectTracker: testing.NewObjectTracker(f.scheme, scheme.Codecs.UniversalDecoder()), scheme: f.scheme}
|
||||
for _, obj := range f.initObject {
|
||||
if err := tracker.Add(obj); err != nil {
|
||||
panic(fmt.Errorf("failed to add object %v to fake client: %w", obj, err))
|
||||
}
|
||||
}
|
||||
return &fakeClient{
|
||||
tracker: versionedTracker{tracker},
|
||||
scheme: clientScheme,
|
||||
for _, obj := range f.initLists {
|
||||
if err := tracker.Add(obj); err != nil {
|
||||
panic(fmt.Errorf("failed to add list %v to fake client: %w", obj, err))
|
||||
}
|
||||
}
|
||||
for _, obj := range f.initRuntimeObjects {
|
||||
if err := tracker.Add(obj); err != nil {
|
||||
panic(fmt.Errorf("failed to add runtime object %v to fake client: %w", obj, err))
|
||||
}
|
||||
}
|
||||
return &fakeClient{
|
||||
tracker: tracker,
|
||||
scheme: f.scheme,
|
||||
}
|
||||
}
|
||||
|
||||
const trackerAddResourceVersion = "999"
|
||||
|
||||
func (t versionedTracker) Add(obj runtime.Object) error {
|
||||
var objects []runtime.Object
|
||||
if meta.IsListType(obj) {
|
||||
var err error
|
||||
objects, err = meta.ExtractList(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
objects = []runtime.Object{obj}
|
||||
}
|
||||
for _, obj := range objects {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get accessor for object: %w", err)
|
||||
}
|
||||
if accessor.GetResourceVersion() == "" {
|
||||
// We use a "magic" value of 999 here because this field
|
||||
// is parsed as uint and and 0 is already used in Update.
|
||||
// As we can't go lower, go very high instead so this can
|
||||
// be recognized
|
||||
accessor.SetResourceVersion(trackerAddResourceVersion)
|
||||
}
|
||||
if err := t.ObjectTracker.Add(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t versionedTracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to get accessor for object: %v", err)
|
||||
}
|
||||
if accessor.GetName() == "" {
|
||||
return apierrors.NewInvalid(
|
||||
@@ -108,20 +204,42 @@ func (t versionedTracker) Update(gvr schema.GroupVersionResource, obj runtime.Ob
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get accessor for object: %v", err)
|
||||
}
|
||||
|
||||
if accessor.GetName() == "" {
|
||||
return apierrors.NewInvalid(
|
||||
obj.GetObjectKind().GroupVersionKind().GroupKind(),
|
||||
accessor.GetName(),
|
||||
field.ErrorList{field.Required(field.NewPath("metadata.name"), "name is required")})
|
||||
}
|
||||
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
if gvk.Empty() {
|
||||
gvk, err = apiutil.GVKForObject(obj, t.scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
oldObject, err := t.ObjectTracker.Get(gvr, ns, accessor.GetName())
|
||||
if err != nil {
|
||||
// If the resource is not found and the resource allows create on update, issue a
|
||||
// create instead.
|
||||
if apierrors.IsNotFound(err) && allowsCreateOnUpdate(gvk) {
|
||||
return t.Create(gvr, obj, ns)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
oldAccessor, err := meta.Accessor(oldObject)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the new object does not have the resource version set and it allows unconditional update,
|
||||
// default it to the resource version of the existing resource
|
||||
if accessor.GetResourceVersion() == "" && allowsUnconditionalUpdate(gvk) {
|
||||
accessor.SetResourceVersion(oldAccessor.GetResourceVersion())
|
||||
}
|
||||
if accessor.GetResourceVersion() != oldAccessor.GetResourceVersion() {
|
||||
return apierrors.NewConflict(gvr.GroupResource(), accessor.GetName(), errors.New("object was modified"))
|
||||
}
|
||||
@@ -134,10 +252,13 @@ func (t versionedTracker) Update(gvr schema.GroupVersionResource, obj runtime.Ob
|
||||
}
|
||||
intResourceVersion++
|
||||
accessor.SetResourceVersion(strconv.FormatUint(intResourceVersion, 10))
|
||||
if !accessor.GetDeletionTimestamp().IsZero() && len(accessor.GetFinalizers()) == 0 {
|
||||
return t.ObjectTracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName())
|
||||
}
|
||||
return t.ObjectTracker.Update(gvr, obj, ns)
|
||||
}
|
||||
|
||||
func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj runtime.Object) error {
|
||||
func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
gvr, err := getGVRFromObject(obj, c.scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -167,19 +288,42 @@ func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj runtime.
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *fakeClient) List(ctx context.Context, obj runtime.Object, opts ...client.ListOption) error {
|
||||
func (c *fakeClient) Watch(ctx context.Context, list client.ObjectList, opts ...client.ListOption) (watch.Interface, error) {
|
||||
gvk, err := apiutil.GVKForObject(list, c.scheme)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if strings.HasSuffix(gvk.Kind, "List") {
|
||||
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
||||
}
|
||||
|
||||
listOpts := client.ListOptions{}
|
||||
listOpts.ApplyOptions(opts)
|
||||
|
||||
gvr, _ := meta.UnsafeGuessKindToResource(gvk)
|
||||
return c.tracker.Watch(gvr, listOpts.Namespace)
|
||||
}
|
||||
|
||||
func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error {
|
||||
gvk, err := apiutil.GVKForObject(obj, c.scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
OriginalKind := gvk.Kind
|
||||
originalKind := gvk.Kind
|
||||
|
||||
if !strings.HasSuffix(gvk.Kind, "List") {
|
||||
return fmt.Errorf("non-list type %T (kind %q) passed as output", obj, gvk)
|
||||
if strings.HasSuffix(gvk.Kind, "List") {
|
||||
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
||||
}
|
||||
|
||||
if _, isUnstructuredList := obj.(*unstructured.UnstructuredList); isUnstructuredList && !c.scheme.Recognizes(gvk) {
|
||||
// We need tor register the ListKind with UnstructuredList:
|
||||
// https://github.com/kubernetes/kubernetes/blob/7b2776b89fb1be28d4e9203bdeec079be903c103/staging/src/k8s.io/client-go/dynamic/fake/simple.go#L44-L51
|
||||
c.schemeWriteLock.Lock()
|
||||
c.scheme.AddKnownTypeWithName(gvk.GroupVersion().WithKind(gvk.Kind+"List"), &unstructured.UnstructuredList{})
|
||||
c.schemeWriteLock.Unlock()
|
||||
}
|
||||
// we need the non-list GVK, so chop off the "List" from the end of the kind
|
||||
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
||||
|
||||
listOpts := client.ListOptions{}
|
||||
listOpts.ApplyOptions(opts)
|
||||
@@ -194,7 +338,7 @@ func (c *fakeClient) List(ctx context.Context, obj runtime.Object, opts ...clien
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ta.SetKind(OriginalKind)
|
||||
ta.SetKind(originalKind)
|
||||
ta.SetAPIVersion(gvk.GroupVersion().String())
|
||||
|
||||
j, err := json.Marshal(o)
|
||||
@@ -224,7 +368,16 @@ func (c *fakeClient) List(ctx context.Context, obj runtime.Object, opts ...clien
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) Create(ctx context.Context, obj runtime.Object, opts ...client.CreateOption) error {
|
||||
func (c *fakeClient) Scheme() *runtime.Scheme {
|
||||
return c.scheme
|
||||
}
|
||||
|
||||
func (c *fakeClient) RESTMapper() meta.RESTMapper {
|
||||
// TODO: Implement a fake RESTMapper.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
|
||||
createOptions := &client.CreateOptions{}
|
||||
createOptions.ApplyOptions(opts)
|
||||
|
||||
@@ -254,7 +407,7 @@ func (c *fakeClient) Create(ctx context.Context, obj runtime.Object, opts ...cli
|
||||
return c.tracker.Create(gvr, obj, accessor.GetNamespace())
|
||||
}
|
||||
|
||||
func (c *fakeClient) Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOption) error {
|
||||
func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
|
||||
gvr, err := getGVRFromObject(obj, c.scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -266,11 +419,10 @@ func (c *fakeClient) Delete(ctx context.Context, obj runtime.Object, opts ...cli
|
||||
delOptions := client.DeleteOptions{}
|
||||
delOptions.ApplyOptions(opts)
|
||||
|
||||
//TODO: implement propagation
|
||||
return c.tracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName())
|
||||
return c.deleteObject(gvr, accessor)
|
||||
}
|
||||
|
||||
func (c *fakeClient) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...client.DeleteAllOfOption) error {
|
||||
func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
|
||||
gvk, err := apiutil.GVKForObject(obj, c.scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -298,7 +450,7 @@ func (c *fakeClient) DeleteAllOf(ctx context.Context, obj runtime.Object, opts .
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.tracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName())
|
||||
err = c.deleteObject(gvr, accessor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -306,7 +458,7 @@ func (c *fakeClient) DeleteAllOf(ctx context.Context, obj runtime.Object, opts .
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) Update(ctx context.Context, obj runtime.Object, opts ...client.UpdateOption) error {
|
||||
func (c *fakeClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
|
||||
updateOptions := &client.UpdateOptions{}
|
||||
updateOptions.ApplyOptions(opts)
|
||||
|
||||
@@ -327,7 +479,7 @@ func (c *fakeClient) Update(ctx context.Context, obj runtime.Object, opts ...cli
|
||||
return c.tracker.Update(gvr, obj, accessor.GetNamespace())
|
||||
}
|
||||
|
||||
func (c *fakeClient) Patch(ctx context.Context, obj runtime.Object, patch client.Patch, opts ...client.PatchOption) error {
|
||||
func (c *fakeClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
|
||||
patchOptions := &client.PatchOptions{}
|
||||
patchOptions.ApplyOptions(opts)
|
||||
|
||||
@@ -383,6 +535,23 @@ func (c *fakeClient) Status() client.StatusWriter {
|
||||
return &fakeStatusWriter{client: c}
|
||||
}
|
||||
|
||||
func (c *fakeClient) deleteObject(gvr schema.GroupVersionResource, accessor metav1.Object) error {
|
||||
old, err := c.tracker.Get(gvr, accessor.GetNamespace(), accessor.GetName())
|
||||
if err == nil {
|
||||
oldAccessor, err := meta.Accessor(old)
|
||||
if err == nil {
|
||||
if len(oldAccessor.GetFinalizers()) > 0 {
|
||||
now := metav1.Now()
|
||||
oldAccessor.SetDeletionTimestamp(&now)
|
||||
return c.tracker.Update(gvr, old, accessor.GetNamespace())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: implement propagation
|
||||
return c.tracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName())
|
||||
}
|
||||
|
||||
func getGVRFromObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionResource, error) {
|
||||
gvk, err := apiutil.GVKForObject(obj, scheme)
|
||||
if err != nil {
|
||||
@@ -396,14 +565,111 @@ type fakeStatusWriter struct {
|
||||
client *fakeClient
|
||||
}
|
||||
|
||||
func (sw *fakeStatusWriter) Update(ctx context.Context, obj runtime.Object, opts ...client.UpdateOption) error {
|
||||
func (sw *fakeStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
|
||||
// TODO(droot): This results in full update of the obj (spec + status). Need
|
||||
// a way to update status field only.
|
||||
return sw.client.Update(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
func (sw *fakeStatusWriter) Patch(ctx context.Context, obj runtime.Object, patch client.Patch, opts ...client.PatchOption) error {
|
||||
func (sw *fakeStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
|
||||
// TODO(droot): This results in full update of the obj (spec + status). Need
|
||||
// a way to update status field only.
|
||||
return sw.client.Patch(ctx, obj, patch, opts...)
|
||||
}
|
||||
|
||||
func allowsUnconditionalUpdate(gvk schema.GroupVersionKind) bool {
|
||||
switch gvk.Group {
|
||||
case "apps":
|
||||
switch gvk.Kind {
|
||||
case "ControllerRevision", "DaemonSet", "Deployment", "ReplicaSet", "StatefulSet":
|
||||
return true
|
||||
}
|
||||
case "autoscaling":
|
||||
switch gvk.Kind {
|
||||
case "HorizontalPodAutoscaler":
|
||||
return true
|
||||
}
|
||||
case "batch":
|
||||
switch gvk.Kind {
|
||||
case "CronJob", "Job":
|
||||
return true
|
||||
}
|
||||
case "certificates":
|
||||
switch gvk.Kind {
|
||||
case "Certificates":
|
||||
return true
|
||||
}
|
||||
case "flowcontrol":
|
||||
switch gvk.Kind {
|
||||
case "FlowSchema", "PriorityLevelConfiguration":
|
||||
return true
|
||||
}
|
||||
case "networking":
|
||||
switch gvk.Kind {
|
||||
case "Ingress", "IngressClass", "NetworkPolicy":
|
||||
return true
|
||||
}
|
||||
case "policy":
|
||||
switch gvk.Kind {
|
||||
case "PodSecurityPolicy":
|
||||
return true
|
||||
}
|
||||
case "rbac":
|
||||
switch gvk.Kind {
|
||||
case "ClusterRole", "ClusterRoleBinding", "Role", "RoleBinding":
|
||||
return true
|
||||
}
|
||||
case "scheduling":
|
||||
switch gvk.Kind {
|
||||
case "PriorityClass":
|
||||
return true
|
||||
}
|
||||
case "settings":
|
||||
switch gvk.Kind {
|
||||
case "PodPreset":
|
||||
return true
|
||||
}
|
||||
case "storage":
|
||||
switch gvk.Kind {
|
||||
case "StorageClass":
|
||||
return true
|
||||
}
|
||||
case "":
|
||||
switch gvk.Kind {
|
||||
case "ConfigMap", "Endpoint", "Event", "LimitRange", "Namespace", "Node",
|
||||
"PersistentVolume", "PersistentVolumeClaim", "Pod", "PodTemplate",
|
||||
"ReplicationController", "ResourceQuota", "Secret", "Service",
|
||||
"ServiceAccount", "EndpointSlice":
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func allowsCreateOnUpdate(gvk schema.GroupVersionKind) bool {
|
||||
switch gvk.Group {
|
||||
case "coordination":
|
||||
switch gvk.Kind {
|
||||
case "Lease":
|
||||
return true
|
||||
}
|
||||
case "node":
|
||||
switch gvk.Kind {
|
||||
case "RuntimeClass":
|
||||
return true
|
||||
}
|
||||
case "rbac":
|
||||
switch gvk.Kind {
|
||||
case "ClusterRole", "ClusterRoleBinding", "Role", "RoleBinding":
|
||||
return true
|
||||
}
|
||||
case "":
|
||||
switch gvk.Kind {
|
||||
case "Endpoint", "Event", "LimitRange", "Service":
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
18
vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go
generated
vendored
18
vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go
generated
vendored
@@ -17,17 +17,23 @@ limitations under the License.
|
||||
/*
|
||||
Package fake provides a fake client for testing.
|
||||
|
||||
Deprecated: please use pkg/envtest for testing. This package will be dropped
|
||||
before the v1.0.0 release.
|
||||
|
||||
An fake client is backed by its simple object store indexed by GroupVersionResource.
|
||||
A fake client is backed by its simple object store indexed by GroupVersionResource.
|
||||
You can create a fake client with optional objects.
|
||||
|
||||
client := NewFakeClient(initObjs...) // initObjs is a slice of runtime.Object
|
||||
client := NewFakeClientWithScheme(scheme, initObjs...) // initObjs is a slice of runtime.Object
|
||||
|
||||
You can invoke the methods defined in the Client interface.
|
||||
|
||||
When it doubt, it's almost always better not to use this package and instead use
|
||||
When in doubt, it's almost always better not to use this package and instead use
|
||||
envtest.Environment with a real client and API server.
|
||||
|
||||
WARNING: ⚠️ Current Limitations / Known Issues with the fake Client ⚠️
|
||||
- This client does not have a way to inject specific errors to test handled vs. unhandled errors.
|
||||
- There is some support for sub resources which can cause issues with tests if you're trying to update
|
||||
e.g. metadata and status in the same reconcile.
|
||||
- No OpeanAPI validation is performed when creating or updating objects.
|
||||
- ObjectMeta's `Generation` and `ResourceVersion` don't behave properly, Patch or Update
|
||||
operations that rely on these fields will fail, or give false positives.
|
||||
|
||||
*/
|
||||
package fake
|
||||
|
||||
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.
|
||||
|
||||
45
vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
generated
vendored
45
vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
generated
vendored
@@ -1,17 +1,17 @@
|
||||
/*
|
||||
Copyright 2020 The Kubernetes Authors.
|
||||
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
|
||||
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
|
||||
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.
|
||||
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
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
|
||||
"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/client-go/metadata"
|
||||
)
|
||||
@@ -50,8 +49,8 @@ func (mc *metadataClient) getResourceInterface(gvk schema.GroupVersionKind, ns s
|
||||
return mc.client.Resource(mapping.Resource).Namespace(ns), nil
|
||||
}
|
||||
|
||||
// Delete implements client.Client
|
||||
func (mc *metadataClient) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOption) error {
|
||||
// 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)
|
||||
@@ -68,8 +67,8 @@ func (mc *metadataClient) Delete(ctx context.Context, obj runtime.Object, opts .
|
||||
return resInt.Delete(ctx, metadata.Name, *deleteOpts.AsDeleteOptions())
|
||||
}
|
||||
|
||||
// DeleteAllOf implements client.Client
|
||||
func (mc *metadataClient) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...DeleteAllOfOption) error {
|
||||
// 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)
|
||||
@@ -86,8 +85,8 @@ func (mc *metadataClient) DeleteAllOf(ctx context.Context, obj runtime.Object, o
|
||||
return resInt.DeleteCollection(ctx, *deleteAllOfOpts.AsDeleteOptions(), *deleteAllOfOpts.AsListOptions())
|
||||
}
|
||||
|
||||
// Patch implements client.Client
|
||||
func (mc *metadataClient) Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
// 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)
|
||||
@@ -105,6 +104,8 @@ func (mc *metadataClient) Patch(ctx context.Context, obj runtime.Object, patch P
|
||||
}
|
||||
|
||||
patchOpts := &PatchOptions{}
|
||||
patchOpts.ApplyOptions(opts)
|
||||
|
||||
res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -114,8 +115,8 @@ func (mc *metadataClient) Patch(ctx context.Context, obj runtime.Object, patch P
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get implements client.Client
|
||||
func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
|
||||
// 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)
|
||||
@@ -137,8 +138,8 @@ func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj runtime.Ob
|
||||
return nil
|
||||
}
|
||||
|
||||
// List implements client.Client
|
||||
func (mc *metadataClient) List(ctx context.Context, obj runtime.Object, opts ...ListOption) error {
|
||||
// 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)
|
||||
@@ -166,7 +167,7 @@ func (mc *metadataClient) List(ctx context.Context, obj runtime.Object, opts ...
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mc *metadataClient) PatchStatus(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error {
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
130
vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go
generated
vendored
130
vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go
generated
vendored
@@ -20,20 +20,18 @@ import (
|
||||
"fmt"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
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/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 {
|
||||
@@ -47,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
|
||||
}
|
||||
|
||||
@@ -56,13 +54,6 @@ func RawPatch(patchType types.PatchType, data []byte) Patch {
|
||||
return &patch{patchType, data}
|
||||
}
|
||||
|
||||
// ConstantPatch constructs a new Patch with the given PatchType and data.
|
||||
//
|
||||
// Deprecated: use RawPatch instead
|
||||
func ConstantPatch(patchType types.PatchType, data []byte) Patch {
|
||||
return RawPatch(patchType, data)
|
||||
}
|
||||
|
||||
// MergeFromWithOptimisticLock can be used if clients want to make sure a patch
|
||||
// is being applied to the latest resource version of an object.
|
||||
//
|
||||
@@ -94,68 +85,97 @@ type MergeFromOptions struct {
|
||||
}
|
||||
|
||||
type mergeFromPatch struct {
|
||||
from runtime.Object
|
||||
opts MergeFromOptions
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modifiedJSON, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := jsonpatch.CreateMergePatch(originalJSON, modifiedJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (s *mergeFromPatch) Data(obj Object) ([]byte, error) {
|
||||
original := s.from
|
||||
modified := obj
|
||||
|
||||
if s.opts.OptimisticLock {
|
||||
dataMap := map[string]interface{}{}
|
||||
if err := json.Unmarshal(data, &dataMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fromMeta, ok := s.from.(metav1.Object)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot use OptimisticLock, from object %q is not a valid metav1.Object", s.from)
|
||||
}
|
||||
resourceVersion := fromMeta.GetResourceVersion()
|
||||
if len(resourceVersion) == 0 {
|
||||
return nil, fmt.Errorf("cannot use OptimisticLock, from object %q does not have any resource version we can use", s.from)
|
||||
}
|
||||
u := &unstructured.Unstructured{Object: dataMap}
|
||||
u.SetResourceVersion(resourceVersion)
|
||||
data, err = json.Marshal(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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(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{from: 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.
|
||||
func MergeFromWithOptions(obj runtime.Object, opts ...MergeFromOption) Patch {
|
||||
// See MergeFrom for more details.
|
||||
func MergeFromWithOptions(obj Object, opts ...MergeFromOption) Patch {
|
||||
options := &MergeFromOptions{}
|
||||
for _, opt := range opts {
|
||||
opt.ApplyToMergeFrom(options)
|
||||
}
|
||||
return &mergeFromPatch{from: obj, opts: *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.
|
||||
@@ -167,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
|
||||
@@ -184,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