Skip to content

Commit 598a4ac

Browse files
Merge pull request #16379 from juanvallejo/jvallejo/fix-debug-on-deployment-w-0-replicas
Automatic merge from submit-queue. UPSTREAM: 53606: use deployment pod template if 0 replicas Fixes #14286 Fixes #14915 Prevent `oc debug` from hanging indefinitely when dealing with a deployment that has been scaled down to 0. cc @openshift/cli-review @smarterclayton
2 parents 87e24b0 + 0598c2d commit 598a4ac

File tree

6 files changed

+145
-83
lines changed

6 files changed

+145
-83
lines changed

pkg/cmd/util/clientcmd/factory.go

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,8 @@ import (
2929
"k8s.io/kubernetes/pkg/printers"
3030

3131
deployapi "github.com/openshift/origin/pkg/apps/apis/apps"
32-
deployutil "github.com/openshift/origin/pkg/apps/util"
3332
buildapi "github.com/openshift/origin/pkg/build/apis/build"
3433
"github.com/openshift/origin/pkg/cmd/util"
35-
imageapi "github.com/openshift/origin/pkg/image/apis/image"
3634
)
3735

3836
// New creates a default Factory for commands that should share identical server
@@ -148,87 +146,6 @@ func (f *Factory) ExtractFileContents(obj runtime.Object) (map[string][]byte, bo
148146
}
149147
}
150148

151-
// ApproximatePodTemplateForObject returns a pod template object for the provided source.
152-
// It may return both an error and a object. It attempt to return the best possible template
153-
// available at the current time.
154-
func (f *Factory) ApproximatePodTemplateForObject(object runtime.Object) (*api.PodTemplateSpec, error) {
155-
switch t := object.(type) {
156-
case *imageapi.ImageStreamTag:
157-
// create a minimal pod spec that uses the image referenced by the istag without any introspection
158-
// it possible that we could someday do a better job introspecting it
159-
return &api.PodTemplateSpec{
160-
Spec: api.PodSpec{
161-
RestartPolicy: api.RestartPolicyNever,
162-
Containers: []api.Container{
163-
{Name: "container-00", Image: t.Image.DockerImageReference},
164-
},
165-
},
166-
}, nil
167-
case *imageapi.ImageStreamImage:
168-
// create a minimal pod spec that uses the image referenced by the istag without any introspection
169-
// it possible that we could someday do a better job introspecting it
170-
return &api.PodTemplateSpec{
171-
Spec: api.PodSpec{
172-
RestartPolicy: api.RestartPolicyNever,
173-
Containers: []api.Container{
174-
{Name: "container-00", Image: t.Image.DockerImageReference},
175-
},
176-
},
177-
}, nil
178-
case *deployapi.DeploymentConfig:
179-
fallback := t.Spec.Template
180-
181-
kc, err := f.ClientSet()
182-
if err != nil {
183-
return fallback, err
184-
}
185-
186-
latestDeploymentName := deployutil.LatestDeploymentNameForConfig(t)
187-
deployment, err := kc.Core().ReplicationControllers(t.Namespace).Get(latestDeploymentName, metav1.GetOptions{})
188-
if err != nil {
189-
return fallback, err
190-
}
191-
192-
fallback = deployment.Spec.Template
193-
194-
pods, err := kc.Core().Pods(deployment.Namespace).List(metav1.ListOptions{LabelSelector: labels.SelectorFromSet(deployment.Spec.Selector).String()})
195-
if err != nil {
196-
return fallback, err
197-
}
198-
199-
for i := range pods.Items {
200-
pod := &pods.Items[i]
201-
if fallback == nil || pod.CreationTimestamp.Before(fallback.CreationTimestamp) {
202-
fallback = &api.PodTemplateSpec{
203-
ObjectMeta: pod.ObjectMeta,
204-
Spec: pod.Spec,
205-
}
206-
}
207-
}
208-
return fallback, nil
209-
210-
default:
211-
pod, err := f.AttachablePodForObject(object, 1*time.Minute)
212-
if pod != nil {
213-
return &api.PodTemplateSpec{
214-
ObjectMeta: pod.ObjectMeta,
215-
Spec: pod.Spec,
216-
}, err
217-
}
218-
switch t := object.(type) {
219-
case *api.ReplicationController:
220-
return t.Spec.Template, err
221-
case *extensions.ReplicaSet:
222-
return &t.Spec.Template, err
223-
case *extensions.DaemonSet:
224-
return &t.Spec.Template, err
225-
case *batch.Job:
226-
return &t.Spec.Template, err
227-
}
228-
return nil, err
229-
}
230-
}
231-
232149
func (f *Factory) PodForResource(resource string, timeout time.Duration) (string, error) {
233150
sortBy := func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) }
234151
namespace, _, err := f.DefaultNamespace()

