From 5ca22df90cd580c1bd104c2731c07a7cb0953fb5 Mon Sep 17 00:00:00 2001 From: Tim Lee Date: Wed, 10 Jul 2024 14:33:39 -0600 Subject: [PATCH] Script Timeout Agent Options Part 1 of 2 (#20266) --- cmd/fleetctl/scripts_test.go | 5 ++- orbit/pkg/scripts/scripts.go | 7 ++-- orbit/pkg/update/notifications.go | 7 ++++ ...9183940_AddTimeoutColumnToScriptResults.go | 38 +++++++++++++++++++ ...40_AddTimeoutColumnToScriptResults_test.go | 34 +++++++++++++++++ server/datastore/mysql/schema.sql | 5 ++- server/datastore/mysql/scripts.go | 5 ++- server/datastore/mysql/scripts_test.go | 5 +++ server/fleet/agent_options.go | 8 ++++ server/fleet/agent_options_test.go | 4 ++ server/fleet/errors.go | 1 - server/fleet/orbit.go | 9 +++-- server/fleet/scripts.go | 19 +++++++++- server/service/integration_enterprise_test.go | 18 ++++++++- server/service/orbit.go | 22 ++++++----- server/service/scripts.go | 4 +- 16 files changed, 163 insertions(+), 28 deletions(-) create mode 100644 server/datastore/mysql/migrations/tables/20240709183940_AddTimeoutColumnToScriptResults.go create mode 100644 server/datastore/mysql/migrations/tables/20240709183940_AddTimeoutColumnToScriptResults_test.go diff --git a/cmd/fleetctl/scripts_test.go b/cmd/fleetctl/scripts_test.go index abb5758584..49fcb1ca67 100644 --- a/cmd/fleetctl/scripts_test.go +++ b/cmd/fleetctl/scripts_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/fleetdm/fleet/v4/pkg/scripts" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/fleetdm/fleet/v4/server/ptr" "github.com/fleetdm/fleet/v4/server/service" @@ -270,10 +271,10 @@ Output: scriptResult: &fleet.HostScriptResult{ ExitCode: ptr.Int64(-1), Output: "Oh no!", - Message: fleet.RunScriptScriptTimeoutErrMsg, + Message: fleet.HostScriptTimeoutMessage(ptr.Int(int(scripts.MaxHostExecutionTime.Seconds()))), }, expectOutput: ` -Error: Timeout. Fleet stopped the script after 5 minutes to protect host performance. +Error: Timeout. Fleet stopped the script after 300 seconds to protect host performance. Output before timeout: diff --git a/orbit/pkg/scripts/scripts.go b/orbit/pkg/scripts/scripts.go index 08207c16ae..d606efb496 100644 --- a/orbit/pkg/scripts/scripts.go +++ b/orbit/pkg/scripts/scripts.go @@ -13,7 +13,6 @@ import ( "unicode/utf8" "github.com/fleetdm/fleet/v4/orbit/pkg/constant" - "github.com/fleetdm/fleet/v4/pkg/scripts" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/rs/zerolog/log" ) @@ -31,6 +30,7 @@ type Client interface { type Runner struct { Client Client ScriptExecutionEnabled bool + ScriptExecutionTimeout time.Duration // tempDirFn is the function to call to get the temporary directory to use, // inside of which the script-specific subdirectories will be created. If nil, @@ -114,7 +114,7 @@ func (r *Runner) runOne(script *fleet.HostScriptResult) (finalErr error) { return fmt.Errorf("write script file: %w", err) } - ctx, cancel := context.WithTimeout(context.Background(), scripts.MaxHostExecutionTime) + ctx, cancel := context.WithTimeout(context.Background(), r.ScriptExecutionTimeout) defer cancel() execCmdFn := r.execCmdFn @@ -122,7 +122,7 @@ func (r *Runner) runOne(script *fleet.HostScriptResult) (finalErr error) { execCmdFn = ExecCmd } start := time.Now() - log.Debug().Msgf("starting script execution of %v", script.ExecutionID) + log.Debug().Msgf("starting script execution of %v with timeout of %v", script.ExecutionID, r.ScriptExecutionTimeout) output, exitCode, execErr := execCmdFn(ctx, scriptFile, nil) log.Debug().Msgf("after script execution of %v", script.ExecutionID) duration := time.Since(start) @@ -144,6 +144,7 @@ func (r *Runner) runOne(script *fleet.HostScriptResult) (finalErr error) { Output: string(output), Runtime: int(duration.Seconds()), ExitCode: exitCode, + Timeout: int(r.ScriptExecutionTimeout.Seconds()), }) if err != nil { return fmt.Errorf("save script result: %w", err) diff --git a/orbit/pkg/update/notifications.go b/orbit/pkg/update/notifications.go index 63224ac859..3d8b9bb033 100644 --- a/orbit/pkg/update/notifications.go +++ b/orbit/pkg/update/notifications.go @@ -10,6 +10,7 @@ import ( "github.com/fleetdm/fleet/v4/orbit/pkg/bitlocker" "github.com/fleetdm/fleet/v4/orbit/pkg/profiles" "github.com/fleetdm/fleet/v4/orbit/pkg/scripts" + fleetscripts "github.com/fleetdm/fleet/v4/pkg/scripts" "github.com/fleetdm/fleet/v4/server/fleet" "github.com/rs/zerolog/log" ) @@ -346,6 +347,11 @@ func (h *runScriptsConfigReceiver) runDynamicScriptsEnabledCheck() { // server sent a list of scripts to execute, starts a goroutine to execute // them. func (h *runScriptsConfigReceiver) Run(cfg *fleet.OrbitConfig) error { + timeout := fleetscripts.MaxHostExecutionTime + if cfg.ScriptExeTimeout > 0 { + timeout = time.Duration(cfg.ScriptExeTimeout) * time.Second + } + if len(cfg.Notifications.PendingScriptExecutionIDs) > 0 { if h.mu.TryLock() { log.Debug().Msgf("received request to run scripts %v", cfg.Notifications.PendingScriptExecutionIDs) @@ -353,6 +359,7 @@ func (h *runScriptsConfigReceiver) Run(cfg *fleet.OrbitConfig) error { runner := &scripts.Runner{ ScriptExecutionEnabled: h.scriptsEnabled(), Client: h.ScriptsClient, + ScriptExecutionTimeout: timeout, } fn := runner.Run if h.runScriptsFn != nil { diff --git a/server/datastore/mysql/migrations/tables/20240709183940_AddTimeoutColumnToScriptResults.go b/server/datastore/mysql/migrations/tables/20240709183940_AddTimeoutColumnToScriptResults.go new file mode 100644 index 0000000000..115972a7b0 --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20240709183940_AddTimeoutColumnToScriptResults.go @@ -0,0 +1,38 @@ +package tables + +import ( + "database/sql" +) + +func init() { + MigrationClient.AddMigration(Up_20240709183940, Down_20240709183940) +} + +// At the time of this migration, all script timeouts are +// hardcoded to 300 seconds. This migration adds a timeout +// column to the host_script_results table to allow for +// custom timeouts. +func Up_20240709183940(tx *sql.Tx) error { + stmt := ` + ALTER TABLE host_script_results + ADD COLUMN timeout INT DEFAULT NULL; + ` + if _, err := tx.Exec(stmt); err != nil { + return err + } + + stmt = ` + UPDATE host_script_results + SET timeout = 300 + WHERE timeout IS NULL; + ` + if _, err := tx.Exec(stmt); err != nil { + return err + } + + return nil +} + +func Down_20240709183940(tx *sql.Tx) error { + return nil +} diff --git a/server/datastore/mysql/migrations/tables/20240709183940_AddTimeoutColumnToScriptResults_test.go b/server/datastore/mysql/migrations/tables/20240709183940_AddTimeoutColumnToScriptResults_test.go new file mode 100644 index 0000000000..d27fff54f5 --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20240709183940_AddTimeoutColumnToScriptResults_test.go @@ -0,0 +1,34 @@ +package tables + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestUp_20240709183940(t *testing.T) { + db := applyUpToPrev(t) + + insertStmt := ` + INSERT INTO host_script_results + (host_id, execution_id, output) + VALUES (?, ?, ?) + ` + _, err := db.Exec(insertStmt, 1, 1, "output") + require.NoError(t, err) + + applyNext(t, db) + + selectStmt := ` + SELECT timeout FROM host_script_results + WHERE host_id = ? + ` + var timeout int + err = db.QueryRow(selectStmt, 1).Scan(&timeout) + require.NoError(t, err) + require.Equal(t, 300, timeout) + + // inserting no timeout succeeds + _, err = db.Exec(insertStmt, 2, 2, "output") + require.NoError(t, err) +} diff --git a/server/datastore/mysql/schema.sql b/server/datastore/mysql/schema.sql index b4a66fa73b..8576f85c4e 100644 --- a/server/datastore/mysql/schema.sql +++ b/server/datastore/mysql/schema.sql @@ -460,6 +460,7 @@ CREATE TABLE `host_script_results` ( `sync_request` tinyint(1) NOT NULL DEFAULT '0', `script_content_id` int(10) unsigned DEFAULT NULL, `host_deleted_at` timestamp NULL DEFAULT NULL, + `timeout` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_host_script_results_execution_id` (`execution_id`), KEY `idx_host_script_results_host_exit_created` (`host_id`,`exit_code`,`created_at`), @@ -948,9 +949,9 @@ CREATE TABLE `migration_status_tables` ( `tstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=283 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +) ENGINE=InnoDB AUTO_INCREMENT=284 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709175341,1,'2020-01-01 01:01:01'); +INSERT INTO `migration_status_tables` VALUES (1,0,1,'2020-01-01 01:01:01'),(2,20161118193812,1,'2020-01-01 01:01:01'),(3,20161118211713,1,'2020-01-01 01:01:01'),(4,20161118212436,1,'2020-01-01 01:01:01'),(5,20161118212515,1,'2020-01-01 01:01:01'),(6,20161118212528,1,'2020-01-01 01:01:01'),(7,20161118212538,1,'2020-01-01 01:01:01'),(8,20161118212549,1,'2020-01-01 01:01:01'),(9,20161118212557,1,'2020-01-01 01:01:01'),(10,20161118212604,1,'2020-01-01 01:01:01'),(11,20161118212613,1,'2020-01-01 01:01:01'),(12,20161118212621,1,'2020-01-01 01:01:01'),(13,20161118212630,1,'2020-01-01 01:01:01'),(14,20161118212641,1,'2020-01-01 01:01:01'),(15,20161118212649,1,'2020-01-01 01:01:01'),(16,20161118212656,1,'2020-01-01 01:01:01'),(17,20161118212758,1,'2020-01-01 01:01:01'),(18,20161128234849,1,'2020-01-01 01:01:01'),(19,20161230162221,1,'2020-01-01 01:01:01'),(20,20170104113816,1,'2020-01-01 01:01:01'),(21,20170105151732,1,'2020-01-01 01:01:01'),(22,20170108191242,1,'2020-01-01 01:01:01'),(23,20170109094020,1,'2020-01-01 01:01:01'),(24,20170109130438,1,'2020-01-01 01:01:01'),(25,20170110202752,1,'2020-01-01 01:01:01'),(26,20170111133013,1,'2020-01-01 01:01:01'),(27,20170117025759,1,'2020-01-01 01:01:01'),(28,20170118191001,1,'2020-01-01 01:01:01'),(29,20170119234632,1,'2020-01-01 01:01:01'),(30,20170124230432,1,'2020-01-01 01:01:01'),(31,20170127014618,1,'2020-01-01 01:01:01'),(32,20170131232841,1,'2020-01-01 01:01:01'),(33,20170223094154,1,'2020-01-01 01:01:01'),(34,20170306075207,1,'2020-01-01 01:01:01'),(35,20170309100733,1,'2020-01-01 01:01:01'),(36,20170331111922,1,'2020-01-01 01:01:01'),(37,20170502143928,1,'2020-01-01 01:01:01'),(38,20170504130602,1,'2020-01-01 01:01:01'),(39,20170509132100,1,'2020-01-01 01:01:01'),(40,20170519105647,1,'2020-01-01 01:01:01'),(41,20170519105648,1,'2020-01-01 01:01:01'),(42,20170831234300,1,'2020-01-01 01:01:01'),(43,20170831234301,1,'2020-01-01 01:01:01'),(44,20170831234303,1,'2020-01-01 01:01:01'),(45,20171116163618,1,'2020-01-01 01:01:01'),(46,20171219164727,1,'2020-01-01 01:01:01'),(47,20180620164811,1,'2020-01-01 01:01:01'),(48,20180620175054,1,'2020-01-01 01:01:01'),(49,20180620175055,1,'2020-01-01 01:01:01'),(50,20191010101639,1,'2020-01-01 01:01:01'),(51,20191010155147,1,'2020-01-01 01:01:01'),(52,20191220130734,1,'2020-01-01 01:01:01'),(53,20200311140000,1,'2020-01-01 01:01:01'),(54,20200405120000,1,'2020-01-01 01:01:01'),(55,20200407120000,1,'2020-01-01 01:01:01'),(56,20200420120000,1,'2020-01-01 01:01:01'),(57,20200504120000,1,'2020-01-01 01:01:01'),(58,20200512120000,1,'2020-01-01 01:01:01'),(59,20200707120000,1,'2020-01-01 01:01:01'),(60,20201011162341,1,'2020-01-01 01:01:01'),(61,20201021104586,1,'2020-01-01 01:01:01'),(62,20201102112520,1,'2020-01-01 01:01:01'),(63,20201208121729,1,'2020-01-01 01:01:01'),(64,20201215091637,1,'2020-01-01 01:01:01'),(65,20210119174155,1,'2020-01-01 01:01:01'),(66,20210326182902,1,'2020-01-01 01:01:01'),(67,20210421112652,1,'2020-01-01 01:01:01'),(68,20210506095025,1,'2020-01-01 01:01:01'),(69,20210513115729,1,'2020-01-01 01:01:01'),(70,20210526113559,1,'2020-01-01 01:01:01'),(71,20210601000001,1,'2020-01-01 01:01:01'),(72,20210601000002,1,'2020-01-01 01:01:01'),(73,20210601000003,1,'2020-01-01 01:01:01'),(74,20210601000004,1,'2020-01-01 01:01:01'),(75,20210601000005,1,'2020-01-01 01:01:01'),(76,20210601000006,1,'2020-01-01 01:01:01'),(77,20210601000007,1,'2020-01-01 01:01:01'),(78,20210601000008,1,'2020-01-01 01:01:01'),(79,20210606151329,1,'2020-01-01 01:01:01'),(80,20210616163757,1,'2020-01-01 01:01:01'),(81,20210617174723,1,'2020-01-01 01:01:01'),(82,20210622160235,1,'2020-01-01 01:01:01'),(83,20210623100031,1,'2020-01-01 01:01:01'),(84,20210623133615,1,'2020-01-01 01:01:01'),(85,20210708143152,1,'2020-01-01 01:01:01'),(86,20210709124443,1,'2020-01-01 01:01:01'),(87,20210712155608,1,'2020-01-01 01:01:01'),(88,20210714102108,1,'2020-01-01 01:01:01'),(89,20210719153709,1,'2020-01-01 01:01:01'),(90,20210721171531,1,'2020-01-01 01:01:01'),(91,20210723135713,1,'2020-01-01 01:01:01'),(92,20210802135933,1,'2020-01-01 01:01:01'),(93,20210806112844,1,'2020-01-01 01:01:01'),(94,20210810095603,1,'2020-01-01 01:01:01'),(95,20210811150223,1,'2020-01-01 01:01:01'),(96,20210818151827,1,'2020-01-01 01:01:01'),(97,20210818151828,1,'2020-01-01 01:01:01'),(98,20210818182258,1,'2020-01-01 01:01:01'),(99,20210819131107,1,'2020-01-01 01:01:01'),(100,20210819143446,1,'2020-01-01 01:01:01'),(101,20210903132338,1,'2020-01-01 01:01:01'),(102,20210915144307,1,'2020-01-01 01:01:01'),(103,20210920155130,1,'2020-01-01 01:01:01'),(104,20210927143115,1,'2020-01-01 01:01:01'),(105,20210927143116,1,'2020-01-01 01:01:01'),(106,20211013133706,1,'2020-01-01 01:01:01'),(107,20211013133707,1,'2020-01-01 01:01:01'),(108,20211102135149,1,'2020-01-01 01:01:01'),(109,20211109121546,1,'2020-01-01 01:01:01'),(110,20211110163320,1,'2020-01-01 01:01:01'),(111,20211116184029,1,'2020-01-01 01:01:01'),(112,20211116184030,1,'2020-01-01 01:01:01'),(113,20211202092042,1,'2020-01-01 01:01:01'),(114,20211202181033,1,'2020-01-01 01:01:01'),(115,20211207161856,1,'2020-01-01 01:01:01'),(116,20211216131203,1,'2020-01-01 01:01:01'),(117,20211221110132,1,'2020-01-01 01:01:01'),(118,20220107155700,1,'2020-01-01 01:01:01'),(119,20220125105650,1,'2020-01-01 01:01:01'),(120,20220201084510,1,'2020-01-01 01:01:01'),(121,20220208144830,1,'2020-01-01 01:01:01'),(122,20220208144831,1,'2020-01-01 01:01:01'),(123,20220215152203,1,'2020-01-01 01:01:01'),(124,20220223113157,1,'2020-01-01 01:01:01'),(125,20220307104655,1,'2020-01-01 01:01:01'),(126,20220309133956,1,'2020-01-01 01:01:01'),(127,20220316155700,1,'2020-01-01 01:01:01'),(128,20220323152301,1,'2020-01-01 01:01:01'),(129,20220330100659,1,'2020-01-01 01:01:01'),(130,20220404091216,1,'2020-01-01 01:01:01'),(131,20220419140750,1,'2020-01-01 01:01:01'),(132,20220428140039,1,'2020-01-01 01:01:01'),(133,20220503134048,1,'2020-01-01 01:01:01'),(134,20220524102918,1,'2020-01-01 01:01:01'),(135,20220526123327,1,'2020-01-01 01:01:01'),(136,20220526123328,1,'2020-01-01 01:01:01'),(137,20220526123329,1,'2020-01-01 01:01:01'),(138,20220608113128,1,'2020-01-01 01:01:01'),(139,20220627104817,1,'2020-01-01 01:01:01'),(140,20220704101843,1,'2020-01-01 01:01:01'),(141,20220708095046,1,'2020-01-01 01:01:01'),(142,20220713091130,1,'2020-01-01 01:01:01'),(143,20220802135510,1,'2020-01-01 01:01:01'),(144,20220818101352,1,'2020-01-01 01:01:01'),(145,20220822161445,1,'2020-01-01 01:01:01'),(146,20220831100036,1,'2020-01-01 01:01:01'),(147,20220831100151,1,'2020-01-01 01:01:01'),(148,20220908181826,1,'2020-01-01 01:01:01'),(149,20220914154915,1,'2020-01-01 01:01:01'),(150,20220915165115,1,'2020-01-01 01:01:01'),(151,20220915165116,1,'2020-01-01 01:01:01'),(152,20220928100158,1,'2020-01-01 01:01:01'),(153,20221014084130,1,'2020-01-01 01:01:01'),(154,20221027085019,1,'2020-01-01 01:01:01'),(155,20221101103952,1,'2020-01-01 01:01:01'),(156,20221104144401,1,'2020-01-01 01:01:01'),(157,20221109100749,1,'2020-01-01 01:01:01'),(158,20221115104546,1,'2020-01-01 01:01:01'),(159,20221130114928,1,'2020-01-01 01:01:01'),(160,20221205112142,1,'2020-01-01 01:01:01'),(161,20221216115820,1,'2020-01-01 01:01:01'),(162,20221220195934,1,'2020-01-01 01:01:01'),(163,20221220195935,1,'2020-01-01 01:01:01'),(164,20221223174807,1,'2020-01-01 01:01:01'),(165,20221227163855,1,'2020-01-01 01:01:01'),(166,20221227163856,1,'2020-01-01 01:01:01'),(167,20230202224725,1,'2020-01-01 01:01:01'),(168,20230206163608,1,'2020-01-01 01:01:01'),(169,20230214131519,1,'2020-01-01 01:01:01'),(170,20230303135738,1,'2020-01-01 01:01:01'),(171,20230313135301,1,'2020-01-01 01:01:01'),(172,20230313141819,1,'2020-01-01 01:01:01'),(173,20230315104937,1,'2020-01-01 01:01:01'),(174,20230317173844,1,'2020-01-01 01:01:01'),(175,20230320133602,1,'2020-01-01 01:01:01'),(176,20230330100011,1,'2020-01-01 01:01:01'),(177,20230330134823,1,'2020-01-01 01:01:01'),(178,20230405232025,1,'2020-01-01 01:01:01'),(179,20230408084104,1,'2020-01-01 01:01:01'),(180,20230411102858,1,'2020-01-01 01:01:01'),(181,20230421155932,1,'2020-01-01 01:01:01'),(182,20230425082126,1,'2020-01-01 01:01:01'),(183,20230425105727,1,'2020-01-01 01:01:01'),(184,20230501154913,1,'2020-01-01 01:01:01'),(185,20230503101418,1,'2020-01-01 01:01:01'),(186,20230515144206,1,'2020-01-01 01:01:01'),(187,20230517140952,1,'2020-01-01 01:01:01'),(188,20230517152807,1,'2020-01-01 01:01:01'),(189,20230518114155,1,'2020-01-01 01:01:01'),(190,20230520153236,1,'2020-01-01 01:01:01'),(191,20230525151159,1,'2020-01-01 01:01:01'),(192,20230530122103,1,'2020-01-01 01:01:01'),(193,20230602111827,1,'2020-01-01 01:01:01'),(194,20230608103123,1,'2020-01-01 01:01:01'),(195,20230629140529,1,'2020-01-01 01:01:01'),(196,20230629140530,1,'2020-01-01 01:01:01'),(197,20230711144622,1,'2020-01-01 01:01:01'),(198,20230721135421,1,'2020-01-01 01:01:01'),(199,20230721161508,1,'2020-01-01 01:01:01'),(200,20230726115701,1,'2020-01-01 01:01:01'),(201,20230807100822,1,'2020-01-01 01:01:01'),(202,20230814150442,1,'2020-01-01 01:01:01'),(203,20230823122728,1,'2020-01-01 01:01:01'),(204,20230906152143,1,'2020-01-01 01:01:01'),(205,20230911163618,1,'2020-01-01 01:01:01'),(206,20230912101759,1,'2020-01-01 01:01:01'),(207,20230915101341,1,'2020-01-01 01:01:01'),(208,20230918132351,1,'2020-01-01 01:01:01'),(209,20231004144339,1,'2020-01-01 01:01:01'),(210,20231009094541,1,'2020-01-01 01:01:01'),(211,20231009094542,1,'2020-01-01 01:01:01'),(212,20231009094543,1,'2020-01-01 01:01:01'),(213,20231009094544,1,'2020-01-01 01:01:01'),(214,20231016091915,1,'2020-01-01 01:01:01'),(215,20231024174135,1,'2020-01-01 01:01:01'),(216,20231025120016,1,'2020-01-01 01:01:01'),(217,20231025160156,1,'2020-01-01 01:01:01'),(218,20231031165350,1,'2020-01-01 01:01:01'),(219,20231106144110,1,'2020-01-01 01:01:01'),(220,20231107130934,1,'2020-01-01 01:01:01'),(221,20231109115838,1,'2020-01-01 01:01:01'),(222,20231121054530,1,'2020-01-01 01:01:01'),(223,20231122101320,1,'2020-01-01 01:01:01'),(224,20231130132828,1,'2020-01-01 01:01:01'),(225,20231130132931,1,'2020-01-01 01:01:01'),(226,20231204155427,1,'2020-01-01 01:01:01'),(227,20231206142340,1,'2020-01-01 01:01:01'),(228,20231207102320,1,'2020-01-01 01:01:01'),(229,20231207102321,1,'2020-01-01 01:01:01'),(230,20231207133731,1,'2020-01-01 01:01:01'),(231,20231212094238,1,'2020-01-01 01:01:01'),(232,20231212095734,1,'2020-01-01 01:01:01'),(233,20231212161121,1,'2020-01-01 01:01:01'),(234,20231215122713,1,'2020-01-01 01:01:01'),(235,20231219143041,1,'2020-01-01 01:01:01'),(236,20231224070653,1,'2020-01-01 01:01:01'),(237,20240110134315,1,'2020-01-01 01:01:01'),(238,20240119091637,1,'2020-01-01 01:01:01'),(239,20240126020642,1,'2020-01-01 01:01:01'),(240,20240126020643,1,'2020-01-01 01:01:01'),(241,20240129162819,1,'2020-01-01 01:01:01'),(242,20240130115133,1,'2020-01-01 01:01:01'),(243,20240131083822,1,'2020-01-01 01:01:01'),(244,20240205095928,1,'2020-01-01 01:01:01'),(245,20240205121956,1,'2020-01-01 01:01:01'),(246,20240209110212,1,'2020-01-01 01:01:01'),(247,20240212111533,1,'2020-01-01 01:01:01'),(248,20240221112844,1,'2020-01-01 01:01:01'),(249,20240222073518,1,'2020-01-01 01:01:01'),(250,20240222135115,1,'2020-01-01 01:01:01'),(251,20240226082255,1,'2020-01-01 01:01:01'),(252,20240228082706,1,'2020-01-01 01:01:01'),(253,20240301173035,1,'2020-01-01 01:01:01'),(254,20240302111134,1,'2020-01-01 01:01:01'),(255,20240312103753,1,'2020-01-01 01:01:01'),(256,20240313143416,1,'2020-01-01 01:01:01'),(257,20240314085226,1,'2020-01-01 01:01:01'),(258,20240314151747,1,'2020-01-01 01:01:01'),(259,20240320145650,1,'2020-01-01 01:01:01'),(260,20240327115530,1,'2020-01-01 01:01:01'),(261,20240327115617,1,'2020-01-01 01:01:01'),(262,20240408085837,1,'2020-01-01 01:01:01'),(263,20240415104633,1,'2020-01-01 01:01:01'),(264,20240430111727,1,'2020-01-01 01:01:01'),(265,20240515200020,1,'2020-01-01 01:01:01'),(266,20240521143023,1,'2020-01-01 01:01:01'),(267,20240521143024,1,'2020-01-01 01:01:01'),(268,20240601174138,1,'2020-01-01 01:01:01'),(269,20240607133721,1,'2020-01-01 01:01:01'),(270,20240612150059,1,'2020-01-01 01:01:01'),(271,20240613162201,1,'2020-01-01 01:01:01'),(272,20240613172616,1,'2020-01-01 01:01:01'),(273,20240618142419,1,'2020-01-01 01:01:01'),(274,20240625093543,1,'2020-01-01 01:01:01'),(275,20240626195531,1,'2020-01-01 01:01:01'),(276,20240702123921,1,'2020-01-01 01:01:01'),(277,20240703154849,1,'2020-01-01 01:01:01'),(278,20240707134035,1,'2020-01-01 01:01:01'),(279,20240707134036,1,'2020-01-01 01:01:01'),(280,20240709124958,1,'2020-01-01 01:01:01'),(281,20240709132642,1,'2020-01-01 01:01:01'),(282,20240709175341,1,'2020-01-01 01:01:01'),(283,20240709183940,1,'2020-01-01 01:01:01'); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `mobile_device_management_solutions` ( diff --git a/server/datastore/mysql/scripts.go b/server/datastore/mysql/scripts.go index 67c223f01f..78dbcbdf58 100644 --- a/server/datastore/mysql/scripts.go +++ b/server/datastore/mysql/scripts.go @@ -96,7 +96,8 @@ func (ds *Datastore) SetHostScriptExecutionResult(ctx context.Context, result *f UPDATE host_script_results SET output = ?, runtime = ?, - exit_code = ? + exit_code = ?, + timeout = ? WHERE host_id = ? AND execution_id = ?` @@ -138,6 +139,7 @@ func (ds *Datastore) SetHostScriptExecutionResult(ctx context.Context, result *f // it to a 32-bit signed integer. // See /orbit/pkg/scripts/exec_windows.go int32(result.ExitCode), + result.Timeout, result.HostID, result.ExecutionID, ) @@ -236,6 +238,7 @@ func (ds *Datastore) getHostScriptExecutionResultDB(ctx context.Context, q sqlx. hsr.output, hsr.runtime, hsr.exit_code, + hsr.timeout, hsr.created_at, hsr.user_id, hsr.sync_request, diff --git a/server/datastore/mysql/scripts_test.go b/server/datastore/mysql/scripts_test.go index 0dbb22e1f4..2ae732923d 100644 --- a/server/datastore/mysql/scripts_test.go +++ b/server/datastore/mysql/scripts_test.go @@ -93,6 +93,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) { Output: "foo", Runtime: 2, ExitCode: 0, + Timeout: 300, }) require.NoError(t, err) @@ -103,6 +104,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) { Output: "foobarbaz", Runtime: 22, ExitCode: 1, + Timeout: 360, }) require.NoError(t, err) require.Nil(t, hsr) @@ -119,6 +121,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) { expectScript.Output = "foo" expectScript.Runtime = 2 expectScript.ExitCode = ptr.Int64(0) + expectScript.Timeout = ptr.Int(300) require.Equal(t, &expectScript, script) // create another script execution request (null user id this time) @@ -166,6 +169,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) { Output: largeOutput, Runtime: 10, ExitCode: 1, + Timeout: 300, }) require.NoError(t, err) @@ -240,6 +244,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) { Output: "foo", Runtime: 1, ExitCode: math.MaxUint32, + Timeout: 300, }) require.NoError(t, err) require.EqualValues(t, -1, *unsignedScriptResult.ExitCode) diff --git a/server/fleet/agent_options.go b/server/fleet/agent_options.go index 53e2d4674a..0e185a3fee 100644 --- a/server/fleet/agent_options.go +++ b/server/fleet/agent_options.go @@ -11,7 +11,11 @@ import ( //go:generate go run ../../tools/osquery-agent-options agent_options_generated.go +const maxAgentScriptExecutionTimeout = 3600 + type AgentOptions struct { + // ScriptExecutionTimeout is the maximum time in seconds that a script can run. + ScriptExecutionTimeout int `json:"script_execution_timeout,omitempty"` // Config is the base config options. Config json.RawMessage `json:"config"` // Overrides includes any platform-based overrides. @@ -49,6 +53,10 @@ func ValidateJSONAgentOptions(ctx context.Context, ds Datastore, rawJSON json.Ra return err } + if opts.ScriptExecutionTimeout > maxAgentScriptExecutionTimeout { + return fmt.Errorf("'script_execution_timeout' value exceeds limit. Maximum value is %d", maxAgentScriptExecutionTimeout) + } + if len(opts.CommandLineStartUpFlags) > 0 { var flags osqueryCommandLineFlags if err := JSONStrictDecode(bytes.NewReader(opts.CommandLineStartUpFlags), &flags); err != nil { diff --git a/server/fleet/agent_options_test.go b/server/fleet/agent_options_test.go index 0e199298b6..3e91fa64af 100644 --- a/server/fleet/agent_options_test.go +++ b/server/fleet/agent_options_test.go @@ -28,6 +28,10 @@ func TestValidateAgentOptions(t *testing.T) { } }}`, true, `unknown field "foo"`}, + {"valid script timeout", `{"script_execution_timeout": 600}`, true, ""}, + + {"invalid script timeout", `{"script_execution_timeout": 3601}`, true, `script_execution_timeout' value exceeds limit. Maximum value is 3600`}, + {"overrides.platform is null", `{"overrides": { "platforms": { "darwin": null diff --git a/server/fleet/errors.go b/server/fleet/errors.go index 484ca36832..49d8566bd0 100644 --- a/server/fleet/errors.go +++ b/server/fleet/errors.go @@ -550,7 +550,6 @@ const ( RunScriptScriptsDisabledGloballyErrMsg = "Running scripts is disabled in organization settings." RunScriptDisabledErrMsg = "Scripts are disabled for this host. To run scripts, deploy the fleetd agent with scripts enabled." RunScriptsOrbitDisabledErrMsg = "Couldn't run script. To run a script, deploy the fleetd agent with --enable-scripts." - RunScriptScriptTimeoutErrMsg = "Timeout. Fleet stopped the script after 5 minutes to protect host performance." RunScriptAsyncScriptEnqueuedErrMsg = "Script is running or will run when the host comes online." RunScripSavedMaxLenErrMsg = "Script is too large. It's limited to 500,000 characters (approximately 10,000 lines)." RunScripUnsavedMaxLenErrMsg = "Script is too large. It's limited to 10,000 characters (approximately 125 lines)." diff --git a/server/fleet/orbit.go b/server/fleet/orbit.go index 606cedf5f1..936c2678c9 100644 --- a/server/fleet/orbit.go +++ b/server/fleet/orbit.go @@ -39,10 +39,11 @@ type OrbitConfigNotifications struct { } type OrbitConfig struct { - Flags json.RawMessage `json:"command_line_startup_flags,omitempty"` - Extensions json.RawMessage `json:"extensions,omitempty"` - NudgeConfig *NudgeConfig `json:"nudge_config,omitempty"` - Notifications OrbitConfigNotifications `json:"notifications,omitempty"` + ScriptExeTimeout int `json:"script_execution_timeout,omitempty"` + Flags json.RawMessage `json:"command_line_startup_flags,omitempty"` + Extensions json.RawMessage `json:"extensions,omitempty"` + NudgeConfig *NudgeConfig `json:"nudge_config,omitempty"` + Notifications OrbitConfigNotifications `json:"notifications,omitempty"` // UpdateChannels contains the TUF channels to use on fleetd components. // // If UpdateChannels is nil it means the server isn't using/setting this feature. diff --git a/server/fleet/scripts.go b/server/fleet/scripts.go index bd86ce7532..310b0804ed 100644 --- a/server/fleet/scripts.go +++ b/server/fleet/scripts.go @@ -3,6 +3,7 @@ package fleet import ( "bufio" "errors" + "fmt" "path/filepath" "regexp" "strings" @@ -195,6 +196,7 @@ type HostScriptResultPayload struct { Output string `json:"output"` Runtime int `json:"runtime"` ExitCode int `json:"exit_code"` + Timeout int `json:"timeout"` } // HostScriptResult represents a script result that was requested to execute on @@ -218,6 +220,9 @@ type HostScriptResult struct { // host. It is -1 if it was received but the script did not terminate // normally (same as how Go handles this: https://pkg.go.dev/os#ProcessState.ExitCode) ExitCode *int64 `json:"exit_code" db:"exit_code"` + // Timeout is the maximum time in seconds that the script was allowed to run + // at the time of execution. + Timeout *int `json:"timeout" db:"timeout"` // CreatedAt is the creation timestamp of the script execution request. It is // not returned as part of the payloads, but is used to determine if the script // is too old to still expect a response from the host. @@ -266,7 +271,7 @@ func (hsr HostScriptResult) AuthzType() string { // for running a script synchronously (so that fleetctl can display it) and to // get the script results for an execution ID (e.g. when looking at the details // screen of a script execution activity in the website). -func (hsr HostScriptResult) UserMessage(hostTimeout bool) string { +func (hsr HostScriptResult) UserMessage(hostTimeout bool, hostTimeoutValue *int) string { if hostTimeout { return RunScriptHostTimeoutErrMsg } @@ -285,7 +290,7 @@ func (hsr HostScriptResult) UserMessage(hostTimeout bool) string { switch *hsr.ExitCode { case -1: - return RunScriptScriptTimeoutErrMsg + return HostScriptTimeoutMessage(hostTimeoutValue) case -2: return RunScriptDisabledErrMsg default: @@ -293,6 +298,16 @@ func (hsr HostScriptResult) UserMessage(hostTimeout bool) string { } } +func HostScriptTimeoutMessage(seconds *int) string { + var timeout int + if seconds == nil { + timeout = int(scripts.MaxHostExecutionTime.Seconds()) + } else { + timeout = *seconds + } + return fmt.Sprintf("Timeout. Fleet stopped the script after %d seconds to protect host performance.", timeout) +} + func (hsr HostScriptResult) HostTimeout(waitForResultTime time.Duration) bool { return hsr.SyncRequest && hsr.ExitCode == nil && time.Now().After(hsr.CreatedAt.Add(waitForResultTime)) } diff --git a/server/service/integration_enterprise_test.go b/server/service/integration_enterprise_test.go index b48cb7d714..d7d26b54bc 100644 --- a/server/service/integration_enterprise_test.go +++ b/server/service/integration_enterprise_test.go @@ -25,6 +25,7 @@ import ( "github.com/fleetdm/fleet/v4/ee/server/calendar" "github.com/fleetdm/fleet/v4/pkg/optjson" + "github.com/fleetdm/fleet/v4/pkg/scripts" "github.com/fleetdm/fleet/v4/server/config" "github.com/fleetdm/fleet/v4/server/contexts/license" "github.com/fleetdm/fleet/v4/server/cron" @@ -5566,6 +5567,21 @@ func (s *integrationEnterpriseTestSuite) TestRunHostScript() { require.Contains(t, extractServerErrorText(res.Body), fleet.RunScriptDisabledErrMsg) res = s.Do("POST", "/api/latest/fleet/scripts/run/sync", fleet.HostScriptRequestPayload{HostID: plainOsqueryHost.ID, ScriptContents: "echo"}, http.StatusUnprocessableEntity) require.Contains(t, extractServerErrorText(res.Body), fleet.RunScriptDisabledErrMsg) + + // create a execution request that will return a timeout + s.DoJSON("POST", "/api/latest/fleet/scripts/run", fleet.HostScriptRequestPayload{HostID: host.ID, ScriptContents: "echo"}, http.StatusAccepted, &runResp) + + // simulate a host response + s.DoJSON("POST", "/api/fleet/orbit/scripts/result", + json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q, "execution_id": %q, "exit_code": -1, "output": "script execution error: signal: killed", "timeout": 900}`, *host.OrbitNodeKey, runSyncResp.ExecutionID)), + http.StatusOK, &orbitPostScriptResp) + + s.DoJSON("GET", "/api/latest/fleet/scripts/results/"+runSyncResp.ExecutionID, nil, http.StatusOK, &scriptResultResp) + require.Equal(t, host.ID, scriptResultResp.HostID) + require.Equal(t, "echo", scriptResultResp.ScriptContents) + require.Equal(t, int64(-1), *scriptResultResp.ExitCode) + require.Equal(t, "Timeout. Fleet stopped the script after 900 seconds to protect host performance.", scriptResultResp.Message) + require.Equal(t, "script execution error: signal: killed", scriptResultResp.Output) } func (s *integrationEnterpriseTestSuite) TestRunHostSavedScript() { @@ -6733,7 +6749,7 @@ VALUES name: "script-timeout", exitCode: ptr.Int64(-1), executedAt: now.Add(-1 * time.Hour), - expected: fleet.RunScriptScriptTimeoutErrMsg, + expected: fleet.HostScriptTimeoutMessage(ptr.Int(int(scripts.MaxHostExecutionTime.Seconds()))), }, { name: "pending", diff --git a/server/service/orbit.go b/server/service/orbit.go index 8fbc709105..0afa2631e4 100644 --- a/server/service/orbit.go +++ b/server/service/orbit.go @@ -324,11 +324,12 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro } return fleet.OrbitConfig{ - Flags: opts.CommandLineStartUpFlags, - Extensions: extensionsFiltered, - Notifications: notifs, - NudgeConfig: nudgeConfig, - UpdateChannels: updateChannels, + ScriptExeTimeout: opts.ScriptExecutionTimeout, + Flags: opts.CommandLineStartUpFlags, + Extensions: extensionsFiltered, + Notifications: notifs, + NudgeConfig: nudgeConfig, + UpdateChannels: updateChannels, }, nil } @@ -386,11 +387,12 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro } return fleet.OrbitConfig{ - Flags: opts.CommandLineStartUpFlags, - Extensions: extensionsFiltered, - Notifications: notifs, - NudgeConfig: nudgeConfig, - UpdateChannels: updateChannels, + ScriptExeTimeout: opts.ScriptExecutionTimeout, + Flags: opts.CommandLineStartUpFlags, + Extensions: extensionsFiltered, + Notifications: notifs, + NudgeConfig: nudgeConfig, + UpdateChannels: updateChannels, }, nil } diff --git a/server/service/scripts.go b/server/service/scripts.go index 91392c6d88..bb3a332b33 100644 --- a/server/service/scripts.go +++ b/server/service/scripts.go @@ -114,7 +114,7 @@ func runScriptSyncEndpoint(ctx context.Context, request interface{}, svc fleet.S // response struct. hostTimeout = true } - result.Message = result.UserMessage(hostTimeout) + result.Message = result.UserMessage(hostTimeout, result.Timeout) return runScriptSyncResponse{ HostScriptResult: result, HostTimeout: hostTimeout, @@ -371,7 +371,7 @@ func getScriptResultEndpoint(ctx context.Context, request interface{}, svc fleet // TODO: move this logic out of the endpoint function and consolidate in either the service // method or the fleet package hostTimeout := scriptResult.HostTimeout(scripts.MaxServerWaitTime) - scriptResult.Message = scriptResult.UserMessage(hostTimeout) + scriptResult.Message = scriptResult.UserMessage(hostTimeout, scriptResult.Timeout) return &getScriptResultResponse{ ScriptContents: scriptResult.ScriptContents,