...

Source file src/k8s.io/kubernetes/pkg/registry/core/namespace/strategy.go

Documentation: k8s.io/kubernetes/pkg/registry/core/namespace

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package namespace
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/fields"
    25  	"k8s.io/apimachinery/pkg/labels"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apimachinery/pkg/util/validation/field"
    28  	"k8s.io/apiserver/pkg/registry/generic"
    29  	apistorage "k8s.io/apiserver/pkg/storage"
    30  	"k8s.io/apiserver/pkg/storage/names"
    31  	"k8s.io/kubernetes/pkg/api/legacyscheme"
    32  	api "k8s.io/kubernetes/pkg/apis/core"
    33  	"k8s.io/kubernetes/pkg/apis/core/validation"
    34  	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
    35  )
    36  
    37  // namespaceStrategy implements behavior for Namespaces
    38  type namespaceStrategy struct {
    39  	runtime.ObjectTyper
    40  	names.NameGenerator
    41  }
    42  
    43  // Strategy is the default logic that applies when creating and updating Namespace
    44  // objects via the REST API.
    45  var Strategy = namespaceStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
    46  
    47  // NamespaceScoped is false for namespaces.
    48  func (namespaceStrategy) NamespaceScoped() bool {
    49  	return false
    50  }
    51  
    52  // GetResetFields returns the set of fields that get reset by the strategy
    53  // and should not be modified by the user.
    54  func (namespaceStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
    55  	return map[fieldpath.APIVersion]*fieldpath.Set{
    56  		"v1": fieldpath.NewSet(
    57  			fieldpath.MakePathOrDie("status"),
    58  		),
    59  	}
    60  }
    61  
    62  // PrepareForCreate clears fields that are not allowed to be set by end users on creation.
    63  func (namespaceStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
    64  	// on create, status is active
    65  	namespace := obj.(*api.Namespace)
    66  	namespace.Status = api.NamespaceStatus{
    67  		Phase: api.NamespaceActive,
    68  	}
    69  	// on create, we require the kubernetes value
    70  	// we cannot use this in defaults conversion because we let it get removed over life of object
    71  	hasKubeFinalizer := false
    72  	for i := range namespace.Spec.Finalizers {
    73  		if namespace.Spec.Finalizers[i] == api.FinalizerKubernetes {
    74  			hasKubeFinalizer = true
    75  			break
    76  		}
    77  	}
    78  	if !hasKubeFinalizer {
    79  		if len(namespace.Spec.Finalizers) == 0 {
    80  			namespace.Spec.Finalizers = []api.FinalizerName{api.FinalizerKubernetes}
    81  		} else {
    82  			namespace.Spec.Finalizers = append(namespace.Spec.Finalizers, api.FinalizerKubernetes)
    83  		}
    84  	}
    85  }
    86  
    87  // PrepareForUpdate clears fields that are not allowed to be set by end users on update.
    88  func (namespaceStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
    89  	newNamespace := obj.(*api.Namespace)
    90  	oldNamespace := old.(*api.Namespace)
    91  	newNamespace.Spec.Finalizers = oldNamespace.Spec.Finalizers
    92  	newNamespace.Status = oldNamespace.Status
    93  }
    94  
    95  // Validate validates a new namespace.
    96  func (namespaceStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
    97  	namespace := obj.(*api.Namespace)
    98  	return validation.ValidateNamespace(namespace)
    99  }
   100  
   101  // WarningsOnCreate returns warnings for the creation of the given object.
   102  func (namespaceStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
   103  	return nil
   104  }
   105  
   106  // Canonicalize normalizes the object after validation.
   107  func (namespaceStrategy) Canonicalize(obj runtime.Object) {
   108  	// Ensure the label matches the name for namespaces just created using GenerateName,
   109  	// where the final name wasn't available for defaulting to make this change.
   110  	// This code needs to be kept in sync with the implementation that exists
   111  	// in Namespace defaulting (pkg/apis/core/v1)
   112  	// Why this hook *and* defaults.go?
   113  	//
   114  	// CREATE:
   115  	// Defaulting and PrepareForCreate happen before generateName is completed
   116  	// (i.e. the name is not yet known). Validation happens after generateName
   117  	// but should not modify objects. Canonicalize happens later, which makes
   118  	// it the best hook for setting the label.
   119  	//
   120  	// UPDATE:
   121  	// Defaulting and Canonicalize will both trigger with the full name.
   122  	//
   123  	// GET:
   124  	// Only defaulting will be applied.
   125  	ns := obj.(*api.Namespace)
   126  	if ns.Labels == nil {
   127  		ns.Labels = map[string]string{}
   128  	}
   129  	ns.Labels[v1.LabelMetadataName] = ns.Name
   130  }
   131  
   132  // AllowCreateOnUpdate is false for namespaces.
   133  func (namespaceStrategy) AllowCreateOnUpdate() bool {
   134  	return false
   135  }
   136  
   137  // ValidateUpdate is the default update validation for an end user.
   138  func (namespaceStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   139  	errorList := validation.ValidateNamespace(obj.(*api.Namespace))
   140  	return append(errorList, validation.ValidateNamespaceUpdate(obj.(*api.Namespace), old.(*api.Namespace))...)
   141  }
   142  
   143  // WarningsOnUpdate returns warnings for the given update.
   144  func (namespaceStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
   145  	return nil
   146  }
   147  
   148  func (namespaceStrategy) AllowUnconditionalUpdate() bool {
   149  	return true
   150  }
   151  
   152  type namespaceStatusStrategy struct {
   153  	namespaceStrategy
   154  }
   155  
   156  var StatusStrategy = namespaceStatusStrategy{Strategy}
   157  
   158  // GetResetFields returns the set of fields that get reset by the strategy
   159  // and should not be modified by the user.
   160  func (namespaceStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
   161  	return map[fieldpath.APIVersion]*fieldpath.Set{
   162  		"v1": fieldpath.NewSet(
   163  			fieldpath.MakePathOrDie("spec"),
   164  		),
   165  	}
   166  }
   167  
   168  func (namespaceStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
   169  	newNamespace := obj.(*api.Namespace)
   170  	oldNamespace := old.(*api.Namespace)
   171  	newNamespace.Spec = oldNamespace.Spec
   172  }
   173  
   174  func (namespaceStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   175  	return validation.ValidateNamespaceStatusUpdate(obj.(*api.Namespace), old.(*api.Namespace))
   176  }
   177  
   178  // WarningsOnUpdate returns warnings for the given update.
   179  func (namespaceStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
   180  	return nil
   181  }
   182  
   183  type namespaceFinalizeStrategy struct {
   184  	namespaceStrategy
   185  }
   186  
   187  var FinalizeStrategy = namespaceFinalizeStrategy{Strategy}
   188  
   189  func (namespaceFinalizeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
   190  	return validation.ValidateNamespaceFinalizeUpdate(obj.(*api.Namespace), old.(*api.Namespace))
   191  }
   192  
   193  // WarningsOnUpdate returns warnings for the given update.
   194  func (namespaceFinalizeStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
   195  	return nil
   196  }
   197  
   198  // GetResetFields returns the set of fields that get reset by the strategy
   199  // and should not be modified by the user.
   200  func (namespaceFinalizeStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
   201  	return map[fieldpath.APIVersion]*fieldpath.Set{
   202  		"v1": fieldpath.NewSet(
   203  			fieldpath.MakePathOrDie("status"),
   204  		),
   205  	}
   206  }
   207  
   208  // PrepareForUpdate clears fields that are not allowed to be set by end users on update.
   209  func (namespaceFinalizeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
   210  	newNamespace := obj.(*api.Namespace)
   211  	oldNamespace := old.(*api.Namespace)
   212  	newNamespace.Status = oldNamespace.Status
   213  }
   214  
   215  // GetAttrs returns labels and fields of a given object for filtering purposes.
   216  func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
   217  	namespaceObj, ok := obj.(*api.Namespace)
   218  	if !ok {
   219  		return nil, nil, fmt.Errorf("not a namespace")
   220  	}
   221  	return labels.Set(namespaceObj.Labels), NamespaceToSelectableFields(namespaceObj), nil
   222  }
   223  
   224  // MatchNamespace returns a generic matcher for a given label and field selector.
   225  func MatchNamespace(label labels.Selector, field fields.Selector) apistorage.SelectionPredicate {
   226  	return apistorage.SelectionPredicate{
   227  		Label:    label,
   228  		Field:    field,
   229  		GetAttrs: GetAttrs,
   230  	}
   231  }
   232  
   233  // NamespaceToSelectableFields returns a field set that represents the object
   234  func NamespaceToSelectableFields(namespace *api.Namespace) fields.Set {
   235  	objectMetaFieldsSet := generic.ObjectMetaFieldsSet(&namespace.ObjectMeta, false)
   236  	specificFieldsSet := fields.Set{
   237  		"status.phase": string(namespace.Status.Phase),
   238  		// This is a bug, but we need to support it for backward compatibility.
   239  		"name": namespace.Name,
   240  	}
   241  	return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)
   242  }
   243  

View as plain text