diff --git a/pkg/object/objmetadata.go b/pkg/object/objmetadata.go index b5bfe99..caf3394 100644 --- a/pkg/object/objmetadata.go +++ b/pkg/object/objmetadata.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation" "k8s.io/cli-runtime/pkg/resource" ) @@ -45,10 +46,15 @@ func CreateObjMetadata(namespace string, name string, gk schema.GroupKind) (*Obj // Namespace can be empty, but name cannot. name = strings.TrimSpace(name) if name == "" { - return nil, fmt.Errorf("empty name for inventory object") + return nil, fmt.Errorf("empty name for object") + } + // Manually validate name, since by the time k8s reports the error + // the invalid name has already been encoded into the inventory object. + if !validateNameChars(name) { + return nil, fmt.Errorf("invalid characters in object name: %s", name) } if gk.Empty() { - return nil, fmt.Errorf("empty GroupKind for inventory object") + return nil, fmt.Errorf("empty GroupKind for object") } return &ObjMetadata{ @@ -58,6 +64,23 @@ func CreateObjMetadata(namespace string, name string, gk schema.GroupKind) (*Obj }, nil } +// validateNameChars returns false if the passed name string contains +// any invalid characters; true otherwise. The allowed characters for +// a Kubernetes resource name are: +// +// Most resource types require a name that can be used as a DNS label name +// as defined in RFC 1123. This means the name must: +// +// * contain no more than 253 characters +// * contain only lowercase alphanumeric characters, '-' +// * start with an alphanumeric character +// * end with an alphanumeric character +// +func validateNameChars(name string) bool { + errs := validation.IsDNS1123Subdomain(name) + return len(errs) == 0 +} + // ParseObjMetadata takes a string, splits it into its five fields, // and returns a pointer to an ObjMetadata struct storing the // five fields. Example inventory string: diff --git a/pkg/object/objmetadata_test.go b/pkg/object/objmetadata_test.go index 5aa5756..eb51b89 100644 --- a/pkg/object/objmetadata_test.go +++ b/pkg/object/objmetadata_test.go @@ -56,13 +56,46 @@ func TestCreateObjMetadata(t *testing.T) { expected: "", isError: true, }, + // Error with invalid name characters "_". + { + namespace: "test-namespace", + name: "test_name", // Invalid "_" character + gk: schema.GroupKind{ + Group: "apps", + Kind: "ReplicaSet", + }, + expected: "", + isError: true, + }, + // Error name not starting with alphanumeric char + { + namespace: "test-namespace", + name: "-test", + gk: schema.GroupKind{ + Group: "apps", + Kind: "ReplicaSet", + }, + expected: "", + isError: true, + }, + // Error name not ending with alphanumeric char + { + namespace: "test-namespace", + name: "test-", + gk: schema.GroupKind{ + Group: "apps", + Kind: "ReplicaSet", + }, + expected: "", + isError: true, + }, } for _, test := range tests { inv, err := CreateObjMetadata(test.namespace, test.name, test.gk) if !test.isError { if err != nil { - t.Errorf("Error creating inventory when it should have worked.") + t.Errorf("Error creating ObjMetadata when it should have worked.") } else if test.expected != inv.String() { t.Errorf("Expected inventory (%s) != created inventory(%s)\n", test.expected, inv.String()) }