... | ... |
@@ -26,13 +26,9 @@ var KnownValidationExceptions = []reflect.Type{ |
26 | 26 |
// MissingValidationExceptions is the list of types that were missing validation methods when I started |
27 | 27 |
// You should never add to this list |
28 | 28 |
var MissingValidationExceptions = []reflect.Type{ |
29 |
- reflect.TypeOf(&buildapi.BuildLogOptions{}), // TODO, looks like this one should have validation |
|
30 |
- reflect.TypeOf(&buildapi.BuildLog{}), // TODO, I have no idea what this is doing |
|
31 |
- reflect.TypeOf(&buildapi.BuildRequest{}), // TODO, looks to be used internally, but needs review |
|
32 |
- reflect.TypeOf(&imageapi.ImageStreamMapping{}), // TODO, looks like this one should have validation |
|
33 |
- reflect.TypeOf(&imageapi.DockerImage{}), // TODO, I think this type is ok to skip validation (internal), but needs review |
|
34 |
- reflect.TypeOf(&authorizationapi.SubjectAccessReview{}), // TODO, this one should have validation |
|
35 |
- reflect.TypeOf(&authorizationapi.ResourceAccessReview{}), // TODO, this one should have validation |
|
29 |
+ reflect.TypeOf(&buildapi.BuildLogOptions{}), // TODO, looks like this one should have validation |
|
30 |
+ reflect.TypeOf(&buildapi.BuildLog{}), // TODO, I have no idea what this is doing |
|
31 |
+ reflect.TypeOf(&imageapi.DockerImage{}), // TODO, I think this type is ok to skip validation (internal), but needs review |
|
36 | 32 |
} |
37 | 33 |
|
38 | 34 |
func TestCoverage(t *testing.T) { |
... | ... |
@@ -25,6 +25,9 @@ import ( |
25 | 25 |
) |
26 | 26 |
|
27 | 27 |
func init() { |
28 |
+ Validator.Register(&authorizationapi.SubjectAccessReview{}, authorizationvalidation.ValidateSubjectAccessReview, nil) |
|
29 |
+ Validator.Register(&authorizationapi.ResourceAccessReview{}, authorizationvalidation.ValidateResourceAccessReview, nil) |
|
30 |
+ |
|
28 | 31 |
Validator.Register(&authorizationapi.Policy{}, authorizationvalidation.ValidateLocalPolicy, authorizationvalidation.ValidateLocalPolicyUpdate) |
29 | 32 |
Validator.Register(&authorizationapi.PolicyBinding{}, authorizationvalidation.ValidateLocalPolicyBinding, authorizationvalidation.ValidateLocalPolicyBindingUpdate) |
30 | 33 |
Validator.Register(&authorizationapi.Role{}, authorizationvalidation.ValidateLocalRole, authorizationvalidation.ValidateLocalRoleUpdate) |
... | ... |
@@ -35,14 +38,16 @@ func init() { |
35 | 35 |
Validator.Register(&authorizationapi.ClusterRole{}, authorizationvalidation.ValidateClusterRole, authorizationvalidation.ValidateClusterRoleUpdate) |
36 | 36 |
Validator.Register(&authorizationapi.ClusterRoleBinding{}, authorizationvalidation.ValidateClusterRoleBinding, authorizationvalidation.ValidateClusterRoleBindingUpdate) |
37 | 37 |
|
38 |
- Validator.Register(&buildapi.Build{}, buildvalidation.ValidateBuild, nil) |
|
39 |
- Validator.Register(&buildapi.BuildConfig{}, buildvalidation.ValidateBuildConfig, nil) |
|
38 |
+ Validator.Register(&buildapi.Build{}, buildvalidation.ValidateBuild, buildvalidation.ValidateBuildUpdate) |
|
39 |
+ Validator.Register(&buildapi.BuildConfig{}, buildvalidation.ValidateBuildConfig, buildvalidation.ValidateBuildConfigUpdate) |
|
40 |
+ Validator.Register(&buildapi.BuildRequest{}, buildvalidation.ValidateBuildRequest, nil) |
|
40 | 41 |
|
41 | 42 |
Validator.Register(&deployapi.DeploymentConfig{}, deployvalidation.ValidateDeploymentConfig, deployvalidation.ValidateDeploymentConfigUpdate) |
42 | 43 |
Validator.Register(&deployapi.DeploymentConfigRollback{}, deployvalidation.ValidateDeploymentConfigRollback, nil) |
43 | 44 |
|
44 | 45 |
Validator.Register(&imageapi.Image{}, imagevalidation.ValidateImage, nil) |
45 | 46 |
Validator.Register(&imageapi.ImageStream{}, imagevalidation.ValidateImageStream, imagevalidation.ValidateImageStreamUpdate) |
47 |
+ Validator.Register(&imageapi.ImageStreamMapping{}, imagevalidation.ValidateImageStreamMapping, nil) |
|
46 | 48 |
|
47 | 49 |
Validator.Register(&oauthapi.OAuthAccessToken{}, oauthvalidation.ValidateAccessToken, nil) |
48 | 50 |
Validator.Register(&oauthapi.OAuthAuthorizeToken{}, oauthvalidation.ValidateAuthorizeToken, nil) |
... | ... |
@@ -52,7 +57,7 @@ func init() { |
52 | 52 |
Validator.Register(&projectapi.Project{}, projectvalidation.ValidateProject, projectvalidation.ValidateProjectUpdate) |
53 | 53 |
Validator.Register(&projectapi.ProjectRequest{}, projectvalidation.ValidateProjectRequest, nil) |
54 | 54 |
|
55 |
- Validator.Register(&routeapi.Route{}, routevalidation.ValidateRoute, nil) |
|
55 |
+ Validator.Register(&routeapi.Route{}, routevalidation.ValidateRoute, routevalidation.ValidateRouteUpdate) |
|
56 | 56 |
|
57 | 57 |
Validator.Register(&sdnapi.ClusterNetwork{}, sdnvalidation.ValidateClusterNetwork, sdnvalidation.ValidateClusterNetworkUpdate) |
58 | 58 |
Validator.Register(&sdnapi.HostSubnet{}, sdnvalidation.ValidateHostSubnet, sdnvalidation.ValidateHostSubnetUpdate) |
... | ... |
@@ -25,10 +25,15 @@ type RuntimeObjectsValidator struct { |
25 | 25 |
} |
26 | 26 |
|
27 | 27 |
type RuntimeObjectValidatorInfo struct { |
28 |
- validator RuntimeObjectValidator |
|
29 |
- isNamespaced bool |
|
30 |
- hasObjectMeta bool |
|
31 |
- updateAllowed bool |
|
28 |
+ Validator RuntimeObjectValidator |
|
29 |
+ IsNamespaced bool |
|
30 |
+ HasObjectMeta bool |
|
31 |
+ UpdateAllowed bool |
|
32 |
+} |
|
33 |
+ |
|
34 |
+func (v *RuntimeObjectsValidator) GetInfo(obj runtime.Object) (RuntimeObjectValidatorInfo, bool) { |
|
35 |
+ ret, ok := v.typeToValidator[reflect.TypeOf(obj)] |
|
36 |
+ return ret, ok |
|
32 | 37 |
} |
33 | 38 |
|
34 | 39 |
func (v *RuntimeObjectsValidator) Register(obj runtime.Object, validateFunction interface{}, validateUpdateFunction interface{}) error { |
... | ... |
@@ -67,7 +72,7 @@ func (v *RuntimeObjectsValidator) Validate(obj runtime.Object) fielderrors.Valid |
67 | 67 |
return allErrs |
68 | 68 |
} |
69 | 69 |
|
70 |
- allErrs = append(allErrs, specificValidationInfo.validator.Validate(obj)...) |
|
70 |
+ allErrs = append(allErrs, specificValidationInfo.Validator.Validate(obj)...) |
|
71 | 71 |
return allErrs |
72 | 72 |
} |
73 | 73 |
|
... | ... |
@@ -87,11 +92,11 @@ func (v *RuntimeObjectsValidator) ValidateUpdate(obj, old runtime.Object) fielde |
87 | 87 |
return allErrs |
88 | 88 |
} |
89 | 89 |
|
90 |
- allErrs = append(allErrs, specificValidationInfo.validator.ValidateUpdate(obj, old)...) |
|
90 |
+ allErrs = append(allErrs, specificValidationInfo.Validator.ValidateUpdate(obj, old)...) |
|
91 | 91 |
|
92 | 92 |
// no errors so far, make sure that the new object is actually valid against the original validator |
93 | 93 |
if len(allErrs) == 0 { |
94 |
- allErrs = append(allErrs, specificValidationInfo.validator.Validate(obj)...) |
|
94 |
+ allErrs = append(allErrs, specificValidationInfo.Validator.Validate(obj)...) |
|
95 | 95 |
} |
96 | 96 |
|
97 | 97 |
return allErrs |
... | ... |
@@ -17,7 +17,7 @@ import ( |
17 | 17 |
|
18 | 18 |
func TestNameFunc(t *testing.T) { |
19 | 19 |
for apiType, validationInfo := range Validator.typeToValidator { |
20 |
- if !validationInfo.hasObjectMeta { |
|
20 |
+ if !validationInfo.HasObjectMeta { |
|
21 | 21 |
continue |
22 | 22 |
} |
23 | 23 |
|
... | ... |
@@ -28,7 +28,7 @@ func TestNameFunc(t *testing.T) { |
28 | 28 |
for _, illegalName := range api.NameMayNotBe { |
29 | 29 |
apiObjectMeta.Set(reflect.ValueOf(kapi.ObjectMeta{Name: illegalName})) |
30 | 30 |
|
31 |
- errList := validationInfo.validator.Validate(apiValue.Interface().(runtime.Object)) |
|
31 |
+ errList := validationInfo.Validator.Validate(apiValue.Interface().(runtime.Object)) |
|
32 | 32 |
_, requiredMessage := api.MinimalNameRequirements(illegalName, false) |
33 | 33 |
|
34 | 34 |
if len(errList) == 0 { |
... | ... |
@@ -65,7 +65,7 @@ func TestNameFunc(t *testing.T) { |
65 | 65 |
|
66 | 66 |
apiObjectMeta.Set(reflect.ValueOf(kapi.ObjectMeta{Name: illegalName})) |
67 | 67 |
|
68 |
- errList := validationInfo.validator.Validate(apiValue.Interface().(runtime.Object)) |
|
68 |
+ errList := validationInfo.Validator.Validate(apiValue.Interface().(runtime.Object)) |
|
69 | 69 |
_, requiredMessage := api.MinimalNameRequirements(illegalName, false) |
70 | 70 |
|
71 | 71 |
if len(errList) == 0 { |
... | ... |
@@ -99,21 +99,21 @@ func TestNameFunc(t *testing.T) { |
99 | 99 |
|
100 | 100 |
func TestObjectMeta(t *testing.T) { |
101 | 101 |
for apiType, validationInfo := range Validator.typeToValidator { |
102 |
- if !validationInfo.hasObjectMeta { |
|
102 |
+ if !validationInfo.HasObjectMeta { |
|
103 | 103 |
continue |
104 | 104 |
} |
105 | 105 |
|
106 | 106 |
apiValue := reflect.New(apiType.Elem()) |
107 | 107 |
apiObjectMeta := apiValue.Elem().FieldByName("ObjectMeta") |
108 | 108 |
|
109 |
- if validationInfo.isNamespaced { |
|
109 |
+ if validationInfo.IsNamespaced { |
|
110 | 110 |
apiObjectMeta.Set(reflect.ValueOf(kapi.ObjectMeta{Name: getValidName(apiType)})) |
111 | 111 |
} else { |
112 | 112 |
apiObjectMeta.Set(reflect.ValueOf(kapi.ObjectMeta{Name: getValidName(apiType), Namespace: kapi.NamespaceDefault})) |
113 | 113 |
} |
114 | 114 |
|
115 |
- errList := validationInfo.validator.Validate(apiValue.Interface().(runtime.Object)) |
|
116 |
- requiredErrors := validation.ValidateObjectMeta(apiObjectMeta.Addr().Interface().(*kapi.ObjectMeta), validationInfo.isNamespaced, api.MinimalNameRequirements).Prefix("metadata") |
|
115 |
+ errList := validationInfo.Validator.Validate(apiValue.Interface().(runtime.Object)) |
|
116 |
+ requiredErrors := validation.ValidateObjectMeta(apiObjectMeta.Addr().Interface().(*kapi.ObjectMeta), validationInfo.IsNamespaced, api.MinimalNameRequirements).Prefix("metadata") |
|
117 | 117 |
|
118 | 118 |
if len(errList) == 0 { |
119 | 119 |
t.Errorf("expected errors %v in %v not found amongst %v. You probably need to call kube/validation.ValidateObjectMeta in your validator.", requiredErrors, apiType.Elem(), errList) |
... | ... |
@@ -164,10 +164,10 @@ func getValidName(apiType reflect.Type) string { |
164 | 164 |
// 4. mismatched UID |
165 | 165 |
func TestObjectMetaUpdate(t *testing.T) { |
166 | 166 |
for apiType, validationInfo := range Validator.typeToValidator { |
167 |
- if !validationInfo.hasObjectMeta { |
|
167 |
+ if !validationInfo.HasObjectMeta { |
|
168 | 168 |
continue |
169 | 169 |
} |
170 |
- if !validationInfo.updateAllowed { |
|
170 |
+ if !validationInfo.UpdateAllowed { |
|
171 | 171 |
continue |
172 | 172 |
} |
173 | 173 |
|
... | ... |
@@ -183,7 +183,7 @@ func TestObjectMetaUpdate(t *testing.T) { |
183 | 183 |
newObj := newAPIValue.Interface().(runtime.Object) |
184 | 184 |
newObjMeta := newAPIObjectMeta.Addr().Interface().(*kapi.ObjectMeta) |
185 | 185 |
|
186 |
- errList := validationInfo.validator.ValidateUpdate(newObj, oldObj) |
|
186 |
+ errList := validationInfo.Validator.ValidateUpdate(newObj, oldObj) |
|
187 | 187 |
requiredErrors := validation.ValidateObjectMetaUpdate(newObjMeta, oldObjMeta).Prefix("metadata") |
188 | 188 |
|
189 | 189 |
if len(errList) == 0 { |
... | ... |
@@ -9,6 +9,32 @@ import ( |
9 | 9 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
10 | 10 |
) |
11 | 11 |
|
12 |
+func ValidateSubjectAccessReview(review *authorizationapi.SubjectAccessReview) fielderrors.ValidationErrorList { |
|
13 |
+ allErrs := fielderrors.ValidationErrorList{} |
|
14 |
+ |
|
15 |
+ if len(review.Verb) == 0 { |
|
16 |
+ allErrs = append(allErrs, fielderrors.NewFieldRequired("verb")) |
|
17 |
+ } |
|
18 |
+ if len(review.Resource) == 0 { |
|
19 |
+ allErrs = append(allErrs, fielderrors.NewFieldRequired("resource")) |
|
20 |
+ } |
|
21 |
+ |
|
22 |
+ return allErrs |
|
23 |
+} |
|
24 |
+ |
|
25 |
+func ValidateResourceAccessReview(review *authorizationapi.ResourceAccessReview) fielderrors.ValidationErrorList { |
|
26 |
+ allErrs := fielderrors.ValidationErrorList{} |
|
27 |
+ |
|
28 |
+ if len(review.Verb) == 0 { |
|
29 |
+ allErrs = append(allErrs, fielderrors.NewFieldRequired("verb")) |
|
30 |
+ } |
|
31 |
+ if len(review.Resource) == 0 { |
|
32 |
+ allErrs = append(allErrs, fielderrors.NewFieldRequired("resource")) |
|
33 |
+ } |
|
34 |
+ |
|
35 |
+ return allErrs |
|
36 |
+} |
|
37 |
+ |
|
12 | 38 |
func ValidatePolicyName(name string, prefix bool) (bool, string) { |
13 | 39 |
if ok, reason := oapi.MinimalNameRequirements(name, prefix); !ok { |
14 | 40 |
return ok, reason |
... | ... |
@@ -5,8 +5,10 @@ import ( |
5 | 5 |
|
6 | 6 |
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
7 | 7 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" |
8 |
+ kutilerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors" |
|
8 | 9 |
|
9 | 10 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
11 |
+ authorizationvalidation "github.com/openshift/origin/pkg/authorization/api/validation" |
|
10 | 12 |
"github.com/openshift/origin/pkg/authorization/authorizer" |
11 | 13 |
) |
12 | 14 |
|
... | ... |
@@ -31,6 +33,9 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err |
31 | 31 |
if !ok { |
32 | 32 |
return nil, fmt.Errorf("not a resourceAccessReview: %#v", obj) |
33 | 33 |
} |
34 |
+ if err := kutilerrors.NewAggregate(authorizationvalidation.ValidateResourceAccessReview(resourceAccessReview)); err != nil { |
|
35 |
+ return nil, err |
|
36 |
+ } |
|
34 | 37 |
|
35 | 38 |
namespace := kapi.NamespaceValue(ctx) |
36 | 39 |
|
... | ... |
@@ -7,8 +7,10 @@ import ( |
7 | 7 |
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
8 | 8 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/user" |
9 | 9 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" |
10 |
+ kutilerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors" |
|
10 | 11 |
|
11 | 12 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
13 |
+ authorizationvalidation "github.com/openshift/origin/pkg/authorization/api/validation" |
|
12 | 14 |
"github.com/openshift/origin/pkg/authorization/authorizer" |
13 | 15 |
) |
14 | 16 |
|
... | ... |
@@ -33,6 +35,9 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err |
33 | 33 |
if !ok { |
34 | 34 |
return nil, fmt.Errorf("not a subjectAccessReview: %#v", obj) |
35 | 35 |
} |
36 |
+ if err := kutilerrors.NewAggregate(authorizationvalidation.ValidateSubjectAccessReview(subjectAccessReview)); err != nil { |
|
37 |
+ return nil, err |
|
38 |
+ } |
|
36 | 39 |
|
37 | 40 |
var userToCheck user.Info |
38 | 41 |
if (len(subjectAccessReview.User) == 0) && (len(subjectAccessReview.Groups) == 0) { |
... | ... |
@@ -22,6 +22,14 @@ func ValidateBuild(build *buildapi.Build) fielderrors.ValidationErrorList { |
22 | 22 |
return allErrs |
23 | 23 |
} |
24 | 24 |
|
25 |
+func ValidateBuildUpdate(build *buildapi.Build, older *buildapi.Build) fielderrors.ValidationErrorList { |
|
26 |
+ allErrs := fielderrors.ValidationErrorList{} |
|
27 |
+ allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(&build.ObjectMeta, &older.ObjectMeta).Prefix("metadata")...) |
|
28 |
+ |
|
29 |
+ allErrs = append(allErrs, ValidateBuild(build)...) |
|
30 |
+ return allErrs |
|
31 |
+} |
|
32 |
+ |
|
25 | 33 |
// ValidateBuildConfig tests required fields for a Build. |
26 | 34 |
func ValidateBuildConfig(config *buildapi.BuildConfig) fielderrors.ValidationErrorList { |
27 | 35 |
allErrs := fielderrors.ValidationErrorList{} |
... | ... |
@@ -43,6 +51,14 @@ func ValidateBuildConfig(config *buildapi.BuildConfig) fielderrors.ValidationErr |
43 | 43 |
return allErrs |
44 | 44 |
} |
45 | 45 |
|
46 |
+func ValidateBuildConfigUpdate(config *buildapi.BuildConfig, older *buildapi.BuildConfig) fielderrors.ValidationErrorList { |
|
47 |
+ allErrs := fielderrors.ValidationErrorList{} |
|
48 |
+ allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(&config.ObjectMeta, &older.ObjectMeta).Prefix("metadata")...) |
|
49 |
+ |
|
50 |
+ allErrs = append(allErrs, ValidateBuildConfig(config)...) |
|
51 |
+ return allErrs |
|
52 |
+} |
|
53 |
+ |
|
46 | 54 |
// ValidateBuildRequest validates a BuildRequest object |
47 | 55 |
func ValidateBuildRequest(request *buildapi.BuildRequest) fielderrors.ValidationErrorList { |
48 | 56 |
allErrs := fielderrors.ValidationErrorList{} |
... | ... |
@@ -75,8 +75,7 @@ func (strategy) Validate(ctx kapi.Context, obj runtime.Object) fielderrors.Valid |
75 | 75 |
|
76 | 76 |
// ValidateUpdate is the default update validation for an end user. |
77 | 77 |
func (strategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) fielderrors.ValidationErrorList { |
78 |
- // TODO: distinguish updates from create, for now, this is preserving old implementation behavior |
|
79 |
- return validation.ValidateBuild(obj.(*api.Build)) |
|
78 |
+ return validation.ValidateBuildUpdate(obj.(*api.Build), old.(*api.Build)) |
|
80 | 79 |
} |
81 | 80 |
|
82 | 81 |
// CheckGracefulDelete allows a build to be gracefully deleted. |
... | ... |
@@ -45,6 +45,8 @@ func TestBuildStrategy(t *testing.T) { |
45 | 45 |
if len(errs) != 0 { |
46 | 46 |
t.Errorf("Unexpected error validating %v", errs) |
47 | 47 |
} |
48 |
+ |
|
49 |
+ build.ResourceVersion = "foo" |
|
48 | 50 |
errs = Strategy.ValidateUpdate(ctx, build, build) |
49 | 51 |
if len(errs) != 0 { |
50 | 52 |
t.Errorf("Unexpected error validating %v", errs) |
... | ... |
@@ -49,8 +49,7 @@ func (strategy) Validate(ctx kapi.Context, obj runtime.Object) fielderrors.Valid |
49 | 49 |
|
50 | 50 |
// ValidateUpdate is the default update validation for an end user. |
51 | 51 |
func (strategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) fielderrors.ValidationErrorList { |
52 |
- // TODO: distinguish updates from create, for now, this is preserving old implementation behavior |
|
53 |
- return validation.ValidateBuildConfig(obj.(*api.BuildConfig)) |
|
52 |
+ return validation.ValidateBuildConfigUpdate(obj.(*api.BuildConfig), old.(*api.BuildConfig)) |
|
54 | 53 |
} |
55 | 54 |
|
56 | 55 |
// Matcher returns a generic matcher for a given label and field selector. |
... | ... |
@@ -40,6 +40,8 @@ func TestBuildConfigStrategy(t *testing.T) { |
40 | 40 |
if len(errs) != 0 { |
41 | 41 |
t.Errorf("Unexpected error validating %v", errs) |
42 | 42 |
} |
43 |
+ |
|
44 |
+ buildConfig.ResourceVersion = "foo" |
|
43 | 45 |
errs = Strategy.ValidateUpdate(ctx, buildConfig, buildConfig) |
44 | 46 |
if len(errs) != 0 { |
45 | 47 |
t.Errorf("Unexpected error validating %v", errs) |
... | ... |
@@ -105,6 +105,7 @@ func ValidateImageStreamStatusUpdate(newStream, oldStream *api.ImageStream) fiel |
105 | 105 |
// ValidateImageStreamMapping tests required fields for an ImageStreamMapping. |
106 | 106 |
func ValidateImageStreamMapping(mapping *api.ImageStreamMapping) fielderrors.ValidationErrorList { |
107 | 107 |
result := fielderrors.ValidationErrorList{} |
108 |
+ result = append(result, validation.ValidateObjectMeta(&mapping.ObjectMeta, true, oapi.MinimalNameRequirements).Prefix("metadata")...) |
|
108 | 109 |
|
109 | 110 |
hasRepository := len(mapping.DockerImageRepository) != 0 |
110 | 111 |
hasName := len(mapping.Name) != 0 |
... | ... |
@@ -4,6 +4,7 @@ import ( |
4 | 4 |
"fmt" |
5 | 5 |
"strings" |
6 | 6 |
|
7 |
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" |
|
7 | 8 |
kval "github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation" |
8 | 9 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
9 | 10 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/fielderrors" |
... | ... |
@@ -41,6 +42,14 @@ func ValidateRoute(route *routeapi.Route) fielderrors.ValidationErrorList { |
41 | 41 |
return result |
42 | 42 |
} |
43 | 43 |
|
44 |
+func ValidateRouteUpdate(route *routeapi.Route, older *routeapi.Route) fielderrors.ValidationErrorList { |
|
45 |
+ allErrs := fielderrors.ValidationErrorList{} |
|
46 |
+ allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(&route.ObjectMeta, &older.ObjectMeta).Prefix("metadata")...) |
|
47 |
+ |
|
48 |
+ allErrs = append(allErrs, ValidateRoute(route)...) |
|
49 |
+ return allErrs |
|
50 |
+} |
|
51 |
+ |
|
44 | 52 |
// ValidateTLS tests fields for different types of TLS combinations are set. Called |
45 | 53 |
// by ValidateRoute. |
46 | 54 |
func validateTLS(route *routeapi.Route) fielderrors.ValidationErrorList { |
... | ... |
@@ -121,7 +121,11 @@ func (rs *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bo |
121 | 121 |
return nil, false, errors.NewConflict("route", route.Namespace, fmt.Errorf("Route.Namespace does not match the provided context")) |
122 | 122 |
} |
123 | 123 |
|
124 |
- if errs := validation.ValidateRoute(route); len(errs) > 0 { |
|
124 |
+ old, err := rs.Get(ctx, route.Name) |
|
125 |
+ if err != nil { |
|
126 |
+ return nil, false, err |
|
127 |
+ } |
|
128 |
+ if errs := validation.ValidateRouteUpdate(route, old.(*api.Route)); len(errs) > 0 { |
|
125 | 129 |
return nil, false, errors.NewInvalid("route", route.Name, errs) |
126 | 130 |
} |
127 | 131 |
|
... | ... |
@@ -129,7 +133,7 @@ func (rs *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bo |
129 | 129 |
// TODO: Call ValidateRouteUpdate->ValidateObjectMetaUpdate |
130 | 130 |
// TODO: In the UpdateStrategy.PrepareForUpdate, set the HostGeneratedAnnotationKey annotation to "false" if the updated route object modifies the host |
131 | 131 |
|
132 |
- err := rs.registry.UpdateRoute(ctx, route) |
|
132 |
+ err = rs.registry.UpdateRoute(ctx, route) |
|
133 | 133 |
if err != nil { |
134 | 134 |
return nil, false, err |
135 | 135 |
} |
... | ... |
@@ -205,14 +205,26 @@ func TestUpdateRouteBadObject(t *testing.T) { |
205 | 205 |
} |
206 | 206 |
|
207 | 207 |
func TestUpdateRouteMissingID(t *testing.T) { |
208 |
- storage := REST{} |
|
208 |
+ mockRegistry := test.NewRouteRegistry() |
|
209 |
+ mockAllocator := ractest.NewTestRouteAllocationController() |
|
210 |
+ mockRegistry.Routes = &api.RouteList{ |
|
211 |
+ Items: []api.Route{ |
|
212 |
+ { |
|
213 |
+ ObjectMeta: kapi.ObjectMeta{Name: "foo"}, |
|
214 |
+ }, |
|
215 |
+ }, |
|
216 |
+ } |
|
217 |
+ storage := REST{ |
|
218 |
+ registry: mockRegistry, |
|
219 |
+ allocator: mockAllocator, |
|
220 |
+ } |
|
209 | 221 |
|
210 | 222 |
obj, created, err := storage.Update(kapi.NewDefaultContext(), &api.Route{}) |
211 | 223 |
if obj != nil || created { |
212 | 224 |
t.Errorf("Expected nil, got %v", obj) |
213 | 225 |
} |
214 |
- if strings.Index(err.Error(), "name: required value") == -1 { |
|
215 |
- t.Errorf("Expected 'name: required value' error, got %v", err) |
|
226 |
+ if strings.Index(err.Error(), "not found") == -1 { |
|
227 |
+ t.Errorf("Expected 'not found' error, got %v", err) |
|
216 | 228 |
} |
217 | 229 |
} |
218 | 230 |
|
... | ... |
@@ -240,7 +252,7 @@ func TestUpdateRouteOK(t *testing.T) { |
240 | 240 |
mockRepositoryRegistry.Routes = &api.RouteList{ |
241 | 241 |
Items: []api.Route{ |
242 | 242 |
{ |
243 |
- ObjectMeta: kapi.ObjectMeta{Name: "bar"}, |
|
243 |
+ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: kapi.NamespaceDefault}, |
|
244 | 244 |
Host: "www.frontend.com", |
245 | 245 |
ServiceName: "rubyservice", |
246 | 246 |
}, |
... | ... |
@@ -253,7 +265,7 @@ func TestUpdateRouteOK(t *testing.T) { |
253 | 253 |
} |
254 | 254 |
|
255 | 255 |
obj, created, err := storage.Update(kapi.NewDefaultContext(), &api.Route{ |
256 |
- ObjectMeta: kapi.ObjectMeta{Name: "bar"}, |
|
256 |
+ ObjectMeta: kapi.ObjectMeta{Name: "bar", ResourceVersion: "foo"}, |
|
257 | 257 |
Host: "www.newfrontend.com", |
258 | 258 |
ServiceName: "newrubyservice", |
259 | 259 |
}) |
... | ... |
@@ -268,6 +280,7 @@ func TestUpdateRouteOK(t *testing.T) { |
268 | 268 |
if route == nil { |
269 | 269 |
t.Errorf("Nil route returned: %#v", route) |
270 | 270 |
t.Errorf("Expected Route, got %#v", obj) |
271 |
+ return |
|
271 | 272 |
} |
272 | 273 |
if route.Name != "bar" { |
273 | 274 |
t.Errorf("Unexpected route returned: %#v", route) |