mirror of
https://github.com/kubernetes/kubectl.git
synced 2026-05-28 04:35:50 -04:00
Automated cherry pick of #130503: Unhandled panic crash on rollout_history printer.PrintObj (#131496)
* Change: Handling nil runtime.Object Signed-off-by: Taha Farahani <tahacodes@proton.me> * Change: Return only if there is error in rollout_history Signed-off-by: Taha Farahani <tahacodes@proton.me> * Change: Return the unknown revision error directly in rollout_history.go Signed-off-by: Taha Farahani <tahacodes@proton.me> * Change: Remove unintended newline Signed-off-by: Taha Farahani <tahacodes@proton.me> * Change: Using go idiomatic way for checking if historyInfo[o.Revision] exists Signed-off-by: Taha Farahani <tahacodes@proton.me> * Change: Remove 'error:' from returned error message in rollout_history.go Signed-off-by: Taha Farahani <tahacodes@proton.me> * Change: Check for printer.PrintObj returned err Signed-off-by: Taha Farahani <tahacodes@proton.me> * Change: Add TestRolloutHistoryErrors test Signed-off-by: Taha Farahani <tahacodes@proton.me> * Change: Simple typo fix on Complete() function description Signed-off-by: Taha Farahani <tahacodes@proton.me> * Change: Checking for error on o.Complete in TestRolloutHistoryErrors Signed-off-by: Taha Farahani <tahacodes@proton.me> --------- Signed-off-by: Taha Farahani <tahacodes@proton.me> Kubernetes-commit: cce99a8c73a32c6dff31768c4757968440ef91c3
This commit is contained in:
parent
ce68e04d46
commit
343265002b
4 changed files with 95 additions and 5 deletions
2
go.mod
2
go.mod
|
|
@ -30,7 +30,7 @@ require (
|
|||
golang.org/x/sys v0.31.0
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0
|
||||
k8s.io/api v0.0.0-20250411021314-16cedc7a66ae
|
||||
k8s.io/apimachinery v0.0.0-20250411020758-955939ffb819
|
||||
k8s.io/apimachinery v0.0.0-20250513120515-173776a0582d
|
||||
k8s.io/cli-runtime v0.0.0-20250411033212-28113218b536
|
||||
k8s.io/client-go v0.0.0-20250411022055-ecbbb0606499
|
||||
k8s.io/component-base v0.0.0-20250411023622-8e0b9e84850c
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -198,8 +198,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.0.0-20250411021314-16cedc7a66ae h1:vrcVMXGw+KvS3H1ADWBP3OnVjHD8POhZ2TTOhVZSrwU=
|
||||
k8s.io/api v0.0.0-20250411021314-16cedc7a66ae/go.mod h1:qoOZZa+05qIrm+4Sofop9RA1fVI3J149R2j6jm9m3VQ=
|
||||
k8s.io/apimachinery v0.0.0-20250411020758-955939ffb819 h1:m17pTPsx0pRmIhMKKtNBYrT1LitJNib+nLiuIc8Fvk8=
|
||||
k8s.io/apimachinery v0.0.0-20250411020758-955939ffb819/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/apimachinery v0.0.0-20250513120515-173776a0582d h1:buOcd3rCTo99nqYltxp0diwOlu3UosLheP/6o6MxnuY=
|
||||
k8s.io/apimachinery v0.0.0-20250513120515-173776a0582d/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/cli-runtime v0.0.0-20250411033212-28113218b536 h1:aRNcqamTSktUBoPyeK8sAGRCFstUhOXozbXlGOpgNI4=
|
||||
k8s.io/cli-runtime v0.0.0-20250411033212-28113218b536/go.mod h1:uyQE9Pml9RhjjShCJsPCN7kRPJ78VRXdMVqupw70/0A=
|
||||
k8s.io/client-go v0.0.0-20250411022055-ecbbb0606499 h1:EeffLakm6zD0zaErZUz+i6YubAlH+1a+MFp2cgg/cIQ=
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ func NewCmdRolloutHistory(f cmdutil.Factory, streams genericiooptions.IOStreams)
|
|||
return cmd
|
||||
}
|
||||
|
||||
// Complete completes al the required options
|
||||
// Complete completes all the required options
|
||||
func (o *RolloutHistoryOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
o.Resources = args
|
||||
|
||||
|
|
@ -177,7 +177,15 @@ func (o *RolloutHistoryOptions) Run() error {
|
|||
}
|
||||
|
||||
if o.Revision > 0 {
|
||||
printer.PrintObj(historyInfo[o.Revision], o.Out)
|
||||
// Ensure the specified revision exists before printing
|
||||
revision, exists := historyInfo[o.Revision]
|
||||
if !exists {
|
||||
return fmt.Errorf("unable to find the specified revision")
|
||||
}
|
||||
|
||||
if err := printer.PrintObj(revision, o.Out); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
sortedKeys := make([]int64, 0, len(historyInfo))
|
||||
for k := range historyInfo {
|
||||
|
|
|
|||
|
|
@ -401,6 +401,88 @@ replicaset.apps/rev2
|
|||
}
|
||||
}
|
||||
|
||||
func TestRolloutHistoryErrors(t *testing.T) {
|
||||
ns := scheme.Codecs.WithoutConversion()
|
||||
tf := cmdtesting.NewTestFactory().WithNamespace("test")
|
||||
defer tf.Cleanup()
|
||||
|
||||
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
encoder := ns.EncoderForVersion(info.Serializer, rolloutPauseGroupVersionEncoder)
|
||||
|
||||
tf.Client = &RolloutPauseRESTClient{
|
||||
RESTClient: &fake.RESTClient{
|
||||
GroupVersion: rolloutPauseGroupVersionEncoder,
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == "/namespaces/test/deployments/foo" && m == "GET":
|
||||
responseDeployment := &appsv1.Deployment{}
|
||||
responseDeployment.Name = "foo"
|
||||
body := io.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(encoder, responseDeployment))))
|
||||
return &http.Response{StatusCode: http.StatusOK, Header: cmdtesting.DefaultHeader(), Body: body}, nil
|
||||
default:
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
revision int64
|
||||
outputFormat string
|
||||
expectedError string
|
||||
}{
|
||||
"get non-existing revision as yaml": {
|
||||
revision: 999,
|
||||
outputFormat: "yaml",
|
||||
expectedError: "unable to find the specified revision",
|
||||
},
|
||||
"get non-existing revision as json": {
|
||||
revision: 999,
|
||||
outputFormat: "json",
|
||||
expectedError: "unable to find the specified revision",
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
fhv := setupFakeHistoryViewer(t)
|
||||
fhv.getHistoryFn = func(namespace, name string) (map[int64]runtime.Object, error) {
|
||||
return map[int64]runtime.Object{
|
||||
1: &appsv1.ReplicaSet{ObjectMeta: v1.ObjectMeta{Name: "rev1"}},
|
||||
2: &appsv1.ReplicaSet{ObjectMeta: v1.ObjectMeta{Name: "rev2"}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
streams := genericiooptions.NewTestIOStreamsDiscard()
|
||||
o := NewRolloutHistoryOptions(streams)
|
||||
|
||||
printFlags := &genericclioptions.PrintFlags{
|
||||
JSONYamlPrintFlags: &genericclioptions.JSONYamlPrintFlags{
|
||||
ShowManagedFields: true,
|
||||
},
|
||||
OutputFormat: &tc.outputFormat,
|
||||
OutputFlagSpecified: func() bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
|
||||
o.PrintFlags = printFlags
|
||||
o.Revision = tc.revision
|
||||
|
||||
if err := o.Complete(tf, nil, []string{"deployment/foo"}); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err := o.Run()
|
||||
if err != nil && err.Error() != tc.expectedError {
|
||||
t.Fatalf("expected '%s' error, but got: %v", tc.expectedError, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
opts := RolloutHistoryOptions{
|
||||
Revision: 0,
|
||||
|
|
|
|||
Loading…
Reference in a new issue