Replace godep with dep

This commit is contained in:
Manuel de Brito Fontes 2017-10-06 17:26:14 -03:00
parent 1e7489927c
commit bf5616c65b
14883 changed files with 3937406 additions and 361781 deletions

View file

@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["validation_test.go"],
library = ":go_default_library",
deps = [
"//pkg/apis/admissionregistration:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["validation.go"],
deps = [
"//pkg/apis/admissionregistration:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View file

@ -0,0 +1,226 @@
/*
Copyright 2017 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 validation
import (
"fmt"
"strings"
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/apis/admissionregistration"
)
func ValidateInitializerConfiguration(ic *admissionregistration.InitializerConfiguration) field.ErrorList {
allErrors := genericvalidation.ValidateObjectMeta(&ic.ObjectMeta, false, genericvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))
for i, initializer := range ic.Initializers {
allErrors = append(allErrors, validateInitializer(&initializer, field.NewPath("initializers").Index(i))...)
}
return allErrors
}
func validateInitializer(initializer *admissionregistration.Initializer, fldPath *field.Path) field.ErrorList {
var allErrors field.ErrorList
// initlializer.Name must be fully qualified
allErrors = append(allErrors, validation.IsFullyQualifiedName(fldPath.Child("name"), initializer.Name)...)
for i, rule := range initializer.Rules {
notAllowSubresources := false
allErrors = append(allErrors, validateRule(&rule, fldPath.Child("rules").Index(i), notAllowSubresources)...)
}
return allErrors
}
func hasWildcard(slice []string) bool {
for _, s := range slice {
if s == "*" {
return true
}
}
return false
}
func validateResources(resources []string, fldPath *field.Path) field.ErrorList {
var allErrors field.ErrorList
if len(resources) == 0 {
allErrors = append(allErrors, field.Required(fldPath, ""))
}
// */x
resourcesWithWildcardSubresoures := sets.String{}
// x/*
subResoucesWithWildcardResource := sets.String{}
// */*
hasDoubleWildcard := false
// *
hasSingleWildcard := false
// x
hasResourceWithoutSubresource := false
for i, resSub := range resources {
if resSub == "" {
allErrors = append(allErrors, field.Required(fldPath.Index(i), ""))
continue
}
if resSub == "*/*" {
hasDoubleWildcard = true
}
if resSub == "*" {
hasSingleWildcard = true
}
parts := strings.SplitN(resSub, "/", 2)
if len(parts) == 1 {
hasResourceWithoutSubresource = resSub != "*"
continue
}
res, sub := parts[0], parts[1]
if _, ok := resourcesWithWildcardSubresoures[res]; ok {
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 {
allErrors = append(allErrors, field.Invalid(fldPath.Index(i), resSub, fmt.Sprintf("if '*/%s' is present, must not specify %s", sub, resSub)))
}
if sub == "*" {
resourcesWithWildcardSubresoures[res] = struct{}{}
}
if res == "*" {
subResoucesWithWildcardResource[sub] = struct{}{}
}
}
if len(resources) > 1 && hasDoubleWildcard {
allErrors = append(allErrors, field.Invalid(fldPath, resources, "if '*/*' is present, must not specify other resources"))
}
if hasSingleWildcard && hasResourceWithoutSubresource {
allErrors = append(allErrors, field.Invalid(fldPath, resources, "if '*' is present, must not specify other resources without subresources"))
}
return allErrors
}
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
if len(rule.APIGroups) == 0 {
allErrors = append(allErrors, field.Required(fldPath.Child("apiGroups"), ""))
}
if len(rule.APIGroups) > 1 && hasWildcard(rule.APIGroups) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("apiGroups"), rule.APIGroups, "if '*' is present, must not specify other API groups"))
}
// Note: group could be empty, e.g., the legacy "v1" API
if len(rule.APIVersions) == 0 {
allErrors = append(allErrors, field.Required(fldPath.Child("apiVersions"), ""))
}
if len(rule.APIVersions) > 1 && hasWildcard(rule.APIVersions) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("apiVersions"), rule.APIVersions, "if '*' is present, must not specify other API versions"))
}
for i, version := range rule.APIVersions {
if version == "" {
allErrors = append(allErrors, field.Required(fldPath.Child("apiVersions").Index(i), ""))
}
}
if allowSubResource {
allErrors = append(allErrors, validateResources(rule.Resources, fldPath.Child("resources"))...)
} else {
allErrors = append(allErrors, validateResourcesNoSubResources(rule.Resources, fldPath.Child("resources"))...)
}
return allErrors
}
func ValidateInitializerConfigurationUpdate(newIC, oldIC *admissionregistration.InitializerConfiguration) field.ErrorList {
return ValidateInitializerConfiguration(newIC)
}
func ValidateExternalAdmissionHookConfiguration(e *admissionregistration.ExternalAdmissionHookConfiguration) field.ErrorList {
allErrors := genericvalidation.ValidateObjectMeta(&e.ObjectMeta, false, genericvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))
for i, hook := range e.ExternalAdmissionHooks {
allErrors = append(allErrors, validateExternalAdmissionHook(&hook, field.NewPath("externalAdmissionHooks").Index(i))...)
}
return allErrors
}
func validateExternalAdmissionHook(hook *admissionregistration.ExternalAdmissionHook, fldPath *field.Path) field.ErrorList {
var allErrors field.ErrorList
// hook.Name must be fully qualified
allErrors = append(allErrors, validation.IsFullyQualifiedName(fldPath.Child("name"), hook.Name)...)
for i, rule := range hook.Rules {
allErrors = append(allErrors, validateRuleWithOperations(&rule, fldPath.Child("rules").Index(i))...)
}
// TODO: relax the validation rule when admissionregistration is beta.
if hook.FailurePolicy != nil && *hook.FailurePolicy != admissionregistration.Ignore {
allErrors = append(allErrors, field.NotSupported(fldPath.Child("failurePolicy"), *hook.FailurePolicy, []string{string(admissionregistration.Ignore)}))
}
return allErrors
}
var supportedOperations = sets.NewString(
string(admissionregistration.OperationAll),
string(admissionregistration.Create),
string(admissionregistration.Update),
string(admissionregistration.Delete),
string(admissionregistration.Connect),
)
func hasWildcardOperation(operations []admissionregistration.OperationType) bool {
for _, o := range operations {
if o == admissionregistration.OperationAll {
return true
}
}
return false
}
func validateRuleWithOperations(ruleWithOperations *admissionregistration.RuleWithOperations, fldPath *field.Path) field.ErrorList {
var allErrors field.ErrorList
if len(ruleWithOperations.Operations) == 0 {
allErrors = append(allErrors, field.Required(fldPath.Child("operations"), ""))
}
if len(ruleWithOperations.Operations) > 1 && hasWildcardOperation(ruleWithOperations.Operations) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("operations"), ruleWithOperations.Operations, "if '*' is present, must not specify other operations"))
}
for i, operation := range ruleWithOperations.Operations {
if !supportedOperations.Has(string(operation)) {
allErrors = append(allErrors, field.NotSupported(fldPath.Child("operations").Index(i), operation, supportedOperations.List()))
}
}
allowSubResource := true
allErrors = append(allErrors, validateRule(&ruleWithOperations.Rule, fldPath, allowSubResource)...)
return allErrors
}
func ValidateExternalAdmissionHookConfigurationUpdate(newC, oldC *admissionregistration.ExternalAdmissionHookConfiguration) field.ErrorList {
return ValidateExternalAdmissionHookConfiguration(newC)
}

