mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 02:43:36 +00:00
build: move e2e dependencies into e2e/go.mod
Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
15da101b1b
commit
bec6090996
7018
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/endpoints.yaml
generated
vendored
Normal file
7018
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/endpoints.yaml
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
108
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/extract.go
generated
vendored
Normal file
108
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/extract.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
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 managedfields
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// ExtractInto extracts the applied configuration state from object for fieldManager
|
||||
// into applyConfiguration. If no managed fields are found for the given fieldManager,
|
||||
// no error is returned, but applyConfiguration is left unpopulated. It is possible
|
||||
// that no managed fields were found for the fieldManager because other field managers
|
||||
// have taken ownership of all the fields previously owned by the fieldManager. It is
|
||||
// also possible the fieldManager never owned fields.
|
||||
//
|
||||
// The provided object MUST bo a root resource object since subresource objects
|
||||
// do not contain their own managed fields. For example, an autoscaling.Scale
|
||||
// object read from a "scale" subresource does not have any managed fields and so
|
||||
// cannot be used as the object.
|
||||
//
|
||||
// If the fields of a subresource are a subset of the fields of the root object,
|
||||
// and their field paths and types are exactly the same, then ExtractInto can be
|
||||
// called with the root resource as the object and the subresource as the
|
||||
// applyConfiguration. This works for "status", obviously, because status is
|
||||
// represented by the exact same object as the root resource. This does NOT
|
||||
// work, for example, with the "scale" subresources of Deployment, ReplicaSet and
|
||||
// StatefulSet. While the spec.replicas, status.replicas fields are in the same
|
||||
// exact field path locations as they are in autoscaling.Scale, the selector
|
||||
// fields are in different locations, and are a different type.
|
||||
func ExtractInto(object runtime.Object, objectType typed.ParseableType, fieldManager string, applyConfiguration interface{}, subresource string) error {
|
||||
typedObj, err := toTyped(object, objectType)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error converting obj to typed: %w", err)
|
||||
}
|
||||
|
||||
accessor, err := meta.Accessor(object)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error accessing metadata: %w", err)
|
||||
}
|
||||
fieldsEntry, ok := findManagedFields(accessor, fieldManager, subresource)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
fieldset := &fieldpath.Set{}
|
||||
err = fieldset.FromJSON(bytes.NewReader(fieldsEntry.FieldsV1.Raw))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error marshalling FieldsV1 to JSON: %w", err)
|
||||
}
|
||||
|
||||
u := typedObj.ExtractItems(fieldset.Leaves()).AsValue().Unstructured()
|
||||
m, ok := u.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("unable to convert managed fields for %s to unstructured, expected map, got %T", fieldManager, u)
|
||||
}
|
||||
|
||||
// set the type meta manually if it doesn't exist to avoid missing kind errors
|
||||
// when decoding from unstructured JSON
|
||||
if _, ok := m["kind"]; !ok && object.GetObjectKind().GroupVersionKind().Kind != "" {
|
||||
m["kind"] = object.GetObjectKind().GroupVersionKind().Kind
|
||||
m["apiVersion"] = object.GetObjectKind().GroupVersionKind().GroupVersion().String()
|
||||
}
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, applyConfiguration); err != nil {
|
||||
return fmt.Errorf("error extracting into obj from unstructured: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func findManagedFields(accessor metav1.Object, fieldManager string, subresource string) (metav1.ManagedFieldsEntry, bool) {
|
||||
objManagedFields := accessor.GetManagedFields()
|
||||
for _, mf := range objManagedFields {
|
||||
if mf.Manager == fieldManager && mf.Operation == metav1.ManagedFieldsOperationApply && mf.Subresource == subresource {
|
||||
return mf, true
|
||||
}
|
||||
}
|
||||
return metav1.ManagedFieldsEntry{}, false
|
||||
}
|
||||
|
||||
func toTyped(obj runtime.Object, objectType typed.ParseableType) (*typed.TypedValue, error) {
|
||||
switch o := obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return objectType.FromUnstructured(o.Object)
|
||||
default:
|
||||
return objectType.FromStructured(o)
|
||||
}
|
||||
}
|
58
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/fieldmanager.go
generated
vendored
Normal file
58
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/fieldmanager.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
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 managedfields
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/managedfields/internal"
|
||||
)
|
||||
|
||||
// FieldManager updates the managed fields and merges applied
|
||||
// configurations.
|
||||
type FieldManager = internal.FieldManager
|
||||
|
||||
// NewDefaultFieldManager creates a new FieldManager that merges apply requests
|
||||
// and update managed fields for other types of requests.
|
||||
func NewDefaultFieldManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, subresource string, resetFields map[fieldpath.APIVersion]fieldpath.Filter) (*FieldManager, error) {
|
||||
f, err := internal.NewStructuredMergeManager(typeConverter, objectConverter, objectDefaulter, kind.GroupVersion(), hub, resetFields)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create field manager: %v", err)
|
||||
}
|
||||
return internal.NewDefaultFieldManager(f, typeConverter, objectConverter, objectCreater, kind, subresource), nil
|
||||
}
|
||||
|
||||
// NewDefaultCRDFieldManager creates a new FieldManager specifically for
|
||||
// CRDs. This allows for the possibility of fields which are not defined
|
||||
// in models, as well as having no models defined at all.
|
||||
func NewDefaultCRDFieldManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, hub schema.GroupVersion, subresource string, resetFields map[fieldpath.APIVersion]fieldpath.Filter) (_ *FieldManager, err error) {
|
||||
f, err := internal.NewCRDStructuredMergeManager(typeConverter, objectConverter, objectDefaulter, kind.GroupVersion(), hub, resetFields)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create field manager: %v", err)
|
||||
}
|
||||
return internal.NewDefaultFieldManager(f, typeConverter, objectConverter, objectCreater, kind, subresource), nil
|
||||
}
|
||||
|
||||
func ValidateManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) error {
|
||||
_, err := internal.DecodeManagedFields(encodedManagedFields)
|
||||
return err
|
||||
}
|
128
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/gvkparser.go
generated
vendored
Normal file
128
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/gvkparser.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
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 managedfields
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kube-openapi/pkg/schemaconv"
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
smdschema "sigs.k8s.io/structured-merge-diff/v4/schema"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
)
|
||||
|
||||
// groupVersionKindExtensionKey is the key used to lookup the
|
||||
// GroupVersionKind value for an object definition from the
|
||||
// definition's "extensions" map.
|
||||
const groupVersionKindExtensionKey = "x-kubernetes-group-version-kind"
|
||||
|
||||
// GvkParser contains a Parser that allows introspecting the schema.
|
||||
type GvkParser struct {
|
||||
gvks map[schema.GroupVersionKind]string
|
||||
parser typed.Parser
|
||||
}
|
||||
|
||||
// Type returns a helper which can produce objects of the given type. Any
|
||||
// errors are deferred until a further function is called.
|
||||
func (p *GvkParser) Type(gvk schema.GroupVersionKind) *typed.ParseableType {
|
||||
typeName, ok := p.gvks[gvk]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
t := p.parser.Type(typeName)
|
||||
return &t
|
||||
}
|
||||
|
||||
// NewGVKParser builds a GVKParser from a proto.Models. This
|
||||
// will automatically find the proper version of the object, and the
|
||||
// corresponding schema information.
|
||||
func NewGVKParser(models proto.Models, preserveUnknownFields bool) (*GvkParser, error) {
|
||||
typeSchema, err := schemaconv.ToSchemaWithPreserveUnknownFields(models, preserveUnknownFields)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert models to schema: %v", err)
|
||||
}
|
||||
parser := GvkParser{
|
||||
gvks: map[schema.GroupVersionKind]string{},
|
||||
}
|
||||
parser.parser = typed.Parser{Schema: smdschema.Schema{Types: typeSchema.Types}}
|
||||
for _, modelName := range models.ListModels() {
|
||||
model := models.LookupModel(modelName)
|
||||
if model == nil {
|
||||
panic(fmt.Sprintf("ListModels returns a model that can't be looked-up for: %v", modelName))
|
||||
}
|
||||
gvkList := parseGroupVersionKind(model)
|
||||
for _, gvk := range gvkList {
|
||||
if len(gvk.Kind) > 0 {
|
||||
_, ok := parser.gvks[gvk]
|
||||
if ok {
|
||||
return nil, fmt.Errorf("duplicate entry for %v", gvk)
|
||||
}
|
||||
parser.gvks[gvk] = modelName
|
||||
}
|
||||
}
|
||||
}
|
||||
return &parser, nil
|
||||
}
|
||||
|
||||
// Get and parse GroupVersionKind from the extension. Returns empty if it doesn't have one.
|
||||
func parseGroupVersionKind(s proto.Schema) []schema.GroupVersionKind {
|
||||
extensions := s.GetExtensions()
|
||||
|
||||
gvkListResult := []schema.GroupVersionKind{}
|
||||
|
||||
// Get the extensions
|
||||
gvkExtension, ok := extensions[groupVersionKindExtensionKey]
|
||||
if !ok {
|
||||
return []schema.GroupVersionKind{}
|
||||
}
|
||||
|
||||
// gvk extension must be a list of at least 1 element.
|
||||
gvkList, ok := gvkExtension.([]interface{})
|
||||
if !ok {
|
||||
return []schema.GroupVersionKind{}
|
||||
}
|
||||
|
||||
for _, gvk := range gvkList {
|
||||
// gvk extension list must be a map with group, version, and
|
||||
// kind fields
|
||||
gvkMap, ok := gvk.(map[interface{}]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
group, ok := gvkMap["group"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
version, ok := gvkMap["version"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
kind, ok := gvkMap["kind"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
gvkListResult = append(gvkListResult, schema.GroupVersionKind{
|
||||
Group: group,
|
||||
Version: version,
|
||||
Kind: kind,
|
||||
})
|
||||
}
|
||||
|
||||
return gvkListResult
|
||||
}
|
60
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/atmostevery.go
generated
vendored
Normal file
60
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/atmostevery.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AtMostEvery will never run the method more than once every specified
|
||||
// duration.
|
||||
type AtMostEvery struct {
|
||||
delay time.Duration
|
||||
lastCall time.Time
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// NewAtMostEvery creates a new AtMostEvery, that will run the method at
|
||||
// most every given duration.
|
||||
func NewAtMostEvery(delay time.Duration) *AtMostEvery {
|
||||
return &AtMostEvery{
|
||||
delay: delay,
|
||||
}
|
||||
}
|
||||
|
||||
// updateLastCall returns true if the lastCall time has been updated,
|
||||
// false if it was too early.
|
||||
func (s *AtMostEvery) updateLastCall() bool {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
if time.Since(s.lastCall) < s.delay {
|
||||
return false
|
||||
}
|
||||
s.lastCall = time.Now()
|
||||
return true
|
||||
}
|
||||
|
||||
// Do will run the method if enough time has passed, and return true.
|
||||
// Otherwise, it does nothing and returns false.
|
||||
func (s *AtMostEvery) Do(fn func()) bool {
|
||||
if !s.updateLastCall() {
|
||||
return false
|
||||
}
|
||||
fn()
|
||||
return true
|
||||
}
|
74
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/buildmanagerinfo.go
generated
vendored
Normal file
74
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/buildmanagerinfo.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type buildManagerInfoManager struct {
|
||||
fieldManager Manager
|
||||
groupVersion schema.GroupVersion
|
||||
subresource string
|
||||
}
|
||||
|
||||
var _ Manager = &buildManagerInfoManager{}
|
||||
|
||||
// NewBuildManagerInfoManager creates a new Manager that converts the manager name into a unique identifier
|
||||
// combining operation and version for update requests, and just operation for apply requests.
|
||||
func NewBuildManagerInfoManager(f Manager, gv schema.GroupVersion, subresource string) Manager {
|
||||
return &buildManagerInfoManager{
|
||||
fieldManager: f,
|
||||
groupVersion: gv,
|
||||
subresource: subresource,
|
||||
}
|
||||
}
|
||||
|
||||
// Update implements Manager.
|
||||
func (f *buildManagerInfoManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
|
||||
manager, err := f.buildManagerInfo(manager, metav1.ManagedFieldsOperationUpdate)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to build manager identifier: %v", err)
|
||||
}
|
||||
return f.fieldManager.Update(liveObj, newObj, managed, manager)
|
||||
}
|
||||
|
||||
// Apply implements Manager.
|
||||
func (f *buildManagerInfoManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
||||
manager, err := f.buildManagerInfo(manager, metav1.ManagedFieldsOperationApply)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to build manager identifier: %v", err)
|
||||
}
|
||||
return f.fieldManager.Apply(liveObj, appliedObj, managed, manager, force)
|
||||
}
|
||||
|
||||
func (f *buildManagerInfoManager) buildManagerInfo(prefix string, operation metav1.ManagedFieldsOperationType) (string, error) {
|
||||
managerInfo := metav1.ManagedFieldsEntry{
|
||||
Manager: prefix,
|
||||
Operation: operation,
|
||||
APIVersion: f.groupVersion.String(),
|
||||
Subresource: f.subresource,
|
||||
}
|
||||
if managerInfo.Manager == "" {
|
||||
managerInfo.Manager = "unknown"
|
||||
}
|
||||
return BuildManagerIdentifier(&managerInfo)
|
||||
}
|
133
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/capmanagers.go
generated
vendored
Normal file
133
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/capmanagers.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
type capManagersManager struct {
|
||||
fieldManager Manager
|
||||
maxUpdateManagers int
|
||||
oldUpdatesManagerName string
|
||||
}
|
||||
|
||||
var _ Manager = &capManagersManager{}
|
||||
|
||||
// NewCapManagersManager creates a new wrapped FieldManager which ensures that the number of managers from updates
|
||||
// does not exceed maxUpdateManagers, by merging some of the oldest entries on each update.
|
||||
func NewCapManagersManager(fieldManager Manager, maxUpdateManagers int) Manager {
|
||||
return &capManagersManager{
|
||||
fieldManager: fieldManager,
|
||||
maxUpdateManagers: maxUpdateManagers,
|
||||
oldUpdatesManagerName: "ancient-changes",
|
||||
}
|
||||
}
|
||||
|
||||
// Update implements Manager.
|
||||
func (f *capManagersManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
|
||||
object, managed, err := f.fieldManager.Update(liveObj, newObj, managed, manager)
|
||||
if err != nil {
|
||||
return object, managed, err
|
||||
}
|
||||
if managed, err = f.capUpdateManagers(managed); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to cap update managers: %v", err)
|
||||
}
|
||||
return object, managed, nil
|
||||
}
|
||||
|
||||
// Apply implements Manager.
|
||||
func (f *capManagersManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) {
|
||||
return f.fieldManager.Apply(liveObj, appliedObj, managed, fieldManager, force)
|
||||
}
|
||||
|
||||
// capUpdateManagers merges a number of the oldest update entries into versioned buckets,
|
||||
// such that the number of entries from updates does not exceed f.maxUpdateManagers.
|
||||
func (f *capManagersManager) capUpdateManagers(managed Managed) (newManaged Managed, err error) {
|
||||
// Gather all entries from updates
|
||||
updaters := []string{}
|
||||
for manager, fields := range managed.Fields() {
|
||||
if !fields.Applied() {
|
||||
updaters = append(updaters, manager)
|
||||
}
|
||||
}
|
||||
if len(updaters) <= f.maxUpdateManagers {
|
||||
return managed, nil
|
||||
}
|
||||
|
||||
// If we have more than the maximum, sort the update entries by time, oldest first.
|
||||
sort.Slice(updaters, func(i, j int) bool {
|
||||
iTime, jTime, iSeconds, jSeconds := managed.Times()[updaters[i]], managed.Times()[updaters[j]], int64(0), int64(0)
|
||||
if iTime != nil {
|
||||
iSeconds = iTime.Unix()
|
||||
}
|
||||
if jTime != nil {
|
||||
jSeconds = jTime.Unix()
|
||||
}
|
||||
if iSeconds != jSeconds {
|
||||
return iSeconds < jSeconds
|
||||
}
|
||||
return updaters[i] < updaters[j]
|
||||
})
|
||||
|
||||
// Merge the oldest updaters with versioned bucket managers until the number of updaters is under the cap
|
||||
versionToFirstManager := map[string]string{}
|
||||
for i, length := 0, len(updaters); i < len(updaters) && length > f.maxUpdateManagers; i++ {
|
||||
manager := updaters[i]
|
||||
vs := managed.Fields()[manager]
|
||||
time := managed.Times()[manager]
|
||||
version := string(vs.APIVersion())
|
||||
|
||||
// Create a new manager identifier for the versioned bucket entry.
|
||||
// The version for this manager comes from the version of the update being merged into the bucket.
|
||||
bucket, err := BuildManagerIdentifier(&metav1.ManagedFieldsEntry{
|
||||
Manager: f.oldUpdatesManagerName,
|
||||
Operation: metav1.ManagedFieldsOperationUpdate,
|
||||
APIVersion: version,
|
||||
})
|
||||
if err != nil {
|
||||
return managed, fmt.Errorf("failed to create bucket manager for version %v: %v", version, err)
|
||||
}
|
||||
|
||||
// Merge the fieldets if this is not the first time the version was seen.
|
||||
// Otherwise just record the manager name in versionToFirstManager
|
||||
if first, ok := versionToFirstManager[version]; ok {
|
||||
// If the bucket doesn't exists yet, create one.
|
||||
if _, ok := managed.Fields()[bucket]; !ok {
|
||||
s := managed.Fields()[first]
|
||||
delete(managed.Fields(), first)
|
||||
managed.Fields()[bucket] = s
|
||||
}
|
||||
|
||||
managed.Fields()[bucket] = fieldpath.NewVersionedSet(vs.Set().Union(managed.Fields()[bucket].Set()), vs.APIVersion(), vs.Applied())
|
||||
delete(managed.Fields(), manager)
|
||||
length--
|
||||
|
||||
// Use the time from the update being merged into the bucket, since it is more recent.
|
||||
managed.Times()[bucket] = time
|
||||
} else {
|
||||
versionToFirstManager[version] = manager
|
||||
}
|
||||
}
|
||||
|
||||
return managed, nil
|
||||
}
|
89
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/conflict.go
generated
vendored
Normal file
89
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/conflict.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/merge"
|
||||
)
|
||||
|
||||
// NewConflictError returns an error including details on the requests apply conflicts
|
||||
func NewConflictError(conflicts merge.Conflicts) *errors.StatusError {
|
||||
causes := []metav1.StatusCause{}
|
||||
for _, conflict := range conflicts {
|
||||
causes = append(causes, metav1.StatusCause{
|
||||
Type: metav1.CauseTypeFieldManagerConflict,
|
||||
Message: fmt.Sprintf("conflict with %v", printManager(conflict.Manager)),
|
||||
Field: conflict.Path.String(),
|
||||
})
|
||||
}
|
||||
return errors.NewApplyConflict(causes, getConflictMessage(conflicts))
|
||||
}
|
||||
|
||||
func getConflictMessage(conflicts merge.Conflicts) string {
|
||||
if len(conflicts) == 1 {
|
||||
return fmt.Sprintf("Apply failed with 1 conflict: conflict with %v: %v", printManager(conflicts[0].Manager), conflicts[0].Path)
|
||||
}
|
||||
|
||||
m := map[string][]fieldpath.Path{}
|
||||
for _, conflict := range conflicts {
|
||||
m[conflict.Manager] = append(m[conflict.Manager], conflict.Path)
|
||||
}
|
||||
|
||||
uniqueManagers := []string{}
|
||||
for manager := range m {
|
||||
uniqueManagers = append(uniqueManagers, manager)
|
||||
}
|
||||
|
||||
// Print conflicts by sorted managers.
|
||||
sort.Strings(uniqueManagers)
|
||||
|
||||
messages := []string{}
|
||||
for _, manager := range uniqueManagers {
|
||||
messages = append(messages, fmt.Sprintf("conflicts with %v:", printManager(manager)))
|
||||
for _, path := range m[manager] {
|
||||
messages = append(messages, fmt.Sprintf("- %v", path))
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("Apply failed with %d conflicts: %s", len(conflicts), strings.Join(messages, "\n"))
|
||||
}
|
||||
|
||||
func printManager(manager string) string {
|
||||
encodedManager := &metav1.ManagedFieldsEntry{}
|
||||
if err := json.Unmarshal([]byte(manager), encodedManager); err != nil {
|
||||
return fmt.Sprintf("%q", manager)
|
||||
}
|
||||
managerStr := fmt.Sprintf("%q", encodedManager.Manager)
|
||||
if encodedManager.Subresource != "" {
|
||||
managerStr = fmt.Sprintf("%s with subresource %q", managerStr, encodedManager.Subresource)
|
||||
}
|
||||
if encodedManager.Operation == metav1.ManagedFieldsOperationUpdate {
|
||||
if encodedManager.Time == nil {
|
||||
return fmt.Sprintf("%s using %v", managerStr, encodedManager.APIVersion)
|
||||
}
|
||||
return fmt.Sprintf("%s using %v at %v", managerStr, encodedManager.APIVersion, encodedManager.Time.UTC().Format(time.RFC3339))
|
||||
}
|
||||
return managerStr
|
||||
}
|
209
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/fieldmanager.go
generated
vendored
Normal file
209
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/fieldmanager.go
generated
vendored
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
Copyright 2022 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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"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"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/merge"
|
||||
)
|
||||
|
||||
// DefaultMaxUpdateManagers defines the default maximum retained number of managedFields entries from updates
|
||||
// if the number of update managers exceeds this, the oldest entries will be merged until the number is below the maximum.
|
||||
// TODO(jennybuckley): Determine if this is really the best value. Ideally we wouldn't unnecessarily merge too many entries.
|
||||
const DefaultMaxUpdateManagers int = 10
|
||||
|
||||
// DefaultTrackOnCreateProbability defines the default probability that the field management of an object
|
||||
// starts being tracked from the object's creation, instead of from the first time the object is applied to.
|
||||
const DefaultTrackOnCreateProbability float32 = 1
|
||||
|
||||
var atMostEverySecond = NewAtMostEvery(time.Second)
|
||||
|
||||
// FieldManager updates the managed fields and merges applied
|
||||
// configurations.
|
||||
type FieldManager struct {
|
||||
fieldManager Manager
|
||||
subresource string
|
||||
}
|
||||
|
||||
// NewFieldManager creates a new FieldManager that decodes, manages, then re-encodes managedFields
|
||||
// on update and apply requests.
|
||||
func NewFieldManager(f Manager, subresource string) *FieldManager {
|
||||
return &FieldManager{fieldManager: f, subresource: subresource}
|
||||
}
|
||||
|
||||
// newDefaultFieldManager is a helper function which wraps a Manager with certain default logic.
|
||||
func NewDefaultFieldManager(f Manager, typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectCreater runtime.ObjectCreater, kind schema.GroupVersionKind, subresource string) *FieldManager {
|
||||
return NewFieldManager(
|
||||
NewVersionCheckManager(
|
||||
NewLastAppliedUpdater(
|
||||
NewLastAppliedManager(
|
||||
NewProbabilisticSkipNonAppliedManager(
|
||||
NewCapManagersManager(
|
||||
NewBuildManagerInfoManager(
|
||||
NewManagedFieldsUpdater(
|
||||
NewStripMetaManager(f),
|
||||
), kind.GroupVersion(), subresource,
|
||||
), DefaultMaxUpdateManagers,
|
||||
), objectCreater, DefaultTrackOnCreateProbability,
|
||||
), typeConverter, objectConverter, kind.GroupVersion(),
|
||||
),
|
||||
), kind,
|
||||
), subresource,
|
||||
)
|
||||
}
|
||||
|
||||
func decodeLiveOrNew(liveObj, newObj runtime.Object, ignoreManagedFieldsFromRequestObject bool) (Managed, error) {
|
||||
liveAccessor, err := meta.Accessor(liveObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We take the managedFields of the live object in case the request tries to
|
||||
// manually set managedFields via a subresource.
|
||||
if ignoreManagedFieldsFromRequestObject {
|
||||
return emptyManagedFieldsOnErr(DecodeManagedFields(liveAccessor.GetManagedFields()))
|
||||
}
|
||||
|
||||
// If the object doesn't have metadata, we should just return without trying to
|
||||
// set the managedFields at all, so creates/updates/patches will work normally.
|
||||
newAccessor, err := meta.Accessor(newObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if isResetManagedFields(newAccessor.GetManagedFields()) {
|
||||
return NewEmptyManaged(), nil
|
||||
}
|
||||
|
||||
// If the managed field is empty or we failed to decode it,
|
||||
// let's try the live object. This is to prevent clients who
|
||||
// don't understand managedFields from deleting it accidentally.
|
||||
managed, err := DecodeManagedFields(newAccessor.GetManagedFields())
|
||||
if err != nil || len(managed.Fields()) == 0 {
|
||||
return emptyManagedFieldsOnErr(DecodeManagedFields(liveAccessor.GetManagedFields()))
|
||||
}
|
||||
return managed, nil
|
||||
}
|
||||
|
||||
func emptyManagedFieldsOnErr(managed Managed, err error) (Managed, error) {
|
||||
if err != nil {
|
||||
return NewEmptyManaged(), nil
|
||||
}
|
||||
return managed, nil
|
||||
}
|
||||
|
||||
// Update is used when the object has already been merged (non-apply
|
||||
// use-case), and simply updates the managed fields in the output
|
||||
// object.
|
||||
func (f *FieldManager) Update(liveObj, newObj runtime.Object, manager string) (object runtime.Object, err error) {
|
||||
// First try to decode the managed fields provided in the update,
|
||||
// This is necessary to allow directly updating managed fields.
|
||||
isSubresource := f.subresource != ""
|
||||
managed, err := decodeLiveOrNew(liveObj, newObj, isSubresource)
|
||||
if err != nil {
|
||||
return newObj, nil
|
||||
}
|
||||
|
||||
RemoveObjectManagedFields(newObj)
|
||||
|
||||
if object, managed, err = f.fieldManager.Update(liveObj, newObj, managed, manager); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = EncodeObjectManagedFields(object, managed); err != nil {
|
||||
return nil, fmt.Errorf("failed to encode managed fields: %v", err)
|
||||
}
|
||||
|
||||
return object, nil
|
||||
}
|
||||
|
||||
// UpdateNoErrors is the same as Update, but it will not return
|
||||
// errors. If an error happens, the object is returned with
|
||||
// managedFields cleared.
|
||||
func (f *FieldManager) UpdateNoErrors(liveObj, newObj runtime.Object, manager string) runtime.Object {
|
||||
obj, err := f.Update(liveObj, newObj, manager)
|
||||
if err != nil {
|
||||
atMostEverySecond.Do(func() {
|
||||
ns, name := "unknown", "unknown"
|
||||
if accessor, err := meta.Accessor(newObj); err == nil {
|
||||
ns = accessor.GetNamespace()
|
||||
name = accessor.GetName()
|
||||
}
|
||||
|
||||
klog.ErrorS(err, "[SHOULD NOT HAPPEN] failed to update managedFields", "versionKind",
|
||||
newObj.GetObjectKind().GroupVersionKind(), "namespace", ns, "name", name)
|
||||
})
|
||||
// Explicitly remove managedFields on failure, so that
|
||||
// we can't have garbage in it.
|
||||
RemoveObjectManagedFields(newObj)
|
||||
return newObj
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// Returns true if the managedFields indicate that the user is trying to
|
||||
// reset the managedFields, i.e. if the list is non-nil but empty, or if
|
||||
// the list has one empty item.
|
||||
func isResetManagedFields(managedFields []metav1.ManagedFieldsEntry) bool {
|
||||
if len(managedFields) == 0 {
|
||||
return managedFields != nil
|
||||
}
|
||||
|
||||
if len(managedFields) == 1 {
|
||||
return reflect.DeepEqual(managedFields[0], metav1.ManagedFieldsEntry{})
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Apply is used when server-side apply is called, as it merges the
|
||||
// object and updates the managed fields.
|
||||
func (f *FieldManager) Apply(liveObj, appliedObj runtime.Object, manager string, force bool) (object runtime.Object, err error) {
|
||||
// If the object doesn't have metadata, apply isn't allowed.
|
||||
accessor, err := meta.Accessor(liveObj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get accessor: %v", err)
|
||||
}
|
||||
|
||||
// Decode the managed fields in the live object, since it isn't allowed in the patch.
|
||||
managed, err := DecodeManagedFields(accessor.GetManagedFields())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode managed fields: %v", err)
|
||||
}
|
||||
|
||||
object, managed, err = f.fieldManager.Apply(liveObj, appliedObj, managed, manager, force)
|
||||
if err != nil {
|
||||
if conflicts, ok := err.(merge.Conflicts); ok {
|
||||
return nil, NewConflictError(conflicts)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = EncodeObjectManagedFields(object, managed); err != nil {
|
||||
return nil, fmt.Errorf("failed to encode managed fields: %v", err)
|
||||
}
|
||||
|
||||
return object, nil
|
||||
}
|
47
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/fields.go
generated
vendored
Normal file
47
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/fields.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// EmptyFields represents a set with no paths
|
||||
// It looks like metav1.Fields{Raw: []byte("{}")}
|
||||
var EmptyFields = func() metav1.FieldsV1 {
|
||||
f, err := SetToFields(*fieldpath.NewSet())
|
||||
if err != nil {
|
||||
panic("should never happen")
|
||||
}
|
||||
return f
|
||||
}()
|
||||
|
||||
// FieldsToSet creates a set paths from an input trie of fields
|
||||
func FieldsToSet(f metav1.FieldsV1) (s fieldpath.Set, err error) {
|
||||
err = s.FromJSON(bytes.NewReader(f.Raw))
|
||||
return s, err
|
||||
}
|
||||
|
||||
// SetToFields creates a trie of fields from an input set of paths
|
||||
func SetToFields(s fieldpath.Set) (f metav1.FieldsV1, err error) {
|
||||
f.Raw, err = s.ToJSON()
|
||||
return f, err
|
||||
}
|
50
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/lastapplied.go
generated
vendored
Normal file
50
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/lastapplied.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
Copyright 2022 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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// LastAppliedConfigAnnotation is the annotation used to store the previous
|
||||
// configuration of a resource for use in a three way diff by UpdateApplyAnnotation.
|
||||
//
|
||||
// This is a copy of the corev1 annotation since we don't want to depend on the whole package.
|
||||
const LastAppliedConfigAnnotation = "kubectl.kubernetes.io/last-applied-configuration"
|
||||
|
||||
// SetLastApplied sets the last-applied annotation the given value in
|
||||
// the object.
|
||||
func SetLastApplied(obj runtime.Object, value string) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("couldn't get accessor: %v", err))
|
||||
}
|
||||
var annotations = accessor.GetAnnotations()
|
||||
if annotations == nil {
|
||||
annotations = map[string]string{}
|
||||
}
|
||||
annotations[LastAppliedConfigAnnotation] = value
|
||||
if err := apimachineryvalidation.ValidateAnnotationsSize(annotations); err != nil {
|
||||
delete(annotations, LastAppliedConfigAnnotation)
|
||||
}
|
||||
accessor.SetAnnotations(annotations)
|
||||
return nil
|
||||
}
|
171
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/lastappliedmanager.go
generated
vendored
Normal file
171
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/lastappliedmanager.go
generated
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"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/structured-merge-diff/v4/fieldpath"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/merge"
|
||||
)
|
||||
|
||||
type lastAppliedManager struct {
|
||||
fieldManager Manager
|
||||
typeConverter TypeConverter
|
||||
objectConverter runtime.ObjectConvertor
|
||||
groupVersion schema.GroupVersion
|
||||
}
|
||||
|
||||
var _ Manager = &lastAppliedManager{}
|
||||
|
||||
// NewLastAppliedManager converts the client-side apply annotation to
|
||||
// server-side apply managed fields
|
||||
func NewLastAppliedManager(fieldManager Manager, typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, groupVersion schema.GroupVersion) Manager {
|
||||
return &lastAppliedManager{
|
||||
fieldManager: fieldManager,
|
||||
typeConverter: typeConverter,
|
||||
objectConverter: objectConverter,
|
||||
groupVersion: groupVersion,
|
||||
}
|
||||
}
|
||||
|
||||
// Update implements Manager.
|
||||
func (f *lastAppliedManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
|
||||
return f.fieldManager.Update(liveObj, newObj, managed, manager)
|
||||
}
|
||||
|
||||
// Apply will consider the last-applied annotation
|
||||
// for upgrading an object managed by client-side apply to server-side apply
|
||||
// without conflicts.
|
||||
func (f *lastAppliedManager) Apply(liveObj, newObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
||||
newLiveObj, newManaged, newErr := f.fieldManager.Apply(liveObj, newObj, managed, manager, force)
|
||||
// Upgrade the client-side apply annotation only from kubectl server-side-apply.
|
||||
// To opt-out of this behavior, users may specify a different field manager.
|
||||
if manager != "kubectl" {
|
||||
return newLiveObj, newManaged, newErr
|
||||
}
|
||||
|
||||
// Check if we have conflicts
|
||||
if newErr == nil {
|
||||
return newLiveObj, newManaged, newErr
|
||||
}
|
||||
conflicts, ok := newErr.(merge.Conflicts)
|
||||
if !ok {
|
||||
return newLiveObj, newManaged, newErr
|
||||
}
|
||||
conflictSet := conflictsToSet(conflicts)
|
||||
|
||||
// Check if conflicts are allowed due to client-side apply,
|
||||
// and if so, then force apply
|
||||
allowedConflictSet, err := f.allowedConflictsFromLastApplied(liveObj)
|
||||
if err != nil {
|
||||
return newLiveObj, newManaged, newErr
|
||||
}
|
||||
if !conflictSet.Difference(allowedConflictSet).Empty() {
|
||||
newConflicts := conflictsDifference(conflicts, allowedConflictSet)
|
||||
return newLiveObj, newManaged, newConflicts
|
||||
}
|
||||
|
||||
return f.fieldManager.Apply(liveObj, newObj, managed, manager, true)
|
||||
}
|
||||
|
||||
func (f *lastAppliedManager) allowedConflictsFromLastApplied(liveObj runtime.Object) (*fieldpath.Set, error) {
|
||||
var accessor, err = meta.Accessor(liveObj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("couldn't get accessor: %v", err))
|
||||
}
|
||||
|
||||
// If there is no client-side apply annotation, then there is nothing to do
|
||||
var annotations = accessor.GetAnnotations()
|
||||
if annotations == nil {
|
||||
return nil, fmt.Errorf("no last applied annotation")
|
||||
}
|
||||
var lastApplied, ok = annotations[LastAppliedConfigAnnotation]
|
||||
if !ok || lastApplied == "" {
|
||||
return nil, fmt.Errorf("no last applied annotation")
|
||||
}
|
||||
|
||||
liveObjVersioned, err := f.objectConverter.ConvertToVersion(liveObj, f.groupVersion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert live obj to versioned: %v", err)
|
||||
}
|
||||
|
||||
liveObjTyped, err := f.typeConverter.ObjectToTyped(liveObjVersioned)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert live obj to typed: %v", err)
|
||||
}
|
||||
|
||||
var lastAppliedObj = &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||
err = json.Unmarshal([]byte(lastApplied), lastAppliedObj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode last applied obj: %v in '%s'", err, lastApplied)
|
||||
}
|
||||
|
||||
if lastAppliedObj.GetAPIVersion() != f.groupVersion.String() {
|
||||
return nil, fmt.Errorf("expected version of last applied to match live object '%s', but got '%s': %v", f.groupVersion.String(), lastAppliedObj.GetAPIVersion(), err)
|
||||
}
|
||||
|
||||
lastAppliedObjTyped, err := f.typeConverter.ObjectToTyped(lastAppliedObj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert last applied to typed: %v", err)
|
||||
}
|
||||
|
||||
lastAppliedObjFieldSet, err := lastAppliedObjTyped.ToFieldSet()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create fieldset for last applied object: %v", err)
|
||||
}
|
||||
|
||||
comparison, err := lastAppliedObjTyped.Compare(liveObjTyped)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compare last applied object and live object: %v", err)
|
||||
}
|
||||
|
||||
// Remove fields in last applied that are different, added, or missing in
|
||||
// the live object.
|
||||
// Because last-applied fields don't match the live object fields,
|
||||
// then we don't own these fields.
|
||||
lastAppliedObjFieldSet = lastAppliedObjFieldSet.
|
||||
Difference(comparison.Modified).
|
||||
Difference(comparison.Added).
|
||||
Difference(comparison.Removed)
|
||||
|
||||
return lastAppliedObjFieldSet, nil
|
||||
}
|
||||
|
||||
// TODO: replace with merge.Conflicts.ToSet()
|
||||
func conflictsToSet(conflicts merge.Conflicts) *fieldpath.Set {
|
||||
conflictSet := fieldpath.NewSet()
|
||||
for _, conflict := range []merge.Conflict(conflicts) {
|
||||
conflictSet.Insert(conflict.Path)
|
||||
}
|
||||
return conflictSet
|
||||
}
|
||||
|
||||
func conflictsDifference(conflicts merge.Conflicts, s *fieldpath.Set) merge.Conflicts {
|
||||
newConflicts := []merge.Conflict{}
|
||||
for _, conflict := range []merge.Conflict(conflicts) {
|
||||
if !s.Has(conflict.Path) {
|
||||
newConflicts = append(newConflicts, conflict)
|
||||
}
|
||||
}
|
||||
return newConflicts
|
||||
}
|
102
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/lastappliedupdater.go
generated
vendored
Normal file
102
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/lastappliedupdater.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
type lastAppliedUpdater struct {
|
||||
fieldManager Manager
|
||||
}
|
||||
|
||||
var _ Manager = &lastAppliedUpdater{}
|
||||
|
||||
// NewLastAppliedUpdater sets the client-side apply annotation up to date with
|
||||
// server-side apply managed fields
|
||||
func NewLastAppliedUpdater(fieldManager Manager) Manager {
|
||||
return &lastAppliedUpdater{
|
||||
fieldManager: fieldManager,
|
||||
}
|
||||
}
|
||||
|
||||
// Update implements Manager.
|
||||
func (f *lastAppliedUpdater) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
|
||||
return f.fieldManager.Update(liveObj, newObj, managed, manager)
|
||||
}
|
||||
|
||||
// server-side apply managed fields
|
||||
func (f *lastAppliedUpdater) Apply(liveObj, newObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
||||
liveObj, managed, err := f.fieldManager.Apply(liveObj, newObj, managed, manager, force)
|
||||
if err != nil {
|
||||
return liveObj, managed, err
|
||||
}
|
||||
|
||||
// Sync the client-side apply annotation only from kubectl server-side apply.
|
||||
// To opt-out of this behavior, users may specify a different field manager.
|
||||
//
|
||||
// If the client-side apply annotation doesn't exist,
|
||||
// then continue because we have no annotation to update
|
||||
if manager == "kubectl" && hasLastApplied(liveObj) {
|
||||
lastAppliedValue, err := buildLastApplied(newObj)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to build last-applied annotation: %v", err)
|
||||
}
|
||||
err = SetLastApplied(liveObj, lastAppliedValue)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to set last-applied annotation: %v", err)
|
||||
}
|
||||
}
|
||||
return liveObj, managed, err
|
||||
}
|
||||
|
||||
func hasLastApplied(obj runtime.Object) bool {
|
||||
var accessor, err = meta.Accessor(obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("couldn't get accessor: %v", err))
|
||||
}
|
||||
var annotations = accessor.GetAnnotations()
|
||||
if annotations == nil {
|
||||
return false
|
||||
}
|
||||
lastApplied, ok := annotations[LastAppliedConfigAnnotation]
|
||||
return ok && len(lastApplied) > 0
|
||||
}
|
||||
|
||||
func buildLastApplied(obj runtime.Object) (string, error) {
|
||||
obj = obj.DeepCopyObject()
|
||||
|
||||
var accessor, err = meta.Accessor(obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("couldn't get accessor: %v", err))
|
||||
}
|
||||
|
||||
// Remove the annotation from the object before encoding the object
|
||||
var annotations = accessor.GetAnnotations()
|
||||
delete(annotations, LastAppliedConfigAnnotation)
|
||||
accessor.SetAnnotations(annotations)
|
||||
|
||||
lastApplied, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("couldn't encode object into last applied annotation: %v", err)
|
||||
}
|
||||
return string(lastApplied), nil
|
||||
}
|
248
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/managedfields.go
generated
vendored
Normal file
248
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/managedfields.go
generated
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// ManagedInterface groups a fieldpath.ManagedFields together with the timestamps associated with each operation.
|
||||
type ManagedInterface interface {
|
||||
// Fields gets the fieldpath.ManagedFields.
|
||||
Fields() fieldpath.ManagedFields
|
||||
|
||||
// Times gets the timestamps associated with each operation.
|
||||
Times() map[string]*metav1.Time
|
||||
}
|
||||
|
||||
type managedStruct struct {
|
||||
fields fieldpath.ManagedFields
|
||||
times map[string]*metav1.Time
|
||||
}
|
||||
|
||||
var _ ManagedInterface = &managedStruct{}
|
||||
|
||||
// Fields implements ManagedInterface.
|
||||
func (m *managedStruct) Fields() fieldpath.ManagedFields {
|
||||
return m.fields
|
||||
}
|
||||
|
||||
// Times implements ManagedInterface.
|
||||
func (m *managedStruct) Times() map[string]*metav1.Time {
|
||||
return m.times
|
||||
}
|
||||
|
||||
// NewEmptyManaged creates an empty ManagedInterface.
|
||||
func NewEmptyManaged() ManagedInterface {
|
||||
return NewManaged(fieldpath.ManagedFields{}, map[string]*metav1.Time{})
|
||||
}
|
||||
|
||||
// NewManaged creates a ManagedInterface from a fieldpath.ManagedFields and the timestamps associated with each operation.
|
||||
func NewManaged(f fieldpath.ManagedFields, t map[string]*metav1.Time) ManagedInterface {
|
||||
return &managedStruct{
|
||||
fields: f,
|
||||
times: t,
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveObjectManagedFields removes the ManagedFields from the object
|
||||
// before we merge so that it doesn't appear in the ManagedFields
|
||||
// recursively.
|
||||
func RemoveObjectManagedFields(obj runtime.Object) {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("couldn't get accessor: %v", err))
|
||||
}
|
||||
accessor.SetManagedFields(nil)
|
||||
}
|
||||
|
||||
// EncodeObjectManagedFields converts and stores the fieldpathManagedFields into the objects ManagedFields
|
||||
func EncodeObjectManagedFields(obj runtime.Object, managed ManagedInterface) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("couldn't get accessor: %v", err))
|
||||
}
|
||||
|
||||
encodedManagedFields, err := encodeManagedFields(managed)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert back managed fields to API: %v", err)
|
||||
}
|
||||
accessor.SetManagedFields(encodedManagedFields)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeManagedFields converts ManagedFields from the wire format (api format)
|
||||
// to the format used by sigs.k8s.io/structured-merge-diff
|
||||
func DecodeManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (ManagedInterface, error) {
|
||||
managed := managedStruct{}
|
||||
managed.fields = make(fieldpath.ManagedFields, len(encodedManagedFields))
|
||||
managed.times = make(map[string]*metav1.Time, len(encodedManagedFields))
|
||||
|
||||
for i, encodedVersionedSet := range encodedManagedFields {
|
||||
switch encodedVersionedSet.Operation {
|
||||
case metav1.ManagedFieldsOperationApply, metav1.ManagedFieldsOperationUpdate:
|
||||
default:
|
||||
return nil, fmt.Errorf("operation must be `Apply` or `Update`")
|
||||
}
|
||||
if len(encodedVersionedSet.APIVersion) < 1 {
|
||||
return nil, fmt.Errorf("apiVersion must not be empty")
|
||||
}
|
||||
switch encodedVersionedSet.FieldsType {
|
||||
case "FieldsV1":
|
||||
// Valid case.
|
||||
case "":
|
||||
return nil, fmt.Errorf("missing fieldsType in managed fields entry %d", i)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid fieldsType %q in managed fields entry %d", encodedVersionedSet.FieldsType, i)
|
||||
}
|
||||
manager, err := BuildManagerIdentifier(&encodedVersionedSet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding manager from %v: %v", encodedVersionedSet, err)
|
||||
}
|
||||
managed.fields[manager], err = decodeVersionedSet(&encodedVersionedSet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding versioned set from %v: %v", encodedVersionedSet, err)
|
||||
}
|
||||
managed.times[manager] = encodedVersionedSet.Time
|
||||
}
|
||||
return &managed, nil
|
||||
}
|
||||
|
||||
// BuildManagerIdentifier creates a manager identifier string from a ManagedFieldsEntry
|
||||
func BuildManagerIdentifier(encodedManager *metav1.ManagedFieldsEntry) (manager string, err error) {
|
||||
encodedManagerCopy := *encodedManager
|
||||
|
||||
// Never include fields type in the manager identifier
|
||||
encodedManagerCopy.FieldsType = ""
|
||||
|
||||
// Never include the fields in the manager identifier
|
||||
encodedManagerCopy.FieldsV1 = nil
|
||||
|
||||
// Never include the time in the manager identifier
|
||||
encodedManagerCopy.Time = nil
|
||||
|
||||
// For appliers, don't include the APIVersion in the manager identifier,
|
||||
// so it will always have the same manager identifier each time it applied.
|
||||
if encodedManager.Operation == metav1.ManagedFieldsOperationApply {
|
||||
encodedManagerCopy.APIVersion = ""
|
||||
}
|
||||
|
||||
// Use the remaining fields to build the manager identifier
|
||||
b, err := json.Marshal(&encodedManagerCopy)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error marshalling manager identifier: %v", err)
|
||||
}
|
||||
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
func decodeVersionedSet(encodedVersionedSet *metav1.ManagedFieldsEntry) (versionedSet fieldpath.VersionedSet, err error) {
|
||||
fields := EmptyFields
|
||||
if encodedVersionedSet.FieldsV1 != nil {
|
||||
fields = *encodedVersionedSet.FieldsV1
|
||||
}
|
||||
set, err := FieldsToSet(fields)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding set: %v", err)
|
||||
}
|
||||
return fieldpath.NewVersionedSet(&set, fieldpath.APIVersion(encodedVersionedSet.APIVersion), encodedVersionedSet.Operation == metav1.ManagedFieldsOperationApply), nil
|
||||
}
|
||||
|
||||
// encodeManagedFields converts ManagedFields from the format used by
|
||||
// sigs.k8s.io/structured-merge-diff to the wire format (api format)
|
||||
func encodeManagedFields(managed ManagedInterface) (encodedManagedFields []metav1.ManagedFieldsEntry, err error) {
|
||||
if len(managed.Fields()) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
encodedManagedFields = []metav1.ManagedFieldsEntry{}
|
||||
for manager := range managed.Fields() {
|
||||
versionedSet := managed.Fields()[manager]
|
||||
v, err := encodeManagerVersionedSet(manager, versionedSet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error encoding versioned set for %v: %v", manager, err)
|
||||
}
|
||||
if t, ok := managed.Times()[manager]; ok {
|
||||
v.Time = t
|
||||
}
|
||||
encodedManagedFields = append(encodedManagedFields, *v)
|
||||
}
|
||||
return sortEncodedManagedFields(encodedManagedFields)
|
||||
}
|
||||
|
||||
func sortEncodedManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (sortedManagedFields []metav1.ManagedFieldsEntry, err error) {
|
||||
sort.Slice(encodedManagedFields, func(i, j int) bool {
|
||||
p, q := encodedManagedFields[i], encodedManagedFields[j]
|
||||
|
||||
if p.Operation != q.Operation {
|
||||
return p.Operation < q.Operation
|
||||
}
|
||||
|
||||
pSeconds, qSeconds := int64(0), int64(0)
|
||||
if p.Time != nil {
|
||||
pSeconds = p.Time.Unix()
|
||||
}
|
||||
if q.Time != nil {
|
||||
qSeconds = q.Time.Unix()
|
||||
}
|
||||
if pSeconds != qSeconds {
|
||||
return pSeconds < qSeconds
|
||||
}
|
||||
|
||||
if p.Manager != q.Manager {
|
||||
return p.Manager < q.Manager
|
||||
}
|
||||
|
||||
if p.APIVersion != q.APIVersion {
|
||||
return p.APIVersion < q.APIVersion
|
||||
}
|
||||
return p.Subresource < q.Subresource
|
||||
})
|
||||
|
||||
return encodedManagedFields, nil
|
||||
}
|
||||
|
||||
func encodeManagerVersionedSet(manager string, versionedSet fieldpath.VersionedSet) (encodedVersionedSet *metav1.ManagedFieldsEntry, err error) {
|
||||
encodedVersionedSet = &metav1.ManagedFieldsEntry{}
|
||||
|
||||
// Get as many fields as we can from the manager identifier
|
||||
err = json.Unmarshal([]byte(manager), encodedVersionedSet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error unmarshalling manager identifier %v: %v", manager, err)
|
||||
}
|
||||
|
||||
// Get the APIVersion, Operation, and Fields from the VersionedSet
|
||||
encodedVersionedSet.APIVersion = string(versionedSet.APIVersion())
|
||||
if versionedSet.Applied() {
|
||||
encodedVersionedSet.Operation = metav1.ManagedFieldsOperationApply
|
||||
}
|
||||
encodedVersionedSet.FieldsType = "FieldsV1"
|
||||
fields, err := SetToFields(*versionedSet.Set())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error encoding set: %v", err)
|
||||
}
|
||||
encodedVersionedSet.FieldsV1 = &fields
|
||||
|
||||
return encodedVersionedSet, nil
|
||||
}
|
82
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/managedfieldsupdater.go
generated
vendored
Normal file
82
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/managedfieldsupdater.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
type managedFieldsUpdater struct {
|
||||
fieldManager Manager
|
||||
}
|
||||
|
||||
var _ Manager = &managedFieldsUpdater{}
|
||||
|
||||
// NewManagedFieldsUpdater is responsible for updating the managedfields
|
||||
// in the object, updating the time of the operation as necessary. For
|
||||
// updates, it uses a hard-coded manager to detect if things have
|
||||
// changed, and swaps back the correct manager after the operation is
|
||||
// done.
|
||||
func NewManagedFieldsUpdater(fieldManager Manager) Manager {
|
||||
return &managedFieldsUpdater{
|
||||
fieldManager: fieldManager,
|
||||
}
|
||||
}
|
||||
|
||||
// Update implements Manager.
|
||||
func (f *managedFieldsUpdater) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
|
||||
self := "current-operation"
|
||||
object, managed, err := f.fieldManager.Update(liveObj, newObj, managed, self)
|
||||
if err != nil {
|
||||
return object, managed, err
|
||||
}
|
||||
|
||||
// If the current operation took any fields from anything, it means the object changed,
|
||||
// so update the timestamp of the managedFieldsEntry and merge with any previous updates from the same manager
|
||||
if vs, ok := managed.Fields()[self]; ok {
|
||||
delete(managed.Fields(), self)
|
||||
|
||||
if previous, ok := managed.Fields()[manager]; ok {
|
||||
managed.Fields()[manager] = fieldpath.NewVersionedSet(vs.Set().Union(previous.Set()), vs.APIVersion(), vs.Applied())
|
||||
} else {
|
||||
managed.Fields()[manager] = vs
|
||||
}
|
||||
|
||||
managed.Times()[manager] = &metav1.Time{Time: time.Now().UTC()}
|
||||
}
|
||||
|
||||
return object, managed, nil
|
||||
}
|
||||
|
||||
// Apply implements Manager.
|
||||
func (f *managedFieldsUpdater) Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) {
|
||||
object, managed, err := f.fieldManager.Apply(liveObj, appliedObj, managed, fieldManager, force)
|
||||
if err != nil {
|
||||
return object, managed, err
|
||||
}
|
||||
if object != nil {
|
||||
managed.Times()[fieldManager] = &metav1.Time{Time: time.Now().UTC()}
|
||||
} else {
|
||||
object = liveObj.DeepCopyObject()
|
||||
RemoveObjectManagedFields(object)
|
||||
}
|
||||
return object, managed, nil
|
||||
}
|
52
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/manager.go
generated
vendored
Normal file
52
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/manager.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2022 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 internal
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// Managed groups a fieldpath.ManagedFields together with the timestamps associated with each operation.
|
||||
type Managed interface {
|
||||
// Fields gets the fieldpath.ManagedFields.
|
||||
Fields() fieldpath.ManagedFields
|
||||
|
||||
// Times gets the timestamps associated with each operation.
|
||||
Times() map[string]*metav1.Time
|
||||
}
|
||||
|
||||
// Manager updates the managed fields and merges applied configurations.
|
||||
type Manager interface {
|
||||
// Update is used when the object has already been merged (non-apply
|
||||
// use-case), and simply updates the managed fields in the output
|
||||
// object.
|
||||
// * `liveObj` is not mutated by this function
|
||||
// * `newObj` may be mutated by this function
|
||||
// Returns the new object with managedFields removed, and the object's new
|
||||
// proposed managedFields separately.
|
||||
Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error)
|
||||
|
||||
// Apply is used when server-side apply is called, as it merges the
|
||||
// object and updates the managed fields.
|
||||
// * `liveObj` is not mutated by this function
|
||||
// * `newObj` may be mutated by this function
|
||||
// Returns the new object with managedFields removed, and the object's new
|
||||
// proposed managedFields separately.
|
||||
Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error)
|
||||
}
|
140
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/pathelement.go
generated
vendored
Normal file
140
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/pathelement.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/value"
|
||||
)
|
||||
|
||||
const (
|
||||
// Field indicates that the content of this path element is a field's name
|
||||
Field = "f"
|
||||
|
||||
// Value indicates that the content of this path element is a field's value
|
||||
Value = "v"
|
||||
|
||||
// Index indicates that the content of this path element is an index in an array
|
||||
Index = "i"
|
||||
|
||||
// Key indicates that the content of this path element is a key value map
|
||||
Key = "k"
|
||||
|
||||
// Separator separates the type of a path element from the contents
|
||||
Separator = ":"
|
||||
)
|
||||
|
||||
// NewPathElement parses a serialized path element
|
||||
func NewPathElement(s string) (fieldpath.PathElement, error) {
|
||||
split := strings.SplitN(s, Separator, 2)
|
||||
if len(split) < 2 {
|
||||
return fieldpath.PathElement{}, fmt.Errorf("missing colon: %v", s)
|
||||
}
|
||||
switch split[0] {
|
||||
case Field:
|
||||
return fieldpath.PathElement{
|
||||
FieldName: &split[1],
|
||||
}, nil
|
||||
case Value:
|
||||
val, err := value.FromJSON([]byte(split[1]))
|
||||
if err != nil {
|
||||
return fieldpath.PathElement{}, err
|
||||
}
|
||||
return fieldpath.PathElement{
|
||||
Value: &val,
|
||||
}, nil
|
||||
case Index:
|
||||
i, err := strconv.Atoi(split[1])
|
||||
if err != nil {
|
||||
return fieldpath.PathElement{}, err
|
||||
}
|
||||
return fieldpath.PathElement{
|
||||
Index: &i,
|
||||
}, nil
|
||||
case Key:
|
||||
kv := map[string]json.RawMessage{}
|
||||
err := json.Unmarshal([]byte(split[1]), &kv)
|
||||
if err != nil {
|
||||
return fieldpath.PathElement{}, err
|
||||
}
|
||||
fields := value.FieldList{}
|
||||
for k, v := range kv {
|
||||
b, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return fieldpath.PathElement{}, err
|
||||
}
|
||||
val, err := value.FromJSON(b)
|
||||
if err != nil {
|
||||
return fieldpath.PathElement{}, err
|
||||
}
|
||||
|
||||
fields = append(fields, value.Field{
|
||||
Name: k,
|
||||
Value: val,
|
||||
})
|
||||
}
|
||||
return fieldpath.PathElement{
|
||||
Key: &fields,
|
||||
}, nil
|
||||
default:
|
||||
// Ignore unknown key types
|
||||
return fieldpath.PathElement{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// PathElementString serializes a path element
|
||||
func PathElementString(pe fieldpath.PathElement) (string, error) {
|
||||
switch {
|
||||
case pe.FieldName != nil:
|
||||
return Field + Separator + *pe.FieldName, nil
|
||||
case pe.Key != nil:
|
||||
kv := map[string]json.RawMessage{}
|
||||
for _, k := range *pe.Key {
|
||||
b, err := value.ToJSON(k.Value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
m := json.RawMessage{}
|
||||
err = json.Unmarshal(b, &m)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
kv[k.Name] = m
|
||||
}
|
||||
b, err := json.Marshal(kv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Key + ":" + string(b), nil
|
||||
case pe.Value != nil:
|
||||
b, err := value.ToJSON(*pe.Value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Value + ":" + string(b), nil
|
||||
case pe.Index != nil:
|
||||
return Index + ":" + strconv.Itoa(*pe.Index), nil
|
||||
default:
|
||||
return "", errors.New("Invalid type of path element")
|
||||
}
|
||||
}
|
89
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/skipnonapplied.go
generated
vendored
Normal file
89
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/skipnonapplied.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
type skipNonAppliedManager struct {
|
||||
fieldManager Manager
|
||||
objectCreater runtime.ObjectCreater
|
||||
beforeApplyManagerName string
|
||||
probability float32
|
||||
}
|
||||
|
||||
var _ Manager = &skipNonAppliedManager{}
|
||||
|
||||
// NewSkipNonAppliedManager creates a new wrapped FieldManager that only starts tracking managers after the first apply.
|
||||
func NewSkipNonAppliedManager(fieldManager Manager, objectCreater runtime.ObjectCreater) Manager {
|
||||
return NewProbabilisticSkipNonAppliedManager(fieldManager, objectCreater, 0.0)
|
||||
}
|
||||
|
||||
// NewProbabilisticSkipNonAppliedManager creates a new wrapped FieldManager that starts tracking managers after the first apply,
|
||||
// or starts tracking on create with p probability.
|
||||
func NewProbabilisticSkipNonAppliedManager(fieldManager Manager, objectCreater runtime.ObjectCreater, p float32) Manager {
|
||||
return &skipNonAppliedManager{
|
||||
fieldManager: fieldManager,
|
||||
objectCreater: objectCreater,
|
||||
beforeApplyManagerName: "before-first-apply",
|
||||
probability: p,
|
||||
}
|
||||
}
|
||||
|
||||
// Update implements Manager.
|
||||
func (f *skipNonAppliedManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
|
||||
accessor, err := meta.Accessor(liveObj)
|
||||
if err != nil {
|
||||
return newObj, managed, nil
|
||||
}
|
||||
|
||||
// If managed fields is empty, we need to determine whether to skip tracking managed fields.
|
||||
if len(managed.Fields()) == 0 {
|
||||
// Check if the operation is a create, by checking whether lastObj's UID is empty.
|
||||
// If the operation is create, P(tracking managed fields) = f.probability
|
||||
// If the operation is update, skip tracking managed fields, since we already know managed fields is empty.
|
||||
if len(accessor.GetUID()) == 0 {
|
||||
if f.probability <= rand.Float32() {
|
||||
return newObj, managed, nil
|
||||
}
|
||||
} else {
|
||||
return newObj, managed, nil
|
||||
}
|
||||
}
|
||||
return f.fieldManager.Update(liveObj, newObj, managed, manager)
|
||||
}
|
||||
|
||||
// Apply implements Manager.
|
||||
func (f *skipNonAppliedManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) {
|
||||
if len(managed.Fields()) == 0 {
|
||||
gvk := appliedObj.GetObjectKind().GroupVersionKind()
|
||||
emptyObj, err := f.objectCreater.New(gvk)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create empty object of type %v: %v", gvk, err)
|
||||
}
|
||||
liveObj, managed, err = f.fieldManager.Update(emptyObj, liveObj, managed, f.beforeApplyManagerName)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create manager for existing fields: %v", err)
|
||||
}
|
||||
}
|
||||
return f.fieldManager.Apply(liveObj, appliedObj, managed, fieldManager, force)
|
||||
}
|
90
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/stripmeta.go
generated
vendored
Normal file
90
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/stripmeta.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
type stripMetaManager struct {
|
||||
fieldManager Manager
|
||||
|
||||
// stripSet is the list of fields that should never be part of a mangedFields.
|
||||
stripSet *fieldpath.Set
|
||||
}
|
||||
|
||||
var _ Manager = &stripMetaManager{}
|
||||
|
||||
// NewStripMetaManager creates a new Manager that strips metadata and typemeta fields from the manager's fieldset.
|
||||
func NewStripMetaManager(fieldManager Manager) Manager {
|
||||
return &stripMetaManager{
|
||||
fieldManager: fieldManager,
|
||||
stripSet: fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("apiVersion"),
|
||||
fieldpath.MakePathOrDie("kind"),
|
||||
fieldpath.MakePathOrDie("metadata"),
|
||||
fieldpath.MakePathOrDie("metadata", "name"),
|
||||
fieldpath.MakePathOrDie("metadata", "namespace"),
|
||||
fieldpath.MakePathOrDie("metadata", "creationTimestamp"),
|
||||
fieldpath.MakePathOrDie("metadata", "selfLink"),
|
||||
fieldpath.MakePathOrDie("metadata", "uid"),
|
||||
fieldpath.MakePathOrDie("metadata", "clusterName"),
|
||||
fieldpath.MakePathOrDie("metadata", "generation"),
|
||||
fieldpath.MakePathOrDie("metadata", "managedFields"),
|
||||
fieldpath.MakePathOrDie("metadata", "resourceVersion"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Update implements Manager.
|
||||
func (f *stripMetaManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
|
||||
newObj, managed, err := f.fieldManager.Update(liveObj, newObj, managed, manager)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
f.stripFields(managed.Fields(), manager)
|
||||
return newObj, managed, nil
|
||||
}
|
||||
|
||||
// Apply implements Manager.
|
||||
func (f *stripMetaManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
||||
newObj, managed, err := f.fieldManager.Apply(liveObj, appliedObj, managed, manager, force)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
f.stripFields(managed.Fields(), manager)
|
||||
return newObj, managed, nil
|
||||
}
|
||||
|
||||
// stripFields removes a predefined set of paths found in typed from managed
|
||||
func (f *stripMetaManager) stripFields(managed fieldpath.ManagedFields, manager string) {
|
||||
vs, ok := managed[manager]
|
||||
if ok {
|
||||
if vs == nil {
|
||||
panic(fmt.Sprintf("Found unexpected nil manager which should never happen: %s", manager))
|
||||
}
|
||||
newSet := vs.Set().Difference(f.stripSet)
|
||||
if newSet.Empty() {
|
||||
delete(managed, manager)
|
||||
} else {
|
||||
managed[manager] = fieldpath.NewVersionedSet(newSet, vs.APIVersion(), vs.Applied())
|
||||
}
|
||||
}
|
||||
}
|
190
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/structuredmerge.go
generated
vendored
Normal file
190
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/structuredmerge.go
generated
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/merge"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type structuredMergeManager struct {
|
||||
typeConverter TypeConverter
|
||||
objectConverter runtime.ObjectConvertor
|
||||
objectDefaulter runtime.ObjectDefaulter
|
||||
groupVersion schema.GroupVersion
|
||||
hubVersion schema.GroupVersion
|
||||
updater merge.Updater
|
||||
}
|
||||
|
||||
var _ Manager = &structuredMergeManager{}
|
||||
|
||||
// NewStructuredMergeManager creates a new Manager that merges apply requests
|
||||
// and update managed fields for other types of requests.
|
||||
func NewStructuredMergeManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion, resetFields map[fieldpath.APIVersion]fieldpath.Filter) (Manager, error) {
|
||||
if typeConverter == nil {
|
||||
return nil, fmt.Errorf("typeconverter must not be nil")
|
||||
}
|
||||
return &structuredMergeManager{
|
||||
typeConverter: typeConverter,
|
||||
objectConverter: objectConverter,
|
||||
objectDefaulter: objectDefaulter,
|
||||
groupVersion: gv,
|
||||
hubVersion: hub,
|
||||
updater: merge.Updater{
|
||||
Converter: newVersionConverter(typeConverter, objectConverter, hub), // This is the converter provided to SMD from k8s
|
||||
IgnoreFilter: resetFields,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewCRDStructuredMergeManager creates a new Manager specifically for
|
||||
// CRDs. This allows for the possibility of fields which are not defined
|
||||
// in models, as well as having no models defined at all.
|
||||
func NewCRDStructuredMergeManager(typeConverter TypeConverter, objectConverter runtime.ObjectConvertor, objectDefaulter runtime.ObjectDefaulter, gv schema.GroupVersion, hub schema.GroupVersion, resetFields map[fieldpath.APIVersion]fieldpath.Filter) (_ Manager, err error) {
|
||||
return &structuredMergeManager{
|
||||
typeConverter: typeConverter,
|
||||
objectConverter: objectConverter,
|
||||
objectDefaulter: objectDefaulter,
|
||||
groupVersion: gv,
|
||||
hubVersion: hub,
|
||||
updater: merge.Updater{
|
||||
Converter: newCRDVersionConverter(typeConverter, objectConverter, hub),
|
||||
IgnoreFilter: resetFields,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func objectGVKNN(obj runtime.Object) string {
|
||||
name := "<unknown>"
|
||||
namespace := "<unknown>"
|
||||
if accessor, err := meta.Accessor(obj); err == nil {
|
||||
name = accessor.GetName()
|
||||
namespace = accessor.GetNamespace()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v/%v; %v", namespace, name, obj.GetObjectKind().GroupVersionKind())
|
||||
}
|
||||
|
||||
// Update implements Manager.
|
||||
func (f *structuredMergeManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
|
||||
newObjVersioned, err := f.toVersioned(newObj)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to convert new object (%v) to proper version (%v): %v", objectGVKNN(newObj), f.groupVersion, err)
|
||||
}
|
||||
liveObjVersioned, err := f.toVersioned(liveObj)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to convert live object (%v) to proper version: %v", objectGVKNN(liveObj), err)
|
||||
}
|
||||
newObjTyped, err := f.typeConverter.ObjectToTyped(newObjVersioned, typed.AllowDuplicates)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to convert new object (%v) to smd typed: %v", objectGVKNN(newObjVersioned), err)
|
||||
}
|
||||
liveObjTyped, err := f.typeConverter.ObjectToTyped(liveObjVersioned, typed.AllowDuplicates)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to convert live object (%v) to smd typed: %v", objectGVKNN(liveObjVersioned), err)
|
||||
}
|
||||
apiVersion := fieldpath.APIVersion(f.groupVersion.String())
|
||||
|
||||
// TODO(apelisse) use the first return value when unions are implemented
|
||||
_, managedFields, err := f.updater.Update(liveObjTyped, newObjTyped, apiVersion, managed.Fields(), manager)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to update ManagedFields (%v): %v", objectGVKNN(newObjVersioned), err)
|
||||
}
|
||||
managed = NewManaged(managedFields, managed.Times())
|
||||
|
||||
return newObj, managed, nil
|
||||
}
|
||||
|
||||
// Apply implements Manager.
|
||||
func (f *structuredMergeManager) Apply(liveObj, patchObj runtime.Object, managed Managed, manager string, force bool) (runtime.Object, Managed, error) {
|
||||
// Check that the patch object has the same version as the live object
|
||||
if patchVersion := patchObj.GetObjectKind().GroupVersionKind().GroupVersion(); patchVersion != f.groupVersion {
|
||||
return nil, nil,
|
||||
errors.NewBadRequest(
|
||||
fmt.Sprintf("Incorrect version specified in apply patch. "+
|
||||
"Specified patch version: %s, expected: %s",
|
||||
patchVersion, f.groupVersion))
|
||||
}
|
||||
|
||||
patchObjMeta, err := meta.Accessor(patchObj)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("couldn't get accessor: %v", err)
|
||||
}
|
||||
if patchObjMeta.GetManagedFields() != nil {
|
||||
return nil, nil, errors.NewBadRequest("metadata.managedFields must be nil")
|
||||
}
|
||||
|
||||
liveObjVersioned, err := f.toVersioned(liveObj)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to convert live object (%v) to proper version: %v", objectGVKNN(liveObj), err)
|
||||
}
|
||||
|
||||
// Don't allow duplicates in the applied object.
|
||||
patchObjTyped, err := f.typeConverter.ObjectToTyped(patchObj)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create typed patch object (%v): %v", objectGVKNN(patchObj), err)
|
||||
}
|
||||
|
||||
liveObjTyped, err := f.typeConverter.ObjectToTyped(liveObjVersioned, typed.AllowDuplicates)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create typed live object (%v): %v", objectGVKNN(liveObjVersioned), err)
|
||||
}
|
||||
|
||||
apiVersion := fieldpath.APIVersion(f.groupVersion.String())
|
||||
newObjTyped, managedFields, err := f.updater.Apply(liveObjTyped, patchObjTyped, apiVersion, managed.Fields(), manager, force)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
managed = NewManaged(managedFields, managed.Times())
|
||||
|
||||
if newObjTyped == nil {
|
||||
return nil, managed, nil
|
||||
}
|
||||
|
||||
newObj, err := f.typeConverter.TypedToObject(newObjTyped)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to convert new typed object (%v) to object: %v", objectGVKNN(patchObj), err)
|
||||
}
|
||||
|
||||
newObjVersioned, err := f.toVersioned(newObj)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to convert new object (%v) to proper version: %v", objectGVKNN(patchObj), err)
|
||||
}
|
||||
f.objectDefaulter.Default(newObjVersioned)
|
||||
|
||||
newObjUnversioned, err := f.toUnversioned(newObjVersioned)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to convert to unversioned (%v): %v", objectGVKNN(patchObj), err)
|
||||
}
|
||||
return newObjUnversioned, managed, nil
|
||||
}
|
||||
|
||||
func (f *structuredMergeManager) toVersioned(obj runtime.Object) (runtime.Object, error) {
|
||||
return f.objectConverter.ConvertToVersion(obj, f.groupVersion)
|
||||
}
|
||||
|
||||
func (f *structuredMergeManager) toUnversioned(obj runtime.Object) (runtime.Object, error) {
|
||||
return f.objectConverter.ConvertToVersion(obj, f.hubVersion)
|
||||
}
|
193
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/typeconverter.go
generated
vendored
Normal file
193
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/typeconverter.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
Copyright 2022 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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kube-openapi/pkg/schemaconv"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
smdschema "sigs.k8s.io/structured-merge-diff/v4/schema"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/value"
|
||||
)
|
||||
|
||||
// TypeConverter allows you to convert from runtime.Object to
|
||||
// typed.TypedValue and the other way around.
|
||||
type TypeConverter interface {
|
||||
ObjectToTyped(runtime.Object, ...typed.ValidationOptions) (*typed.TypedValue, error)
|
||||
TypedToObject(*typed.TypedValue) (runtime.Object, error)
|
||||
}
|
||||
|
||||
type typeConverter struct {
|
||||
parser map[schema.GroupVersionKind]*typed.ParseableType
|
||||
}
|
||||
|
||||
var _ TypeConverter = &typeConverter{}
|
||||
|
||||
func NewTypeConverter(openapiSpec map[string]*spec.Schema, preserveUnknownFields bool) (TypeConverter, error) {
|
||||
typeSchema, err := schemaconv.ToSchemaFromOpenAPI(openapiSpec, preserveUnknownFields)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert models to schema: %v", err)
|
||||
}
|
||||
|
||||
typeParser := typed.Parser{Schema: smdschema.Schema{Types: typeSchema.Types}}
|
||||
tr := indexModels(&typeParser, openapiSpec)
|
||||
|
||||
return &typeConverter{parser: tr}, nil
|
||||
}
|
||||
|
||||
func (c *typeConverter) ObjectToTyped(obj runtime.Object, opts ...typed.ValidationOptions) (*typed.TypedValue, error) {
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
t := c.parser[gvk]
|
||||
if t == nil {
|
||||
return nil, NewNoCorrespondingTypeError(gvk)
|
||||
}
|
||||
switch o := obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return t.FromUnstructured(o.UnstructuredContent(), opts...)
|
||||
default:
|
||||
return t.FromStructured(obj, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *typeConverter) TypedToObject(value *typed.TypedValue) (runtime.Object, error) {
|
||||
return valueToObject(value.AsValue())
|
||||
}
|
||||
|
||||
type deducedTypeConverter struct{}
|
||||
|
||||
// DeducedTypeConverter is a TypeConverter for CRDs that don't have a
|
||||
// schema. It does implement the same interface though (and create the
|
||||
// same types of objects), so that everything can still work the same.
|
||||
// CRDs are merged with all their fields being "atomic" (lists
|
||||
// included).
|
||||
func NewDeducedTypeConverter() TypeConverter {
|
||||
return deducedTypeConverter{}
|
||||
}
|
||||
|
||||
// ObjectToTyped converts an object into a TypedValue with a "deduced type".
|
||||
func (deducedTypeConverter) ObjectToTyped(obj runtime.Object, opts ...typed.ValidationOptions) (*typed.TypedValue, error) {
|
||||
switch o := obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
return typed.DeducedParseableType.FromUnstructured(o.UnstructuredContent(), opts...)
|
||||
default:
|
||||
return typed.DeducedParseableType.FromStructured(obj, opts...)
|
||||
}
|
||||
}
|
||||
|
||||
// TypedToObject transforms the typed value into a runtime.Object. That
|
||||
// is not specific to deduced type.
|
||||
func (deducedTypeConverter) TypedToObject(value *typed.TypedValue) (runtime.Object, error) {
|
||||
return valueToObject(value.AsValue())
|
||||
}
|
||||
|
||||
func valueToObject(val value.Value) (runtime.Object, error) {
|
||||
vu := val.Unstructured()
|
||||
switch o := vu.(type) {
|
||||
case map[string]interface{}:
|
||||
return &unstructured.Unstructured{Object: o}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("failed to convert value to unstructured for type %T", vu)
|
||||
}
|
||||
}
|
||||
|
||||
func indexModels(
|
||||
typeParser *typed.Parser,
|
||||
openAPISchemas map[string]*spec.Schema,
|
||||
) map[schema.GroupVersionKind]*typed.ParseableType {
|
||||
tr := map[schema.GroupVersionKind]*typed.ParseableType{}
|
||||
for modelName, model := range openAPISchemas {
|
||||
gvkList := parseGroupVersionKind(model.Extensions)
|
||||
if len(gvkList) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
parsedType := typeParser.Type(modelName)
|
||||
for _, gvk := range gvkList {
|
||||
if len(gvk.Kind) > 0 {
|
||||
tr[schema.GroupVersionKind(gvk)] = &parsedType
|
||||
}
|
||||
}
|
||||
}
|
||||
return tr
|
||||
}
|
||||
|
||||
// Get and parse GroupVersionKind from the extension. Returns empty if it doesn't have one.
|
||||
func parseGroupVersionKind(extensions map[string]interface{}) []schema.GroupVersionKind {
|
||||
gvkListResult := []schema.GroupVersionKind{}
|
||||
|
||||
// Get the extensions
|
||||
gvkExtension, ok := extensions["x-kubernetes-group-version-kind"]
|
||||
if !ok {
|
||||
return []schema.GroupVersionKind{}
|
||||
}
|
||||
|
||||
// gvk extension must be a list of at least 1 element.
|
||||
gvkList, ok := gvkExtension.([]interface{})
|
||||
if !ok {
|
||||
return []schema.GroupVersionKind{}
|
||||
}
|
||||
|
||||
for _, gvk := range gvkList {
|
||||
var group, version, kind string
|
||||
|
||||
// gvk extension list must be a map with group, version, and
|
||||
// kind fields
|
||||
if gvkMap, ok := gvk.(map[interface{}]interface{}); ok {
|
||||
group, ok = gvkMap["group"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
version, ok = gvkMap["version"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
kind, ok = gvkMap["kind"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
} else if gvkMap, ok := gvk.(map[string]interface{}); ok {
|
||||
group, ok = gvkMap["group"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
version, ok = gvkMap["version"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
kind, ok = gvkMap["kind"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
gvkListResult = append(gvkListResult, schema.GroupVersionKind{
|
||||
Group: group,
|
||||
Version: version,
|
||||
Kind: kind,
|
||||
})
|
||||
}
|
||||
|
||||
return gvkListResult
|
||||
}
|
52
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/versioncheck.go
generated
vendored
Normal file
52
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/versioncheck.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2023 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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
type versionCheckManager struct {
|
||||
fieldManager Manager
|
||||
gvk schema.GroupVersionKind
|
||||
}
|
||||
|
||||
var _ Manager = &versionCheckManager{}
|
||||
|
||||
// NewVersionCheckManager creates a manager that makes sure that the
|
||||
// applied object is in the proper version.
|
||||
func NewVersionCheckManager(fieldManager Manager, gvk schema.GroupVersionKind) Manager {
|
||||
return &versionCheckManager{fieldManager: fieldManager, gvk: gvk}
|
||||
}
|
||||
|
||||
// Update implements Manager.
|
||||
func (f *versionCheckManager) Update(liveObj, newObj runtime.Object, managed Managed, manager string) (runtime.Object, Managed, error) {
|
||||
// Nothing to do for updates, this is checked in many other places.
|
||||
return f.fieldManager.Update(liveObj, newObj, managed, manager)
|
||||
}
|
||||
|
||||
// Apply implements Manager.
|
||||
func (f *versionCheckManager) Apply(liveObj, appliedObj runtime.Object, managed Managed, fieldManager string, force bool) (runtime.Object, Managed, error) {
|
||||
if gvk := appliedObj.GetObjectKind().GroupVersionKind(); gvk != f.gvk {
|
||||
return nil, nil, errors.NewBadRequest(fmt.Sprintf("invalid object type: %v", gvk))
|
||||
}
|
||||
return f.fieldManager.Apply(liveObj, appliedObj, managed, fieldManager, force)
|
||||
}
|
123
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/versionconverter.go
generated
vendored
Normal file
123
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/internal/versionconverter.go
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
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 internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/merge"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
)
|
||||
|
||||
// versionConverter is an implementation of
|
||||
// sigs.k8s.io/structured-merge-diff/merge.Converter
|
||||
type versionConverter struct {
|
||||
typeConverter TypeConverter
|
||||
objectConvertor runtime.ObjectConvertor
|
||||
hubGetter func(from schema.GroupVersion) schema.GroupVersion
|
||||
}
|
||||
|
||||
var _ merge.Converter = &versionConverter{}
|
||||
|
||||
// NewVersionConverter builds a VersionConverter from a TypeConverter and an ObjectConvertor.
|
||||
func newVersionConverter(t TypeConverter, o runtime.ObjectConvertor, h schema.GroupVersion) merge.Converter {
|
||||
return &versionConverter{
|
||||
typeConverter: t,
|
||||
objectConvertor: o,
|
||||
hubGetter: func(from schema.GroupVersion) schema.GroupVersion {
|
||||
return schema.GroupVersion{
|
||||
Group: from.Group,
|
||||
Version: h.Version,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewCRDVersionConverter builds a VersionConverter for CRDs from a TypeConverter and an ObjectConvertor.
|
||||
func newCRDVersionConverter(t TypeConverter, o runtime.ObjectConvertor, h schema.GroupVersion) merge.Converter {
|
||||
return &versionConverter{
|
||||
typeConverter: t,
|
||||
objectConvertor: o,
|
||||
hubGetter: func(from schema.GroupVersion) schema.GroupVersion {
|
||||
return h
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Convert implements sigs.k8s.io/structured-merge-diff/merge.Converter
|
||||
func (v *versionConverter) Convert(object *typed.TypedValue, version fieldpath.APIVersion) (*typed.TypedValue, error) {
|
||||
// Convert the smd typed value to a kubernetes object.
|
||||
objectToConvert, err := v.typeConverter.TypedToObject(object)
|
||||
if err != nil {
|
||||
return object, err
|
||||
}
|
||||
|
||||
// Parse the target groupVersion.
|
||||
groupVersion, err := schema.ParseGroupVersion(string(version))
|
||||
if err != nil {
|
||||
return object, err
|
||||
}
|
||||
|
||||
// If attempting to convert to the same version as we already have, just return it.
|
||||
fromVersion := objectToConvert.GetObjectKind().GroupVersionKind().GroupVersion()
|
||||
if fromVersion == groupVersion {
|
||||
return object, nil
|
||||
}
|
||||
|
||||
// Convert to internal
|
||||
internalObject, err := v.objectConvertor.ConvertToVersion(objectToConvert, v.hubGetter(fromVersion))
|
||||
if err != nil {
|
||||
return object, err
|
||||
}
|
||||
|
||||
// Convert the object into the target version
|
||||
convertedObject, err := v.objectConvertor.ConvertToVersion(internalObject, groupVersion)
|
||||
if err != nil {
|
||||
return object, err
|
||||
}
|
||||
|
||||
// Convert the object back to a smd typed value and return it.
|
||||
return v.typeConverter.ObjectToTyped(convertedObject)
|
||||
}
|
||||
|
||||
// IsMissingVersionError
|
||||
func (v *versionConverter) IsMissingVersionError(err error) bool {
|
||||
return runtime.IsNotRegisteredError(err) || isNoCorrespondingTypeError(err)
|
||||
}
|
||||
|
||||
type noCorrespondingTypeErr struct {
|
||||
gvk schema.GroupVersionKind
|
||||
}
|
||||
|
||||
func NewNoCorrespondingTypeError(gvk schema.GroupVersionKind) error {
|
||||
return &noCorrespondingTypeErr{gvk: gvk}
|
||||
}
|
||||
|
||||
func (k *noCorrespondingTypeErr) Error() string {
|
||||
return fmt.Sprintf("no corresponding type for %v", k.gvk)
|
||||
}
|
||||
|
||||
func isNoCorrespondingTypeError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := err.(*noCorrespondingTypeErr)
|
||||
return ok
|
||||
}
|
261
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/node.yaml
generated
vendored
Normal file
261
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/node.yaml
generated
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
apiVersion: v1
|
||||
kind: Node
|
||||
metadata:
|
||||
annotations:
|
||||
container.googleapis.com/instance_id: "123456789321654789"
|
||||
node.alpha.kubernetes.io/ttl: "0"
|
||||
volumes.kubernetes.io/controller-managed-attach-detach: "true"
|
||||
creationTimestamp: "2019-07-09T16:17:29Z"
|
||||
labels:
|
||||
kubernetes.io/arch: amd64
|
||||
beta.kubernetes.io/fluentd-ds-ready: "true"
|
||||
beta.kubernetes.io/instance-type: n1-standard-4
|
||||
kubernetes.io/os: linux
|
||||
cloud.google.com/gke-nodepool: default-pool
|
||||
cloud.google.com/gke-os-distribution: cos
|
||||
failure-domain.beta.kubernetes.io/region: us-central1
|
||||
failure-domain.beta.kubernetes.io/zone: us-central1-b
|
||||
topology.kubernetes.io/region: us-central1
|
||||
topology.kubernetes.io/zone: us-central1-b
|
||||
kubernetes.io/hostname: node-default-pool-something
|
||||
name: node-default-pool-something
|
||||
resourceVersion: "211582541"
|
||||
selfLink: /api/v1/nodes/node-default-pool-something
|
||||
uid: 0c24d0e1-a265-11e9-abe4-42010a80026b
|
||||
spec:
|
||||
podCIDR: 10.0.0.1/24
|
||||
providerID: some-provider-id-of-some-sort
|
||||
status:
|
||||
addresses:
|
||||
- address: 10.0.0.1
|
||||
type: InternalIP
|
||||
- address: 192.168.0.1
|
||||
type: ExternalIP
|
||||
- address: node-default-pool-something
|
||||
type: Hostname
|
||||
allocatable:
|
||||
cpu: 3920m
|
||||
ephemeral-storage: "104638878617"
|
||||
hugepages-2Mi: "0"
|
||||
memory: 12700100Ki
|
||||
pods: "110"
|
||||
capacity:
|
||||
cpu: "4"
|
||||
ephemeral-storage: 202086868Ki
|
||||
hugepages-2Mi: "0"
|
||||
memory: 15399364Ki
|
||||
pods: "110"
|
||||
conditions:
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:08Z"
|
||||
lastTransitionTime: "2019-07-09T16:22:08Z"
|
||||
message: containerd is functioning properly
|
||||
reason: FrequentContainerdRestart
|
||||
status: "False"
|
||||
type: FrequentContainerdRestart
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:08Z"
|
||||
lastTransitionTime: "2019-07-09T16:22:06Z"
|
||||
message: docker overlay2 is functioning properly
|
||||
reason: CorruptDockerOverlay2
|
||||
status: "False"
|
||||
type: CorruptDockerOverlay2
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:08Z"
|
||||
lastTransitionTime: "2019-07-09T16:22:06Z"
|
||||
message: node is functioning properly
|
||||
reason: UnregisterNetDevice
|
||||
status: "False"
|
||||
type: FrequentUnregisterNetDevice
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:08Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:04Z"
|
||||
message: kernel has no deadlock
|
||||
reason: KernelHasNoDeadlock
|
||||
status: "False"
|
||||
type: KernelDeadlock
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:08Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:04Z"
|
||||
message: Filesystem is not read-only
|
||||
reason: FilesystemIsNotReadOnly
|
||||
status: "False"
|
||||
type: ReadonlyFilesystem
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:08Z"
|
||||
lastTransitionTime: "2019-07-09T16:22:05Z"
|
||||
message: kubelet is functioning properly
|
||||
reason: FrequentKubeletRestart
|
||||
status: "False"
|
||||
type: FrequentKubeletRestart
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:08Z"
|
||||
lastTransitionTime: "2019-07-09T16:22:06Z"
|
||||
message: docker is functioning properly
|
||||
reason: FrequentDockerRestart
|
||||
status: "False"
|
||||
type: FrequentDockerRestart
|
||||
- lastHeartbeatTime: "2019-07-09T16:17:47Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:47Z"
|
||||
message: RouteController created a route
|
||||
reason: RouteCreated
|
||||
status: "False"
|
||||
type: NetworkUnavailable
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:50Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:29Z"
|
||||
message: kubelet has sufficient disk space available
|
||||
reason: KubeletHasSufficientDisk
|
||||
status: "False"
|
||||
type: OutOfDisk
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:50Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:29Z"
|
||||
message: kubelet has sufficient memory available
|
||||
reason: KubeletHasSufficientMemory
|
||||
status: "False"
|
||||
type: MemoryPressure
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:50Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:29Z"
|
||||
message: kubelet has no disk pressure
|
||||
reason: KubeletHasNoDiskPressure
|
||||
status: "False"
|
||||
type: DiskPressure
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:50Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:29Z"
|
||||
message: kubelet has sufficient PID available
|
||||
reason: KubeletHasSufficientPID
|
||||
status: "False"
|
||||
type: PIDPressure
|
||||
- lastHeartbeatTime: "2019-09-20T19:32:50Z"
|
||||
lastTransitionTime: "2019-07-09T16:17:49Z"
|
||||
message: kubelet is posting ready status
|
||||
reason: KubeletReady
|
||||
status: "True"
|
||||
type: Ready
|
||||
daemonEndpoints:
|
||||
kubeletEndpoint:
|
||||
Port: 10250
|
||||
images:
|
||||
- names:
|
||||
- grafana/grafana@sha256:80e5e113a984d74836aa16f5b4524012099436b1a50df293f00ac6377fb512c8
|
||||
- grafana/grafana:4.4.2
|
||||
sizeBytes: 287008013
|
||||
- names:
|
||||
- registry.k8s.io/node-problem-detector@sha256:f95cab985c26b2f46e9bd43283e0bfa88860c14e0fb0649266babe8b65e9eb2b
|
||||
- registry.k8s.io/node-problem-detector:v0.4.1
|
||||
sizeBytes: 286572743
|
||||
- names:
|
||||
- grafana/grafana@sha256:7ff7f9b2501a5d55b55ce3f58d21771b1c5af1f2a4ab7dbf11bef7142aae7033
|
||||
- grafana/grafana:4.2.0
|
||||
sizeBytes: 277940263
|
||||
- names:
|
||||
- influxdb@sha256:7dddf03376348876ed4bdf33d6dfa3326f45a2bae0930dbd80781a374eb519bc
|
||||
- influxdb:1.2.2
|
||||
sizeBytes: 223948571
|
||||
- names:
|
||||
- gcr.io/stackdriver-agents/stackdriver-logging-agent@sha256:f8d5231b67b9c53f60068b535a11811d29d1b3efd53d2b79f2a2591ea338e4f2
|
||||
- gcr.io/stackdriver-agents/stackdriver-logging-agent:0.6-1.6.0-1
|
||||
sizeBytes: 223242132
|
||||
- names:
|
||||
- nginx@sha256:35779791c05d119df4fe476db8f47c0bee5943c83eba5656a15fc046db48178b
|
||||
- nginx:1.10.1
|
||||
sizeBytes: 180708613
|
||||
- names:
|
||||
- registry.k8s.io/fluentd-elasticsearch@sha256:b8c94527b489fb61d3d81ce5ad7f3ddbb7be71e9620a3a36e2bede2f2e487d73
|
||||
- registry.k8s.io/fluentd-elasticsearch:v2.0.4
|
||||
sizeBytes: 135716379
|
||||
- names:
|
||||
- nginx@sha256:00be67d6ba53d5318cd91c57771530f5251cfbe028b7be2c4b70526f988cfc9f
|
||||
- nginx:latest
|
||||
sizeBytes: 109357355
|
||||
- names:
|
||||
- registry.k8s.io/kubernetes-dashboard-amd64@sha256:dc4026c1b595435ef5527ca598e1e9c4343076926d7d62b365c44831395adbd0
|
||||
- registry.k8s.io/kubernetes-dashboard-amd64:v1.8.3
|
||||
sizeBytes: 102319441
|
||||
- names:
|
||||
- gcr.io/google_containers/kube-proxy:v1.11.10-gke.5
|
||||
- registry.k8s.io/kube-proxy:v1.11.10-gke.5
|
||||
sizeBytes: 102279340
|
||||
- names:
|
||||
- registry.k8s.io/event-exporter@sha256:7f9cd7cb04d6959b0aa960727d04fa86759008048c785397b7b0d9dff0007516
|
||||
- registry.k8s.io/event-exporter:v0.2.3
|
||||
sizeBytes: 94171943
|
||||
- names:
|
||||
- registry.k8s.io/prometheus-to-sd@sha256:6c0c742475363d537ff059136e5d5e4ab1f512ee0fd9b7ca42ea48bc309d1662
|
||||
- registry.k8s.io/prometheus-to-sd:v0.3.1
|
||||
sizeBytes: 88077694
|
||||
- names:
|
||||
- registry.k8s.io/fluentd-gcp-scaler@sha256:a5ace7506d393c4ed65eb2cbb6312c64ab357fcea16dff76b9055bc6e498e5ff
|
||||
- registry.k8s.io/fluentd-gcp-scaler:0.5.1
|
||||
sizeBytes: 86637208
|
||||
- names:
|
||||
- registry.k8s.io/heapster-amd64@sha256:9fae0af136ce0cf4f88393b3670f7139ffc464692060c374d2ae748e13144521
|
||||
- registry.k8s.io/heapster-amd64:v1.6.0-beta.1
|
||||
sizeBytes: 76016169
|
||||
- names:
|
||||
- registry.k8s.io/ingress-glbc-amd64@sha256:31d36bbd9c44caffa135fc78cf0737266fcf25e3cf0cd1c2fcbfbc4f7309cc52
|
||||
- registry.k8s.io/ingress-glbc-amd64:v1.1.1
|
||||
sizeBytes: 67801919
|
||||
- names:
|
||||
- registry.k8s.io/kube-addon-manager@sha256:d53486c3a0b49ebee019932878dc44232735d5622a51dbbdcec7124199020d09
|
||||
- registry.k8s.io/kube-addon-manager:v8.7
|
||||
sizeBytes: 63322109
|
||||
- names:
|
||||
- nginx@sha256:4aacdcf186934dcb02f642579314075910f1855590fd3039d8fa4c9f96e48315
|
||||
- nginx:1.10-alpine
|
||||
sizeBytes: 54042627
|
||||
- names:
|
||||
- registry.k8s.io/cpvpa-amd64@sha256:cfe7b0a11c9c8e18c87b1eb34fef9a7cbb8480a8da11fc2657f78dbf4739f869
|
||||
- registry.k8s.io/cpvpa-amd64:v0.6.0
|
||||
sizeBytes: 51785854
|
||||
- names:
|
||||
- registry.k8s.io/cluster-proportional-autoscaler-amd64@sha256:003f98d9f411ddfa6ff6d539196355e03ddd69fa4ed38c7ffb8fec6f729afe2d
|
||||
- registry.k8s.io/cluster-proportional-autoscaler-amd64:1.1.2-r2
|
||||
sizeBytes: 49648481
|
||||
- names:
|
||||
- registry.k8s.io/ip-masq-agent-amd64@sha256:1ffda57d87901bc01324c82ceb2145fe6a0448d3f0dd9cb65aa76a867cd62103
|
||||
- registry.k8s.io/ip-masq-agent-amd64:v2.1.1
|
||||
sizeBytes: 49612505
|
||||
- names:
|
||||
- registry.k8s.io/k8s-dns-kube-dns-amd64@sha256:b99fc3eee2a9f052f7eb4cc00f15eb12fc405fa41019baa2d6b79847ae7284a8
|
||||
- registry.k8s.io/k8s-dns-kube-dns-amd64:1.14.10
|
||||
sizeBytes: 49549457
|
||||
- names:
|
||||
- registry.k8s.io/rescheduler@sha256:156cfbfd05a5a815206fd2eeb6cbdaf1596d71ea4b415d3a6c43071dd7b99450
|
||||
- registry.k8s.io/rescheduler:v0.4.0
|
||||
sizeBytes: 48973149
|
||||
- names:
|
||||
- registry.k8s.io/event-exporter@sha256:16ca66e2b5dc7a1ce6a5aafcb21d0885828b75cdfc08135430480f7ad2364adc
|
||||
- registry.k8s.io/event-exporter:v0.2.4
|
||||
sizeBytes: 47261019
|
||||
- names:
|
||||
- registry.k8s.io/coredns@sha256:db2bf53126ed1c761d5a41f24a1b82a461c85f736ff6e90542e9522be4757848
|
||||
- registry.k8s.io/coredns:1.1.3
|
||||
sizeBytes: 45587362
|
||||
- names:
|
||||
- prom/prometheus@sha256:483f4c9d7733699ba79facca9f8bcce1cef1af43dfc3e7c5a1882aa85f53cb74
|
||||
- prom/prometheus:v1.1.3
|
||||
sizeBytes: 45493941
|
||||
nodeInfo:
|
||||
architecture: amd64
|
||||
bootID: a32eca78-4ad4-4b76-9252-f143d6c2ae61
|
||||
containerRuntimeVersion: docker://17.3.2
|
||||
kernelVersion: 4.14.127+
|
||||
kubeProxyVersion: v1.11.10-gke.5
|
||||
kubeletVersion: v1.11.10-gke.5
|
||||
machineID: 1739555e5b231057f0f9a0b5fa29511b
|
||||
operatingSystem: linux
|
||||
osImage: Container-Optimized OS from Google
|
||||
systemUUID: 1739555E-5B23-1057-F0F9-A0B5FA29511B
|
||||
volumesAttached:
|
||||
- devicePath: /dev/disk/by-id/b9772-pvc-c787c67d-14d7-11e7-9baf-42010a800049
|
||||
name: kubernetes.io/pd/some-random-clusterb9772-pvc-c787c67d-14d7-11e7-9baf-42010a800049
|
||||
- devicePath: /dev/disk/by-id/b9772-pvc-8895a852-fd42-11e6-94d4-42010a800049
|
||||
name: kubernetes.io/pd/some-random-clusterb9772-pvc-8895a852-fd42-11e6-94d4-42010a800049
|
||||
- devicePath: /dev/disk/by-id/some-random-clusterb9772-pvc-72e1c7f1-fd41-11e6-94d4-42010a800049
|
||||
name: kubernetes.io/pd/some-random-clusterb9772-pvc-72e1c7f1-fd41-11e6-94d4-42010a800049
|
||||
- devicePath: /dev/disk/by-id/some-random-clusterb9772-pvc-c2435a06-14d7-11e7-9baf-42010a800049
|
||||
name: kubernetes.io/pd/some-random-clusterb9772-pvc-c2435a06-14d7-11e7-9baf-42010a800049
|
||||
- devicePath: /dev/disk/by-id/some-random-clusterb9772-pvc-8bf50554-fd42-11e6-94d4-42010a800049
|
||||
name: kubernetes.io/pd/some-random-clusterb9772-pvc-8bf50554-fd42-11e6-94d4-42010a800049
|
||||
- devicePath: /dev/disk/by-id/some-random-clusterb9772-pvc-8fb5e386-4641-11e7-a490-42010a800283
|
||||
name: kubernetes.io/pd/some-random-clusterb9772-pvc-8fb5e386-4641-11e7-a490-42010a800283
|
||||
volumesInUse:
|
||||
- kubernetes.io/pd/some-random-clusterb9772-pvc-72e1c7f1-fd41-11e6-94d4-42010a800049
|
||||
- kubernetes.io/pd/some-random-clusterb9772-pvc-8895a852-fd42-11e6-94d4-42010a800049
|
||||
- kubernetes.io/pd/some-random-clusterb9772-pvc-8bf50554-fd42-11e6-94d4-42010a800049
|
||||
- kubernetes.io/pd/some-random-clusterb9772-pvc-8fb5e386-4641-11e7-a490-42010a800283
|
||||
- kubernetes.io/pd/some-random-clusterb9772-pvc-c2435a06-14d7-11e7-9baf-42010a800049
|
||||
- kubernetes.io/pd/some-random-clusterb9772-pvc-c787c67d-14d7-11e7-9baf-42010a800049
|
121
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/pod.yaml
generated
vendored
Normal file
121
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/pod.yaml
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
app: some-app
|
||||
plugin1: some-value
|
||||
plugin2: some-value
|
||||
plugin3: some-value
|
||||
plugin4: some-value
|
||||
name: some-name
|
||||
namespace: default
|
||||
ownerReferences:
|
||||
- apiVersion: apps/v1
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: ReplicaSet
|
||||
name: some-name
|
||||
uid: 0a9d2b9e-779e-11e7-b422-42010a8001be
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- one
|
||||
- two
|
||||
- three
|
||||
- four
|
||||
- five
|
||||
- six
|
||||
- seven
|
||||
- eight
|
||||
- nine
|
||||
env:
|
||||
- name: VAR_3
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: some-other-key
|
||||
name: some-oher-name
|
||||
- name: VAR_2
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: other-key
|
||||
name: other-name
|
||||
- name: VAR_1
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
key: some-key
|
||||
name: some-name
|
||||
image: some-image-name
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: some-name
|
||||
resources:
|
||||
requests:
|
||||
cpu: '0'
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
volumeMounts:
|
||||
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
|
||||
name: default-token-hu5jz
|
||||
readOnly: true
|
||||
dnsPolicy: ClusterFirst
|
||||
nodeName: node-name
|
||||
priority: 0
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
serviceAccount: default
|
||||
serviceAccountName: default
|
||||
terminationGracePeriodSeconds: 30
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
operator: Exists
|
||||
tolerationSeconds: 300
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/unreachable
|
||||
operator: Exists
|
||||
tolerationSeconds: 300
|
||||
volumes:
|
||||
- name: default-token-hu5jz
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: default-token-hu5jz
|
||||
status:
|
||||
conditions:
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: '2019-07-08T09:31:18Z'
|
||||
status: 'True'
|
||||
type: Initialized
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: '2019-07-08T09:41:59Z'
|
||||
status: 'True'
|
||||
type: Ready
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: null
|
||||
status: 'True'
|
||||
type: ContainersReady
|
||||
- lastProbeTime: null
|
||||
lastTransitionTime: '2019-07-08T09:31:18Z'
|
||||
status: 'True'
|
||||
type: PodScheduled
|
||||
containerStatuses:
|
||||
- containerID: docker://885e82a1ed0b7356541bb410a0126921ac42439607c09875cd8097dd5d7b5376
|
||||
image: some-image-name
|
||||
imageID: docker-pullable://some-image-id
|
||||
lastState:
|
||||
terminated:
|
||||
containerID: docker://d57290f9e00fad626b20d2dd87a3cf69bbc22edae07985374f86a8b2b4e39565
|
||||
exitCode: 255
|
||||
finishedAt: '2019-07-08T09:39:09Z'
|
||||
reason: Error
|
||||
startedAt: '2019-07-08T09:38:54Z'
|
||||
name: name
|
||||
ready: true
|
||||
restartCount: 6
|
||||
state:
|
||||
running:
|
||||
startedAt: '2019-07-08T09:41:59Z'
|
||||
hostIP: 10.0.0.1
|
||||
phase: Running
|
||||
podIP: 10.0.0.1
|
||||
qosClass: BestEffort
|
||||
startTime: '2019-07-08T09:31:18Z'
|
174
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/scalehandler.go
generated
vendored
Normal file
174
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/scalehandler.go
generated
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
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 managedfields
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"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/schema"
|
||||
"k8s.io/apimachinery/pkg/util/managedfields/internal"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
var (
|
||||
scaleGroupVersion = schema.GroupVersion{Group: "autoscaling", Version: "v1"}
|
||||
replicasPathInScale = fieldpath.MakePathOrDie("spec", "replicas")
|
||||
)
|
||||
|
||||
// ResourcePathMappings maps a group/version to its replicas path. The
|
||||
// assumption is that all the paths correspond to leaf fields.
|
||||
type ResourcePathMappings map[string]fieldpath.Path
|
||||
|
||||
// ScaleHandler manages the conversion of managed fields between a main
|
||||
// resource and the scale subresource
|
||||
type ScaleHandler struct {
|
||||
parentEntries []metav1.ManagedFieldsEntry
|
||||
groupVersion schema.GroupVersion
|
||||
mappings ResourcePathMappings
|
||||
}
|
||||
|
||||
// NewScaleHandler creates a new ScaleHandler
|
||||
func NewScaleHandler(parentEntries []metav1.ManagedFieldsEntry, groupVersion schema.GroupVersion, mappings ResourcePathMappings) *ScaleHandler {
|
||||
return &ScaleHandler{
|
||||
parentEntries: parentEntries,
|
||||
groupVersion: groupVersion,
|
||||
mappings: mappings,
|
||||
}
|
||||
}
|
||||
|
||||
// ToSubresource filter the managed fields of the main resource and convert
|
||||
// them so that they can be handled by scale.
|
||||
// For the managed fields that have a replicas path it performs two changes:
|
||||
// 1. APIVersion is changed to the APIVersion of the scale subresource
|
||||
// 2. Replicas path of the main resource is transformed to the replicas path of
|
||||
// the scale subresource
|
||||
func (h *ScaleHandler) ToSubresource() ([]metav1.ManagedFieldsEntry, error) {
|
||||
managed, err := internal.DecodeManagedFields(h.parentEntries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f := fieldpath.ManagedFields{}
|
||||
t := map[string]*metav1.Time{}
|
||||
for manager, versionedSet := range managed.Fields() {
|
||||
path, ok := h.mappings[string(versionedSet.APIVersion())]
|
||||
// Skip the entry if the APIVersion is unknown
|
||||
if !ok || path == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if versionedSet.Set().Has(path) {
|
||||
newVersionedSet := fieldpath.NewVersionedSet(
|
||||
fieldpath.NewSet(replicasPathInScale),
|
||||
fieldpath.APIVersion(scaleGroupVersion.String()),
|
||||
versionedSet.Applied(),
|
||||
)
|
||||
|
||||
f[manager] = newVersionedSet
|
||||
t[manager] = managed.Times()[manager]
|
||||
}
|
||||
}
|
||||
|
||||
return managedFieldsEntries(internal.NewManaged(f, t))
|
||||
}
|
||||
|
||||
// ToParent merges `scaleEntries` with the entries of the main resource and
|
||||
// transforms them accordingly
|
||||
func (h *ScaleHandler) ToParent(scaleEntries []metav1.ManagedFieldsEntry) ([]metav1.ManagedFieldsEntry, error) {
|
||||
decodedParentEntries, err := internal.DecodeManagedFields(h.parentEntries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parentFields := decodedParentEntries.Fields()
|
||||
|
||||
decodedScaleEntries, err := internal.DecodeManagedFields(scaleEntries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scaleFields := decodedScaleEntries.Fields()
|
||||
|
||||
f := fieldpath.ManagedFields{}
|
||||
t := map[string]*metav1.Time{}
|
||||
|
||||
for manager, versionedSet := range parentFields {
|
||||
// Get the main resource "replicas" path
|
||||
path, ok := h.mappings[string(versionedSet.APIVersion())]
|
||||
// Drop the entry if the APIVersion is unknown.
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the parent entry does not have the replicas path or it is nil, just
|
||||
// keep it as it is. The path is nil for Custom Resources without scale
|
||||
// subresource.
|
||||
if path == nil || !versionedSet.Set().Has(path) {
|
||||
f[manager] = versionedSet
|
||||
t[manager] = decodedParentEntries.Times()[manager]
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := scaleFields[manager]; !ok {
|
||||
// "Steal" the replicas path from the main resource entry
|
||||
newSet := versionedSet.Set().Difference(fieldpath.NewSet(path))
|
||||
|
||||
if !newSet.Empty() {
|
||||
newVersionedSet := fieldpath.NewVersionedSet(
|
||||
newSet,
|
||||
versionedSet.APIVersion(),
|
||||
versionedSet.Applied(),
|
||||
)
|
||||
f[manager] = newVersionedSet
|
||||
t[manager] = decodedParentEntries.Times()[manager]
|
||||
}
|
||||
} else {
|
||||
// Field wasn't stolen, let's keep the entry as it is.
|
||||
f[manager] = versionedSet
|
||||
t[manager] = decodedParentEntries.Times()[manager]
|
||||
delete(scaleFields, manager)
|
||||
}
|
||||
}
|
||||
|
||||
for manager, versionedSet := range scaleFields {
|
||||
if !versionedSet.Set().Has(replicasPathInScale) {
|
||||
continue
|
||||
}
|
||||
newVersionedSet := fieldpath.NewVersionedSet(
|
||||
fieldpath.NewSet(h.mappings[h.groupVersion.String()]),
|
||||
fieldpath.APIVersion(h.groupVersion.String()),
|
||||
versionedSet.Applied(),
|
||||
)
|
||||
f[manager] = newVersionedSet
|
||||
t[manager] = decodedParentEntries.Times()[manager]
|
||||
}
|
||||
|
||||
return managedFieldsEntries(internal.NewManaged(f, t))
|
||||
}
|
||||
|
||||
func managedFieldsEntries(entries internal.ManagedInterface) ([]metav1.ManagedFieldsEntry, error) {
|
||||
obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||
if err := internal.EncodeObjectManagedFields(obj, entries); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("couldn't get accessor: %v", err))
|
||||
}
|
||||
return accessor.GetManagedFields(), nil
|
||||
}
|
47
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/typeconverter.go
generated
vendored
Normal file
47
e2e/vendor/k8s.io/apimachinery/pkg/util/managedfields/typeconverter.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
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 managedfields
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/util/managedfields/internal"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// TypeConverter allows you to convert from runtime.Object to
|
||||
// typed.TypedValue and the other way around.
|
||||
type TypeConverter = internal.TypeConverter
|
||||
|
||||
// NewDeducedTypeConverter creates a TypeConverter for CRDs that don't
|
||||
// have a schema. It does implement the same interface though (and
|
||||
// create the same types of objects), so that everything can still work
|
||||
// the same. CRDs are merged with all their fields being "atomic" (lists
|
||||
// included).
|
||||
func NewDeducedTypeConverter() TypeConverter {
|
||||
return internal.NewDeducedTypeConverter()
|
||||
}
|
||||
|
||||
// NewTypeConverter builds a TypeConverter from a map of OpenAPIV3 schemas.
|
||||
// This will automatically find the proper version of the object, and the
|
||||
// corresponding schema information.
|
||||
// The keys to the map must be consistent with the names
|
||||
// used by Refs within the schemas.
|
||||
// The schemas should conform to the Kubernetes Structural Schema OpenAPI
|
||||
// restrictions found in docs:
|
||||
// https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema
|
||||
func NewTypeConverter(openapiSpec map[string]*spec.Schema, preserveUnknownFields bool) (TypeConverter, error) {
|
||||
return internal.NewTypeConverter(openapiSpec, preserveUnknownFields)
|
||||
}
|
Reference in New Issue
Block a user