1/* 2Copyright 2016 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package apiservice 18 19import ( 20 "context" 21 "fmt" 22 23 "k8s.io/apimachinery/pkg/fields" 24 "k8s.io/apimachinery/pkg/labels" 25 "k8s.io/apimachinery/pkg/runtime" 26 "k8s.io/apimachinery/pkg/util/validation/field" 27 "k8s.io/apiserver/pkg/registry/generic" 28 "k8s.io/apiserver/pkg/registry/rest" 29 "k8s.io/apiserver/pkg/storage" 30 "k8s.io/apiserver/pkg/storage/names" 31 32 "k8s.io/kube-aggregator/pkg/apis/apiregistration" 33 "k8s.io/kube-aggregator/pkg/apis/apiregistration/validation" 34 "sigs.k8s.io/structured-merge-diff/v4/fieldpath" 35) 36 37type apiServerStrategy struct { 38 runtime.ObjectTyper 39 names.NameGenerator 40} 41 42// apiServerStrategy must implement rest.RESTCreateUpdateStrategy 43var _ rest.RESTCreateUpdateStrategy = apiServerStrategy{} 44var Strategy = apiServerStrategy{} 45 46// NewStrategy creates a new apiServerStrategy. 47func NewStrategy(typer runtime.ObjectTyper) rest.CreateUpdateResetFieldsStrategy { 48 return apiServerStrategy{typer, names.SimpleNameGenerator} 49} 50 51func (apiServerStrategy) NamespaceScoped() bool { 52 return false 53} 54 55func (apiServerStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 56 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 57 "apiregistration.k8s.io/v1": fieldpath.NewSet( 58 fieldpath.MakePathOrDie("status"), 59 ), 60 "apiregistration.k8s.io/v1beta1": fieldpath.NewSet( 61 fieldpath.MakePathOrDie("status"), 62 ), 63 } 64 65 return fields 66} 67 68func (apiServerStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { 69 apiservice := obj.(*apiregistration.APIService) 70 apiservice.Status = apiregistration.APIServiceStatus{} 71 72 // mark local API services as immediately available on create 73 if apiservice.Spec.Service == nil { 74 apiregistration.SetAPIServiceCondition(apiservice, apiregistration.NewLocalAvailableAPIServiceCondition()) 75 } 76} 77 78func (apiServerStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 79 newAPIService := obj.(*apiregistration.APIService) 80 oldAPIService := old.(*apiregistration.APIService) 81 newAPIService.Status = oldAPIService.Status 82} 83 84func (apiServerStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { 85 return validation.ValidateAPIService(obj.(*apiregistration.APIService)) 86} 87 88// WarningsOnCreate returns warnings for the creation of the given object. 89func (apiServerStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { 90 return nil 91} 92 93func (apiServerStrategy) AllowCreateOnUpdate() bool { 94 return false 95} 96 97func (apiServerStrategy) AllowUnconditionalUpdate() bool { 98 return false 99} 100 101func (apiServerStrategy) Canonicalize(obj runtime.Object) { 102} 103 104func (apiServerStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 105 return validation.ValidateAPIServiceUpdate(obj.(*apiregistration.APIService), old.(*apiregistration.APIService)) 106} 107 108// WarningsOnUpdate returns warnings for the given update. 109func (apiServerStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 110 return nil 111} 112 113type apiServerStatusStrategy struct { 114 runtime.ObjectTyper 115 names.NameGenerator 116} 117 118// NewStatusStrategy creates a new apiServerStatusStrategy. 119func NewStatusStrategy(typer runtime.ObjectTyper) rest.UpdateResetFieldsStrategy { 120 return apiServerStatusStrategy{typer, names.SimpleNameGenerator} 121} 122 123func (apiServerStatusStrategy) NamespaceScoped() bool { 124 return false 125} 126 127func (apiServerStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 128 fields := map[fieldpath.APIVersion]*fieldpath.Set{ 129 "apiregistration.k8s.io/v1": fieldpath.NewSet( 130 fieldpath.MakePathOrDie("spec"), 131 fieldpath.MakePathOrDie("metadata"), 132 ), 133 "apiregistration.k8s.io/v1beta1": fieldpath.NewSet( 134 fieldpath.MakePathOrDie("spec"), 135 fieldpath.MakePathOrDie("metadata"), 136 ), 137 } 138 139 return fields 140} 141 142func (apiServerStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { 143 newAPIService := obj.(*apiregistration.APIService) 144 oldAPIService := old.(*apiregistration.APIService) 145 newAPIService.Spec = oldAPIService.Spec 146 newAPIService.Labels = oldAPIService.Labels 147 newAPIService.Annotations = oldAPIService.Annotations 148 newAPIService.Finalizers = oldAPIService.Finalizers 149 newAPIService.OwnerReferences = oldAPIService.OwnerReferences 150} 151 152func (apiServerStatusStrategy) AllowCreateOnUpdate() bool { 153 return false 154} 155 156func (apiServerStatusStrategy) AllowUnconditionalUpdate() bool { 157 return false 158} 159 160// Canonicalize normalizes the object after validation. 161func (apiServerStatusStrategy) Canonicalize(obj runtime.Object) { 162} 163 164// ValidateUpdate validates an update of apiServerStatusStrategy. 165func (apiServerStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { 166 return validation.ValidateAPIServiceStatusUpdate(obj.(*apiregistration.APIService), old.(*apiregistration.APIService)) 167} 168 169// WarningsOnUpdate returns warnings for the given update. 170func (apiServerStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { 171 return nil 172} 173 174// GetAttrs returns the labels and fields of an API server for filtering purposes. 175func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { 176 apiserver, ok := obj.(*apiregistration.APIService) 177 if !ok { 178 return nil, nil, fmt.Errorf("given object is not a APIService") 179 } 180 return labels.Set(apiserver.ObjectMeta.Labels), ToSelectableFields(apiserver), nil 181} 182 183// MatchAPIService is the filter used by the generic etcd backend to watch events 184// from etcd to clients of the apiserver only interested in specific labels/fields. 185func MatchAPIService(label labels.Selector, field fields.Selector) storage.SelectionPredicate { 186 return storage.SelectionPredicate{ 187 Label: label, 188 Field: field, 189 GetAttrs: GetAttrs, 190 } 191} 192 193// ToSelectableFields returns a field set that represents the object. 194func ToSelectableFields(obj *apiregistration.APIService) fields.Set { 195 return generic.ObjectMetaFieldsSet(&obj.ObjectMeta, true) 196} 197