View file

@ -0,0 +1,499 @@
/*
Copyright 2017 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 validation
import (
"strings"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/apis/admissionregistration"
)
func getInitializerConfiguration(initializers []admissionregistration.Initializer) *admissionregistration.InitializerConfiguration {
return &admissionregistration.InitializerConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "config",
},
Initializers: initializers,
}
}
func TestValidateInitializerConfiguration(t *testing.T) {
tests := []struct {
name string
config *admissionregistration.InitializerConfiguration
expectedError string
}{
{
name: "0 rule is valid",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
},
}),
},
{
name: "all initializers must have a fully qualified name",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
},
{
Name: "k8s.io",
},
{
Name: "",
},
}),
expectedError: `initializers[1].name: Invalid value: "k8s.io": should be a domain with at least three segments separated by dots, initializers[2].name: Required value`,
},
{
name: "APIGroups must not be empty or nil",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
Rules: []admissionregistration.Rule{
{
APIGroups: []string{},
APIVersions: []string{"a"},
Resources: []string{"a"},
},
{
APIGroups: nil,
APIVersions: []string{"a"},
Resources: []string{"a"},
},
},
},
}),
expectedError: `initializers[0].rules[0].apiGroups: Required value, initializers[0].rules[1].apiGroups: Required value`,
},
{
name: "APIVersions must not be empty or nil",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
Rules: []admissionregistration.Rule{
{
APIGroups: []string{"a"},
APIVersions: []string{},
Resources: []string{"a"},
},
{
APIGroups: []string{"a"},
APIVersions: nil,
Resources: []string{"a"},
},
},
},
}),
expectedError: `initializers[0].rules[0].apiVersions: Required value, initializers[0].rules[1].apiVersions: Required value`,
},
{
name: "Resources must not be empty or nil",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
Rules: []admissionregistration.Rule{
{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{},
},
{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: nil,
},
},
},
}),
expectedError: `initializers[0].rules[0].resources: Required value, initializers[0].rules[1].resources: Required value`,
},
{
name: "\"\" is a valid APIGroup",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
Rules: []admissionregistration.Rule{
{
APIGroups: []string{"a", ""},
APIVersions: []string{"a"},
Resources: []string{"a"},
},
},
},
}),
},
{
name: "\"\" is NOT a valid APIVersion",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
Rules: []admissionregistration.Rule{
{
APIGroups: []string{"a"},
APIVersions: []string{"a", ""},
Resources: []string{"a"},
},
},
},
}),
expectedError: "apiVersions[1]: Required value",
},
{
name: "\"\" is NOT a valid Resource",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
Rules: []admissionregistration.Rule{
{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"a", ""},
},
},
},
}),
expectedError: "resources[1]: Required value",
},
{
name: "wildcard cannot be mixed with other strings for APIGroups or APIVersions or Resources",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
Rules: []admissionregistration.Rule{
{
APIGroups: []string{"a", "*"},
APIVersions: []string{"a", "*"},
Resources: []string{"a", "*"},
},
},
},
}),
expectedError: `[initializers[0].rules[0].apiGroups: Invalid value: []string{"a", "*"}: if '*' is present, must not specify other API groups, initializers[0].rules[0].apiVersions: Invalid value: []string{"a", "*"}: if '*' is present, must not specify other API versions, initializers[0].rules[0].resources: Invalid value: []string{"a", "*"}: if '*' is present, must not specify other resources]`,
},
{
name: "Subresource not allowed",
config: getInitializerConfiguration(
[]admissionregistration.Initializer{
{
Name: "initializer.k8s.io",
Rules: []admissionregistration.Rule{
{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"a/b"},
},
},
},
}),
expectedError: ` "a/b": must not specify subresources`,
},
}
for _, test := range tests {
errs := ValidateInitializerConfiguration(test.config)
err := errs.ToAggregate()
if err != nil {
if e, a := test.expectedError, err.Error(); !strings.Contains(a, e) || e == "" {
t.Errorf("test case %s, expected to contain %s, got %s", test.name, e, a)
}
} else {
if test.expectedError != "" {
t.Errorf("test case %s, unexpected no error, expected to contain %s", test.name, test.expectedError)
}
}
}
}
func getExternalAdmissionHookConfiguration(hooks []admissionregistration.ExternalAdmissionHook) *admissionregistration.ExternalAdmissionHookConfiguration {
return &admissionregistration.ExternalAdmissionHookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "config",
},
ExternalAdmissionHooks: hooks,
}
}
func TestValidateExternalAdmissionHookConfiguration(t *testing.T) {
tests := []struct {
name string
config *admissionregistration.ExternalAdmissionHookConfiguration
expectedError string
}{
{
name: "all ExternalAdmissionHook must have a fully qualified name",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
},
{
Name: "k8s.io",
},
{
Name: "",
},
}),
expectedError: `externalAdmissionHooks[1].name: Invalid value: "k8s.io": should be a domain with at least three segments separated by dots, externalAdmissionHooks[2].name: Required value`,
},
{
name: "Operations must not be empty or nil",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"a"},
},
},
{
Operations: nil,
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"a"},
},
},
},
},
}),
expectedError: `externalAdmissionHooks[0].rules[0].operations: Required value, externalAdmissionHooks[0].rules[1].operations: Required value`,
},
{
name: "\"\" is NOT a valid operation",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{"CREATE", ""},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"a"},
},
},
},
},
}),
expectedError: `Unsupported value: ""`,
},
{
name: "operation must be either create/update/delete/connect",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{"PATCH"},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"a"},
},
},
},
},
}),
expectedError: `Unsupported value: "PATCH"`,
},
{
name: "wildcard operation cannot be mixed with other strings",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{"CREATE", "*"},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"a"},
},
},
},
},
}),
expectedError: `if '*' is present, must not specify other operations`,
},
{
name: `resource "*" can co-exist with resources that have subresources`,
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{"CREATE"},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"*", "a/b", "a/*", "*/b"},
},
},
},
},
}),
},
{
name: `resource "*" cannot mix with resources that don't have subresources`,
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{"CREATE"},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"*", "a"},
},
},
},
},
}),
expectedError: `if '*' is present, must not specify other resources without subresources`,
},
{
name: "resource a/* cannot mix with a/x",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{"CREATE"},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"a/*", "a/x"},
},
},
},
},
}),
expectedError: `externalAdmissionHooks[0].rules[0].resources[1]: Invalid value: "a/x": if 'a/*' is present, must not specify a/x`,
},
{
name: "resource a/* can mix with a",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{"CREATE"},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"a/*", "a"},
},
},
},
},
}),
},
{
name: "resource */a cannot mix with x/a",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{"CREATE"},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"*/a", "x/a"},
},
},
},
},
}),
expectedError: `externalAdmissionHooks[0].rules[0].resources[1]: Invalid value: "x/a": if '*/a' is present, must not specify x/a`,
},
{
name: "resource */* cannot mix with other resources",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
Rules: []admissionregistration.RuleWithOperations{
{
Operations: []admissionregistration.OperationType{"CREATE"},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"*/*", "a"},
},
},
},
},
}),
expectedError: `externalAdmissionHooks[0].rules[0].resources: Invalid value: []string{"*/*", "a"}: if '*/*' is present, must not specify other resources`,
},
{
name: "FailurePolicy can only be \"Ignore\"",
config: getExternalAdmissionHookConfiguration(
[]admissionregistration.ExternalAdmissionHook{
{
Name: "webhook.k8s.io",
FailurePolicy: func() *admissionregistration.FailurePolicyType {
r := admissionregistration.Fail
return &r
}(),
},
}),
expectedError: `failurePolicy: Unsupported value: "Fail": supported values: Ignore`,
},
}
for _, test := range tests {
errs := ValidateExternalAdmissionHookConfiguration(test.config)
err := errs.ToAggregate()
if err != nil {
if e, a := test.expectedError, err.Error(); !strings.Contains(a, e) || e == "" {
t.Errorf("test case %s, expected to contain %s, got %s", test.name, e, a)
}
} else {
if test.expectedError != "" {
t.Errorf("test case %s, unexpected no error, expected to contain %s", test.name, test.expectedError)
}
}
}
}