pkg/cmd/util/clientcmd/factory_object_mapping.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
appsmanualclient "github.com/openshift/origin/pkg/apps/client/internalversion"
3232
deploycmd "github.com/openshift/origin/pkg/apps/cmd"
3333
appsclient "github.com/openshift/origin/pkg/apps/generated/internalclientset"
34+
deployutil "github.com/openshift/origin/pkg/apps/util"
3435
authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization"
3536
authorizationreaper "github.com/openshift/origin/pkg/authorization/reaper"
3637
buildapi "github.com/openshift/origin/pkg/build/apis/build"
@@ -39,6 +40,7 @@ import (
3940
buildclient "github.com/openshift/origin/pkg/build/generated/internalclientset"
4041
buildutil "github.com/openshift/origin/pkg/build/util"
4142
configcmd "github.com/openshift/origin/pkg/config/cmd"
43+
imageapi "github.com/openshift/origin/pkg/image/apis/image"
4244
"github.com/openshift/origin/pkg/oc/cli/describe"
4345
userapi "github.com/openshift/origin/pkg/user/apis/user"
4446
authenticationreaper "github.com/openshift/origin/pkg/user/reaper"
@@ -351,6 +353,74 @@ func (f *ring1Factory) StatusViewer(mapping *meta.RESTMapping) (kubectl.StatusVi
351353
return f.kubeObjectMappingFactory.StatusViewer(mapping)
352354
}
353355

356+
// ApproximatePodTemplateForObject returns a pod template object for the provided source.
357+
// It may return both an error and a object. It attempt to return the best possible template
358+
// available at the current time.
359+
func (f *ring1Factory) ApproximatePodTemplateForObject(object runtime.Object) (*kapi.PodTemplateSpec, error) {
360+
switch t := object.(type) {
361+
case *imageapi.ImageStreamTag:
362+
// create a minimal pod spec that uses the image referenced by the istag without any introspection
363+
// it possible that we could someday do a better job introspecting it
364+
return &kapi.PodTemplateSpec{
365+
Spec: kapi.PodSpec{
366+
RestartPolicy: kapi.RestartPolicyNever,
367+
Containers: []kapi.Container{
368+
{Name: "container-00", Image: t.Image.DockerImageReference},
369+
},
370+
},
371+
}, nil
372+
case *imageapi.ImageStreamImage:
373+
// create a minimal pod spec that uses the image referenced by the istag without any introspection
374+
// it possible that we could someday do a better job introspecting it
375+
return &kapi.PodTemplateSpec{
376+
Spec: kapi.PodSpec{
377+
RestartPolicy: kapi.RestartPolicyNever,
378+
Containers: []kapi.Container{
379+
{Name: "container-00", Image: t.Image.DockerImageReference},
380+
},
381+
},
382+
}, nil
383+
case *deployapi.DeploymentConfig:
384+
fallback := t.Spec.Template
385+
386+
kc, err := f.clientAccessFactory.ClientSet()
387+
if err != nil {
388+
return fallback, err
389+
}
390+
391+
latestDeploymentName := deployutil.LatestDeploymentNameForConfig(t)
392+
deployment, err := kc.Core().ReplicationControllers(t.Namespace).Get(latestDeploymentName, metav1.GetOptions{})
393+
if err != nil {
394+
return fallback, err
395+
}
396+
397+
fallback = deployment.Spec.Template
398+
399+
pods, err := kc.Core().Pods(deployment.Namespace).List(metav1.ListOptions{LabelSelector: labels.SelectorFromSet(deployment.Spec.Selector).String()})
400+
if err != nil {
401+
return fallback, err
402+
}
403+
404+
// If we have any pods available, find the newest
405+
// pod with regards to our most recent deployment.
406+
// If the fallback PodTemplateSpec is nil, prefer
407+
// the newest pod available.
408+
for i := range pods.Items {
409+
pod := &pods.Items[i]
410+
if fallback == nil || pod.CreationTimestamp.Before(fallback.CreationTimestamp) {
411+
fallback = &kapi.PodTemplateSpec{
412+
ObjectMeta: pod.ObjectMeta,
413+
Spec: pod.Spec,
414+
}
415+
}
416+
}
417+
return fallback, nil
418+
419+
default:
420+
return f.kubeObjectMappingFactory.ApproximatePodTemplateForObject(object)
421+
}
422+
}
423+
354424
func (f *ring1Factory) AttachablePodForObject(object runtime.Object, timeout time.Duration) (*kapi.Pod, error) {
355425
switch t := object.(type) {
356426
case *deployapi.DeploymentConfig:

test/cmd/debug.sh

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,45 @@ os::cmd::expect_success_and_not_text "oc debug -f examples/hello-openshift/hello
3333
os::cmd::expect_success_and_not_text "oc debug -f examples/hello-openshift/hello-pod.json -o yaml -- /bin/env" 'tty'
3434
# TODO: write a test that emulates a TTY to verify the correct defaulting of what the pod is created
3535

36+
# Ensure debug does not depend on a container actually existing for the selected resource.
37+
# The command should not hang waiting for an attachable pod. Timeout each cmd after 10s.
38+
os::cmd::expect_success 'oc create -f test/integration/testdata/test-replication-controller.yaml'
39+
os::cmd::expect_success 'oc scale --replicas=0 rc/test-replication-controller'
40+
os::cmd::expect_success_and_text "oc debug --request-timeout=10s -c ruby-helloworld --one-container rc/test-replication-controller -o jsonpath='{.metadata.name}'" 'test-replication-controller-debug'
41+
42+
os::cmd::expect_success 'oc scale --replicas=0 dc/test-deployment-config'
43+
os::cmd::expect_success_and_text "oc debug --request-timeout=10s -c ruby-helloworld --one-container dc/test-deployment-config -o jsonpath='{.metadata.name}'" 'test-deployment-config'
44+
45+
os::cmd::expect_success 'oc create -f - >> cat << __EOF__
46+
apiVersion: extensions/v1beta1
47+
kind: Deployment
48+
metadata:
49+
name: test-deployment
50+
labels:
51+
deployment: test-deployment
52+
spec:
53+
replicas: 0
54+
selector:
55+
matchLabels:
56+
deployment: test-deployment
57+
template:
58+
metadata:
59+
labels:
60+
deployment: test-deployment
61+
name: test-deployment
62+
spec:
63+
containers:
64+
- name: ruby-helloworld
65+
image: openshift/origin-pod
66+
imagePullPolicy: IfNotPresent
67+
resources: {}
68+
status: {}
69+
__EOF__'
70+
os::cmd::expect_success_and_text "oc debug --request-timeout=10s -c ruby-helloworld --one-container deploy/test-deployment -o jsonpath='{.metadata.name}'" 'test-deployment-debug'
71+
72+
# re-scale existing resources
73+
os::cmd::expect_success 'oc scale --replicas=1 dc/test-deployment-config'
74+
3675
os::cmd::expect_success 'oc create -f examples/image-streams/image-streams-centos7.json'
3776
os::cmd::try_until_success 'oc get imagestreamtags wildfly:latest'
3877
os::cmd::expect_success_and_text "oc debug istag/wildfly:latest -o yaml" 'image: openshift/wildfly-101-centos7'

vendor/k8s.io/kubernetes/pkg/kubectl/cmd/testing/fake.go

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/factory.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/k8s.io/kubernetes/pkg/kubectl/cmd/util/factory_object_mapping.go

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)