prevent live queries to stall if a detail query override was set for a team (#14296)
alternative approach for #14286
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* Fixed a bug that would cause live queries to stall if a detail query override was set for a team.
|
||||
@@ -79,6 +79,7 @@ func (s *integrationTestSuite) TestSlowOsqueryHost() {
|
||||
SkipCreateTestUsers: true,
|
||||
//nolint:gosec // G112: server is just run for testing this explicit config.
|
||||
HTTPServerConfig: &http.Server{ReadTimeout: 2 * time.Second},
|
||||
EnableCachedDS: true,
|
||||
},
|
||||
)
|
||||
defer func() {
|
||||
|
||||
@@ -54,9 +54,10 @@ func (s *integrationEnterpriseTestSuite) SetupSuite() {
|
||||
License: &fleet.LicenseInfo{
|
||||
Tier: fleet.TierPremium,
|
||||
},
|
||||
Pool: s.redisPool,
|
||||
Lq: s.lq,
|
||||
Logger: log.NewLogfmtLogger(os.Stdout),
|
||||
Pool: s.redisPool,
|
||||
Lq: s.lq,
|
||||
Logger: log.NewLogfmtLogger(os.Stdout),
|
||||
EnableCachedDS: true,
|
||||
}
|
||||
users, server := RunServerForTestsWithDS(s.T(), s.ds, &config)
|
||||
s.server = server
|
||||
@@ -4106,3 +4107,92 @@ func (s *integrationEnterpriseTestSuite) TestOrbitConfigExtensions() {
|
||||
}
|
||||
}`), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
func (s *integrationEnterpriseTestSuite) TestTeamConfigDetailQueriesOverrides() {
|
||||
ctx := context.Background()
|
||||
t := s.T()
|
||||
|
||||
teamName := t.Name() + "team1"
|
||||
team := &fleet.Team{
|
||||
Name: teamName,
|
||||
Description: "desc team1",
|
||||
}
|
||||
s.Do("POST", "/api/latest/fleet/teams", team, http.StatusOK)
|
||||
|
||||
spec := []byte(fmt.Sprintf(`
|
||||
name: %s
|
||||
features:
|
||||
additional_queries:
|
||||
time: SELECT * FROM time
|
||||
enable_host_users: true
|
||||
detail_query_overrides:
|
||||
users: null
|
||||
software_linux: "select * from blah;"
|
||||
disk_encryption_linux: null
|
||||
`, teamName))
|
||||
|
||||
s.applyTeamSpec(spec)
|
||||
team, err := s.ds.TeamByName(ctx, teamName)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, team.Config.Features.DetailQueryOverrides)
|
||||
require.Nil(t, team.Config.Features.DetailQueryOverrides["users"])
|
||||
require.Nil(t, team.Config.Features.DetailQueryOverrides["disk_encryption_linux"])
|
||||
require.NotNil(t, team.Config.Features.DetailQueryOverrides["software_linux"])
|
||||
require.Equal(t, "select * from blah;", *team.Config.Features.DetailQueryOverrides["software_linux"])
|
||||
|
||||
// create a linux host
|
||||
linuxHost, err := s.ds.NewHost(context.Background(), &fleet.Host{
|
||||
DetailUpdatedAt: time.Now().Add(-10 * time.Hour),
|
||||
LabelUpdatedAt: time.Now().Add(-10 * time.Hour),
|
||||
PolicyUpdatedAt: time.Now().Add(-10 * time.Hour),
|
||||
SeenTime: time.Now().Add(-1 * time.Minute),
|
||||
OsqueryHostID: ptr.String(t.Name()),
|
||||
NodeKey: ptr.String(t.Name()),
|
||||
UUID: uuid.New().String(),
|
||||
Hostname: fmt.Sprintf("%sfoo.local", t.Name()),
|
||||
Platform: "linux",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// add the host to team1
|
||||
err = s.ds.AddHostsToTeam(context.Background(), &team.ID, []uint{linuxHost.ID})
|
||||
require.NoError(t, err)
|
||||
|
||||
// get distributed queries for the host
|
||||
s.lq.On("QueriesForHost", linuxHost.ID).Return(map[string]string{fmt.Sprintf("%d", linuxHost.ID): "select 1 from osquery;"}, nil)
|
||||
req := getDistributedQueriesRequest{NodeKey: *linuxHost.NodeKey}
|
||||
var dqResp getDistributedQueriesResponse
|
||||
s.DoJSON("POST", "/api/osquery/distributed/read", req, http.StatusOK, &dqResp)
|
||||
require.NotContains(t, dqResp.Queries, "fleet_detail_query_users")
|
||||
require.NotContains(t, dqResp.Queries, "fleet_detail_query_disk_encryption_linux")
|
||||
require.Contains(t, dqResp.Queries, "fleet_detail_query_software_linux")
|
||||
require.Contains(t, dqResp.Queries, "fleet_distributed_query_17")
|
||||
|
||||
spec = []byte(fmt.Sprintf(`
|
||||
name: %s
|
||||
features:
|
||||
additional_queries:
|
||||
time: SELECT * FROM time
|
||||
enable_host_users: true
|
||||
detail_query_overrides:
|
||||
software_linux: "select * from blah;"
|
||||
`, teamName))
|
||||
|
||||
s.applyTeamSpec(spec)
|
||||
team, err = s.ds.TeamByName(ctx, teamName)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, team.Config.Features.DetailQueryOverrides)
|
||||
require.Nil(t, team.Config.Features.DetailQueryOverrides["users"])
|
||||
require.Nil(t, team.Config.Features.DetailQueryOverrides["disk_encryption_linux"])
|
||||
require.NotNil(t, team.Config.Features.DetailQueryOverrides["software_linux"])
|
||||
require.Equal(t, "select * from blah;", *team.Config.Features.DetailQueryOverrides["software_linux"])
|
||||
|
||||
// get distributed queries for the host
|
||||
req = getDistributedQueriesRequest{NodeKey: *linuxHost.NodeKey}
|
||||
dqResp = getDistributedQueriesResponse{}
|
||||
s.DoJSON("POST", "/api/osquery/distributed/read", req, http.StatusOK, &dqResp)
|
||||
require.Contains(t, dqResp.Queries, "fleet_detail_query_users")
|
||||
require.Contains(t, dqResp.Queries, "fleet_detail_query_disk_encryption_linux")
|
||||
require.Contains(t, dqResp.Queries, "fleet_detail_query_software_linux")
|
||||
require.Contains(t, dqResp.Queries, "fleet_distributed_query_17")
|
||||
}
|
||||
|
||||
@@ -1617,7 +1617,7 @@ func GetDetailQueries(
|
||||
unknownQueries = append(unknownQueries, name)
|
||||
continue
|
||||
}
|
||||
if override == nil {
|
||||
if override == nil || *override == "" {
|
||||
delete(generatedMap, name)
|
||||
} else {
|
||||
query.Query = *override
|
||||
|
||||
@@ -873,6 +873,18 @@ func TestAppConfigReplaceQuery(t *testing.T) {
|
||||
queries = GetDetailQueries(context.Background(), config.FleetConfig{}, nil, &fleet.Features{EnableHostUsers: true, DetailQueryOverrides: replacementMap})
|
||||
_, exists := queries["users"]
|
||||
assert.False(t, exists)
|
||||
|
||||
// put the query back again
|
||||
replacementMap["users"] = ptr.String("select 1 from blah")
|
||||
queries = GetDetailQueries(context.Background(), config.FleetConfig{}, nil, &fleet.Features{EnableHostUsers: true, DetailQueryOverrides: replacementMap})
|
||||
assert.NotEqual(t, originalQuery, queries["users"].Query)
|
||||
assert.Equal(t, "select 1 from blah", queries["users"].Query)
|
||||
|
||||
// empty strings are also ignored
|
||||
replacementMap["users"] = ptr.String("")
|
||||
queries = GetDetailQueries(context.Background(), config.FleetConfig{}, nil, &fleet.Features{EnableHostUsers: true, DetailQueryOverrides: replacementMap})
|
||||
_, exists = queries["users"]
|
||||
assert.False(t, exists)
|
||||
}
|
||||
|
||||
func TestDirectIngestSoftware(t *testing.T) {
|
||||
|
||||
@@ -298,6 +298,17 @@ func (ts *withServer) getConfig() *appConfigResponse {
|
||||
return responseBody
|
||||
}
|
||||
|
||||
func (ts *withServer) applyTeamSpec(yamlSpec []byte) {
|
||||
var teamSpec any
|
||||
err := yaml.Unmarshal(yamlSpec, &teamSpec)
|
||||
require.NoError(ts.s.T(), err)
|
||||
|
||||
specsReq := map[string]any{
|
||||
"specs": []any{teamSpec},
|
||||
}
|
||||
ts.Do("POST", "/api/latest/fleet/spec/teams", specsReq, http.StatusOK)
|
||||
}
|
||||
|
||||
func (ts *withServer) LoginSSOUser(username, password string) (fleet.Auth, string) {
|
||||
t := ts.s.T()
|
||||
auth, res := ts.loginSSOUser(username, password, "/api/v1/fleet/sso", http.StatusOK)
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
eeservice "github.com/fleetdm/fleet/v4/ee/server/service"
|
||||
"github.com/fleetdm/fleet/v4/server/config"
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/license"
|
||||
"github.com/fleetdm/fleet/v4/server/datastore/cached_mysql"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/logging"
|
||||
"github.com/fleetdm/fleet/v4/server/mail"
|
||||
@@ -288,9 +289,13 @@ type TestServerOpts struct {
|
||||
UseMailService bool
|
||||
APNSTopic string
|
||||
ProfileMatcher fleet.ProfileMatcher
|
||||
EnableCachedDS bool
|
||||
}
|
||||
|
||||
func RunServerForTestsWithDS(t *testing.T, ds fleet.Datastore, opts ...*TestServerOpts) (map[string]fleet.User, *httptest.Server) {
|
||||
if len(opts) > 0 && opts[0].EnableCachedDS {
|
||||
ds = cached_mysql.New(ds)
|
||||
}
|
||||
var rs fleet.QueryResultStore
|
||||
if len(opts) > 0 && opts[0].Rs != nil {
|
||||
rs = opts[0].Rs
|
||||
|
||||
Reference in New Issue
Block a user