Browse code

Refactors from upstream Kube changes

* Change signature of storage.Update in rest to accept
rest.DefaultObjectUpdatedInfo
* Validation now returns []string instead of (bool, string)
* Internal HPA group is now autoscaling, not extensions
* genericapiserver constants moved into genericapiserver/options
* api/errors now returns *StatusError instead of error
* All code accepts unversioned.GroupVersion now
* EncodeToStream became Encode
* Temporarily disable encoding round trippers

Clayton Coleman authored on 2016/07/03 07:06:13
Showing 171 changed files
... ...
@@ -7,7 +7,7 @@ import (
7 7
 
8 8
 	kapi "k8s.io/kubernetes/pkg/api"
9 9
 	"k8s.io/kubernetes/pkg/api/meta"
10
-	"k8s.io/kubernetes/pkg/apis/extensions"
10
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
11 11
 	"k8s.io/kubernetes/pkg/kubectl/resource"
12 12
 	"k8s.io/kubernetes/pkg/runtime"
13 13
 
... ...
@@ -58,7 +58,7 @@ func init() {
58 58
 	if err := RegisterEnsureNode(&kapi.ReplicationController{}, kubegraph.EnsureReplicationControllerNode); err != nil {
59 59
 		panic(err)
60 60
 	}
61
-	if err := RegisterEnsureNode(&extensions.HorizontalPodAutoscaler{}, kubegraph.EnsureHorizontalPodAutoscalerNode); err != nil {
61
+	if err := RegisterEnsureNode(&autoscaling.HorizontalPodAutoscaler{}, kubegraph.EnsureHorizontalPodAutoscalerNode); err != nil {
62 62
 		panic(err)
63 63
 	}
64 64
 	if err := RegisterEnsureNode(&routeapi.Route{}, routegraph.EnsureRouteNode); err != nil {
... ...
@@ -10,27 +10,27 @@ import (
10 10
 var NameMayNotBe = []string{".", ".."}
11 11
 var NameMayNotContain = []string{"/", "%"}
12 12
 
13
-func MinimalNameRequirements(name string, prefix bool) (bool, string) {
13
+func MinimalNameRequirements(name string, prefix bool) []string {
14 14
 	for _, illegalName := range NameMayNotBe {
15 15
 		if name == illegalName {
16
-			return false, fmt.Sprintf(`name may not be %q`, illegalName)
16
+			return []string{fmt.Sprintf(`name may not be %q`, illegalName)}
17 17
 		}
18 18
 	}
19 19
 
20 20
 	for _, illegalContent := range NameMayNotContain {
21 21
 		if strings.Contains(name, illegalContent) {
22
-			return false, fmt.Sprintf(`name may not contain %q`, illegalContent)
22
+			return []string{fmt.Sprintf(`name may not contain %q`, illegalContent)}
23 23
 		}
24 24
 	}
25 25
 
26
-	return true, ""
26
+	return nil
27 27
 }
28 28
 
29 29
 // GetNameValidationFunc returns a name validation function that includes the standard restrictions we want for all types
30 30
 func GetNameValidationFunc(nameFunc validation.ValidateNameFunc) validation.ValidateNameFunc {
31
-	return func(name string, prefix bool) (bool, string) {
32
-		if ok, reason := MinimalNameRequirements(name, prefix); !ok {
33
-			return ok, reason
31
+	return func(name string, prefix bool) []string {
32
+		if reasons := MinimalNameRequirements(name, prefix); len(reasons) != 0 {
33
+			return reasons
34 34
 		}
35 35
 
36 36
 		return nameFunc(name, prefix)
... ...
@@ -35,13 +35,13 @@ func FindHPASpecsMissingCPUTargets(graph osgraph.Graph, namer osgraph.Namer) []o
35 35
 	for _, uncastNode := range graph.NodesByKind(kubenodes.HorizontalPodAutoscalerNodeKind) {
36 36
 		node := uncastNode.(*kubenodes.HorizontalPodAutoscalerNode)
37 37
 
38
-		if node.HorizontalPodAutoscaler.Spec.CPUUtilization == nil {
38
+		if node.HorizontalPodAutoscaler.Spec.TargetCPUUtilizationPercentage == nil {
39 39
 			markers = append(markers, osgraph.Marker{
40 40
 				Node:       node,
41 41
 				Severity:   osgraph.ErrorSeverity,
42 42
 				Key:        HPAMissingCPUTargetError,
43 43
 				Message:    fmt.Sprintf("%s is missing a CPU utilization target", namer.ResourceName(node)),
44
-				Suggestion: osgraph.Suggestion(fmt.Sprintf(`oc patch %s -p '{"spec":{"cpuUtilization":{"targetPercentage": 80}}}'`, namer.ResourceName(node))),
44
+				Suggestion: osgraph.Suggestion(fmt.Sprintf(`oc patch %s -p '{"spec":{"targetCPUUtilizationPercentage": 80}}'`, namer.ResourceName(node))),
45 45
 			})
46 46
 		}
47 47
 	}
... ...
@@ -86,8 +86,8 @@ func createMissingScaleRefMarker(hpaNode *kubenodes.HorizontalPodAutoscalerNode,
86 86
 		Key:          HPAMissingScaleRefError,
87 87
 		Message: fmt.Sprintf("%s is attempting to scale %s/%s, which doesn't exist",
88 88
 			namer.ResourceName(hpaNode),
89
-			hpaNode.HorizontalPodAutoscaler.Spec.ScaleRef.Kind,
90
-			hpaNode.HorizontalPodAutoscaler.Spec.ScaleRef.Name,
89
+			hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.Kind,
90
+			hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.Name,
91 91
 		),
92 92
 	}
93 93
 }
... ...
@@ -29,7 +29,7 @@ func TestHPAMissingCPUTargetError(t *testing.T) {
29 29
 		t.Errorf("expected marker type %v, got %v", expected, actual)
30 30
 	}
31 31
 
32
-	patchString := `-p '{"spec":{"cpuUtilization":{"targetPercentage": 80}}}'`
32
+	patchString := `-p '{"spec":{"targetCPUUtilizationPercentage": 80}}'`
33 33
 	if !strings.HasSuffix(string(markers[0].Suggestion), patchString) {
34 34
 		t.Errorf("expected suggestion to end with patch JSON path, got %q", markers[0].Suggestion)
35 35
 	}
... ...
@@ -8,7 +8,7 @@ import (
8 8
 
9 9
 	kapi "k8s.io/kubernetes/pkg/api"
10 10
 	_ "k8s.io/kubernetes/pkg/api/install"
11
-	"k8s.io/kubernetes/pkg/apis/extensions"
11
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
12 12
 	"k8s.io/kubernetes/pkg/runtime"
13 13
 
14 14
 	osgraph "github.com/openshift/origin/pkg/api/graph"
... ...
@@ -130,11 +130,11 @@ func TestSecretEdges(t *testing.T) {
130 130
 }
131 131
 
132 132
 func TestHPARCEdges(t *testing.T) {
133
-	hpa := &extensions.HorizontalPodAutoscaler{}
133
+	hpa := &autoscaling.HorizontalPodAutoscaler{}
134 134
 	hpa.Namespace = "test-ns"
135 135
 	hpa.Name = "test-hpa"
136
-	hpa.Spec = extensions.HorizontalPodAutoscalerSpec{
137
-		ScaleRef: extensions.SubresourceReference{
136
+	hpa.Spec = autoscaling.HorizontalPodAutoscalerSpec{
137
+		ScaleTargetRef: autoscaling.CrossVersionObjectReference{
138 138
 			Name: "test-rc",
139 139
 			Kind: "ReplicationController",
140 140
 		},
... ...
@@ -160,11 +160,11 @@ func TestHPARCEdges(t *testing.T) {
160 160
 }
161 161
 
162 162
 func TestHPADCEdges(t *testing.T) {
163
-	hpa := &extensions.HorizontalPodAutoscaler{}
163
+	hpa := &autoscaling.HorizontalPodAutoscaler{}
164 164
 	hpa.Namespace = "test-ns"
165 165
 	hpa.Name = "test-hpa"
166
-	hpa.Spec = extensions.HorizontalPodAutoscalerSpec{
167
-		ScaleRef: extensions.SubresourceReference{
166
+	hpa.Spec = autoscaling.HorizontalPodAutoscalerSpec{
167
+		ScaleTargetRef: autoscaling.CrossVersionObjectReference{
168 168
 			Name: "test-dc",
169 169
 			Kind: "DeploymentConfig",
170 170
 		},
... ...
@@ -211,13 +211,13 @@ func AddHPAScaleRefEdges(g osgraph.Graph) {
211 211
 		hpaNode := node.(*kubegraph.HorizontalPodAutoscalerNode)
212 212
 
213 213
 		syntheticMeta := kapi.ObjectMeta{
214
-			Name:      hpaNode.HorizontalPodAutoscaler.Spec.ScaleRef.Name,
214
+			Name:      hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.Name,
215 215
 			Namespace: hpaNode.HorizontalPodAutoscaler.Namespace,
216 216
 		}
217 217
 
218 218
 		var groupVersionResource unversioned.GroupVersionResource
219
-		resource := strings.ToLower(hpaNode.HorizontalPodAutoscaler.Spec.ScaleRef.Kind)
220
-		if groupVersion, err := unversioned.ParseGroupVersion(hpaNode.HorizontalPodAutoscaler.Spec.ScaleRef.APIVersion); err == nil {
219
+		resource := strings.ToLower(hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.Kind)
220
+		if groupVersion, err := unversioned.ParseGroupVersion(hpaNode.HorizontalPodAutoscaler.Spec.ScaleTargetRef.APIVersion); err == nil {
221 221
 			groupVersionResource = groupVersion.WithResource(resource)
222 222
 		} else {
223 223
 			groupVersionResource = unversioned.GroupVersionResource{Resource: resource}
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"github.com/gonum/graph"
5 5
 
6 6
 	kapi "k8s.io/kubernetes/pkg/api"
7
-	"k8s.io/kubernetes/pkg/apis/extensions"
7
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
8 8
 
9 9
 	osgraph "github.com/openshift/origin/pkg/api/graph"
10 10
 )
... ...
@@ -146,7 +146,7 @@ func EnsurePodTemplateSpecNode(g osgraph.MutableUniqueGraph, ptSpec *kapi.PodTem
146 146
 	return ptSpecNode
147 147
 }
148 148
 
149
-func EnsureHorizontalPodAutoscalerNode(g osgraph.MutableUniqueGraph, hpa *extensions.HorizontalPodAutoscaler) *HorizontalPodAutoscalerNode {
149
+func EnsureHorizontalPodAutoscalerNode(g osgraph.MutableUniqueGraph, hpa *autoscaling.HorizontalPodAutoscaler) *HorizontalPodAutoscalerNode {
150 150
 	return osgraph.EnsureUnique(g,
151 151
 		HorizontalPodAutoscalerNodeName(hpa),
152 152
 		func(node osgraph.Node) graph.Node {
... ...
@@ -5,7 +5,7 @@ import (
5 5
 	"reflect"
6 6
 
7 7
 	kapi "k8s.io/kubernetes/pkg/api"
8
-	"k8s.io/kubernetes/pkg/apis/extensions"
8
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
9 9
 
10 10
 	osgraph "github.com/openshift/origin/pkg/api/graph"
11 11
 )
... ...
@@ -19,7 +19,7 @@ var (
19 19
 	ReplicationControllerSpecNodeKind = reflect.TypeOf(kapi.ReplicationControllerSpec{}).Name()
20 20
 	ServiceAccountNodeKind            = reflect.TypeOf(kapi.ServiceAccount{}).Name()
21 21
 	SecretNodeKind                    = reflect.TypeOf(kapi.Secret{}).Name()
22
-	HorizontalPodAutoscalerNodeKind   = reflect.TypeOf(extensions.HorizontalPodAutoscaler{}).Name()
22
+	HorizontalPodAutoscalerNodeKind   = reflect.TypeOf(autoscaling.HorizontalPodAutoscaler{}).Name()
23 23
 )
24 24
 
25 25
 func ServiceNodeName(o *kapi.Service) osgraph.UniqueName {
... ...
@@ -243,13 +243,13 @@ func (*SecretNode) Kind() string {
243 243
 	return SecretNodeKind
244 244
 }
245 245
 
246
-func HorizontalPodAutoscalerNodeName(o *extensions.HorizontalPodAutoscaler) osgraph.UniqueName {
246
+func HorizontalPodAutoscalerNodeName(o *autoscaling.HorizontalPodAutoscaler) osgraph.UniqueName {
247 247
 	return osgraph.GetUniqueRuntimeObjectNodeName(HorizontalPodAutoscalerNodeKind, o)
248 248
 }
249 249
 
250 250
 type HorizontalPodAutoscalerNode struct {
251 251
 	osgraph.Node
252
-	HorizontalPodAutoscaler *extensions.HorizontalPodAutoscaler
252
+	HorizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler
253 253
 }
254 254
 
255 255
 func (n HorizontalPodAutoscalerNode) Object() interface{} {
... ...
@@ -151,6 +151,14 @@ func (d *discoveryRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...
151 151
 	return delegate.RESTMapping(gk, versions...)
152 152
 }
153 153
 
154
+func (d *discoveryRESTMapper) RESTMappings(gk unversioned.GroupKind) ([]*meta.RESTMapping, error) {
155
+	delegate, err := d.getDelegate()
156
+	if err != nil {
157
+		return nil, err
158
+	}
159
+	return delegate.RESTMappings(gk)
160
+}
161
+
154 162
 func (d *discoveryRESTMapper) AliasesForResource(resource string) ([]string, bool) {
155 163
 	delegate, err := d.getDelegate()
156 164
 	if err != nil {
... ...
@@ -32,6 +32,7 @@ import (
32 32
 	quotaapi "github.com/openshift/origin/pkg/quota/api"
33 33
 	quotaapiv1 "github.com/openshift/origin/pkg/quota/api/v1"
34 34
 	route "github.com/openshift/origin/pkg/route/api"
35
+	securityapi "github.com/openshift/origin/pkg/security/api"
35 36
 	template "github.com/openshift/origin/pkg/template/api"
36 37
 	uservalidation "github.com/openshift/origin/pkg/user/api/validation"
37 38
 
... ...
@@ -65,21 +66,21 @@ func fuzzInternalObject(t *testing.T, forVersion unversioned.GroupVersion, item
65 65
 				switch j.Subjects[i].Kind {
66 66
 				case authorizationapi.UserKind:
67 67
 					j.Subjects[i].Namespace = ""
68
-					if valid, _ := uservalidation.ValidateUserName(j.Subjects[i].Name, false); !valid {
68
+					if len(uservalidation.ValidateUserName(j.Subjects[i].Name, false)) != 0 {
69 69
 						j.Subjects[i].Name = fmt.Sprintf("validusername%d", i)
70 70
 					}
71 71
 
72 72
 				case authorizationapi.GroupKind:
73 73
 					j.Subjects[i].Namespace = ""
74
-					if valid, _ := uservalidation.ValidateGroupName(j.Subjects[i].Name, false); !valid {
74
+					if len(uservalidation.ValidateGroupName(j.Subjects[i].Name, false)) != 0 {
75 75
 						j.Subjects[i].Name = fmt.Sprintf("validgroupname%d", i)
76 76
 					}
77 77
 
78 78
 				case authorizationapi.ServiceAccountKind:
79
-					if valid, _ := validation.ValidateNamespaceName(j.Subjects[i].Namespace, false); !valid {
79
+					if len(validation.ValidateNamespaceName(j.Subjects[i].Namespace, false)) != 0 {
80 80
 						j.Subjects[i].Namespace = fmt.Sprintf("sanamespacehere%d", i)
81 81
 					}
82
-					if valid, _ := validation.ValidateServiceAccountName(j.Subjects[i].Name, false); !valid {
82
+					if len(validation.ValidateServiceAccountName(j.Subjects[i].Name, false)) != 0 {
83 83
 						j.Subjects[i].Name = fmt.Sprintf("sanamehere%d", i)
84 84
 					}
85 85
 
... ...
@@ -110,21 +111,21 @@ func fuzzInternalObject(t *testing.T, forVersion unversioned.GroupVersion, item
110 110
 				switch j.Subjects[i].Kind {
111 111
 				case authorizationapi.UserKind:
112 112
 					j.Subjects[i].Namespace = ""
113
-					if valid, _ := uservalidation.ValidateUserName(j.Subjects[i].Name, false); !valid {
113
+					if len(uservalidation.ValidateUserName(j.Subjects[i].Name, false)) != 0 {
114 114
 						j.Subjects[i].Name = fmt.Sprintf("validusername%d", i)
115 115
 					}
116 116
 
117 117
 				case authorizationapi.GroupKind:
118 118
 					j.Subjects[i].Namespace = ""
119
-					if valid, _ := uservalidation.ValidateGroupName(j.Subjects[i].Name, false); !valid {
119
+					if len(uservalidation.ValidateGroupName(j.Subjects[i].Name, false)) != 0 {
120 120
 						j.Subjects[i].Name = fmt.Sprintf("validgroupname%d", i)
121 121
 					}
122 122
 
123 123
 				case authorizationapi.ServiceAccountKind:
124
-					if valid, _ := validation.ValidateNamespaceName(j.Subjects[i].Namespace, false); !valid {
124
+					if len(validation.ValidateNamespaceName(j.Subjects[i].Namespace, false)) != 0 {
125 125
 						j.Subjects[i].Namespace = fmt.Sprintf("sanamespacehere%d", i)
126 126
 					}
127
-					if valid, _ := validation.ValidateServiceAccountName(j.Subjects[i].Name, false); !valid {
127
+					if len(validation.ValidateServiceAccountName(j.Subjects[i].Name, false)) != 0 {
128 128
 						j.Subjects[i].Name = fmt.Sprintf("sanamehere%d", i)
129 129
 					}
130 130
 
... ...
@@ -340,6 +341,27 @@ func fuzzInternalObject(t *testing.T, forVersion unversioned.GroupVersion, item
340 340
 			j.From.Kind = "DockerImage"
341 341
 			j.From.Name = specs[c.Intn(len(specs))]
342 342
 		},
343
+
344
+		// TODO: uncomment when round tripping for init containers is available (the annotation is
345
+		// not supported on security context review for now)
346
+		func(j *securityapi.PodSecurityPolicyReview, c fuzz.Continue) {
347
+			c.FuzzNoCustom(j)
348
+			j.Spec.PodSpec.InitContainers = nil
349
+			for i := range j.Status.AllowedServiceAccounts {
350
+				j.Status.AllowedServiceAccounts[i].PodSpec.InitContainers = nil
351
+			}
352
+		},
353
+		func(j *securityapi.PodSecurityPolicySelfSubjectReview, c fuzz.Continue) {
354
+			c.FuzzNoCustom(j)
355
+			j.Spec.PodSpec.InitContainers = nil
356
+			j.Status.PodSpec.InitContainers = nil
357
+		},
358
+		func(j *securityapi.PodSecurityPolicySubjectReview, c fuzz.Continue) {
359
+			c.FuzzNoCustom(j)
360
+			j.Spec.PodSpec.InitContainers = nil
361
+			j.Status.PodSpec.InitContainers = nil
362
+		},
363
+
343 364
 		func(j *runtime.Object, c fuzz.Continue) {
344 365
 			// runtime.EmbeddedObject causes a panic inside of fuzz because runtime.Object isn't handled.
345 366
 		},
... ...
@@ -420,7 +442,7 @@ func roundTrip(t *testing.T, codec runtime.Codec, originalItem runtime.Object) {
420 420
 	}
421 421
 
422 422
 	if !kapi.Semantic.DeepEqual(originalItem, obj2) {
423
-		t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %s", name, diff.ObjectDiff(originalItem, obj2), codec, string(data), diff.ObjectGoPrintSideBySide(originalItem, obj2))
423
+		t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s", name, diff.ObjectReflectDiff(originalItem, obj2), codec, string(data))
424 424
 		return
425 425
 	}
426 426
 
... ...
@@ -430,7 +452,7 @@ func roundTrip(t *testing.T, codec runtime.Codec, originalItem runtime.Object) {
430 430
 		return
431 431
 	}
432 432
 	if !kapi.Semantic.DeepEqual(originalItem, obj3) {
433
-		t.Errorf("3: %v: diff: %v\nCodec: %v", name, diff.ObjectDiff(originalItem, obj3), codec)
433
+		t.Errorf("3: %v: diff: %v\nCodec: %v", name, diff.ObjectReflectDiff(originalItem, obj3), codec)
434 434
 		return
435 435
 	}
436 436
 }
... ...
@@ -457,14 +479,14 @@ func TestSpecificKind(t *testing.T) {
457 457
 	}
458 458
 	seed := int64(2703387474910584091) //rand.Int63()
459 459
 	for i := 0; i < fuzzIters; i++ {
460
-		t.Logf(`About to test %v with "v1"`, kind)
460
+		//t.Logf(`About to test %v with "v1"`, kind)
461 461
 		fuzzInternalObject(t, v1.SchemeGroupVersion, item, seed)
462 462
 		roundTrip(t, kapi.Codecs.LegacyCodec(v1.SchemeGroupVersion), item)
463 463
 	}
464 464
 }
465 465
 
466 466
 // Keep this in sync with the respective upstream set
467
-var nonInternalRoundTrippableTypes = sets.NewString("List", "ListOptions")
467
+var nonInternalRoundTrippableTypes = sets.NewString("List", "ListOptions", "WatchEvent")
468 468
 
469 469
 // TestTypes will try to roundtrip all OpenShift and Kubernetes stable api types
470 470
 func TestTypes(t *testing.T) {
... ...
@@ -497,13 +519,13 @@ func TestTypes(t *testing.T) {
497 497
 
498 498
 					if versions, ok := skipStandardVersions[kind]; ok {
499 499
 						for _, v := range versions {
500
-							t.Logf("About to test %v with %q", kind, v)
500
+							//t.Logf("About to test %v with %q", kind, v)
501 501
 							fuzzInternalObject(t, v, item, seed)
502 502
 							roundTrip(t, kapi.Codecs.LegacyCodec(v), item)
503 503
 						}
504 504
 						continue
505 505
 					}
506
-					t.Logf(`About to test %v with "v1"`, kind)
506
+					//t.Logf(`About to test %v with "v1"`, kind)
507 507
 					fuzzInternalObject(t, externalVersion, item, seed)
508 508
 					roundTrip(t, kapi.Codecs.LegacyCodec(externalVersion), item)
509 509
 				}
... ...
@@ -122,12 +122,12 @@ func (v *RuntimeObjectsValidator) getSpecificValidationInfo(obj runtime.Object)
122 122
 }
123 123
 
124 124
 func GetRequiresNamespace(obj runtime.Object) (bool, error) {
125
-	groupVersionKind, err := kapi.Scheme.ObjectKind(obj)
125
+	groupVersionKinds, _, err := kapi.Scheme.ObjectKinds(obj)
126 126
 	if err != nil {
127 127
 		return false, err
128 128
 	}
129 129
 
130
-	restMapping, err := kapi.RESTMapper.RESTMapping(groupVersionKind.GroupKind())
130
+	restMapping, err := kapi.RESTMapper.RESTMapping(groupVersionKinds[0].GroupKind())
131 131
 	if err != nil {
132 132
 		return false, err
133 133
 	}
... ...
@@ -3,6 +3,7 @@ package validation
3 3
 import (
4 4
 	"fmt"
5 5
 	"reflect"
6
+	"strings"
6 7
 	"testing"
7 8
 
8 9
 	kapi "k8s.io/kubernetes/pkg/api"
... ...
@@ -39,6 +40,8 @@ func TestNilPath(t *testing.T) {
39 39
 }
40 40
 
41 41
 func TestNameFunc(t *testing.T) {
42
+	const nameRulesMessage = `must match the regex [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)* (e.g. 'example.com')`
43
+
42 44
 	for apiType, validationInfo := range Validator.typeToValidator {
43 45
 		if !validationInfo.HasObjectMeta {
44 46
 			continue
... ...
@@ -52,7 +55,8 @@ func TestNameFunc(t *testing.T) {
52 52
 			apiObjectMeta.Set(reflect.ValueOf(kapi.ObjectMeta{Name: illegalName}))
53 53
 
54 54
 			errList := validationInfo.Validator.Validate(apiValue.Interface().(runtime.Object))
55
-			_, requiredMessage := api.MinimalNameRequirements(illegalName, false)
55
+			reasons := api.MinimalNameRequirements(illegalName, false)
56
+			requiredMessage := strings.Join(reasons, ", ")
56 57
 
57 58
 			if len(errList) == 0 {
58 59
 				t.Errorf("expected error for %v in %v not found amongst %v.  You probably need to add api.MinimalNameRequirements to your name validator..", illegalName, apiType.Elem(), errList)
... ...
@@ -65,13 +69,12 @@ func TestNameFunc(t *testing.T) {
65 65
 				if validationError.Type != field.ErrorTypeInvalid || validationError.Field != "metadata.name" {
66 66
 					continue
67 67
 				}
68
-
69 68
 				if validationError.Detail == requiredMessage {
70 69
 					foundExpectedError = true
71 70
 					break
72 71
 				}
73 72
 				// this message is from a stock name validation method in kube that covers our requirements in MinimalNameRequirements
74
-				if validationError.Detail == validation.DNSSubdomainErrorMsg {
73
+				if validationError.Detail == nameRulesMessage {
75 74
 					foundExpectedError = true
76 75
 					break
77 76
 				}
... ...
@@ -89,7 +92,8 @@ func TestNameFunc(t *testing.T) {
89 89
 			apiObjectMeta.Set(reflect.ValueOf(kapi.ObjectMeta{Name: illegalName}))
90 90
 
91 91
 			errList := validationInfo.Validator.Validate(apiValue.Interface().(runtime.Object))
92
-			_, requiredMessage := api.MinimalNameRequirements(illegalName, false)
92
+			reasons := api.MinimalNameRequirements(illegalName, false)
93
+			requiredMessage := strings.Join(reasons, ", ")
93 94
 
94 95
 			if len(errList) == 0 {
95 96
 				t.Errorf("expected error for %v in %v not found amongst %v.  You probably need to add api.MinimalNameRequirements to your name validator.", illegalName, apiType.Elem(), errList)
... ...
@@ -107,7 +111,8 @@ func TestNameFunc(t *testing.T) {
107 107
 					foundExpectedError = true
108 108
 					break
109 109
 				}
110
-				if validationError.Detail == validation.DNSSubdomainErrorMsg {
110
+				// this message is from a stock name validation method in kube that covers our requirements in MinimalNameRequirements
111
+				if validationError.Detail == nameRulesMessage {
111 112
 					foundExpectedError = true
112 113
 					break
113 114
 				}
... ...
@@ -165,7 +165,7 @@ func BuildSubjects(users, groups []string, userNameValidator, groupNameValidator
165 165
 		}
166 166
 
167 167
 		kind := UserKind
168
-		if valid, _ := userNameValidator(user, false); !valid {
168
+		if len(userNameValidator(user, false)) != 0 {
169 169
 			kind = SystemUserKind
170 170
 		}
171 171
 
... ...
@@ -174,7 +174,7 @@ func BuildSubjects(users, groups []string, userNameValidator, groupNameValidator
174 174
 
175 175
 	for _, group := range groups {
176 176
 		kind := GroupKind
177
-		if valid, _ := groupNameValidator(group, false); !valid {
177
+		if len(groupNameValidator(group, false)) != 0 {
178 178
 			kind = SystemGroupKind
179 179
 		}
180 180
 
... ...
@@ -2,6 +2,7 @@ package validation
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"strings"
5 6
 
6 7
 	kapi "k8s.io/kubernetes/pkg/api"
7 8
 	"k8s.io/kubernetes/pkg/api/validation"
... ...
@@ -69,16 +70,16 @@ func ValidateLocalResourceAccessReview(review *authorizationapi.LocalResourceAcc
69 69
 	return allErrs
70 70
 }
71 71
 
72
-func ValidatePolicyName(name string, prefix bool) (bool, string) {
73
-	if ok, reason := oapi.MinimalNameRequirements(name, prefix); !ok {
74
-		return ok, reason
72
+func ValidatePolicyName(name string, prefix bool) []string {
73
+	if reasons := oapi.MinimalNameRequirements(name, prefix); len(reasons) != 0 {
74
+		return reasons
75 75
 	}
76 76
 
77 77
 	if name != authorizationapi.PolicyName {
78
-		return false, "name must be " + authorizationapi.PolicyName
78
+		return []string{"name must be " + authorizationapi.PolicyName}
79 79
 	}
80 80
 
81
-	return true, ""
81
+	return nil
82 82
 }
83 83
 
84 84
 func ValidateLocalPolicy(policy *authorizationapi.Policy) field.ErrorList {
... ...
@@ -125,16 +126,16 @@ func ValidatePolicyUpdate(policy *authorizationapi.Policy, oldPolicy *authorizat
125 125
 }
126 126
 
127 127
 func PolicyBindingNameValidator(policyRefNamespace string) validation.ValidateNameFunc {
128
-	return func(name string, prefix bool) (bool, string) {
129
-		if ok, reason := oapi.MinimalNameRequirements(name, prefix); !ok {
130
-			return ok, reason
128
+	return func(name string, prefix bool) []string {
129
+		if reasons := oapi.MinimalNameRequirements(name, prefix); len(reasons) != 0 {
130
+			return reasons
131 131
 		}
132 132
 
133 133
 		if name != authorizationapi.GetPolicyBindingName(policyRefNamespace) {
134
-			return false, "name must be " + authorizationapi.GetPolicyBindingName(policyRefNamespace)
134
+			return []string{"name must be " + authorizationapi.GetPolicyBindingName(policyRefNamespace)}
135 135
 		}
136 136
 
137
-		return true, ""
137
+		return nil
138 138
 	}
139 139
 }
140 140
 
... ...
@@ -251,15 +252,15 @@ func validateRoleBinding(roleBinding *authorizationapi.RoleBinding, isNamespaced
251 251
 	allErrs = append(allErrs, validation.ValidateObjectMeta(&roleBinding.ObjectMeta, isNamespaced, oapi.MinimalNameRequirements, fldPath.Child("metadata"))...)
252 252
 
253 253
 	// roleRef namespace is empty when referring to global policy.
254
-	if (len(roleBinding.RoleRef.Namespace) > 0) && !kvalidation.IsDNS1123Subdomain(roleBinding.RoleRef.Namespace) {
254
+	if (len(roleBinding.RoleRef.Namespace) > 0) && len(kvalidation.IsDNS1123Subdomain(roleBinding.RoleRef.Namespace)) != 0 {
255 255
 		allErrs = append(allErrs, field.Invalid(fldPath.Child("roleRef", "namespace"), roleBinding.RoleRef.Namespace, "roleRef.namespace must be a valid subdomain"))
256 256
 	}
257 257
 
258 258
 	if len(roleBinding.RoleRef.Name) == 0 {
259 259
 		allErrs = append(allErrs, field.Required(fldPath.Child("roleRef", "name"), ""))
260 260
 	} else {
261
-		if valid, err := oapi.MinimalNameRequirements(roleBinding.RoleRef.Name, false); !valid {
262
-			allErrs = append(allErrs, field.Invalid(fldPath.Child("roleRef", "name"), roleBinding.RoleRef.Name, err))
261
+		if reasons := oapi.MinimalNameRequirements(roleBinding.RoleRef.Name, false); len(reasons) != 0 {
262
+			allErrs = append(allErrs, field.Invalid(fldPath.Child("roleRef", "name"), roleBinding.RoleRef.Name, strings.Join(reasons, ", ")))
263 263
 		}
264 264
 	}
265 265
 
... ...
@@ -292,32 +293,32 @@ func validateRoleBindingSubject(subject kapi.ObjectReference, isNamespaced bool,
292 292
 
293 293
 	switch subject.Kind {
294 294
 	case authorizationapi.ServiceAccountKind:
295
-		if valid, reason := validation.ValidateServiceAccountName(subject.Name, false); len(subject.Name) > 0 && !valid {
296
-			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, reason))
295
+		if reasons := validation.ValidateServiceAccountName(subject.Name, false); len(subject.Name) > 0 && len(reasons) != 0 {
296
+			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, strings.Join(reasons, ", ")))
297 297
 		}
298 298
 		if !isNamespaced && len(subject.Namespace) == 0 {
299 299
 			allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), ""))
300 300
 		}
301 301
 
302 302
 	case authorizationapi.UserKind:
303
-		if valid, reason := uservalidation.ValidateUserName(subject.Name, false); len(subject.Name) > 0 && !valid {
304
-			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, reason))
303
+		if reasons := uservalidation.ValidateUserName(subject.Name, false); len(subject.Name) > 0 && len(reasons) != 0 {
304
+			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, strings.Join(reasons, ", ")))
305 305
 		}
306 306
 
307 307
 	case authorizationapi.GroupKind:
308
-		if valid, reason := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && !valid {
309
-			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, reason))
308
+		if reasons := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && len(reasons) != 0 {
309
+			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, strings.Join(reasons, ", ")))
310 310
 		}
311 311
 
312 312
 	case authorizationapi.SystemUserKind:
313
-		isValidSAName, _ := validation.ValidateServiceAccountName(subject.Name, false)
314
-		isValidUserName, _ := uservalidation.ValidateUserName(subject.Name, false)
313
+		isValidSAName := len(validation.ValidateServiceAccountName(subject.Name, false)) == 0
314
+		isValidUserName := len(uservalidation.ValidateUserName(subject.Name, false)) == 0
315 315
 		if isValidSAName || isValidUserName {
316 316
 			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, "conforms to User.name or ServiceAccount.name restrictions"))
317 317
 		}
318 318
 
319 319
 	case authorizationapi.SystemGroupKind:
320
-		if valid, _ := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && valid {
320
+		if reasons := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && len(reasons) == 0 {
321 321
 			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, "conforms to Group.name restrictions"))
322 322
 		}
323 323
 
... ...
@@ -243,6 +243,9 @@ func (e clusterRoleEvaluator) ResolveRules(scope, namespace string, clusterPolic
243 243
 	return rules, nil
244 244
 }
245 245
 
246
+// TODO: direct deep copy needing a cloner is something that should be fixed upstream
247
+var localCloner = conversion.NewCloner()
248
+
246 249
 // removeEscalatingResources inspects a PolicyRule and removes any references to escalating resources.
247 250
 // It has coarse logic for now.  It is possible to rewrite one rule into many for the finest grain control
248 251
 // but removing the entire matching resource regardless of verb or secondary group is cheaper, easier, and errs on the side removing
... ...
@@ -260,7 +263,7 @@ func removeEscalatingResources(in authorizationapi.PolicyRule) authorizationapi.
260 260
 			// we're using a cache of cache of an object that uses pointers to data.  I'm pretty sure we need to do a copy to avoid
261 261
 			// muddying the cache
262 262
 			ruleCopy = &authorizationapi.PolicyRule{}
263
-			authorizationapi.DeepCopy_api_PolicyRule(in, ruleCopy, nil)
263
+			authorizationapi.DeepCopy_api_PolicyRule(in, ruleCopy, localCloner)
264 264
 		}
265 265
 
266 266
 		ruleCopy.Resources.Delete(resource.Resource)
... ...
@@ -59,13 +59,13 @@ func (s *storage) ListClusterPolicies(ctx kapi.Context, options *kapi.ListOption
59 59
 	return obj.(*authorizationapi.ClusterPolicyList), nil
60 60
 }
61 61
 
62
-func (s *storage) CreateClusterPolicy(ctx kapi.Context, node *authorizationapi.ClusterPolicy) error {
63
-	_, err := s.Create(ctx, node)
62
+func (s *storage) CreateClusterPolicy(ctx kapi.Context, policy *authorizationapi.ClusterPolicy) error {
63
+	_, err := s.Create(ctx, policy)
64 64
 	return err
65 65
 }
66 66
 
67
-func (s *storage) UpdateClusterPolicy(ctx kapi.Context, node *authorizationapi.ClusterPolicy) error {
68
-	_, _, err := s.Update(ctx, node)
67
+func (s *storage) UpdateClusterPolicy(ctx kapi.Context, policy *authorizationapi.ClusterPolicy) error {
68
+	_, _, err := s.Update(ctx, policy.Name, rest.DefaultUpdatedObjectInfo(policy, kapi.Scheme))
69 69
 	return err
70 70
 }
71 71
 
... ...
@@ -65,7 +65,7 @@ func (s *storage) CreateClusterPolicyBinding(ctx kapi.Context, policyBinding *au
65 65
 }
66 66
 
67 67
 func (s *storage) UpdateClusterPolicyBinding(ctx kapi.Context, policyBinding *authorizationapi.ClusterPolicyBinding) error {
68
-	_, _, err := s.Update(ctx, policyBinding)
68
+	_, _, err := s.Update(ctx, policyBinding.Name, rest.DefaultUpdatedObjectInfo(policyBinding, kapi.Scheme))
69 69
 	return err
70 70
 }
71 71
 
... ...
@@ -2,6 +2,7 @@ package proxy
2 2
 
3 3
 import (
4 4
 	kapi "k8s.io/kubernetes/pkg/api"
5
+	"k8s.io/kubernetes/pkg/api/rest"
5 6
 	"k8s.io/kubernetes/pkg/api/unversioned"
6 7
 	"k8s.io/kubernetes/pkg/runtime"
7 8
 
... ...
@@ -81,11 +82,24 @@ func (s *ClusterRoleStorage) Create(ctx kapi.Context, obj runtime.Object) (runti
81 81
 	return authorizationapi.ToClusterRole(ret.(*authorizationapi.Role)), err
82 82
 }
83 83
 
84
-func (s *ClusterRoleStorage) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
84
+type convertingObjectInfo struct {
85
+	rest.UpdatedObjectInfo
86
+}
87
+
88
+func (i convertingObjectInfo) UpdatedObject(ctx kapi.Context, old runtime.Object) (runtime.Object, error) {
89
+	oldObj := old.(*authorizationapi.Role)
90
+	convertedOldObj := authorizationapi.ToClusterRole(oldObj)
91
+	obj, err := i.UpdatedObjectInfo.UpdatedObject(ctx, convertedOldObj)
92
+	if err != nil {
93
+		return nil, err
94
+	}
85 95
 	clusterObj := obj.(*authorizationapi.ClusterRole)
86 96
 	convertedObj := authorizationapi.ToRole(clusterObj)
97
+	return convertedObj, nil
98
+}
87 99
 
88
-	ret, created, err := s.roleStorage.Update(ctx, convertedObj)
100
+func (s *ClusterRoleStorage) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
101
+	ret, created, err := s.roleStorage.Update(ctx, name, convertingObjectInfo{objInfo})
89 102
 	if ret == nil {
90 103
 		return nil, created, err
91 104
 	}
... ...
@@ -64,7 +64,7 @@ func (s *storage) CreateClusterRole(ctx kapi.Context, node *authorizationapi.Clu
64 64
 }
65 65
 
66 66
 func (s *storage) UpdateClusterRole(ctx kapi.Context, node *authorizationapi.ClusterRole) (*authorizationapi.ClusterRole, bool, error) {
67
-	obj, created, err := s.Update(ctx, node)
67
+	obj, created, err := s.Update(ctx, node.Name, rest.DefaultUpdatedObjectInfo(node, kapi.Scheme))
68 68
 	if err != nil {
69 69
 		return nil, created, err
70 70
 	}
... ...
@@ -2,6 +2,7 @@ package proxy
2 2
 
3 3
 import (
4 4
 	kapi "k8s.io/kubernetes/pkg/api"
5
+	"k8s.io/kubernetes/pkg/api/rest"
5 6
 	"k8s.io/kubernetes/pkg/api/unversioned"
6 7
 	"k8s.io/kubernetes/pkg/runtime"
7 8
 
... ...
@@ -82,11 +83,24 @@ func (s *ClusterRoleBindingStorage) Create(ctx kapi.Context, obj runtime.Object)
82 82
 	return authorizationapi.ToClusterRoleBinding(ret.(*authorizationapi.RoleBinding)), err
83 83
 }
84 84
 
85
-func (s *ClusterRoleBindingStorage) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
85
+type convertingObjectInfo struct {
86
+	rest.UpdatedObjectInfo
87
+}
88
+
89
+func (i convertingObjectInfo) UpdatedObject(ctx kapi.Context, old runtime.Object) (runtime.Object, error) {
90
+	oldObj := old.(*authorizationapi.RoleBinding)
91
+	convertedOldObj := authorizationapi.ToClusterRoleBinding(oldObj)
92
+	obj, err := i.UpdatedObjectInfo.UpdatedObject(ctx, convertedOldObj)
93
+	if err != nil {
94
+		return nil, err
95
+	}
86 96
 	clusterObj := obj.(*authorizationapi.ClusterRoleBinding)
87 97
 	convertedObj := authorizationapi.ToRoleBinding(clusterObj)
98
+	return convertedObj, nil
99
+}
88 100
 
89
-	ret, created, err := s.roleBindingStorage.Update(ctx, convertedObj)
101
+func (s *ClusterRoleBindingStorage) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
102
+	ret, created, err := s.roleBindingStorage.Update(ctx, name, convertingObjectInfo{objInfo})
90 103
 	if ret == nil {
91 104
 		return nil, created, err
92 105
 	}
... ...
@@ -54,16 +54,16 @@ func (s *storage) ListRoleBindings(ctx kapi.Context, options *kapi.ListOptions)
54 54
 	return obj.(*authorizationapi.RoleBindingList), nil
55 55
 }
56 56
 
57
-func (s *storage) CreateRoleBinding(ctx kapi.Context, node *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, error) {
58
-	obj, err := s.Create(ctx, node)
57
+func (s *storage) CreateRoleBinding(ctx kapi.Context, binding *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, error) {
58
+	obj, err := s.Create(ctx, binding)
59 59
 	if err != nil {
60 60
 		return nil, err
61 61
 	}
62 62
 	return obj.(*authorizationapi.RoleBinding), err
63 63
 }
64 64
 
65
-func (s *storage) UpdateRoleBinding(ctx kapi.Context, node *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, bool, error) {
66
-	obj, created, err := s.Update(ctx, node)
65
+func (s *storage) UpdateRoleBinding(ctx kapi.Context, binding *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, bool, error) {
66
+	obj, created, err := s.Update(ctx, binding.Name, rest.DefaultUpdatedObjectInfo(binding, kapi.Scheme))
67 67
 	if err != nil {
68 68
 		return nil, created, err
69 69
 	}
... ...
@@ -59,7 +59,7 @@ func (s *storage) CreatePolicy(ctx kapi.Context, node *authorizationapi.Policy)
59 59
 }
60 60
 
61 61
 func (s *storage) UpdatePolicy(ctx kapi.Context, node *authorizationapi.Policy) error {
62
-	_, _, err := s.Update(ctx, node)
62
+	_, _, err := s.Update(ctx, node.Name, rest.DefaultUpdatedObjectInfo(node, kapi.Scheme))
63 63
 	return err
64 64
 }
65 65
 
... ...
@@ -59,7 +59,7 @@ func (s *storage) CreatePolicyBinding(ctx kapi.Context, policyBinding *authoriza
59 59
 }
60 60
 
61 61
 func (s *storage) UpdatePolicyBinding(ctx kapi.Context, policyBinding *authorizationapi.PolicyBinding) error {
62
-	_, _, err := s.Update(ctx, policyBinding)
62
+	_, _, err := s.Update(ctx, policyBinding.Name, rest.DefaultUpdatedObjectInfo(policyBinding, kapi.Scheme))
63 63
 	return err
64 64
 }
65 65
 
... ...
@@ -74,7 +74,7 @@ func (r *REST) isAllowed(ctx kapi.Context, rar *authorizationapi.ResourceAccessR
74 74
 		return kapierrors.NewForbidden(authorizationapi.Resource(localRARAttributes.GetResource()), localRARAttributes.GetResourceName(), err)
75 75
 	}
76 76
 	if !allowed {
77
-		forbiddenError, _ := kapierrors.NewForbidden(authorizationapi.Resource(localRARAttributes.GetResource()), localRARAttributes.GetResourceName(), errors.New("") /*discarded*/).(*kapierrors.StatusError)
77
+		forbiddenError := kapierrors.NewForbidden(authorizationapi.Resource(localRARAttributes.GetResource()), localRARAttributes.GetResourceName(), errors.New("") /*discarded*/)
78 78
 		forbiddenError.ErrStatus.Message = reason
79 79
 		return forbiddenError
80 80
 	}
... ...
@@ -140,24 +140,29 @@ func (m *VirtualStorage) createRole(ctx kapi.Context, obj runtime.Object, allowE
140 140
 	return role, nil
141 141
 }
142 142
 
143
-func (m *VirtualStorage) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
144
-	return m.updateRole(ctx, obj, false)
143
+func (m *VirtualStorage) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
144
+	return m.updateRole(ctx, name, objInfo, false)
145 145
 }
146 146
 func (m *VirtualStorage) UpdateRoleWithEscalation(ctx kapi.Context, obj *authorizationapi.Role) (*authorizationapi.Role, bool, error) {
147
-	return m.updateRole(ctx, obj, true)
147
+	return m.updateRole(ctx, obj.Name, rest.DefaultUpdatedObjectInfo(obj, kapi.Scheme), true)
148 148
 }
149 149
 
150
-func (m *VirtualStorage) updateRole(ctx kapi.Context, obj runtime.Object, allowEscalation bool) (*authorizationapi.Role, bool, error) {
151
-	role, ok := obj.(*authorizationapi.Role)
152
-	if !ok {
153
-		return nil, false, kapierrors.NewBadRequest(fmt.Sprintf("obj is not a role: %#v", obj))
150
+func (m *VirtualStorage) updateRole(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo, allowEscalation bool) (*authorizationapi.Role, bool, error) {
151
+	old, err := m.Get(ctx, name)
152
+	if err != nil {
153
+		return nil, false, err
154 154
 	}
155 155
 
156
-	old, err := m.Get(ctx, role.Name)
156
+	obj, err := objInfo.UpdatedObject(ctx, old)
157 157
 	if err != nil {
158 158
 		return nil, false, err
159 159
 	}
160 160
 
161
+	role, ok := obj.(*authorizationapi.Role)
162
+	if !ok {
163
+		return nil, false, kapierrors.NewBadRequest(fmt.Sprintf("obj is not a role: %#v", obj))
164
+	}
165
+
161 166
 	if err := rest.BeforeUpdate(m.UpdateStrategy, ctx, obj, old); err != nil {
162 167
 		return nil, false, err
163 168
 	}
... ...
@@ -6,8 +6,10 @@ import (
6 6
 
7 7
 	kapi "k8s.io/kubernetes/pkg/api"
8 8
 	kapierrors "k8s.io/kubernetes/pkg/api/errors"
9
+	"k8s.io/kubernetes/pkg/api/rest"
9 10
 	"k8s.io/kubernetes/pkg/api/unversioned"
10 11
 	"k8s.io/kubernetes/pkg/auth/user"
12
+	"k8s.io/kubernetes/pkg/util/diff"
11 13
 	"k8s.io/kubernetes/pkg/util/sets"
12 14
 
13 15
 	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
... ...
@@ -108,25 +110,28 @@ func TestUpdate(t *testing.T) {
108 108
 	realizedRole := realizedRoleObj.(*authorizationapi.Role)
109 109
 
110 110
 	role := &authorizationapi.Role{
111
-		ObjectMeta: kapi.ObjectMeta{Name: "my-role", ResourceVersion: realizedRole.ResourceVersion},
111
+		ObjectMeta: realizedRole.ObjectMeta,
112 112
 		Rules: []authorizationapi.PolicyRule{
113 113
 			{Verbs: sets.NewString("list", "update")},
114 114
 		},
115 115
 	}
116 116
 
117
-	obj, created, err := storage.Update(ctx, role)
117
+	obj, created, err := storage.Update(ctx, role.Name, rest.DefaultUpdatedObjectInfo(role, kapi.Scheme))
118 118
 	if err != nil || created {
119 119
 		t.Errorf("Unexpected error %v", err)
120 120
 	}
121 121
 
122
-	switch obj.(type) {
122
+	switch actual := obj.(type) {
123 123
 	case *unversioned.Status:
124 124
 		t.Errorf("Unexpected operation error: %v", obj)
125 125
 
126 126
 	case *authorizationapi.Role:
127
+		if realizedRole.ResourceVersion == actual.ResourceVersion {
128
+			t.Errorf("Expected change to role binding. Expected: %s, Got: %s", realizedRole.ResourceVersion, actual.ResourceVersion)
129
+		}
130
+		role.ResourceVersion = actual.ResourceVersion
127 131
 		if !reflect.DeepEqual(role, obj) {
128
-			t.Errorf("Updated role does not match input role."+
129
-				" Expected: %v, Got: %v", role, obj)
132
+			t.Errorf("Updated role does not match input role. %s", diff.ObjectReflectDiff(role, obj))
130 133
 		}
131 134
 	default:
132 135
 		t.Errorf("Unexpected result type: %v", obj)
... ...
@@ -149,13 +154,13 @@ func TestUpdateNoOp(t *testing.T) {
149 149
 	realizedRole := realizedRoleObj.(*authorizationapi.Role)
150 150
 
151 151
 	role := &authorizationapi.Role{
152
-		ObjectMeta: kapi.ObjectMeta{Name: "my-role", ResourceVersion: realizedRole.ResourceVersion},
152
+		ObjectMeta: realizedRole.ObjectMeta,
153 153
 		Rules: []authorizationapi.PolicyRule{
154 154
 			{Verbs: sets.NewString(authorizationapi.VerbAll)},
155 155
 		},
156 156
 	}
157 157
 
158
-	obj, created, err := storage.Update(ctx, role)
158
+	obj, created, err := storage.Update(ctx, role.Name, rest.DefaultUpdatedObjectInfo(role, kapi.Scheme))
159 159
 	if err != nil || created {
160 160
 		t.Errorf("Unexpected error %v", err)
161 161
 	}
... ...
@@ -169,8 +174,7 @@ func TestUpdateNoOp(t *testing.T) {
169 169
 			t.Errorf("Expected no change to role binding. Expected: %s, Got: %s", realizedRole.ResourceVersion, o.ResourceVersion)
170 170
 		}
171 171
 		if !reflect.DeepEqual(role, obj) {
172
-			t.Errorf("Updated role does not match input role."+
173
-				" Expected: %v, Got: %v", role, obj)
172
+			t.Errorf("Updated role does not match input role. %s", diff.ObjectReflectDiff(role, obj))
174 173
 		}
175 174
 	default:
176 175
 		t.Errorf("Unexpected result type: %v", obj)
... ...
@@ -185,7 +189,7 @@ func TestUpdateError(t *testing.T) {
185 185
 	}
186 186
 
187 187
 	ctx := kapi.WithNamespace(kapi.NewContext(), "unittest")
188
-	_, _, err := storage.Update(ctx, role)
188
+	_, _, err := storage.Update(ctx, role.Name, rest.DefaultUpdatedObjectInfo(role, kapi.Scheme))
189 189
 	if err == nil {
190 190
 		t.Errorf("Missing expected error")
191 191
 		return
... ...
@@ -54,13 +54,13 @@ func (s *storage) ListRoles(ctx kapi.Context, options *kapi.ListOptions) (*autho
54 54
 	return obj.(*authorizationapi.RoleList), nil
55 55
 }
56 56
 
57
-func (s *storage) CreateRole(ctx kapi.Context, node *authorizationapi.Role) (*authorizationapi.Role, error) {
58
-	obj, err := s.Create(ctx, node)
57
+func (s *storage) CreateRole(ctx kapi.Context, role *authorizationapi.Role) (*authorizationapi.Role, error) {
58
+	obj, err := s.Create(ctx, role)
59 59
 	return obj.(*authorizationapi.Role), err
60 60
 }
61 61
 
62
-func (s *storage) UpdateRole(ctx kapi.Context, node *authorizationapi.Role) (*authorizationapi.Role, bool, error) {
63
-	obj, created, err := s.Update(ctx, node)
62
+func (s *storage) UpdateRole(ctx kapi.Context, role *authorizationapi.Role) (*authorizationapi.Role, bool, error) {
63
+	obj, created, err := s.Update(ctx, role.Name, rest.DefaultUpdatedObjectInfo(role, kapi.Scheme))
64 64
 	return obj.(*authorizationapi.Role), created, err
65 65
 }
66 66
 
... ...
@@ -150,24 +150,29 @@ func (m *VirtualStorage) createRoleBinding(ctx kapi.Context, obj runtime.Object,
150 150
 	return roleBinding, nil
151 151
 }
152 152
 
153
-func (m *VirtualStorage) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
154
-	return m.updateRoleBinding(ctx, obj, false)
153
+func (m *VirtualStorage) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
154
+	return m.updateRoleBinding(ctx, name, objInfo, false)
155 155
 }
156 156
 func (m *VirtualStorage) UpdateRoleBindingWithEscalation(ctx kapi.Context, obj *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, bool, error) {
157
-	return m.updateRoleBinding(ctx, obj, true)
157
+	return m.updateRoleBinding(ctx, obj.Name, rest.DefaultUpdatedObjectInfo(obj, kapi.Scheme), true)
158 158
 }
159 159
 
160
-func (m *VirtualStorage) updateRoleBinding(ctx kapi.Context, obj runtime.Object, allowEscalation bool) (*authorizationapi.RoleBinding, bool, error) {
161
-	roleBinding, ok := obj.(*authorizationapi.RoleBinding)
162
-	if !ok {
163
-		return nil, false, kapierrors.NewBadRequest(fmt.Sprintf("obj is not a role: %#v", obj))
160
+func (m *VirtualStorage) updateRoleBinding(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo, allowEscalation bool) (*authorizationapi.RoleBinding, bool, error) {
161
+	old, err := m.Get(ctx, name)
162
+	if err != nil {
163
+		return nil, false, err
164 164
 	}
165 165
 
166
-	old, err := m.Get(ctx, roleBinding.Name)
166
+	obj, err := objInfo.UpdatedObject(ctx, old)
167 167
 	if err != nil {
168 168
 		return nil, false, err
169 169
 	}
170 170
 
171
+	roleBinding, ok := obj.(*authorizationapi.RoleBinding)
172
+	if !ok {
173
+		return nil, false, kapierrors.NewBadRequest(fmt.Sprintf("obj is not a role: %#v", obj))
174
+	}
175
+
171 176
 	if err := rest.BeforeUpdate(m.UpdateStrategy, ctx, obj, old); err != nil {
172 177
 		return nil, false, err
173 178
 	}
... ...
@@ -8,8 +8,10 @@ import (
8 8
 
9 9
 	kapi "k8s.io/kubernetes/pkg/api"
10 10
 	kapierrors "k8s.io/kubernetes/pkg/api/errors"
11
+	"k8s.io/kubernetes/pkg/api/rest"
11 12
 	"k8s.io/kubernetes/pkg/api/unversioned"
12 13
 	"k8s.io/kubernetes/pkg/auth/user"
14
+	"k8s.io/kubernetes/pkg/util/diff"
13 15
 	"k8s.io/kubernetes/pkg/util/sets"
14 16
 
15 17
 	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
... ...
@@ -152,24 +154,27 @@ func TestUpdate(t *testing.T) {
152 152
 	original := obj.(*authorizationapi.RoleBinding)
153 153
 
154 154
 	roleBinding := &authorizationapi.RoleBinding{
155
-		ObjectMeta: kapi.ObjectMeta{Name: "my-roleBinding", ResourceVersion: original.ResourceVersion},
155
+		ObjectMeta: original.ObjectMeta,
156 156
 		RoleRef:    kapi.ObjectReference{Name: "admin"},
157 157
 		Subjects:   []kapi.ObjectReference{{Name: "bob", Kind: "User"}},
158 158
 	}
159 159
 
160
-	obj, created, err := storage.Update(ctx, roleBinding)
160
+	obj, created, err := storage.Update(ctx, roleBinding.Name, rest.DefaultUpdatedObjectInfo(roleBinding, kapi.Scheme))
161 161
 	if err != nil || created {
162 162
 		t.Errorf("Unexpected error %v", err)
163 163
 	}
164 164
 
165
-	switch obj.(type) {
165
+	switch actual := obj.(type) {
166 166
 	case *unversioned.Status:
167 167
 		t.Errorf("Unexpected operation error: %v", obj)
168 168
 
169 169
 	case *authorizationapi.RoleBinding:
170
+		if original.ResourceVersion == actual.ResourceVersion {
171
+			t.Errorf("Expected change to role binding. Expected: %s, Got: %s", original.ResourceVersion, actual.ResourceVersion)
172
+		}
173
+		roleBinding.ResourceVersion = actual.ResourceVersion
170 174
 		if !reflect.DeepEqual(roleBinding, obj) {
171
-			t.Errorf("Updated roleBinding does not match input roleBinding."+
172
-				" Expected: %v, Got: %v", roleBinding, obj)
175
+			t.Errorf("Updated roleBinding does not match input roleBinding. %s", diff.ObjectReflectDiff(roleBinding, obj))
173 176
 		}
174 177
 	default:
175 178
 		t.Errorf("Unexpected result type: %v", obj)
... ...
@@ -191,11 +196,11 @@ func TestUpdateNoOp(t *testing.T) {
191 191
 	original := obj.(*authorizationapi.RoleBinding)
192 192
 
193 193
 	roleBinding := &authorizationapi.RoleBinding{
194
-		ObjectMeta: kapi.ObjectMeta{Name: "my-roleBinding", ResourceVersion: original.ResourceVersion},
194
+		ObjectMeta: original.ObjectMeta,
195 195
 		RoleRef:    kapi.ObjectReference{Name: "admin"},
196 196
 	}
197 197
 
198
-	obj, created, err := storage.Update(ctx, roleBinding)
198
+	obj, created, err := storage.Update(ctx, roleBinding.Name, rest.DefaultUpdatedObjectInfo(roleBinding, kapi.Scheme))
199 199
 	if err != nil || created {
200 200
 		t.Errorf("Unexpected error %v", err)
201 201
 	}
... ...
@@ -209,8 +214,7 @@ func TestUpdateNoOp(t *testing.T) {
209 209
 			t.Errorf("Expected no change to role binding. Expected: %s, Got: %s", original.ResourceVersion, o.ResourceVersion)
210 210
 		}
211 211
 		if !reflect.DeepEqual(roleBinding, obj) {
212
-			t.Errorf("Updated roleBinding does not match input roleBinding."+
213
-				" Expected: %v, Got: %v", roleBinding, obj)
212
+			t.Errorf("Updated roleBinding does not match input roleBinding. %s", diff.ObjectReflectDiff(roleBinding, obj))
214 213
 		}
215 214
 	default:
216 215
 		t.Errorf("Unexpected result type: %v", obj)
... ...
@@ -236,7 +240,7 @@ func TestUpdateError(t *testing.T) {
236 236
 		RoleRef:    kapi.ObjectReference{Name: "admin"},
237 237
 	}
238 238
 
239
-	_, _, err = storage.Update(ctx, roleBinding)
239
+	_, _, err = storage.Update(ctx, roleBinding.Name, rest.DefaultUpdatedObjectInfo(roleBinding, kapi.Scheme))
240 240
 	if err == nil {
241 241
 		t.Errorf("Missing expected error")
242 242
 		return
... ...
@@ -265,7 +269,7 @@ func TestUpdateCannotChangeRoleRefError(t *testing.T) {
265 265
 		RoleRef:    kapi.ObjectReference{Name: "cluster-admin"},
266 266
 	}
267 267
 
268
-	_, _, err = storage.Update(ctx, roleBinding)
268
+	_, _, err = storage.Update(ctx, roleBinding.Name, rest.DefaultUpdatedObjectInfo(roleBinding, kapi.Scheme))
269 269
 	if err == nil {
270 270
 		t.Errorf("Missing expected error")
271 271
 		return
... ...
@@ -54,13 +54,13 @@ func (s *storage) ListRoleBindings(ctx kapi.Context, options *kapi.ListOptions)
54 54
 	return obj.(*authorizationapi.RoleBindingList), nil
55 55
 }
56 56
 
57
-func (s *storage) CreateRoleBinding(ctx kapi.Context, node *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, error) {
58
-	obj, err := s.Create(ctx, node)
57
+func (s *storage) CreateRoleBinding(ctx kapi.Context, rolebinding *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, error) {
58
+	obj, err := s.Create(ctx, rolebinding)
59 59
 	return obj.(*authorizationapi.RoleBinding), err
60 60
 }
61 61
 
62
-func (s *storage) UpdateRoleBinding(ctx kapi.Context, node *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, bool, error) {
63
-	obj, created, err := s.Update(ctx, node)
62
+func (s *storage) UpdateRoleBinding(ctx kapi.Context, rolebinding *authorizationapi.RoleBinding) (*authorizationapi.RoleBinding, bool, error) {
63
+	obj, created, err := s.Update(ctx, rolebinding.Name, rest.DefaultUpdatedObjectInfo(rolebinding, kapi.Scheme))
64 64
 	return obj.(*authorizationapi.RoleBinding), created, err
65 65
 }
66 66
 
... ...
@@ -125,7 +125,7 @@ func (r *REST) isAllowed(ctx kapi.Context, sar *authorizationapi.SubjectAccessRe
125 125
 		return kapierrors.NewForbidden(authorizationapi.Resource(localSARAttributes.GetResource()), localSARAttributes.GetResourceName(), err)
126 126
 	}
127 127
 	if !allowed {
128
-		forbiddenError, _ := kapierrors.NewForbidden(authorizationapi.Resource(localSARAttributes.GetResource()), localSARAttributes.GetResourceName(), errors.New("") /*discarded*/).(*kapierrors.StatusError)
128
+		forbiddenError := kapierrors.NewForbidden(authorizationapi.Resource(localSARAttributes.GetResource()), localSARAttributes.GetResourceName(), errors.New("") /*discarded*/)
129 129
 		forbiddenError.ErrStatus.Message = reason
130 130
 		return forbiddenError
131 131
 	}
... ...
@@ -31,33 +31,33 @@ func TestAdmission(t *testing.T) {
31 31
 	}{
32 32
 		{
33 33
 			name:            "disabled",
34
-			attributes:      admission.NewAttributesRecord(enableBuild, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
34
+			attributes:      admission.NewAttributesRecord(enableBuild, nil, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
35 35
 			jenkinsEnabled:  boolptr(false),
36 36
 			validateClients: noAction,
37 37
 		},
38 38
 		{
39 39
 			name:            "not a jenkins build",
40
-			attributes:      admission.NewAttributesRecord(&buildapi.Build{Spec: buildapi.BuildSpec{CommonSpec: buildapi.CommonSpec{Strategy: buildapi.BuildStrategy{}}}}, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
40
+			attributes:      admission.NewAttributesRecord(&buildapi.Build{Spec: buildapi.BuildSpec{CommonSpec: buildapi.CommonSpec{Strategy: buildapi.BuildStrategy{}}}}, nil, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
41 41
 			validateClients: noAction,
42 42
 		},
43 43
 		{
44 44
 			name:            "not a build kind",
45
-			attributes:      admission.NewAttributesRecord(&kapi.Service{}, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
45
+			attributes:      admission.NewAttributesRecord(&kapi.Service{}, nil, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
46 46
 			validateClients: noAction,
47 47
 		},
48 48
 		{
49 49
 			name:            "not a build resource",
50
-			attributes:      admission.NewAttributesRecord(enableBuild, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("notbuilds"), "", admission.Create, &user.DefaultInfo{}),
50
+			attributes:      admission.NewAttributesRecord(enableBuild, nil, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("notbuilds"), "", admission.Create, &user.DefaultInfo{}),
51 51
 			validateClients: noAction,
52 52
 		},
53 53
 		{
54 54
 			name:            "subresource",
55
-			attributes:      admission.NewAttributesRecord(enableBuild, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "subresource", admission.Create, &user.DefaultInfo{}),
55
+			attributes:      admission.NewAttributesRecord(enableBuild, nil, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "subresource", admission.Create, &user.DefaultInfo{}),
56 56
 			validateClients: noAction,
57 57
 		},
58 58
 		{
59 59
 			name:       "service present",
60
-			attributes: admission.NewAttributesRecord(enableBuild, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
60
+			attributes: admission.NewAttributesRecord(enableBuild, nil, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
61 61
 			objects: []runtime.Object{
62 62
 				&kapi.Service{ObjectMeta: kapi.ObjectMeta{Namespace: "namespace", Name: "jenkins"}},
63 63
 			},
... ...
@@ -70,7 +70,7 @@ func TestAdmission(t *testing.T) {
70 70
 		},
71 71
 		{
72 72
 			name:       "works on true",
73
-			attributes: admission.NewAttributesRecord(enableBuild, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
73
+			attributes: admission.NewAttributesRecord(enableBuild, nil, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
74 74
 			objects: []runtime.Object{
75 75
 				&kapi.Service{ObjectMeta: kapi.ObjectMeta{Namespace: "namespace", Name: "jenkins"}},
76 76
 			},
... ...
@@ -84,7 +84,7 @@ func TestAdmission(t *testing.T) {
84 84
 		},
85 85
 		{
86 86
 			name:       "service missing",
87
-			attributes: admission.NewAttributesRecord(enableBuild, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
87
+			attributes: admission.NewAttributesRecord(enableBuild, nil, unversioned.GroupVersionKind{}, "namespace", "name", buildapi.SchemeGroupVersion.WithResource("builds"), "", admission.Create, &user.DefaultInfo{}),
88 88
 			objects:    []runtime.Object{},
89 89
 			validateClients: func(kubeClient *fake.Clientset, originClient *testclient.Fake) string {
90 90
 				if len(kubeClient.Actions()) == 0 {
... ...
@@ -26,6 +26,7 @@ func TestBuildAdmission(t *testing.T) {
26 26
 		resource         unversioned.GroupResource
27 27
 		subResource      string
28 28
 		object           runtime.Object
29
+		oldObject        runtime.Object
29 30
 		responseObject   runtime.Object
30 31
 		reviewResponse   *authorizationapi.SubjectAccessReviewResponse
31 32
 		expectedResource string
... ...
@@ -167,7 +168,7 @@ func TestBuildAdmission(t *testing.T) {
167 167
 			client := fakeClient(test.expectedResource, test.reviewResponse, test.responseObject)
168 168
 			c := NewBuildByStrategy()
169 169
 			c.(oadmission.WantsOpenshiftClient).SetOpenshiftClient(client)
170
-			attrs := admission.NewAttributesRecord(test.object, test.kind.WithVersion("version"), "default", "name", test.resource.WithVersion("version"), test.subResource, op, fakeUser())
170
+			attrs := admission.NewAttributesRecord(test.object, test.oldObject, test.kind.WithVersion("version"), "default", "name", test.resource.WithVersion("version"), test.subResource, op, fakeUser())
171 171
 			err := c.Admit(attrs)
172 172
 			if err != nil && test.expectAccept {
173 173
 				t.Errorf("%s: unexpected error: %v", test.name, err)
... ...
@@ -72,6 +72,7 @@ func (p *TestPod) GetBuild(t *testing.T) *buildapi.Build {
72 72
 
73 73
 func (p *TestPod) ToAttributes() admission.Attributes {
74 74
 	return admission.NewAttributesRecord((*kapi.Pod)(p),
75
+		nil,
75 76
 		kapi.Kind("Pod").WithVersion("version"),
76 77
 		"default",
77 78
 		"TestPod",
... ...
@@ -38,7 +38,7 @@ func TestBinaryBuildRequestOptions(t *testing.T) {
38 38
 		AsFile: "Dockerfile",
39 39
 		Commit: "abcdef",
40 40
 	}
41
-	versioned, err := knewer.Scheme.ConvertToVersion(r, "v1")
41
+	versioned, err := knewer.Scheme.ConvertToVersion(r, kolder.SchemeGroupVersion)
42 42
 	if err != nil {
43 43
 		t.Fatal(err)
44 44
 	}
... ...
@@ -278,7 +278,7 @@ func validateSecrets(secrets []buildapi.SecretBuildSource, isDockerStrategy bool
278 278
 		if len(s.Secret.Name) == 0 {
279 279
 			allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("secret"), ""))
280 280
 		}
281
-		if ok, _ := validation.ValidateSecretName(s.Secret.Name, false); !ok {
281
+		if reasons := validation.ValidateSecretName(s.Secret.Name, false); len(reasons) != 0 {
282 282
 			allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("secret"), s, "must be valid secret name"))
283 283
 		}
284 284
 		if strings.HasPrefix(path.Clean(s.DestinationDir), "..") {
... ...
@@ -349,7 +349,7 @@ func validateToImageReference(reference *kapi.ObjectReference, fldPath *field.Pa
349 349
 		} else if _, _, ok := imageapi.SplitImageStreamTag(name); !ok {
350 350
 			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), name, "ImageStreamTag object references must be in the form <name>:<tag>"))
351 351
 		}
352
-		if len(namespace) != 0 && !kvalidation.IsDNS1123Subdomain(namespace) {
352
+		if len(namespace) != 0 && len(kvalidation.IsDNS1123Subdomain(namespace)) != 0 {
353 353
 			allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), namespace, "namespace must be a valid subdomain"))
354 354
 		}
355 355
 
... ...
@@ -380,7 +380,7 @@ func validateFromImageReference(reference *kapi.ObjectReference, fldPath *field.
380 380
 			allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), name, "ImageStreamTag object references must be in the form <name>:<tag>"))
381 381
 		}
382 382
 
383
-		if len(namespace) != 0 && !kvalidation.IsDNS1123Subdomain(namespace) {
383
+		if len(namespace) != 0 && len(kvalidation.IsDNS1123Subdomain(namespace)) != 0 {
384 384
 			allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), namespace, "namespace must be a valid subdomain"))
385 385
 		}
386 386
 
... ...
@@ -397,7 +397,7 @@ func validateFromImageReference(reference *kapi.ObjectReference, fldPath *field.
397 397
 		if len(name) == 0 {
398 398
 			allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
399 399
 		}
400
-		if len(namespace) != 0 && !kvalidation.IsDNS1123Subdomain(namespace) {
400
+		if len(namespace) != 0 && len(kvalidation.IsDNS1123Subdomain(namespace)) != 0 {
401 401
 			allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), namespace, "namespace must be a valid subdomain"))
402 402
 		}
403 403
 	case "":
... ...
@@ -72,7 +72,7 @@ func (t *PipelineTemplate) Process() (*kapi.List, []error) {
72 72
 func (t *PipelineTemplate) HasJenkinsService(items *kapi.List) bool {
73 73
 	accessor := meta.NewAccessor()
74 74
 	for _, item := range items.Items {
75
-		kind, err := kapi.Scheme.ObjectKind(item)
75
+		kind, _, err := kapi.Scheme.ObjectKind(item)
76 76
 		if err != nil {
77 77
 			glog.Infof("Error checking Jenkins service kind: %v", err)
78 78
 			return false
... ...
@@ -129,7 +129,7 @@ func (bs *SourceBuildStrategy) canRunAsRoot(build *buildapi.Build) bool {
129 129
 		},
130 130
 	}
131 131
 	userInfo := serviceaccount.UserInfo(build.Namespace, build.Spec.ServiceAccount, "")
132
-	attrs := admission.NewAttributesRecord(pod, kapi.Kind("Pod").WithVersion(""), pod.Namespace, pod.Name, kapi.Resource("pods").WithVersion(""), "", admission.Create, userInfo)
132
+	attrs := admission.NewAttributesRecord(pod, pod, kapi.Kind("Pod").WithVersion(""), pod.Namespace, pod.Name, kapi.Resource("pods").WithVersion(""), "", admission.Create, userInfo)
133 133
 	err := bs.AdmissionControl.Admit(attrs)
134 134
 	if err != nil {
135 135
 		glog.V(2).Infof("Admit for root user returned error: %v", err)
... ...
@@ -26,6 +26,10 @@ func (s FakeBuildConfigStore) Delete(obj interface{}) error {
26 26
 	return s.Err
27 27
 }
28 28
 
29
+func (s FakeBuildConfigStore) Resync() error {
30
+	return s.Err
31
+}
32
+
29 33
 func (s FakeBuildConfigStore) List() []interface{} {
30 34
 	return []interface{}{s.Build}
31 35
 }
... ...
@@ -26,6 +26,10 @@ func (s FakeBuildStore) Delete(obj interface{}) error {
26 26
 	return s.Err
27 27
 }
28 28
 
29
+func (s FakeBuildStore) Resync() error {
30
+	return s.Err
31
+}
32
+
29 33
 func (s FakeBuildStore) List() []interface{} {
30 34
 	return []interface{}{s.Build}
31 35
 }
... ...
@@ -120,7 +120,7 @@ func actionsAreEqual(a, b ktestclient.Action) bool {
120 120
 
121 121
 func TestStop(t *testing.T) {
122 122
 	notFound := func() runtime.Object {
123
-		return &(kerrors.NewNotFound(buildapi.Resource("BuildConfig"), configName).(*kerrors.StatusError).ErrStatus)
123
+		return &(kerrors.NewNotFound(buildapi.Resource("BuildConfig"), configName).ErrStatus)
124 124
 	}
125 125
 
126 126
 	tests := map[string]struct {
... ...
@@ -2,6 +2,7 @@ package etcd
2 2
 
3 3
 import (
4 4
 	kapi "k8s.io/kubernetes/pkg/api"
5
+	"k8s.io/kubernetes/pkg/api/rest"
5 6
 	"k8s.io/kubernetes/pkg/fields"
6 7
 	"k8s.io/kubernetes/pkg/labels"
7 8
 	"k8s.io/kubernetes/pkg/registry/generic"
... ...
@@ -64,6 +65,6 @@ func (r *DetailsREST) New() runtime.Object {
64 64
 }
65 65
 
66 66
 // Update finds a resource in the storage and updates it.
67
-func (r *DetailsREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
68
-	return r.store.Update(ctx, obj)
67
+func (r *DetailsREST) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
68
+	return r.store.Update(ctx, name, objInfo)
69 69
 }
... ...
@@ -61,7 +61,7 @@ func (s *storage) CreateBuild(ctx kapi.Context, build *api.Build) error {
61 61
 }
62 62
 
63 63
 func (s *storage) UpdateBuild(ctx kapi.Context, build *api.Build) error {
64
-	_, _, err := s.Update(ctx, build)
64
+	_, _, err := s.Update(ctx, build.Name, rest.DefaultUpdatedObjectInfo(build, kapi.Scheme))
65 65
 	return err
66 66
 }
67 67
 
... ...
@@ -60,7 +60,7 @@ func (s *storage) CreateBuildConfig(ctx kapi.Context, build *api.BuildConfig) er
60 60
 }
61 61
 
62 62
 func (s *storage) UpdateBuildConfig(ctx kapi.Context, build *api.BuildConfig) error {
63
-	_, _, err := s.Update(ctx, build)
63
+	_, _, err := s.Update(ctx, build.Name, rest.DefaultUpdatedObjectInfo(build, kapi.Scheme))
64 64
 	return err
65 65
 }
66 66
 
... ...
@@ -355,6 +355,30 @@ func (eq *EventQueue) ListConsumed() bool {
355 355
 	return eq.lastReplaceKey == ""
356 356
 }
357 357
 
358
+// Resync will touch all objects to put them into the processing queue
359
+func (eq *EventQueue) Resync() error {
360
+	eq.lock.Lock()
361
+	defer eq.lock.Unlock()
362
+
363
+	inQueue := sets.NewString()
364
+	for _, id := range eq.queue {
365
+		inQueue.Insert(id)
366
+	}
367
+
368
+	for _, id := range eq.store.ListKeys() {
369
+		if !inQueue.Has(id) {
370
+			eq.queue = append(eq.queue, id)
371
+		}
372
+	}
373
+
374
+	if len(eq.queue) > 0 {
375
+		eq.cond.Broadcast()
376
+	} else {
377
+		eq.lastReplaceKey = ""
378
+	}
379
+	return nil
380
+}
381
+
358 382
 // NewEventQueue returns a new EventQueue.
359 383
 func NewEventQueue(keyFn kcache.KeyFunc) *EventQueue {
360 384
 	q := &EventQueue{
... ...
@@ -28,19 +28,19 @@ func TestImageStreamImportUnsupported(t *testing.T) {
28 28
 		errFn  func(err error) bool
29 29
 	}{
30 30
 		{
31
-			status: errors.NewNotFound(api.Resource(""), "").(errors.APIStatus).Status(),
31
+			status: errors.NewNotFound(api.Resource(""), "").ErrStatus,
32 32
 			errFn:  func(err error) bool { return err == ErrImageStreamImportUnsupported },
33 33
 		},
34 34
 		{
35
-			status: errors.NewNotFound(api.Resource("ImageStreamImport"), "").(errors.APIStatus).Status(),
35
+			status: errors.NewNotFound(api.Resource("ImageStreamImport"), "").ErrStatus,
36 36
 			errFn:  func(err error) bool { return err != ErrImageStreamImportUnsupported && errors.IsNotFound(err) },
37 37
 		},
38 38
 		{
39
-			status: errors.NewConflict(api.Resource("ImageStreamImport"), "", nil).(errors.APIStatus).Status(),
39
+			status: errors.NewConflict(api.Resource("ImageStreamImport"), "", nil).ErrStatus,
40 40
 			errFn:  func(err error) bool { return err != ErrImageStreamImportUnsupported && errors.IsConflict(err) },
41 41
 		},
42 42
 		{
43
-			status: errors.NewForbidden(api.Resource("ImageStreamImport"), "", nil).(errors.APIStatus).Status(),
43
+			status: errors.NewForbidden(api.Resource("ImageStreamImport"), "", nil).ErrStatus,
44 44
 			errFn:  func(err error) bool { return err == ErrImageStreamImportUnsupported },
45 45
 		},
46 46
 	}
... ...
@@ -41,8 +41,8 @@ func TestErrors(t *testing.T) {
41 41
 	o := testclient.NewObjects(kapi.Scheme, kapi.Codecs.UniversalDecoder())
42 42
 	o.Add(&kapi.List{
43 43
 		Items: []runtime.Object{
44
-			&(errors.NewNotFound(deployapi.Resource("DeploymentConfigList"), "").(*errors.StatusError).ErrStatus),
45
-			&(errors.NewForbidden(deployapi.Resource("DeploymentConfigList"), "", nil).(*errors.StatusError).ErrStatus),
44
+			&(errors.NewNotFound(deployapi.Resource("DeploymentConfigList"), "").ErrStatus),
45
+			&(errors.NewForbidden(deployapi.Resource("DeploymentConfigList"), "", nil).ErrStatus),
46 46
 		},
47 47
 	})
48 48
 	oc, _ := NewFixtureClients(o)
... ...
@@ -6,6 +6,8 @@ import (
6 6
 
7 7
 	"github.com/spf13/cobra"
8 8
 
9
+	kubectl "k8s.io/kubernetes/pkg/kubectl/cmd"
10
+
9 11
 	"github.com/openshift/origin/pkg/cmd/admin/cert"
10 12
 	diagnostics "github.com/openshift/origin/pkg/cmd/admin/diagnostics"
11 13
 	"github.com/openshift/origin/pkg/cmd/admin/groups"
... ...
@@ -45,54 +47,55 @@ func NewCommandAdmin(name, fullName string, out io.Writer, errout io.Writer) *co
45 45
 
46 46
 	groups := templates.CommandGroups{
47 47
 		{
48
-			Message: "Basic Commands:",
48
+			Message: "Component Installation:",
49
+			Commands: []*cobra.Command{
50
+				router.NewCmdRouter(f, fullName, "router", out),
51
+				exipfailover.NewCmdIPFailoverConfig(f, fullName, "ipfailover", out, errout),
52
+				registry.NewCmdRegistry(f, fullName, "registry", out),
53
+			},
54
+		},
55
+		{
56
+			Message: "Security and Policy:",
49 57
 			Commands: []*cobra.Command{
50 58
 				project.NewCmdNewProject(project.NewProjectRecommendedName, fullName+" "+project.NewProjectRecommendedName, f, out),
51 59
 				policy.NewCmdPolicy(policy.PolicyRecommendedName, fullName+" "+policy.PolicyRecommendedName, f, out, errout),
52 60
 				groups.NewCmdGroups(groups.GroupsRecommendedName, fullName+" "+groups.GroupsRecommendedName, f, out),
61
+				cert.NewCmdCert(cert.CertRecommendedName, fullName+" "+cert.CertRecommendedName, out, errout),
62
+				admin.NewCommandOverwriteBootstrapPolicy(admin.OverwriteBootstrapPolicyCommandName, fullName+" "+admin.OverwriteBootstrapPolicyCommandName, fullName+" "+admin.CreateBootstrapPolicyFileCommand, out),
53 63
 			},
54 64
 		},
55 65
 		{
56
-			Message: "Install Commands:",
66
+			Message: "Node Management:",
57 67
 			Commands: []*cobra.Command{
58
-				router.NewCmdRouter(f, fullName, "router", out),
59
-				exipfailover.NewCmdIPFailoverConfig(f, fullName, "ipfailover", out, errout),
60
-				registry.NewCmdRegistry(f, fullName, "registry", out),
68
+				admin.NewCommandNodeConfig(admin.NodeConfigCommandName, fullName+" "+admin.NodeConfigCommandName, out),
69
+				node.NewCommandManageNode(f, node.ManageNodeCommandName, fullName+" "+node.ManageNodeCommandName, out, errout),
70
+				cmdutil.ReplaceCommandName("kubectl", fullName, kubectl.NewCmdCordon(f.Factory, out)),
71
+				cmdutil.ReplaceCommandName("kubectl", fullName, kubectl.NewCmdUncordon(f.Factory, out)),
72
+				cmdutil.ReplaceCommandName("kubectl", fullName, kubectl.NewCmdDrain(f.Factory, out)),
73
+				cmdutil.ReplaceCommandName("kubectl", fullName, kubectl.NewCmdTaint(f.Factory, out)),
74
+				network.NewCmdPodNetwork(network.PodNetworkCommandName, fullName+" "+network.PodNetworkCommandName, f, out),
61 75
 			},
62 76
 		},
63 77
 		{
64
-			Message: "Maintenance Commands:",
78
+			Message: "Maintenance:",
65 79
 			Commands: []*cobra.Command{
66
-				buildchain.NewCmdBuildChain(name, fullName+" "+buildchain.BuildChainRecommendedCommandName, f, out),
67 80
 				diagnostics.NewCmdDiagnostics(diagnostics.DiagnosticsRecommendedName, fullName+" "+diagnostics.DiagnosticsRecommendedName, out),
68
-				node.NewCommandManageNode(f, node.ManageNodeCommandName, fullName+" "+node.ManageNodeCommandName, out, errout),
69 81
 				prune.NewCommandPrune(prune.PruneRecommendedName, fullName+" "+prune.PruneRecommendedName, f, out),
82
+				buildchain.NewCmdBuildChain(name, fullName+" "+buildchain.BuildChainRecommendedCommandName, f, out),
70 83
 			},
71 84
 		},
72 85
 		{
73
-			Message: "Settings Commands:",
86
+			Message: "Configuration:",
74 87
 			Commands: []*cobra.Command{
75
-				cmd.NewCmdConfig(fullName, "config"),
76
-
77
-				// TODO: these probably belong in a sub command
78 88
 				admin.NewCommandCreateKubeConfig(admin.CreateKubeConfigCommandName, fullName+" "+admin.CreateKubeConfigCommandName, out),
79 89
 				admin.NewCommandCreateClient(admin.CreateClientCommandName, fullName+" "+admin.CreateClientCommandName, out),
80 90
 
81
-				cmd.NewCmdCompletion(fullName, f, out),
82
-			},
83
-		},
84
-		{
85
-			Message: "Advanced Commands:",
86
-			Commands: []*cobra.Command{
87
-				network.NewCmdPodNetwork(network.PodNetworkCommandName, fullName+" "+network.PodNetworkCommandName, f, out),
88 91
 				admin.NewCommandCreateBootstrapProjectTemplate(f, admin.CreateBootstrapProjectTemplateCommand, fullName+" "+admin.CreateBootstrapProjectTemplateCommand, out),
89 92
 				admin.NewCommandCreateBootstrapPolicyFile(admin.CreateBootstrapPolicyFileCommand, fullName+" "+admin.CreateBootstrapPolicyFileCommand, out),
93
+
90 94
 				admin.NewCommandCreateLoginTemplate(f, admin.CreateLoginTemplateCommand, fullName+" "+admin.CreateLoginTemplateCommand, out),
91 95
 				admin.NewCommandCreateProviderSelectionTemplate(f, admin.CreateProviderSelectionTemplateCommand, fullName+" "+admin.CreateProviderSelectionTemplateCommand, out),
92 96
 				admin.NewCommandCreateErrorTemplate(f, admin.CreateErrorTemplateCommand, fullName+" "+admin.CreateErrorTemplateCommand, out),
93
-				admin.NewCommandOverwriteBootstrapPolicy(admin.OverwriteBootstrapPolicyCommandName, fullName+" "+admin.OverwriteBootstrapPolicyCommandName, fullName+" "+admin.CreateBootstrapPolicyFileCommand, out),
94
-				admin.NewCommandNodeConfig(admin.NodeConfigCommandName, fullName+" "+admin.NodeConfigCommandName, out),
95
-				cert.NewCmdCert(cert.CertRecommendedName, fullName+" "+cert.CertRecommendedName, out, errout),
96 97
 			},
97 98
 		},
98 99
 	}
... ...
@@ -114,11 +117,18 @@ func NewCommandAdmin(name, fullName string, out io.Writer, errout io.Writer) *co
114 114
 		cmds.AddCommand(cmd)
115 115
 	}
116 116
 
117
+	cmds.AddCommand(
118
+		// part of every root command
119
+		cmd.NewCmdConfig(fullName, "config"),
120
+		cmd.NewCmdCompletion(fullName, f, out),
121
+
122
+		// hidden
123
+		cmd.NewCmdOptions(out),
124
+	)
125
+
117 126
 	if name == fullName {
118 127
 		cmds.AddCommand(version.NewVersionCommand(fullName, false))
119 128
 	}
120 129
 
121
-	cmds.AddCommand(cmd.NewCmdOptions(out))
122
-
123 130
 	return cmds
124 131
 }
... ...
@@ -158,11 +158,11 @@ func (n *NodeOptions) GetNodes() ([]*kapi.Node, error) {
158 158
 }
159 159
 
160 160
 func (n *NodeOptions) GetPrintersByObject(obj runtime.Object) (kubectl.ResourcePrinter, kubectl.ResourcePrinter, error) {
161
-	gvk, err := kapi.Scheme.ObjectKind(obj)
161
+	gvk, _, err := kapi.Scheme.ObjectKinds(obj)
162 162
 	if err != nil {
163 163
 		return nil, nil, err
164 164
 	}
165
-	return n.GetPrinters(gvk)
165
+	return n.GetPrinters(gvk[0])
166 166
 }
167 167
 
168 168
 func (n *NodeOptions) GetPrintersByResource(resource unversioned.GroupVersionResource) (kubectl.ResourcePrinter, kubectl.ResourcePrinter, error) {
... ...
@@ -94,7 +94,7 @@ func (o *CreateClusterQuotaOptions) Complete(cmd *cobra.Command, f *clientcmd.Fa
94 94
 		if err != nil {
95 95
 			return err
96 96
 		}
97
-		o.ClusterQuota.Spec.Quota.Hard[kapi.ResourceName(tokens[0])] = *quantity
97
+		o.ClusterQuota.Spec.Quota.Hard[kapi.ResourceName(tokens[0])] = quantity
98 98
 	}
99 99
 
100 100
 	o.Client, _, err = f.Clients()
... ...
@@ -138,7 +138,7 @@ func RunExport(f *clientcmd.Factory, exporter Exporter, in io.Reader, out io.Wri
138 138
 
139 139
 	var result runtime.Object
140 140
 	if len(asTemplate) > 0 {
141
-		objects, err := resource.AsVersionedObjects(infos, outputVersion.String(), kapi.Codecs.LegacyCodec(outputVersion))
141
+		objects, err := resource.AsVersionedObjects(infos, outputVersion, kapi.Codecs.LegacyCodec(outputVersion))
142 142
 		if err != nil {
143 143
 			return err
144 144
 		}
... ...
@@ -146,12 +146,12 @@ func RunExport(f *clientcmd.Factory, exporter Exporter, in io.Reader, out io.Wri
146 146
 			Objects: objects,
147 147
 		}
148 148
 		template.Name = asTemplate
149
-		result, err = kapi.Scheme.ConvertToVersion(template, outputVersion.String())
149
+		result, err = kapi.Scheme.ConvertToVersion(template, outputVersion)
150 150
 		if err != nil {
151 151
 			return err
152 152
 		}
153 153
 	} else {
154
-		object, err := resource.AsVersionedObject(infos, !one, outputVersion.String(), kapi.Codecs.LegacyCodec(outputVersion))
154
+		object, err := resource.AsVersionedObject(infos, !one, outputVersion, kapi.Codecs.LegacyCodec(outputVersion))
155 155
 		if err != nil {
156 156
 			return err
157 157
 		}
... ...
@@ -54,9 +54,8 @@ func parsePathSpec(path string) (*pathSpec, error) {
54 54
 			Path: path,
55 55
 		}, nil
56 56
 	}
57
-	valid, msg := kvalidation.ValidatePodName(parts[0], false)
58
-	if !valid {
59
-		return nil, fmt.Errorf("invalid pod name %s: %s", parts[0], msg)
57
+	if reasons := kvalidation.ValidatePodName(parts[0], false); len(reasons) != 0 {
58
+		return nil, fmt.Errorf("invalid pod name %s: %s", parts[0], strings.Join(reasons, ", "))
60 59
 	}
61 60
 	return &pathSpec{
62 61
 		PodName: parts[0],
... ...
@@ -215,7 +215,7 @@ func (o *BuildHookOptions) Run() error {
215 215
 	}
216 216
 
217 217
 	if o.PrintObject != nil {
218
-		object, err := resource.AsVersionedObject(infos, !singular, o.OutputVersion.String(), kapi.Codecs.LegacyCodec(o.OutputVersion))
218
+		object, err := resource.AsVersionedObject(infos, !singular, o.OutputVersion, kapi.Codecs.LegacyCodec(o.OutputVersion))
219 219
 		if err != nil {
220 220
 			return err
221 221
 		}
... ...
@@ -22,15 +22,15 @@ const (
22 22
 	deploymentHookLong = `
23 23
 Set or remove a deployment hook on a deployment config
24 24
 
25
-Deployment configs allow hooks to execute at different points in the lifecycle of the 
26
-deployment, depending on the deployment strategy. 
25
+Deployment configs allow hooks to execute at different points in the lifecycle of the
26
+deployment, depending on the deployment strategy.
27 27
 
28
-For deployments with a Recreate strategy, a Pre, Mid, and Post hook can be specified. 
29
-The Pre hook will execute before the deployment starts. The Mid hook will execute once the 
30
-previous deployment has been scaled down to 0, but before the new one ramps up. 
28
+For deployments with a Recreate strategy, a Pre, Mid, and Post hook can be specified.
29
+The Pre hook will execute before the deployment starts. The Mid hook will execute once the
30
+previous deployment has been scaled down to 0, but before the new one ramps up.
31 31
 The Post hook will execute once the deployment has completed.
32 32
 
33
-For deployments with a Rolling strategy, a Pre and Post hook can be specified. 
33
+For deployments with a Rolling strategy, a Pre and Post hook can be specified.
34 34
 The Pre hook will execute before the deployment starts and the Post hook will execute once
35 35
 the deployment has completed.
36 36
 
... ...
@@ -253,7 +253,7 @@ func (o *DeploymentHookOptions) Run() error {
253 253
 	}
254 254
 
255 255
 	if o.PrintObject != nil {
256
-		object, err := resource.AsVersionedObject(infos, !singular, o.OutputVersion.String(), kapi.Codecs.LegacyCodec(o.OutputVersion))
256
+		object, err := resource.AsVersionedObject(infos, !singular, o.OutputVersion, kapi.Codecs.LegacyCodec(o.OutputVersion))
257 257
 		if err != nil {
258 258
 			return err
259 259
 		}
... ...
@@ -236,7 +236,8 @@ func RunEnv(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Comman
236 236
 	}
237 237
 	// Keep a copy of the original objects prior to updating their environment.
238 238
 	// Used in constructing the patch(es) that will be applied in the server.
239
-	oldObjects, err := resource.AsVersionedObjects(infos, clientConfig.GroupVersion.String(), kapi.Codecs.LegacyCodec(*clientConfig.GroupVersion))
239
+	gv := *clientConfig.GroupVersion
240
+	oldObjects, err := resource.AsVersionedObjects(infos, gv, kapi.Codecs.LegacyCodec(gv))
240 241
 	if err != nil {
241 242
 		return err
242 243
 	}
... ...
@@ -332,7 +333,7 @@ func RunEnv(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Comman
332 332
 		if err != nil {
333 333
 			return err
334 334
 		}
335
-		objects, err := resource.AsVersionedObjects(infos, outputVersion.String(), kapi.Codecs.LegacyCodec(outputVersion))
335
+		objects, err := resource.AsVersionedObjects(infos, outputVersion, kapi.Codecs.LegacyCodec(outputVersion))
336 336
 		if err != nil {
337 337
 			return err
338 338
 		}
... ...
@@ -351,7 +352,7 @@ func RunEnv(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Comman
351 351
 		return nil
352 352
 	}
353 353
 
354
-	objects, err := resource.AsVersionedObjects(infos, clientConfig.GroupVersion.String(), kapi.Codecs.LegacyCodec(*clientConfig.GroupVersion))
354
+	objects, err := resource.AsVersionedObjects(infos, gv, kapi.Codecs.LegacyCodec(gv))
355 355
 	if err != nil {
356 356
 		return err
357 357
 	}
... ...
@@ -156,7 +156,7 @@ func CalculatePatches(infos []*resource.Info, encoder runtime.Encoder, mutateFn
156 156
 		}
157 157
 
158 158
 		// TODO: should be via New
159
-		versioned, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion().String())
159
+		versioned, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
160 160
 		if err != nil {
161 161
 			patch.Err = err
162 162
 			continue
... ...
@@ -316,7 +316,7 @@ func (o *ProbeOptions) Run() error {
316 316
 	}
317 317
 
318 318
 	if o.PrintObject != nil {
319
-		object, err := resource.AsVersionedObject(infos, !singular, o.OutputVersion.String(), kapi.Codecs.LegacyCodec(o.OutputVersion))
319
+		object, err := resource.AsVersionedObject(infos, !singular, o.OutputVersion, kapi.Codecs.LegacyCodec(o.OutputVersion))
320 320
 		if err != nil {
321 321
 			return err
322 322
 		}
... ...
@@ -284,7 +284,7 @@ func (o *TriggersOptions) Run() error {
284 284
 		return fmt.Errorf("%s/%s is not a deployment config or build config", infos[0].Mapping.Resource, infos[0].Name)
285 285
 	}
286 286
 	if o.PrintObject != nil {
287
-		object, err := resource.AsVersionedObject(infos, !singular, o.OutputVersion.String(), kapi.Codecs.LegacyCodec(o.OutputVersion))
287
+		object, err := resource.AsVersionedObject(infos, !singular, o.OutputVersion, kapi.Codecs.LegacyCodec(o.OutputVersion))
288 288
 		if err != nil {
289 289
 			return err
290 290
 		}
... ...
@@ -447,7 +447,7 @@ func (v *VolumeOptions) RunVolume(args []string) error {
447 447
 	}
448 448
 
449 449
 	// TODO: replace with a strategic merge patch
450
-	objects, err := resource.AsVersionedObject(infos, false, v.OutputVersion.String(), kapi.Codecs.LegacyCodec(v.OutputVersion))
450
+	objects, err := resource.AsVersionedObject(infos, false, v.OutputVersion, kapi.Codecs.LegacyCodec(v.OutputVersion))
451 451
 	if err != nil {
452 452
 		return err
453 453
 	}
... ...
@@ -11,7 +11,7 @@ import (
11 11
 	kapi "k8s.io/kubernetes/pkg/api"
12 12
 	kerrors "k8s.io/kubernetes/pkg/api/errors"
13 13
 	"k8s.io/kubernetes/pkg/api/unversioned"
14
-	"k8s.io/kubernetes/pkg/apis/extensions"
14
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
15 15
 	kclient "k8s.io/kubernetes/pkg/client/unversioned"
16 16
 	rcutils "k8s.io/kubernetes/pkg/controller/replication"
17 17
 	kctl "k8s.io/kubernetes/pkg/kubectl"
... ...
@@ -264,22 +264,22 @@ func printDeploymentConfigSpec(kc kclient.Interface, dc deployapi.DeploymentConf
264 264
 
265 265
 // TODO: Move this upstream
266 266
 func printAutoscalingInfo(res unversioned.GroupResource, namespace, name string, kclient kclient.Interface, w *tabwriter.Writer) {
267
-	hpaList, err := kclient.Extensions().HorizontalPodAutoscalers(namespace).List(kapi.ListOptions{LabelSelector: labels.Everything()})
267
+	hpaList, err := kclient.Autoscaling().HorizontalPodAutoscalers(namespace).List(kapi.ListOptions{LabelSelector: labels.Everything()})
268 268
 	if err != nil {
269 269
 		return
270 270
 	}
271 271
 
272
-	scaledBy := []extensions.HorizontalPodAutoscaler{}
272
+	scaledBy := []autoscaling.HorizontalPodAutoscaler{}
273 273
 	for _, hpa := range hpaList.Items {
274
-		if hpa.Spec.ScaleRef.Name == name && hpa.Spec.ScaleRef.Kind == res.String() {
274
+		if hpa.Spec.ScaleTargetRef.Name == name && hpa.Spec.ScaleTargetRef.Kind == res.String() {
275 275
 			scaledBy = append(scaledBy, hpa)
276 276
 		}
277 277
 	}
278 278
 
279 279
 	for _, hpa := range scaledBy {
280 280
 		cpuUtil := ""
281
-		if hpa.Spec.CPUUtilization != nil {
282
-			cpuUtil = fmt.Sprintf(", triggered at %d%% CPU usage", hpa.Spec.CPUUtilization.TargetPercentage)
281
+		if hpa.Spec.TargetCPUUtilizationPercentage != nil {
282
+			cpuUtil = fmt.Sprintf(", triggered at %d%% CPU usage", *hpa.Spec.TargetCPUUtilizationPercentage)
283 283
 		}
284 284
 		fmt.Fprintf(w, "Autoscaling:\tbetween %d and %d replicas%s\n", *hpa.Spec.MinReplicas, hpa.Spec.MaxReplicas, cpuUtil)
285 285
 		// TODO: Print a warning in case of multiple hpas.
... ...
@@ -5,7 +5,7 @@ import (
5 5
 	"testing"
6 6
 
7 7
 	kapi "k8s.io/kubernetes/pkg/api"
8
-	"k8s.io/kubernetes/pkg/apis/extensions"
8
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
9 9
 	ktestclient "k8s.io/kubernetes/pkg/client/unversioned/testclient"
10 10
 	"k8s.io/kubernetes/pkg/kubectl"
11 11
 	"k8s.io/kubernetes/pkg/runtime"
... ...
@@ -27,8 +27,8 @@ func TestDeploymentConfigDescriber(t *testing.T) {
27 27
 	})
28 28
 	kFake := &ktestclient.Fake{}
29 29
 	kFake.PrependReactor("list", "horizontalpodautoscalers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
30
-		return true, &extensions.HorizontalPodAutoscalerList{
31
-			Items: []extensions.HorizontalPodAutoscaler{
30
+		return true, &autoscaling.HorizontalPodAutoscalerList{
31
+			Items: []autoscaling.HorizontalPodAutoscaler{
32 32
 				*deployapitest.OkHPAForDeploymentConfig(config, 1, 3),
33 33
 			}}, nil
34 34
 	})
... ...
@@ -915,10 +915,14 @@ func (d *TemplateDescriber) describeObjects(objects []runtime.Object, out *tabwr
915 915
 			continue
916 916
 		}
917 917
 
918
-		gvk, _ := d.ObjectTyper.ObjectKind(obj)
919 918
 		meta := kapi.ObjectMeta{}
920 919
 		meta.Name, _ = d.MetadataAccessor.Name(obj)
921
-		fmt.Fprintf(out, fmt.Sprintf("%s%s\t%s\n", indent, gvk.Kind, meta.Name))
920
+		gvk, _, err := d.ObjectTyper.ObjectKinds(obj)
921
+		if err != nil {
922
+			fmt.Fprintf(out, fmt.Sprintf("%s%s\t%s\n", indent, "<unknown>", meta.Name))
923
+			continue
924
+		}
925
+		fmt.Fprintf(out, fmt.Sprintf("%s%s\t%s\n", indent, gvk[0].Kind, meta.Name))
922 926
 		//meta.Annotations, _ = d.MetadataAccessor.Annotations(obj)
923 927
 		//meta.Labels, _ = d.MetadataAccessor.Labels(obj)
924 928
 		/*if len(meta.Labels) > 0 {
... ...
@@ -11,7 +11,7 @@ import (
11 11
 	kapi "k8s.io/kubernetes/pkg/api"
12 12
 	kapierrors "k8s.io/kubernetes/pkg/api/errors"
13 13
 	"k8s.io/kubernetes/pkg/api/unversioned"
14
-	"k8s.io/kubernetes/pkg/apis/extensions"
14
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
15 15
 	kclient "k8s.io/kubernetes/pkg/client/unversioned"
16 16
 	utilerrors "k8s.io/kubernetes/pkg/util/errors"
17 17
 	"k8s.io/kubernetes/pkg/util/sets"
... ...
@@ -66,7 +66,7 @@ func (d *ProjectStatusDescriber) MakeGraph(namespace string) (osgraph.Graph, set
66 66
 		&secretLoader{namespace: namespace, lister: d.K},
67 67
 		&rcLoader{namespace: namespace, lister: d.K},
68 68
 		&podLoader{namespace: namespace, lister: d.K},
69
-		&horizontalPodAutoscalerLoader{namespace: namespace, lister: d.K.Extensions()},
69
+		&horizontalPodAutoscalerLoader{namespace: namespace, lister: d.K.Autoscaling()},
70 70
 		// TODO check swagger for feature enablement and selectively add bcLoader and buildLoader
71 71
 		// then remove errors.TolerateNotFoundError method.
72 72
 		&bcLoader{namespace: namespace, lister: d.C},
... ...
@@ -1188,7 +1188,7 @@ func (l *podLoader) AddToGraph(g osgraph.Graph) error {
1188 1188
 type horizontalPodAutoscalerLoader struct {
1189 1189
 	namespace string
1190 1190
 	lister    kclient.HorizontalPodAutoscalersNamespacer
1191
-	items     []extensions.HorizontalPodAutoscaler
1191
+	items     []autoscaling.HorizontalPodAutoscaler
1192 1192
 }
1193 1193
 
1194 1194
 func (l *horizontalPodAutoscalerLoader) Load() error {
... ...
@@ -20,9 +20,12 @@ var MissingCommands = sets.NewString(
20 20
 	"namespace", "rolling-update",
21 21
 	"cluster-info", "api-versions",
22 22
 	"stop",
23
+
24
+	// are on admin commands
23 25
 	"cordon",
24 26
 	"drain",
25 27
 	"uncordon",
28
+	"taint",
26 29
 )
27 30
 
28 31
 // WhitelistedCommands is the list of commands we're never going to have in oc
... ...
@@ -120,7 +120,7 @@ func (o *PatchOptions) RunPatch() error {
120 120
 	}
121 121
 	info := infos[0]
122 122
 
123
-	originalObjJS, err := runtime.Encode(configapi.Codecs.LegacyCodec(), info.VersionedObject.(runtime.Object))
123
+	originalObjJS, err := runtime.Encode(configapi.Codecs.LegacyCodec(info.Mapping.GroupVersionKind.GroupVersion()), info.VersionedObject.(runtime.Object))
124 124
 	if err != nil {
125 125
 		return err
126 126
 	}
... ...
@@ -10,6 +10,7 @@ import (
10 10
 
11 11
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
12 12
 	deploytest "github.com/openshift/origin/pkg/deploy/api/test"
13
+	deployv1 "github.com/openshift/origin/pkg/deploy/api/v1"
13 14
 	scalertest "github.com/openshift/origin/pkg/deploy/scaler/test"
14 15
 	"github.com/openshift/origin/pkg/deploy/strategy"
15 16
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
... ...
@@ -197,7 +198,7 @@ func TestDeployer_deployScenarios(t *testing.T) {
197 197
 }
198 198
 
199 199
 func mkdeployment(version int64, status deployapi.DeploymentStatus) *kapi.ReplicationController {
200
-	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(version), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
200
+	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(version), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
201 201
 	deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(status)
202 202
 	return deployment
203 203
 }
... ...
@@ -82,7 +82,7 @@ func (o CreateBootstrapPolicyFileOptions) CreateBootstrapPolicyFile() error {
82 82
 
83 83
 	clusterRoles := bootstrappolicy.GetBootstrapClusterRoles()
84 84
 	for i := range clusterRoles {
85
-		versionedObject, err := kapi.Scheme.ConvertToVersion(&clusterRoles[i], latest.Version.String())
85
+		versionedObject, err := kapi.Scheme.ConvertToVersion(&clusterRoles[i], latest.Version)
86 86
 		if err != nil {
87 87
 			return err
88 88
 		}
... ...
@@ -91,7 +91,7 @@ func (o CreateBootstrapPolicyFileOptions) CreateBootstrapPolicyFile() error {
91 91
 
92 92
 	clusterRoleBindings := bootstrappolicy.GetBootstrapClusterRoleBindings()
93 93
 	for i := range clusterRoleBindings {
94
-		versionedObject, err := kapi.Scheme.ConvertToVersion(&clusterRoleBindings[i], latest.Version.String())
94
+		versionedObject, err := kapi.Scheme.ConvertToVersion(&clusterRoleBindings[i], latest.Version)
95 95
 		if err != nil {
96 96
 			return err
97 97
 		}
... ...
@@ -100,7 +100,7 @@ func (o CreateBootstrapPolicyFileOptions) CreateBootstrapPolicyFile() error {
100 100
 
101 101
 	openshiftRoles := bootstrappolicy.GetBootstrapOpenshiftRoles(o.OpenShiftSharedResourcesNamespace)
102 102
 	for i := range openshiftRoles {
103
-		versionedObject, err := kapi.Scheme.ConvertToVersion(&openshiftRoles[i], latest.Version.String())
103
+		versionedObject, err := kapi.Scheme.ConvertToVersion(&openshiftRoles[i], latest.Version)
104 104
 		if err != nil {
105 105
 			return err
106 106
 		}
... ...
@@ -109,14 +109,14 @@ func (o CreateBootstrapPolicyFileOptions) CreateBootstrapPolicyFile() error {
109 109
 
110 110
 	openshiftRoleBindings := bootstrappolicy.GetBootstrapOpenshiftRoleBindings(o.OpenShiftSharedResourcesNamespace)
111 111
 	for i := range openshiftRoleBindings {
112
-		versionedObject, err := kapi.Scheme.ConvertToVersion(&openshiftRoleBindings[i], latest.Version.String())
112
+		versionedObject, err := kapi.Scheme.ConvertToVersion(&openshiftRoleBindings[i], latest.Version)
113 113
 		if err != nil {
114 114
 			return err
115 115
 		}
116 116
 		policyTemplate.Objects = append(policyTemplate.Objects, versionedObject)
117 117
 	}
118 118
 
119
-	versionedPolicyTemplate, err := kapi.Scheme.ConvertToVersion(policyTemplate, latest.Version.String())
119
+	versionedPolicyTemplate, err := kapi.Scheme.ConvertToVersion(policyTemplate, latest.Version)
120 120
 	if err != nil {
121 121
 		return err
122 122
 	}
... ...
@@ -432,11 +432,11 @@ func (o CreateNodeConfigOptions) MakeNodeConfig(serverCertFile, serverKeyFile, n
432 432
 	}
433 433
 
434 434
 	// Roundtrip the config to v1 and back to ensure proper defaults are set.
435
-	ext, err := configapi.Scheme.ConvertToVersion(config, latestconfigapi.Version.String())
435
+	ext, err := configapi.Scheme.ConvertToVersion(config, latestconfigapi.Version)
436 436
 	if err != nil {
437 437
 		return err
438 438
 	}
439
-	internal, err := configapi.Scheme.ConvertToVersion(ext, configapi.SchemeGroupVersion.String())
439
+	internal, err := configapi.Scheme.ConvertToVersion(ext, configapi.SchemeGroupVersion)
440 440
 	if err != nil {
441 441
 		return err
442 442
 	}
... ...
@@ -293,7 +293,7 @@ func addConversionFuncs(scheme *runtime.Scheme) {
293 293
 			}
294 294
 			if in.Provider.Object != nil {
295 295
 				var err error
296
-				out.Provider, err = internal.Scheme.ConvertToVersion(in.Provider.Object, internal.SchemeGroupVersion.String())
296
+				out.Provider, err = internal.Scheme.ConvertToVersion(in.Provider.Object, internal.SchemeGroupVersion)
297 297
 				if err != nil {
298 298
 					return err
299 299
 				}
... ...
@@ -317,7 +317,7 @@ func addConversionFuncs(scheme *runtime.Scheme) {
317 317
 			}
318 318
 			if in.Configuration.Object != nil {
319 319
 				var err error
320
-				out.Configuration, err = internal.Scheme.ConvertToVersion(in.Configuration.Object, internal.SchemeGroupVersion.String())
320
+				out.Configuration, err = internal.Scheme.ConvertToVersion(in.Configuration.Object, internal.SchemeGroupVersion)
321 321
 				if err != nil {
322 322
 					return err
323 323
 				}
... ...
@@ -4,7 +4,6 @@ import (
4 4
 	"testing"
5 5
 
6 6
 	"github.com/ghodss/yaml"
7
-	"speter.net/go/exp/math/dec/inf"
8 7
 
9 8
 	"k8s.io/kubernetes/pkg/api/unversioned"
10 9
 	"k8s.io/kubernetes/pkg/runtime"
... ...
@@ -532,7 +531,7 @@ volumeConfig:
532 532
   localQuota:
533 533
     perFSGroup: 200000
534 534
 `,
535
-			expected: "200000",
535
+			expected: "200k",
536 536
 		},
537 537
 		"Kb quota": {
538 538
 			config: `
... ...
@@ -541,7 +540,7 @@ volumeConfig:
541 541
   localQuota:
542 542
     perFSGroup: 200Ki
543 543
 `,
544
-			expected: "204800",
544
+			expected: "200Ki",
545 545
 		},
546 546
 		"Mb quota": {
547 547
 			config: `
... ...
@@ -550,7 +549,7 @@ volumeConfig:
550 550
   localQuota:
551 551
     perFSGroup: 512Mi
552 552
 `,
553
-			expected: "536870912",
553
+			expected: "512Mi",
554 554
 		},
555 555
 		"Gb quota": {
556 556
 			config: `
... ...
@@ -559,7 +558,7 @@ volumeConfig:
559 559
   localQuota:
560 560
     perFSGroup: 2Gi
561 561
 `,
562
-			expected: "2147483648",
562
+			expected: "2Gi",
563 563
 		},
564 564
 		"Tb quota": {
565 565
 			config: `
... ...
@@ -568,7 +567,7 @@ volumeConfig:
568 568
   localQuota:
569 569
     perFSGroup: 2Ti
570 570
 `,
571
-			expected: "2199023255552",
571
+			expected: "2Ti",
572 572
 		},
573 573
 		// This is invalid config, would be caught by validation but just
574 574
 		// testing it parses ok:
... ...
@@ -579,7 +578,7 @@ volumeConfig:
579 579
   localQuota:
580 580
     perFSGroup: -512Mi
581 581
 `,
582
-			expected: "-536870912",
582
+			expected: "-512Mi",
583 583
 		},
584 584
 		"zero quota": {
585 585
 			config: `
... ...
@@ -599,19 +598,16 @@ volumeConfig:
599 599
 			t.Errorf("Error reading yaml: %s", err.Error())
600 600
 		}
601 601
 		if test.expected == "" && nodeConfig.VolumeConfig.LocalQuota.PerFSGroup != nil {
602
-			t.Errorf("Expected empty quota but got: %s", *nodeConfig.VolumeConfig.LocalQuota.PerFSGroup)
602
+			t.Errorf("Expected empty quota but got: %v", nodeConfig.VolumeConfig.LocalQuota.PerFSGroup)
603 603
 		}
604 604
 		if test.expected != "" {
605 605
 			if nodeConfig.VolumeConfig.LocalQuota.PerFSGroup == nil {
606 606
 				t.Errorf("Expected quota: %s, got: nil", test.expected)
607 607
 			} else {
608
-				amount := nodeConfig.VolumeConfig.LocalQuota.PerFSGroup.Amount
608
+				amount := nodeConfig.VolumeConfig.LocalQuota.PerFSGroup
609 609
 				t.Logf("%s", amount.String())
610
-				rounded := new(inf.Dec)
611
-				rounded.Round(amount, 0, inf.RoundUp)
612
-				t.Logf("%s", rounded.String())
613
-				if test.expected != rounded.String() {
614
-					t.Errorf("Expected quota: %s, got: %s", test.expected, rounded.String())
610
+				if test.expected != amount.String() {
611
+					t.Errorf("Expected quota: %s, got: %s", test.expected, amount.String())
615 612
 				}
616 613
 			}
617 614
 		}
... ...
@@ -276,8 +276,8 @@ func ValidateServiceAccountConfig(config api.ServiceAccountConfig, builtInKubern
276 276
 	}
277 277
 
278 278
 	for i, name := range config.ManagedNames {
279
-		if ok, msg := kvalidation.ValidateServiceAccountName(name, false); !ok {
280
-			validationResults.AddErrors(field.Invalid(managedNamesPath.Index(i), name, msg))
279
+		if reasons := kvalidation.ValidateServiceAccountName(name, false); len(reasons) != 0 {
280
+			validationResults.AddErrors(field.Invalid(managedNamesPath.Index(i), name, strings.Join(reasons, ", ")))
281 281
 		}
282 282
 	}
283 283
 
... ...
@@ -574,7 +574,7 @@ func ValidateRoutingConfig(config api.RoutingConfig, fldPath *field.Path) field.
574 574
 
575 575
 	if len(config.Subdomain) == 0 {
576 576
 		allErrs = append(allErrs, field.Required(fldPath.Child("subdomain"), ""))
577
-	} else if !kuval.IsDNS1123Subdomain(config.Subdomain) {
577
+	} else if len(kuval.IsDNS1123Subdomain(config.Subdomain)) != 0 {
578 578
 		allErrs = append(allErrs, field.Invalid(fldPath.Child("subdomain"), config.Subdomain, "must be a valid subdomain"))
579 579
 	}
580 580
 
... ...
@@ -149,8 +149,8 @@ func ValidateIdentityProvider(identityProvider api.IdentityProvider, fldPath *fi
149 149
 	if len(identityProvider.Name) == 0 {
150 150
 		validationResults.AddErrors(field.Required(fldPath.Child("name"), ""))
151 151
 	}
152
-	if ok, err := validation.ValidateIdentityProviderName(identityProvider.Name); !ok {
153
-		validationResults.AddErrors(field.Invalid(fldPath.Child("name"), identityProvider.Name, err))
152
+	if reasons := validation.ValidateIdentityProviderName(identityProvider.Name); len(reasons) != 0 {
153
+		validationResults.AddErrors(field.Invalid(fldPath.Child("name"), identityProvider.Name, strings.Join(reasons, ", ")))
154 154
 	}
155 155
 
156 156
 	if len(identityProvider.MappingMethod) == 0 {
... ...
@@ -167,7 +167,7 @@ func ValidateNamedCertificates(fldPath *field.Path, namedCertificates []api.Name
167 167
 			// validate names as domain names or *.*.foo.com domain names
168 168
 			validDNSName := true
169 169
 			for _, s := range strings.Split(name, ".") {
170
-				if s != "*" && !utilvalidation.IsDNS1123Label(s) {
170
+				if s != "*" && len(utilvalidation.IsDNS1123Label(s)) != 0 {
171 171
 					validDNSName = false
172 172
 				}
173 173
 			}
... ...
@@ -313,7 +313,7 @@ func ValidateNamespace(namespace string, fldPath *field.Path) field.ErrorList {
313 313
 
314 314
 	if len(namespace) == 0 {
315 315
 		allErrs = append(allErrs, field.Required(fldPath, ""))
316
-	} else if ok, _ := kvalidation.ValidateNamespaceName(namespace, false); !ok {
316
+	} else if reasons := kvalidation.ValidateNamespaceName(namespace, false); len(reasons) != 0 {
317 317
 		allErrs = append(allErrs, field.Invalid(fldPath, namespace, "must be a valid namespace"))
318 318
 	}
319 319
 
... ...
@@ -26,6 +26,7 @@ import (
26 26
 	clientadapter "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset"
27 27
 	"k8s.io/kubernetes/pkg/cloudprovider"
28 28
 	"k8s.io/kubernetes/pkg/genericapiserver"
29
+	genericapiserveroptions "k8s.io/kubernetes/pkg/genericapiserver/options"
29 30
 	kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
30 31
 	"k8s.io/kubernetes/pkg/master"
31 32
 	"k8s.io/kubernetes/pkg/registry/cachesize"
... ...
@@ -251,7 +252,7 @@ func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextM
251 251
 		KeyFile:    options.EtcdClientInfo.ClientCert.KeyFile,
252 252
 		CertFile:   options.EtcdClientInfo.ClientCert.CertFile,
253 253
 		CAFile:     options.EtcdClientInfo.CA,
254
-		DeserializationCacheSize: genericapiserver.DefaultDeserializationCacheSize,
254
+		DeserializationCacheSize: genericapiserveroptions.DefaultDeserializationCacheSize,
255 255
 	}
256 256
 	storageFactory := genericapiserver.NewDefaultStorageFactory(etcdConfig, "", kapi.Codecs, resourceEncodingConfig, master.DefaultAPIResourceConfigSource())
257 257
 	// the order here is important, it defines which version will be used for storage
... ...
@@ -13,7 +13,7 @@ import (
13 13
 	"k8s.io/kubernetes/pkg/apimachinery/registered"
14 14
 	"k8s.io/kubernetes/pkg/apis/componentconfig"
15 15
 	extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
16
-	"k8s.io/kubernetes/pkg/genericapiserver"
16
+	genericapiserveroptions "k8s.io/kubernetes/pkg/genericapiserver/options"
17 17
 	kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
18 18
 	"k8s.io/kubernetes/pkg/storage/storagebackend"
19 19
 	utilconfig "k8s.io/kubernetes/pkg/util/config"
... ...
@@ -29,7 +29,7 @@ func TestAPIServerDefaults(t *testing.T) {
29 29
 	// If the default changes (new fields are added, or default values change), we want to know
30 30
 	// Once we've reacted to the changes appropriately in BuildKubernetesMasterConfig(), update this expected default to match the new upstream defaults
31 31
 	expectedDefaults := &apiserveroptions.APIServer{
32
-		ServerRunOptions: &genericapiserver.ServerRunOptions{
32
+		ServerRunOptions: &genericapiserveroptions.ServerRunOptions{
33 33
 			BindAddress:            net.ParseIP("0.0.0.0"),
34 34
 			CertDirectory:          "/var/run/kubernetes",
35 35
 			InsecureBindAddress:    net.ParseIP("127.0.0.1"),
... ...
@@ -49,15 +49,15 @@ func TestAPIServerDefaults(t *testing.T) {
49 49
 			DefaultStorageVersions: registered.AllPreferredGroupVersions(),
50 50
 			StorageConfig: storagebackend.Config{
51 51
 				Prefix: "/registry",
52
-				DeserializationCacheSize: genericapiserver.DefaultDeserializationCacheSize,
52
+				DeserializationCacheSize: genericapiserveroptions.DefaultDeserializationCacheSize,
53 53
 			},
54
+			DefaultStorageMediaType: "application/json",
55
+			AdmissionControl:        "AlwaysAdmit",
56
+			AuthorizationMode:       "AlwaysAllow",
57
+			DeleteCollectionWorkers: 1,
58
+			MasterServiceNamespace:  "default",
54 59
 		},
55
-		DefaultStorageMediaType: "application/json",
56
-		AdmissionControl:        "AlwaysAdmit",
57
-		AuthorizationMode:       "AlwaysAllow",
58
-		DeleteCollectionWorkers: 1,
59
-		EventTTL:                1 * time.Hour,
60
-		MasterServiceNamespace:  "default",
60
+		EventTTL: 1 * time.Hour,
61 61
 		KubeletConfig: kubeletclient.KubeletClientConfig{
62 62
 			Port:        10250,
63 63
 			EnableHttps: true,
... ...
@@ -232,7 +232,7 @@ func (c *NodeConfig) EnsureLocalQuota(nodeConfig configapi.NodeConfig) {
232 232
 		// Can't really do type checking or use a constant here as they are not exported:
233 233
 		if plugin.CanSupport(emptyDirSpec) {
234 234
 			wrapper := emptydir.EmptyDirQuotaPlugin{
235
-				Wrapped:         plugin,
235
+				VolumePlugin:    plugin,
236 236
 				Quota:           *nodeConfig.VolumeConfig.LocalQuota.PerFSGroup,
237 237
 				QuotaApplicator: quotaApplicator,
238 238
 			}
... ...
@@ -128,7 +128,7 @@ func forbidden(reason string, attributes authorizer.AuthorizationAttributes, w h
128 128
 	// We don't have direct access to kind or name (not that those apply either in the general case)
129 129
 	// We create a NewForbidden to stay close the API, but then we override the message to get a serialization
130 130
 	// that makes sense when a human reads it.
131
-	forbiddenError, _ := kapierrors.NewForbidden(unversioned.GroupResource{Group: group, Resource: resource}, name, errors.New("") /*discarded*/).(*kapierrors.StatusError)
131
+	forbiddenError := kapierrors.NewForbidden(unversioned.GroupResource{Group: group, Resource: resource}, name, errors.New("") /*discarded*/)
132 132
 	forbiddenError.ErrStatus.Message = reason
133 133
 
134 134
 	formatted := &bytes.Buffer{}
... ...
@@ -22,7 +22,7 @@ import (
22 22
 	kclient "k8s.io/kubernetes/pkg/client/unversioned"
23 23
 	clientadapter "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset"
24 24
 	sacontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
25
-	"k8s.io/kubernetes/pkg/genericapiserver"
25
+	genericapiserveroptions "k8s.io/kubernetes/pkg/genericapiserver/options"
26 26
 	kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
27 27
 	"k8s.io/kubernetes/pkg/runtime"
28 28
 	"k8s.io/kubernetes/pkg/serviceaccount"
... ...
@@ -343,7 +343,7 @@ func newServiceAccountTokenGetter(options configapi.MasterConfig, client newetcd
343 343
 	} else {
344 344
 		// When we're running in-process, go straight to etcd (using the KubernetesStorageVersion/KubernetesStoragePrefix, since service accounts are kubernetes objects)
345 345
 		codec := kapi.Codecs.LegacyCodec(unversioned.GroupVersion{Group: kapi.GroupName, Version: options.EtcdStorageConfig.KubernetesStorageVersion})
346
-		ketcdHelper := etcdstorage.NewEtcdStorage(client, codec, options.EtcdStorageConfig.KubernetesStoragePrefix, false, genericapiserver.DefaultDeserializationCacheSize)
346
+		ketcdHelper := etcdstorage.NewEtcdStorage(client, codec, options.EtcdStorageConfig.KubernetesStoragePrefix, false, genericapiserveroptions.DefaultDeserializationCacheSize)
347 347
 		tokenGetter = sacontroller.NewGetterFromStorageInterface(ketcdHelper)
348 348
 	}
349 349
 	return tokenGetter, nil
... ...
@@ -734,7 +734,7 @@ func (c *MasterConfig) OriginNamespaceControllerClients() (*osclient.Client, *kc
734 734
 
735 735
 // NewEtcdStorage returns a storage interface for the provided storage version.
736 736
 func NewEtcdStorage(client newetcdclient.Client, version unversioned.GroupVersion, prefix string) (oshelper storage.Interface, err error) {
737
-	return etcdstorage.NewEtcdStorage(client, kapi.Codecs.LegacyCodec(version), prefix, false, genericapiserver.DefaultDeserializationCacheSize), nil
737
+	return etcdstorage.NewEtcdStorage(client, kapi.Codecs.LegacyCodec(version), prefix, false, genericapiserveroptions.DefaultDeserializationCacheSize), nil
738 738
 }
739 739
 
740 740
 // GetServiceAccountClients returns an OpenShift and Kubernetes client with the credentials of the
... ...
@@ -9,7 +9,7 @@ import (
9 9
 	"k8s.io/kubernetes/pkg/api/rest"
10 10
 	extapi "k8s.io/kubernetes/pkg/apis/extensions"
11 11
 	"k8s.io/kubernetes/pkg/client/unversioned/testclient"
12
-	"k8s.io/kubernetes/pkg/genericapiserver"
12
+	genericapiserveroptions "k8s.io/kubernetes/pkg/genericapiserver/options"
13 13
 	kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
14 14
 	etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
15 15
 
... ...
@@ -72,7 +72,7 @@ func TestValidationRegistration(t *testing.T) {
72 72
 
73 73
 // fakeMasterConfig creates a new fake master config with an empty kubelet config and dummy storage.
74 74
 func fakeMasterConfig() *MasterConfig {
75
-	etcdHelper := etcdstorage.NewEtcdStorage(nil, api.Codecs.LegacyCodec(), "", false, genericapiserver.DefaultDeserializationCacheSize)
75
+	etcdHelper := etcdstorage.NewEtcdStorage(nil, api.Codecs.LegacyCodec(), "", false, genericapiserveroptions.DefaultDeserializationCacheSize)
76 76
 
77 77
 	informerFactory := shared.NewInformerFactory(testclient.NewSimpleFake(), otestclient.NewSimpleFake(), shared.DefaultListerWatcherOverrides{}, 1*time.Second)
78 78
 	return &MasterConfig{
... ...
@@ -641,11 +641,11 @@ func getPort(theURL url.URL) int {
641 641
 
642 642
 // applyDefaults roundtrips the config to v1 and back to ensure proper defaults are set.
643 643
 func applyDefaults(config runtime.Object, version unversioned.GroupVersion) (runtime.Object, error) {
644
-	ext, err := configapi.Scheme.ConvertToVersion(config, version.String())
644
+	ext, err := configapi.Scheme.ConvertToVersion(config, version)
645 645
 	if err != nil {
646 646
 		return nil, err
647 647
 	}
648
-	return configapi.Scheme.ConvertToVersion(ext, configapi.SchemeGroupVersion.String())
648
+	return configapi.Scheme.ConvertToVersion(ext, configapi.SchemeGroupVersion)
649 649
 }
650 650
 
651 651
 func servingInfoForAddr(addr *flagtypes.Addr) configapi.ServingInfo {
... ...
@@ -38,7 +38,7 @@ func (c *fakeCodec) Decode([]byte, *unversioned.GroupVersionKind, runtime.Object
38 38
 	return nil, nil, nil
39 39
 }
40 40
 
41
-func (c *fakeCodec) EncodeToStream(obj runtime.Object, stream io.Writer, overrides ...unversioned.GroupVersion) error {
41
+func (c *fakeCodec) Encode(obj runtime.Object, stream io.Writer) error {
42 42
 	return nil
43 43
 }
44 44
 
... ...
@@ -408,6 +408,16 @@ func NewFactory(clientConfig kclientcmd.ClientConfig) *Factory {
408 408
 			return kAttachablePodForObjectFunc(object)
409 409
 		}
410 410
 	}
411
+	kProtocolsForObject := w.Factory.ProtocolsForObject
412
+	w.ProtocolsForObject = func(object runtime.Object) (map[string]string, error) {
413
+		switch t := object.(type) {
414
+		case *deployapi.DeploymentConfig:
415
+			return getProtocols(t.Spec.Template.Spec), nil
416
+		default:
417
+			return kProtocolsForObject(object)
418
+		}
419
+	}
420
+
411 421
 	kSwaggerSchemaFunc := w.Factory.SwaggerSchema
412 422
 	w.Factory.SwaggerSchema = func(gvk unversioned.GroupVersionKind) (*swagger.ApiDeclaration, error) {
413 423
 		if !latest.OriginKind(gvk) {
... ...
@@ -519,6 +529,16 @@ func getPorts(spec api.PodSpec) []string {
519 519
 	return result
520 520
 }
521 521
 
522
+func getProtocols(spec api.PodSpec) map[string]string {
523
+	result := make(map[string]string)
524
+	for _, container := range spec.Containers {
525
+		for _, port := range container.Ports {
526
+			result[strconv.Itoa(int(port.ContainerPort))] = string(port.Protocol)
527
+		}
528
+	}
529
+	return result
530
+}
531
+
522 532
 func ResourceMapper(f *Factory) *resource.Mapper {
523 533
 	mapper, typer := f.Object(false)
524 534
 	return &resource.Mapper{
... ...
@@ -73,6 +73,10 @@ func (e ShortcutExpander) RESTMapping(gk unversioned.GroupKind, versions ...stri
73 73
 	return e.RESTMapper.RESTMapping(gk, versions...)
74 74
 }
75 75
 
76
+func (e ShortcutExpander) RESTMappings(gk unversioned.GroupKind) ([]*meta.RESTMapping, error) {
77
+	return e.RESTMapper.RESTMappings(gk)
78
+}
79
+
76 80
 // userResources are the resource names that apply to the primary, user facing resources used by
77 81
 // client tools. They are in deletion-first order - dependent resources should be last.
78 82
 var userResources = []string{
... ...
@@ -20,6 +20,16 @@ import (
20 20
 // ErrExit is a marker interface for cli commands indicating that the response has been processed
21 21
 var ErrExit = fmt.Errorf("exit directly")
22 22
 
23
+// ReplaceCommandName recursively processes the examples in a given command to change a hardcoded
24
+// command name (like 'kubectl' to the appropriate target name). It returns c.
25
+func ReplaceCommandName(from, to string, c *cobra.Command) *cobra.Command {
26
+	c.Example = strings.Replace(c.Example, from, to, -1)
27
+	for _, sub := range c.Commands() {
28
+		ReplaceCommandName(from, to, sub)
29
+	}
30
+	return c
31
+}
32
+
23 33
 // RequireNoArguments exits with a usage error if extra arguments are provided.
24 34
 func RequireNoArguments(c *cobra.Command, args []string) {
25 35
 	if len(args) > 0 {
... ...
@@ -82,7 +92,7 @@ func convertItemsForDisplay(objs []runtime.Object, preferredVersions ...unversio
82 82
 
83 83
 	for i := range objs {
84 84
 		obj := objs[i]
85
-		kind, err := kapi.Scheme.ObjectKind(obj)
85
+		kind, _, err := kapi.Scheme.ObjectKind(obj)
86 86
 		if err != nil {
87 87
 			return nil, err
88 88
 		}
... ...
@@ -110,7 +120,7 @@ func convertItemsForDisplay(objs []runtime.Object, preferredVersions ...unversio
110 110
 			}
111 111
 		}
112 112
 
113
-		convertedObject, err := kapi.Scheme.ConvertToVersion(obj, actualOutputVersion.String())
113
+		convertedObject, err := kapi.Scheme.ConvertToVersion(obj, actualOutputVersion)
114 114
 		if err != nil {
115 115
 			return nil, err
116 116
 		}
... ...
@@ -46,7 +46,8 @@ func (_ *Helper) GetKubeClient() (*KubeDocker, string, error) {
46 46
 	} else {
47 47
 		endpoint = "unix:///var/run/docker.sock"
48 48
 	}
49
-	client := dockertools.ConnectToDockerOrDie(endpoint)
49
+	// TODO: set a timeout here
50
+	client := dockertools.ConnectToDockerOrDie(endpoint, 0)
50 51
 	originClient := &KubeDocker{client}
51 52
 	return originClient, endpoint, nil
52 53
 }
... ...
@@ -76,7 +76,7 @@ func RequestToken(clientCfg *restclient.Config, reader io.Reader, defaultUsernam
76 76
 			unauthorizedError := apierrs.NewUnauthorized("")
77 77
 			// Attempt to read body content and include as an error detail
78 78
 			if details, err := ioutil.ReadAll(resp.Body); err == nil && len(details) > 0 {
79
-				unauthorizedError.(*apierrs.StatusError).ErrStatus.Details = &unversioned.StatusDetails{
79
+				unauthorizedError.ErrStatus.Details = &unversioned.StatusDetails{
80 80
 					Causes: []unversioned.StatusCause{
81 81
 						{Message: string(details)},
82 82
 					},
... ...
@@ -38,17 +38,32 @@ type RetryController struct {
38 38
 
39 39
 // Queue is a narrow abstraction of a cache.FIFO.
40 40
 type Queue interface {
41
-	Pop() interface{}
41
+	Pop(kcache.PopProcessFunc) (interface{}, error)
42 42
 }
43 43
 
44 44
 // Run begins processing resources from Queue asynchronously.
45 45
 func (c *RetryController) Run() {
46
-	go utilwait.Forever(func() { c.handleOne(c.Queue.Pop()) }, 0)
46
+	go utilwait.Forever(c.pop, 0)
47 47
 }
48 48
 
49 49
 // RunUntil begins processing resources from Queue asynchronously until stopCh is closed.
50 50
 func (c *RetryController) RunUntil(stopCh <-chan struct{}) {
51
-	go utilwait.Until(func() { c.handleOne(c.Queue.Pop()) }, 0, stopCh)
51
+	go utilwait.Until(c.pop, 0, stopCh)
52
+}
53
+
54
+// pop removes the next item from the stack and handles it. If Handle returns
55
+// a retryable error, the handled resource is passed to the RetryManager. If
56
+// no error is returned from Handle, the RetryManager is asked to forget the
57
+// processed resource.
58
+// TODO: Pop holds the lock on the queue, which means we can't AddIfNotPresent
59
+//   from within Handle.  We need to fix that.
60
+func (c *RetryController) pop() {
61
+	resource, err := c.Queue.Pop(c.Handle)
62
+	if err != nil {
63
+		c.Retry(resource, err)
64
+		return
65
+	}
66
+	c.Forget(resource)
52 67
 }
53 68
 
54 69
 // handleOne processes resource with Handle. If Handle returns a retryable
... ...
@@ -144,13 +144,13 @@ func TestRetryController_realFifoEventOrdering(t *testing.T) {
144 144
 	}
145 145
 
146 146
 	fifo.Add(testObj{"a", 1})
147
-	controller.handleOne(fifo.Pop())
147
+	controller.handleOne(kcache.Pop(fifo))
148 148
 
149 149
 	if e, a := 1, len(fifo.List()); e != a {
150 150
 		t.Fatalf("expected queue length %d, got %d", e, a)
151 151
 	}
152 152
 
153
-	obj := fifo.Pop()
153
+	obj := kcache.Pop(fifo)
154 154
 	if e, a := 2, obj.(testObj).value; e != a {
155 155
 		t.Fatalf("expected queued value %d, got %d", e, a)
156 156
 	}
... ...
@@ -213,8 +213,10 @@ func (t *testFifo) AddIfNotPresent(obj interface{}) error {
213 213
 	return t.AddIfNotPresentFunc(obj)
214 214
 }
215 215
 
216
-func (t *testFifo) Pop() interface{} {
217
-	return t.PopFunc()
216
+func (t *testFifo) Pop(fn kcache.PopProcessFunc) (interface{}, error) {
217
+	obj := t.PopFunc()
218
+	err := fn(obj)
219
+	return obj, err
218 220
 }
219 221
 
220 222
 type testRetryManager struct {
... ...
@@ -3,7 +3,7 @@ package test
3 3
 import (
4 4
 	kapi "k8s.io/kubernetes/pkg/api"
5 5
 	"k8s.io/kubernetes/pkg/api/resource"
6
-	"k8s.io/kubernetes/pkg/apis/extensions"
6
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
7 7
 	"k8s.io/kubernetes/pkg/util/sets"
8 8
 
9 9
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
... ...
@@ -223,12 +223,12 @@ func TestDeploymentConfig(config *deployapi.DeploymentConfig) *deployapi.Deploym
223 223
 	return config
224 224
 }
225 225
 
226
-func OkHPAForDeploymentConfig(config *deployapi.DeploymentConfig, min, max int) *extensions.HorizontalPodAutoscaler {
226
+func OkHPAForDeploymentConfig(config *deployapi.DeploymentConfig, min, max int) *autoscaling.HorizontalPodAutoscaler {
227 227
 	newMin := int32(min)
228
-	return &extensions.HorizontalPodAutoscaler{
228
+	return &autoscaling.HorizontalPodAutoscaler{
229 229
 		ObjectMeta: kapi.ObjectMeta{Name: config.Name, Namespace: config.Namespace},
230
-		Spec: extensions.HorizontalPodAutoscalerSpec{
231
-			ScaleRef: extensions.SubresourceReference{
230
+		Spec: autoscaling.HorizontalPodAutoscalerSpec{
231
+			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
232 232
 				Name: config.Name,
233 233
 				Kind: "DeploymentConfig",
234 234
 			},
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"fmt"
6 6
 	"regexp"
7 7
 	"strconv"
8
+	"strings"
8 9
 
9 10
 	kapi "k8s.io/kubernetes/pkg/api"
10 11
 	unversionedvalidation "k8s.io/kubernetes/pkg/api/unversioned/validation"
... ...
@@ -150,7 +151,7 @@ func ValidateDeploymentConfigRollback(rollback *deployapi.DeploymentConfigRollba
150 150
 
151 151
 	if len(rollback.Name) == 0 {
152 152
 		result = append(result, field.Required(field.NewPath("name"), "name of the deployment config is missing"))
153
-	} else if !kvalidation.IsDNS1123Subdomain(rollback.Name) {
153
+	} else if len(kvalidation.IsDNS1123Subdomain(rollback.Name)) != 0 {
154 154
 		result = append(result, field.Invalid(field.NewPath("name"), rollback.Name, "name of the deployment config is invalid"))
155 155
 	}
156 156
 
... ...
@@ -417,7 +418,7 @@ func validateImageChangeParams(params *deployapi.DeploymentTriggerImageChangePar
417 417
 		if err := validateImageStreamTagName(params.From.Name); err != nil {
418 418
 			errs = append(errs, field.Invalid(fromPath.Child("name"), params.From.Name, err.Error()))
419 419
 		}
420
-		if len(params.From.Namespace) != 0 && !kvalidation.IsDNS1123Subdomain(params.From.Namespace) {
420
+		if len(params.From.Namespace) != 0 && len(kvalidation.IsDNS1123Subdomain(params.From.Namespace)) != 0 {
421 421
 			errs = append(errs, field.Invalid(fromPath.Child("namespace"), params.From.Namespace, "namespace must be a valid subdomain"))
422 422
 		}
423 423
 	}
... ...
@@ -434,9 +435,8 @@ func validateImageStreamTagName(istag string) error {
434 434
 	if !ok {
435 435
 		return fmt.Errorf("invalid ImageStreamTag: %s", istag)
436 436
 	}
437
-	ok, reason := imageval.ValidateImageStreamName(name, false)
438
-	if !ok {
439
-		return errors.New(reason)
437
+	if reasons := imageval.ValidateImageStreamName(name, false); len(reasons) != 0 {
438
+		return errors.New(strings.Join(reasons, ", "))
440 439
 	}
441 440
 	return nil
442 441
 }
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
14 14
 	_ "github.com/openshift/origin/pkg/deploy/api/install"
15 15
 	deploytest "github.com/openshift/origin/pkg/deploy/api/test"
16
+	deployv1 "github.com/openshift/origin/pkg/deploy/api/v1"
16 17
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
17 18
 )
18 19
 
... ...
@@ -75,12 +76,12 @@ func TestHandle_uncorrelatedPod(t *testing.T) {
75 75
 	controller := &DeployerPodController{
76 76
 		kClient: kFake,
77 77
 		decodeConfig: func(deployment *kapi.ReplicationController) (*deployapi.DeploymentConfig, error) {
78
-			return deployutil.DecodeDeploymentConfig(deployment, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
78
+			return deployutil.DecodeDeploymentConfig(deployment, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
79 79
 		},
80 80
 	}
81 81
 
82 82
 	// Verify no-op
83
-	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
83
+	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
84 84
 	pod := runningPod(deployment)
85 85
 	pod.Annotations = make(map[string]string)
86 86
 
... ...
@@ -109,7 +110,7 @@ func TestHandle_orphanedPod(t *testing.T) {
109 109
 	})
110 110
 	kFake.PrependReactor("list", "pods", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
111 111
 		mkpod := func(suffix string) kapi.Pod {
112
-			deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
112
+			deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
113 113
 			p := okPod(deployment)
114 114
 			p.Name = p.Name + suffix
115 115
 			return *p
... ...
@@ -127,7 +128,7 @@ func TestHandle_orphanedPod(t *testing.T) {
127 127
 		kClient: kFake,
128 128
 	}
129 129
 
130
-	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
130
+	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
131 131
 	err := controller.Handle(runningPod(deployment))
132 132
 	if err != nil {
133 133
 		t.Fatalf("unexpected error: %v", err)
... ...
@@ -142,7 +143,7 @@ func TestHandle_orphanedPod(t *testing.T) {
142 142
 // TestHandle_runningPod ensures that a running deployer pod results in a
143 143
 // transition of the deployment's status to running.
144 144
 func TestHandle_runningPod(t *testing.T) {
145
-	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
145
+	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
146 146
 	deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusPending)
147 147
 	var updatedDeployment *kapi.ReplicationController
148 148
 
... ...
@@ -177,7 +178,7 @@ func TestHandle_runningPod(t *testing.T) {
177 177
 // TestHandle_podTerminatedOk ensures that a successfully completed deployer
178 178
 // pod results in a transition of the deployment's status to complete.
179 179
 func TestHandle_podTerminatedOk(t *testing.T) {
180
-	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
180
+	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
181 181
 	deployment.Spec.Replicas = 1
182 182
 	deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusRunning)
183 183
 	var updatedDeployment *kapi.ReplicationController
... ...
@@ -219,7 +220,7 @@ func TestHandle_podTerminatedOk(t *testing.T) {
219 219
 // TestHandle_podTerminatedOk ensures that a successfully completed deployer
220 220
 // pod results in a transition of the deployment's status to complete.
221 221
 func TestHandle_podTerminatedOkTest(t *testing.T) {
222
-	deployment, _ := deployutil.MakeDeployment(deploytest.TestDeploymentConfig(deploytest.OkDeploymentConfig(1)), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
222
+	deployment, _ := deployutil.MakeDeployment(deploytest.TestDeploymentConfig(deploytest.OkDeploymentConfig(1)), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
223 223
 	deployment.Spec.Replicas = 1
224 224
 	deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusRunning)
225 225
 	var updatedDeployment *kapi.ReplicationController
... ...
@@ -263,7 +264,7 @@ func TestHandle_podTerminatedOkTest(t *testing.T) {
263 263
 // deployment's status to failed.
264 264
 func TestHandle_podTerminatedFailNoContainerStatus(t *testing.T) {
265 265
 	var updatedDeployment *kapi.ReplicationController
266
-	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
266
+	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
267 267
 	deployment.Spec.Replicas = 1
268 268
 	// since we do not set the desired replicas annotation,
269 269
 	// this also tests that the error is just logged and not result in a failure
... ...
@@ -308,7 +309,7 @@ func TestHandle_podTerminatedFailNoContainerStatus(t *testing.T) {
308 308
 // deployment's status to failed.
309 309
 func TestHandle_podTerminatedFailNoContainerStatusTest(t *testing.T) {
310 310
 	var updatedDeployment *kapi.ReplicationController
311
-	deployment, _ := deployutil.MakeDeployment(deploytest.TestDeploymentConfig(deploytest.OkDeploymentConfig(1)), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
311
+	deployment, _ := deployutil.MakeDeployment(deploytest.TestDeploymentConfig(deploytest.OkDeploymentConfig(1)), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
312 312
 	deployment.Spec.Replicas = 1
313 313
 	// since we do not set the desired replicas annotation,
314 314
 	// this also tests that the error is just logged and not result in a failure
... ...
@@ -352,7 +353,7 @@ func TestHandle_podTerminatedFailNoContainerStatusTest(t *testing.T) {
352 352
 // will be cleaned up in a complete deployment and stay around in a failed deployment
353 353
 func TestHandle_cleanupDesiredReplicasAnnotation(t *testing.T) {
354 354
 	// shared fixtures shouldn't be used in unit tests
355
-	shared, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
355
+	shared, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
356 356
 
357 357
 	tests := []struct {
358 358
 		name     string
... ...
@@ -372,7 +373,7 @@ func TestHandle_cleanupDesiredReplicasAnnotation(t *testing.T) {
372 372
 	}
373 373
 
374 374
 	for _, test := range tests {
375
-		deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
375
+		deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
376 376
 		var updatedDeployment *kapi.ReplicationController
377 377
 		deployment.Annotations[deployapi.DesiredReplicasAnnotation] = "1"
378 378
 
... ...
@@ -19,12 +19,13 @@ import (
19 19
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
20 20
 	_ "github.com/openshift/origin/pkg/deploy/api/install"
21 21
 	deploytest "github.com/openshift/origin/pkg/deploy/api/test"
22
+	deployapiv1 "github.com/openshift/origin/pkg/deploy/api/v1"
22 23
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
23 24
 )
24 25
 
25 26
 var (
26 27
 	env   = []kapi.EnvVar{{Name: "ENV1", Value: "VAL1"}}
27
-	codec = kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)
28
+	codec = kapi.Codecs.LegacyCodec(deployapiv1.SchemeGroupVersion)
28 29
 )
29 30
 
30 31
 func okDeploymentController(fake kclient.Interface, deployment *kapi.ReplicationController, hookPodNames []string, related bool) *DeploymentController {
... ...
@@ -18,6 +18,7 @@ import (
18 18
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
19 19
 	_ "github.com/openshift/origin/pkg/deploy/api/install"
20 20
 	deploytest "github.com/openshift/origin/pkg/deploy/api/test"
21
+	deployv1 "github.com/openshift/origin/pkg/deploy/api/v1"
21 22
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
22 23
 )
23 24
 
... ...
@@ -41,7 +42,7 @@ func TestHandleScenarios(t *testing.T) {
41 41
 		if d.test {
42 42
 			config = deploytest.TestDeploymentConfig(config)
43 43
 		}
44
-		deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
44
+		deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
45 45
 		deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(d.status)
46 46
 		if d.cancelled {
47 47
 			deployment.Annotations[deployapi.DeploymentCancelledAnnotation] = deployapi.DeploymentCancelledAnnotationValue
... ...
@@ -642,7 +643,7 @@ func TestHandleScenarios(t *testing.T) {
642 642
 			deployments[rc.Name] = *rc
643 643
 			return true, rc, nil
644 644
 		})
645
-		codec := kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)
645
+		codec := kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion)
646 646
 
647 647
 		dcInformer := framework.NewSharedIndexInformer(
648 648
 			&cache.ListWatch{
... ...
@@ -9,18 +9,20 @@ import (
9 9
 	ktestclient "k8s.io/kubernetes/pkg/client/unversioned/testclient"
10 10
 	"k8s.io/kubernetes/pkg/controller/framework"
11 11
 	"k8s.io/kubernetes/pkg/runtime"
12
+	"k8s.io/kubernetes/pkg/util/diff"
12 13
 	"k8s.io/kubernetes/pkg/watch"
13 14
 
14 15
 	"github.com/openshift/origin/pkg/client/testclient"
15 16
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
16 17
 	_ "github.com/openshift/origin/pkg/deploy/api/install"
17 18
 	testapi "github.com/openshift/origin/pkg/deploy/api/test"
19
+	deployv1 "github.com/openshift/origin/pkg/deploy/api/v1"
18 20
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
19 21
 	imageapi "github.com/openshift/origin/pkg/image/api"
20 22
 )
21 23
 
22 24
 var (
23
-	codec      = kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)
25
+	codec      = kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion)
24 26
 	mock       = &testclient.Fake{}
25 27
 	dcInformer = framework.NewSharedIndexInformer(
26 28
 		&cache.ListWatch{
... ...
@@ -147,7 +149,7 @@ func TestHandle_changeWithTemplateDiff(t *testing.T) {
147 147
 		config := testapi.OkDeploymentConfig(1)
148 148
 		config.Namespace = kapi.NamespaceDefault
149 149
 		config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger()}
150
-		deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
150
+		deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
151 151
 		var updated *deployapi.DeploymentConfig
152 152
 
153 153
 		fake.PrependReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
... ...
@@ -168,7 +170,7 @@ func TestHandle_changeWithTemplateDiff(t *testing.T) {
168 168
 
169 169
 		if !s.changeExpected {
170 170
 			if updated != nil {
171
-				t.Errorf("unexpected update to version %d", updated.Status.LatestVersion)
171
+				t.Errorf("unexpected update to version %d: %s", updated.Status.LatestVersion, diff.ObjectReflectDiff(config, updated))
172 172
 			}
173 173
 			continue
174 174
 		}
... ...
@@ -267,7 +269,7 @@ func TestHandle_automaticImageUpdates(t *testing.T) {
267 267
 		kFake.PrependReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
268 268
 			// This will always return no template difference. We test template differences in TestHandle_changeWithTemplateDiff
269 269
 			config := testapi.OkDeploymentConfig(0)
270
-			deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
270
+			deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
271 271
 			return true, deployment, nil
272 272
 		})
273 273
 
... ...
@@ -32,7 +32,7 @@ func mkdeploymentlist(versions ...int64) *kapi.ReplicationControllerList {
32 32
 
33 33
 func TestStop(t *testing.T) {
34 34
 	notfound := func() runtime.Object {
35
-		return &(kerrors.NewNotFound(kapi.Resource("DeploymentConfig"), "config").(*kerrors.StatusError).ErrStatus)
35
+		return &(kerrors.NewNotFound(kapi.Resource("DeploymentConfig"), "config").ErrStatus)
36 36
 	}
37 37
 
38 38
 	tests := []struct {
... ...
@@ -93,7 +93,18 @@ func (r *ScaleREST) Get(ctx kapi.Context, name string) (runtime.Object, error) {
93 93
 }
94 94
 
95 95
 // Update scales the DeploymentConfig for the given Scale subresource, returning the updated Scale.
96
-func (r *ScaleREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
96
+func (r *ScaleREST) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
97
+	deploymentConfig, err := r.registry.GetDeploymentConfig(ctx, name)
98
+	if err != nil {
99
+		return nil, false, errors.NewNotFound(extensions.Resource("scale"), name)
100
+	}
101
+
102
+	old := api.ScaleFromConfig(deploymentConfig)
103
+	obj, err := objInfo.UpdatedObject(ctx, old)
104
+	if err != nil {
105
+		return nil, false, err
106
+	}
107
+
97 108
 	scale, ok := obj.(*extensions.Scale)
98 109
 	if !ok {
99 110
 		return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj))
... ...
@@ -103,17 +114,12 @@ func (r *ScaleREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object
103 103
 		return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs)
104 104
 	}
105 105
 
106
-	deploymentConfig, err := r.registry.GetDeploymentConfig(ctx, scale.Name)
107
-	if err != nil {
108
-		return nil, false, errors.NewNotFound(extensions.Resource("scale"), scale.Name)
109
-	}
110
-
111 106
 	deploymentConfig.Spec.Replicas = scale.Spec.Replicas
112 107
 	if err := r.registry.UpdateDeploymentConfig(ctx, deploymentConfig); err != nil {
113 108
 		return nil, false, err
114 109
 	}
115 110
 
116
-	return api.ScaleFromConfig(deploymentConfig), false, nil
111
+	return scale, false, nil
117 112
 }
118 113
 
119 114
 // StatusREST implements the REST endpoint for changing the status of a DeploymentConfig.
... ...
@@ -129,6 +135,6 @@ func (r *StatusREST) New() runtime.Object {
129 129
 }
130 130
 
131 131
 // Update alters the status subset of an deploymentConfig.
132
-func (r *StatusREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
133
-	return r.store.Update(ctx, obj)
132
+func (r *StatusREST) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
133
+	return r.store.Update(ctx, name, objInfo)
134 134
 }
... ...
@@ -55,7 +55,7 @@ func (s *storage) CreateDeploymentConfig(ctx kapi.Context, deploymentConfig *dep
55 55
 }
56 56
 
57 57
 func (s *storage) UpdateDeploymentConfig(ctx kapi.Context, deploymentConfig *deployapi.DeploymentConfig) error {
58
-	_, _, err := s.Update(ctx, deploymentConfig)
58
+	_, _, err := s.Update(ctx, deploymentConfig.Name, rest.DefaultUpdatedObjectInfo(deploymentConfig, kapi.Scheme))
59 59
 	return err
60 60
 }
61 61
 
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
13 13
 	_ "github.com/openshift/origin/pkg/deploy/api/install"
14 14
 	deploytest "github.com/openshift/origin/pkg/deploy/api/test"
15
+	deployv1 "github.com/openshift/origin/pkg/deploy/api/v1"
15 16
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
16 17
 )
17 18
 
... ...
@@ -48,14 +49,14 @@ func TestCreateOkDepr(t *testing.T) {
48 48
 				return &deployapi.DeploymentConfig{}, nil
49 49
 			},
50 50
 			RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) {
51
-				deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
51
+				deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
52 52
 				return deployment, nil
53 53
 			},
54 54
 			DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) {
55 55
 				return deploytest.OkDeploymentConfig(1), nil
56 56
 			},
57 57
 		},
58
-		codec: kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion),
58
+		codec: kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion),
59 59
 	}
60 60
 
61 61
 	obj, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{
... ...
@@ -87,14 +88,14 @@ func TestCreateGeneratorErrorDepr(t *testing.T) {
87 87
 				return nil, kerrors.NewInternalError(fmt.Errorf("something terrible happened"))
88 88
 			},
89 89
 			RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) {
90
-				deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
90
+				deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
91 91
 				return deployment, nil
92 92
 			},
93 93
 			DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) {
94 94
 				return deploytest.OkDeploymentConfig(1), nil
95 95
 			},
96 96
 		},
97
-		codec: kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion),
97
+		codec: kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion),
98 98
 	}
99 99
 
100 100
 	_, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{
... ...
@@ -127,7 +128,7 @@ func TestCreateMissingDeploymentDepr(t *testing.T) {
127 127
 				return nil, kerrors.NewNotFound(deployapi.Resource("deploymentConfig"), name)
128 128
 			},
129 129
 		},
130
-		codec: kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion),
130
+		codec: kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion),
131 131
 	}
132 132
 
133 133
 	obj, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{
... ...
@@ -157,7 +158,7 @@ func TestCreateInvalidDeploymentDepr(t *testing.T) {
157 157
 			},
158 158
 			RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) {
159 159
 				// invalidate the encoded config
160
-				deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
160
+				deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
161 161
 				deployment.Annotations[deployapi.DeploymentEncodedConfigAnnotation] = ""
162 162
 				return deployment, nil
163 163
 			},
... ...
@@ -167,7 +168,7 @@ func TestCreateInvalidDeploymentDepr(t *testing.T) {
167 167
 				return nil, kerrors.NewNotFound(deployapi.Resource("deploymentConfig"), name)
168 168
 			},
169 169
 		},
170
-		codec: kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion),
170
+		codec: kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion),
171 171
 	}
172 172
 
173 173
 	obj, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{
... ...
@@ -196,14 +197,14 @@ func TestCreateMissingDeploymentConfigDepr(t *testing.T) {
196 196
 				return nil, errors.New("something terrible happened")
197 197
 			},
198 198
 			RCFn: func(ctx kapi.Context, name string) (*kapi.ReplicationController, error) {
199
-				deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
199
+				deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
200 200
 				return deployment, nil
201 201
 			},
202 202
 			DCFn: func(ctx kapi.Context, name string) (*deployapi.DeploymentConfig, error) {
203 203
 				return nil, kerrors.NewNotFound(deployapi.Resource("deploymentConfig"), name)
204 204
 			},
205 205
 		},
206
-		codec: kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion),
206
+		codec: kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion),
207 207
 	}
208 208
 
209 209
 	obj, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{
... ...
@@ -226,6 +227,6 @@ func TestCreateMissingDeploymentConfigDepr(t *testing.T) {
226 226
 
227 227
 func TestNewDepr(t *testing.T) {
228 228
 	// :)
229
-	rest := NewDeprecatedREST(Client{}, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
229
+	rest := NewDeprecatedREST(Client{}, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
230 230
 	rest.New()
231 231
 }
... ...
@@ -14,10 +14,11 @@ import (
14 14
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
15 15
 	_ "github.com/openshift/origin/pkg/deploy/api/install"
16 16
 	deploytest "github.com/openshift/origin/pkg/deploy/api/test"
17
+	deployv1 "github.com/openshift/origin/pkg/deploy/api/v1"
17 18
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
18 19
 )
19 20
 
20
-var codec = kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)
21
+var codec = kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion)
21 22
 
22 23
 type terribleGenerator struct{}
23 24
 
... ...
@@ -99,7 +100,7 @@ func TestCreateGeneratorError(t *testing.T) {
99 99
 		generator: &terribleGenerator{},
100 100
 		dn:        oc,
101 101
 		rn:        kc,
102
-		codec:     kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion),
102
+		codec:     kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion),
103 103
 	}
104 104
 
105 105
 	_, err := rest.Create(kapi.NewDefaultContext(), &deployapi.DeploymentConfigRollback{
... ...
@@ -11,6 +11,7 @@ import (
11 11
 
12 12
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
13 13
 	deploytest "github.com/openshift/origin/pkg/deploy/api/test"
14
+	deployv1 "github.com/openshift/origin/pkg/deploy/api/v1"
14 15
 	scalertest "github.com/openshift/origin/pkg/deploy/scaler/test"
15 16
 	"github.com/openshift/origin/pkg/deploy/strategy"
16 17
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
... ...
@@ -121,7 +122,7 @@ func TestRecreate_deploymentPreHookFail(t *testing.T) {
121 121
 func TestRecreate_deploymentMidHookSuccess(t *testing.T) {
122 122
 	config := deploytest.OkDeploymentConfig(1)
123 123
 	config.Spec.Strategy = recreateParams(30, "", deployapi.LifecycleHookFailurePolicyAbort, "")
124
-	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
124
+	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
125 125
 	scaler := &scalertest.FakeScaler{}
126 126
 
127 127
 	hookExecuted := false
... ...
@@ -156,7 +157,7 @@ func TestRecreate_deploymentMidHookSuccess(t *testing.T) {
156 156
 func TestRecreate_deploymentMidHookFail(t *testing.T) {
157 157
 	config := deploytest.OkDeploymentConfig(1)
158 158
 	config.Spec.Strategy = recreateParams(30, "", deployapi.LifecycleHookFailurePolicyAbort, "")
159
-	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
159
+	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
160 160
 	scaler := &scalertest.FakeScaler{}
161 161
 
162 162
 	strategy := &RecreateDeploymentStrategy{
... ...
@@ -476,7 +476,7 @@ func NewPodWatch(client kclient.PodsNamespacer, namespace, name, resourceVersion
476 476
 	cache.NewReflector(podLW, &kapi.Pod{}, queue, 1*time.Minute).RunUntil(stopChannel)
477 477
 
478 478
 	return func() *kapi.Pod {
479
-		obj := queue.Pop()
479
+		obj := cache.Pop(queue)
480 480
 		return obj.(*kapi.Pod)
481 481
 	}
482 482
 }
... ...
@@ -19,6 +19,7 @@ import (
19 19
 
20 20
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
21 21
 	deploytest "github.com/openshift/origin/pkg/deploy/api/test"
22
+	deployv1 "github.com/openshift/origin/pkg/deploy/api/v1"
22 23
 	deployutil "github.com/openshift/origin/pkg/deploy/util"
23 24
 	namer "github.com/openshift/origin/pkg/util/namer"
24 25
 
... ...
@@ -33,7 +34,7 @@ func TestHookExecutor_executeExecNewCreatePodFailure(t *testing.T) {
33 33
 		},
34 34
 	}
35 35
 
36
-	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
36
+	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
37 37
 
38 38
 	executor := &HookExecutor{
39 39
 		podClient: &HookExecutorPodClientImpl{
... ...
@@ -64,7 +65,7 @@ func TestHookExecutor_executeExecNewPodSucceeded(t *testing.T) {
64 64
 	}
65 65
 
66 66
 	config := deploytest.OkDeploymentConfig(1)
67
-	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
67
+	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
68 68
 	deployment.Spec.Template.Spec.NodeSelector = map[string]string{"labelKey1": "labelValue1", "labelKey2": "labelValue2"}
69 69
 
70 70
 	podLogs := &bytes.Buffer{}
... ...
@@ -118,7 +119,7 @@ func TestHookExecutor_executeExecNewPodFailed(t *testing.T) {
118 118
 		},
119 119
 	}
120 120
 
121
-	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
121
+	deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
122 122
 
123 123
 	var createdPod *kapi.Pod
124 124
 	executor := &HookExecutor{
... ...
@@ -156,7 +157,7 @@ func TestHookExecutor_makeHookPodInvalidContainerRef(t *testing.T) {
156 156
 	}
157 157
 
158 158
 	config := deploytest.OkDeploymentConfig(1)
159
-	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
159
+	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
160 160
 
161 161
 	_, err := makeHookPod(hook, deployment, &config.Spec.Strategy, "hook")
162 162
 
... ...
@@ -412,7 +413,7 @@ func TestHookExecutor_makeHookPodRestart(t *testing.T) {
412 412
 	}
413 413
 
414 414
 	config := deploytest.OkDeploymentConfig(1)
415
-	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
415
+	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
416 416
 
417 417
 	pod, err := makeHookPod(hook, deployment, &config.Spec.Strategy, "hook")
418 418
 	if err != nil {
... ...
@@ -513,7 +514,7 @@ func TestAcceptNewlyObservedReadyPods_scenarios(t *testing.T) {
513 513
 			acceptedPods: acceptedPods,
514 514
 		}
515 515
 
516
-		deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
516
+		deployment, _ := deployutil.MakeDeployment(deploytest.OkDeploymentConfig(1), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
517 517
 		deployment.Spec.Replicas = 1
518 518
 
519 519
 		acceptor.out = &bytes.Buffer{}
... ...
@@ -610,7 +611,7 @@ func deployment(name, namespace string, strategyLabels, strategyAnnotations map[
610 610
 			},
611 611
 		},
612 612
 	}
613
-	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
613
+	deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
614 614
 	deployment.Namespace = namespace
615 615
 	return config, deployment
616 616
 }
... ...
@@ -11,6 +11,7 @@ import (
11 11
 
12 12
 	deployapi "github.com/openshift/origin/pkg/deploy/api"
13 13
 	deploytest "github.com/openshift/origin/pkg/deploy/api/test"
14
+	deployv1 "github.com/openshift/origin/pkg/deploy/api/v1"
14 15
 
15 16
 	_ "github.com/openshift/origin/pkg/api/install"
16 17
 )
... ...
@@ -65,7 +66,7 @@ func TestPodName(t *testing.T) {
65 65
 
66 66
 func TestMakeDeploymentOk(t *testing.T) {
67 67
 	config := deploytest.OkDeploymentConfig(1)
68
-	deployment, err := MakeDeployment(config, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
68
+	deployment, err := MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
69 69
 
70 70
 	if err != nil {
71 71
 		t.Fatalf("unexpected error: %#v", err)
... ...
@@ -99,7 +100,7 @@ func TestMakeDeploymentOk(t *testing.T) {
99 99
 		t.Fatalf("expected deployment with DeploymentEncodedConfigAnnotation annotation")
100 100
 	}
101 101
 
102
-	if decodedConfig, err := DecodeDeploymentConfig(deployment, kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion)); err != nil {
102
+	if decodedConfig, err := DecodeDeploymentConfig(deployment, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion)); err != nil {
103 103
 		t.Fatalf("invalid encoded config on deployment: %v", err)
104 104
 	} else {
105 105
 		if e, a := config.Name, decodedConfig.Name; e != a {
... ...
@@ -135,7 +136,7 @@ func TestMakeDeploymentOk(t *testing.T) {
135 135
 
136 136
 func TestDeploymentsByLatestVersion_sorting(t *testing.T) {
137 137
 	mkdeployment := func(version int64) kapi.ReplicationController {
138
-		deployment, _ := MakeDeployment(deploytest.OkDeploymentConfig(version), kapi.Codecs.LegacyCodec(deployapi.SchemeGroupVersion))
138
+		deployment, _ := MakeDeployment(deploytest.OkDeploymentConfig(version), kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion))
139 139
 		return *deployment
140 140
 	}
141 141
 	deployments := []kapi.ReplicationController{
... ...
@@ -3,6 +3,7 @@ package dns
3 3
 import (
4 4
 	"github.com/golang/glog"
5 5
 
6
+	"github.com/skynetservices/skydns/metrics"
6 7
 	"github.com/skynetservices/skydns/server"
7 8
 
8 9
 	client "k8s.io/kubernetes/pkg/client/unversioned"
... ...
@@ -44,7 +45,7 @@ func (s *Server) ListenAndServe() error {
44 44
 	resolver := NewServiceResolver(s.Config, s.Services, s.Endpoints, openshiftFallback)
45 45
 	resolvers := server.FirstBackend{resolver}
46 46
 	if len(s.MetricsName) > 0 {
47
-		server.RegisterMetrics(s.MetricsName, "")
47
+		metrics.RegisterPrometheusMetrics(s.MetricsName, "")
48 48
 	}
49 49
 	dns := server.New(resolvers, s.Config)
50 50
 	if s.Stop != nil {
... ...
@@ -6,7 +6,7 @@ import (
6 6
 	"net"
7 7
 	"strings"
8 8
 
9
-	"github.com/coreos/go-etcd/etcd"
9
+	etcd "github.com/coreos/etcd/client"
10 10
 	"github.com/golang/glog"
11 11
 
12 12
 	kapi "k8s.io/kubernetes/pkg/api"
... ...
@@ -33,7 +33,7 @@ type ServiceResolver struct {
33 33
 var _ server.Backend = &ServiceResolver{}
34 34
 
35 35
 // TODO: abstract in upstream SkyDNS
36
-var errNoSuchName = &etcd.EtcdError{ErrorCode: 100}
36
+var errNoSuchName = etcd.Error{Code: etcd.ErrorCodeKeyNotFound}
37 37
 
38 38
 type FallbackFunc func(name string, exact bool) (string, bool)
39 39
 
... ...
@@ -383,8 +383,8 @@ func simulateOpenShiftMaster(responses []response) (*httptest.Server, *[]string)
383 383
 			response = responses[i]
384 384
 		}
385 385
 		i++
386
-		w.WriteHeader(response.code)
387 386
 		w.Header().Set("Content-Type", "application/json")
387
+		w.WriteHeader(response.code)
388 388
 		fmt.Fprintln(w, response.body)
389 389
 		actions = append(actions, r.Method+" "+r.URL.Path)
390 390
 	}))
... ...
@@ -466,7 +466,7 @@ func LabelsFromSpec(spec []string) (map[string]string, []string, error) {
466 466
 func AsVersionedObjects(objects []runtime.Object, typer runtime.ObjectTyper, convertor runtime.ObjectConvertor, versions ...unversioned.GroupVersion) []error {
467 467
 	var errs []error
468 468
 	for i, object := range objects {
469
-		kinds, err := typer.ObjectKinds(object)
469
+		kinds, _, err := typer.ObjectKinds(object)
470 470
 		if err != nil {
471 471
 			errs = append(errs, err)
472 472
 			continue
... ...
@@ -511,7 +511,7 @@ func kindsInVersions(kinds []unversioned.GroupVersionKind, versions []unversione
511 511
 func tryConvert(convertor runtime.ObjectConvertor, object runtime.Object, versions []unversioned.GroupVersion) (runtime.Object, error) {
512 512
 	var last error
513 513
 	for _, version := range versions {
514
-		obj, err := convertor.ConvertToVersion(object, version.String())
514
+		obj, err := convertor.ConvertToVersion(object, version)
515 515
 		if err != nil {
516 516
 			last = err
517 517
 			continue
... ...
@@ -263,7 +263,7 @@ func (c *AppConfig) validateBuilders(components app.ComponentReferences) error {
263 263
 }
264 264
 
265 265
 func validateEnforcedName(name string) error {
266
-	if ok, _ := validation.ValidateServiceName(name, false); !ok && !app.IsParameterizableValue(name) {
266
+	if reasons := validation.ValidateServiceName(name, false); len(reasons) != 0 && !app.IsParameterizableValue(name) {
267 267
 		return fmt.Errorf("invalid name: %s. Must be an a lower case alphanumeric (a-z, and 0-9) string with a maximum length of 24 characters, where the first character is a letter (a-z), and the '-' character is allowed anywhere except the first or last character.", name)
268 268
 	}
269 269
 	return nil
... ...
@@ -257,7 +257,7 @@ func (g PipelineGroup) String() string {
257 257
 var invalidServiceChars = regexp.MustCompile("[^-a-z0-9]")
258 258
 
259 259
 func makeValidServiceName(name string) (string, string) {
260
-	if ok, _ := validation.ValidateServiceName(name, false); ok {
260
+	if len(validation.ValidateServiceName(name, false)) == 0 {
261 261
 		return name, ""
262 262
 	}
263 263
 	name = strings.ToLower(name)
... ...
@@ -420,11 +420,11 @@ func (a *acceptUnique) Accept(from interface{}) bool {
420 420
 	if err != nil {
421 421
 		return false
422 422
 	}
423
-	gvk, err := a.typer.ObjectKind(obj)
423
+	gvk, _, err := a.typer.ObjectKinds(obj)
424 424
 	if err != nil {
425 425
 		return false
426 426
 	}
427
-	key := fmt.Sprintf("%s/%s/%s", gvk.Kind, meta.Namespace, meta.Name)
427
+	key := fmt.Sprintf("%s/%s/%s", gvk[0].Kind, meta.Namespace, meta.Name)
428 428
 	_, exists := a.objects[key]
429 429
 	if exists {
430 430
 		return false
... ...
@@ -464,11 +464,11 @@ func (a *acceptBuildConfigs) Accept(from interface{}) bool {
464 464
 	if err != nil {
465 465
 		return false
466 466
 	}
467
-	gvk, err := a.typer.ObjectKind(obj)
467
+	gvk, _, err := a.typer.ObjectKinds(obj)
468 468
 	if err != nil {
469 469
 		return false
470 470
 	}
471
-	return gvk.GroupKind() == build.Kind("BuildConfig") || gvk.GroupKind() == image.Kind("ImageStream")
471
+	return gvk[0].GroupKind() == build.Kind("BuildConfig") || gvk[0].GroupKind() == image.Kind("ImageStream")
472 472
 }
473 473
 
474 474
 // NewAcceptBuildConfigs creates an acceptor accepting BuildConfig objects
... ...
@@ -345,7 +345,7 @@ func (r *SourceRepository) AddBuildSecrets(secrets []string, isDockerBuild bool)
345 345
 		if isDockerBuild && filepath.IsAbs(in.Destination) {
346 346
 			return fmt.Errorf("for the docker strategy, the secret destination directory %q must be a relative path", in.Destination)
347 347
 		}
348
-		if ok, _ := validation.ValidateSecretName(in.Source, false); !ok {
348
+		if len(validation.ValidateSecretName(in.Source, false)) != 0 {
349 349
 			return fmt.Errorf("the %q must be valid secret name", in.Source)
350 350
 		}
351 351
 		if secretExists(in.Source) {
... ...
@@ -55,7 +55,7 @@ func TestAdmitImageStreamMapping(t *testing.T) {
55 55
 			continue
56 56
 		}
57 57
 
58
-		attrs := kadmission.NewAttributesRecord(v.imageStreamMapping,
58
+		attrs := kadmission.NewAttributesRecord(v.imageStreamMapping, nil,
59 59
 			imageapi.Kind("ImageStreamMapping").WithVersion("version"),
60 60
 			v.imageStreamMapping.Namespace,
61 61
 			v.imageStreamMapping.Name,
... ...
@@ -214,7 +214,7 @@ func TestSupports(t *testing.T) {
214 214
 	}
215 215
 	ilr := plugin.(*imageLimitRangerPlugin)
216 216
 	for _, r := range resources {
217
-		attr := kadmission.NewAttributesRecord(nil, unversioned.Kind("ImageStreamMapping").WithVersion("version"), "ns", "name", imageapi.Resource(r).WithVersion("version"), "", kadmission.Create, nil)
217
+		attr := kadmission.NewAttributesRecord(nil, nil, unversioned.Kind("ImageStreamMapping").WithVersion("version"), "ns", "name", imageapi.Resource(r).WithVersion("version"), "", kadmission.Create, nil)
218 218
 		if !ilr.SupportsAttributes(attr) {
219 219
 			t.Errorf("plugin is expected to support %s", r)
220 220
 		}
... ...
@@ -222,7 +222,7 @@ func TestSupports(t *testing.T) {
222 222
 
223 223
 	badKinds := []string{"ImageStream", "Image", "Pod", "foo"}
224 224
 	for _, k := range badKinds {
225
-		attr := kadmission.NewAttributesRecord(nil, unversioned.Kind(k).WithVersion("version"), "ns", "name", imageapi.Resource("bar").WithVersion("version"), "", kadmission.Create, nil)
225
+		attr := kadmission.NewAttributesRecord(nil, nil, unversioned.Kind(k).WithVersion("version"), "ns", "name", imageapi.Resource("bar").WithVersion("version"), "", kadmission.Create, nil)
226 226
 		if ilr.SupportsAttributes(attr) {
227 227
 			t.Errorf("plugin is not expected to support %s", k)
228 228
 		}
... ...
@@ -36,7 +36,7 @@ func Convert_api_Image_To_v1_Image(in *newer.Image, out *Image, s conversion.Sco
36 36
 	if err != nil {
37 37
 		return err
38 38
 	}
39
-	data, err := runtime.Encode(api.Codecs.LegacyCodec(version), &in.DockerImageMetadata, version)
39
+	data, err := runtime.Encode(api.Codecs.LegacyCodec(version), &in.DockerImageMetadata)
40 40
 	if err != nil {
41 41
 		return err
42 42
 	}
... ...
@@ -3,6 +3,7 @@ package validation
3 3
 import (
4 4
 	"fmt"
5 5
 	"regexp"
6
+	"strings"
6 7
 
7 8
 	"github.com/docker/distribution/reference"
8 9
 	"github.com/golang/glog"
... ...
@@ -32,15 +33,15 @@ var RepositoryNameComponentAnchoredRegexp = regexp.MustCompile(`^` + RepositoryN
32 32
 // Copied from github.com/docker/distribution/registry/api/v2/names.go v2.1.1
33 33
 var RepositoryNameRegexp = regexp.MustCompile(`(?:` + RepositoryNameComponentRegexp.String() + `/)*` + RepositoryNameComponentRegexp.String())
34 34
 
35
-func ValidateImageStreamName(name string, prefix bool) (bool, string) {
36
-	if ok, reason := oapi.MinimalNameRequirements(name, prefix); !ok {
37
-		return ok, reason
35
+func ValidateImageStreamName(name string, prefix bool) []string {
36
+	if reasons := oapi.MinimalNameRequirements(name, prefix); len(reasons) != 0 {
37
+		return reasons
38 38
 	}
39 39
 
40 40
 	if !RepositoryNameComponentAnchoredRegexp.MatchString(name) {
41
-		return false, fmt.Sprintf("must match %q", RepositoryNameComponentRegexp.String())
41
+		return []string{fmt.Sprintf("must match %q", RepositoryNameComponentRegexp.String())}
42 42
 	}
43
-	return true, ""
43
+	return nil
44 44
 }
45 45
 
46 46
 // ValidateImage tests required fields for an Image.
... ...
@@ -209,8 +210,8 @@ func ValidateImageStreamMapping(mapping *api.ImageStreamMapping) field.ErrorList
209 209
 		result = append(result, field.Required(field.NewPath("dockerImageRepository"), ""))
210 210
 	}
211 211
 
212
-	if ok, msg := validation.ValidateNamespaceName(mapping.Namespace, false); !ok {
213
-		result = append(result, field.Invalid(field.NewPath("metadata", "namespace"), mapping.Namespace, msg))
212
+	if reasons := validation.ValidateNamespaceName(mapping.Namespace, false); len(reasons) != 0 {
213
+		result = append(result, field.Invalid(field.NewPath("metadata", "namespace"), mapping.Namespace, strings.Join(reasons, ", ")))
214 214
 	}
215 215
 	if len(mapping.Tag) == 0 {
216 216
 		result = append(result, field.Required(field.NewPath("tag"), ""))
... ...
@@ -377,7 +377,7 @@ func TestValidateImageStream(t *testing.T) {
377 377
 			namespace: "!$",
378 378
 			name:      "foo",
379 379
 			expected: field.ErrorList{
380
-				field.Invalid(field.NewPath("metadata", "namespace"), "!$", `must be a DNS label (at most 63 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?): e.g. "my-name"`),
380
+				field.Invalid(field.NewPath("metadata", "namespace"), "!$", `must match the regex [a-z0-9]([-a-z0-9]*[a-z0-9])? (e.g. 'my-name' or '123-abc')`),
381 381
 			},
382 382
 		},
383 383
 		"invalid dockerImageRepository": {
... ...
@@ -682,7 +682,7 @@ func TestValidateImageStreamImport(t *testing.T) {
682 682
 		"invalid namespace": {
683 683
 			isi: &api.ImageStreamImport{ObjectMeta: kapi.ObjectMeta{Namespace: "!$", Name: "foo"}, Spec: validSpec},
684 684
 			expected: field.ErrorList{
685
-				field.Invalid(field.NewPath("metadata", "namespace"), "!$", `must be a DNS label (at most 63 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?): e.g. "my-name"`),
685
+				field.Invalid(field.NewPath("metadata", "namespace"), "!$", `must match the regex [a-z0-9]([-a-z0-9]*[a-z0-9])? (e.g. 'my-name' or '123-abc')`),
686 686
 			},
687 687
 		},
688 688
 		"invalid dockerImageRepository": {
... ...
@@ -396,7 +396,7 @@ func TestScheduledImport(t *testing.T) {
396 396
 	}
397 397
 
398 398
 	// encountering a not found error for image streams should drop the controller
399
-	status := apierrs.NewNotFound(api.Resource("imagestream"), "test").(*apierrs.StatusError).ErrStatus
399
+	status := apierrs.NewNotFound(api.Resource("imagestream"), "test").ErrStatus
400 400
 	fake = client.NewSimpleFake(&status)
401 401
 	b.controller.streams = fake
402 402
 	b.scheduler.RunOnce()
... ...
@@ -480,14 +480,14 @@ func importRepositoryFromDocker(ctx gocontext.Context, retriever RepositoryRetri
480 480
 func importRepositoryFromDockerV1(ctx gocontext.Context, repository *importRepository, limiter flowcontrol.RateLimiter) {
481 481
 	value := ctx.Value(ContextKeyV1RegistryClient)
482 482
 	if value == nil {
483
-		err := kapierrors.NewForbidden(api.Resource(""), "", fmt.Errorf("registry %q does not support the v2 Registry API", repository.Registry.Host)).(*kapierrors.StatusError)
483
+		err := kapierrors.NewForbidden(api.Resource(""), "", fmt.Errorf("registry %q does not support the v2 Registry API", repository.Registry.Host))
484 484
 		err.ErrStatus.Reason = "NotV2Registry"
485 485
 		applyErrorToRepository(repository, err)
486 486
 		return
487 487
 	}
488 488
 	client, ok := value.(dockerregistry.Client)
489 489
 	if !ok {
490
-		err := kapierrors.NewForbidden(api.Resource(""), "", fmt.Errorf("registry %q does not support the v2 Registry API", repository.Registry.Host)).(*kapierrors.StatusError)
490
+		err := kapierrors.NewForbidden(api.Resource(""), "", fmt.Errorf("registry %q does not support the v2 Registry API", repository.Registry.Host))
491 491
 		err.ErrStatus.Reason = "NotV2Registry"
492 492
 		return
493 493
 	}
... ...
@@ -616,9 +616,9 @@ func imageImportStatus(err error, kind, position string) unversioned.Status {
616 616
 	case kapierrors.APIStatus:
617 617
 		return t.Status()
618 618
 	case *field.Error:
619
-		return kapierrors.NewInvalid(api.Kind(kind), position, field.ErrorList{t}).(kapierrors.APIStatus).Status()
619
+		return kapierrors.NewInvalid(api.Kind(kind), position, field.ErrorList{t}).ErrStatus
620 620
 	default:
621
-		return kapierrors.NewInternalError(err).(kapierrors.APIStatus).Status()
621
+		return kapierrors.NewInternalError(err).ErrStatus
622 622
 	}
623 623
 }
624 624
 
... ...
@@ -628,5 +628,5 @@ func setImageImportStatus(images *api.ImageStreamImport, i int, tag string, err
628 628
 }
629 629
 
630 630
 func invalidStatus(position string, errs ...*field.Error) unversioned.Status {
631
-	return kapierrors.NewInvalid(api.Kind(""), position, errs).(kapierrors.APIStatus).Status()
631
+	return kapierrors.NewInvalid(api.Kind(""), position, errs).ErrStatus
632 632
 }
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"testing"
5 5
 
6 6
 	kapi "k8s.io/kubernetes/pkg/api"
7
+	"k8s.io/kubernetes/pkg/api/rest"
7 8
 	"k8s.io/kubernetes/pkg/fields"
8 9
 	"k8s.io/kubernetes/pkg/labels"
9 10
 	"k8s.io/kubernetes/pkg/registry/registrytest"
... ...
@@ -387,7 +388,7 @@ func TestUpdateResetsMetadata(t *testing.T) {
387 387
 
388 388
 		// Copy the resource version into our update object
389 389
 		test.image.ResourceVersion = created.(*api.Image).ResourceVersion
390
-		obj, _, err := storage.Update(kapi.NewDefaultContext(), test.image)
390
+		obj, _, err := storage.Update(kapi.NewDefaultContext(), test.image.Name, rest.DefaultUpdatedObjectInfo(test.image, kapi.Scheme))
391 391
 		if err != nil {
392 392
 			t.Errorf("%d: Unexpected non-nil error: %#v", i, err)
393 393
 			continue
... ...
@@ -2,6 +2,7 @@ package etcd
2 2
 
3 3
 import (
4 4
 	kapi "k8s.io/kubernetes/pkg/api"
5
+	"k8s.io/kubernetes/pkg/api/rest"
5 6
 	"k8s.io/kubernetes/pkg/fields"
6 7
 	"k8s.io/kubernetes/pkg/labels"
7 8
 	"k8s.io/kubernetes/pkg/registry/generic"
... ...
@@ -89,8 +90,8 @@ func (r *StatusREST) New() runtime.Object {
89 89
 }
90 90
 
91 91
 // Update alters the status subset of an object.
92
-func (r *StatusREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
93
-	return r.store.Update(ctx, obj)
92
+func (r *StatusREST) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
93
+	return r.store.Update(ctx, name, objInfo)
94 94
 }
95 95
 
96 96
 // InternalREST implements the REST endpoint for changing both the spec and status of an image stream.
... ...
@@ -108,6 +109,6 @@ func (r *InternalREST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Obj
108 108
 }
109 109
 
110 110
 // Update alters both the spec and status of the object.
111
-func (r *InternalREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
112
-	return r.store.Update(ctx, obj)
111
+func (r *InternalREST) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
112
+	return r.store.Update(ctx, name, objInfo)
113 113
 }
... ...
@@ -38,7 +38,7 @@ type Storage interface {
38 38
 	rest.Watcher
39 39
 
40 40
 	Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error)
41
-	Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error)
41
+	Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error)
42 42
 }
43 43
 
44 44
 // storage puts strong typing around storage calls
... ...
@@ -79,7 +79,7 @@ func (s *storage) CreateImageStream(ctx kapi.Context, imageStream *api.ImageStre
79 79
 }
80 80
 
81 81
 func (s *storage) UpdateImageStream(ctx kapi.Context, imageStream *api.ImageStream) (*api.ImageStream, error) {
82
-	obj, _, err := s.internal.Update(ctx, imageStream)
82
+	obj, _, err := s.internal.Update(ctx, imageStream.Name, rest.DefaultUpdatedObjectInfo(imageStream, kapi.Scheme))
83 83
 	if err != nil {
84 84
 		return nil, err
85 85
 	}
... ...
@@ -87,7 +87,7 @@ func (s *storage) UpdateImageStream(ctx kapi.Context, imageStream *api.ImageStre
87 87
 }
88 88
 
89 89
 func (s *storage) UpdateImageStreamSpec(ctx kapi.Context, imageStream *api.ImageStream) (*api.ImageStream, error) {
90
-	obj, _, err := s.Update(ctx, imageStream)
90
+	obj, _, err := s.Update(ctx, imageStream.Name, rest.DefaultUpdatedObjectInfo(imageStream, kapi.Scheme))
91 91
 	if err != nil {
92 92
 		return nil, err
93 93
 	}
... ...
@@ -95,7 +95,7 @@ func (s *storage) UpdateImageStreamSpec(ctx kapi.Context, imageStream *api.Image
95 95
 }
96 96
 
97 97
 func (s *storage) UpdateImageStreamStatus(ctx kapi.Context, imageStream *api.ImageStream) (*api.ImageStream, error) {
98
-	obj, _, err := s.status.Update(ctx, imageStream)
98
+	obj, _, err := s.status.Update(ctx, imageStream.Name, rest.DefaultUpdatedObjectInfo(imageStream, kapi.Scheme))
99 99
 	if err != nil {
100 100
 		return nil, err
101 101
 	}
... ...
@@ -250,7 +250,7 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err
250 250
 				glog.V(4).Infof("updated stream %s", diff.ObjectDiff(original, stream))
251 251
 			}
252 252
 			stream.Annotations[api.DockerImageRepositoryCheckAnnotation] = now.UTC().Format(time.RFC3339)
253
-			obj, _, err = r.internalStreams.Update(ctx, stream)
253
+			obj, _, err = r.internalStreams.Update(ctx, stream.Name, rest.DefaultUpdatedObjectInfo(stream, kapi.Scheme))
254 254
 		}
255 255
 	}
256 256
 
... ...
@@ -426,5 +426,5 @@ func newImportFailedCondition(err error, gen int64, now unversioned.Time) api.Ta
426 426
 }
427 427
 
428 428
 func invalidStatus(kind, position string, errs ...*field.Error) unversioned.Status {
429
-	return kapierrors.NewInvalid(api.Kind(kind), position, errs).(kapierrors.APIStatus).Status()
429
+	return kapierrors.NewInvalid(api.Kind(kind), position, errs).ErrStatus
430 430
 }
... ...
@@ -99,20 +99,16 @@ func (r *REST) Get(ctx kapi.Context, id string) (runtime.Object, error) {
99 99
 	return newISTag(tag, imageStream, image, false)
100 100
 }
101 101
 
102
-func (r *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
103
-	istag, ok := obj.(*api.ImageStreamTag)
104
-	if !ok {
105
-		return nil, false, kapierrors.NewBadRequest(fmt.Sprintf("obj is not an ImageStreamTag: %#v", obj))
106
-	}
107
-
108
-	name, tag, err := nameAndTag(istag.Name)
102
+func (r *REST) Update(ctx kapi.Context, tagName string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
103
+	name, tag, err := nameAndTag(tagName)
109 104
 	if err != nil {
110 105
 		return nil, false, err
111 106
 	}
112 107
 
108
+	create := false
113 109
 	imageStream, err := r.imageStreamRegistry.GetImageStream(ctx, name)
114 110
 	if err != nil {
115
-		if !kapierrors.IsNotFound(err) || len(istag.ResourceVersion) != 0 {
111
+		if !kapierrors.IsNotFound(err) {
116 112
 			return nil, false, err
117 113
 		}
118 114
 		namespace, ok := kapi.NamespaceFrom(ctx)
... ...
@@ -120,16 +116,13 @@ func (r *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, boo
120 120
 			return nil, false, kapierrors.NewBadRequest("namespace is required on ImageStreamTags")
121 121
 		}
122 122
 		imageStream = &api.ImageStream{
123
-			ObjectMeta: kapi.ObjectMeta{Namespace: namespace, Name: name},
123
+			ObjectMeta: kapi.ObjectMeta{
124
+				Namespace: namespace,
125
+				Name:      name,
126
+			},
124 127
 		}
125
-	}
126
-
127
-	// check for conflict
128
-	if len(istag.ResourceVersion) == 0 {
129
-		istag.ResourceVersion = imageStream.ResourceVersion
130
-	}
131
-	if imageStream.ResourceVersion != istag.ResourceVersion {
132
-		return nil, false, kapierrors.NewConflict(api.Resource("imagestreamtags"), istag.Name, fmt.Errorf("another caller has updated the resource version to %s", imageStream.ResourceVersion))
128
+		kapi.FillObjectMetaSystemFields(ctx, &imageStream.ObjectMeta)
129
+		create = true
133 130
 	}
134 131
 
135 132
 	// create the synthetic old istag
... ...
@@ -138,7 +131,30 @@ func (r *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, boo
138 138
 		return nil, false, err
139 139
 	}
140 140
 
141
-	if len(istag.ResourceVersion) == 0 {
141
+	obj, err := objInfo.UpdatedObject(ctx, old)
142
+	if err != nil {
143
+		return nil, false, err
144
+	}
145
+
146
+	istag, ok := obj.(*api.ImageStreamTag)
147
+	if !ok {
148
+		return nil, false, kapierrors.NewBadRequest(fmt.Sprintf("obj is not an ImageStreamTag: %#v", obj))
149
+	}
150
+
151
+	// check for conflict
152
+	switch {
153
+	case len(istag.ResourceVersion) == 0:
154
+		// should disallow blind PUT, but this was previously supported
155
+		istag.ResourceVersion = imageStream.ResourceVersion
156
+	case len(imageStream.ResourceVersion) == 0:
157
+		// image stream did not exist, cannot update
158
+		return nil, false, kapierrors.NewNotFound(api.Resource("imagestreamtags"), tagName)
159
+	case imageStream.ResourceVersion != istag.ResourceVersion:
160
+		// conflicting input and output
161
+		return nil, false, kapierrors.NewConflict(api.Resource("imagestreamtags"), istag.Name, fmt.Errorf("another caller has updated the resource version to %s", imageStream.ResourceVersion))
162
+	}
163
+
164
+	if create {
142 165
 		if err := rest.BeforeCreate(Strategy, ctx, obj); err != nil {
143 166
 			return nil, false, err
144 167
 		}
... ...
@@ -163,7 +179,7 @@ func (r *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, boo
163 163
 
164 164
 	// mutate the image stream
165 165
 	var newImageStream *api.ImageStream
166
-	if imageStream.CreationTimestamp.IsZero() {
166
+	if create {
167 167
 		newImageStream, err = r.imageStreamRegistry.CreateImageStream(ctx, imageStream)
168 168
 	} else {
169 169
 		newImageStream, err = r.imageStreamRegistry.UpdateImageStream(ctx, imageStream)
... ...
@@ -254,6 +270,7 @@ func newISTag(tag string, imageStream *api.ImageStream, image *api.Image, allowE
254 254
 			CreationTimestamp: event.Created,
255 255
 			Annotations:       map[string]string{},
256 256
 			ResourceVersion:   imageStream.ResourceVersion,
257
+			UID:               imageStream.UID,
257 258
 		},
258 259
 		Generation: event.Generation,
259 260
 		Conditions: imageStream.Status.Tags[tag].Conditions,
... ...
@@ -17,15 +17,15 @@ import (
17 17
 
18 18
 const MinTokenLength = 32
19 19
 
20
-func ValidateTokenName(name string, prefix bool) (bool, string) {
21
-	if ok, reason := oapi.MinimalNameRequirements(name, prefix); !ok {
22
-		return ok, reason
20
+func ValidateTokenName(name string, prefix bool) []string {
21
+	if reasons := oapi.MinimalNameRequirements(name, prefix); len(reasons) != 0 {
22
+		return reasons
23 23
 	}
24 24
 
25 25
 	if len(name) < MinTokenLength {
26
-		return false, fmt.Sprintf("must be at least %d characters long", MinTokenLength)
26
+		return []string{fmt.Sprintf("must be at least %d characters long", MinTokenLength)}
27 27
 	}
28
-	return true, ""
28
+	return nil
29 29
 }
30 30
 
31 31
 func ValidateRedirectURI(redirect string) (bool, string) {
... ...
@@ -156,17 +156,17 @@ func ValidateClientUpdate(client *api.OAuthClient, oldClient *api.OAuthClient) f
156 156
 	return allErrs
157 157
 }
158 158
 
159
-func ValidateClientAuthorizationName(name string, prefix bool) (bool, string) {
160
-	if ok, reason := oapi.MinimalNameRequirements(name, prefix); !ok {
161
-		return ok, reason
159
+func ValidateClientAuthorizationName(name string, prefix bool) []string {
160
+	if reasons := oapi.MinimalNameRequirements(name, prefix); len(reasons) != 0 {
161
+		return reasons
162 162
 	}
163 163
 
164 164
 	lastColon := strings.Index(name, ":")
165 165
 	if lastColon <= 0 || lastColon >= len(name)-1 {
166
-		return false, "must be in the format <userName>:<clientName>"
166
+		return []string{"must be in the format <userName>:<clientName>"}
167 167
 	}
168 168
 
169
-	return true, ""
169
+	return nil
170 170
 }
171 171
 
172 172
 func ValidateClientAuthorization(clientAuthorization *api.OAuthClientAuthorization) field.ErrorList {
... ...
@@ -214,11 +214,11 @@ func ValidateClientNameField(value string, fldPath *field.Path) field.ErrorList
214 214
 	if len(value) == 0 {
215 215
 		return field.ErrorList{field.Required(fldPath, "")}
216 216
 	} else if _, saName, err := serviceaccount.SplitUsername(value); err == nil {
217
-		if ok, errString := validation.ValidateServiceAccountName(saName, false); !ok {
218
-			return field.ErrorList{field.Invalid(fldPath, value, errString)}
217
+		if reasons := validation.ValidateServiceAccountName(saName, false); len(reasons) != 0 {
218
+			return field.ErrorList{field.Invalid(fldPath, value, strings.Join(reasons, ", "))}
219 219
 		}
220
-	} else if ok, msg := validation.NameIsDNSSubdomain(value, false); !ok {
221
-		return field.ErrorList{field.Invalid(fldPath, value, msg)}
220
+	} else if reasons := validation.NameIsDNSSubdomain(value, false); len(reasons) != 0 {
221
+		return field.ErrorList{field.Invalid(fldPath, value, strings.Join(reasons, ", "))}
222 222
 	}
223 223
 	return field.ErrorList{}
224 224
 }
... ...
@@ -226,8 +226,8 @@ func ValidateClientNameField(value string, fldPath *field.Path) field.ErrorList
226 226
 func ValidateUserNameField(value string, fldPath *field.Path) field.ErrorList {
227 227
 	if len(value) == 0 {
228 228
 		return field.ErrorList{field.Required(fldPath, "")}
229
-	} else if ok, msg := uservalidation.ValidateUserName(value, false); !ok {
230
-		return field.ErrorList{field.Invalid(fldPath, value, msg)}
229
+	} else if reasons := uservalidation.ValidateUserName(value, false); len(reasons) != 0 {
230
+		return field.ErrorList{field.Invalid(fldPath, value, strings.Join(reasons, ", "))}
231 231
 	}
232 232
 	return field.ErrorList{}
233 233
 }
... ...
@@ -63,7 +63,7 @@ func (s *storage) CreateClient(ctx kapi.Context, client *api.OAuthClient) (*api.
63 63
 }
64 64
 
65 65
 func (s *storage) UpdateClient(ctx kapi.Context, client *api.OAuthClient) (*api.OAuthClient, error) {
66
-	obj, _, err := s.Update(ctx, client)
66
+	obj, _, err := s.Update(ctx, client.Name, rest.DefaultUpdatedObjectInfo(client, kapi.Scheme))
67 67
 	if err != nil {
68 68
 		return nil, err
69 69
 	}
... ...
@@ -63,7 +63,7 @@ func (s *storage) CreateClientAuthorization(ctx kapi.Context, client *api.OAuthC
63 63
 }
64 64
 
65 65
 func (s *storage) UpdateClientAuthorization(ctx kapi.Context, client *api.OAuthClientAuthorization) (*api.OAuthClientAuthorization, error) {
66
-	obj, _, err := s.Update(ctx, client)
66
+	obj, _, err := s.Update(ctx, client.Name, rest.DefaultUpdatedObjectInfo(client, kapi.Scheme))
67 67
 	if err != nil {
68 68
 		return nil, err
69 69
 	}
... ...
@@ -12,7 +12,7 @@ import (
12 12
 	"k8s.io/kubernetes/pkg/client/cache"
13 13
 	clientsetfake "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
14 14
 	"k8s.io/kubernetes/pkg/client/unversioned/testclient"
15
-	"k8s.io/kubernetes/pkg/genericapiserver"
15
+	genericapiserveroptions "k8s.io/kubernetes/pkg/genericapiserver/options"
16 16
 	kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
17 17
 	"k8s.io/kubernetes/pkg/runtime"
18 18
 	etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
... ...
@@ -41,7 +41,7 @@ func TestIgnoreThatWhichCannotBeKnown(t *testing.T) {
41 41
 	handler := &lifecycle{}
42 42
 	unknown := &UnknownObject{}
43 43
 
44
-	err := handler.Admit(admission.NewAttributesRecord(unknown, kapi.Kind("kind").WithVersion("version"), "namespace", "name", kapi.Resource("resource").WithVersion("version"), "subresource", "CREATE", nil))
44
+	err := handler.Admit(admission.NewAttributesRecord(unknown, nil, kapi.Kind("kind").WithVersion("version"), "namespace", "name", kapi.Resource("resource").WithVersion("version"), "subresource", "CREATE", nil))
45 45
 	if err != nil {
46 46
 		t.Errorf("Admission control should not error if it finds an object it knows nothing about %v", err)
47 47
 	}
... ...
@@ -84,7 +84,7 @@ func TestAdmissionExists(t *testing.T) {
84 84
 			Phase: buildapi.BuildPhaseNew,
85 85
 		},
86 86
 	}
87
-	err := handler.Admit(admission.NewAttributesRecord(build, kapi.Kind("Build").WithVersion("version"), "namespace", "name", kapi.Resource("builds").WithVersion("version"), "", "CREATE", nil))
87
+	err := handler.Admit(admission.NewAttributesRecord(build, nil, kapi.Kind("Build").WithVersion("version"), "namespace", "name", kapi.Resource("builds").WithVersion("version"), "", "CREATE", nil))
88 88
 	if err == nil {
89 89
 		t.Errorf("Expected an error because namespace does not exist")
90 90
 	}
... ...
@@ -134,7 +134,7 @@ func TestAdmissionLifecycle(t *testing.T) {
134 134
 			Phase: buildapi.BuildPhaseNew,
135 135
 		},
136 136
 	}
137
-	err := handler.Admit(admission.NewAttributesRecord(build, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "CREATE", nil))
137
+	err := handler.Admit(admission.NewAttributesRecord(build, nil, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "CREATE", nil))
138 138
 	if err != nil {
139 139
 		t.Errorf("Unexpected error returned from admission handler: %v", err)
140 140
 	}
... ...
@@ -144,19 +144,19 @@ func TestAdmissionLifecycle(t *testing.T) {
144 144
 	store.Add(namespaceObj)
145 145
 
146 146
 	// verify create operations in the namespace cause an error
147
-	err = handler.Admit(admission.NewAttributesRecord(build, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "CREATE", nil))
147
+	err = handler.Admit(admission.NewAttributesRecord(build, nil, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "CREATE", nil))
148 148
 	if err == nil {
149 149
 		t.Errorf("Expected error rejecting creates in a namespace when it is terminating")
150 150
 	}
151 151
 
152 152
 	// verify update operations in the namespace can proceed
153
-	err = handler.Admit(admission.NewAttributesRecord(build, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "UPDATE", nil))
153
+	err = handler.Admit(admission.NewAttributesRecord(build, build, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "UPDATE", nil))
154 154
 	if err != nil {
155 155
 		t.Errorf("Unexpected error returned from admission handler: %v", err)
156 156
 	}
157 157
 
158 158
 	// verify delete operations in the namespace can proceed
159
-	err = handler.Admit(admission.NewAttributesRecord(nil, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "DELETE", nil))
159
+	err = handler.Admit(admission.NewAttributesRecord(nil, nil, kapi.Kind("Build").WithVersion("version"), build.Namespace, "name", kapi.Resource("builds").WithVersion("version"), "", "DELETE", nil))
160 160
 	if err != nil {
161 161
 		t.Errorf("Unexpected error returned from admission handler: %v", err)
162 162
 	}
... ...
@@ -165,7 +165,7 @@ func TestAdmissionLifecycle(t *testing.T) {
165 165
 
166 166
 // TestCreatesAllowedDuringNamespaceDeletion checks to make sure that the resources in the whitelist are allowed
167 167
 func TestCreatesAllowedDuringNamespaceDeletion(t *testing.T) {
168
-	etcdHelper := etcdstorage.NewEtcdStorage(nil, kapi.Codecs.LegacyCodec(), "", false, genericapiserver.DefaultDeserializationCacheSize)
168
+	etcdHelper := etcdstorage.NewEtcdStorage(nil, kapi.Codecs.LegacyCodec(), "", false, genericapiserveroptions.DefaultDeserializationCacheSize)
169 169
 
170 170
 	informerFactory := shared.NewInformerFactory(testclient.NewSimpleFake(), otestclient.NewSimpleFake(), shared.DefaultListerWatcherOverrides{}, 1*time.Second)
171 171
 	config := &origin.MasterConfig{
... ...
@@ -216,7 +216,7 @@ func TestSAR(t *testing.T) {
216 216
 	}
217 217
 
218 218
 	for k, v := range tests {
219
-		err := handler.Admit(admission.NewAttributesRecord(nil, kapi.Kind(v.kind).WithVersion("version"), "foo", "name", kapi.Resource(v.resource).WithVersion("version"), "", "CREATE", nil))
219
+		err := handler.Admit(admission.NewAttributesRecord(nil, nil, kapi.Kind(v.kind).WithVersion("version"), "foo", "name", kapi.Resource(v.resource).WithVersion("version"), "", "CREATE", nil))
220 220
 		if err != nil {
221 221
 			t.Errorf("Unexpected error for %s returned from admission handler: %v", k, err)
222 222
 		}
... ...
@@ -113,7 +113,7 @@ func TestPodAdmission(t *testing.T) {
113 113
 		}
114 114
 		pod.Spec = kapi.PodSpec{NodeSelector: test.podNodeSelector}
115 115
 
116
-		err := handler.Admit(admission.NewAttributesRecord(pod, kapi.Kind("Pod").WithVersion("version"), "namespace", project.ObjectMeta.Name, kapi.Resource("pods").WithVersion("version"), "", admission.Create, nil))
116
+		err := handler.Admit(admission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", project.ObjectMeta.Name, kapi.Resource("pods").WithVersion("version"), "", admission.Create, nil))
117 117
 		if test.admit && err != nil {
118 118
 			t.Errorf("Test: %s, expected no error but got: %s", test.testName, err)
119 119
 		} else if !test.admit && err == nil {
... ...
@@ -110,7 +110,7 @@ func (o *projectRequestLimit) maxProjectsByRequester(userName string) (int, bool
110 110
 	}
111 111
 
112 112
 	// if we aren't a valid username, we came in as cert user for certain, use our cert user rules
113
-	if valid, _ := uservalidation.ValidateUserName(userName, false); !valid {
113
+	if reasons := uservalidation.ValidateUserName(userName, false); len(reasons) != 0 {
114 114
 		if o.config.MaxProjectsForSystemUsers == nil {
115 115
 			return 0, false, nil
116 116
 		}
... ...
@@ -281,6 +281,7 @@ func TestAdmit(t *testing.T) {
281 281
 		}
282 282
 		err = reqLimit.Admit(admission.NewAttributesRecord(
283 283
 			&projectapi.ProjectRequest{},
284
+			nil,
284 285
 			projectapi.Kind("ProjectRequest").WithVersion("version"),
285 286
 			"foo",
286 287
 			"name",
... ...
@@ -13,20 +13,20 @@ import (
13 13
 	"github.com/openshift/origin/pkg/util/labelselector"
14 14
 )
15 15
 
16
-func ValidateProjectName(name string, prefix bool) (bool, string) {
17
-	if ok, reason := oapi.MinimalNameRequirements(name, prefix); !ok {
18
-		return ok, reason
16
+func ValidateProjectName(name string, prefix bool) []string {
17
+	if reasons := oapi.MinimalNameRequirements(name, prefix); len(reasons) != 0 {
18
+		return reasons
19 19
 	}
20 20
 
21 21
 	if len(name) < 2 {
22
-		return false, "must be at least 2 characters long"
22
+		return []string{"must be at least 2 characters long"}
23 23
 	}
24 24
 
25
-	if ok, msg := validation.ValidateNamespaceName(name, false); !ok {
26
-		return ok, msg
25
+	if reasons := validation.ValidateNamespaceName(name, false); len(reasons) != 0 {
26
+		return reasons
27 27
 	}
28 28
 
29
-	return true, ""
29
+	return nil
30 30
 }
31 31
 
32 32
 // ValidateProject tests required fields for a Project.
... ...
@@ -131,16 +131,22 @@ func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err
131 131
 
132 132
 var _ = rest.Updater(&REST{})
133 133
 
134
-func (s *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
135
-	project, ok := obj.(*api.Project)
136
-	if !ok {
137
-		return nil, false, fmt.Errorf("not a project: %#v", obj)
134
+func (s *REST) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
135
+	oldObj, err := s.Get(ctx, name)
136
+	if err != nil {
137
+		return nil, false, err
138 138
 	}
139 139
 
140
-	oldObj, err := s.Get(ctx, project.Name)
140
+	obj, err := objInfo.UpdatedObject(ctx, oldObj)
141 141
 	if err != nil {
142 142
 		return nil, false, err
143 143
 	}
144
+
145
+	project, ok := obj.(*api.Project)
146
+	if !ok {
147
+		return nil, false, fmt.Errorf("not a project: %#v", obj)
148
+	}
149
+
144 150
 	s.updateStrategy.PrepareForUpdate(obj, oldObj)
145 151
 	if errs := s.updateStrategy.ValidateUpdate(ctx, obj, oldObj); len(errs) > 0 {
146 152
 		return nil, false, kerrors.NewInvalid(projectapi.Kind("Project"), project.Name, errs)
... ...
@@ -218,7 +218,7 @@ func (r *REST) List(ctx kapi.Context, options *kapi.ListOptions) (runtime.Object
218 218
 		return &unversioned.Status{Status: unversioned.StatusSuccess}, nil
219 219
 	}
220 220
 
221
-	forbiddenError, _ := kapierror.NewForbidden(projectapi.Resource("projectrequest"), "", errors.New("you may not request a new project via this API.")).(*kapierror.StatusError)
221
+	forbiddenError := kapierror.NewForbidden(projectapi.Resource("projectrequest"), "", errors.New("you may not request a new project via this API."))
222 222
 	if len(r.message) > 0 {
223 223
 		forbiddenError.ErrStatus.Message = r.message
224 224
 		forbiddenError.ErrStatus.Details = &unversioned.StatusDetails{
... ...
@@ -4,11 +4,8 @@ import (
4 4
 	"fmt"
5 5
 	"io"
6 6
 
7
-	oadmission "github.com/openshift/origin/pkg/cmd/server/admission"
8
-	configlatest "github.com/openshift/origin/pkg/cmd/server/api/latest"
9
-	"github.com/openshift/origin/pkg/project/cache"
10
-	"github.com/openshift/origin/pkg/quota/admission/clusterresourceoverride/api"
11
-	"github.com/openshift/origin/pkg/quota/admission/clusterresourceoverride/api/validation"
7
+	"github.com/golang/glog"
8
+
12 9
 	"k8s.io/kubernetes/pkg/admission"
13 10
 	kapi "k8s.io/kubernetes/pkg/api"
14 11
 	"k8s.io/kubernetes/pkg/api/resource"
... ...
@@ -16,8 +13,11 @@ import (
16 16
 	"k8s.io/kubernetes/pkg/runtime"
17 17
 	"k8s.io/kubernetes/plugin/pkg/admission/limitranger"
18 18
 
19
-	"github.com/golang/glog"
20
-	"speter.net/go/exp/math/dec/inf"
19
+	oadmission "github.com/openshift/origin/pkg/cmd/server/admission"
20
+	configlatest "github.com/openshift/origin/pkg/cmd/server/api/latest"
21
+	"github.com/openshift/origin/pkg/project/cache"
22
+	"github.com/openshift/origin/pkg/quota/admission/clusterresourceoverride/api"
23
+	"github.com/openshift/origin/pkg/quota/admission/clusterresourceoverride/api/validation"
21 24
 )
22 25
 
23 26
 const (
... ...
@@ -26,8 +26,6 @@ const (
26 26
 )
27 27
 
28 28
 var (
29
-	zeroDec  = inf.NewDec(0, 0)
30
-	miDec    = inf.NewDec(1024*1024, 0)
31 29
 	cpuFloor = resource.MustParse("1m")
32 30
 	memFloor = resource.MustParse("1Mi")
33 31
 )
... ...
@@ -47,9 +45,9 @@ func init() {
47 47
 }
48 48
 
49 49
 type internalConfig struct {
50
-	limitCPUToMemoryRatio     *inf.Dec
51
-	cpuRequestToLimitRatio    *inf.Dec
52
-	memoryRequestToLimitRatio *inf.Dec
50
+	limitCPUToMemoryRatio     float64
51
+	cpuRequestToLimitRatio    float64
52
+	memoryRequestToLimitRatio float64
53 53
 }
54 54
 type clusterResourceOverridePlugin struct {
55 55
 	*admission.Handler
... ...
@@ -70,9 +68,9 @@ func newClusterResourceOverride(client clientset.Interface, config *api.ClusterR
70 70
 	var internal *internalConfig
71 71
 	if config != nil {
72 72
 		internal = &internalConfig{
73
-			limitCPUToMemoryRatio:     inf.NewDec(config.LimitCPUToMemoryPercent, 2),
74
-			cpuRequestToLimitRatio:    inf.NewDec(config.CPURequestToLimitPercent, 2),
75
-			memoryRequestToLimitRatio: inf.NewDec(config.MemoryRequestToLimitPercent, 2),
73
+			limitCPUToMemoryRatio:     float64(config.LimitCPUToMemoryPercent) / 100,
74
+			cpuRequestToLimitRatio:    float64(config.CPURequestToLimitPercent) / 100,
75
+			memoryRequestToLimitRatio: float64(config.MemoryRequestToLimitPercent) / 100,
76 76
 		}
77 77
 	}
78 78
 
... ...
@@ -165,48 +163,46 @@ func (a *clusterResourceOverridePlugin) Admit(attr admission.Attributes) error {
165 165
 	for _, container := range pod.Spec.Containers {
166 166
 		resources := container.Resources
167 167
 		memLimit, memFound := resources.Limits[kapi.ResourceMemory]
168
-		if memFound && a.config.memoryRequestToLimitRatio.Cmp(zeroDec) != 0 {
168
+		if memFound && a.config.memoryRequestToLimitRatio != 0 {
169 169
 			// memory is measured in whole bytes.
170 170
 			// the plugin rounds down to the nearest MiB rather than bytes to improve ease of use for end-users.
171
-			amount := multiply(memLimit.Amount, a.config.memoryRequestToLimitRatio)
172
-			roundDownToNearestMi := multiply(divide(amount, miDec, 0, inf.RoundDown), miDec)
173
-			value := resource.Quantity{Amount: roundDownToNearestMi, Format: resource.BinarySI}
174
-			if memFloor.Cmp(value) > 0 {
175
-				value = *(memFloor.Copy())
171
+			amount := memLimit.Value() * int64(a.config.memoryRequestToLimitRatio*100) / 100
172
+			// TODO: move into resource.Quantity
173
+			var mod int64
174
+			switch memLimit.Format {
175
+			case resource.BinarySI:
176
+				mod = 1024 * 1024
177
+			default:
178
+				mod = 1000 * 1000
179
+			}
180
+			if rem := amount % mod; rem != 0 {
181
+				amount = amount - rem
182
+			}
183
+			q := resource.NewQuantity(int64(amount), memLimit.Format)
184
+			if memFloor.Cmp(*q) > 0 {
185
+				q = memFloor.Copy()
176 186
 			}
177
-			resources.Requests[kapi.ResourceMemory] = value
187
+			resources.Requests[kapi.ResourceMemory] = *q
178 188
 		}
179
-		if memFound && a.config.limitCPUToMemoryRatio.Cmp(zeroDec) != 0 {
180
-			// float math is necessary here as there is no way to create an inf.Dec to represent cpuBaseScaleFactor < 0.001
181
-			// cpu is measured in millicores, so we need to scale and round down the value to nearest millicore scale
182
-			amount := multiply(inf.NewDec(int64(float64(memLimit.Value())*cpuBaseScaleFactor), 3), a.config.limitCPUToMemoryRatio)
183
-			amount.Round(amount, 3, inf.RoundDown)
184
-			value := resource.Quantity{Amount: amount, Format: resource.DecimalSI}
185
-			if cpuFloor.Cmp(value) > 0 {
186
-				value = *(cpuFloor.Copy())
189
+		if memFound && a.config.limitCPUToMemoryRatio != 0 {
190
+			amount := float64(memLimit.Value()) * a.config.limitCPUToMemoryRatio * cpuBaseScaleFactor
191
+			q := resource.NewMilliQuantity(int64(amount), resource.DecimalSI)
192
+			if cpuFloor.Cmp(*q) > 0 {
193
+				q = cpuFloor.Copy()
187 194
 			}
188
-			resources.Limits[kapi.ResourceCPU] = value
195
+			resources.Limits[kapi.ResourceCPU] = *q
189 196
 		}
197
+
190 198
 		cpuLimit, cpuFound := resources.Limits[kapi.ResourceCPU]
191
-		if cpuFound && a.config.cpuRequestToLimitRatio.Cmp(zeroDec) != 0 {
192
-			// cpu is measured in millicores, so we need to scale and round down the value to nearest millicore scale
193
-			amount := multiply(cpuLimit.Amount, a.config.cpuRequestToLimitRatio)
194
-			amount.Round(amount, 3, inf.RoundDown)
195
-			value := resource.Quantity{Amount: amount, Format: resource.DecimalSI}
196
-			if cpuFloor.Cmp(value) > 0 {
197
-				value = *(cpuFloor.Copy())
199
+		if cpuFound && a.config.cpuRequestToLimitRatio != 0 {
200
+			amount := float64(cpuLimit.MilliValue()) * a.config.cpuRequestToLimitRatio
201
+			q := resource.NewMilliQuantity(int64(amount), cpuLimit.Format)
202
+			if cpuFloor.Cmp(*q) > 0 {
203
+				q = cpuFloor.Copy()
198 204
 			}
199
-			resources.Requests[kapi.ResourceCPU] = value
205
+			resources.Requests[kapi.ResourceCPU] = *q
200 206
 		}
201 207
 	}
202 208
 	glog.V(5).Infof("%s: pod limits after overrides are: %#v", api.PluginName, pod.Spec.Containers[0].Resources)
203 209
 	return nil
204 210
 }
205
-
206
-func multiply(x *inf.Dec, y *inf.Dec) *inf.Dec {
207
-	return inf.NewDec(0, 0).Mul(x, y)
208
-}
209
-
210
-func divide(x *inf.Dec, y *inf.Dec, s inf.Scale, r inf.Rounder) *inf.Dec {
211
-	return inf.NewDec(0, 0).QuoRound(x, y, s, r)
212
-}
... ...
@@ -220,20 +220,20 @@ func TestLimitRequestAdmission(t *testing.T) {
220 220
 			continue
221 221
 		}
222 222
 		c.(*clusterResourceOverridePlugin).SetProjectCache(fakeProjectCache(test.namespace))
223
-		attrs := admission.NewAttributesRecord(test.pod, unversioned.GroupVersionKind{}, test.namespace.Name, "name", kapi.Resource("pods").WithVersion("version"), "", admission.Create, fakeUser())
223
+		attrs := admission.NewAttributesRecord(test.pod, nil, unversioned.GroupVersionKind{}, test.namespace.Name, "name", kapi.Resource("pods").WithVersion("version"), "", admission.Create, fakeUser())
224 224
 		if err = c.Admit(attrs); err != nil {
225 225
 			t.Errorf("%s: admission controller returned error: %v", test.name, err)
226 226
 			continue
227 227
 		}
228 228
 		resources := test.pod.Spec.Containers[0].Resources // only test one container
229 229
 		if actual := resources.Requests[kapi.ResourceMemory]; test.expectedMemRequest.Cmp(actual) != 0 {
230
-			t.Errorf("%s: memory requests do not match; %s should be %s", test.name, actual, test.expectedMemRequest)
230
+			t.Errorf("%s: memory requests do not match; %v should be %v", test.name, actual, test.expectedMemRequest)
231 231
 		}
232 232
 		if actual := resources.Requests[kapi.ResourceCPU]; test.expectedCpuRequest.Cmp(actual) != 0 {
233
-			t.Errorf("%s: cpu requests do not match; %s should be %s", test.name, actual, test.expectedCpuRequest)
233
+			t.Errorf("%s: cpu requests do not match; %v should be %v", test.name, actual, test.expectedCpuRequest)
234 234
 		}
235 235
 		if actual := resources.Limits[kapi.ResourceCPU]; test.expectedCpuLimit.Cmp(actual) != 0 {
236
-			t.Errorf("%s: cpu limits do not match; %s should be %s", test.name, actual, test.expectedCpuLimit)
236
+			t.Errorf("%s: cpu limits do not match; %v should be %v", test.name, actual, test.expectedCpuLimit)
237 237
 		}
238 238
 	}
239 239
 }
... ...
@@ -43,7 +43,7 @@ func TestOriginQuotaAdmissionIsErrorQuotaExceeded(t *testing.T) {
43 43
 		},
44 44
 	}
45 45
 
46
-	err := plugin.Admit(admission.NewAttributesRecord(newIS, imageapi.Kind("ImageStream").WithVersion("version"), newIS.Namespace, newIS.Name, kapi.Resource("imageStreams").WithVersion("version"), "", admission.Create, nil))
46
+	err := plugin.Admit(admission.NewAttributesRecord(newIS, nil, imageapi.Kind("ImageStream").WithVersion("version"), newIS.Namespace, newIS.Name, kapi.Resource("imageStreams").WithVersion("version"), "", admission.Create, nil))
47 47
 	if err == nil {
48 48
 		t.Fatalf("Expected an error exceeding quota")
49 49
 	}
... ...
@@ -137,7 +137,7 @@ func TestRunOnceDurationAdmit(t *testing.T) {
137 137
 		runOnceDuration := NewRunOnceDuration(tc.config)
138 138
 		runOnceDuration.(oadmission.WantsProjectCache).SetProjectCache(testCache(tc.projectAnnotations))
139 139
 		pod := tc.pod
140
-		attrs := admission.NewAttributesRecord(pod, kapi.Kind("Pod").WithVersion("version"), "default", "test", kapi.Resource("pods").WithVersion("version"), "", admission.Create, nil)
140
+		attrs := admission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "default", "test", kapi.Resource("pods").WithVersion("version"), "", admission.Create, nil)
141 141
 		err := runOnceDuration.Admit(attrs)
142 142
 		if err != nil {
143 143
 			t.Errorf("%s: unexpected admission error: %v", tc.name, err)
... ...
@@ -269,12 +269,12 @@ func TestSyncFunc(t *testing.T) {
269 269
 		}
270 270
 
271 271
 		// the internal representation doesn't have json tags and I want a better diff, so converting
272
-		expectedV1, err := kapi.Scheme.ConvertToVersion(tc.expectedQuota(), quotaapiv1.SchemeGroupVersion.String())
272
+		expectedV1, err := kapi.Scheme.ConvertToVersion(tc.expectedQuota(), quotaapiv1.SchemeGroupVersion)
273 273
 		if err != nil {
274 274
 			t.Errorf("%s: unexpected error: %v", tc.name, err)
275 275
 			continue
276 276
 		}
277
-		actualV1, err := kapi.Scheme.ConvertToVersion(actualQuota, quotaapiv1.SchemeGroupVersion.String())
277
+		actualV1, err := kapi.Scheme.ConvertToVersion(actualQuota, quotaapiv1.SchemeGroupVersion)
278 278
 		if err != nil {
279 279
 			t.Errorf("%s: unexpected error: %v", tc.name, err)
280 280
 			continue
... ...
@@ -27,7 +27,7 @@ func NewSimpleAllocationPlugin(suffix string) (*SimpleAllocationPlugin, error) {
27 27
 	glog.V(4).Infof("Route plugin initialized with suffix=%s", suffix)
28 28
 
29 29
 	// Check that the DNS suffix is valid.
30
-	if !kvalidation.IsDNS1123Subdomain(suffix) {
30
+	if len(kvalidation.IsDNS1123Subdomain(suffix)) != 0 {
31 31
 		return nil, fmt.Errorf("invalid DNS suffix: %s", suffix)
32 32
 	}
33 33
 
... ...
@@ -150,7 +150,7 @@ func TestSimpleAllocationPlugin(t *testing.T) {
150 150
 		case tc.empty:
151 151
 			continue
152 152
 		}
153
-		if !validation.IsDNS1123Subdomain(name) {
153
+		if len(validation.IsDNS1123Subdomain(name)) != 0 {
154 154
 			t.Errorf("Test case %s got %s - invalid DNS name.", tc.name, name)
155 155
 		}
156 156
 	}
... ...
@@ -244,7 +244,7 @@ func TestSimpleAllocationPluginViaController(t *testing.T) {
244 244
 		case tc.empty:
245 245
 			continue
246 246
 		}
247
-		if !validation.IsDNS1123Subdomain(name) {
247
+		if len(validation.IsDNS1123Subdomain(name)) != 0 {
248 248
 			t.Errorf("Test case %s got %s - invalid DNS name.", tc.name, name)
249 249
 		}
250 250
 	}
... ...
@@ -26,7 +26,7 @@ func ValidateRoute(route *routeapi.Route) field.ErrorList {
26 26
 
27 27
 	//host is not required but if it is set ensure it meets DNS requirements
28 28
 	if len(route.Spec.Host) > 0 {
29
-		if !kvalidation.IsDNS1123Subdomain(route.Spec.Host) {
29
+		if len(kvalidation.IsDNS1123Subdomain(route.Spec.Host)) != 0 {
30 30
 			result = append(result, field.Invalid(specPath.Child("host"), route.Spec.Host, "host must conform to DNS 952 subdomain conventions"))
31 31
 		}
32 32
 	}
... ...
@@ -2,6 +2,7 @@ package etcd
2 2
 
3 3
 import (
4 4
 	kapi "k8s.io/kubernetes/pkg/api"
5
+	kapirest "k8s.io/kubernetes/pkg/api/rest"
5 6
 	"k8s.io/kubernetes/pkg/fields"
6 7
 	"k8s.io/kubernetes/pkg/labels"
7 8
 	"k8s.io/kubernetes/pkg/registry/generic"
... ...
@@ -65,6 +66,6 @@ func (r *StatusREST) New() runtime.Object {
65 65
 }
66 66
 
67 67
 // Update alters the status subset of an object.
68
-func (r *StatusREST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
69
-	return r.store.Update(ctx, obj)
68
+func (r *StatusREST) Update(ctx kapi.Context, name string, objInfo kapirest.UpdatedObjectInfo) (runtime.Object, bool, error) {
69
+	return r.store.Update(ctx, name, objInfo)
70 70
 }
... ...
@@ -139,7 +139,7 @@ func TestStatusAdmitsRouteOnForbidden(t *testing.T) {
139 139
 	nowFn = func() unversioned.Time { return now }
140 140
 	touched := unversioned.Time{Time: now.Add(-time.Minute)}
141 141
 	p := &fakePlugin{}
142
-	c := testclient.NewSimpleFake(&(errors.NewForbidden(kapi.Resource("Route"), "route1", nil).(*errors.StatusError).ErrStatus))
142
+	c := testclient.NewSimpleFake(&(errors.NewForbidden(kapi.Resource("Route"), "route1", nil).ErrStatus))
143 143
 	admitter := NewStatusAdmitter(p, c, "test")
144 144
 	err := admitter.HandleRoute(watch.Added, &routeapi.Route{
145 145
 		ObjectMeta: kapi.ObjectMeta{Name: "route1", Namespace: "default", UID: types.UID("uid1")},
... ...
@@ -168,7 +168,7 @@ func TestStatusBackoffOnConflict(t *testing.T) {
168 168
 	nowFn = func() unversioned.Time { return now }
169 169
 	touched := unversioned.Time{Time: now.Add(-time.Minute)}
170 170
 	p := &fakePlugin{}
171
-	c := testclient.NewSimpleFake(&(errors.NewConflict(kapi.Resource("Route"), "route1", nil).(*errors.StatusError).ErrStatus))
171
+	c := testclient.NewSimpleFake(&(errors.NewConflict(kapi.Resource("Route"), "route1", nil).ErrStatus))
172 172
 	admitter := NewStatusAdmitter(p, c, "test")
173 173
 	err := admitter.HandleRoute(watch.Added, &routeapi.Route{
174 174
 		ObjectMeta: kapi.ObjectMeta{Name: "route1", Namespace: "default", UID: types.UID("uid1")},
... ...
@@ -361,7 +361,7 @@ func TestStatusRecordRejectionConflict(t *testing.T) {
361 361
 	nowFn = func() unversioned.Time { return now }
362 362
 	touched := unversioned.Time{Time: now.Add(-time.Minute)}
363 363
 	p := &fakePlugin{}
364
-	c := testclient.NewSimpleFake(&(errors.NewConflict(kapi.Resource("Route"), "route1", nil).(*errors.StatusError).ErrStatus))
364
+	c := testclient.NewSimpleFake(&(errors.NewConflict(kapi.Resource("Route"), "route1", nil).ErrStatus))
365 365
 	admitter := NewStatusAdmitter(p, c, "test")
366 366
 	admitter.RecordRouteRejection(&routeapi.Route{
367 367
 		ObjectMeta: kapi.ObjectMeta{Name: "route1", Namespace: "default", UID: types.UID("uid1")},
... ...
@@ -452,7 +452,7 @@ func TestStatusFightBetweenRouters(t *testing.T) {
452 452
 	now1 := unversioned.Now()
453 453
 	nowFn = func() unversioned.Time { return now1 }
454 454
 	touched1 := unversioned.Time{Time: now1.Add(-time.Minute)}
455
-	c1 := testclient.NewSimpleFake(&(errors.NewConflict(kapi.Resource("Route"), "route1", nil).(*errors.StatusError).ErrStatus), &routeapi.Route{})
455
+	c1 := testclient.NewSimpleFake(&(errors.NewConflict(kapi.Resource("Route"), "route1", nil).ErrStatus), &routeapi.Route{})
456 456
 	admitter1 := NewStatusAdmitter(p, c1, "test2")
457 457
 	err := admitter1.HandleRoute(watch.Added, &routeapi.Route{
458 458
 		ObjectMeta: kapi.ObjectMeta{Name: "route1", Namespace: "default", UID: types.UID("uid1")},
... ...
@@ -530,7 +530,7 @@ func makePass(t *testing.T, host string, admitter *StatusAdmitter, srcObj *route
530 530
 	// initialize a new client
531 531
 	var c *testclient.Fake
532 532
 	if conflict {
533
-		c = testclient.NewSimpleFake(&(errors.NewConflict(kapi.Resource("Route"), "route1", nil).(*errors.StatusError).ErrStatus))
533
+		c = testclient.NewSimpleFake(&(errors.NewConflict(kapi.Resource("Route"), "route1", nil).ErrStatus))
534 534
 	} else {
535 535
 		c = testclient.NewSimpleFake(&routeapi.Route{})
536 536
 	}
... ...
@@ -69,9 +69,12 @@ var resourcesToCheck = map[unversioned.GroupResource]unversioned.GroupKind{
69 69
 	kapi.Resource("podtemplates"):                               kapi.Kind("PodTemplate"),
70 70
 	kapi.Resource("replicationcontrollers"):                     kapi.Kind("ReplicationController"),
71 71
 	batch.Resource("jobs"):                                      batch.Kind("Job"),
72
+	batch.Resource("jobtemplates"):                              batch.Kind("JobTemplate"),
73
+	batch.Resource("scheduledjobs"):                             batch.Kind("ScheduledJob"),
72 74
 	extensions.Resource("deployments"):                          extensions.Kind("Deployment"),
73 75
 	extensions.Resource("replicasets"):                          extensions.Kind("ReplicaSet"),
74 76
 	extensions.Resource("jobs"):                                 extensions.Kind("Job"),
77
+	extensions.Resource("jobtemplates"):                         extensions.Kind("JobTemplate"),
75 78
 	apps.Resource("petsets"):                                    apps.Kind("PetSet"),
76 79
 	deployapi.Resource("deploymentconfigs"):                     deployapi.Kind("DeploymentConfig"),
77 80
 	securityapi.Resource("podsecuritypolicysubjectreviews"):     securityapi.Kind("PodSecurityPolicySubjectReview"),
... ...
@@ -157,6 +160,10 @@ func (o *podNodeConstraints) getPodSpec(attr admission.Attributes) (kapi.PodSpec
157 157
 		return r.Spec.Template.Spec, nil
158 158
 	case *batch.Job:
159 159
 		return r.Spec.Template.Spec, nil
160
+	case *batch.ScheduledJob:
161
+		return r.Spec.JobTemplate.Spec.Template.Spec, nil
162
+	case *batch.JobTemplate:
163
+		return r.Template.Spec.Template.Spec, nil
160 164
 	case *deployapi.DeploymentConfig:
161 165
 		return r.Spec.Template.Spec, nil
162 166
 	case *securityapi.PodSecurityPolicySubjectReview:
... ...
@@ -112,7 +112,7 @@ func TestPodNodeConstraints(t *testing.T) {
112 112
 			checkAdmitError(t, err, expectedError, errPrefix)
113 113
 			continue
114 114
 		}
115
-		attrs := admission.NewAttributesRecord(tc.resource, kapi.Kind("Pod").WithVersion("version"), ns, "test", kapi.Resource("pods").WithVersion("version"), "", admission.Create, tc.userinfo)
115
+		attrs := admission.NewAttributesRecord(tc.resource, nil, kapi.Kind("Pod").WithVersion("version"), ns, "test", kapi.Resource("pods").WithVersion("version"), "", admission.Create, tc.userinfo)
116 116
 		if tc.expectedErrorMsg != "" {
117 117
 			expectedError = admission.NewForbidden(attrs, fmt.Errorf(tc.expectedErrorMsg))
118 118
 		}
... ...
@@ -132,7 +132,7 @@ func TestPodNodeConstraintsPodUpdate(t *testing.T) {
132 132
 		checkAdmitError(t, err, expectedError, errPrefix)
133 133
 		return
134 134
 	}
135
-	attrs := admission.NewAttributesRecord(nodeNamePod(), kapi.Kind("Pod").WithVersion("version"), ns, "test", kapi.Resource("pods").WithVersion("version"), "", admission.Update, serviceaccount.UserInfo("", "", ""))
135
+	attrs := admission.NewAttributesRecord(nodeNamePod(), nodeNamePod(), kapi.Kind("Pod").WithVersion("version"), ns, "test", kapi.Resource("pods").WithVersion("version"), "", admission.Update, serviceaccount.UserInfo("", "", ""))
136 136
 	err = prc.Admit(attrs)
137 137
 	checkAdmitError(t, err, expectedError, errPrefix)
138 138
 }
... ...
@@ -148,7 +148,7 @@ func TestPodNodeConstraintsNonHandledResources(t *testing.T) {
148 148
 		checkAdmitError(t, err, expectedError, errPrefix)
149 149
 		return
150 150
 	}
151
-	attrs := admission.NewAttributesRecord(resourceQuota(), kapi.Kind("ResourceQuota").WithVersion("version"), ns, "test", kapi.Resource("resourcequotas").WithVersion("version"), "", admission.Create, serviceaccount.UserInfo("", "", ""))
151
+	attrs := admission.NewAttributesRecord(resourceQuota(), nil, kapi.Kind("ResourceQuota").WithVersion("version"), ns, "test", kapi.Resource("resourcequotas").WithVersion("version"), "", admission.Create, serviceaccount.UserInfo("", "", ""))
152 152
 	err = prc.Admit(attrs)
153 153
 	checkAdmitError(t, err, expectedError, errPrefix)
154 154
 }
... ...
@@ -272,7 +272,7 @@ func TestPodNodeConstraintsResources(t *testing.T) {
272 272
 						checkAdmitError(t, err, expectedError, errPrefix)
273 273
 						continue
274 274
 					}
275
-					attrs := admission.NewAttributesRecord(tr.resource(tp.nodeselector), tr.kind.WithVersion("version"), ns, "test", tr.groupresource.WithVersion("version"), "", top.operation, tc.userinfo)
275
+					attrs := admission.NewAttributesRecord(tr.resource(tp.nodeselector), nil, tr.kind.WithVersion("version"), ns, "test", tr.groupresource.WithVersion("version"), "", top.operation, tc.userinfo)
276 276
 					if tp.expectedErrorMsg != "" {
277 277
 						expectedError = admission.NewForbidden(attrs, fmt.Errorf(tp.expectedErrorMsg))
278 278
 					}
... ...
@@ -10,6 +10,7 @@ import (
10 10
 
11 11
 	kapi "k8s.io/kubernetes/pkg/api"
12 12
 	"k8s.io/kubernetes/pkg/api/resource"
13
+	"k8s.io/kubernetes/pkg/apis/componentconfig"
13 14
 	kubeletTypes "k8s.io/kubernetes/pkg/kubelet/container"
14 15
 	knetwork "k8s.io/kubernetes/pkg/kubelet/network"
15 16
 	utilsets "k8s.io/kubernetes/pkg/util/sets"
... ...
@@ -52,7 +53,7 @@ func (plugin *OsdnNode) getExecutable() string {
52 52
 	return "openshift-sdn-ovs"
53 53
 }
54 54
 
55
-func (plugin *OsdnNode) Init(host knetwork.Host) error {
55
+func (plugin *OsdnNode) Init(host knetwork.Host, _ componentconfig.HairpinMode, _ string) error {
56 56
 	return nil
57 57
 }
58 58
 
... ...
@@ -133,7 +133,7 @@ func testSCCAdmit(testCaseName string, sccs []*kapi.SecurityContextConstraints,
133 133
 
134 134
 	plugin := NewTestAdmission(store, tc)
135 135
 
136
-	attrs := kadmission.NewAttributesRecord(pod, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
136
+	attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
137 137
 	err := plugin.Admit(attrs)
138 138
 
139 139
 	if shouldPass && err != nil {
... ...
@@ -374,7 +374,7 @@ func TestAdmit(t *testing.T) {
374 374
 	}
375 375
 
376 376
 	for k, v := range testCases {
377
-		attrs := kadmission.NewAttributesRecord(v.pod, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
377
+		attrs := kadmission.NewAttributesRecord(v.pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
378 378
 		err := p.Admit(attrs)
379 379
 
380 380
 		if v.shouldAdmit && err != nil {
... ...
@@ -448,7 +448,7 @@ func TestAdmit(t *testing.T) {
448 448
 
449 449
 	for k, v := range testCases {
450 450
 		if !v.shouldAdmit {
451
-			attrs := kadmission.NewAttributesRecord(v.pod, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
451
+			attrs := kadmission.NewAttributesRecord(v.pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
452 452
 			err := p.Admit(attrs)
453 453
 			if err != nil {
454 454
 				t.Errorf("Expected %s to pass with escalated scc but got error %v", k, err)
... ...
@@ -823,7 +823,7 @@ func TestCreateProvidersFromConstraints(t *testing.T) {
823 823
 		scc := v.scc()
824 824
 
825 825
 		// create the providers, this method only needs the namespace
826
-		attributes := kadmission.NewAttributesRecord(nil, kapi.Kind("Pod").WithVersion("version"), v.namespace.Name, "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, nil)
826
+		attributes := kadmission.NewAttributesRecord(nil, nil, kapi.Kind("Pod").WithVersion("version"), v.namespace.Name, "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, nil)
827 827
 		_, errs := admit.createProvidersFromConstraints(attributes.GetNamespace(), []*kapi.SecurityContextConstraints{scc})
828 828
 
829 829
 		if !reflect.DeepEqual(scc, v.scc()) {
... ...
@@ -1465,7 +1465,7 @@ func TestAdmitWithPrioritizedSCC(t *testing.T) {
1465 1465
 // testSCCAdmission is a helper to admit the pod and ensure it was validated against the expected
1466 1466
 // SCC.
1467 1467
 func testSCCAdmission(pod *kapi.Pod, plugin kadmission.Interface, expectedSCC string, t *testing.T) {
1468
-	attrs := kadmission.NewAttributesRecord(pod, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
1468
+	attrs := kadmission.NewAttributesRecord(pod, nil, kapi.Kind("Pod").WithVersion("version"), "namespace", "", kapi.Resource("pods").WithVersion("version"), "", kadmission.Create, &user.DefaultInfo{})
1469 1469
 	err := plugin.Admit(attrs)
1470 1470
 	if err != nil {
1471 1471
 		t.Errorf("error admitting pod: %v", err)
... ...
@@ -42,7 +42,7 @@ func (d *sccExecRestrictions) Admit(a admission.Attributes) (err error) {
42 42
 
43 43
 	// TODO, if we want to actually limit who can use which service account, then we'll need to add logic here to make sure that
44 44
 	// we're allowed to use the SA the pod is using.  Otherwise, user-A creates pod and user-B (who can't use the SA) can exec into it.
45
-	createAttributes := admission.NewAttributesRecord(pod, kapi.Kind("Pod").WithVersion(""), a.GetNamespace(), a.GetName(), a.GetResource(), "", admission.Create, a.GetUserInfo())
45
+	createAttributes := admission.NewAttributesRecord(pod, pod, kapi.Kind("Pod").WithVersion(""), a.GetNamespace(), a.GetName(), a.GetResource(), "", admission.Create, a.GetUserInfo())
46 46
 	if err := d.constraintAdmission.Admit(createAttributes); err != nil {
47 47
 		return admission.NewForbidden(a, err)
48 48
 	}
... ...
@@ -34,7 +34,7 @@ func TestExecAdmit(t *testing.T) {
34 34
 		resource    string
35 35
 		subresource string
36 36
 
37
-		pod                    *kapi.Pod
37
+		pod, oldPod            *kapi.Pod
38 38
 		shouldAdmit            bool
39 39
 		shouldHaveClientAction bool
40 40
 	}{
... ...
@@ -90,7 +90,7 @@ func TestExecAdmit(t *testing.T) {
90 90
 		// create the admission plugin
91 91
 		p := NewSCCExecRestrictions(tc)
92 92
 
93
-		attrs := kadmission.NewAttributesRecord(v.pod, kapi.Kind("Pod").WithVersion("version"), "namespace", "pod-name", kapi.Resource(v.resource).WithVersion("version"), v.subresource, v.operation, &user.DefaultInfo{})
93
+		attrs := kadmission.NewAttributesRecord(v.pod, v.oldPod, kapi.Kind("Pod").WithVersion("version"), "namespace", "pod-name", kapi.Resource(v.resource).WithVersion("version"), v.subresource, v.operation, &user.DefaultInfo{})
94 94
 		err := p.Admit(attrs)
95 95
 
96 96
 		if v.shouldAdmit && err != nil {
... ...
@@ -1,6 +1,8 @@
1 1
 package validation
2 2
 
3 3
 import (
4
+	"strings"
5
+
4 6
 	kapivalidation "k8s.io/kubernetes/pkg/api/validation"
5 7
 	"k8s.io/kubernetes/pkg/util/validation/field"
6 8
 
... ...
@@ -55,8 +57,8 @@ func validateServiceAccountNames(serviceAccountNames []string, fldPath *field.Pa
55 55
 		case len(sa) == 0:
56 56
 			allErrs = append(allErrs, field.Invalid(idxPath, sa, ""))
57 57
 		case len(sa) > 0:
58
-			if ok, msg := kapivalidation.ValidateServiceAccountName(sa, false); !ok {
59
-				allErrs = append(allErrs, field.Invalid(idxPath, sa, msg))
58
+			if reasons := kapivalidation.ValidateServiceAccountName(sa, false); len(reasons) != 0 {
59
+				allErrs = append(allErrs, field.Invalid(idxPath, sa, strings.Join(reasons, ", ")))
60 60
 			}
61 61
 		}
62 62
 	}
... ...
@@ -129,13 +129,13 @@ func TestValidatePodSecurityPolicyReview(t *testing.T) {
129 129
 				PodSpec: invalidPodSpec(),
130 130
 			},
131 131
 		},
132
-		`spec.serviceAccountNames[0]: Invalid value: "my bad sa": must be a DNS subdomain (at most 253 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*): e.g. "example.com"`: {
132
+		`spec.serviceAccountNames[0]: Invalid value: "my bad sa": must match the regex [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)* (e.g. 'example.com')`: {
133 133
 			Spec: securityapi.PodSecurityPolicyReviewSpec{
134 134
 				PodSpec:             validPodSpec(),
135 135
 				ServiceAccountNames: []string{"my bad sa"},
136 136
 			},
137 137
 		},
138
-		`spec.serviceAccountNames[1]: Invalid value: "my bad sa": must be a DNS subdomain (at most 253 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*): e.g. "example.com"`: {
138
+		`spec.serviceAccountNames[1]: Invalid value: "my bad sa": must match the regex [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)* (e.g. 'example.com')`: {
139 139
 			Spec: securityapi.PodSecurityPolicyReviewSpec{
140 140
 				PodSpec:             validPodSpec(),
141 141
 				ServiceAccountNames: []string{"good-service.account", "my bad sa"},
... ...
@@ -161,7 +161,7 @@ func TestAdmission(t *testing.T) {
161 161
 		svc.Spec.ExternalIPs = test.externalIPs
162 162
 		handler := NewExternalIPRanger(test.rejects, test.admits)
163 163
 
164
-		err := handler.Admit(admission.NewAttributesRecord(svc, kapi.Kind("Service").WithVersion("version"), "namespace", svc.ObjectMeta.Name, kapi.Resource("services").WithVersion("version"), "", test.op, nil))
164
+		err := handler.Admit(admission.NewAttributesRecord(svc, nil, kapi.Kind("Service").WithVersion("version"), "namespace", svc.ObjectMeta.Name, kapi.Resource("services").WithVersion("version"), "", test.op, nil))
165 165
 		if test.admit && err != nil {
166 166
 			t.Errorf("%s: expected no error but got: %s", test.testName, err)
167 167
 		} else if !test.admit && err == nil {
... ...
@@ -17,7 +17,7 @@ func AddObjectsToTemplate(template *Template, objects []runtime.Object, targetVe
17 17
 			return errors.New("cannot add a nil object to a template")
18 18
 		}
19 19
 
20
-		kind, err := kapi.Scheme.ObjectKind(obj)
20
+		kind, _, err := kapi.Scheme.ObjectKind(obj)
21 21
 		if err != nil {
22 22
 			return err
23 23
 		}
... ...
@@ -11,64 +11,64 @@ import (
11 11
 	"github.com/openshift/origin/pkg/user/api"
12 12
 )
13 13
 
14
-func ValidateUserName(name string, _ bool) (bool, string) {
15
-	if ok, reason := oapi.MinimalNameRequirements(name, false); !ok {
16
-		return ok, reason
14
+func ValidateUserName(name string, _ bool) []string {
15
+	if reasons := oapi.MinimalNameRequirements(name, false); len(reasons) != 0 {
16
+		return reasons
17 17
 	}
18 18
 
19 19
 	if strings.Contains(name, ":") {
20
-		return false, `may not contain ":"`
20
+		return []string{`may not contain ":"`}
21 21
 	}
22 22
 	if name == "~" {
23
-		return false, `may not equal "~"`
23
+		return []string{`may not equal "~"`}
24 24
 	}
25
-	return true, ""
25
+	return nil
26 26
 }
27 27
 
28
-func ValidateIdentityName(name string, _ bool) (bool, string) {
29
-	if ok, reason := oapi.MinimalNameRequirements(name, false); !ok {
30
-		return ok, reason
28
+func ValidateIdentityName(name string, _ bool) []string {
29
+	if reasons := oapi.MinimalNameRequirements(name, false); len(reasons) != 0 {
30
+		return reasons
31 31
 	}
32 32
 
33 33
 	parts := strings.Split(name, ":")
34 34
 	if len(parts) != 2 {
35
-		return false, `must be in the format <providerName>:<providerUserName>`
35
+		return []string{`must be in the format <providerName>:<providerUserName>`}
36 36
 	}
37 37
 	if len(parts[0]) == 0 {
38
-		return false, `must be in the format <providerName>:<providerUserName> with a non-empty providerName`
38
+		return []string{`must be in the format <providerName>:<providerUserName> with a non-empty providerName`}
39 39
 	}
40 40
 	if len(parts[1]) == 0 {
41
-		return false, `must be in the format <providerName>:<providerUserName> with a non-empty providerUserName`
41
+		return []string{`must be in the format <providerName>:<providerUserName> with a non-empty providerUserName`}
42 42
 	}
43
-	return true, ""
43
+	return nil
44 44
 }
45 45
 
46
-func ValidateGroupName(name string, _ bool) (bool, string) {
47
-	if ok, reason := oapi.MinimalNameRequirements(name, false); !ok {
48
-		return ok, reason
46
+func ValidateGroupName(name string, _ bool) []string {
47
+	if reasons := oapi.MinimalNameRequirements(name, false); len(reasons) != 0 {
48
+		return reasons
49 49
 	}
50 50
 
51 51
 	if strings.Contains(name, ":") {
52
-		return false, `may not contain ":"`
52
+		return []string{`may not contain ":"`}
53 53
 	}
54 54
 	if name == "~" {
55
-		return false, `may not equal "~"`
55
+		return []string{`may not equal "~"`}
56 56
 	}
57
-	return true, ""
57
+	return nil
58 58
 }
59 59
 
60
-func ValidateIdentityProviderName(name string) (bool, string) {
61
-	if ok, reason := oapi.MinimalNameRequirements(name, false); !ok {
62
-		return ok, reason
60
+func ValidateIdentityProviderName(name string) []string {
61
+	if reasons := oapi.MinimalNameRequirements(name, false); len(reasons) != 0 {
62
+		return reasons
63 63
 	}
64 64
 
65 65
 	if strings.Contains(name, ":") {
66
-		return false, `may not contain ":"`
66
+		return []string{`may not contain ":"`}
67 67
 	}
68
-	return true, ""
68
+	return nil
69 69
 }
70 70
 
71
-func ValidateIdentityProviderUserName(name string) (bool, string) {
71
+func ValidateIdentityProviderUserName(name string) []string {
72 72
 	// Any provider user name must be a valid user name
73 73
 	return ValidateUserName(name, false)
74 74
 }
... ...
@@ -83,8 +83,8 @@ func ValidateGroup(group *api.Group) field.ErrorList {
83 83
 			allErrs = append(allErrs, field.Invalid(idxPath, user, "may not be empty"))
84 84
 			continue
85 85
 		}
86
-		if ok, msg := ValidateUserName(user, false); !ok {
87
-			allErrs = append(allErrs, field.Invalid(idxPath, user, msg))
86
+		if reasons := ValidateUserName(user, false); len(reasons) != 0 {
87
+			allErrs = append(allErrs, field.Invalid(idxPath, user, strings.Join(reasons, ", ")))
88 88
 		}
89 89
 	}
90 90
 
... ...
@@ -102,8 +102,8 @@ func ValidateUser(user *api.User) field.ErrorList {
102 102
 	identitiesPath := field.NewPath("identities")
103 103
 	for index, identity := range user.Identities {
104 104
 		idxPath := identitiesPath.Index(index)
105
-		if ok, msg := ValidateIdentityName(identity, false); !ok {
106
-			allErrs = append(allErrs, field.Invalid(idxPath, identity, msg))
105
+		if reasons := ValidateIdentityName(identity, false); len(reasons) != 0 {
106
+			allErrs = append(allErrs, field.Invalid(idxPath, identity, strings.Join(reasons, ", ")))
107 107
 		}
108 108
 	}
109 109
 
... ...
@@ -114,8 +114,8 @@ func ValidateUser(user *api.User) field.ErrorList {
114 114
 			allErrs = append(allErrs, field.Invalid(idxPath, group, "may not be empty"))
115 115
 			continue
116 116
 		}
117
-		if ok, msg := ValidateGroupName(group, false); !ok {
118
-			allErrs = append(allErrs, field.Invalid(idxPath, group, msg))
117
+		if reasons := ValidateGroupName(group, false); len(reasons) != 0 {
118
+			allErrs = append(allErrs, field.Invalid(idxPath, group, strings.Join(reasons, ", ")))
119 119
 		}
120 120
 	}
121 121
 
... ...
@@ -133,14 +133,14 @@ func ValidateIdentity(identity *api.Identity) field.ErrorList {
133 133
 
134 134
 	if len(identity.ProviderName) == 0 {
135 135
 		allErrs = append(allErrs, field.Required(field.NewPath("providerName"), ""))
136
-	} else if ok, msg := ValidateIdentityProviderName(identity.ProviderName); !ok {
137
-		allErrs = append(allErrs, field.Invalid(field.NewPath("providerName"), identity.ProviderName, msg))
136
+	} else if reasons := ValidateIdentityProviderName(identity.ProviderName); len(reasons) != 0 {
137
+		allErrs = append(allErrs, field.Invalid(field.NewPath("providerName"), identity.ProviderName, strings.Join(reasons, ", ")))
138 138
 	}
139 139
 
140 140
 	if len(identity.ProviderUserName) == 0 {
141 141
 		allErrs = append(allErrs, field.Required(field.NewPath("providerUserName"), ""))
142
-	} else if ok, msg := ValidateIdentityProviderName(identity.ProviderUserName); !ok {
143
-		allErrs = append(allErrs, field.Invalid(field.NewPath("providerUserName"), identity.ProviderUserName, msg))
142
+	} else if reasons := ValidateIdentityProviderName(identity.ProviderUserName); len(reasons) != 0 {
143
+		allErrs = append(allErrs, field.Invalid(field.NewPath("providerUserName"), identity.ProviderUserName, strings.Join(reasons, ", ")))
144 144
 	}
145 145
 
146 146
 	userPath := field.NewPath("user")
... ...
@@ -151,8 +151,8 @@ func ValidateIdentity(identity *api.Identity) field.ErrorList {
151 151
 		}
152 152
 	}
153 153
 
154
-	if ok, msg := ValidateUserName(identity.User.Name, false); !ok {
155
-		allErrs = append(allErrs, field.Invalid(userPath.Child("name"), identity.User.Name, msg))
154
+	if reasons := ValidateUserName(identity.User.Name, false); len(reasons) != 0 {
155
+		allErrs = append(allErrs, field.Invalid(userPath.Child("name"), identity.User.Name, strings.Join(reasons, ", ")))
156 156
 	}
157 157
 	if len(identity.User.Name) == 0 && len(identity.User.UID) != 0 {
158 158
 		allErrs = append(allErrs, field.Invalid(userPath.Child("uid"), identity.User.UID, "may not be set if user.name is empty"))
... ...
@@ -65,7 +65,7 @@ func (s *storage) CreateGroup(ctx kapi.Context, group *api.Group) (*api.Group, e
65 65
 }
66 66
 
67 67
 func (s *storage) UpdateGroup(ctx kapi.Context, group *api.Group) (*api.Group, error) {
68
-	obj, _, err := s.Update(ctx, group)
68
+	obj, _, err := s.Update(ctx, group.Name, rest.DefaultUpdatedObjectInfo(group, kapi.Scheme))
69 69
 	if err != nil {
70 70
 		return nil, err
71 71
 	}
... ...
@@ -32,7 +32,7 @@ type Storage interface {
32 32
 	rest.Getter
33 33
 
34 34
 	Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error)
35
-	Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error)
35
+	Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error)
36 36
 }
37 37
 
38 38
 // storage puts strong typing around storage calls
... ...
@@ -62,16 +62,16 @@ func (s *storage) GetIdentity(ctx kapi.Context, name string) (*api.Identity, err
62 62
 	return obj.(*api.Identity), nil
63 63
 }
64 64
 
65
-func (s *storage) CreateIdentity(ctx kapi.Context, Identity *api.Identity) (*api.Identity, error) {
66
-	obj, err := s.Create(ctx, Identity)
65
+func (s *storage) CreateIdentity(ctx kapi.Context, identity *api.Identity) (*api.Identity, error) {
66
+	obj, err := s.Create(ctx, identity)
67 67
 	if err != nil {
68 68
 		return nil, err
69 69
 	}
70 70
 	return obj.(*api.Identity), nil
71 71
 }
72 72
 
73
-func (s *storage) UpdateIdentity(ctx kapi.Context, Identity *api.Identity) (*api.Identity, error) {
74
-	obj, _, err := s.Update(ctx, Identity)
73
+func (s *storage) UpdateIdentity(ctx kapi.Context, identity *api.Identity) (*api.Identity, error) {
74
+	obj, _, err := s.Update(ctx, identity.Name, rest.DefaultUpdatedObjectInfo(identity, kapi.Scheme))
75 75
 	if err != nil {
76 76
 		return nil, err
77 77
 	}
... ...
@@ -2,6 +2,7 @@ package etcd
2 2
 
3 3
 import (
4 4
 	"errors"
5
+	"strings"
5 6
 
6 7
 	kapi "k8s.io/kubernetes/pkg/api"
7 8
 	kerrs "k8s.io/kubernetes/pkg/api/errors"
... ...
@@ -73,8 +74,8 @@ func (r *REST) Get(ctx kapi.Context, name string) (runtime.Object, error) {
73 73
 		contextGroups := sets.NewString(user.GetGroups()...)
74 74
 		contextGroups.Delete(bootstrappolicy.UnauthenticatedGroup, bootstrappolicy.AuthenticatedGroup)
75 75
 
76
-		if ok, _ := validation.ValidateUserName(name, false); !ok {
77
-			// The user the authentication layer has identified cannot possibly be a persisted user
76
+		if reasons := validation.ValidateUserName(name, false); len(reasons) != 0 {
77
+			// The user the authentication layer has identified cannot be a valid persisted user
78 78
 			// Return an API representation of the virtual user
79 79
 			return &api.User{ObjectMeta: kapi.ObjectMeta{Name: name}, Groups: contextGroups.List()}, nil
80 80
 		}
... ...
@@ -91,8 +92,8 @@ func (r *REST) Get(ctx kapi.Context, name string) (runtime.Object, error) {
91 91
 		return &api.User{ObjectMeta: kapi.ObjectMeta{Name: name}, Groups: contextGroups.List()}, nil
92 92
 	}
93 93
 
94
-	if ok, details := validation.ValidateUserName(name, false); !ok {
95
-		return nil, field.Invalid(field.NewPath("metadata", "name"), name, details)
94
+	if reasons := validation.ValidateUserName(name, false); len(reasons) != 0 {
95
+		return nil, field.Invalid(field.NewPath("metadata", "name"), name, strings.Join(reasons, ", "))
96 96
 	}
97 97
 
98 98
 	return r.Store.Get(ctx, name)
... ...
@@ -27,7 +27,7 @@ type Storage interface {
27 27
 	rest.Getter
28 28
 
29 29
 	Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error)
30
-	Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error)
30
+	Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error)
31 31
 }
32 32
 
33 33
 // storage puts strong typing around storage calls
... ...
@@ -66,7 +66,7 @@ func (s *storage) CreateUser(ctx kapi.Context, user *api.User) (*api.User, error
66 66
 }
67 67
 
68 68
 func (s *storage) UpdateUser(ctx kapi.Context, user *api.User) (*api.User, error) {
69
-	obj, _, err := s.Update(ctx, user)
69
+	obj, _, err := s.Update(ctx, user.Name, rest.DefaultUpdatedObjectInfo(user, kapi.Scheme))
70 70
 	if err != nil {
71 71
 		return nil, err
72 72
 	}
... ...
@@ -27,7 +27,7 @@ type Storage interface {
27 27
 	rest.Deleter
28 28
 
29 29
 	Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error)
30
-	Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error)
30
+	Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error)
31 31
 }
32 32
 
33 33
 // storage puts strong typing around storage calls
... ...
@@ -58,7 +58,7 @@ func (s *storage) CreateUserIdentityMapping(ctx kapi.Context, mapping *api.UserI
58 58
 }
59 59
 
60 60
 func (s *storage) UpdateUserIdentityMapping(ctx kapi.Context, mapping *api.UserIdentityMapping) (*api.UserIdentityMapping, error) {
61
-	obj, _, err := s.Update(ctx, mapping)
61
+	obj, _, err := s.Update(ctx, mapping.Name, rest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
62 62
 	if err != nil {
63 63
 		return nil, err
64 64
 	}
... ...
@@ -55,7 +55,11 @@ func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err
55 55
 // Update associates an identity with a user.
56 56
 // Both the identity and user must already exist.
57 57
 // If the identity is associated with another user already, it is disassociated.
58
-func (s *REST) Update(ctx kapi.Context, obj runtime.Object) (runtime.Object, bool, error) {
58
+func (s *REST) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) {
59
+	obj, err := objInfo.UpdatedObject(ctx, nil)
60
+	if err != nil {
61
+		return nil, false, err
62
+	}
59 63
 	mapping, ok := obj.(*api.UserIdentityMapping)
60 64
 	if !ok {
61 65
 		return nil, false, kerrs.NewBadRequest("invalid type")
... ...
@@ -8,6 +8,7 @@ import (
8 8
 
9 9
 	kapi "k8s.io/kubernetes/pkg/api"
10 10
 	kerrs "k8s.io/kubernetes/pkg/api/errors"
11
+	kapirest "k8s.io/kubernetes/pkg/api/rest"
11 12
 	"k8s.io/kubernetes/pkg/runtime"
12 13
 	"k8s.io/kubernetes/pkg/types"
13 14
 
... ...
@@ -409,7 +410,7 @@ func TestUpdate(t *testing.T) {
409 409
 	}
410 410
 
411 411
 	actions, _, _, rest := setupRegistries(associatedIdentity1User1, associatedUser1, unassociatedUser2)
412
-	createdMapping, created, err := rest.Update(kapi.NewContext(), mapping)
412
+	createdMapping, created, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
413 413
 
414 414
 	if err != nil {
415 415
 		t.Errorf("Unexpected error: %v", err)
... ...
@@ -440,7 +441,7 @@ func TestUpdateMissingIdentity(t *testing.T) {
440 440
 	}
441 441
 
442 442
 	actions, _, _, rest := setupRegistries(nil, associatedUser1, unassociatedUser2)
443
-	_, _, err := rest.Update(kapi.NewContext(), mapping)
443
+	_, _, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
444 444
 
445 445
 	if err == nil {
446 446
 		t.Errorf("Expected error: %v", err)
... ...
@@ -473,7 +474,7 @@ func TestUpdateMissingUser(t *testing.T) {
473 473
 	}
474 474
 
475 475
 	actions, _, _, rest := setupRegistries(associatedIdentity1User1, associatedUser1)
476
-	_, _, err := rest.Update(kapi.NewContext(), mapping)
476
+	_, _, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
477 477
 
478 478
 	if err == nil {
479 479
 		t.Errorf("Expected error: %v", err)
... ...
@@ -500,7 +501,7 @@ func TestUpdateOldUserMatches(t *testing.T) {
500 500
 	}
501 501
 
502 502
 	actions, _, _, rest := setupRegistries(identity, user)
503
-	createdMapping, created, err := rest.Update(kapi.NewContext(), mapping)
503
+	createdMapping, created, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
504 504
 
505 505
 	if err != nil {
506 506
 		t.Errorf("Unexpected error: %v", err)
... ...
@@ -531,7 +532,7 @@ func TestUpdateWithEmptyResourceVersion(t *testing.T) {
531 531
 	}
532 532
 
533 533
 	actions, _, _, rest := setupRegistries(associatedIdentity1User1, associatedUser1, unassociatedUser2)
534
-	_, _, err := rest.Update(kapi.NewContext(), mapping)
534
+	_, _, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
535 535
 
536 536
 	if err == nil {
537 537
 		t.Errorf("Expected error")
... ...
@@ -562,7 +563,7 @@ func TestUpdateWithMismatchedResourceVersion(t *testing.T) {
562 562
 	}
563 563
 
564 564
 	actions, _, _, rest := setupRegistries(associatedIdentity1User1, associatedUser1, unassociatedUser2)
565
-	_, _, err := rest.Update(kapi.NewContext(), mapping)
565
+	_, _, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
566 566
 
567 567
 	if err == nil {
568 568
 		t.Errorf("Expected error")
... ...
@@ -604,7 +605,7 @@ func TestUpdateOldUserUpdateError(t *testing.T) {
604 604
 
605 605
 	actions, userRegistry, _, rest := setupRegistries(associatedIdentity1User1, associatedUser1, unassociatedUser2)
606 606
 	userRegistry.UpdateErr[unassociatedUser1.Name] = expectedErr
607
-	createdMapping, created, err := rest.Update(kapi.NewContext(), mapping)
607
+	createdMapping, created, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
608 608
 
609 609
 	// An error cleaning up the old user shouldn't manifest as an update failure, since the mapping was successfully updated
610 610
 	if err != nil {
... ...
@@ -644,7 +645,7 @@ func TestUpdateUserUpdateError(t *testing.T) {
644 644
 
645 645
 	actions, userRegistry, _, rest := setupRegistries(associatedIdentity1User1, associatedUser1, unassociatedUser2)
646 646
 	userRegistry.UpdateErr[associatedUser2.Name] = expectedErr
647
-	_, _, err := rest.Update(kapi.NewContext(), mapping)
647
+	_, _, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
648 648
 
649 649
 	if err == nil {
650 650
 		t.Errorf("Expected error")
... ...
@@ -684,7 +685,7 @@ func TestUpdateIdentityUpdateError(t *testing.T) {
684 684
 
685 685
 	actions, _, identityRegistry, rest := setupRegistries(associatedIdentity1User1, associatedUser1, unassociatedUser2)
686 686
 	identityRegistry.UpdateErr = expectedErr
687
-	_, _, err := rest.Update(kapi.NewContext(), mapping)
687
+	_, _, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme))
688 688
 
689 689
 	if err == nil {
690 690
 		t.Errorf("Expected error")
... ...
@@ -342,14 +342,14 @@ func Equals(labels1, labels2 map[string]string) bool {
342 342
 const qualifiedNameErrorMsg string = "must match regex [" + kvalidation.DNS1123SubdomainFmt + " / ] " + kvalidation.DNS1123LabelFmt
343 343
 
344 344
 func validateLabelKey(k string) error {
345
-	if !kvalidation.IsQualifiedName(k) {
345
+	if len(kvalidation.IsQualifiedName(k)) != 0 {
346 346
 		return field.Invalid(field.NewPath("label key"), k, qualifiedNameErrorMsg)
347 347
 	}
348 348
 	return nil
349 349
 }
350 350
 
351 351
 func validateLabelValue(v string) error {
352
-	if !kvalidation.IsValidLabelValue(v) {
352
+	if len(kvalidation.IsValidLabelValue(v)) != 0 {
353 353
 		return field.Invalid(field.NewPath("label value"), v, qualifiedNameErrorMsg)
354 354
 	}
355 355
 	return nil
... ...
@@ -39,14 +39,16 @@ func NewRateLimitedFunction(keyFunc kcache.KeyFunc, interval int, handlerFunc Ha
39 39
 // RunUntil begins processes the resources from queue asynchronously until
40 40
 // stopCh is closed.
41 41
 func (rlf *RateLimitedFunction) RunUntil(stopCh <-chan struct{}) {
42
-	go utilwait.Until(func() { rlf.handleOne(rlf.queue.Pop()) }, 0, stopCh)
42
+	go utilwait.Until(rlf.pop, 0, stopCh)
43 43
 }
44 44
 
45 45
 // handleOne processes a request in the queue invoking the rate limited
46 46
 // function.
47
-func (rlf *RateLimitedFunction) handleOne(resource interface{}) {
47
+func (rlf *RateLimitedFunction) pop() {
48 48
 	rlf.RateLimiter.Accept()
49
-	if err := rlf.Handler(); err != nil {
49
+	if _, err := rlf.queue.Pop(func(_ interface{}) error {
50
+		return rlf.Handler()
51
+	}); err != nil {
50 52
 		utilruntime.HandleError(err)
51 53
 	}
52 54
 }
... ...
@@ -10,7 +10,7 @@ import (
10 10
 	kapi "k8s.io/kubernetes/pkg/api"
11 11
 	"k8s.io/kubernetes/pkg/api/rest"
12 12
 	"k8s.io/kubernetes/pkg/api/unversioned"
13
-	"k8s.io/kubernetes/pkg/genericapiserver"
13
+	genericserveroptions "k8s.io/kubernetes/pkg/genericapiserver/options"
14 14
 	genericrest "k8s.io/kubernetes/pkg/registry/generic"
15 15
 	"k8s.io/kubernetes/pkg/registry/generic/registry"
16 16
 	"k8s.io/kubernetes/pkg/runtime"
... ...
@@ -108,7 +108,7 @@ func (g *configRESTOptionsGetter) GetRESTOptions(resource unversioned.GroupResou
108 108
 		// TODO: choose destination group/version based on input group/resource
109 109
 		// TODO: Tune the cache size
110 110
 		groupVersion := unversioned.GroupVersion{Group: "", Version: g.masterOptions.EtcdStorageConfig.OpenShiftStorageVersion}
111
-		g.etcdHelper = etcdstorage.NewEtcdStorage(etcdClient, kapi.Codecs.LegacyCodec(groupVersion), g.masterOptions.EtcdStorageConfig.OpenShiftStoragePrefix, false, genericapiserver.DefaultDeserializationCacheSize)
111
+		g.etcdHelper = etcdstorage.NewEtcdStorage(etcdClient, kapi.Codecs.LegacyCodec(groupVersion), g.masterOptions.EtcdStorageConfig.OpenShiftStoragePrefix, false, genericserveroptions.DefaultDeserializationCacheSize)
112 112
 	}
113 113
 
114 114
 	configuredCacheSize, specified := g.cacheSizes[resource]
... ...
@@ -3,7 +3,6 @@ package emptydir
3 3
 import (
4 4
 	"k8s.io/kubernetes/pkg/api"
5 5
 	"k8s.io/kubernetes/pkg/api/resource"
6
-	"k8s.io/kubernetes/pkg/types"
7 6
 	"k8s.io/kubernetes/pkg/volume"
8 7
 )
9 8
 
... ...
@@ -12,8 +11,9 @@ var _ volume.Mounter = &emptyDirQuotaMounter{}
12 12
 
13 13
 // EmptyDirQuotaPlugin is a simple wrapper for the k8s empty dir plugin mounter.
14 14
 type EmptyDirQuotaPlugin struct {
15
-	// wrapped is the actual k8s emptyDir volume plugin we will pass method calls to.
16
-	Wrapped volume.VolumePlugin
15
+	// the actual k8s emptyDir volume plugin we will pass method calls to.
16
+	// TODO: do we need to implement unmount
17
+	volume.VolumePlugin
17 18
 
18 19
 	// The default quota to apply to each node:
19 20
 	Quota resource.Quantity
... ...
@@ -24,7 +24,7 @@ type EmptyDirQuotaPlugin struct {
24 24
 }
25 25
 
26 26
 func (plugin *EmptyDirQuotaPlugin) NewMounter(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Mounter, error) {
27
-	volMounter, err := plugin.Wrapped.NewMounter(spec, pod, opts)
27
+	volMounter, err := plugin.VolumePlugin.NewMounter(spec, pod, opts)
28 28
 	if err != nil {
29 29
 		return volMounter, err
30 30
 	}
... ...
@@ -49,22 +49,6 @@ func (plugin *EmptyDirQuotaPlugin) NewMounter(spec *volume.Spec, pod *api.Pod, o
49 49
 	return wrapperEmptyDir, err
50 50
 }
51 51
 
52
-func (plugin *EmptyDirQuotaPlugin) Init(host volume.VolumeHost) error {
53
-	return plugin.Wrapped.Init(host)
54
-}
55
-
56
-func (plugin *EmptyDirQuotaPlugin) Name() string {
57
-	return plugin.Wrapped.Name()
58
-}
59
-
60
-func (plugin *EmptyDirQuotaPlugin) CanSupport(spec *volume.Spec) bool {
61
-	return plugin.Wrapped.CanSupport(spec)
62
-}
63
-
64
-func (plugin *EmptyDirQuotaPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
65
-	return plugin.Wrapped.NewUnmounter(volName, podUID)
66
-}
67
-
68 52
 // emptyDirQuotaMounter is a wrapper plugin mounter for the k8s empty dir mounter itself.
69 53
 // This plugin just extends and adds the functionality to apply a
70 54
 // quota for the pods FSGroup on an XFS filesystem.
... ...
@@ -45,8 +45,8 @@ os::cmd::expect_success_and_text 'oc types' 'Deployment Config'
45 45
 os::cmd::expect_success_and_text 'openshift kubectl' 'Kubernetes cluster'
46 46
 os::cmd::expect_success_and_text 'oadm' 'Administrative Commands'
47 47
 os::cmd::expect_success_and_text 'openshift admin' 'Administrative Commands'
48
-os::cmd::expect_success_and_text 'oadm' 'Basic Commands:'
49
-os::cmd::expect_success_and_text 'oadm' 'Install Commands:'
48
+os::cmd::expect_success_and_text 'oadm' 'Component Installation:'
49
+os::cmd::expect_success_and_text 'oadm' 'Security and Policy:'
50 50
 os::cmd::expect_success_and_text 'oadm ca' 'Manage certificates'
51 51
 os::cmd::expect_success_and_text 'openshift start kubernetes' 'Kubernetes server components'
52 52
 os::cmd::expect_success_and_text 'oc exec --help' '\[options\] POD \[\-c CONTAINER\] \-\- COMMAND \[args\.\.\.\]$'
... ...
@@ -61,10 +61,7 @@ var _ = Describe("[networking] network isolation", func() {
61 61
 })
62 62
 
63 63
 func checkPodIsolation(f1, f2 *e2e.Framework, numNodes int) error {
64
-	nodes, err := e2e.GetReadyNodes(f1)
65
-	if err != nil {
66
-		e2e.Failf("Failed to list nodes: %v", err)
67
-	}
64
+	nodes := e2e.GetReadySchedulableNodesOrDie(f1.Client)
68 65
 	var serverNode, clientNode *api.Node
69 66
 	serverNode = &nodes.Items[0]
70 67
 	if numNodes == 2 {
... ...
@@ -68,10 +68,7 @@ var _ = Describe("[networking] services", func() {
68 68
 })
69 69
 
70 70
 func checkServiceConnectivity(serverFramework, clientFramework *e2e.Framework, numNodes int) error {
71
-	nodes, err := e2e.GetReadyNodes(serverFramework)
72
-	if err != nil {
73
-		e2e.Failf("Failed to list nodes: %v", err)
74
-	}
71
+	nodes := e2e.GetReadySchedulableNodesOrDie(serverFramework.Client)
75 72
 	var serverNode, clientNode *api.Node
76 73
 	serverNode = &nodes.Items[0]
77 74
 	if numNodes == 2 {
... ...
@@ -81,7 +81,7 @@ func InitTest() {
81 81
 	TestContext.CreateTestingNS = createTestingNS
82 82
 
83 83
 	// Override the default Kubernetes E2E configuration
84
-	e2e.SetTestContext(TestContext)
84
+	e2e.TestContext = TestContext
85 85
 }
86 86
 
87 87
 func ExecuteTest(t *testing.T, suite string) {
... ...
@@ -11,6 +11,7 @@ import (
11 11
 
12 12
 	kapi "k8s.io/kubernetes/pkg/api"
13 13
 	"k8s.io/kubernetes/pkg/api/errors"
14
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
14 15
 	"k8s.io/kubernetes/pkg/apis/batch"
15 16
 	expapi "k8s.io/kubernetes/pkg/apis/extensions"
16 17
 	"k8s.io/kubernetes/pkg/util/wait"
... ...
@@ -53,15 +54,16 @@ func TestExtensionsAPIDeletion(t *testing.T) {
53 53
 	}
54 54
 
55 55
 	// create the extensions resources as the project admin
56
-	hpa := expapi.HorizontalPodAutoscaler{
56
+	percent := int32(10)
57
+	hpa := autoscaling.HorizontalPodAutoscaler{
57 58
 		ObjectMeta: kapi.ObjectMeta{Name: "test-hpa"},
58
-		Spec: expapi.HorizontalPodAutoscalerSpec{
59
-			ScaleRef:       expapi.SubresourceReference{Kind: "DeploymentConfig", Name: "frontend", APIVersion: "v1", Subresource: "scale"},
60
-			MaxReplicas:    10,
61
-			CPUUtilization: &expapi.CPUTargetUtilization{TargetPercentage: 10},
59
+		Spec: autoscaling.HorizontalPodAutoscalerSpec{
60
+			ScaleTargetRef:                 autoscaling.CrossVersionObjectReference{Kind: "DeploymentConfig", Name: "frontend", APIVersion: "v1"},
61
+			MaxReplicas:                    10,
62
+			TargetCPUUtilizationPercentage: &percent,
62 63
 		},
63 64
 	}
64
-	if _, err := projectAdminKubeClient.Extensions().HorizontalPodAutoscalers(projName).Create(&hpa); err != nil {
65
+	if _, err := projectAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(projName).Create(&hpa); err != nil {
65 66
 		t.Fatalf("unexpected error creating the HPA object: %v", err)
66 67
 	}
67 68
 
... ...
@@ -95,7 +97,7 @@ func TestExtensionsAPIDeletion(t *testing.T) {
95 95
 		t.Fatalf("unexpected error while waiting for project to delete: %v", err)
96 96
 	}
97 97
 
98
-	if _, err := clusterAdminKubeClient.Extensions().HorizontalPodAutoscalers(projName).Get(hpa.Name); err == nil {
98
+	if _, err := clusterAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(projName).Get(hpa.Name); err == nil {
99 99
 		t.Fatalf("HPA object was still present after project was deleted!")
100 100
 	} else if !errors.IsNotFound(err) {
101 101
 		t.Fatalf("Error trying to get deleted HPA object (not a not-found error): %v", err)
... ...
@@ -10,6 +10,7 @@ import (
10 10
 
11 11
 	kapi "k8s.io/kubernetes/pkg/api"
12 12
 	"k8s.io/kubernetes/pkg/api/errors"
13
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
13 14
 	"k8s.io/kubernetes/pkg/apis/batch"
14 15
 	expapi "k8s.io/kubernetes/pkg/apis/extensions"
15 16
 )
... ...
@@ -59,11 +60,11 @@ func TestExtensionsAPIDisabledAutoscaleBatchEnabled(t *testing.T) {
59 59
 		t.Fatalf("unexpected error waiting for policy update: %v", err)
60 60
 	}
61 61
 
62
-	validHPA := &expapi.HorizontalPodAutoscaler{
62
+	validHPA := &autoscaling.HorizontalPodAutoscaler{
63 63
 		ObjectMeta: kapi.ObjectMeta{Name: "myjob"},
64
-		Spec: expapi.HorizontalPodAutoscalerSpec{
65
-			ScaleRef:    expapi.SubresourceReference{Name: "foo", Kind: "ReplicationController", Subresource: "scale"},
66
-			MaxReplicas: 1,
64
+		Spec: autoscaling.HorizontalPodAutoscalerSpec{
65
+			ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "foo", Kind: "ReplicationController"},
66
+			MaxReplicas:    1,
67 67
 		},
68 68
 	}
69 69
 	validJob := &batch.Job{
... ...
@@ -78,11 +79,17 @@ func TestExtensionsAPIDisabledAutoscaleBatchEnabled(t *testing.T) {
78 78
 		},
79 79
 	}
80 80
 
81
+	legacyAutoscalers := legacyExtensionsAutoscaling{
82
+		projectAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(projName),
83
+		projectAdminKubeClient.ExtensionsClient.RESTClient,
84
+		projName,
85
+	}
86
+
81 87
 	// make sure extensions API objects cannot be listed or created
82
-	if _, err := projectAdminKubeClient.Extensions().HorizontalPodAutoscalers(projName).List(kapi.ListOptions{}); !errors.IsNotFound(err) {
88
+	if _, err := legacyAutoscalers.List(kapi.ListOptions{}); !errors.IsNotFound(err) {
83 89
 		t.Fatalf("expected NotFound error listing HPA, got %v", err)
84 90
 	}
85
-	if _, err := projectAdminKubeClient.Extensions().HorizontalPodAutoscalers(projName).Create(validHPA); !errors.IsNotFound(err) {
91
+	if _, err := legacyAutoscalers.Create(validHPA); !errors.IsNotFound(err) {
86 92
 		t.Fatalf("expected NotFound error creating HPA, got %v", err)
87 93
 	}
88 94
 	if _, err := projectAdminKubeClient.Extensions().Jobs(projName).List(kapi.ListOptions{}); !errors.IsNotFound(err) {
... ...
@@ -180,11 +187,17 @@ func TestExtensionsAPIDisabled(t *testing.T) {
180 180
 		t.Fatalf("unexpected error waiting for policy update: %v", err)
181 181
 	}
182 182
 
183
+	legacyAutoscalers := legacyExtensionsAutoscaling{
184
+		projectAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(projName),
185
+		projectAdminKubeClient.AutoscalingClient.RESTClient,
186
+		projName,
187
+	}
188
+
183 189
 	// make sure extensions API objects cannot be listed or created
184
-	if _, err := projectAdminKubeClient.Extensions().HorizontalPodAutoscalers(projName).List(kapi.ListOptions{}); !errors.IsNotFound(err) {
190
+	if _, err := legacyAutoscalers.List(kapi.ListOptions{}); !errors.IsNotFound(err) {
185 191
 		t.Fatalf("expected NotFound error listing HPA, got %v", err)
186 192
 	}
187
-	if _, err := projectAdminKubeClient.Extensions().HorizontalPodAutoscalers(projName).Create(&expapi.HorizontalPodAutoscaler{}); !errors.IsNotFound(err) {
193
+	if _, err := legacyAutoscalers.Create(&autoscaling.HorizontalPodAutoscaler{}); !errors.IsNotFound(err) {
188 194
 		t.Fatalf("expected NotFound error creating HPA, got %v", err)
189 195
 	}
190 196
 	if _, err := projectAdminKubeClient.Extensions().Jobs(projName).List(kapi.ListOptions{}); !errors.IsNotFound(err) {
... ...
@@ -14,9 +14,11 @@ import (
14 14
 
15 15
 	kapi "k8s.io/kubernetes/pkg/api"
16 16
 	"k8s.io/kubernetes/pkg/api/unversioned"
17
+	"k8s.io/kubernetes/pkg/apis/autoscaling"
17 18
 	"k8s.io/kubernetes/pkg/apis/batch"
18 19
 	"k8s.io/kubernetes/pkg/apis/extensions"
19 20
 	extensions_v1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
21
+	"k8s.io/kubernetes/pkg/client/restclient"
20 22
 	kclient "k8s.io/kubernetes/pkg/client/unversioned"
21 23
 	"k8s.io/kubernetes/pkg/runtime"
22 24
 )
... ...
@@ -38,6 +40,29 @@ func TestStorageVersionsUnified(t *testing.T) {
38 38
 	)
39 39
 }
40 40
 
41
+type legacyExtensionsAutoscaling struct {
42
+	kclient.HorizontalPodAutoscalerInterface
43
+	client    *restclient.RESTClient
44
+	namespace string
45
+}
46
+
47
+// List takes label and field selectors, and returns the list of horizontalPodAutoscalers that match those selectors.
48
+func (c legacyExtensionsAutoscaling) List(opts kapi.ListOptions) (result *autoscaling.HorizontalPodAutoscalerList, err error) {
49
+	result = &autoscaling.HorizontalPodAutoscalerList{}
50
+	err = c.client.Get().Namespace(c.namespace).Resource("horizontalPodAutoscalers").VersionedParams(&opts, kapi.ParameterCodec).Do().Into(result)
51
+	return
52
+}
53
+
54
+func (c legacyExtensionsAutoscaling) Create(hpa *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) {
55
+	var result autoscaling.HorizontalPodAutoscaler
56
+	return &result, c.client.Post().Resource("horizontalpodautoscalers").Namespace(c.namespace).Body(hpa).Do().Into(&result)
57
+}
58
+
59
+func (c legacyExtensionsAutoscaling) Get(name string) (*autoscaling.HorizontalPodAutoscaler, error) {
60
+	var result autoscaling.HorizontalPodAutoscaler
61
+	return &result, c.client.Get().Resource("horizontalpodautoscalers").Namespace(c.namespace).Name(name).Do().Into(&result)
62
+}
63
+
41 64
 func runStorageTest(t *testing.T, ns string, autoscalingVersion, batchVersion, extensionsVersion unversioned.GroupVersion) {
42 65
 	etcdServer := testutil.RequireEtcd(t)
43 66
 
... ...
@@ -126,18 +151,25 @@ func runStorageTest(t *testing.T, ns string, autoscalingVersion, batchVersion, e
126 126
 		}
127 127
 	}
128 128
 
129
+	legacyClient := legacyExtensionsAutoscaling{
130
+		projectAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(ns),
131
+		projectAdminKubeClient.AutoscalingClient.RESTClient,
132
+		ns,
133
+	}
129 134
 	hpaTestcases := map[string]struct {
130 135
 		creator kclient.HorizontalPodAutoscalerInterface
131 136
 	}{
132 137
 		"autoscaling": {creator: projectAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(ns)},
133
-		"extensions":  {creator: projectAdminKubeClient.Extensions().HorizontalPodAutoscalers(ns)},
138
+		"extensions": {
139
+			creator: legacyClient,
140
+		},
134 141
 	}
135 142
 	for name, testcase := range hpaTestcases {
136
-		hpa := extensions.HorizontalPodAutoscaler{
143
+		hpa := autoscaling.HorizontalPodAutoscaler{
137 144
 			ObjectMeta: kapi.ObjectMeta{Name: name + "-hpa"},
138
-			Spec: extensions.HorizontalPodAutoscalerSpec{
139
-				MaxReplicas: 1,
140
-				ScaleRef:    extensions.SubresourceReference{Kind: "ReplicationController", Name: "myrc", Subresource: "scale"},
145
+			Spec: autoscaling.HorizontalPodAutoscalerSpec{
146
+				MaxReplicas:    1,
147
+				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: "myrc"},
141 148
 			},
142 149
 		}
143 150
 
... ...
@@ -153,12 +185,12 @@ func runStorageTest(t *testing.T, ns string, autoscalingVersion, batchVersion, e
153 153
 			t.Fatalf("%s: expected api version %s in etcd, got %s reading HPA", name, autoscalingVersion, gvk)
154 154
 		}
155 155
 
156
-		// Make sure it is available from both APIs
156
+		// Make sure it is available from the api
157 157
 		if _, err := projectAdminKubeClient.Autoscaling().HorizontalPodAutoscalers(ns).Get(hpa.Name); err != nil {
158 158
 			t.Errorf("%s: Error reading HPA.autoscaling from the autoscaling/v1 API: %#v", name, err)
159 159
 		}
160
-		if _, err := projectAdminKubeClient.Extensions().HorizontalPodAutoscalers(ns).Get(hpa.Name); err != nil {
161
-			t.Errorf("%s: Error reading HPA.extensions from the extensions/v1beta1 API: %#v", name, err)
160
+		if _, err := legacyClient.Get(hpa.Name); err != nil {
161
+			t.Errorf("%s: Error reading HPA.autoscaling from the extensions/v1beta1 API: %#v", name, err)
162 162
 		}
163 163
 	}
164 164
 }
... ...
@@ -49,8 +49,6 @@ func main() {
49 49
 		"k8s.io/kubernetes/pkg/apis/componentconfig/v1alpha1",
50 50
 		"k8s.io/kubernetes/pkg/apis/extensions",
51 51
 		"k8s.io/kubernetes/pkg/apis/extensions/v1beta1",
52
-		"k8s.io/kubernetes/pkg/apis/metrics",
53
-		"k8s.io/kubernetes/pkg/apis/metrics/v1alpha1",
54 52
 		"github.com/openshift/origin/pkg/authorization/api/v1",
55 53
 		"github.com/openshift/origin/pkg/authorization/api",
56 54
 		"github.com/openshift/origin/pkg/build/api/v1",