Skip to content

Commit 3432650

Browse files
Taha Farahanik8s-publishing-bot
authored andcommitted
Automated cherry pick of #130503: Unhandled panic crash on rollout_history printer.PrintObj (#131496)
* Change: Handling nil runtime.Object Signed-off-by: Taha Farahani <[email protected]> * Change: Return only if there is error in rollout_history Signed-off-by: Taha Farahani <[email protected]> * Change: Return the unknown revision error directly in rollout_history.go Signed-off-by: Taha Farahani <[email protected]> * Change: Remove unintended newline Signed-off-by: Taha Farahani <[email protected]> * Change: Using go idiomatic way for checking if historyInfo[o.Revision] exists Signed-off-by: Taha Farahani <[email protected]> * Change: Remove 'error:' from returned error message in rollout_history.go Signed-off-by: Taha Farahani <[email protected]> * Change: Check for printer.PrintObj returned err Signed-off-by: Taha Farahani <[email protected]> * Change: Add TestRolloutHistoryErrors test Signed-off-by: Taha Farahani <[email protected]> * Change: Simple typo fix on Complete() function description Signed-off-by: Taha Farahani <[email protected]> * Change: Checking for error on o.Complete in TestRolloutHistoryErrors Signed-off-by: Taha Farahani <[email protected]> --------- Signed-off-by: Taha Farahani <[email protected]> Kubernetes-commit: cce99a8c73a32c6dff31768c4757968440ef91c3
1 parent ce68e04 commit 3432650

File tree

4 files changed

+95
-5
lines changed

4 files changed

+95
-5
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ require (
3030
golang.org/x/sys v0.31.0
3131
gopkg.in/evanphx/json-patch.v4 v4.12.0
3232
k8s.io/api v0.0.0-20250411021314-16cedc7a66ae
33-
k8s.io/apimachinery v0.0.0-20250411020758-955939ffb819
33+
k8s.io/apimachinery v0.0.0-20250513120515-173776a0582d
3434
k8s.io/cli-runtime v0.0.0-20250411033212-28113218b536
3535
k8s.io/client-go v0.0.0-20250411022055-ecbbb0606499
3636
k8s.io/component-base v0.0.0-20250411023622-8e0b9e84850c

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
198198
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
199199
k8s.io/api v0.0.0-20250411021314-16cedc7a66ae h1:vrcVMXGw+KvS3H1ADWBP3OnVjHD8POhZ2TTOhVZSrwU=
200200
k8s.io/api v0.0.0-20250411021314-16cedc7a66ae/go.mod h1:qoOZZa+05qIrm+4Sofop9RA1fVI3J149R2j6jm9m3VQ=
201-
k8s.io/apimachinery v0.0.0-20250411020758-955939ffb819 h1:m17pTPsx0pRmIhMKKtNBYrT1LitJNib+nLiuIc8Fvk8=
202-
k8s.io/apimachinery v0.0.0-20250411020758-955939ffb819/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
201+
k8s.io/apimachinery v0.0.0-20250513120515-173776a0582d h1:buOcd3rCTo99nqYltxp0diwOlu3UosLheP/6o6MxnuY=
202+
k8s.io/apimachinery v0.0.0-20250513120515-173776a0582d/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
203203
k8s.io/cli-runtime v0.0.0-20250411033212-28113218b536 h1:aRNcqamTSktUBoPyeK8sAGRCFstUhOXozbXlGOpgNI4=
204204
k8s.io/cli-runtime v0.0.0-20250411033212-28113218b536/go.mod h1:uyQE9Pml9RhjjShCJsPCN7kRPJ78VRXdMVqupw70/0A=
205205
k8s.io/client-go v0.0.0-20250411022055-ecbbb0606499 h1:EeffLakm6zD0zaErZUz+i6YubAlH+1a+MFp2cgg/cIQ=

pkg/cmd/rollout/rollout_history.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func NewCmdRolloutHistory(f cmdutil.Factory, streams genericiooptions.IOStreams)
105105
return cmd
106106
}
107107

