mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-13 11:25:19 +00:00
Introduce priority class in the resource quota
This commit is contained in:
committed by
vikaschoudhary16
parent
4c13f5fdf5
commit
3cfe6412c7
@@ -103,6 +103,7 @@ var standardResourceQuotaScopes = sets.NewString(
|
||||
string(core.ResourceQuotaScopeNotTerminating),
|
||||
string(core.ResourceQuotaScopeBestEffort),
|
||||
string(core.ResourceQuotaScopeNotBestEffort),
|
||||
string(core.ResourceQuotaScopePriorityClass),
|
||||
)
|
||||
|
||||
// IsStandardResourceQuotaScope returns true if the scope is a standard value
|
||||
@@ -126,7 +127,7 @@ var podComputeQuotaResources = sets.NewString(
|
||||
// IsResourceQuotaScopeValidForResource returns true if the resource applies to the specified scope
|
||||
func IsResourceQuotaScopeValidForResource(scope core.ResourceQuotaScope, resource string) bool {
|
||||
switch scope {
|
||||
case core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating, core.ResourceQuotaScopeNotBestEffort:
|
||||
case core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating, core.ResourceQuotaScopeNotBestEffort, core.ResourceQuotaScopePriorityClass:
|
||||
return podObjectCountQuotaResources.Has(resource) || podComputeQuotaResources.Has(resource)
|
||||
case core.ResourceQuotaScopeBestEffort:
|
||||
return podObjectCountQuotaResources.Has(resource)
|
||||
@@ -584,3 +585,28 @@ func PersistentVolumeClaimHasClass(claim *core.PersistentVolumeClaim) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// ScopedResourceSelectorRequirementsAsSelector converts the ScopedResourceSelectorRequirement api type into a struct that implements
|
||||
// labels.Selector.
|
||||
func ScopedResourceSelectorRequirementsAsSelector(ssr core.ScopedResourceSelectorRequirement) (labels.Selector, error) {
|
||||
selector := labels.NewSelector()
|
||||
var op selection.Operator
|
||||
switch ssr.Operator {
|
||||
case core.ScopeSelectorOpIn:
|
||||
op = selection.In
|
||||
case core.ScopeSelectorOpNotIn:
|
||||
op = selection.NotIn
|
||||
case core.ScopeSelectorOpExists:
|
||||
op = selection.Exists
|
||||
case core.ScopeSelectorOpDoesNotExist:
|
||||
op = selection.DoesNotExist
|
||||
default:
|
||||
return nil, fmt.Errorf("%q is not a valid scope selector operator", ssr.Operator)
|
||||
}
|
||||
r, err := labels.NewRequirement(string(ssr.ScopeName), op, ssr.Values)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
selector = selector.Add(*r)
|
||||
return selector, nil
|
||||
}
|
||||
|
||||
@@ -4168,6 +4168,8 @@ const (
|
||||
ResourceQuotaScopeBestEffort ResourceQuotaScope = "BestEffort"
|
||||
// Match all pod objects that do not have best effort quality of service
|
||||
ResourceQuotaScopeNotBestEffort ResourceQuotaScope = "NotBestEffort"
|
||||
// Match all pod objects that have priority class mentioned
|
||||
ResourceQuotaScopePriorityClass ResourceQuotaScope = "PriorityClass"
|
||||
)
|
||||
|
||||
// ResourceQuotaSpec defines the desired hard limits to enforce for Quota
|
||||
@@ -4179,8 +4181,47 @@ type ResourceQuotaSpec struct {
|
||||
// If not specified, the quota matches all objects.
|
||||
// +optional
|
||||
Scopes []ResourceQuotaScope
|
||||
// ScopeSelector is also a collection of filters like Scopes that must match each object tracked by a quota
|
||||
// but expressed using ScopeSelectorOperator in combination with possible values.
|
||||
// +optional
|
||||
ScopeSelector *ScopeSelector
|
||||
}
|
||||
|
||||
// A scope selector represents the AND of the selectors represented
|
||||
// by the scoped-resource selector terms.
|
||||
type ScopeSelector struct {
|
||||
// A list of scope selector requirements by scope of the resources.
|
||||
// +optional
|
||||
MatchExpressions []ScopedResourceSelectorRequirement
|
||||
}
|
||||
|
||||
// A scoped-resource selector requirement is a selector that contains values, a scope name, and an operator
|
||||
// that relates the scope name and values.
|
||||
type ScopedResourceSelectorRequirement struct {
|
||||
// The name of the scope that the selector applies to.
|
||||
ScopeName ResourceQuotaScope
|
||||
// Represents a scope's relationship to a set of values.
|
||||
// Valid operators are In, NotIn, Exists, DoesNotExist.
|
||||
Operator ScopeSelectorOperator
|
||||
// An array of string values. If the operator is In or NotIn,
|
||||
// the values array must be non-empty. If the operator is Exists or DoesNotExist,
|
||||
// the values array must be empty.
|
||||
// This array is replaced during a strategic merge patch.
|
||||
// +optional
|
||||
Values []string
|
||||
}
|
||||
|
||||
// A scope selector operator is the set of operators that can be used in
|
||||
// a scope selector requirement.
|
||||
type ScopeSelectorOperator string
|
||||
|
||||
const (
|
||||
ScopeSelectorOpIn ScopeSelectorOperator = "In"
|
||||
ScopeSelectorOpNotIn ScopeSelectorOperator = "NotIn"
|
||||
ScopeSelectorOpExists ScopeSelectorOperator = "Exists"
|
||||
ScopeSelectorOpDoesNotExist ScopeSelectorOperator = "DoesNotExist"
|
||||
)
|
||||
|
||||
// ResourceQuotaStatus defines the enforced hard limits and observed use
|
||||
type ResourceQuotaStatus struct {
|
||||
// Hard is the set of enforced hard limits for each named resource
|
||||
|
||||
50
pkg/apis/core/v1/zz_generated.conversion.go
generated
50
pkg/apis/core/v1/zz_generated.conversion.go
generated
@@ -354,6 +354,10 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
Convert_core_ScaleIOPersistentVolumeSource_To_v1_ScaleIOPersistentVolumeSource,
|
||||
Convert_v1_ScaleIOVolumeSource_To_core_ScaleIOVolumeSource,
|
||||
Convert_core_ScaleIOVolumeSource_To_v1_ScaleIOVolumeSource,
|
||||
Convert_v1_ScopeSelector_To_core_ScopeSelector,
|
||||
Convert_core_ScopeSelector_To_v1_ScopeSelector,
|
||||
Convert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement,
|
||||
Convert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement,
|
||||
Convert_v1_Secret_To_core_Secret,
|
||||
Convert_core_Secret_To_v1_Secret,
|
||||
Convert_v1_SecretEnvSource_To_core_SecretEnvSource,
|
||||
@@ -4641,6 +4645,7 @@ func Convert_core_ResourceQuotaList_To_v1_ResourceQuotaList(in *core.ResourceQuo
|
||||
func autoConvert_v1_ResourceQuotaSpec_To_core_ResourceQuotaSpec(in *v1.ResourceQuotaSpec, out *core.ResourceQuotaSpec, s conversion.Scope) error {
|
||||
out.Hard = *(*core.ResourceList)(unsafe.Pointer(&in.Hard))
|
||||
out.Scopes = *(*[]core.ResourceQuotaScope)(unsafe.Pointer(&in.Scopes))
|
||||
out.ScopeSelector = (*core.ScopeSelector)(unsafe.Pointer(in.ScopeSelector))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4652,6 +4657,7 @@ func Convert_v1_ResourceQuotaSpec_To_core_ResourceQuotaSpec(in *v1.ResourceQuota
|
||||
func autoConvert_core_ResourceQuotaSpec_To_v1_ResourceQuotaSpec(in *core.ResourceQuotaSpec, out *v1.ResourceQuotaSpec, s conversion.Scope) error {
|
||||
out.Hard = *(*v1.ResourceList)(unsafe.Pointer(&in.Hard))
|
||||
out.Scopes = *(*[]v1.ResourceQuotaScope)(unsafe.Pointer(&in.Scopes))
|
||||
out.ScopeSelector = (*v1.ScopeSelector)(unsafe.Pointer(in.ScopeSelector))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4806,6 +4812,50 @@ func Convert_core_ScaleIOVolumeSource_To_v1_ScaleIOVolumeSource(in *core.ScaleIO
|
||||
return autoConvert_core_ScaleIOVolumeSource_To_v1_ScaleIOVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_ScopeSelector_To_core_ScopeSelector(in *v1.ScopeSelector, out *core.ScopeSelector, s conversion.Scope) error {
|
||||
out.MatchExpressions = *(*[]core.ScopedResourceSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_ScopeSelector_To_core_ScopeSelector is an autogenerated conversion function.
|
||||
func Convert_v1_ScopeSelector_To_core_ScopeSelector(in *v1.ScopeSelector, out *core.ScopeSelector, s conversion.Scope) error {
|
||||
return autoConvert_v1_ScopeSelector_To_core_ScopeSelector(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_core_ScopeSelector_To_v1_ScopeSelector(in *core.ScopeSelector, out *v1.ScopeSelector, s conversion.Scope) error {
|
||||
out.MatchExpressions = *(*[]v1.ScopedResourceSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_core_ScopeSelector_To_v1_ScopeSelector is an autogenerated conversion function.
|
||||
func Convert_core_ScopeSelector_To_v1_ScopeSelector(in *core.ScopeSelector, out *v1.ScopeSelector, s conversion.Scope) error {
|
||||
return autoConvert_core_ScopeSelector_To_v1_ScopeSelector(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement(in *v1.ScopedResourceSelectorRequirement, out *core.ScopedResourceSelectorRequirement, s conversion.Scope) error {
|
||||
out.ScopeName = core.ResourceQuotaScope(in.ScopeName)
|
||||
out.Operator = core.ScopeSelectorOperator(in.Operator)
|
||||
out.Values = *(*[]string)(unsafe.Pointer(&in.Values))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement is an autogenerated conversion function.
|
||||
func Convert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement(in *v1.ScopedResourceSelectorRequirement, out *core.ScopedResourceSelectorRequirement, s conversion.Scope) error {
|
||||
return autoConvert_v1_ScopedResourceSelectorRequirement_To_core_ScopedResourceSelectorRequirement(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement(in *core.ScopedResourceSelectorRequirement, out *v1.ScopedResourceSelectorRequirement, s conversion.Scope) error {
|
||||
out.ScopeName = v1.ResourceQuotaScope(in.ScopeName)
|
||||
out.Operator = v1.ScopeSelectorOperator(in.Operator)
|
||||
out.Values = *(*[]string)(unsafe.Pointer(&in.Values))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement is an autogenerated conversion function.
|
||||
func Convert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement(in *core.ScopedResourceSelectorRequirement, out *v1.ScopedResourceSelectorRequirement, s conversion.Scope) error {
|
||||
return autoConvert_core_ScopedResourceSelectorRequirement_To_v1_ScopedResourceSelectorRequirement(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_Secret_To_core_Secret(in *v1.Secret, out *core.Secret, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
out.Data = *(*map[string][]byte)(unsafe.Pointer(&in.Data))
|
||||
|
||||
@@ -4786,6 +4786,74 @@ func validateResourceQuotaScopes(resourceQuotaSpec *core.ResourceQuotaSpec, fld
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validateScopedResourceSelectorRequirement tests that the match expressions has valid data
|
||||
func validateScopedResourceSelectorRequirement(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
hardLimits := sets.NewString()
|
||||
for k := range resourceQuotaSpec.Hard {
|
||||
hardLimits.Insert(string(k))
|
||||
}
|
||||
fldPath := fld.Child("matchExpressions")
|
||||
scopeSet := sets.NewString()
|
||||
for _, req := range resourceQuotaSpec.ScopeSelector.MatchExpressions {
|
||||
if !helper.IsStandardResourceQuotaScope(string(req.ScopeName)) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("scopeName"), req.ScopeName, "unsupported scope"))
|
||||
}
|
||||
for _, k := range hardLimits.List() {
|
||||
if helper.IsStandardQuotaResourceName(k) && !helper.IsResourceQuotaScopeValidForResource(req.ScopeName, k) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.ScopeSelector, "unsupported scope applied to resource"))
|
||||
}
|
||||
}
|
||||
switch req.ScopeName {
|
||||
case core.ResourceQuotaScopeBestEffort, core.ResourceQuotaScopeNotBestEffort, core.ResourceQuotaScopeTerminating, core.ResourceQuotaScopeNotTerminating:
|
||||
if req.Operator != core.ScopeSelectorOpExists {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), req.Operator,
|
||||
"must be 'Exist' only operator when scope is any of ResourceQuotaScopeTerminating, ResourceQuotaScopeNotTerminating, ResourceQuotaScopeBestEffort and ResourceQuotaScopeNotBestEffort"))
|
||||
}
|
||||
}
|
||||
|
||||
switch req.Operator {
|
||||
case core.ScopeSelectorOpIn, core.ScopeSelectorOpNotIn:
|
||||
if len(req.Values) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("values"),
|
||||
"must be atleast one value when `operator` is 'In' or 'NotIn' for scope selector"))
|
||||
}
|
||||
case core.ScopeSelectorOpExists, core.ScopeSelectorOpDoesNotExist:
|
||||
if len(req.Values) != 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("values"), req.Values,
|
||||
"must be no value when `operator` is 'Exist' or 'DoesNotExist' for scope selector"))
|
||||
}
|
||||
default:
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), req.Operator, "not a valid selector operator"))
|
||||
}
|
||||
scopeSet.Insert(string(req.ScopeName))
|
||||
}
|
||||
invalidScopePairs := []sets.String{
|
||||
sets.NewString(string(core.ResourceQuotaScopeBestEffort), string(core.ResourceQuotaScopeNotBestEffort)),
|
||||
sets.NewString(string(core.ResourceQuotaScopeTerminating), string(core.ResourceQuotaScopeNotTerminating)),
|
||||
}
|
||||
for _, invalidScopePair := range invalidScopePairs {
|
||||
if scopeSet.HasAll(invalidScopePair.List()...) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "conflicting scopes"))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// validateScopeSelector tests that the specified scope selector has valid data
|
||||
func validateScopeSelector(resourceQuotaSpec *core.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if resourceQuotaSpec.ScopeSelector == nil {
|
||||
return allErrs
|
||||
}
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ResourceQuotaScopeSelectors) && resourceQuotaSpec.ScopeSelector != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fld.Child("scopeSelector"), "ResourceQuotaScopeSelectors feature-gate is disabled"))
|
||||
}
|
||||
allErrs = append(allErrs, validateScopedResourceSelectorRequirement(resourceQuotaSpec, fld.Child("scopeSelector"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateResourceQuota tests if required fields in the ResourceQuota are set.
|
||||
func ValidateResourceQuota(resourceQuota *core.ResourceQuota) field.ErrorList {
|
||||
allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, field.NewPath("metadata"))
|
||||
@@ -4825,6 +4893,7 @@ func ValidateResourceQuotaSpec(resourceQuotaSpec *core.ResourceQuotaSpec, fld *f
|
||||
allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
|
||||
}
|
||||
allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuotaSpec, fld)...)
|
||||
allErrs = append(allErrs, validateScopeSelector(resourceQuotaSpec, fld)...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@@ -11508,6 +11508,18 @@ func TestValidateResourceQuota(t *testing.T) {
|
||||
Scopes: []core.ResourceQuotaScope{core.ResourceQuotaScopeNotBestEffort},
|
||||
}
|
||||
|
||||
scopeSelectorSpec := core.ResourceQuotaSpec{
|
||||
ScopeSelector: &core.ScopeSelector{
|
||||
MatchExpressions: []core.ScopedResourceSelectorRequirement{
|
||||
{
|
||||
ScopeName: core.ResourceQuotaScopePriorityClass,
|
||||
Operator: core.ScopeSelectorOpIn,
|
||||
Values: []string{"cluster-services"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// storage is not yet supported as a quota tracked resource
|
||||
invalidQuotaResourceSpec := core.ResourceQuotaSpec{
|
||||
Hard: core.ResourceList{
|
||||
@@ -11600,6 +11612,13 @@ func TestValidateResourceQuota(t *testing.T) {
|
||||
},
|
||||
Spec: bestEffortSpec,
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "abc",
|
||||
Namespace: "foo",
|
||||
},
|
||||
Spec: scopeSelectorSpec,
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "abc",
|
||||
@@ -11608,12 +11627,13 @@ func TestValidateResourceQuota(t *testing.T) {
|
||||
Spec: nonBestEffortSpec,
|
||||
},
|
||||
}
|
||||
|
||||
utilfeature.DefaultFeatureGate.Set("ResourceQuotaScopeSelectors=true")
|
||||
for _, successCase := range successCases {
|
||||
if errs := ValidateResourceQuota(&successCase); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
utilfeature.DefaultFeatureGate.Set("ResourceQuotaScopeSelectors=false")
|
||||
|
||||
errorCases := map[string]struct {
|
||||
R core.ResourceQuota
|
||||
@@ -11659,6 +11679,10 @@ func TestValidateResourceQuota(t *testing.T) {
|
||||
core.ResourceQuota{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: invalidScopeNameSpec},
|
||||
"unsupported scope",
|
||||
},
|
||||
"forbidden-quota-scope-selector": {
|
||||
core.ResourceQuota{ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "foo"}, Spec: scopeSelectorSpec},
|
||||
"feature-gate is disabled",
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
errs := ValidateResourceQuota(&v.R)
|
||||
|
||||
53
pkg/apis/core/zz_generated.deepcopy.go
generated
53
pkg/apis/core/zz_generated.deepcopy.go
generated
@@ -4630,6 +4630,15 @@ func (in *ResourceQuotaSpec) DeepCopyInto(out *ResourceQuotaSpec) {
|
||||
*out = make([]ResourceQuotaScope, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ScopeSelector != nil {
|
||||
in, out := &in.ScopeSelector, &out.ScopeSelector
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(ScopeSelector)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4769,6 +4778,50 @@ func (in *ScaleIOVolumeSource) DeepCopy() *ScaleIOVolumeSource {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ScopeSelector) DeepCopyInto(out *ScopeSelector) {
|
||||
*out = *in
|
||||
if in.MatchExpressions != nil {
|
||||
in, out := &in.MatchExpressions, &out.MatchExpressions
|
||||
*out = make([]ScopedResourceSelectorRequirement, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScopeSelector.
|
||||
func (in *ScopeSelector) DeepCopy() *ScopeSelector {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ScopeSelector)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ScopedResourceSelectorRequirement) DeepCopyInto(out *ScopedResourceSelectorRequirement) {
|
||||
*out = *in
|
||||
if in.Values != nil {
|
||||
in, out := &in.Values, &out.Values
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScopedResourceSelectorRequirement.
|
||||
func (in *ScopedResourceSelectorRequirement) DeepCopy() *ScopedResourceSelectorRequirement {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ScopedResourceSelectorRequirement)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Secret) DeepCopyInto(out *Secret) {
|
||||
*out = *in
|
||||
|
||||
Reference in New Issue
Block a user