diff --git a/hack/test-cmd.sh b/hack/test-cmd.sh index b9c7bcd31ee..89dbdb9768f 100755 --- a/hack/test-cmd.sh +++ b/hack/test-cmd.sh @@ -943,6 +943,7 @@ __EOF__ kubectl scale --replicas=2 -f examples/guestbook/frontend-controller.yaml "${kube_flags[@]}" # Post-condition: 2 replicas kube::test::get_object_assert 'rc frontend' "{{$rc_replicas_field}}" '2' + kubectl delete rc frontend "${kube_flags[@]}" ### Scale multiple replication controllers kubectl create -f examples/guestbook/redis-master-controller.yaml "${kube_flags[@]}" @@ -963,16 +964,16 @@ __EOF__ kube::test::get_object_assert 'job pi' "{{$job_parallelism_field}}" '2' # Clean-up kubectl delete job/pi "${kube_flags[@]}" - ### Scale a deployment - kubectl create -f examples/extensions/deployment.yaml "${kube_flags[@]}" - # Command - kubectl scale --current-replicas=3 --replicas=1 deployment/nginx-deployment - # Post-condition: 1 replica for nginx-deployment - kube::test::get_object_assert 'deployment nginx-deployment' "{{$deployment_replicas}}" '1' - # Clean-up - kubectl delete deployment/nginx-deployment "${kube_flags[@]}" - # TODO: Remove once deployment reaping is implemented - kubectl delete rc --all "${kube_flags[@]}" + # ### Scale a deployment + # kubectl create -f examples/extensions/deployment.yaml "${kube_flags[@]}" + # # Command + # kubectl scale --current-replicas=3 --replicas=1 deployment/nginx-deployment + # # Post-condition: 1 replica for nginx-deployment + # kube::test::get_object_assert 'deployment nginx-deployment' "{{$deployment_replicas}}" '1' + # # Clean-up + # kubectl delete deployment/nginx-deployment "${kube_flags[@]}" + # # TODO: Remove once deployment reaping is implemented + # kubectl delete rs --all "${kube_flags[@]}" ### Expose a deployment as a service kubectl create -f examples/extensions/deployment.yaml "${kube_flags[@]}" @@ -985,7 +986,7 @@ __EOF__ # Clean-up kubectl delete deployment/nginx-deployment service/nginx-deployment "${kube_flags[@]}" # TODO: Remove once deployment reaping is implemented - kubectl delete rc --all "${kube_flags[@]}" + kubectl delete rs --all "${kube_flags[@]}" ### Expose replication controller as service kubectl create -f examples/guestbook/frontend-controller.yaml "${kube_flags[@]}" @@ -1102,7 +1103,7 @@ __EOF__ # Clean up kubectl delete hpa nginx-deployment "${kube_flags[@]}" kubectl delete deployment nginx-deployment "${kube_flags[@]}" - kubectl delete rc -l pod-template-hash "${kube_flags[@]}" + kubectl delete rs -l pod-template-hash "${kube_flags[@]}" ### Rollback a deployment # Pre-condition: no deployment exists @@ -1131,7 +1132,7 @@ __EOF__ kube::test::get_object_assert deployment "{{range.items}}{{$deployment_image_field}}:{{end}}" 'nginx:latest:' # Clean up kubectl delete deployment nginx-deployment "${kube_flags[@]}" - kubectl delete rc -l pod-template-hash "${kube_flags[@]}" + kubectl delete rs -l pod-template-hash "${kube_flags[@]}" ###################### # ConfigMap # diff --git a/hack/testdata/deployment-revision2.yaml b/hack/testdata/deployment-revision2.yaml index 833f79e4f88..e723526b106 100644 --- a/hack/testdata/deployment-revision2.yaml +++ b/hack/testdata/deployment-revision2.yaml @@ -7,7 +7,8 @@ metadata: spec: replicas: 3 selector: - name: nginx + matchLabels: + name: nginx template: metadata: labels: diff --git a/pkg/apis/extensions/helpers.go b/pkg/apis/extensions/helpers.go index 19068de660e..8196a921c5d 100644 --- a/pkg/apis/extensions/helpers.go +++ b/pkg/apis/extensions/helpers.go @@ -16,29 +16,32 @@ limitations under the License. package extensions -import ( - "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/unversioned" -) +// TODO(madhusudancs): Fix this when Scale group issues are resolved. +// import ( +// "fmt" -// ScaleFromDeployment returns a scale subresource for a deployment. -func ScaleFromDeployment(deployment *Deployment) (*Scale, error) { - selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) - if err != nil { - return nil, fmt.Errorf("failed to convert label selector to selector: %v", err) - } - return &Scale{ - ObjectMeta: api.ObjectMeta{ - Name: deployment.Name, - Namespace: deployment.Namespace, - CreationTimestamp: deployment.CreationTimestamp, - }, - Spec: ScaleSpec{ - Replicas: deployment.Spec.Replicas, - }, - Status: ScaleStatus{ - Replicas: deployment.Status.Replicas, - Selector: selector.String(), - }, - }, nil -} +// "k8s.io/kubernetes/pkg/api" +// "k8s.io/kubernetes/pkg/api/unversioned" +// ) + +// // ScaleFromDeployment returns a scale subresource for a deployment. +// func ScaleFromDeployment(deployment *Deployment) (*Scale, error) { +// selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) +// if err != nil { +// return nil, fmt.Errorf("failed to convert label selector to selector: %v", err) +// } +// return &Scale{ +// ObjectMeta: api.ObjectMeta{ +// Name: deployment.Name, +// Namespace: deployment.Namespace, +// CreationTimestamp: deployment.CreationTimestamp, +// }, +// Spec: ScaleSpec{ +// Replicas: deployment.Spec.Replicas, +// }, +// Status: ScaleStatus{ +// Replicas: deployment.Status.Replicas, +// Selector: selector.String(), +// }, +// }, nil +// } diff --git a/pkg/apis/extensions/types.go b/pkg/apis/extensions/types.go index 9f000d943bf..c70baf82971 100644 --- a/pkg/apis/extensions/types.go +++ b/pkg/apis/extensions/types.go @@ -235,7 +235,7 @@ type DeploymentSpec struct { // Label selector for pods. Existing ReplicaSets whose pods are // selected by this will be the ones affected by this deployment. - Selector *LabelSelector `json:"selector,omitempty"` + Selector *unversioned.LabelSelector `json:"selector,omitempty"` // Template describes the pods that will be created. Template api.PodTemplateSpec `json:"template"` diff --git a/pkg/apis/extensions/v1beta1/conversion.go b/pkg/apis/extensions/v1beta1/conversion.go index def484fb2b8..68eaba419e1 100644 --- a/pkg/apis/extensions/v1beta1/conversion.go +++ b/pkg/apis/extensions/v1beta1/conversion.go @@ -105,7 +105,7 @@ func Convert_extensions_DeploymentSpec_To_v1beta1_DeploymentSpec(in *extensions. *out.Replicas = int32(in.Replicas) if in.Selector != nil { out.Selector = new(LabelSelector) - if err := Convert_extensions_LabelSelector_To_v1beta1_LabelSelector(in.Selector, out.Selector, s); err != nil { + if err := Convert_unversioned_LabelSelector_To_v1beta1_LabelSelector(in.Selector, out.Selector, s); err != nil { return err } } else { @@ -141,8 +141,8 @@ func Convert_v1beta1_DeploymentSpec_To_extensions_DeploymentSpec(in *DeploymentS } if in.Selector != nil { - out.Selector = new(extensions.LabelSelector) - if err := Convert_v1beta1_LabelSelector_To_extensions_LabelSelector(in.Selector, out.Selector, s); err != nil { + out.Selector = new(unversioned.LabelSelector) + if err := Convert_v1beta1_LabelSelector_To_unversioned_LabelSelector(in.Selector, out.Selector, s); err != nil { return err } } else { diff --git a/pkg/apis/extensions/validation/validation.go b/pkg/apis/extensions/validation/validation.go index bc67ecbbb1a..2a72bdeeed7 100644 --- a/pkg/apis/extensions/validation/validation.go +++ b/pkg/apis/extensions/validation/validation.go @@ -351,13 +351,13 @@ func ValidateDeploymentSpec(spec *extensions.DeploymentSpec, fldPath *field.Path if spec.Selector == nil { allErrs = append(allErrs, field.Required(fldPath.Child("selector"), "")) } else { - allErrs = append(allErrs, ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) + allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) if len(spec.Selector.MatchLabels)+len(spec.Selector.MatchExpressions) == 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "empty selector is not valid for deployment.")) } } - selector, err := extensions.LabelSelectorAsSelector(spec.Selector) + selector, err := unversioned.LabelSelectorAsSelector(spec.Selector) if err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "failed to convert LabelSelector to Selector.")) } else { diff --git a/pkg/apis/extensions/validation/validation_test.go b/pkg/apis/extensions/validation/validation_test.go index 0b687513693..fbe751ab063 100644 --- a/pkg/apis/extensions/validation/validation_test.go +++ b/pkg/apis/extensions/validation/validation_test.go @@ -952,7 +952,7 @@ func validDeployment() *extensions.Deployment { Namespace: api.NamespaceDefault, }, Spec: extensions.DeploymentSpec{ - Selector: &extensions.LabelSelector{ + Selector: &unversioned.LabelSelector{ MatchLabels: map[string]string{ "name": "abc", }, @@ -1002,7 +1002,7 @@ func TestValidateDeployment(t *testing.T) { } // selector should match the labels in pod template. invalidSelectorDeployment := validDeployment() - invalidSelectorDeployment.Spec.Selector = &extensions.LabelSelector{ + invalidSelectorDeployment.Spec.Selector = &unversioned.LabelSelector{ MatchLabels: map[string]string{ "name": "def", }, diff --git a/pkg/client/cache/listers.go b/pkg/client/cache/listers.go index 42e0ecf4235..77982b318b6 100644 --- a/pkg/client/cache/listers.go +++ b/pkg/client/cache/listers.go @@ -252,7 +252,7 @@ func (s *StoreToDeploymentLister) GetDeploymentsForReplicaSet(rs *extensions.Rep continue } - selector, err := extensions.LabelSelectorAsSelector(rs.Spec.Selector) + selector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector) if err != nil { return nil, fmt.Errorf("failed to convert LabelSelector to Selector: %v", err) } @@ -291,6 +291,27 @@ func (s *StoreToReplicaSetLister) List() (rss []extensions.ReplicaSet, err error return rss, nil } +type storeReplicaSetsNamespacer struct { + store Store + namespace string +} + +func (s storeReplicaSetsNamespacer) List(selector labels.Selector) (rss []extensions.ReplicaSet, err error) { + for _, c := range s.store.List() { + rs := *(c.(*extensions.ReplicaSet)) + if s.namespace == api.NamespaceAll || s.namespace == rs.Namespace { + if selector.Matches(labels.Set(rs.Labels)) { + rss = append(rss, rs) + } + } + } + return +} + +func (s *StoreToReplicaSetLister) ReplicaSets(namespace string) storeReplicaSetsNamespacer { + return storeReplicaSetsNamespacer{s.Store, namespace} +} + // GetPodReplicaSets returns a list of ReplicaSets managing a pod. Returns an error only if no matching ReplicaSets are found. func (s *StoreToReplicaSetLister) GetPodReplicaSets(pod *api.Pod) (rss []extensions.ReplicaSet, err error) { var selector labels.Selector diff --git a/pkg/controller/controller_utils.go b/pkg/controller/controller_utils.go index 74ead4cf8af..a4206d8bd35 100644 --- a/pkg/controller/controller_utils.go +++ b/pkg/controller/controller_utils.go @@ -26,6 +26,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/validation" + "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/client/cache" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/record" @@ -477,3 +478,16 @@ func (o ControllersByCreationTimestamp) Less(i, j int) bool { } return o[i].CreationTimestamp.Before(o[j].CreationTimestamp) } + +// ReplicaSetsByCreationTimestamp sorts a list of ReplicationSets by creation timestamp, using their names as a tie breaker. +type ReplicaSetsByCreationTimestamp []*extensions.ReplicaSet + +func (o ReplicaSetsByCreationTimestamp) Len() int { return len(o) } +func (o ReplicaSetsByCreationTimestamp) Swap(i, j int) { o[i], o[j] = o[j], o[i] } + +func (o ReplicaSetsByCreationTimestamp) Less(i, j int) bool { + if o[i].CreationTimestamp.Equal(o[j].CreationTimestamp) { + return o[i].Name < o[j].Name + } + return o[i].CreationTimestamp.Before(o[j].CreationTimestamp) +} diff --git a/pkg/controller/deployment/deployment_controller.go b/pkg/controller/deployment/deployment_controller.go index a36bff98e39..f562693c80e 100644 --- a/pkg/controller/deployment/deployment_controller.go +++ b/pkg/controller/deployment/deployment_controller.go @@ -1020,14 +1020,14 @@ func (dc *DeploymentController) cleanupOldReplicaSets(oldRSs []*extensions.Repli return nil } - sort.Sort(controller.ControllersByCreationTimestamp(oldRSs)) + sort.Sort(controller.ReplicaSetsByCreationTimestamp(oldRSs)) var errList []error // TODO: This should be parallelized. for i := 0; i < diff; i++ { - controller := oldRSs[i] + rs := oldRSs[i] // Avoid delete replica set with non-zero replica counts - if controller.Spec.Replicas != 0 || controller.Generation > controller.Status.ObservedGeneration { + if rs.Spec.Replicas != 0 || rs.Generation > rs.Status.ObservedGeneration { continue } if err := dc.client.Extensions().ReplicaSets(rs.Namespace).Delete(rs.Name, nil); err != nil && !errors.IsNotFound(err) { @@ -1076,7 +1076,7 @@ func (dc *DeploymentController) scaleReplicaSetAndRecordEvent(rs *extensions.Rep } newRS, err := dc.scaleReplicaSet(rs, newScale) if err == nil { - dc.eventRecorder.Eventf(&deployment, api.EventTypeNormal, "ScalingReplicaSet", "Scaled %s ReplicaSet %s to %d", scalingOperation, rs.Name, newScale) + dc.eventRecorder.Eventf(&deployment, api.EventTypeNormal, "ScalingReplicaSet", "Scaled %s replica set %s to %d", scalingOperation, rs.Name, newScale) } return newRS, err } diff --git a/pkg/controller/deployment/deployment_controller_test.go b/pkg/controller/deployment/deployment_controller_test.go index 7c89b0175e9..9faf718d279 100644 --- a/pkg/controller/deployment/deployment_controller_test.go +++ b/pkg/controller/deployment/deployment_controller_test.go @@ -89,12 +89,11 @@ func TestDeploymentController_reconcileNewReplicaSet(t *testing.T) { t.Logf("executing scenario %d", i) newRS := rs("foo-v2", test.newReplicas, nil) oldRS := rs("foo-v2", test.oldReplicas, nil) - allRSs := []*extensions.ReplicaSet{newRS, oldRS} + allRSs := []*exp.ReplicaSet{newRS, oldRS} deployment := deployment("foo", test.deploymentReplicas, test.maxSurge, intstr.FromInt(0)) fake := fake.Clientset{} controller := &DeploymentController{ client: &fake, - expClient: fake.Extensions(), eventRecorder: &record.FakeRecorder{}, } scaled, err := controller.reconcileNewReplicaSet(allRSs, newRS, deployment) @@ -430,8 +429,8 @@ func TestDeploymentController_scaleDownOldReplicaSetsForRollingUpdate(t *testing for i, test := range tests { t.Logf("executing scenario %d", i) oldRS := rs("foo-v2", test.oldReplicas, nil) - allRSs := []*extensions.ReplicaSet{oldRS} - oldRSs := []*extensions.ReplicaSet{oldRS} + allRSs := []*exp.ReplicaSet{oldRS} + oldRSs := []*exp.ReplicaSet{oldRS} deployment := deployment("foo", test.deploymentReplicas, intstr.FromInt(0), test.maxUnavailable) fakeClientset := fake.Clientset{} fakeClientset.AddReactor("list", "pods", func(action core.Action) (handled bool, ret runtime.Object, err error) { @@ -460,7 +459,6 @@ func TestDeploymentController_scaleDownOldReplicaSetsForRollingUpdate(t *testing }) controller := &DeploymentController{ client: &fakeClientset, - expClient: fake.Extensions(), eventRecorder: &record.FakeRecorder{}, } scaled, err := controller.scaleDownOldReplicaSetsForRollingUpdate(allRSs, oldRSs, deployment) @@ -506,12 +504,12 @@ func TestDeploymentController_cleanupOldReplicaSets(t *testing.T) { selector := map[string]string{"foo": "bar"} tests := []struct { - oldRSs []*extensions.ReplicaSet + oldRSs []*exp.ReplicaSet revisionHistoryLimit int expectedDeletions int }{ { - oldRSs: []*extensions.ReplicaSet{ + oldRSs: []*exp.ReplicaSet{ rs("foo-1", 0, selector), rs("foo-2", 0, selector), rs("foo-3", 0, selector), @@ -520,7 +518,7 @@ func TestDeploymentController_cleanupOldReplicaSets(t *testing.T) { expectedDeletions: 2, }, { - oldRSs: []*extensions.ReplicaSet{ + oldRSs: []*exp.ReplicaSet{ rs("foo-1", 0, selector), rs("foo-2", 0, selector), }, @@ -528,7 +526,7 @@ func TestDeploymentController_cleanupOldReplicaSets(t *testing.T) { expectedDeletions: 2, }, { - oldRSs: []*extensions.ReplicaSet{ + oldRSs: []*exp.ReplicaSet{ rs("foo-1", 1, selector), rs("foo-2", 1, selector), }, @@ -564,14 +562,14 @@ func TestDeploymentController_cleanupOldReplicaSets(t *testing.T) { } } -func rs(name string, replicas int, selector map[string]string) *extensions.ReplicaSet { - return &extensions.ReplicaSet{ +func rs(name string, replicas int, selector map[string]string) *exp.ReplicaSet { + return &exp.ReplicaSet{ ObjectMeta: api.ObjectMeta{ Name: name, }, Spec: exp.ReplicaSetSpec{ Replicas: replicas, - Selector: &exp.LabelSelector{MatchLabels: selector}, + Selector: &unversioned.LabelSelector{MatchLabels: selector}, Template: &api.PodTemplateSpec{}, }, } @@ -612,7 +610,7 @@ func newDeployment(replicas int, revisionHistoryLimit *int) *exp.Deployment { RollingUpdate: &exp.RollingUpdateDeployment{}, }, Replicas: replicas, - Selector: &exp.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, + Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}}, Template: api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: map[string]string{ @@ -681,12 +679,12 @@ func (f *fixture) expectUpdateDeploymentAction(d *exp.Deployment) { f.objects.Items = append(f.objects.Items, d) } -func (f *fixture) expectCreateRSAction(rs *extensions.ReplicaSet) { +func (f *fixture) expectCreateRSAction(rs *exp.ReplicaSet) { f.actions = append(f.actions, core.NewCreateAction("replicasets", rs.Namespace, rs)) f.objects.Items = append(f.objects.Items, rs) } -func (f *fixture) expectUpdateRSAction(rs *extensions.ReplicaSet) { +func (f *fixture) expectUpdateRSAction(rs *exp.ReplicaSet) { f.actions = append(f.actions, core.NewUpdateAction("replicasets", rs.Namespace, rs)) f.objects.Items = append(f.objects.Items, rs) } diff --git a/pkg/kubectl/cmd/cmd_test.go b/pkg/kubectl/cmd/cmd_test.go index fbcc2be5fd1..d8ba40a43bd 100644 --- a/pkg/kubectl/cmd/cmd_test.go +++ b/pkg/kubectl/cmd/cmd_test.go @@ -291,6 +291,7 @@ func NewAPIFactory() (*cmdutil.Factory, *testFactory, runtime.Codec) { } rf := cmdutil.NewFactory(nil) f.PodSelectorForObject = rf.PodSelectorForObject + f.MapBasedSelectorForObject = rf.MapBasedSelectorForObject f.PortsForObject = rf.PortsForObject f.LabelsForObject = rf.LabelsForObject f.CanBeExposed = rf.CanBeExposed diff --git a/pkg/kubectl/cmd/expose.go b/pkg/kubectl/cmd/expose.go index a00d00eb5a0..9455065c6cd 100644 --- a/pkg/kubectl/cmd/expose.go +++ b/pkg/kubectl/cmd/expose.go @@ -149,9 +149,9 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str // For objects that need a pod selector, derive it from the exposed object in case a user // didn't explicitly specify one via --selector if s, found := params["selector"]; found && kubectl.IsZero(s) { - s, err := f.PodSelectorForObject(inputObject) + s, err := f.MapBasedSelectorForObject(inputObject) if err != nil { - return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't find selectors via --selector flag or introspection: %s", err)) + return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't retrieve selectors via --selector flag or introspection: %s", err)) } params["selector"] = s } diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index cb796e03b96..77b728d3e5e 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -94,6 +94,10 @@ type Factory struct { Rollbacker func(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) // PodSelectorForObject returns the pod selector associated with the provided object PodSelectorForObject func(object runtime.Object) (string, error) + // MapBasedSelectorForObject returns the map-based selector associated with the provided object. If a + // new set-based selector is provided, an error is returned if the selector cannot be converted to a + // map-based selector + MapBasedSelectorForObject func(object runtime.Object) (string, error) // PortsForObject returns the ports associated with the provided object PortsForObject func(object runtime.Object) ([]string, error) // LabelsForObject returns the labels associated with the provided object @@ -257,7 +261,41 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { } return kubectl.MakeLabels(t.Spec.Selector), nil case *extensions.Deployment: + selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) + if err != nil { + return "", fmt.Errorf("failed to convert label selector to selector: %v", err) + } + return selector.String(), nil + default: + gvk, err := api.Scheme.ObjectKind(object) + if err != nil { + return "", err + } + return "", fmt.Errorf("cannot extract pod selector from %v", gvk) + } + }, + MapBasedSelectorForObject: func(object runtime.Object) (string, error) { + // TODO: replace with a swagger schema based approach (identify pod selector via schema introspection) + switch t := object.(type) { + case *api.ReplicationController: return kubectl.MakeLabels(t.Spec.Selector), nil + case *api.Pod: + if len(t.Labels) == 0 { + return "", fmt.Errorf("the pod has no labels and cannot be exposed") + } + return kubectl.MakeLabels(t.Labels), nil + case *api.Service: + if t.Spec.Selector == nil { + return "", fmt.Errorf("the service has no pod selector set") + } + return kubectl.MakeLabels(t.Spec.Selector), nil + case *extensions.Deployment: + // TODO(madhusudancs): Make this smarter by admitting MatchExpressions with Equals + // operator, DoubleEquals operator and In operator with only one element in the set. + if len(t.Spec.Selector.MatchExpressions) > 0 { + return "", fmt.Errorf("couldn't convert expressions - \"%+v\" to map-based selector format") + } + return kubectl.MakeLabels(t.Spec.Selector.MatchLabels), nil default: gvk, err := api.Scheme.ObjectKind(object) if err != nil { @@ -450,13 +488,13 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory { selector := labels.SelectorFromSet(t.Spec.Selector) return GetFirstPod(client, t.Namespace, selector) case *extensions.Deployment: - selector, err := extensions.LabelSelectorAsSelector(t.Spec.Selector) + selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("failed to convert label selector to selector: %v", err) } return GetFirstPod(client, t.Namespace, selector) case *extensions.Job: - selector, err := extensions.LabelSelectorAsSelector(t.Spec.Selector) + selector, err := unversioned.LabelSelectorAsSelector(t.Spec.Selector) if err != nil { return nil, fmt.Errorf("failed to convert label selector to selector: %v", err) } diff --git a/pkg/kubectl/history.go b/pkg/kubectl/history.go index d51dea1b428..501e9dd9916 100644 --- a/pkg/kubectl/history.go +++ b/pkg/kubectl/history.go @@ -67,11 +67,11 @@ func (h *DeploymentHistoryViewer) History(namespace, name string) (HistoryInfo, if err != nil { return historyInfo, fmt.Errorf("failed to retrieve deployment %s: %v", name, err) } - _, allOldRCs, err := deploymentutil.GetOldRCs(*deployment, h.c) + _, allOldRCs, err := deploymentutil.GetOldReplicaSets(*deployment, h.c) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve old RCs from deployment %s: %v", name, err) } - newRC, err := deploymentutil.GetNewRC(*deployment, h.c) + newRC, err := deploymentutil.GetNewReplicaSet(*deployment, h.c) if err != nil { return historyInfo, fmt.Errorf("failed to retrieve new RC from deployment %s: %v", name, err) } diff --git a/pkg/kubectl/run.go b/pkg/kubectl/run.go index c6a93185bc0..e0ed8ada89f 100644 --- a/pkg/kubectl/run.go +++ b/pkg/kubectl/run.go @@ -103,7 +103,7 @@ func (DeploymentV1Beta1) Generate(genericParams map[string]interface{}) (runtime }, Spec: extensions.DeploymentSpec{ Replicas: count, - Selector: &extensions.LabelSelector{MatchLabels: labels}, + Selector: &unversioned.LabelSelector{MatchLabels: labels}, Template: api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: labels, diff --git a/pkg/kubectl/run_test.go b/pkg/kubectl/run_test.go index e9b6e6465e5..27a366c418b 100644 --- a/pkg/kubectl/run_test.go +++ b/pkg/kubectl/run_test.go @@ -656,7 +656,7 @@ func TestGenerateDeployment(t *testing.T) { }, Spec: extensions.DeploymentSpec{ Replicas: 3, - Selector: &extensions.LabelSelector{MatchLabels: map[string]string{"foo": "bar", "baz": "blah"}}, + Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar", "baz": "blah"}}, Template: api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: map[string]string{"foo": "bar", "baz": "blah"}, diff --git a/pkg/kubectl/scale.go b/pkg/kubectl/scale.go index 0d5edad82a3..be603563634 100644 --- a/pkg/kubectl/scale.go +++ b/pkg/kubectl/scale.go @@ -48,8 +48,9 @@ func ScalerFor(kind unversioned.GroupKind, c client.Interface) (Scaler, error) { return &ReplicaSetScaler{c.Extensions()}, nil case extensions.Kind("Job"): return &JobScaler{c.Extensions()}, nil - case extensions.Kind("Deployment"): - return &DeploymentScaler{c.Extensions()}, nil + // TODO(madhusudancs): Fix this when Scale group issues are resolved. + // case extensions.Kind("Deployment"): + // return &DeploymentScaler{c.Extensions()}, nil } return nil, fmt.Errorf("no scaler has been implemented for %q", kind) } @@ -327,56 +328,57 @@ func (precondition *ScalePrecondition) ValidateDeployment(deployment *extensions return nil } -type DeploymentScaler struct { - c client.ExtensionsInterface -} +// TODO(madhusudancs): Fix this when Scale group issues are resolved. +// type DeploymentScaler struct { +// c client.ExtensionsInterface +// } -// ScaleSimple is responsible for updating a deployment's desired replicas count. -func (scaler *DeploymentScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) error { - deployment, err := scaler.c.Deployments(namespace).Get(name) - if err != nil { - return ScaleError{ScaleGetFailure, "Unknown", err} - } - if preconditions != nil { - if err := preconditions.ValidateDeployment(deployment); err != nil { - return err - } - } - scale, err := extensions.ScaleFromDeployment(deployment) - if err != nil { - return ScaleError{ScaleUpdateFailure, deployment.ResourceVersion, err} - } - scale.Spec.Replicas = int(newSize) - if _, err := scaler.c.Scales(namespace).Update("Deployment", scale); err != nil { - if errors.IsInvalid(err) { - return ScaleError{ScaleUpdateInvalidFailure, deployment.ResourceVersion, err} - } - return ScaleError{ScaleUpdateFailure, deployment.ResourceVersion, err} - } - return nil -} +// // ScaleSimple is responsible for updating a deployment's desired replicas count. +// func (scaler *DeploymentScaler) ScaleSimple(namespace, name string, preconditions *ScalePrecondition, newSize uint) error { +// deployment, err := scaler.c.Deployments(namespace).Get(name) +// if err != nil { +// return ScaleError{ScaleGetFailure, "Unknown", err} +// } +// if preconditions != nil { +// if err := preconditions.ValidateDeployment(deployment); err != nil { +// return err +// } +// } +// scale, err := extensions.ScaleFromDeployment(deployment) +// if err != nil { +// return ScaleError{ScaleUpdateFailure, deployment.ResourceVersion, err} +// } +// scale.Spec.Replicas = int(newSize) +// if _, err := scaler.c.Scales(namespace).Update("Deployment", scale); err != nil { +// if errors.IsInvalid(err) { +// return ScaleError{ScaleUpdateInvalidFailure, deployment.ResourceVersion, err} +// } +// return ScaleError{ScaleUpdateFailure, deployment.ResourceVersion, err} +// } +// return nil +// } -// Scale updates a deployment to a new size, with optional precondition check (if preconditions is not nil), -// optional retries (if retry is not nil), and then optionally waits for the status to reach desired count. -func (scaler *DeploymentScaler) Scale(namespace, name string, newSize uint, preconditions *ScalePrecondition, retry, waitForReplicas *RetryParams) error { - if preconditions == nil { - preconditions = &ScalePrecondition{-1, ""} - } - if retry == nil { - // Make it try only once, immediately - retry = &RetryParams{Interval: time.Millisecond, Timeout: time.Millisecond} - } - cond := ScaleCondition(scaler, preconditions, namespace, name, newSize) - if err := wait.Poll(retry.Interval, retry.Timeout, cond); err != nil { - return err - } - if waitForReplicas != nil { - deployment, err := scaler.c.Deployments(namespace).Get(name) - if err != nil { - return err - } - return wait.Poll(waitForReplicas.Interval, waitForReplicas.Timeout, - client.DeploymentHasDesiredReplicas(scaler.c, deployment)) - } - return nil -} +// // Scale updates a deployment to a new size, with optional precondition check (if preconditions is not nil), +// // optional retries (if retry is not nil), and then optionally waits for the status to reach desired count. +// func (scaler *DeploymentScaler) Scale(namespace, name string, newSize uint, preconditions *ScalePrecondition, retry, waitForReplicas *RetryParams) error { +// if preconditions == nil { +// preconditions = &ScalePrecondition{-1, ""} +// } +// if retry == nil { +// // Make it try only once, immediately +// retry = &RetryParams{Interval: time.Millisecond, Timeout: time.Millisecond} +// } +// cond := ScaleCondition(scaler, preconditions, namespace, name, newSize) +// if err := wait.Poll(retry.Interval, retry.Timeout, cond); err != nil { +// return err +// } +// if waitForReplicas != nil { +// deployment, err := scaler.c.Deployments(namespace).Get(name) +// if err != nil { +// return err +// } +// return wait.Poll(waitForReplicas.Interval, waitForReplicas.Timeout, +// client.DeploymentHasDesiredReplicas(scaler.c, deployment)) +// } +// return nil +// } diff --git a/pkg/kubectl/scale_test.go b/pkg/kubectl/scale_test.go index 02d222ecfe5..18893353bc1 100644 --- a/pkg/kubectl/scale_test.go +++ b/pkg/kubectl/scale_test.go @@ -488,143 +488,145 @@ func TestValidateJob(t *testing.T) { } } -type ErrorScales struct { - testclient.FakeScales - invalid bool -} +// TODO(madhusudancs): Fix this when Scale group issues are resolved. -func (c *ErrorScales) Update(kind string, scale *extensions.Scale) (*extensions.Scale, error) { - if c.invalid { - return nil, kerrors.NewInvalid(extensions.Kind(scale.Kind), scale.Name, nil) - } - return nil, errors.New("scale update failure") -} +// type ErrorScales struct { +// testclient.FakeScales +// invalid bool +// } -func (c *ErrorScales) Get(kind, name string) (*extensions.Scale, error) { - return &extensions.Scale{ - Spec: extensions.ScaleSpec{ - Replicas: 0, - }, - }, nil -} +// func (c *ErrorScales) Update(kind string, scale *extensions.Scale) (*extensions.Scale, error) { +// if c.invalid { +// return nil, kerrors.NewInvalid(extensions.Kind(scale.Kind), scale.Name, nil) +// } +// return nil, errors.New("scale update failure") +// } -type ErrorDeployments struct { - testclient.FakeDeployments - invalid bool -} +// func (c *ErrorScales) Get(kind, name string) (*extensions.Scale, error) { +// return &extensions.Scale{ +// Spec: extensions.ScaleSpec{ +// Replicas: 0, +// }, +// }, nil +// } -func (c *ErrorDeployments) Update(deployment *extensions.Deployment) (*extensions.Deployment, error) { - if c.invalid { - return nil, kerrors.NewInvalid(extensions.Kind(deployment.Kind), deployment.Name, nil) - } - return nil, errors.New("deployment update failure") -} +// type ErrorDeployments struct { +// testclient.FakeDeployments +// invalid bool +// } -func (c *ErrorDeployments) Get(name string) (*extensions.Deployment, error) { - return &extensions.Deployment{ - Spec: extensions.DeploymentSpec{ - Replicas: 0, - }, - }, nil -} +// func (c *ErrorDeployments) Update(deployment *extensions.Deployment) (*extensions.Deployment, error) { +// if c.invalid { +// return nil, kerrors.NewInvalid(extensions.Kind(deployment.Kind), deployment.Name, nil) +// } +// return nil, errors.New("deployment update failure") +// } -type ErrorDeploymentClient struct { - testclient.FakeExperimental - invalid bool -} +// func (c *ErrorDeployments) Get(name string) (*extensions.Deployment, error) { +// return &extensions.Deployment{ +// Spec: extensions.DeploymentSpec{ +// Replicas: 0, +// }, +// }, nil +// } -func (c *ErrorDeploymentClient) Deployments(namespace string) client.DeploymentInterface { - return &ErrorDeployments{testclient.FakeDeployments{Fake: &c.FakeExperimental, Namespace: namespace}, c.invalid} -} +// type ErrorDeploymentClient struct { +// testclient.FakeExperimental +// invalid bool +// } -func (c *ErrorDeploymentClient) Scales(namespace string) client.ScaleInterface { - return &ErrorScales{testclient.FakeScales{Fake: &c.FakeExperimental, Namespace: namespace}, c.invalid} -} +// func (c *ErrorDeploymentClient) Deployments(namespace string) client.DeploymentInterface { +// return &ErrorDeployments{testclient.FakeDeployments{Fake: &c.FakeExperimental, Namespace: namespace}, c.invalid} +// } -func TestDeploymentScaleRetry(t *testing.T) { - fake := &ErrorDeploymentClient{FakeExperimental: testclient.FakeExperimental{Fake: &testclient.Fake{}}, invalid: false} - scaler := &DeploymentScaler{fake} - preconditions := &ScalePrecondition{-1, ""} - count := uint(3) - name := "foo" - namespace := "default" +// func (c *ErrorDeploymentClient) Scales(namespace string) client.ScaleInterface { +// return &ErrorScales{testclient.FakeScales{Fake: &c.FakeExperimental, Namespace: namespace}, c.invalid} +// } - scaleFunc := ScaleCondition(scaler, preconditions, namespace, name, count) - pass, err := scaleFunc() - if pass != false { - t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass) - } - if err != nil { - t.Errorf("Did not expect an error on update failure, got %v", err) - } - preconditions = &ScalePrecondition{3, ""} - scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count) - pass, err = scaleFunc() - if err == nil { - t.Errorf("Expected error on precondition failure") - } -} +// func TestDeploymentScaleRetry(t *testing.T) { +// fake := &ErrorDeploymentClient{FakeExperimental: testclient.FakeExperimental{Fake: &testclient.Fake{}}, invalid: false} +// scaler := &DeploymentScaler{fake} +// preconditions := &ScalePrecondition{-1, ""} +// count := uint(3) +// name := "foo" +// namespace := "default" -func TestDeploymentScale(t *testing.T) { - fake := &testclient.FakeExperimental{Fake: &testclient.Fake{}} - scaler := DeploymentScaler{fake} - preconditions := ScalePrecondition{-1, ""} - count := uint(3) - name := "foo" - scaler.Scale("default", name, count, &preconditions, nil, nil) +// scaleFunc := ScaleCondition(scaler, preconditions, namespace, name, count) +// pass, err := scaleFunc() +// if pass != false { +// t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass) +// } +// if err != nil { +// t.Errorf("Did not expect an error on update failure, got %v", err) +// } +// preconditions = &ScalePrecondition{3, ""} +// scaleFunc = ScaleCondition(scaler, preconditions, namespace, name, count) +// pass, err = scaleFunc() +// if err == nil { +// t.Errorf("Expected error on precondition failure") +// } +// } - actions := fake.Actions() - if len(actions) != 2 { - t.Errorf("unexpected actions: %v, expected 2 actions (get, update)", actions) - } - if action, ok := actions[0].(testclient.GetAction); !ok || action.GetResource() != "deployments" || action.GetName() != name { - t.Errorf("unexpected action: %v, expected get-replicationController %s", actions[0], name) - } - // TODO: The testclient needs to support subresources - if action, ok := actions[1].(testclient.UpdateAction); !ok || action.GetResource() != "Deployment" || action.GetObject().(*extensions.Scale).Spec.Replicas != int(count) { - t.Errorf("unexpected action %v, expected update-deployment-scale with replicas = %d", actions[1], count) - } -} +// func TestDeploymentScale(t *testing.T) { +// fake := &testclient.FakeExperimental{Fake: &testclient.Fake{}} +// scaler := DeploymentScaler{fake} +// preconditions := ScalePrecondition{-1, ""} +// count := uint(3) +// name := "foo" +// scaler.Scale("default", name, count, &preconditions, nil, nil) -func TestDeploymentScaleInvalid(t *testing.T) { - fake := &ErrorDeploymentClient{FakeExperimental: testclient.FakeExperimental{Fake: &testclient.Fake{}}, invalid: true} - scaler := DeploymentScaler{fake} - preconditions := ScalePrecondition{-1, ""} - count := uint(3) - name := "foo" - namespace := "default" +// actions := fake.Actions() +// if len(actions) != 2 { +// t.Errorf("unexpected actions: %v, expected 2 actions (get, update)", actions) +// } +// if action, ok := actions[0].(testclient.GetAction); !ok || action.GetResource() != "deployments" || action.GetName() != name { +// t.Errorf("unexpected action: %v, expected get-replicationController %s", actions[0], name) +// } +// // TODO: The testclient needs to support subresources +// if action, ok := actions[1].(testclient.UpdateAction); !ok || action.GetResource() != "Deployment" || action.GetObject().(*extensions.Scale).Spec.Replicas != int(count) { +// t.Errorf("unexpected action %v, expected update-deployment-scale with replicas = %d", actions[1], count) +// } +// } - scaleFunc := ScaleCondition(&scaler, &preconditions, namespace, name, count) - pass, err := scaleFunc() - if pass { - t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass) - } - e, ok := err.(ScaleError) - if err == nil || !ok || e.FailureType != ScaleUpdateInvalidFailure { - t.Errorf("Expected error on invalid update failure, got %v", err) - } -} +// func TestDeploymentScaleInvalid(t *testing.T) { +// fake := &ErrorDeploymentClient{FakeExperimental: testclient.FakeExperimental{Fake: &testclient.Fake{}}, invalid: true} +// scaler := DeploymentScaler{fake} +// preconditions := ScalePrecondition{-1, ""} +// count := uint(3) +// name := "foo" +// namespace := "default" -func TestDeploymentScaleFailsPreconditions(t *testing.T) { - fake := testclient.NewSimpleFake(&extensions.Deployment{ - Spec: extensions.DeploymentSpec{ - Replicas: 10, - }, - }) - scaler := DeploymentScaler{&testclient.FakeExperimental{fake}} - preconditions := ScalePrecondition{2, ""} - count := uint(3) - name := "foo" - scaler.Scale("default", name, count, &preconditions, nil, nil) +// scaleFunc := ScaleCondition(&scaler, &preconditions, namespace, name, count) +// pass, err := scaleFunc() +// if pass { +// t.Errorf("Expected an update failure to return pass = false, got pass = %v", pass) +// } +// e, ok := err.(ScaleError) +// if err == nil || !ok || e.FailureType != ScaleUpdateInvalidFailure { +// t.Errorf("Expected error on invalid update failure, got %v", err) +// } +// } - actions := fake.Actions() - if len(actions) != 1 { - t.Errorf("unexpected actions: %v, expected 1 actions (get)", actions) - } - if action, ok := actions[0].(testclient.GetAction); !ok || action.GetResource() != "deployments" || action.GetName() != name { - t.Errorf("unexpected action: %v, expected get-deployment %s", actions[0], name) - } -} +// func TestDeploymentScaleFailsPreconditions(t *testing.T) { +// fake := testclient.NewSimpleFake(&extensions.Deployment{ +// Spec: extensions.DeploymentSpec{ +// Replicas: 10, +// }, +// }) +// scaler := DeploymentScaler{&testclient.FakeExperimental{fake}} +// preconditions := ScalePrecondition{2, ""} +// count := uint(3) +// name := "foo" +// scaler.Scale("default", name, count, &preconditions, nil, nil) + +// actions := fake.Actions() +// if len(actions) != 1 { +// t.Errorf("unexpected actions: %v, expected 1 actions (get)", actions) +// } +// if action, ok := actions[0].(testclient.GetAction); !ok || action.GetResource() != "deployments" || action.GetName() != name { +// t.Errorf("unexpected action: %v, expected get-deployment %s", actions[0], name) +// } +// } func TestValidateDeployment(t *testing.T) { zero, ten, twenty := 0, 10, 20 diff --git a/pkg/master/master.go b/pkg/master/master.go index 74843e87691..089231a74b1 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -624,7 +624,8 @@ func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage { deploymentStorage := deploymentetcd.NewStorage(dbClient("deployments"), storageDecorator) storage["deployments"] = deploymentStorage.Deployment storage["deployments/status"] = deploymentStorage.Status - storage["deployments/scale"] = deploymentStorage.Scale + // TODO(madhusudancs): Install scale when Scale group issues are fixed. + // storage["deployments/scale"] = deploymentStorage.Scale storage["deployments/rollback"] = deploymentStorage.Rollback } if isEnabled("jobs") { diff --git a/pkg/registry/deployment/etcd/etcd.go b/pkg/registry/deployment/etcd/etcd.go index 79f09afdca3..f71f7a7a7ec 100644 --- a/pkg/registry/deployment/etcd/etcd.go +++ b/pkg/registry/deployment/etcd/etcd.go @@ -183,51 +183,53 @@ type ScaleREST struct { registry *deployment.Registry } -// ScaleREST implements Patcher -var _ = rest.Patcher(&ScaleREST{}) +// TODO(madhusudancs): Fix this when Scale group issues are resolved. -// New creates a new Scale object -func (r *ScaleREST) New() runtime.Object { - return &extensions.Scale{} -} +// // ScaleREST implements Patcher +// var _ = rest.Patcher(&ScaleREST{}) -func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) { - deployment, err := (*r.registry).GetDeployment(ctx, name) - if err != nil { - return nil, errors.NewNotFound(extensions.Resource("deployments/scale"), name) - } - scale, err := extensions.ScaleFromDeployment(deployment) - if err != nil { - return nil, errors.NewBadRequest(fmt.Sprintf("%v", err)) - } - return scale, nil -} +// // New creates a new Scale object +// func (r *ScaleREST) New() runtime.Object { +// return &extensions.Scale{} +// } -func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { - if obj == nil { - return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale")) - } - scale, ok := obj.(*extensions.Scale) - if !ok { - return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) - } +// func (r *ScaleREST) Get(ctx api.Context, name string) (runtime.Object, error) { +// deployment, err := (*r.registry).GetDeployment(ctx, name) +// if err != nil { +// return nil, errors.NewNotFound(extensions.Resource("deployments/scale"), name) +// } +// scale, err := extensions.ScaleFromDeployment(deployment) +// if err != nil { +// return nil, errors.NewBadRequest(fmt.Sprintf("%v", err)) +// } +// return scale, nil +// } - if errs := extvalidation.ValidateScale(scale); len(errs) > 0 { - return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs) - } +// func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) { +// if obj == nil { +// return nil, false, errors.NewBadRequest(fmt.Sprintf("nil update passed to Scale")) +// } +// scale, ok := obj.(*extensions.Scale) +// if !ok { +// return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) +// } - deployment, err := (*r.registry).GetDeployment(ctx, scale.Name) - if err != nil { - return nil, false, errors.NewNotFound(extensions.Resource("deployments/scale"), scale.Name) - } - deployment.Spec.Replicas = scale.Spec.Replicas - deployment, err = (*r.registry).UpdateDeployment(ctx, deployment) - if err != nil { - return nil, false, errors.NewConflict(extensions.Resource("deployments/scale"), scale.Name, err) - } - newScale, err := extensions.ScaleFromDeployment(deployment) - if err != nil { - return nil, false, errors.NewBadRequest(fmt.Sprintf("%v", err)) - } - return newScale, false, nil -} +// if errs := extvalidation.ValidateScale(scale); len(errs) > 0 { +// return nil, false, errors.NewInvalid(extensions.Kind("Scale"), scale.Name, errs) +// } + +// deployment, err := (*r.registry).GetDeployment(ctx, scale.Name) +// if err != nil { +// return nil, false, errors.NewNotFound(extensions.Resource("deployments/scale"), scale.Name) +// } +// deployment.Spec.Replicas = scale.Spec.Replicas +// deployment, err = (*r.registry).UpdateDeployment(ctx, deployment) +// if err != nil { +// return nil, false, errors.NewConflict(extensions.Resource("deployments/scale"), scale.Name, err) +// } +// newScale, err := extensions.ScaleFromDeployment(deployment) +// if err != nil { +// return nil, false, errors.NewBadRequest(fmt.Sprintf("%v", err)) +// } +// return newScale, false, nil +// } diff --git a/pkg/registry/deployment/etcd/etcd_test.go b/pkg/registry/deployment/etcd/etcd_test.go index b866d722f83..cdd022d7221 100644 --- a/pkg/registry/deployment/etcd/etcd_test.go +++ b/pkg/registry/deployment/etcd/etcd_test.go @@ -23,6 +23,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" etcderrors "k8s.io/kubernetes/pkg/api/errors/etcd" + "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" @@ -31,7 +32,6 @@ import ( "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/storage/etcd/etcdtest" etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" - "k8s.io/kubernetes/pkg/util" ) func newStorage(t *testing.T) (*DeploymentStorage, *etcdtesting.EtcdTestServer) { @@ -50,7 +50,7 @@ func validNewDeployment() *extensions.Deployment { Namespace: namespace, }, Spec: extensions.DeploymentSpec{ - Selector: &extensions.LabelSelector{MatchLabels: map[string]string{"a": "b"}}, + Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"a": "b"}}, Template: api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: map[string]string{"a": "b"}, @@ -89,7 +89,7 @@ func TestCreate(t *testing.T) { // invalid (invalid selector) &extensions.Deployment{ Spec: extensions.DeploymentSpec{ - Selector: &extensions.LabelSelector{MatchLabels: map[string]string{}}, + Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{}}, Template: validDeployment.Spec.Template, }, }, @@ -127,7 +127,7 @@ func TestUpdate(t *testing.T) { }, func(obj runtime.Object) runtime.Object { object := obj.(*extensions.Deployment) - object.Spec.Selector = &extensions.LabelSelector{MatchLabels: map[string]string{}} + object.Spec.Selector = &unversioned.LabelSelector{MatchLabels: map[string]string{}} return object }, ) @@ -179,71 +179,73 @@ func TestWatch(t *testing.T) { ) } -func validNewScale() *extensions.Scale { - return &extensions.Scale{ - ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace}, - Spec: extensions.ScaleSpec{ - Replicas: validDeployment.Spec.Replicas, - }, - Status: extensions.ScaleStatus{ - Replicas: validDeployment.Status.Replicas, - Selector: validDeployment.Spec.Template.Labels, - }, - } -} +// TODO(madhusudancs): Fix this when Scale group issues are resolved. -var validScale = *validNewScale() +// func validNewScale() *extensions.Scale { +// return &extensions.Scale{ +// ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace}, +// Spec: extensions.ScaleSpec{ +// Replicas: validDeployment.Spec.Replicas, +// }, +// Status: extensions.ScaleStatus{ +// Replicas: validDeployment.Status.Replicas, +// Selector: validDeployment.Spec.Template.Labels, +// }, +// } +// } -func TestScaleGet(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) +// var validScale = *validNewScale() - ctx := api.WithNamespace(api.NewContext(), namespace) - key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name) - if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, nil, 0); err != nil { - t.Fatalf("unexpected error: %v", err) - } +// func TestScaleGet(t *testing.T) { +// storage, server := newStorage(t) +// defer server.Terminate(t) - expect := &validScale - obj, err := storage.Scale.Get(ctx, name) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - scale := obj.(*extensions.Scale) - if e, a := expect, scale; !api.Semantic.DeepDerivative(e, a) { - t.Errorf("unexpected scale: %s", util.ObjectDiff(e, a)) - } -} +// ctx := api.WithNamespace(api.NewContext(), namespace) +// key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name) +// if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, nil, 0); err != nil { +// t.Fatalf("unexpected error: %v", err) +// } -func TestScaleUpdate(t *testing.T) { - storage, server := newStorage(t) - defer server.Terminate(t) +// expect := &validScale +// obj, err := storage.Scale.Get(ctx, name) +// if err != nil { +// t.Fatalf("unexpected error: %v", err) +// } +// scale := obj.(*extensions.Scale) +// if e, a := expect, scale; !api.Semantic.DeepDerivative(e, a) { +// t.Errorf("unexpected scale: %s", util.ObjectDiff(e, a)) +// } +// } - ctx := api.WithNamespace(api.NewContext(), namespace) - key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name) - if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, nil, 0); err != nil { - t.Fatalf("unexpected error: %v", err) - } - replicas := 12 - update := extensions.Scale{ - ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace}, - Spec: extensions.ScaleSpec{ - Replicas: replicas, - }, - } +// func TestScaleUpdate(t *testing.T) { +// storage, server := newStorage(t) +// defer server.Terminate(t) - if _, _, err := storage.Scale.Update(ctx, &update); err != nil { - t.Fatalf("unexpected error: %v", err) - } - obj, err := storage.Deployment.Get(ctx, name) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - deployment := obj.(*extensions.Deployment) - if deployment.Spec.Replicas != replicas { - t.Errorf("wrong replicas count expected: %d got: %d", replicas, deployment.Spec.Replicas) - } -} +// ctx := api.WithNamespace(api.NewContext(), namespace) +// key := etcdtest.AddPrefix("/deployments/" + namespace + "/" + name) +// if err := storage.Deployment.Storage.Set(ctx, key, &validDeployment, nil, 0); err != nil { +// t.Fatalf("unexpected error: %v", err) +// } +// replicas := 12 +// update := extensions.Scale{ +// ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace}, +// Spec: extensions.ScaleSpec{ +// Replicas: replicas, +// }, +// } + +// if _, _, err := storage.Scale.Update(ctx, &update); err != nil { +// t.Fatalf("unexpected error: %v", err) +// } +// obj, err := storage.Deployment.Get(ctx, name) +// if err != nil { +// t.Fatalf("unexpected error: %v", err) +// } +// deployment := obj.(*extensions.Deployment) +// if deployment.Spec.Replicas != replicas { +// t.Errorf("wrong replicas count expected: %d got: %d", replicas, deployment.Spec.Replicas) +// } +// } func TestStatusUpdate(t *testing.T) { storage, server := newStorage(t) diff --git a/pkg/util/deployment/deployment.go b/pkg/util/deployment/deployment.go index e33a669fe4f..158d844ef5d 100644 --- a/pkg/util/deployment/deployment.go +++ b/pkg/util/deployment/deployment.go @@ -22,6 +22,7 @@ import ( "time" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apis/extensions" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/labels" @@ -56,9 +57,9 @@ func GetOldReplicaSets(deployment extensions.Deployment, c clientset.Interface) // Note that the first set of old replica sets doesn't include the ones with no pods, and the second set of old replica sets include all old replica sets. func GetOldReplicaSetsFromLists(deployment extensions.Deployment, c clientset.Interface, getPodList func(string, api.ListOptions) (*api.PodList, error), getRcList func(string, api.ListOptions) ([]extensions.ReplicaSet, error)) ([]*extensions.ReplicaSet, []*extensions.ReplicaSet, error) { namespace := deployment.ObjectMeta.Namespace - selector, err := extensions.LabelSelectorAsSelector(deployment.Spec.Selector) + selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) if err != nil { - return nil, fmt.Errorf("failed to convert LabelSelector to Selector: %v", err) + return nil, nil, fmt.Errorf("failed to convert LabelSelector to Selector: %v", err) } // 1. Find all pods whose labels match deployment.Spec.Selector @@ -79,7 +80,10 @@ func GetOldReplicaSetsFromLists(deployment extensions.Deployment, c clientset.In for _, pod := range podList.Items { podLabelsSelector := labels.Set(pod.ObjectMeta.Labels) for _, rs := range rsList { - rsLabelsSelector := labels.SelectorFromSet(rs.Spec.Selector) + rsLabelsSelector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector) + if err != nil { + return nil, nil, fmt.Errorf("failed to convert LabelSelector to Selector: %v", err) + } // Filter out replica set that has the same pod template spec as the deployment - that is the new replica set. if api.Semantic.DeepEqual(rs.Spec.Template, &newRSTemplate) { continue @@ -117,7 +121,12 @@ func GetNewReplicaSet(deployment extensions.Deployment, c clientset.Interface) ( // Returns nil if the new replica set doesnt exist yet. func GetNewReplicaSetFromList(deployment extensions.Deployment, c clientset.Interface, getRcList func(string, api.ListOptions) ([]extensions.ReplicaSet, error)) (*extensions.ReplicaSet, error) { namespace := deployment.ObjectMeta.Namespace - rsList, err := getRcList(namespace, api.ListOptions{LabelSelector: labels.SelectorFromSet(deployment.Spec.Selector)}) + selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) + if err != nil { + return nil, fmt.Errorf("failed to convert LabelSelector to Selector: %v", err) + } + + rsList, err := getRcList(namespace, api.ListOptions{LabelSelector: selector}) if err != nil { return nil, fmt.Errorf("error listing ReplicaSets: %v", err) } @@ -158,7 +167,7 @@ func SetFromReplicaSetTemplate(deployment *extensions.Deployment, template api.P } // Returns the sum of Replicas of the given replica sets. -func GetReplicaCountForReplicaSets(replicationControllers []*extensions.ReplicaSet) int { +func GetReplicaCountForReplicaSets(replicaSets []*extensions.ReplicaSet) int { totalReplicaCount := 0 for _, rs := range replicaSets { totalReplicaCount += rs.Spec.Replicas @@ -199,10 +208,10 @@ func getReadyPodsCount(pods []api.Pod, minReadySeconds int) int { return readyPodCount } -func getPodsForReplicaSets(c clientset.Interface, replicationControllers []*extensions.ReplicaSet) ([]api.Pod, error) { +func getPodsForReplicaSets(c clientset.Interface, replicaSets []*extensions.ReplicaSet) ([]api.Pod, error) { allPods := []api.Pod{} for _, rs := range replicaSets { - selector, err := extensions.LabelSelectorAsSelector(rs.Spec.Selector) + selector, err := unversioned.LabelSelectorAsSelector(rs.Spec.Selector) if err != nil { return nil, fmt.Errorf("failed to convert LabelSelector to Selector: %v", err) } diff --git a/pkg/util/deployment/deployment_test.go b/pkg/util/deployment/deployment_test.go index c1ae5583cad..8d7317e4158 100644 --- a/pkg/util/deployment/deployment_test.go +++ b/pkg/util/deployment/deployment_test.go @@ -118,7 +118,7 @@ func generateRSWithLabel(labels map[string]string, image string) extensions.Repl }, Spec: extensions.ReplicaSetSpec{ Replicas: 1, - Selector: &extensions.LabelSelector{MatchLabels: labels}, + Selector: &unversioned.LabelSelector{MatchLabels: labels}, Template: &api.PodTemplateSpec{ Spec: api.PodSpec{ Containers: []api.Container{ @@ -145,7 +145,7 @@ func generateRS(deployment extensions.Deployment) extensions.ReplicaSet { }, Spec: extensions.ReplicaSetSpec{ Template: &template, - Selector: &extensions.LabelSelector{MatchLabels: template.Labels}, + Selector: &unversioned.LabelSelector{MatchLabels: template.Labels}, }, } } @@ -160,7 +160,7 @@ func generateDeployment(image string) extensions.Deployment { }, Spec: extensions.DeploymentSpec{ Replicas: 1, - Selector: &extensions.LabelSelector{MatchLabels: podLabels}, + Selector: &unversioned.LabelSelector{MatchLabels: podLabels}, Template: api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: podLabels, diff --git a/pkg/util/labels/labels.go b/pkg/util/labels/labels.go index f6eb596b5fa..3960165afe3 100644 --- a/pkg/util/labels/labels.go +++ b/pkg/util/labels/labels.go @@ -19,7 +19,7 @@ package labels import ( "fmt" - "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/api/unversioned" ) // Clones the given map and returns a new map with the given key and value added. @@ -56,14 +56,14 @@ func CloneAndRemoveLabel(labels map[string]string, labelKey string) map[string]s // Clones the given selector and returns a new selector with the given key and value added. // Returns the given selector, if labelKey is empty. -func CloneSelectorAndAddLabel(selector *extensions.LabelSelector, labelKey string, labelValue uint32) *extensions.LabelSelector { +func CloneSelectorAndAddLabel(selector *unversioned.LabelSelector, labelKey string, labelValue uint32) *unversioned.LabelSelector { if labelKey == "" { // Dont need to add a label. return selector } // Clone. - newSelector := new(extensions.LabelSelector) + newSelector := new(unversioned.LabelSelector) // TODO(madhusudancs): Check if you can use deepCopy_extensions_LabelSelector here. newSelector.MatchLabels = make(map[string]string) @@ -75,7 +75,7 @@ func CloneSelectorAndAddLabel(selector *extensions.LabelSelector, labelKey strin newSelector.MatchLabels[labelKey] = fmt.Sprintf("%d", labelValue) if selector.MatchExpressions != nil { - newMExps := make([]extensions.LabelSelectorRequirement, len(selector.MatchExpressions)) + newMExps := make([]unversioned.LabelSelectorRequirement, len(selector.MatchExpressions)) for i, me := range selector.MatchExpressions { newMExps[i].Key = me.Key newMExps[i].Operator = me.Operator diff --git a/test/e2e/deployment.go b/test/e2e/deployment.go index 6b50c3f845c..2632b4231e6 100644 --- a/test/e2e/deployment.go +++ b/test/e2e/deployment.go @@ -21,10 +21,10 @@ import ( "time" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apis/extensions" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/kubectl" - "k8s.io/kubernetes/pkg/labels" deploymentutil "k8s.io/kubernetes/pkg/util/deployment" "k8s.io/kubernetes/pkg/util/intstr" @@ -64,14 +64,14 @@ var _ = Describe("Deployment [Feature:Deployment]", func() { }) }) -func newReplicaSet(rsName string, replicas int, rsPodLabels map[string]string, imageName string, image string) *extensions.ReplicaSet { +func newRS(rsName string, replicas int, rsPodLabels map[string]string, imageName string, image string) *extensions.ReplicaSet { return &extensions.ReplicaSet{ ObjectMeta: api.ObjectMeta{ Name: rsName, }, Spec: extensions.ReplicaSetSpec{ Replicas: replicas, - Selector: &extensions.LabelSelector{MatchLabels: rsPodLabels}, + Selector: &unversioned.LabelSelector{MatchLabels: rsPodLabels}, Template: &api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: rsPodLabels, @@ -96,7 +96,7 @@ func newDeployment(deploymentName string, replicas int, podLabels map[string]str }, Spec: extensions.DeploymentSpec{ Replicas: replicas, - Selector: &extensions.LabelSelector{MatchLabels: podLabels}, + Selector: &unversioned.LabelSelector{MatchLabels: podLabels}, Strategy: extensions.DeploymentStrategy{ Type: strategyType, }, @@ -214,7 +214,7 @@ func testRollingUpdateDeployment(f *Framework) { rsName := "nginx-controller" replicas := 3 - _, err := c.Extensions().ReplicaSets(ns).Create(newReplicaSet(rsName, replicas, rsPodLabels, "nginx", "nginx")) + _, err := c.Extensions().ReplicaSets(ns).Create(newRS(rsName, replicas, rsPodLabels, "nginx", "nginx")) Expect(err).NotTo(HaveOccurred()) defer func() { Logf("deleting replica set %s", rsName) @@ -557,7 +557,11 @@ func testPausedDeployment(f *Framework) { deployment, err = c.Extensions().Deployments(ns).Update(deployment) Expect(err).NotTo(HaveOccurred()) - opts := api.ListOptions{LabelSelector: labels.Set(deployment.Spec.Selector).AsSelector()} + selector, err := unversioned.LabelSelectorAsSelector(deployment.Spec.Selector) + if err != nil { + Expect(err).NotTo(HaveOccurred()) + } + opts := api.ListOptions{LabelSelector: selector} w, err := c.Extensions().ReplicaSets(ns).Watch(opts) Expect(err).NotTo(HaveOccurred()) diff --git a/test/e2e/horizontal_pod_autoscaling.go b/test/e2e/horizontal_pod_autoscaling.go index 978832c3458..fe5568a3212 100644 --- a/test/e2e/horizontal_pod_autoscaling.go +++ b/test/e2e/horizontal_pod_autoscaling.go @@ -41,15 +41,16 @@ var _ = Describe("Horizontal pod autoscaling (scale resource: CPU) [Serial] [Slo titleUp := "Should scale from 1 pod to 3 pods and from 3 to 5" titleDown := "Should scale from 5 pods to 3 pods and from 3 to 1" - Describe("Deployment [Feature:Deployment]", func() { - // CPU tests via deployments - It(titleUp, func() { - scaleUp("deployment", kindDeployment, rc, f) - }) - It(titleDown, func() { - scaleDown("deployment", kindDeployment, rc, f) - }) - }) + // TODO(madhusudancs): Fix this when Scale group issues are resolved. + // Describe("Deployment [Feature:Deployment]", func() { + // // CPU tests via deployments + // It(titleUp, func() { + // scaleUp("deployment", kindDeployment, rc, f) + // }) + // It(titleDown, func() { + // scaleDown("deployment", kindDeployment, rc, f) + // }) + // }) Describe("ReplicationController", func() { // CPU tests via replication controllers diff --git a/test/e2e/util.go b/test/e2e/util.go index 5d5f1f2849b..15856888912 100644 --- a/test/e2e/util.go +++ b/test/e2e/util.go @@ -1529,7 +1529,7 @@ func (config *DeploymentConfig) create() error { }, Spec: extensions.DeploymentSpec{ Replicas: config.Replicas, - Selector: &extensions.LabelSelector{ + Selector: &unversioned.LabelSelector{ MatchLabels: map[string]string{ "name": config.Name, },