mirror of https://github.com/k3s-io/k3s
Don't use json.Marshal when printing error bodies
Internal types panic when json.Marshal is called to prevent accidental use.pull/6/head
parent
1ad5cea24e
commit
45ec4e1151
|
@ -306,7 +306,7 @@ func TestValidateObjectMetaUpdatePreventsDeletionFieldMutation(t *testing.T) {
|
||||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1"},
|
||||||
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
New: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||||
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
ExpectedNew: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||||
ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: \"1970-01-01T00:16:40Z\": field is immutable; may only be changed via deletion"},
|
ExpectedErrs: []string{"field.deletionTimestamp: Invalid value: 1970-01-01 00:16:40 +0000 UTC: field is immutable; may only be changed via deletion"},
|
||||||
},
|
},
|
||||||
"invalid clear deletionTimestamp": {
|
"invalid clear deletionTimestamp": {
|
||||||
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
Old: metav1.ObjectMeta{Name: "test", ResourceVersion: "1", DeletionTimestamp: &now},
|
||||||
|
|
|
@ -17,8 +17,8 @@ limitations under the License.
|
||||||
package field
|
package field
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
|
@ -49,14 +49,30 @@ func (v *Error) ErrorBody() string {
|
||||||
case ErrorTypeRequired, ErrorTypeForbidden, ErrorTypeTooLong, ErrorTypeInternal:
|
case ErrorTypeRequired, ErrorTypeForbidden, ErrorTypeTooLong, ErrorTypeInternal:
|
||||||
s = fmt.Sprintf("%s", v.Type)
|
s = fmt.Sprintf("%s", v.Type)
|
||||||
default:
|
default:
|
||||||
var bad string
|
value := v.BadValue
|
||||||
badBytes, err := json.Marshal(v.BadValue)
|
if reflect.TypeOf(value).Kind() == reflect.Ptr {
|
||||||
if err != nil {
|
if reflectValue := reflect.ValueOf(value); reflectValue.IsNil() {
|
||||||
bad = err.Error()
|
value = "null"
|
||||||
} else {
|
} else {
|
||||||
bad = string(badBytes)
|
value = reflectValue.Elem().Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch t := value.(type) {
|
||||||
|
case int64, int32, float64, float32, bool:
|
||||||
|
// use simple printer for simple types
|
||||||
|
s = fmt.Sprintf("%s: %v", v.Type, value)
|
||||||
|
case string:
|
||||||
|
s = fmt.Sprintf("%s: %q", v.Type, t)
|
||||||
|
case fmt.Stringer:
|
||||||
|
// anything that defines String() is better than raw struct
|
||||||
|
s = fmt.Sprintf("%s: %s", v.Type, t.String())
|
||||||
|
default:
|
||||||
|
// fallback to raw struct
|
||||||
|
// TODO: internal types have panic guards against json.Marshalling to prevent
|
||||||
|
// accidental use of internal types in external serialized form. For now, use
|
||||||
|
// %#v, although it would be better to show a more expressive output in the future
|
||||||
|
s = fmt.Sprintf("%s: %#v", v.Type, value)
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s: %s", v.Type, bad)
|
|
||||||
}
|
}
|
||||||
if len(v.Detail) != 0 {
|
if len(v.Detail) != 0 {
|
||||||
s += fmt.Sprintf(": %s", v.Detail)
|
s += fmt.Sprintf(": %s", v.Detail)
|
||||||
|
|
|
@ -90,7 +90,8 @@ func TestErrorUsefulMessage(t *testing.T) {
|
||||||
for _, part := range []string{
|
for _, part := range []string{
|
||||||
"foo", ErrorTypeInvalid.String(),
|
"foo", ErrorTypeInvalid.String(),
|
||||||
"Baz", "Qux", "Inner", "KV", "detail",
|
"Baz", "Qux", "Inner", "KV", "detail",
|
||||||
"1", "aoeu", "asdf", "Billy", "2",
|
"1", "aoeu", "Billy", "2",
|
||||||
|
// "asdf", TODO: reenable once we have a better nested printer
|
||||||
} {
|
} {
|
||||||
if !strings.Contains(s, part) {
|
if !strings.Contains(s, part) {
|
||||||
t.Errorf("error message did not contain expected part '%v'", part)
|
t.Errorf("error message did not contain expected part '%v'", part)
|
||||||
|
|
Loading…
Reference in New Issue