From 0f4c0ec4b16dfd79e06d29b7e5553afae23b4341 Mon Sep 17 00:00:00 2001 From: Yassine Bounekhla <56373201+rudream@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:21:04 +0700 Subject: [PATCH] fix filtering by no upgrader (#63184) --- lib/cache/inventory/inventory_cache_test.go | 42 +++++++++++++++++-- lib/web/inventory.go | 9 +++- .../teleport/src/Instances/Instances.tsx | 2 +- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/lib/cache/inventory/inventory_cache_test.go b/lib/cache/inventory/inventory_cache_test.go index 98be7630b8f..d3381a29129 100644 --- a/lib/cache/inventory/inventory_cache_test.go +++ b/lib/cache/inventory/inventory_cache_test.go @@ -897,6 +897,18 @@ func TestInventoryCacheFiltering(t *testing.T) { ExternalUpgrader: "kube", }, }, + { + ResourceHeader: types.ResourceHeader{ + Metadata: types.Metadata{ + Name: "node-no-upgrader", + }, + }, + Spec: types.InstanceSpecV1{ + Hostname: "no-upgrader.example.com", + Version: "18.3.0", + Services: []types.SystemRole{types.RoleNode}, + }, + }, } bots := []*machineidv1.BotInstance{ @@ -1038,7 +1050,7 @@ func TestInventoryCacheFiltering(t *testing.T) { require.Equal(t, "18.1.0", resp.Items[0].GetInstance().Spec.Version) // Test predicate query filtering by version (greater than) for both instance types. - // This should return 2 instances and 1 bot instance. + // This should return 3 instances and 1 bot instance. resp, err = inventoryCache.ListUnifiedInstances(ctx, &inventoryv1.ListUnifiedInstancesRequest{ PageSize: 100, Filter: &inventoryv1.ListUnifiedInstancesFilter{ @@ -1047,7 +1059,7 @@ func TestInventoryCacheFiltering(t *testing.T) { }, }) require.NoError(t, err) - require.Len(t, resp.Items, 3) + require.Len(t, resp.Items, 4) // Test predicate query filtering by version (between) resp, err = inventoryCache.ListUnifiedInstances(ctx, &inventoryv1.ListUnifiedInstancesRequest{ @@ -1058,7 +1070,7 @@ func TestInventoryCacheFiltering(t *testing.T) { }, }) require.NoError(t, err) - require.Len(t, resp.Items, 2) + require.Len(t, resp.Items, 3) // Test predicate query filtering by hostname resp, err = inventoryCache.ListUnifiedInstances(ctx, &inventoryv1.ListUnifiedInstancesRequest{ @@ -1117,6 +1129,30 @@ func TestInventoryCacheFiltering(t *testing.T) { } require.True(t, upgraders["kube"]) require.Len(t, upgraders, 1) + + // Test filtering for no upgrader works + resp, err = inventoryCache.ListUnifiedInstances(ctx, &inventoryv1.ListUnifiedInstancesRequest{ + PageSize: 100, + Filter: &inventoryv1.ListUnifiedInstancesFilter{ + Upgraders: []string{""}, + InstanceTypes: []inventoryv1.InstanceType{inventoryv1.InstanceType_INSTANCE_TYPE_INSTANCE}, + }, + }) + require.NoError(t, err) + require.Len(t, resp.Items, 1) + require.Equal(t, "no-upgrader.example.com", resp.Items[0].GetInstance().Spec.Hostname) + require.Empty(t, resp.Items[0].GetInstance().Spec.ExternalUpgrader) + + // Test filtering for no upgrader or kube upgrader + resp, err = inventoryCache.ListUnifiedInstances(ctx, &inventoryv1.ListUnifiedInstancesRequest{ + PageSize: 100, + Filter: &inventoryv1.ListUnifiedInstancesFilter{ + Upgraders: []string{"", "kube"}, + InstanceTypes: []inventoryv1.InstanceType{inventoryv1.InstanceType_INSTANCE_TYPE_INSTANCE}, + }, + }) + require.NoError(t, err) + require.Len(t, resp.Items, 3) // 2 with kube upgrader + 1 with no upgrader }) } diff --git a/lib/web/inventory.go b/lib/web/inventory.go index 1542bb920d6..e2e5d142ea8 100644 --- a/lib/web/inventory.go +++ b/lib/web/inventory.go @@ -89,11 +89,18 @@ func (h *Handler) clusterUnifiedInstancesGet(w http.ResponseWriter, r *http.Requ } } + // We don't use splitQuery for parsing upgraders since it should be possible to filter for upgrader "" (none), + // and splitQuery would remove it. + var upgraders []string + if upgradersParam := values.Get("upgraders"); upgradersParam != "" { + upgraders = strings.Split(upgradersParam, ",") + } + filter := &inventoryv1.ListUnifiedInstancesFilter{ Search: values.Get("search"), PredicateExpression: values.Get("query"), Services: splitQuery(values.Get("services")), - Upgraders: splitQuery(values.Get("upgraders")), + Upgraders: upgraders, UpdaterGroups: splitQuery(values.Get("updaterGroups")), } diff --git a/web/packages/teleport/src/Instances/Instances.tsx b/web/packages/teleport/src/Instances/Instances.tsx index 6c1bf3706e2..c33437fe0b3 100644 --- a/web/packages/teleport/src/Instances/Instances.tsx +++ b/web/packages/teleport/src/Instances/Instances.tsx @@ -96,7 +96,7 @@ export function Instances() { const upgradersParam = queryParams.get('upgraders'); const selectedUpgraders = ( - upgradersParam ? upgradersParam.split(',') : [] + upgradersParam !== null ? upgradersParam.split(',') : [] ) as UpgraderType[]; const versionFilter = queryParams.get('version_filter') || '';