108-
// Complete completes al the required options
108+
// Complete completes all the required options
109109
func (o *RolloutHistoryOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
110110
o.Resources = args
111111

@@ -177,7 +177,15 @@ func (o *RolloutHistoryOptions) Run() error {
177177
}
178178

179179
if o.Revision > 0 {
180-
printer.PrintObj(historyInfo[o.Revision], o.Out)
180+
// Ensure the specified revision exists before printing
181+
revision, exists := historyInfo[o.Revision]
182+
if !exists {
183+
return fmt.Errorf("unable to find the specified revision")
184+
}
185+
186+
if err := printer.PrintObj(revision, o.Out); err != nil {
187+
return err
188+
}
181189
} else {
182190
sortedKeys := make([]int64, 0, len(historyInfo))
183191
for k := range historyInfo {

pkg/cmd/rollout/rollout_history_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,88 @@ replicaset.apps/rev2
401401
}
402402
}
403403

404+
func TestRolloutHistoryErrors(t *testing.T) {
405+
ns := scheme.Codecs.WithoutConversion()
406+
tf := cmdtesting.NewTestFactory().WithNamespace("test")
407+
defer tf.Cleanup()
408+
409+
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
410+
encoder := ns.EncoderForVersion(info.Serializer, rolloutPauseGroupVersionEncoder)
411+
412+
tf.Client = &RolloutPauseRESTClient{
413+
RESTClient: &fake.RESTClient{
414+
GroupVersion: rolloutPauseGroupVersionEncoder,
415+
NegotiatedSerializer: ns,
416+
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
417+
switch p, m := req.URL.Path, req.Method; {
418+
case p == "/namespaces/test/deployments/foo" && m == "GET":
419+
responseDeployment := &appsv1.Deployment{}
420+
responseDeployment.Name = "foo"
421+
body := io.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, responseDeployment))))
422+
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil
423+
default:
424+
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
425+
return nil, nil
426+
}
427+
}),
428+
},
429+
}
430+
431+
testCases := map[string]struct {
432+
revision int64
433+
outputFormat string
434+
expectedError string
435+
}{
436+
"get non-existing revision as yaml": {
437+
revision: 999,
438+
outputFormat: "yaml",
439+
expectedError: "unable to find the specified revision",
440+
},
441+
"get non-existing revision as json": {
442+
revision: 999,
443+
outputFormat: "json",
444+
expectedError: "unable to find the specified revision",
445+
},
446+
}
447+
448+
for name, tc := range testCases {
449+
t.Run(name, func(t *testing.T) {
450+
fhv := setupFakeHistoryViewer(t)
451+
fhv.getHistoryFn = func(namespace, name string) (map[int64]runtime.Object, error) {
452+
return map[int64]runtime.Object{
453+
1: &appsv1.ReplicaSet{ObjectMeta: v1.ObjectMeta{Name: "rev1"}},
454+
2: &appsv1.ReplicaSet{ObjectMeta: v1.ObjectMeta{Name: "rev2"}},
455+
}, nil
456+
}
457+
458+
streams := genericiooptions.NewTestIOStreamsDiscard()
459+
o := NewRolloutHistoryOptions(streams)
460+
461+
printFlags := &genericclioptions.PrintFlags{
462+
JSONYamlPrintFlags: &genericclioptions.JSONYamlPrintFlags{
463+
ShowManagedFields: true,
464+
},
465+
OutputFormat: &tc.outputFormat,
466+
OutputFlagSpecified: func() bool {
467+
return true
468+
},
469+
}
470+
471+
o.PrintFlags = printFlags
472+
o.Revision = tc.revision
473+
474+
if err := o.Complete(tf, nil, []string{"deployment/foo"}); err != nil {
475+
t.Fatalf("unexpected error: %v", err)
476+
}
477+
478+
err := o.Run()
479+
if err != nil && err.Error() != tc.expectedError {
480+
t.Fatalf("expected '%s' error, but got: %v", tc.expectedError, err)
481+
}
482+
})
483+
}
484+
}
485+
404486
func TestValidate(t *testing.T) {
405487
opts := RolloutHistoryOptions{
406488
Revision: 0,

0 commit comments

Comments
 (0)