mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
rebase: bump k8s.io/kubernetes from 1.26.2 to 1.27.2
Bumps [k8s.io/kubernetes](https://github.com/kubernetes/kubernetes) from 1.26.2 to 1.27.2. - [Release notes](https://github.com/kubernetes/kubernetes/releases) - [Commits](https://github.com/kubernetes/kubernetes/compare/v1.26.2...v1.27.2) --- updated-dependencies: - dependency-name: k8s.io/kubernetes dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
mergify[bot]
parent
0e79135419
commit
07b05616a0
19
vendor/k8s.io/apiserver/pkg/registry/generic/OWNERS
generated
vendored
Normal file
19
vendor/k8s.io/apiserver/pkg/registry/generic/OWNERS
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
reviewers:
|
||||
- thockin
|
||||
- lavalamp
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- yujuhong
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- mikedanese
|
||||
- liggitt
|
||||
- saad-ali
|
||||
- janetkuo
|
||||
- pwittrock
|
||||
- ncdc
|
||||
- dims
|
||||
- enj
|
19
vendor/k8s.io/apiserver/pkg/registry/generic/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/apiserver/pkg/registry/generic/doc.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2014 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 generic provides a generic object store interface and a
|
||||
// generic label/field matching type.
|
||||
package generic // import "k8s.io/apiserver/pkg/registry/generic"
|
52
vendor/k8s.io/apiserver/pkg/registry/generic/matcher.go
generated
vendored
Normal file
52
vendor/k8s.io/apiserver/pkg/registry/generic/matcher.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2014 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 generic
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
)
|
||||
|
||||
// ObjectMetaFieldsSet returns a fields that represent the ObjectMeta.
|
||||
func ObjectMetaFieldsSet(objectMeta *metav1.ObjectMeta, hasNamespaceField bool) fields.Set {
|
||||
if !hasNamespaceField {
|
||||
return fields.Set{
|
||||
"metadata.name": objectMeta.Name,
|
||||
}
|
||||
}
|
||||
return fields.Set{
|
||||
"metadata.name": objectMeta.Name,
|
||||
"metadata.namespace": objectMeta.Namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// AdObjectMetaField add fields that represent the ObjectMeta to source.
|
||||
func AddObjectMetaFieldsSet(source fields.Set, objectMeta *metav1.ObjectMeta, hasNamespaceField bool) fields.Set {
|
||||
source["metadata.name"] = objectMeta.Name
|
||||
if hasNamespaceField {
|
||||
source["metadata.namespace"] = objectMeta.Namespace
|
||||
}
|
||||
return source
|
||||
}
|
||||
|
||||
// MergeFieldsSets merges a fields'set from fragment into the source.
|
||||
func MergeFieldsSets(source fields.Set, fragment fields.Set) fields.Set {
|
||||
for k, value := range fragment {
|
||||
source[k] = value
|
||||
}
|
||||
return source
|
||||
}
|
56
vendor/k8s.io/apiserver/pkg/registry/generic/options.go
generated
vendored
Normal file
56
vendor/k8s.io/apiserver/pkg/registry/generic/options.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2016 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 generic
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
flowcontrolrequest "k8s.io/apiserver/pkg/util/flowcontrol/request"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// RESTOptions is set of resource-specific configuration options to generic registries.
|
||||
type RESTOptions struct {
|
||||
StorageConfig *storagebackend.ConfigForResource
|
||||
Decorator StorageDecorator
|
||||
|
||||
EnableGarbageCollection bool
|
||||
DeleteCollectionWorkers int
|
||||
ResourcePrefix string
|
||||
CountMetricPollPeriod time.Duration
|
||||
StorageObjectCountTracker flowcontrolrequest.StorageObjectCountTracker
|
||||
}
|
||||
|
||||
// Implement RESTOptionsGetter so that RESTOptions can directly be used when available (i.e. tests)
|
||||
func (opts RESTOptions) GetRESTOptions(schema.GroupResource) (RESTOptions, error) {
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
type RESTOptionsGetter interface {
|
||||
GetRESTOptions(resource schema.GroupResource) (RESTOptions, error)
|
||||
}
|
||||
|
||||
// StoreOptions is set of configuration options used to complete generic registries.
|
||||
type StoreOptions struct {
|
||||
RESTOptions RESTOptionsGetter
|
||||
TriggerFunc storage.IndexerFuncs
|
||||
AttrFunc storage.AttrFunc
|
||||
Indexers *cache.Indexers
|
||||
}
|
91
vendor/k8s.io/apiserver/pkg/registry/generic/registry/decorated_watcher.go
generated
vendored
Normal file
91
vendor/k8s.io/apiserver/pkg/registry/generic/registry/decorated_watcher.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2016 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 registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
)
|
||||
|
||||
type decoratedWatcher struct {
|
||||
w watch.Interface
|
||||
decorator func(runtime.Object)
|
||||
cancel context.CancelFunc
|
||||
resultCh chan watch.Event
|
||||
}
|
||||
|
||||
func newDecoratedWatcher(ctx context.Context, w watch.Interface, decorator func(runtime.Object)) *decoratedWatcher {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
d := &decoratedWatcher{
|
||||
w: w,
|
||||
decorator: decorator,
|
||||
cancel: cancel,
|
||||
resultCh: make(chan watch.Event),
|
||||
}
|
||||
go d.run(ctx)
|
||||
return d
|
||||
}
|
||||
|
||||
// run decorates watch events from the underlying watcher until its result channel
|
||||
// is closed or the passed in context is done.
|
||||
// When run() returns, decoratedWatcher#resultCh is closed.
|
||||
func (d *decoratedWatcher) run(ctx context.Context) {
|
||||
var recv, send watch.Event
|
||||
var ok bool
|
||||
defer close(d.resultCh)
|
||||
for {
|
||||
select {
|
||||
case recv, ok = <-d.w.ResultChan():
|
||||
if !ok {
|
||||
// The underlying channel was closed, cancel our context
|
||||
d.cancel()
|
||||
return
|
||||
}
|
||||
switch recv.Type {
|
||||
case watch.Added, watch.Modified, watch.Deleted, watch.Bookmark:
|
||||
d.decorator(recv.Object)
|
||||
send = recv
|
||||
case watch.Error:
|
||||
send = recv
|
||||
}
|
||||
select {
|
||||
case d.resultCh <- send:
|
||||
// propagated event successfully
|
||||
case <-ctx.Done():
|
||||
// context timed out or was cancelled, stop the underlying watcher
|
||||
d.w.Stop()
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
// context timed out or was cancelled, stop the underlying watcher
|
||||
d.w.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *decoratedWatcher) Stop() {
|
||||
// stop the underlying watcher
|
||||
d.w.Stop()
|
||||
// cancel our context
|
||||
d.cancel()
|
||||
}
|
||||
|
||||
func (d *decoratedWatcher) ResultChan() <-chan watch.Event {
|
||||
return d.resultCh
|
||||
}
|
19
vendor/k8s.io/apiserver/pkg/registry/generic/registry/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/apiserver/pkg/registry/generic/registry/doc.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2014 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 etcd has a generic implementation of a registry that
|
||||
// stores things in etcd.
|
||||
package registry // import "k8s.io/apiserver/pkg/registry/generic/registry"
|
109
vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun.go
generated
vendored
Normal file
109
vendor/k8s.io/apiserver/pkg/registry/generic/registry/dryrun.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
Copyright 2018 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 registry
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
)
|
||||
|
||||
type DryRunnableStorage struct {
|
||||
Storage storage.Interface
|
||||
Codec runtime.Codec
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Versioner() storage.Versioner {
|
||||
return s.Storage.Versioner()
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Create(ctx context.Context, key string, obj, out runtime.Object, ttl uint64, dryRun bool) error {
|
||||
if dryRun {
|
||||
if err := s.Storage.Get(ctx, key, storage.GetOptions{}, out); err == nil {
|
||||
return storage.NewKeyExistsError(key, 0)
|
||||
}
|
||||
return s.copyInto(obj, out)
|
||||
}
|
||||
return s.Storage.Create(ctx, key, obj, out, ttl)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Delete(ctx context.Context, key string, out runtime.Object, preconditions *storage.Preconditions, deleteValidation storage.ValidateObjectFunc, dryRun bool, cachedExistingObject runtime.Object) error {
|
||||
if dryRun {
|
||||
if err := s.Storage.Get(ctx, key, storage.GetOptions{}, out); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := preconditions.Check(key, out); err != nil {
|
||||
return err
|
||||
}
|
||||
return deleteValidation(ctx, out)
|
||||
}
|
||||
return s.Storage.Delete(ctx, key, out, preconditions, deleteValidation, cachedExistingObject)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Watch(ctx context.Context, key string, opts storage.ListOptions) (watch.Interface, error) {
|
||||
return s.Storage.Watch(ctx, key, opts)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Get(ctx context.Context, key string, opts storage.GetOptions, objPtr runtime.Object) error {
|
||||
return s.Storage.Get(ctx, key, opts, objPtr)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) GetList(ctx context.Context, key string, opts storage.ListOptions, listObj runtime.Object) error {
|
||||
return s.Storage.GetList(ctx, key, opts, listObj)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) GuaranteedUpdate(
|
||||
ctx context.Context, key string, destination runtime.Object, ignoreNotFound bool,
|
||||
preconditions *storage.Preconditions, tryUpdate storage.UpdateFunc, dryRun bool, cachedExistingObject runtime.Object) error {
|
||||
if dryRun {
|
||||
err := s.Storage.Get(ctx, key, storage.GetOptions{IgnoreNotFound: ignoreNotFound}, destination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = preconditions.Check(key, destination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rev, err := s.Versioner().ObjectResourceVersion(destination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updated, _, err := tryUpdate(destination, storage.ResponseMeta{ResourceVersion: rev})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.copyInto(updated, destination)
|
||||
}
|
||||
return s.Storage.GuaranteedUpdate(ctx, key, destination, ignoreNotFound, preconditions, tryUpdate, cachedExistingObject)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) Count(key string) (int64, error) {
|
||||
return s.Storage.Count(key)
|
||||
}
|
||||
|
||||
func (s *DryRunnableStorage) copyInto(in, out runtime.Object) error {
|
||||
var data []byte
|
||||
|
||||
data, err := runtime.Encode(s.Codec, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _, err = s.Codec.Decode(data, nil, out)
|
||||
return err
|
||||
}
|
95
vendor/k8s.io/apiserver/pkg/registry/generic/registry/storage_factory.go
generated
vendored
Normal file
95
vendor/k8s.io/apiserver/pkg/registry/generic/registry/storage_factory.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright 2015 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 registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
cacherstorage "k8s.io/apiserver/pkg/storage/cacher"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend/factory"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// Creates a cacher based given storageConfig.
|
||||
func StorageWithCacher() generic.StorageDecorator {
|
||||
return func(
|
||||
storageConfig *storagebackend.ConfigForResource,
|
||||
resourcePrefix string,
|
||||
keyFunc func(obj runtime.Object) (string, error),
|
||||
newFunc func() runtime.Object,
|
||||
newListFunc func() runtime.Object,
|
||||
getAttrsFunc storage.AttrFunc,
|
||||
triggerFuncs storage.IndexerFuncs,
|
||||
indexers *cache.Indexers) (storage.Interface, factory.DestroyFunc, error) {
|
||||
|
||||
s, d, err := generic.NewRawStorage(storageConfig, newFunc)
|
||||
if err != nil {
|
||||
return s, d, err
|
||||
}
|
||||
if klogV := klog.V(5); klogV.Enabled() {
|
||||
//nolint:logcheck // It complains about the key/value pairs because it cannot check them.
|
||||
klogV.InfoS("Storage caching is enabled", objectTypeToArgs(newFunc())...)
|
||||
}
|
||||
|
||||
cacherConfig := cacherstorage.Config{
|
||||
Storage: s,
|
||||
Versioner: storage.APIObjectVersioner{},
|
||||
GroupResource: storageConfig.GroupResource,
|
||||
ResourcePrefix: resourcePrefix,
|
||||
KeyFunc: keyFunc,
|
||||
NewFunc: newFunc,
|
||||
NewListFunc: newListFunc,
|
||||
GetAttrsFunc: getAttrsFunc,
|
||||
IndexerFuncs: triggerFuncs,
|
||||
Indexers: indexers,
|
||||
Codec: storageConfig.Codec,
|
||||
}
|
||||
cacher, err := cacherstorage.NewCacherFromConfig(cacherConfig)
|
||||
if err != nil {
|
||||
return nil, func() {}, err
|
||||
}
|
||||
var once sync.Once
|
||||
destroyFunc := func() {
|
||||
once.Do(func() {
|
||||
cacher.Stop()
|
||||
d()
|
||||
})
|
||||
}
|
||||
|
||||
return cacher, destroyFunc, nil
|
||||
}
|
||||
}
|
||||
|
||||
func objectTypeToArgs(obj runtime.Object) []interface{} {
|
||||
// special-case unstructured objects that tell us their apiVersion/kind
|
||||
if u, isUnstructured := obj.(*unstructured.Unstructured); isUnstructured {
|
||||
if apiVersion, kind := u.GetAPIVersion(), u.GetKind(); len(apiVersion) > 0 && len(kind) > 0 {
|
||||
return []interface{}{"apiVersion", apiVersion, "kind", kind}
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise just return the type
|
||||
return []interface{}{"type", fmt.Sprintf("%T", obj)}
|
||||
}
|
1529
vendor/k8s.io/apiserver/pkg/registry/generic/registry/store.go
generated
vendored
Normal file
1529
vendor/k8s.io/apiserver/pkg/registry/generic/registry/store.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
58
vendor/k8s.io/apiserver/pkg/registry/generic/storage_decorator.go
generated
vendored
Normal file
58
vendor/k8s.io/apiserver/pkg/registry/generic/storage_decorator.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2015 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 generic
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend/factory"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// StorageDecorator is a function signature for producing a storage.Interface
|
||||
// and an associated DestroyFunc from given parameters.
|
||||
type StorageDecorator func(
|
||||
config *storagebackend.ConfigForResource,
|
||||
resourcePrefix string,
|
||||
keyFunc func(obj runtime.Object) (string, error),
|
||||
newFunc func() runtime.Object,
|
||||
newListFunc func() runtime.Object,
|
||||
getAttrsFunc storage.AttrFunc,
|
||||
trigger storage.IndexerFuncs,
|
||||
indexers *cache.Indexers) (storage.Interface, factory.DestroyFunc, error)
|
||||
|
||||
// UndecoratedStorage returns the given a new storage from the given config
|
||||
// without any decoration.
|
||||
func UndecoratedStorage(
|
||||
config *storagebackend.ConfigForResource,
|
||||
resourcePrefix string,
|
||||
keyFunc func(obj runtime.Object) (string, error),
|
||||
newFunc func() runtime.Object,
|
||||
newListFunc func() runtime.Object,
|
||||
getAttrsFunc storage.AttrFunc,
|
||||
trigger storage.IndexerFuncs,
|
||||
indexers *cache.Indexers) (storage.Interface, factory.DestroyFunc, error) {
|
||||
return NewRawStorage(config, newFunc)
|
||||
}
|
||||
|
||||
// NewRawStorage creates the low level kv storage. This is a work-around for current
|
||||
// two layer of same storage interface.
|
||||
// TODO: Once cacher is enabled on all registries (event registry is special), we will remove this method.
|
||||
func NewRawStorage(config *storagebackend.ConfigForResource, newFunc func() runtime.Object) (storage.Interface, factory.DestroyFunc, error) {
|
||||
return factory.Create(*config, newFunc)
|
||||
}
|
16
vendor/k8s.io/apiserver/pkg/registry/rest/OWNERS
generated
vendored
Normal file
16
vendor/k8s.io/apiserver/pkg/registry/rest/OWNERS
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# See the OWNERS docs at https://go.k8s.io/owners
|
||||
|
||||
reviewers:
|
||||
- thockin
|
||||
- smarterclayton
|
||||
- wojtek-t
|
||||
- deads2k
|
||||
- derekwaynecarr
|
||||
- caesarxuchao
|
||||
- mikedanese
|
||||
- liggitt
|
||||
- justinsb
|
||||
- ncdc
|
||||
- dims
|
||||
- ingvagabund
|
||||
- enj
|
223
vendor/k8s.io/apiserver/pkg/registry/rest/create.go
generated
vendored
Normal file
223
vendor/k8s.io/apiserver/pkg/registry/rest/create.go
generated
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
Copyright 2014 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 rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||
"k8s.io/apimachinery/pkg/api/validation/path"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
"k8s.io/apiserver/pkg/warning"
|
||||
)
|
||||
|
||||
// RESTCreateStrategy defines the minimum validation, accepted input, and
|
||||
// name generation behavior to create an object that follows Kubernetes
|
||||
// API conventions.
|
||||
type RESTCreateStrategy interface {
|
||||
runtime.ObjectTyper
|
||||
// The name generator is used when the standard GenerateName field is set.
|
||||
// The NameGenerator will be invoked prior to validation.
|
||||
names.NameGenerator
|
||||
|
||||
// NamespaceScoped returns true if the object must be within a namespace.
|
||||
NamespaceScoped() bool
|
||||
// PrepareForCreate is invoked on create before validation to normalize
|
||||
// the object. For example: remove fields that are not to be persisted,
|
||||
// sort order-insensitive list fields, etc. This should not remove fields
|
||||
// whose presence would be considered a validation error.
|
||||
//
|
||||
// Often implemented as a type check and an initailization or clearing of
|
||||
// status. Clear the status because status changes are internal. External
|
||||
// callers of an api (users) should not be setting an initial status on
|
||||
// newly created objects.
|
||||
PrepareForCreate(ctx context.Context, obj runtime.Object)
|
||||
// Validate returns an ErrorList with validation errors or nil. Validate
|
||||
// is invoked after default fields in the object have been filled in
|
||||
// before the object is persisted. This method should not mutate the
|
||||
// object.
|
||||
Validate(ctx context.Context, obj runtime.Object) field.ErrorList
|
||||
// WarningsOnCreate returns warnings to the client performing a create.
|
||||
// WarningsOnCreate is invoked after default fields in the object have been filled in
|
||||
// and after Validate has passed, before Canonicalize is called, and the object is persisted.
|
||||
// This method must not mutate the object.
|
||||
//
|
||||
// Be brief; limit warnings to 120 characters if possible.
|
||||
// Don't include a "Warning:" prefix in the message (that is added by clients on output).
|
||||
// Warnings returned about a specific field should be formatted as "path.to.field: message".
|
||||
// For example: `spec.imagePullSecrets[0].name: invalid empty name ""`
|
||||
//
|
||||
// Use warning messages to describe problems the client making the API request should correct or be aware of.
|
||||
// For example:
|
||||
// - use of deprecated fields/labels/annotations that will stop working in a future release
|
||||
// - use of obsolete fields/labels/annotations that are non-functional
|
||||
// - malformed or invalid specifications that prevent successful handling of the submitted object,
|
||||
// but are not rejected by validation for compatibility reasons
|
||||
//
|
||||
// Warnings should not be returned for fields which cannot be resolved by the caller.
|
||||
// For example, do not warn about spec fields in a subresource creation request.
|
||||
WarningsOnCreate(ctx context.Context, obj runtime.Object) []string
|
||||
// Canonicalize allows an object to be mutated into a canonical form. This
|
||||
// ensures that code that operates on these objects can rely on the common
|
||||
// form for things like comparison. Canonicalize is invoked after
|
||||
// validation has succeeded but before the object has been persisted.
|
||||
// This method may mutate the object. Often implemented as a type check or
|
||||
// empty method.
|
||||
Canonicalize(obj runtime.Object)
|
||||
}
|
||||
|
||||
// BeforeCreate ensures that common operations for all resources are performed on creation. It only returns
|
||||
// errors that can be converted to api.Status. It invokes PrepareForCreate, then Validate.
|
||||
// It returns nil if the object should be created.
|
||||
func BeforeCreate(strategy RESTCreateStrategy, ctx context.Context, obj runtime.Object) error {
|
||||
objectMeta, kind, kerr := objectMetaAndKind(strategy, obj)
|
||||
if kerr != nil {
|
||||
return kerr
|
||||
}
|
||||
|
||||
// ensure that system-critical metadata has been populated
|
||||
if !metav1.HasObjectMetaSystemFieldValues(objectMeta) {
|
||||
return errors.NewInternalError(fmt.Errorf("system metadata was not initialized"))
|
||||
}
|
||||
|
||||
// ensure the name has been generated
|
||||
if len(objectMeta.GetGenerateName()) > 0 && len(objectMeta.GetName()) == 0 {
|
||||
return errors.NewInternalError(fmt.Errorf("metadata.name was not generated"))
|
||||
}
|
||||
|
||||
// ensure namespace on the object is correct, or error if a conflicting namespace was set in the object
|
||||
requestNamespace, ok := genericapirequest.NamespaceFrom(ctx)
|
||||
if !ok {
|
||||
return errors.NewInternalError(fmt.Errorf("no namespace information found in request context"))
|
||||
}
|
||||
if err := EnsureObjectNamespaceMatchesRequestNamespace(ExpectedNamespaceForScope(requestNamespace, strategy.NamespaceScoped()), objectMeta); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
strategy.PrepareForCreate(ctx, obj)
|
||||
|
||||
if errs := strategy.Validate(ctx, obj); len(errs) > 0 {
|
||||
return errors.NewInvalid(kind.GroupKind(), objectMeta.GetName(), errs)
|
||||
}
|
||||
|
||||
// Custom validation (including name validation) passed
|
||||
// Now run common validation on object meta
|
||||
// Do this *after* custom validation so that specific error messages are shown whenever possible
|
||||
if errs := genericvalidation.ValidateObjectMetaAccessor(objectMeta, strategy.NamespaceScoped(), path.ValidatePathSegmentName, field.NewPath("metadata")); len(errs) > 0 {
|
||||
return errors.NewInvalid(kind.GroupKind(), objectMeta.GetName(), errs)
|
||||
}
|
||||
|
||||
for _, w := range strategy.WarningsOnCreate(ctx, obj) {
|
||||
warning.AddWarning(ctx, "", w)
|
||||
}
|
||||
|
||||
strategy.Canonicalize(obj)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckGeneratedNameError checks whether an error that occurred creating a resource is due
|
||||
// to generation being unable to pick a valid name.
|
||||
func CheckGeneratedNameError(ctx context.Context, strategy RESTCreateStrategy, err error, obj runtime.Object) error {
|
||||
if !errors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
objectMeta, gvk, kerr := objectMetaAndKind(strategy, obj)
|
||||
if kerr != nil {
|
||||
return kerr
|
||||
}
|
||||
|
||||
if len(objectMeta.GetGenerateName()) == 0 {
|
||||
// If we don't have a generated name, return the original error (AlreadyExists).
|
||||
// When we're here, the user picked a name that is causing a conflict.
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the group resource information from the context, if populated.
|
||||
gr := schema.GroupResource{}
|
||||
if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found {
|
||||
gr = schema.GroupResource{Group: gvk.Group, Resource: requestInfo.Resource}
|
||||
}
|
||||
|
||||
// If we have a name and generated name, the server picked a name
|
||||
// that already exists.
|
||||
return errors.NewGenerateNameConflict(gr, objectMeta.GetName(), 1)
|
||||
}
|
||||
|
||||
// objectMetaAndKind retrieves kind and ObjectMeta from a runtime object, or returns an error.
|
||||
func objectMetaAndKind(typer runtime.ObjectTyper, obj runtime.Object) (metav1.Object, schema.GroupVersionKind, error) {
|
||||
objectMeta, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, schema.GroupVersionKind{}, errors.NewInternalError(err)
|
||||
}
|
||||
kinds, _, err := typer.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return nil, schema.GroupVersionKind{}, errors.NewInternalError(err)
|
||||
}
|
||||
return objectMeta, kinds[0], nil
|
||||
}
|
||||
|
||||
// NamespaceScopedStrategy has a method to tell if the object must be in a namespace.
|
||||
type NamespaceScopedStrategy interface {
|
||||
// NamespaceScoped returns if the object must be in a namespace.
|
||||
NamespaceScoped() bool
|
||||
}
|
||||
|
||||
// AdmissionToValidateObjectFunc converts validating admission to a rest validate object func
|
||||
func AdmissionToValidateObjectFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectFunc {
|
||||
validatingAdmission, ok := admit.(admission.ValidationInterface)
|
||||
if !ok {
|
||||
return func(ctx context.Context, obj runtime.Object) error { return nil }
|
||||
}
|
||||
return func(ctx context.Context, obj runtime.Object) error {
|
||||
name := staticAttributes.GetName()
|
||||
// in case the generated name is populated
|
||||
if len(name) == 0 {
|
||||
if metadata, err := meta.Accessor(obj); err == nil {
|
||||
name = metadata.GetName()
|
||||
}
|
||||
}
|
||||
|
||||
finalAttributes := admission.NewAttributesRecord(
|
||||
obj,
|
||||
staticAttributes.GetOldObject(),
|
||||
staticAttributes.GetKind(),
|
||||
staticAttributes.GetNamespace(),
|
||||
name,
|
||||
staticAttributes.GetResource(),
|
||||
staticAttributes.GetSubresource(),
|
||||
staticAttributes.GetOperation(),
|
||||
staticAttributes.GetOperationOptions(),
|
||||
staticAttributes.IsDryRun(),
|
||||
staticAttributes.GetUserInfo(),
|
||||
)
|
||||
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
||||
return nil
|
||||
}
|
||||
return validatingAdmission.Validate(ctx, finalAttributes, o)
|
||||
}
|
||||
}
|
72
vendor/k8s.io/apiserver/pkg/registry/rest/create_update.go
generated
vendored
Normal file
72
vendor/k8s.io/apiserver/pkg/registry/rest/create_update.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2019 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 rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
// RESTCreateUpdateStrategy is a union of RESTUpdateStrategy and RESTCreateStrategy,
|
||||
// and it defines the minimum validation, accepted input, and name generation
|
||||
// behavior to create and update an object that follows Kubernetes API conventions.
|
||||
type RESTCreateUpdateStrategy interface {
|
||||
RESTCreateStrategy
|
||||
// AllowCreateOnUpdate returns true if the object can be created by a PUT.
|
||||
AllowCreateOnUpdate() bool
|
||||
// PrepareForUpdate is invoked on update before validation to normalize
|
||||
// the object. For example: remove fields that are not to be persisted,
|
||||
// sort order-insensitive list fields, etc. This should not remove fields
|
||||
// whose presence would be considered a validation error.
|
||||
PrepareForUpdate(ctx context.Context, obj, old runtime.Object)
|
||||
// ValidateUpdate is invoked after default fields in the object have been
|
||||
// filled in before the object is persisted. This method should not mutate
|
||||
// the object.
|
||||
ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList
|
||||
// WarningsOnUpdate returns warnings to the client performing the update.
|
||||
// WarningsOnUpdate is invoked after default fields in the object have been filled in
|
||||
// and after ValidateUpdate has passed, before Canonicalize is called, and before the object is persisted.
|
||||
// This method must not mutate either object.
|
||||
//
|
||||
// Be brief; limit warnings to 120 characters if possible.
|
||||
// Don't include a "Warning:" prefix in the message (that is added by clients on output).
|
||||
// Warnings returned about a specific field should be formatted as "path.to.field: message".
|
||||
// For example: `spec.imagePullSecrets[0].name: invalid empty name ""`
|
||||
//
|
||||
// Use warning messages to describe problems the client making the API request should correct or be aware of.
|
||||
// For example:
|
||||
// - use of deprecated fields/labels/annotations that will stop working in a future release
|
||||
// - use of obsolete fields/labels/annotations that are non-functional
|
||||
// - malformed or invalid specifications that prevent successful handling of the submitted object,
|
||||
// but are not rejected by validation for compatibility reasons
|
||||
//
|
||||
// Warnings should not be returned for fields which cannot be resolved by the caller.
|
||||
// For example, do not warn about spec fields in a status update.
|
||||
WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string
|
||||
// AllowUnconditionalUpdate returns true if the object can be updated
|
||||
// unconditionally (irrespective of the latest resource version), when
|
||||
// there is no resource version specified in the object.
|
||||
AllowUnconditionalUpdate() bool
|
||||
}
|
||||
|
||||
// Ensure that RESTCreateUpdateStrategy extends RESTCreateStrategy
|
||||
var _ RESTCreateStrategy = (RESTCreateUpdateStrategy)(nil)
|
||||
|
||||
// Ensure that RESTCreateUpdateStrategy extends RESTUpdateStrategy
|
||||
var _ RESTUpdateStrategy = (RESTCreateUpdateStrategy)(nil)
|
202
vendor/k8s.io/apiserver/pkg/registry/rest/delete.go
generated
vendored
Normal file
202
vendor/k8s.io/apiserver/pkg/registry/rest/delete.go
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
Copyright 2014 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 rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
// RESTDeleteStrategy defines deletion behavior on an object that follows Kubernetes
|
||||
// API conventions.
|
||||
type RESTDeleteStrategy interface {
|
||||
runtime.ObjectTyper
|
||||
}
|
||||
|
||||
type GarbageCollectionPolicy string
|
||||
|
||||
const (
|
||||
DeleteDependents GarbageCollectionPolicy = "DeleteDependents"
|
||||
OrphanDependents GarbageCollectionPolicy = "OrphanDependents"
|
||||
// Unsupported means that the resource knows that it cannot be GC'd, so the finalizers
|
||||
// should never be set in storage.
|
||||
Unsupported GarbageCollectionPolicy = "Unsupported"
|
||||
)
|
||||
|
||||
// GarbageCollectionDeleteStrategy must be implemented by the registry that wants to
|
||||
// orphan dependents by default.
|
||||
type GarbageCollectionDeleteStrategy interface {
|
||||
// DefaultGarbageCollectionPolicy returns the default garbage collection behavior.
|
||||
DefaultGarbageCollectionPolicy(ctx context.Context) GarbageCollectionPolicy
|
||||
}
|
||||
|
||||
// RESTGracefulDeleteStrategy must be implemented by the registry that supports
|
||||
// graceful deletion.
|
||||
type RESTGracefulDeleteStrategy interface {
|
||||
// CheckGracefulDelete should return true if the object can be gracefully deleted and set
|
||||
// any default values on the DeleteOptions.
|
||||
// NOTE: if return true, `options.GracePeriodSeconds` must be non-nil (nil will fail),
|
||||
// that's what tells the deletion how "graceful" to be.
|
||||
CheckGracefulDelete(ctx context.Context, obj runtime.Object, options *metav1.DeleteOptions) bool
|
||||
}
|
||||
|
||||
// BeforeDelete tests whether the object can be gracefully deleted.
|
||||
// If graceful is set, the object should be gracefully deleted. If gracefulPending
|
||||
// is set, the object has already been gracefully deleted (and the provided grace
|
||||
// period is longer than the time to deletion). An error is returned if the
|
||||
// condition cannot be checked or the gracePeriodSeconds is invalid. The options
|
||||
// argument may be updated with default values if graceful is true. Second place
|
||||
// where we set deletionTimestamp is pkg/registry/generic/registry/store.go.
|
||||
// This function is responsible for setting deletionTimestamp during gracefulDeletion,
|
||||
// other one for cascading deletions.
|
||||
func BeforeDelete(strategy RESTDeleteStrategy, ctx context.Context, obj runtime.Object, options *metav1.DeleteOptions) (graceful, gracefulPending bool, err error) {
|
||||
objectMeta, gvk, kerr := objectMetaAndKind(strategy, obj)
|
||||
if kerr != nil {
|
||||
return false, false, kerr
|
||||
}
|
||||
if errs := validation.ValidateDeleteOptions(options); len(errs) > 0 {
|
||||
return false, false, errors.NewInvalid(schema.GroupKind{Group: metav1.GroupName, Kind: "DeleteOptions"}, "", errs)
|
||||
}
|
||||
// Checking the Preconditions here to fail early. They'll be enforced later on when we actually do the deletion, too.
|
||||
if options.Preconditions != nil {
|
||||
if options.Preconditions.UID != nil && *options.Preconditions.UID != objectMeta.GetUID() {
|
||||
return false, false, errors.NewConflict(schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, objectMeta.GetName(), fmt.Errorf("the UID in the precondition (%s) does not match the UID in record (%s). The object might have been deleted and then recreated", *options.Preconditions.UID, objectMeta.GetUID()))
|
||||
}
|
||||
if options.Preconditions.ResourceVersion != nil && *options.Preconditions.ResourceVersion != objectMeta.GetResourceVersion() {
|
||||
return false, false, errors.NewConflict(schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, objectMeta.GetName(), fmt.Errorf("the ResourceVersion in the precondition (%s) does not match the ResourceVersion in record (%s). The object might have been modified", *options.Preconditions.ResourceVersion, objectMeta.GetResourceVersion()))
|
||||
}
|
||||
}
|
||||
|
||||
// Negative values will be treated as the value `1s` on the delete path.
|
||||
if gracePeriodSeconds := options.GracePeriodSeconds; gracePeriodSeconds != nil && *gracePeriodSeconds < 0 {
|
||||
options.GracePeriodSeconds = utilpointer.Int64(1)
|
||||
}
|
||||
if deletionGracePeriodSeconds := objectMeta.GetDeletionGracePeriodSeconds(); deletionGracePeriodSeconds != nil && *deletionGracePeriodSeconds < 0 {
|
||||
objectMeta.SetDeletionGracePeriodSeconds(utilpointer.Int64(1))
|
||||
}
|
||||
|
||||
gracefulStrategy, ok := strategy.(RESTGracefulDeleteStrategy)
|
||||
if !ok {
|
||||
// If we're not deleting gracefully there's no point in updating Generation, as we won't update
|
||||
// the obcject before deleting it.
|
||||
return false, false, nil
|
||||
}
|
||||
// if the object is already being deleted, no need to update generation.
|
||||
if objectMeta.GetDeletionTimestamp() != nil {
|
||||
// if we are already being deleted, we may only shorten the deletion grace period
|
||||
// this means the object was gracefully deleted previously but deletionGracePeriodSeconds was not set,
|
||||
// so we force deletion immediately
|
||||
// IMPORTANT:
|
||||
// The deletion operation happens in two phases.
|
||||
// 1. Update to set DeletionGracePeriodSeconds and DeletionTimestamp
|
||||
// 2. Delete the object from storage.
|
||||
// If the update succeeds, but the delete fails (network error, internal storage error, etc.),
|
||||
// a resource was previously left in a state that was non-recoverable. We
|
||||
// check if the existing stored resource has a grace period as 0 and if so
|
||||
// attempt to delete immediately in order to recover from this scenario.
|
||||
if objectMeta.GetDeletionGracePeriodSeconds() == nil || *objectMeta.GetDeletionGracePeriodSeconds() == 0 {
|
||||
return false, false, nil
|
||||
}
|
||||
// only a shorter grace period may be provided by a user
|
||||
if options.GracePeriodSeconds != nil {
|
||||
period := int64(*options.GracePeriodSeconds)
|
||||
if period >= *objectMeta.GetDeletionGracePeriodSeconds() {
|
||||
return false, true, nil
|
||||
}
|
||||
newDeletionTimestamp := metav1.NewTime(
|
||||
objectMeta.GetDeletionTimestamp().Add(-time.Second * time.Duration(*objectMeta.GetDeletionGracePeriodSeconds())).
|
||||
Add(time.Second * time.Duration(*options.GracePeriodSeconds)))
|
||||
objectMeta.SetDeletionTimestamp(&newDeletionTimestamp)
|
||||
objectMeta.SetDeletionGracePeriodSeconds(&period)
|
||||
return true, false, nil
|
||||
}
|
||||
// graceful deletion is pending, do nothing
|
||||
options.GracePeriodSeconds = objectMeta.GetDeletionGracePeriodSeconds()
|
||||
return false, true, nil
|
||||
}
|
||||
|
||||
// `CheckGracefulDelete` will be implemented by specific strategy
|
||||
if !gracefulStrategy.CheckGracefulDelete(ctx, obj, options) {
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
if options.GracePeriodSeconds == nil {
|
||||
return false, false, errors.NewInternalError(fmt.Errorf("options.GracePeriodSeconds should not be nil"))
|
||||
}
|
||||
|
||||
now := metav1.NewTime(metav1.Now().Add(time.Second * time.Duration(*options.GracePeriodSeconds)))
|
||||
objectMeta.SetDeletionTimestamp(&now)
|
||||
objectMeta.SetDeletionGracePeriodSeconds(options.GracePeriodSeconds)
|
||||
// If it's the first graceful deletion we are going to set the DeletionTimestamp to non-nil.
|
||||
// Controllers of the object that's being deleted shouldn't take any nontrivial actions, hence its behavior changes.
|
||||
// Thus we need to bump object's Generation (if set). This handles generation bump during graceful deletion.
|
||||
// The bump for objects that don't support graceful deletion is handled in pkg/registry/generic/registry/store.go.
|
||||
if objectMeta.GetGeneration() > 0 {
|
||||
objectMeta.SetGeneration(objectMeta.GetGeneration() + 1)
|
||||
}
|
||||
|
||||
return true, false, nil
|
||||
}
|
||||
|
||||
// AdmissionToValidateObjectDeleteFunc returns a admission validate func for object deletion
|
||||
func AdmissionToValidateObjectDeleteFunc(admit admission.Interface, staticAttributes admission.Attributes, objInterfaces admission.ObjectInterfaces) ValidateObjectFunc {
|
||||
mutatingAdmission, isMutatingAdmission := admit.(admission.MutationInterface)
|
||||
validatingAdmission, isValidatingAdmission := admit.(admission.ValidationInterface)
|
||||
|
||||
mutating := isMutatingAdmission && mutatingAdmission.Handles(staticAttributes.GetOperation())
|
||||
validating := isValidatingAdmission && validatingAdmission.Handles(staticAttributes.GetOperation())
|
||||
|
||||
return func(ctx context.Context, old runtime.Object) error {
|
||||
if !mutating && !validating {
|
||||
return nil
|
||||
}
|
||||
finalAttributes := admission.NewAttributesRecord(
|
||||
nil,
|
||||
// Deep copy the object to avoid accidentally changing the object.
|
||||
old.DeepCopyObject(),
|
||||
staticAttributes.GetKind(),
|
||||
staticAttributes.GetNamespace(),
|
||||
staticAttributes.GetName(),
|
||||
staticAttributes.GetResource(),
|
||||
staticAttributes.GetSubresource(),
|
||||
staticAttributes.GetOperation(),
|
||||
staticAttributes.GetOperationOptions(),
|
||||
staticAttributes.IsDryRun(),
|
||||
staticAttributes.GetUserInfo(),
|
||||
)
|
||||
if mutating {
|
||||
if err := mutatingAdmission.Admit(ctx, finalAttributes, objInterfaces); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if validating {
|
||||
if err := validatingAdmission.Validate(ctx, finalAttributes, objInterfaces); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
18
vendor/k8s.io/apiserver/pkg/registry/rest/doc.go
generated
vendored
Normal file
18
vendor/k8s.io/apiserver/pkg/registry/rest/doc.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright 2014 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 rest defines common logic around changes to Kubernetes-style resources.
|
||||
package rest // import "k8s.io/apiserver/pkg/registry/rest"
|
81
vendor/k8s.io/apiserver/pkg/registry/rest/meta.go
generated
vendored
Normal file
81
vendor/k8s.io/apiserver/pkg/registry/rest/meta.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rest
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
)
|
||||
|
||||
// WipeObjectMetaSystemFields erases fields that are managed by the system on ObjectMeta.
|
||||
func WipeObjectMetaSystemFields(meta metav1.Object) {
|
||||
meta.SetCreationTimestamp(metav1.Time{})
|
||||
meta.SetUID("")
|
||||
meta.SetDeletionTimestamp(nil)
|
||||
meta.SetDeletionGracePeriodSeconds(nil)
|
||||
meta.SetSelfLink("")
|
||||
}
|
||||
|
||||
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
|
||||
func FillObjectMetaSystemFields(meta metav1.Object) {
|
||||
meta.SetCreationTimestamp(metav1.Now())
|
||||
meta.SetUID(uuid.NewUUID())
|
||||
}
|
||||
|
||||
// EnsureObjectNamespaceMatchesRequestNamespace returns an error if obj.Namespace and requestNamespace
|
||||
// are both populated and do not match. If either is unpopulated, it modifies obj as needed to ensure
|
||||
// obj.GetNamespace() == requestNamespace.
|
||||
func EnsureObjectNamespaceMatchesRequestNamespace(requestNamespace string, obj metav1.Object) error {
|
||||
objNamespace := obj.GetNamespace()
|
||||
switch {
|
||||
case objNamespace == requestNamespace:
|
||||
// already matches, no-op
|
||||
return nil
|
||||
|
||||
case objNamespace == metav1.NamespaceNone:
|
||||
// unset, default to request namespace
|
||||
obj.SetNamespace(requestNamespace)
|
||||
return nil
|
||||
|
||||
case requestNamespace == metav1.NamespaceNone:
|
||||
// cluster-scoped, clear namespace
|
||||
obj.SetNamespace(metav1.NamespaceNone)
|
||||
return nil
|
||||
|
||||
default:
|
||||
// mismatch, error
|
||||
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
|
||||
}
|
||||
}
|
||||
|
||||
// ExpectedNamespaceForScope returns the expected namespace for a resource, given the request namespace and resource scope.
|
||||
func ExpectedNamespaceForScope(requestNamespace string, namespaceScoped bool) string {
|
||||
if namespaceScoped {
|
||||
return requestNamespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ExpectedNamespaceForResource returns the expected namespace for a resource, given the request namespace.
|
||||
func ExpectedNamespaceForResource(requestNamespace string, resource schema.GroupVersionResource) string {
|
||||
if resource.Resource == "namespaces" && resource.Group == "" {
|
||||
return ""
|
||||
}
|
||||
return requestNamespace
|
||||
}
|
379
vendor/k8s.io/apiserver/pkg/registry/rest/rest.go
generated
vendored
Normal file
379
vendor/k8s.io/apiserver/pkg/registry/rest/rest.go
generated
vendored
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
Copyright 2014 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 rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
//TODO:
|
||||
// Storage interfaces need to be separated into two groups; those that operate
|
||||
// on collections and those that operate on individually named items.
|
||||
// Collection interfaces:
|
||||
// (Method: Current -> Proposed)
|
||||
// GET: Lister -> CollectionGetter
|
||||
// WATCH: Watcher -> CollectionWatcher
|
||||
// CREATE: Creater -> CollectionCreater
|
||||
// DELETE: (n/a) -> CollectionDeleter
|
||||
// UPDATE: (n/a) -> CollectionUpdater
|
||||
//
|
||||
// Single item interfaces:
|
||||
// (Method: Current -> Proposed)
|
||||
// GET: Getter -> NamedGetter
|
||||
// WATCH: (n/a) -> NamedWatcher
|
||||
// CREATE: (n/a) -> NamedCreater
|
||||
// DELETE: Deleter -> NamedDeleter
|
||||
// UPDATE: Update -> NamedUpdater
|
||||
|
||||
// Storage is a generic interface for RESTful storage services.
|
||||
// Resources which are exported to the RESTful API of apiserver need to implement this interface. It is expected
|
||||
// that objects may implement any of the below interfaces.
|
||||
type Storage interface {
|
||||
// New returns an empty object that can be used with Create and Update after request data has been put into it.
|
||||
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
|
||||
New() runtime.Object
|
||||
|
||||
// Destroy cleans up its resources on shutdown.
|
||||
// Destroy has to be implemented in thread-safe way and be prepared
|
||||
// for being called more than once.
|
||||
Destroy()
|
||||
}
|
||||
|
||||
// Scoper indicates what scope the resource is at. It must be specified.
|
||||
// It is usually provided automatically based on your strategy.
|
||||
type Scoper interface {
|
||||
// NamespaceScoped returns true if the storage is namespaced
|
||||
NamespaceScoped() bool
|
||||
}
|
||||
|
||||
// KindProvider specifies a different kind for its API than for its internal storage. This is necessary for external
|
||||
// objects that are not compiled into the api server. For such objects, there is no in-memory representation for
|
||||
// the object, so they must be represented as generic objects (e.g. runtime.Unknown), but when we present the object as part of
|
||||
// API discovery we want to present the specific kind, not the generic internal representation.
|
||||
type KindProvider interface {
|
||||
Kind() string
|
||||
}
|
||||
|
||||
// ShortNamesProvider is an interface for RESTful storage services. Delivers a list of short names for a resource. The list is used by kubectl to have short names representation of resources.
|
||||
type ShortNamesProvider interface {
|
||||
ShortNames() []string
|
||||
}
|
||||
|
||||
// CategoriesProvider allows a resource to specify which groups of resources (categories) it's part of. Categories can
|
||||
// be used by API clients to refer to a batch of resources by using a single name (e.g. "all" could translate to "pod,rc,svc,...").
|
||||
type CategoriesProvider interface {
|
||||
Categories() []string
|
||||
}
|
||||
|
||||
// GroupVersionKindProvider is used to specify a particular GroupVersionKind to discovery. This is used for polymorphic endpoints
|
||||
// which generally point to foreign versions. Scale refers to Scale.v1beta1.extensions for instance.
|
||||
// This trumps KindProvider since it is capable of providing the information required.
|
||||
// TODO KindProvider (only used by federation) should be removed and replaced with this, but that presents greater risk late in 1.8.
|
||||
type GroupVersionKindProvider interface {
|
||||
GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind
|
||||
}
|
||||
|
||||
// GroupVersionAcceptor is used to determine if a particular GroupVersion is acceptable to send to an endpoint.
|
||||
// This is used for endpoints which accept multiple versions (which is extremely rare).
|
||||
// The only known instance is pods/evictions which accepts policy/v1, but also policy/v1beta1 for backwards compatibility.
|
||||
type GroupVersionAcceptor interface {
|
||||
AcceptsGroupVersion(gv schema.GroupVersion) bool
|
||||
}
|
||||
|
||||
// Lister is an object that can retrieve resources that match the provided field and label criteria.
|
||||
type Lister interface {
|
||||
// NewList returns an empty object that can be used with the List call.
|
||||
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
|
||||
NewList() runtime.Object
|
||||
// List selects resources in the storage which match to the selector. 'options' can be nil.
|
||||
List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error)
|
||||
// TableConvertor ensures all list implementers also implement table conversion
|
||||
TableConvertor
|
||||
}
|
||||
|
||||
// Getter is an object that can retrieve a named RESTful resource.
|
||||
type Getter interface {
|
||||
// Get finds a resource in the storage by name and returns it.
|
||||
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
|
||||
// returned error value err when the specified resource is not found.
|
||||
Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error)
|
||||
}
|
||||
|
||||
// GetterWithOptions is an object that retrieve a named RESTful resource and takes
|
||||
// additional options on the get request. It allows a caller to also receive the
|
||||
// subpath of the GET request.
|
||||
type GetterWithOptions interface {
|
||||
// Get finds a resource in the storage by name and returns it.
|
||||
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
|
||||
// returned error value err when the specified resource is not found.
|
||||
// The options object passed to it is of the same type returned by the NewGetOptions
|
||||
// method.
|
||||
// TODO: Pass metav1.GetOptions.
|
||||
Get(ctx context.Context, name string, options runtime.Object) (runtime.Object, error)
|
||||
|
||||
// NewGetOptions returns an empty options object that will be used to pass
|
||||
// options to the Get method. It may return a bool and a string, if true, the
|
||||
// value of the request path below the object will be included as the named
|
||||
// string in the serialization of the runtime object. E.g., returning "path"
|
||||
// will convert the trailing request scheme value to "path" in the map[string][]string
|
||||
// passed to the converter.
|
||||
NewGetOptions() (runtime.Object, bool, string)
|
||||
}
|
||||
|
||||
type TableConvertor interface {
|
||||
ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error)
|
||||
}
|
||||
|
||||
// GracefulDeleter knows how to pass deletion options to allow delayed deletion of a
|
||||
// RESTful object.
|
||||
type GracefulDeleter interface {
|
||||
// Delete finds a resource in the storage and deletes it.
|
||||
// The delete attempt is validated by the deleteValidation first.
|
||||
// If options are provided, the resource will attempt to honor them or return an invalid
|
||||
// request error.
|
||||
// Although it can return an arbitrary error value, IsNotFound(err) is true for the
|
||||
// returned error value err when the specified resource is not found.
|
||||
// Delete *may* return the object that was deleted, or a status object indicating additional
|
||||
// information about deletion.
|
||||
// It also returns a boolean which is set to true if the resource was instantly
|
||||
// deleted or false if it will be deleted asynchronously.
|
||||
Delete(ctx context.Context, name string, deleteValidation ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error)
|
||||
}
|
||||
|
||||
// MayReturnFullObjectDeleter may return deleted object (instead of a simple status) on deletion.
|
||||
type MayReturnFullObjectDeleter interface {
|
||||
DeleteReturnsDeletedObject() bool
|
||||
}
|
||||
|
||||
// CollectionDeleter is an object that can delete a collection
|
||||
// of RESTful resources.
|
||||
type CollectionDeleter interface {
|
||||
// DeleteCollection selects all resources in the storage matching given 'listOptions'
|
||||
// and deletes them. The delete attempt is validated by the deleteValidation first.
|
||||
// If 'options' are provided, the resource will attempt to honor them or return an
|
||||
// invalid request error.
|
||||
// DeleteCollection may not be atomic - i.e. it may delete some objects and still
|
||||
// return an error after it. On success, returns a list of deleted objects.
|
||||
DeleteCollection(ctx context.Context, deleteValidation ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error)
|
||||
}
|
||||
|
||||
// Creater is an object that can create an instance of a RESTful object.
|
||||
type Creater interface {
|
||||
// New returns an empty object that can be used with Create after request data has been put into it.
|
||||
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
|
||||
New() runtime.Object
|
||||
|
||||
// Create creates a new version of a resource.
|
||||
Create(ctx context.Context, obj runtime.Object, createValidation ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error)
|
||||
}
|
||||
|
||||
// NamedCreater is an object that can create an instance of a RESTful object using a name parameter.
|
||||
type NamedCreater interface {
|
||||
// New returns an empty object that can be used with Create after request data has been put into it.
|
||||
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
|
||||
New() runtime.Object
|
||||
|
||||
// Create creates a new version of a resource. It expects a name parameter from the path.
|
||||
// This is needed for create operations on subresources which include the name of the parent
|
||||
// resource in the path.
|
||||
Create(ctx context.Context, name string, obj runtime.Object, createValidation ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error)
|
||||
}
|
||||
|
||||
// UpdatedObjectInfo provides information about an updated object to an Updater.
|
||||
// It requires access to the old object in order to return the newly updated object.
|
||||
type UpdatedObjectInfo interface {
|
||||
// Returns preconditions built from the updated object, if applicable.
|
||||
// May return nil, or a preconditions object containing nil fields,
|
||||
// if no preconditions can be determined from the updated object.
|
||||
Preconditions() *metav1.Preconditions
|
||||
|
||||
// UpdatedObject returns the updated object, given a context and old object.
|
||||
// The only time an empty oldObj should be passed in is if a "create on update" is occurring (there is no oldObj).
|
||||
UpdatedObject(ctx context.Context, oldObj runtime.Object) (newObj runtime.Object, err error)
|
||||
}
|
||||
|
||||
// ValidateObjectFunc is a function to act on a given object. An error may be returned
|
||||
// if the hook cannot be completed. A ValidateObjectFunc may NOT transform the provided
|
||||
// object.
|
||||
type ValidateObjectFunc func(ctx context.Context, obj runtime.Object) error
|
||||
|
||||
// ValidateAllObjectFunc is a "admit everything" instance of ValidateObjectFunc.
|
||||
func ValidateAllObjectFunc(ctx context.Context, obj runtime.Object) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateObjectUpdateFunc is a function to act on a given object and its predecessor.
|
||||
// An error may be returned if the hook cannot be completed. An UpdateObjectFunc
|
||||
// may NOT transform the provided object.
|
||||
type ValidateObjectUpdateFunc func(ctx context.Context, obj, old runtime.Object) error
|
||||
|
||||
// ValidateAllObjectUpdateFunc is a "admit everything" instance of ValidateObjectUpdateFunc.
|
||||
func ValidateAllObjectUpdateFunc(ctx context.Context, obj, old runtime.Object) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Updater is an object that can update an instance of a RESTful object.
|
||||
type Updater interface {
|
||||
// New returns an empty object that can be used with Update after request data has been put into it.
|
||||
// This object must be a pointer type for use with Codec.DecodeInto([]byte, runtime.Object)
|
||||
New() runtime.Object
|
||||
|
||||
// Update finds a resource in the storage and updates it. Some implementations
|
||||
// may allow updates creates the object - they should set the created boolean
|
||||
// to true.
|
||||
Update(ctx context.Context, name string, objInfo UpdatedObjectInfo, createValidation ValidateObjectFunc, updateValidation ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error)
|
||||
}
|
||||
|
||||
// CreaterUpdater is a storage object that must support both create and update.
|
||||
// Go prevents embedded interfaces that implement the same method.
|
||||
type CreaterUpdater interface {
|
||||
Creater
|
||||
Update(ctx context.Context, name string, objInfo UpdatedObjectInfo, createValidation ValidateObjectFunc, updateValidation ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error)
|
||||
}
|
||||
|
||||
// CreaterUpdater must satisfy the Updater interface.
|
||||
var _ Updater = CreaterUpdater(nil)
|
||||
|
||||
// Patcher is a storage object that supports both get and update.
|
||||
type Patcher interface {
|
||||
Getter
|
||||
Updater
|
||||
}
|
||||
|
||||
// Watcher should be implemented by all Storage objects that
|
||||
// want to offer the ability to watch for changes through the watch api.
|
||||
type Watcher interface {
|
||||
// 'label' selects on labels; 'field' selects on the object's fields. Not all fields
|
||||
// are supported; an error should be returned if 'field' tries to select on a field that
|
||||
// isn't supported. 'resourceVersion' allows for continuing/starting a watch at a
|
||||
// particular version.
|
||||
Watch(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
|
||||
}
|
||||
|
||||
// StandardStorage is an interface covering the common verbs. Provided for testing whether a
|
||||
// resource satisfies the normal storage methods. Use Storage when passing opaque storage objects.
|
||||
type StandardStorage interface {
|
||||
Getter
|
||||
Lister
|
||||
CreaterUpdater
|
||||
GracefulDeleter
|
||||
CollectionDeleter
|
||||
Watcher
|
||||
|
||||
// Destroy cleans up its resources on shutdown.
|
||||
// Destroy has to be implemented in thread-safe way and be prepared
|
||||
// for being called more than once.
|
||||
Destroy()
|
||||
}
|
||||
|
||||
// Redirector know how to return a remote resource's location.
|
||||
type Redirector interface {
|
||||
// ResourceLocation should return the remote location of the given resource, and an optional transport to use to request it, or an error.
|
||||
ResourceLocation(ctx context.Context, id string) (remoteLocation *url.URL, transport http.RoundTripper, err error)
|
||||
}
|
||||
|
||||
// Responder abstracts the normal response behavior for a REST method and is passed to callers that
|
||||
// may wish to handle the response directly in some cases, but delegate to the normal error or object
|
||||
// behavior in other cases.
|
||||
type Responder interface {
|
||||
// Object writes the provided object to the response. Invoking this method multiple times is undefined.
|
||||
Object(statusCode int, obj runtime.Object)
|
||||
// Error writes the provided error to the response. This method may only be invoked once.
|
||||
Error(err error)
|
||||
}
|
||||
|
||||
// Connecter is a storage object that responds to a connection request.
|
||||
type Connecter interface {
|
||||
// Connect returns an http.Handler that will handle the request/response for a given API invocation.
|
||||
// The provided responder may be used for common API responses. The responder will write both status
|
||||
// code and body, so the ServeHTTP method should exit after invoking the responder. The Handler will
|
||||
// be used for a single API request and then discarded. The Responder is guaranteed to write to the
|
||||
// same http.ResponseWriter passed to ServeHTTP.
|
||||
Connect(ctx context.Context, id string, options runtime.Object, r Responder) (http.Handler, error)
|
||||
|
||||
// NewConnectOptions returns an empty options object that will be used to pass
|
||||
// options to the Connect method. If nil, then a nil options object is passed to
|
||||
// Connect. It may return a bool and a string. If true, the value of the request
|
||||
// path below the object will be included as the named string in the serialization
|
||||
// of the runtime object.
|
||||
NewConnectOptions() (runtime.Object, bool, string)
|
||||
|
||||
// ConnectMethods returns the list of HTTP methods handled by Connect
|
||||
ConnectMethods() []string
|
||||
}
|
||||
|
||||
// ResourceStreamer is an interface implemented by objects that prefer to be streamed from the server
|
||||
// instead of decoded directly.
|
||||
type ResourceStreamer interface {
|
||||
// InputStream should return an io.ReadCloser if the provided object supports streaming. The desired
|
||||
// api version and an accept header (may be empty) are passed to the call. If no error occurs,
|
||||
// the caller may return a flag indicating whether the result should be flushed as writes occur
|
||||
// and a content type string that indicates the type of the stream.
|
||||
// If a null stream is returned, a StatusNoContent response wil be generated.
|
||||
InputStream(ctx context.Context, apiVersion, acceptHeader string) (stream io.ReadCloser, flush bool, mimeType string, err error)
|
||||
}
|
||||
|
||||
// StorageMetadata is an optional interface that callers can implement to provide additional
|
||||
// information about their Storage objects.
|
||||
type StorageMetadata interface {
|
||||
// ProducesMIMETypes returns a list of the MIME types the specified HTTP verb (GET, POST, DELETE,
|
||||
// PATCH) can respond with.
|
||||
ProducesMIMETypes(verb string) []string
|
||||
|
||||
// ProducesObject returns an object the specified HTTP verb respond with. It will overwrite storage object if
|
||||
// it is not nil. Only the type of the return object matters, the value will be ignored.
|
||||
ProducesObject(verb string) interface{}
|
||||
}
|
||||
|
||||
// StorageVersionProvider is an optional interface that a storage object can
|
||||
// implement if it wishes to disclose its storage version.
|
||||
type StorageVersionProvider interface {
|
||||
// StorageVersion returns a group versioner, which will outputs the gvk
|
||||
// an object will be converted to before persisted in etcd, given a
|
||||
// list of kinds the object might belong to.
|
||||
StorageVersion() runtime.GroupVersioner
|
||||
}
|
||||
|
||||
// ResetFieldsStrategy is an optional interface that a storage object can
|
||||
// implement if it wishes to provide the fields reset by its strategies.
|
||||
type ResetFieldsStrategy interface {
|
||||
GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set
|
||||
}
|
||||
|
||||
// CreateUpdateResetFieldsStrategy is a union of RESTCreateUpdateStrategy
|
||||
// and ResetFieldsStrategy.
|
||||
type CreateUpdateResetFieldsStrategy interface {
|
||||
RESTCreateUpdateStrategy
|
||||
ResetFieldsStrategy
|
||||
}
|
||||
|
||||
// UpdateResetFieldsStrategy is a union of RESTUpdateStrategy
|
||||
// and ResetFieldsStrategy.
|
||||
type UpdateResetFieldsStrategy interface {
|
||||
RESTUpdateStrategy
|
||||
ResetFieldsStrategy
|
||||
}
|
105
vendor/k8s.io/apiserver/pkg/registry/rest/table.go
generated
vendored
Normal file
105
vendor/k8s.io/apiserver/pkg/registry/rest/table.go
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
Copyright 2014 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 rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
type defaultTableConvertor struct {
|
||||
defaultQualifiedResource schema.GroupResource
|
||||
}
|
||||
|
||||
// NewDefaultTableConvertor creates a default convertor; the provided resource is used for error messages
|
||||
// if no resource info can be determined from the context passed to ConvertToTable.
|
||||
func NewDefaultTableConvertor(defaultQualifiedResource schema.GroupResource) TableConvertor {
|
||||
return defaultTableConvertor{defaultQualifiedResource: defaultQualifiedResource}
|
||||
}
|
||||
|
||||
var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()
|
||||
|
||||
func (c defaultTableConvertor) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
|
||||
var table metav1.Table
|
||||
fn := func(obj runtime.Object) error {
|
||||
m, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
resource := c.defaultQualifiedResource
|
||||
if info, ok := genericapirequest.RequestInfoFrom(ctx); ok {
|
||||
resource = schema.GroupResource{Group: info.APIGroup, Resource: info.Resource}
|
||||
}
|
||||
return errNotAcceptable{resource: resource}
|
||||
}
|
||||
table.Rows = append(table.Rows, metav1.TableRow{
|
||||
Cells: []interface{}{m.GetName(), m.GetCreationTimestamp().Time.UTC().Format(time.RFC3339)},
|
||||
Object: runtime.RawExtension{Object: obj},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
switch {
|
||||
case meta.IsListType(object):
|
||||
if err := meta.EachListItem(object, fn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
if err := fn(object); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if m, err := meta.ListAccessor(object); err == nil {
|
||||
table.ResourceVersion = m.GetResourceVersion()
|
||||
table.Continue = m.GetContinue()
|
||||
table.RemainingItemCount = m.GetRemainingItemCount()
|
||||
} else {
|
||||
if m, err := meta.CommonAccessor(object); err == nil {
|
||||
table.ResourceVersion = m.GetResourceVersion()
|
||||
}
|
||||
}
|
||||
if opt, ok := tableOptions.(*metav1.TableOptions); !ok || !opt.NoHeaders {
|
||||
table.ColumnDefinitions = []metav1.TableColumnDefinition{
|
||||
{Name: "Name", Type: "string", Format: "name", Description: swaggerMetadataDescriptions["name"]},
|
||||
{Name: "Created At", Type: "date", Description: swaggerMetadataDescriptions["creationTimestamp"]},
|
||||
}
|
||||
}
|
||||
return &table, nil
|
||||
}
|
||||
|
||||
// errNotAcceptable indicates the resource doesn't support Table conversion
|
||||
type errNotAcceptable struct {
|
||||
resource schema.GroupResource
|
||||
}
|
||||
|
||||
func (e errNotAcceptable) Error() string {
|
||||
return fmt.Sprintf("the resource %s does not support being converted to a Table", e.resource)
|
||||
}
|
||||
|
||||
func (e errNotAcceptable) Status() metav1.Status {
|
||||
return metav1.Status{
|
||||
Status: metav1.StatusFailure,
|
||||
Code: http.StatusNotAcceptable,
|
||||
Reason: metav1.StatusReason("NotAcceptable"),
|
||||
Message: e.Error(),
|
||||
}
|
||||
}
|
295
vendor/k8s.io/apiserver/pkg/registry/rest/update.go
generated
vendored
Normal file
295
vendor/k8s.io/apiserver/pkg/registry/rest/update.go
generated
vendored
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
Copyright 2014 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 rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||
"k8s.io/apimachinery/pkg/api/validation/path"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/warning"
|
||||
)
|
||||
|
||||
// RESTUpdateStrategy defines the minimum validation, accepted input, and
|
||||
// name generation behavior to update an object that follows Kubernetes
|
||||
// API conventions. A resource may have many UpdateStrategies, depending on
|
||||
// the call pattern in use.
|
||||
type RESTUpdateStrategy interface {
|
||||
runtime.ObjectTyper
|
||||
// NamespaceScoped returns true if the object must be within a namespace.
|
||||
NamespaceScoped() bool
|
||||
// AllowCreateOnUpdate returns true if the object can be created by a PUT.
|
||||
AllowCreateOnUpdate() bool
|
||||
// PrepareForUpdate is invoked on update before validation to normalize
|
||||
// the object. For example: remove fields that are not to be persisted,
|
||||
// sort order-insensitive list fields, etc. This should not remove fields
|
||||
// whose presence would be considered a validation error.
|
||||
PrepareForUpdate(ctx context.Context, obj, old runtime.Object)
|
||||
// ValidateUpdate is invoked after default fields in the object have been
|
||||
// filled in before the object is persisted. This method should not mutate
|
||||
// the object.
|
||||
ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList
|
||||
// WarningsOnUpdate returns warnings to the client performing the update.
|
||||
// WarningsOnUpdate is invoked after default fields in the object have been filled in
|
||||
// and after ValidateUpdate has passed, before Canonicalize is called, and before the object is persisted.
|
||||
// This method must not mutate either object.
|
||||
//
|
||||
// Be brief; limit warnings to 120 characters if possible.
|
||||
// Don't include a "Warning:" prefix in the message (that is added by clients on output).
|
||||
// Warnings returned about a specific field should be formatted as "path.to.field: message".
|
||||
// For example: `spec.imagePullSecrets[0].name: invalid empty name ""`
|
||||
//
|
||||
// Use warning messages to describe problems the client making the API request should correct or be aware of.
|
||||
// For example:
|
||||
// - use of deprecated fields/labels/annotations that will stop working in a future release
|
||||
// - use of obsolete fields/labels/annotations that are non-functional
|
||||
// - malformed or invalid specifications that prevent successful handling of the submitted object,
|
||||
// but are not rejected by validation for compatibility reasons
|
||||
//
|
||||
// Warnings should not be returned for fields which cannot be resolved by the caller.
|
||||
// For example, do not warn about spec fields in a status update.
|
||||
WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string
|
||||
// Canonicalize allows an object to be mutated into a canonical form. This
|
||||
// ensures that code that operates on these objects can rely on the common
|
||||
// form for things like comparison. Canonicalize is invoked after
|
||||
// validation has succeeded but before the object has been persisted.
|
||||
// This method may mutate the object.
|
||||
Canonicalize(obj runtime.Object)
|
||||
// AllowUnconditionalUpdate returns true if the object can be updated
|
||||
// unconditionally (irrespective of the latest resource version), when
|
||||
// there is no resource version specified in the object.
|
||||
AllowUnconditionalUpdate() bool
|
||||
}
|
||||
|
||||
// TODO: add other common fields that require global validation.
|
||||
func validateCommonFields(obj, old runtime.Object, strategy RESTUpdateStrategy) (field.ErrorList, error) {
|
||||
allErrs := field.ErrorList{}
|
||||
objectMeta, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get new object metadata: %v", err)
|
||||
}
|
||||
oldObjectMeta, err := meta.Accessor(old)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get old object metadata: %v", err)
|
||||
}
|
||||
allErrs = append(allErrs, genericvalidation.ValidateObjectMetaAccessor(objectMeta, strategy.NamespaceScoped(), path.ValidatePathSegmentName, field.NewPath("metadata"))...)
|
||||
allErrs = append(allErrs, genericvalidation.ValidateObjectMetaAccessorUpdate(objectMeta, oldObjectMeta, field.NewPath("metadata"))...)
|
||||
|
||||
return allErrs, nil
|
||||
}
|
||||
|
||||
// BeforeUpdate ensures that common operations for all resources are performed on update. It only returns
|
||||
// errors that can be converted to api.Status. It will invoke update validation with the provided existing
|
||||
// and updated objects.
|
||||
// It sets zero values only if the object does not have a zero value for the respective field.
|
||||
func BeforeUpdate(strategy RESTUpdateStrategy, ctx context.Context, obj, old runtime.Object) error {
|
||||
objectMeta, kind, kerr := objectMetaAndKind(strategy, obj)
|
||||
if kerr != nil {
|
||||
return kerr
|
||||
}
|
||||
|
||||
// ensure namespace on the object is correct, or error if a conflicting namespace was set in the object
|
||||
requestNamespace, ok := genericapirequest.NamespaceFrom(ctx)
|
||||
if !ok {
|
||||
return errors.NewInternalError(fmt.Errorf("no namespace information found in request context"))
|
||||
}
|
||||
if err := EnsureObjectNamespaceMatchesRequestNamespace(ExpectedNamespaceForScope(requestNamespace, strategy.NamespaceScoped()), objectMeta); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure requests cannot update generation
|
||||
oldMeta, err := meta.Accessor(old)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objectMeta.SetGeneration(oldMeta.GetGeneration())
|
||||
|
||||
strategy.PrepareForUpdate(ctx, obj, old)
|
||||
|
||||
// Use the existing UID if none is provided
|
||||
if len(objectMeta.GetUID()) == 0 {
|
||||
objectMeta.SetUID(oldMeta.GetUID())
|
||||
}
|
||||
// ignore changes to timestamp
|
||||
if oldCreationTime := oldMeta.GetCreationTimestamp(); !oldCreationTime.IsZero() {
|
||||
objectMeta.SetCreationTimestamp(oldMeta.GetCreationTimestamp())
|
||||
}
|
||||
// an update can never remove/change a deletion timestamp
|
||||
if !oldMeta.GetDeletionTimestamp().IsZero() {
|
||||
objectMeta.SetDeletionTimestamp(oldMeta.GetDeletionTimestamp())
|
||||
}
|
||||
// an update can never remove/change grace period seconds
|
||||
if oldMeta.GetDeletionGracePeriodSeconds() != nil && objectMeta.GetDeletionGracePeriodSeconds() == nil {
|
||||
objectMeta.SetDeletionGracePeriodSeconds(oldMeta.GetDeletionGracePeriodSeconds())
|
||||
}
|
||||
|
||||
// Ensure some common fields, like UID, are validated for all resources.
|
||||
errs, err := validateCommonFields(obj, old, strategy)
|
||||
if err != nil {
|
||||
return errors.NewInternalError(err)
|
||||
}
|
||||
|
||||
errs = append(errs, strategy.ValidateUpdate(ctx, obj, old)...)
|
||||
if len(errs) > 0 {
|
||||
return errors.NewInvalid(kind.GroupKind(), objectMeta.GetName(), errs)
|
||||
}
|
||||
|
||||
for _, w := range strategy.WarningsOnUpdate(ctx, obj, old) {
|
||||
warning.AddWarning(ctx, "", w)
|
||||
}
|
||||
|
||||
strategy.Canonicalize(obj)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TransformFunc is a function to transform and return newObj
|
||||
type TransformFunc func(ctx context.Context, newObj runtime.Object, oldObj runtime.Object) (transformedNewObj runtime.Object, err error)
|
||||
|
||||
// defaultUpdatedObjectInfo implements UpdatedObjectInfo
|
||||
type defaultUpdatedObjectInfo struct {
|
||||
// obj is the updated object
|
||||
obj runtime.Object
|
||||
|
||||
// transformers is an optional list of transforming functions that modify or
|
||||
// replace obj using information from the context, old object, or other sources.
|
||||
transformers []TransformFunc
|
||||
}
|
||||
|
||||
// DefaultUpdatedObjectInfo returns an UpdatedObjectInfo impl based on the specified object.
|
||||
func DefaultUpdatedObjectInfo(obj runtime.Object, transformers ...TransformFunc) UpdatedObjectInfo {
|
||||
return &defaultUpdatedObjectInfo{obj, transformers}
|
||||
}
|
||||
|
||||
// Preconditions satisfies the UpdatedObjectInfo interface.
|
||||
func (i *defaultUpdatedObjectInfo) Preconditions() *metav1.Preconditions {
|
||||
// Attempt to get the UID out of the object
|
||||
accessor, err := meta.Accessor(i.obj)
|
||||
if err != nil {
|
||||
// If no UID can be read, no preconditions are possible
|
||||
return nil
|
||||
}
|
||||
|
||||
// If empty, no preconditions needed
|
||||
uid := accessor.GetUID()
|
||||
if len(uid) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &metav1.Preconditions{UID: &uid}
|
||||
}
|
||||
|
||||
// UpdatedObject satisfies the UpdatedObjectInfo interface.
|
||||
// It returns a copy of the held obj, passed through any configured transformers.
|
||||
func (i *defaultUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj runtime.Object) (runtime.Object, error) {
|
||||
var err error
|
||||
// Start with the configured object
|
||||
newObj := i.obj
|
||||
|
||||
// If the original is non-nil (might be nil if the first transformer builds the object from the oldObj), make a copy,
|
||||
// so we don't return the original. BeforeUpdate can mutate the returned object, doing things like clearing ResourceVersion.
|
||||
// If we're re-called, we need to be able to return the pristine version.
|
||||
if newObj != nil {
|
||||
newObj = newObj.DeepCopyObject()
|
||||
}
|
||||
|
||||
// Allow any configured transformers to update the new object
|
||||
for _, transformer := range i.transformers {
|
||||
newObj, err = transformer(ctx, newObj, oldObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return newObj, nil
|
||||
}
|
||||
|
||||
// wrappedUpdatedObjectInfo allows wrapping an existing objInfo and
|
||||
// chaining additional transformations/checks on the result of UpdatedObject()
|
||||
type wrappedUpdatedObjectInfo struct {
|
||||
// obj is the updated object
|
||||
objInfo UpdatedObjectInfo
|
||||
|
||||
// transformers is an optional list of transforming functions that modify or
|
||||
// replace obj using information from the context, old object, or other sources.
|
||||
transformers []TransformFunc
|
||||
}
|
||||
|
||||
// WrapUpdatedObjectInfo returns an UpdatedObjectInfo impl that delegates to
|
||||
// the specified objInfo, then calls the passed transformers
|
||||
func WrapUpdatedObjectInfo(objInfo UpdatedObjectInfo, transformers ...TransformFunc) UpdatedObjectInfo {
|
||||
return &wrappedUpdatedObjectInfo{objInfo, transformers}
|
||||
}
|
||||
|
||||
// Preconditions satisfies the UpdatedObjectInfo interface.
|
||||
func (i *wrappedUpdatedObjectInfo) Preconditions() *metav1.Preconditions {
|
||||
return i.objInfo.Preconditions()
|
||||
}
|
||||
|
||||
// UpdatedObject satisfies the UpdatedObjectInfo interface.
|
||||
// It delegates to the wrapped objInfo and passes the result through any configured transformers.
|
||||
func (i *wrappedUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj runtime.Object) (runtime.Object, error) {
|
||||
newObj, err := i.objInfo.UpdatedObject(ctx, oldObj)
|
||||
if err != nil {
|
||||
return newObj, err
|
||||
}
|
||||
|
||||
// Allow any configured transformers to update the new object or error
|
||||
for _, transformer := range i.transformers {
|
||||
newObj, err = transformer(ctx, newObj, oldObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return newObj, nil
|
||||
}
|
||||
|
||||
// AdmissionToValidateObjectUpdateFunc converts validating admission to a rest validate object update func
|
||||
func AdmissionToValidateObjectUpdateFunc(admit admission.Interface, staticAttributes admission.Attributes, o admission.ObjectInterfaces) ValidateObjectUpdateFunc {
|
||||
validatingAdmission, ok := admit.(admission.ValidationInterface)
|
||||
if !ok {
|
||||
return func(ctx context.Context, obj, old runtime.Object) error { return nil }
|
||||
}
|
||||
return func(ctx context.Context, obj, old runtime.Object) error {
|
||||
finalAttributes := admission.NewAttributesRecord(
|
||||
obj,
|
||||
old,
|
||||
staticAttributes.GetKind(),
|
||||
staticAttributes.GetNamespace(),
|
||||
staticAttributes.GetName(),
|
||||
staticAttributes.GetResource(),
|
||||
staticAttributes.GetSubresource(),
|
||||
staticAttributes.GetOperation(),
|
||||
staticAttributes.GetOperationOptions(),
|
||||
staticAttributes.IsDryRun(),
|
||||
staticAttributes.GetUserInfo(),
|
||||
)
|
||||
if !validatingAdmission.Handles(finalAttributes.GetOperation()) {
|
||||
return nil
|
||||
}
|
||||
return validatingAdmission.Validate(ctx, finalAttributes, o)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user