diff --git a/flux.go b/flux.go index cd2f812c0..168d365f5 100644 --- a/flux.go +++ b/flux.go @@ -13,9 +13,14 @@ import ( var ( ErrInvalidServiceID = errors.New("invalid service ID") - LegacyServiceIDRegexp = regexp.MustCompile("^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)$") - ResourceIDRegexp = regexp.MustCompile("^([a-zA-Z0-9_-]+):([a-zA-Z0-9_-]+)/([a-zA-Z0-9_.-]+)$") - UnqualifiedResourceIDRegexp = regexp.MustCompile("^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_.-]+)$") + LegacyServiceIDRegexp = regexp.MustCompile("^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)$") + // The namespace and name commponents are (apparently + // non-normatively) defined in + // https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture/identifiers.md + // In practice, more punctuation is used than allowed there; + // specifically, people use underscores as well as dashes and dots, and in names, colons. + ResourceIDRegexp = regexp.MustCompile("^([a-zA-Z0-9_-]+):([a-zA-Z0-9_-]+)/([a-zA-Z0-9_.:-]+)$") + UnqualifiedResourceIDRegexp = regexp.MustCompile("^([a-zA-Z0-9_-]+)/([a-zA-Z0-9_.:-]+)$") ) // ResourceID is an opaque type which uniquely identifies a resource in an diff --git a/resourceid_test.go b/resourceid_test.go new file mode 100644 index 000000000..49616d451 --- /dev/null +++ b/resourceid_test.go @@ -0,0 +1,38 @@ +package flux + +import ( + "testing" +) + +func TestResourceIDParsing(t *testing.T) { + type test struct { + name, id string + } + valid := []test{ + {"full", "namespace:kind/name"}, + {"legacy", "namespace/service"}, + {"dots", "namespace:kind/name.with.dots"}, + {"colons", "namespace:kind/name:with:colons"}, + {"punctuation in general", "name-space:ki_nd/punc_tu:a.tion-rules"}, + } + invalid := []test{ + {"unqualified", "justname"}, + {"dots in namespace", "name.space:kind/name"}, + {"too many colons", "namespace:kind:name"}, + } + + for _, tc := range valid { + t.Run(tc.name, func(t *testing.T) { + if _, err := ParseResourceID(tc.id); err != nil { + t.Error(err) + } + }) + } + for _, tc := range invalid { + t.Run(tc.name, func(t *testing.T) { + if _, err := ParseResourceID(tc.id); err == nil { + t.Errorf("expected %q to be considered invalid", tc.id) + } + }) + } +}