Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api-server): contain matches on name and tags #5606

Merged
merged 1 commit into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 29 additions & 22 deletions api/mesh/v1alpha1/dataplane_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,28 +189,27 @@ func (n *Dataplane_Networking) GetHealthyInbounds() (inbounds []*Dataplane_Netwo

// Matches is simply an alias for MatchTags to make source code more aesthetic.
func (d *Dataplane) Matches(selector TagSelector) bool {
if d != nil {
return d.MatchTags(selector)
if d == nil {
return false
}
return false
}

func (d *Dataplane) MatchTags(selector TagSelector) bool {
for _, inbound := range d.GetNetworking().GetInbound() {
if inbound.MatchTags(selector) {
if selector.Matches(inbound.Tags) {
return true
}
}
if d.GetNetworking().GetGateway() != nil {
if d.Networking.Gateway.MatchTags(selector) {
return selector.Matches(d.GetNetworking().GetGateway().GetTags())
}

func (d *Dataplane) MatchTagsFuzzy(selector TagSelector) bool {
if d == nil {
return false
}
for _, inbound := range d.GetNetworking().GetInbound() {
if selector.MatchesFuzzy(inbound.Tags) {
return true
}
}
return false
}

func (d *Dataplane_Networking_Gateway) MatchTags(selector TagSelector) bool {
return selector.Matches(d.Tags)
return selector.MatchesFuzzy(d.GetNetworking().GetGateway().GetTags())
}

// GetService returns a service represented by this inbound interface.
Expand All @@ -235,14 +234,6 @@ func (d *Dataplane_Networking_Inbound) GetProtocol() string {
return d.Tags[ProtocolTag]
}

func (d *Dataplane_Networking_Inbound) MatchTags(selector TagSelector) bool {
return selector.Matches(d.Tags)
}

func (d *Dataplane_Networking_Outbound) MatchTags(selector TagSelector) bool {
return selector.Matches(d.GetTagsIncludingLegacy())
}

// GetTagsIncludingLegacy returns tags but taking on account old legacy format of "kuma.io/service" field in outbound
// Remove it and migrate to GetTags() once "kuma.io/service" field is removed.
func (d *Dataplane_Networking_Outbound) GetTagsIncludingLegacy() map[string]string {
Expand Down Expand Up @@ -274,6 +265,22 @@ func (s TagSelector) Matches(tags map[string]string) bool {
return true
}

func (s TagSelector) MatchesFuzzy(tags map[string]string) bool {
if len(s) == 0 {
return true
}
for tag, value := range s {
inboundVal, exist := tags[tag]
if !exist {
return false
}
if !strings.Contains(inboundVal, value) && value != MatchAllTag {
return false
}
}
return true
}

func (s TagSelector) Rank() (r TagSelectorRank) {
for _, value := range s {
if value == MatchAllTag {
Expand Down
89 changes: 0 additions & 89 deletions api/mesh/v1alpha1/dataplane_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,49 +180,6 @@ var _ = Describe("Dataplane_Networking", func() {
})
})

var _ = Describe("Dataplane_Networking_Outbound", func() {
type testCase struct {
serviceTag string
selector TagSelector
expectedMatch bool
}
DescribeTable("MatchTags()",
func(given testCase) {
// given
outbound := Dataplane_Networking_Outbound{
Service: given.serviceTag,
}

// when
matched := outbound.MatchTags(given.selector)

// then
Expect(matched).To(Equal(given.expectedMatch))
},
Entry("it should match *", testCase{
serviceTag: "backend",
selector: map[string]string{
"kuma.io/service": "*",
},
expectedMatch: true,
}),
Entry("it should match service", testCase{
serviceTag: "backend",
selector: map[string]string{
"kuma.io/service": "backend",
},
expectedMatch: true,
}),
Entry("it shouldn't match tag other than service", testCase{
serviceTag: "backend",
selector: map[string]string{
"version": "1.0",
},
expectedMatch: false,
}),
)
})

var _ = Describe("Dataplane_Networking_Inbound", func() {

Describe("GetService()", func() {
Expand Down Expand Up @@ -326,29 +283,6 @@ var _ = Describe("Dataplane with inbound", func() {
Expect(tags.Values("role")).To(Equal([]string{"metrics"}))
})
})

Describe("MatchTags()", func() {
It("should match any inbound", func() {
// when
selector := TagSelector{
"kuma.io/service": "backend",
"version": "v1",
}

// then
Expect(d.MatchTags(selector)).To(BeTrue())
})

It("should not match if all inbounds did not match", func() {
// when
selector := TagSelector{
"kuma.io/service": "unknown",
}

// then
Expect(d.MatchTags(selector)).To(BeFalse())
})
})
})

var _ = Describe("Dataplane classification", func() {
Expand Down Expand Up @@ -424,29 +358,6 @@ var _ = Describe("Dataplane with gateway", func() {
Expect(tags.Values("kuma.io/service")).To(Equal([]string{"backend"}))
})
})

Describe("MatchTags()", func() {
It("should match gateway", func() {
// when
selector := TagSelector{
"kuma.io/service": "backend",
"version": "v1",
}

// then
Expect(d.MatchTags(selector)).To(BeTrue())
})

It("should not match if gateway did not match", func() {
// when
selector := TagSelector{
"kuma.io/service": "unknown",
}

// then
Expect(d.MatchTags(selector)).To(BeFalse())
})
})
})

var _ = Describe("TagSelector", func() {
Expand Down
8 changes: 4 additions & 4 deletions pkg/api-server/dataplane_overview_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ func (r *dataplaneOverviewEndpoints) inspectDataplanes(request *restful.Request,
rest_errors.HandleError(response, err, "Could not retrieve dataplane overviews")
return
}
namePrefix := request.QueryParameter("namePrefix")
nameContains := request.QueryParameter("name")

overviews, err := r.fetchOverviews(request.Request.Context(), page, meshName, namePrefix, filter)
overviews, err := r.fetchOverviews(request.Request.Context(), page, meshName, nameContains, filter)
if err != nil {
rest_errors.HandleError(response, err, "Could not retrieve dataplane overviews")
return
Expand All @@ -126,9 +126,9 @@ func (r *dataplaneOverviewEndpoints) inspectDataplanes(request *restful.Request,
}
}

func (r *dataplaneOverviewEndpoints) fetchOverviews(ctx context.Context, p page, meshName string, namePrefix string, filter store.ListFilterFunc) (mesh.DataplaneOverviewResourceList, error) {
func (r *dataplaneOverviewEndpoints) fetchOverviews(ctx context.Context, p page, meshName string, nameContains string, filter store.ListFilterFunc) (mesh.DataplaneOverviewResourceList, error) {
dataplanes := mesh.DataplaneResourceList{}
if err := r.resManager.List(ctx, &dataplanes, store.ListByMesh(meshName), store.ListByPage(p.size, p.offset), store.ListByFilterFunc(filter), store.ListByNamePrefix(namePrefix)); err != nil {
if err := r.resManager.List(ctx, &dataplanes, store.ListByMesh(meshName), store.ListByPage(p.size, p.offset), store.ListByFilterFunc(filter), store.ListByNameContains(nameContains)); err != nil {
return mesh.DataplaneOverviewResourceList{}, err
}

Expand Down
10 changes: 9 additions & 1 deletion pkg/api-server/dataplane_overview_endpoints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ var _ = Describe("Dataplane Overview Endpoints", func() {
url: "/meshes/mesh1/dataplanes+insights?tag=service:backend",
expectedJson: fmt.Sprintf(`{"total": 1, "items": [%s], "next": null}`, dp1Json),
}),
Entry("should list with only subset tag", testCase{
url: "/meshes/mesh1/dataplanes+insights?tag=service:ck",
expectedJson: fmt.Sprintf(`{"total": 1, "items": [%s], "next": null}`, dp1Json),
}),
Entry("should list all with all matching tags", testCase{
url: "/meshes/mesh1/dataplanes+insights?tag=service:backend&tag=version:v1",
expectedJson: fmt.Sprintf(`{"total": 1, "items": [%s], "next": null}`, dp1Json),
Expand All @@ -278,7 +282,11 @@ var _ = Describe("Dataplane Overview Endpoints", func() {
expectedJson: fmt.Sprintf(`{"total": 1, "items": [%s], "next": null}`, gatewayDelegatedJson),
}),
Entry("should list only dataplanes that starts with gateway", testCase{
url: "/meshes/mesh1/dataplanes+insights?namePrefix=gateway",
url: "/meshes/mesh1/dataplanes+insights?name=gateway",
expectedJson: fmt.Sprintf(`{"total": 2, "items": [%s, %s], "next": null}`, gatewayBuiltinJson, gatewayDelegatedJson),
}),
Entry("should list only dataplanes that contains with tew", testCase{
url: "/meshes/mesh1/dataplanes+insights?name=tew",
expectedJson: fmt.Sprintf(`{"total": 2, "items": [%s, %s], "next": null}`, gatewayBuiltinJson, gatewayDelegatedJson),
}),
)
Expand Down
2 changes: 1 addition & 1 deletion pkg/api-server/filtering.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func genFilter(request *restful.Request) (store.ListFilterFunc, error) {
return false
}

if !dataplane.Spec.MatchTags(tags) {
if !dataplane.Spec.MatchTagsFuzzy(tags) {
return false
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/core/permissions/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func MatchExternalServicesTrafficPermissions(
}
matched := false
for _, selector := range permission.Spec.Sources {
if dataplane.Spec.MatchTags(selector.Match) {
if dataplane.Spec.Matches(selector.Match) {
matched = true
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/core/policy/dataplane_matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func SelectInboundDataplanePolicies(dataplane *mesh.DataplaneResource, policies
continue
}
tagSelector := mesh_proto.TagSelector(selector.Match)
if inbound.MatchTags(tagSelector) {
if tagSelector.Matches(inbound.Tags) {
lahabana marked this conversation as resolved.
Show resolved Hide resolved
rank := tagSelector.Rank()
if rank.CompareTo(bestRank) > 0 || sameRankCreatedLater(policy, rank) {
bestRank = rank
Expand Down
16 changes: 8 additions & 8 deletions pkg/core/resources/store/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,12 @@ func (g *GetOptions) HashCode() string {
type ListFilterFunc func(rs core_model.Resource) bool

type ListOptions struct {
Mesh string
PageSize int
PageOffset string
FilterFunc ListFilterFunc
NamePrefix string
Ordered bool
Mesh string
PageSize int
PageOffset string
FilterFunc ListFilterFunc
NameContains string
Ordered bool
}

type ListOptionsFunc func(*ListOptions)
Expand All @@ -180,9 +180,9 @@ func (l *ListOptions) Filter(rs core_model.Resource) bool {
return l.FilterFunc(rs)
}

func ListByNamePrefix(name string) ListOptionsFunc {
func ListByNameContains(name string) ListOptionsFunc {
return func(opts *ListOptions) {
opts.NamePrefix = name
opts.NameContains = name
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/plugins/resources/k8s/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func (s *KubernetesStore) List(ctx context.Context, rs core_model.ResourceList,
if opts.Mesh != "" && r.GetMeta().GetMesh() != opts.Mesh {
return false
}
if opts.NamePrefix != "" && !strings.HasPrefix(r.GetMeta().GetName(), opts.NamePrefix) {
if opts.NameContains != "" && !strings.Contains(r.GetMeta().GetName(), opts.NameContains) {
return false
}
return true
Expand Down
6 changes: 3 additions & 3 deletions pkg/plugins/resources/memory/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func (c *memoryStore) List(_ context.Context, rs core_model.ResourceList, fs ...

opts := store.NewListOptions(fs...)

records := c.findRecords(string(rs.GetItemType()), opts.Mesh, opts.NamePrefix)
records := c.findRecords(string(rs.GetItemType()), opts.Mesh, opts.NameContains)

for i := 0; i < len(records); i++ {
r := rs.NewItem()
Expand All @@ -289,7 +289,7 @@ func (c *memoryStore) findRecord(
return -1, nil
}

func (c *memoryStore) findRecords(resourceType string, mesh string, prefix string) []*memoryStoreRecord {
func (c *memoryStore) findRecords(resourceType string, mesh string, contains string) []*memoryStoreRecord {
res := make([]*memoryStoreRecord, 0)
for _, rec := range c.records {
if rec.ResourceType != resourceType {
Expand All @@ -298,7 +298,7 @@ func (c *memoryStore) findRecords(resourceType string, mesh string, prefix strin
if mesh != "" && rec.Mesh != mesh {
continue
}
if prefix != "" && !strings.HasPrefix(rec.Name, prefix) {
if contains != "" && !strings.Contains(rec.Name, contains) {
continue
}
res = append(res, rec)
Expand Down
4 changes: 2 additions & 2 deletions pkg/plugins/resources/postgres/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,10 @@ func (r *postgresResourceStore) List(_ context.Context, resources core_model.Res
statement += fmt.Sprintf(" AND mesh=$%d", argsIndex)
statementArgs = append(statementArgs, opts.Mesh)
}
if opts.NamePrefix != "" {
if opts.NameContains != "" {
argsIndex++
statement += fmt.Sprintf(" AND name LIKE $%d", argsIndex)
statementArgs = append(statementArgs, opts.NamePrefix+"%")
statementArgs = append(statementArgs, "%"+opts.NameContains+"%")
}
statement += " ORDER BY name, mesh"

Expand Down
4 changes: 2 additions & 2 deletions pkg/test/store/store_test_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ func ExecuteStoreTests(
list := core_mesh.TrafficRouteResourceList{}

// when
err := s.List(context.Background(), &list, store.ListByNamePrefix("list-res"))
err := s.List(context.Background(), &list, store.ListByNameContains("list-res"))

// then
Expect(err).ToNot(HaveOccurred())
Expand All @@ -373,7 +373,7 @@ func ExecuteStoreTests(
list := core_mesh.TrafficRouteResourceList{}

// when
err := s.List(context.Background(), &list, store.ListByNamePrefix("list-res"), store.ListByMesh(mesh))
err := s.List(context.Background(), &list, store.ListByNameContains("list-res"), store.ListByMesh(mesh))

// then
Expect(err).ToNot(HaveOccurred())
Expand Down