Commit 80a53d52 authored by Chao Xu's avatar Chao Xu

do not allow subresources in initializer rules

parent ab3e7a73
...@@ -64,6 +64,7 @@ type Initializer struct { ...@@ -64,6 +64,7 @@ type Initializer struct {
// Rules describes what resources/subresources the initializer cares about. // Rules describes what resources/subresources the initializer cares about.
// The initializer cares about an operation if it matches _any_ Rule. // The initializer cares about an operation if it matches _any_ Rule.
// Rule.Resources must not include subresources.
Rules []Rule Rules []Rule
// FailurePolicy defines what happens if the responsible initializer controller // FailurePolicy defines what happens if the responsible initializer controller
...@@ -97,7 +98,10 @@ type Rule struct { ...@@ -97,7 +98,10 @@ type Rule struct {
// '*/scale' means all scale subresources. // '*/scale' means all scale subresources.
// '*/*' means all resources and their subresources. // '*/*' means all resources and their subresources.
// //
// If '*' or '*/*' is present, the length of the slice must be one. // If wildcard is present, the validation rule will ensure resources do not
// overlap with each other.
//
// Depending on the enclosing object, subresources might not be allowed.
// Required. // Required.
Resources []string Resources []string
} }
......
...@@ -66,6 +66,7 @@ type Initializer struct { ...@@ -66,6 +66,7 @@ type Initializer struct {
// Rules describes what resources/subresources the initializer cares about. // Rules describes what resources/subresources the initializer cares about.
// The initializer cares about an operation if it matches _any_ Rule. // The initializer cares about an operation if it matches _any_ Rule.
// Rule.Resources must not include subresources.
Rules []Rule `json:"rules,omitempty" protobuf:"bytes,2,rep,name=rules"` Rules []Rule `json:"rules,omitempty" protobuf:"bytes,2,rep,name=rules"`
// FailurePolicy defines what happens if the responsible initializer controller // FailurePolicy defines what happens if the responsible initializer controller
...@@ -99,7 +100,10 @@ type Rule struct { ...@@ -99,7 +100,10 @@ type Rule struct {
// '*/scale' means all scale subresources. // '*/scale' means all scale subresources.
// '*/*' means all resources and their subresources. // '*/*' means all resources and their subresources.
// //
// If '*' or '*/*' is present, the length of the slice must be one. // If wildcard is present, the validation rule will ensure resources do not
// overlap with each other.
//
// Depending on the enclosing object, subresources might not be allowed.
// Required. // Required.
Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"` Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"`
} }
......
...@@ -49,7 +49,8 @@ func validateInitializer(initializer *admissionregistration.Initializer, fldPath ...@@ -49,7 +49,8 @@ func validateInitializer(initializer *admissionregistration.Initializer, fldPath
} }
for i, rule := range initializer.Rules { for i, rule := range initializer.Rules {
allErrors = append(allErrors, validateRule(&rule, fldPath.Child("rules").Index(i))...) notAllowSubresources := false
allErrors = append(allErrors, validateRule(&rule, fldPath.Child("rules").Index(i), notAllowSubresources)...)
} }
// TODO: relax the validation rule when admissionregistration is beta. // TODO: relax the validation rule when admissionregistration is beta.
if initializer.FailurePolicy != nil && *initializer.FailurePolicy != admissionregistration.Ignore { if initializer.FailurePolicy != nil && *initializer.FailurePolicy != admissionregistration.Ignore {
...@@ -102,10 +103,10 @@ func validateResources(resources []string, fldPath *field.Path) field.ErrorList ...@@ -102,10 +103,10 @@ func validateResources(resources []string, fldPath *field.Path) field.ErrorList
} }
res, sub := parts[0], parts[1] res, sub := parts[0], parts[1]
if _, ok := resourcesWithWildcardSubresoures[res]; ok { if _, ok := resourcesWithWildcardSubresoures[res]; ok {
allErrors = append(allErrors, field.Invalid(fldPath.Index(i), resources[i], fmt.Sprintf("if '%s/*' is present, must not specify %s", res, resources[i]))) allErrors = append(allErrors, field.Invalid(fldPath.Index(i), resSub, fmt.Sprintf("if '%s/*' is present, must not specify %s", res, resSub)))
} }
if _, ok := subResoucesWithWildcardResource[sub]; ok { if _, ok := subResoucesWithWildcardResource[sub]; ok {
allErrors = append(allErrors, field.Invalid(fldPath.Index(i), resources[i], fmt.Sprintf("if '*/%s' is present, must not specify %s", sub, resources[i]))) allErrors = append(allErrors, field.Invalid(fldPath.Index(i), resSub, fmt.Sprintf("if '*/%s' is present, must not specify %s", sub, resSub)))
} }
if sub == "*" { if sub == "*" {
resourcesWithWildcardSubresoures[res] = struct{}{} resourcesWithWildcardSubresoures[res] = struct{}{}
...@@ -123,7 +124,26 @@ func validateResources(resources []string, fldPath *field.Path) field.ErrorList ...@@ -123,7 +124,26 @@ func validateResources(resources []string, fldPath *field.Path) field.ErrorList
return allErrors return allErrors
} }
func validateRule(rule *admissionregistration.Rule, fldPath *field.Path) field.ErrorList { func validateResourcesNoSubResources(resources []string, fldPath *field.Path) field.ErrorList {
var allErrors field.ErrorList
if len(resources) == 0 {
allErrors = append(allErrors, field.Required(fldPath, ""))
}
for i, resource := range resources {
if resource == "" {
allErrors = append(allErrors, field.Required(fldPath.Index(i), ""))
}
if strings.Contains(resource, "/") {
allErrors = append(allErrors, field.Invalid(fldPath.Index(i), resource, "must not specify subresources"))
}
}
if len(resources) > 1 && hasWildcard(resources) {
allErrors = append(allErrors, field.Invalid(fldPath, resources, "if '*' is present, must not specify other resources"))
}
return allErrors
}
func validateRule(rule *admissionregistration.Rule, fldPath *field.Path, allowSubResource bool) field.ErrorList {
var allErrors field.ErrorList var allErrors field.ErrorList
if len(rule.APIGroups) == 0 { if len(rule.APIGroups) == 0 {
allErrors = append(allErrors, field.Required(fldPath.Child("apiGroups"), "")) allErrors = append(allErrors, field.Required(fldPath.Child("apiGroups"), ""))
...@@ -143,7 +163,11 @@ func validateRule(rule *admissionregistration.Rule, fldPath *field.Path) field.E ...@@ -143,7 +163,11 @@ func validateRule(rule *admissionregistration.Rule, fldPath *field.Path) field.E
allErrors = append(allErrors, field.Required(fldPath.Child("apiVersions").Index(i), "")) allErrors = append(allErrors, field.Required(fldPath.Child("apiVersions").Index(i), ""))
} }
} }
allErrors = append(allErrors, validateResources(rule.Resources, fldPath.Child("resources"))...) if allowSubResource {
allErrors = append(allErrors, validateResources(rule.Resources, fldPath.Child("resources"))...)
} else {
allErrors = append(allErrors, validateResourcesNoSubResources(rule.Resources, fldPath.Child("resources"))...)
}
return allErrors return allErrors
} }
...@@ -154,7 +178,7 @@ func ValidateInitializerConfigurationUpdate(newIC, oldIC *admissionregistration. ...@@ -154,7 +178,7 @@ func ValidateInitializerConfigurationUpdate(newIC, oldIC *admissionregistration.
func ValidateExternalAdmissionHookConfiguration(e *admissionregistration.ExternalAdmissionHookConfiguration) field.ErrorList { func ValidateExternalAdmissionHookConfiguration(e *admissionregistration.ExternalAdmissionHookConfiguration) field.ErrorList {
allErrors := genericvalidation.ValidateObjectMeta(&e.ObjectMeta, false, genericvalidation.NameIsDNSSubdomain, field.NewPath("metadata")) allErrors := genericvalidation.ValidateObjectMeta(&e.ObjectMeta, false, genericvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))
for i, hook := range e.ExternalAdmissionHooks { for i, hook := range e.ExternalAdmissionHooks {
allErrors = append(allErrors, validateExternalAdmissionHook(&hook, field.NewPath("externalAdmissionHook").Index(i))...) allErrors = append(allErrors, validateExternalAdmissionHook(&hook, field.NewPath("externalAdmissionHooks").Index(i))...)
} }
return allErrors return allErrors
} }
...@@ -212,7 +236,8 @@ func validateRuleWithOperations(ruleWithOperations *admissionregistration.RuleWi ...@@ -212,7 +236,8 @@ func validateRuleWithOperations(ruleWithOperations *admissionregistration.RuleWi
allErrors = append(allErrors, field.NotSupported(fldPath.Child("operations").Index(i), operation, supportedOperations.List())) allErrors = append(allErrors, field.NotSupported(fldPath.Child("operations").Index(i), operation, supportedOperations.List()))
} }
} }
allErrors = append(allErrors, validateRule(&ruleWithOperations.Rule, fldPath)...) allowSubResource := true
allErrors = append(allErrors, validateRule(&ruleWithOperations.Rule, fldPath, allowSubResource)...)
return allErrors return allErrors
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment