From 2c3fc2033ea725cdcd85126ecc9217544f0aa1ba Mon Sep 17 00:00:00 2001 From: Martin Angers Date: Wed, 8 Jan 2025 11:49:02 -0500 Subject: [PATCH] Unified Queue: tentative DB schema, start refactoring scripts (#25215) --- .../23913-upcoming-activities-handle-scripts | 1 + ee/server/service/setup_experience.go | 9 +- server/datastore/mysql/hosts.go | 1 + .../20250106162751_AddUnifiedQueueTable.go | 70 ++++ server/datastore/mysql/schema.sql | 35 +- server/datastore/mysql/scripts.go | 119 +++++- server/datastore/mysql/scripts_test.go | 362 ++++++++++-------- 7 files changed, 417 insertions(+), 180 deletions(-) create mode 100644 changes/23913-upcoming-activities-handle-scripts create mode 100644 server/datastore/mysql/migrations/tables/20250106162751_AddUnifiedQueueTable.go diff --git a/changes/23913-upcoming-activities-handle-scripts b/changes/23913-upcoming-activities-handle-scripts new file mode 100644 index 000000000000..22c952f1966f --- /dev/null +++ b/changes/23913-upcoming-activities-handle-scripts @@ -0,0 +1 @@ +* Added script execution to the new `upcoming_activities` table. diff --git a/ee/server/service/setup_experience.go b/ee/server/service/setup_experience.go index c11b1ac05f92..79698a67e28d 100644 --- a/ee/server/service/setup_experience.go +++ b/ee/server/service/setup_experience.go @@ -224,9 +224,12 @@ func (svc *Service) SetupExperienceNextStep(ctx context.Context, hostUUID string return false, ctxerr.Errorf(ctx, "setup experience script missing content id: %d", *script.SetupExperienceScriptID) } req := &fleet.HostScriptRequestPayload{ - HostID: host.ID, - ScriptName: script.Name, - ScriptContentID: *script.ScriptContentID, + HostID: host.ID, + ScriptName: script.Name, + ScriptContentID: *script.ScriptContentID, + // because the script execution request is associated with setup experience, + // it will be enqueued with a higher priority and will run before other + // items in the queue. SetupExperienceScriptID: script.SetupExperienceScriptID, } res, err := svc.ds.NewHostScriptExecutionRequest(ctx, req) diff --git a/server/datastore/mysql/hosts.go b/server/datastore/mysql/hosts.go index a044e96998db..e1d85ed61751 100644 --- a/server/datastore/mysql/hosts.go +++ b/server/datastore/mysql/hosts.go @@ -539,6 +539,7 @@ var hostRefs = []string{ "host_activities", "host_mdm_actions", "host_calendar_events", + "upcoming_activities", } // NOTE: The following tables are explicity excluded from hostRefs list and accordingly are not diff --git a/server/datastore/mysql/migrations/tables/20250106162751_AddUnifiedQueueTable.go b/server/datastore/mysql/migrations/tables/20250106162751_AddUnifiedQueueTable.go new file mode 100644 index 000000000000..8f5c3e73542e --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20250106162751_AddUnifiedQueueTable.go @@ -0,0 +1,70 @@ +package tables + +import ( + "database/sql" +) + +func init() { + MigrationClient.AddMigration(Up_20250106162751, Down_20250106162751) +} + +func Up_20250106162751(tx *sql.Tx) error { + _, err := tx.Exec(` +CREATE TABLE upcoming_activities ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT, + host_id INT UNSIGNED NOT NULL, + + -- priority 0 is normal, > 0 is higher priority, < 0 is lower priority. + priority INT NOT NULL DEFAULT 0, + + -- user_id is the user that triggered the activity, it may be null if the + -- activity is fleet-initiated or the user was deleted. Additional user + -- information (name, email, etc.) is stored in the JSON payload. + user_id INT UNSIGNED NULL, + + -- type of activity to be executed, currently we only support those, but as + -- more activity types get added, we can enrich the ENUM with an ALTER TABLE. + activity_type ENUM('script', 'software_install', 'vpp_app_install') NOT NULL, + + -- execution_id is the identifier of the activity that will be used when + -- executed - e.g. scripts and software installs have an execution_id, and + -- it is sometimes important to know it as soon as the activity is enqueued, + -- so we need to generate it immediately. + execution_id VARCHAR(255) NOT NULL, + + -- those are all columns and not JSON fields because we need FKs on them to + -- do processing ON DELETE, otherwise we'd have to check for existence of + -- each one when executing the activity (we need the enqueue next activity + -- action to be efficient). + script_id INT UNSIGNED NULL, + script_content_id INT UNSIGNED NULL, + policy_id INT UNSIGNED NULL, + setup_experience_script_id INT UNSIGNED NULL, + + payload JSON NOT NULL, + + -- Using DATETIME instead of TIMESTAMP to prevent future Y2K38 issues + created_at DATETIME(6) NOT NULL DEFAULT NOW(6), + updated_at DATETIME(6) NOT NULL DEFAULT NOW(6) ON UPDATE NOW(6), + + PRIMARY KEY (id), + UNIQUE KEY idx_upcoming_activities_execution_id (execution_id), + INDEX idx_upcoming_activities_host_id_activity_type (host_id, priority, created_at, activity_type), + CONSTRAINT fk_upcoming_activities_script_id + FOREIGN KEY (script_id) REFERENCES scripts (id) ON DELETE SET NULL, + CONSTRAINT fk_upcoming_activities_script_content_id + FOREIGN KEY (script_content_id) REFERENCES script_contents (id) ON DELETE CASCADE, + CONSTRAINT fk_upcoming_activities_policy_id + FOREIGN KEY (policy_id) REFERENCES policies (id) ON DELETE SET NULL, + CONSTRAINT fk_upcoming_activities_setup_experience_script_id + FOREIGN KEY (setup_experience_script_id) REFERENCES setup_experience_scripts (id) ON DELETE SET NULL, + CONSTRAINT fk_upcoming_activities_user_id + FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE SET NULL +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci`, + ) + return err +} + +func Down_20250106162751(tx *sql.Tx) error { + return nil +} diff --git a/server/datastore/mysql/schema.sql b/server/datastore/mysql/schema.sql index 4588000e1f9d..fce32fea06b2 100644 --- a/server/datastore/mysql/schema.sql +++ b/server/datastore/mysql/schema.sql @@ -1111,9 +1111,9 @@ CREATE TABLE `migration_status_tables` ( `is_applied` tinyint(1) NOT NULL, `tstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) -) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB AUTO_INCREMENT=346 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +) /*!50100 TABLESPACE `innodb_system` */ ENGINE=InnoDB AUTO_INCREMENT=347 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,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240730171504,1,'2020-01-01 01:01:01'),(289,20240730174056,1,'2020-01-01 01:01:01'),(290,20240730215453,1,'2020-01-01 01:01:01'),(291,20240730374423,1,'2020-01-01 01:01:01'),(292,20240801115359,1,'2020-01-01 01:01:01'),(293,20240802101043,1,'2020-01-01 01:01:01'),(294,20240802113716,1,'2020-01-01 01:01:01'),(295,20240814135330,1,'2020-01-01 01:01:01'),(296,20240815000000,1,'2020-01-01 01:01:01'),(297,20240815000001,1,'2020-01-01 01:01:01'),(298,20240816103247,1,'2020-01-01 01:01:01'),(299,20240820091218,1,'2020-01-01 01:01:01'),(300,20240826111228,1,'2020-01-01 01:01:01'),(301,20240826160025,1,'2020-01-01 01:01:01'),(302,20240829165448,1,'2020-01-01 01:01:01'),(303,20240829165605,1,'2020-01-01 01:01:01'),(304,20240829165715,1,'2020-01-01 01:01:01'),(305,20240829165930,1,'2020-01-01 01:01:01'),(306,20240829170023,1,'2020-01-01 01:01:01'),(307,20240829170033,1,'2020-01-01 01:01:01'),(308,20240829170044,1,'2020-01-01 01:01:01'),(309,20240905105135,1,'2020-01-01 01:01:01'),(310,20240905140514,1,'2020-01-01 01:01:01'),(311,20240905200000,1,'2020-01-01 01:01:01'),(312,20240905200001,1,'2020-01-01 01:01:01'),(313,20241002104104,1,'2020-01-01 01:01:01'),(314,20241002104105,1,'2020-01-01 01:01:01'),(315,20241002104106,1,'2020-01-01 01:01:01'),(316,20241002210000,1,'2020-01-01 01:01:01'),(317,20241003145349,1,'2020-01-01 01:01:01'),(318,20241004005000,1,'2020-01-01 01:01:01'),(319,20241008083925,1,'2020-01-01 01:01:01'),(320,20241009090010,1,'2020-01-01 01:01:01'),(321,20241017163402,1,'2020-01-01 01:01:01'),(322,20241021224359,1,'2020-01-01 01:01:01'),(323,20241022140321,1,'2020-01-01 01:01:01'),(324,20241025111236,1,'2020-01-01 01:01:01'),(325,20241025112748,1,'2020-01-01 01:01:01'),(326,20241025141855,1,'2020-01-01 01:01:01'),(327,20241110152839,1,'2020-01-01 01:01:01'),(328,20241110152840,1,'2020-01-01 01:01:01'),(329,20241110152841,1,'2020-01-01 01:01:01'),(330,20241116233322,1,'2020-01-01 01:01:01'),(331,20241122171434,1,'2020-01-01 01:01:01'),(332,20241125150614,1,'2020-01-01 01:01:01'),(333,20241203125346,1,'2020-01-01 01:01:01'),(334,20241203130032,1,'2020-01-01 01:01:01'),(335,20241205122800,1,'2020-01-01 01:01:01'),(336,20241209164540,1,'2020-01-01 01:01:01'),(337,20241210140021,1,'2020-01-01 01:01:01'),(338,20241219180042,1,'2020-01-01 01:01:01'),(339,20241220100000,1,'2020-01-01 01:01:01'),(340,20241220114903,1,'2020-01-01 01:01:01'),(341,20241220114904,1,'2020-01-01 01:01:01'),(342,20241224000000,1,'2020-01-01 01:01:01'),(343,20241230000000,1,'2020-01-01 01:01:01'),(344,20241231112624,1,'2020-01-01 01:01:01'),(345,20250102121439,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,20240709183940,1,'2020-01-01 01:01:01'),(283,20240710155623,1,'2020-01-01 01:01:01'),(284,20240723102712,1,'2020-01-01 01:01:01'),(285,20240725152735,1,'2020-01-01 01:01:01'),(286,20240725182118,1,'2020-01-01 01:01:01'),(287,20240726100517,1,'2020-01-01 01:01:01'),(288,20240730171504,1,'2020-01-01 01:01:01'),(289,20240730174056,1,'2020-01-01 01:01:01'),(290,20240730215453,1,'2020-01-01 01:01:01'),(291,20240730374423,1,'2020-01-01 01:01:01'),(292,20240801115359,1,'2020-01-01 01:01:01'),(293,20240802101043,1,'2020-01-01 01:01:01'),(294,20240802113716,1,'2020-01-01 01:01:01'),(295,20240814135330,1,'2020-01-01 01:01:01'),(296,20240815000000,1,'2020-01-01 01:01:01'),(297,20240815000001,1,'2020-01-01 01:01:01'),(298,20240816103247,1,'2020-01-01 01:01:01'),(299,20240820091218,1,'2020-01-01 01:01:01'),(300,20240826111228,1,'2020-01-01 01:01:01'),(301,20240826160025,1,'2020-01-01 01:01:01'),(302,20240829165448,1,'2020-01-01 01:01:01'),(303,20240829165605,1,'2020-01-01 01:01:01'),(304,20240829165715,1,'2020-01-01 01:01:01'),(305,20240829165930,1,'2020-01-01 01:01:01'),(306,20240829170023,1,'2020-01-01 01:01:01'),(307,20240829170033,1,'2020-01-01 01:01:01'),(308,20240829170044,1,'2020-01-01 01:01:01'),(309,20240905105135,1,'2020-01-01 01:01:01'),(310,20240905140514,1,'2020-01-01 01:01:01'),(311,20240905200000,1,'2020-01-01 01:01:01'),(312,20240905200001,1,'2020-01-01 01:01:01'),(313,20241002104104,1,'2020-01-01 01:01:01'),(314,20241002104105,1,'2020-01-01 01:01:01'),(315,20241002104106,1,'2020-01-01 01:01:01'),(316,20241002210000,1,'2020-01-01 01:01:01'),(317,20241003145349,1,'2020-01-01 01:01:01'),(318,20241004005000,1,'2020-01-01 01:01:01'),(319,20241008083925,1,'2020-01-01 01:01:01'),(320,20241009090010,1,'2020-01-01 01:01:01'),(321,20241017163402,1,'2020-01-01 01:01:01'),(322,20241021224359,1,'2020-01-01 01:01:01'),(323,20241022140321,1,'2020-01-01 01:01:01'),(324,20241025111236,1,'2020-01-01 01:01:01'),(325,20241025112748,1,'2020-01-01 01:01:01'),(326,20241025141855,1,'2020-01-01 01:01:01'),(327,20241110152839,1,'2020-01-01 01:01:01'),(328,20241110152840,1,'2020-01-01 01:01:01'),(329,20241110152841,1,'2020-01-01 01:01:01'),(330,20241116233322,1,'2020-01-01 01:01:01'),(331,20241122171434,1,'2020-01-01 01:01:01'),(332,20241125150614,1,'2020-01-01 01:01:01'),(333,20241203125346,1,'2020-01-01 01:01:01'),(334,20241203130032,1,'2020-01-01 01:01:01'),(335,20241205122800,1,'2020-01-01 01:01:01'),(336,20241209164540,1,'2020-01-01 01:01:01'),(337,20241210140021,1,'2020-01-01 01:01:01'),(338,20241219180042,1,'2020-01-01 01:01:01'),(339,20241220100000,1,'2020-01-01 01:01:01'),(340,20241220114903,1,'2020-01-01 01:01:01'),(341,20241220114904,1,'2020-01-01 01:01:01'),(342,20241224000000,1,'2020-01-01 01:01:01'),(343,20241230000000,1,'2020-01-01 01:01:01'),(344,20241231112624,1,'2020-01-01 01:01:01'),(345,20250102121439,1,'2020-01-01 01:01:01'),(346,20250106162751,1,'2020-01-01 01:01:01'); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `mobile_device_management_solutions` ( @@ -1911,6 +1911,37 @@ CREATE TABLE `teams` ( /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `upcoming_activities` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `host_id` int unsigned NOT NULL, + `priority` int NOT NULL DEFAULT '0', + `user_id` int unsigned DEFAULT NULL, + `activity_type` enum('script','software_install','vpp_app_install') COLLATE utf8mb4_unicode_ci NOT NULL, + `execution_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `script_id` int unsigned DEFAULT NULL, + `script_content_id` int unsigned DEFAULT NULL, + `policy_id` int unsigned DEFAULT NULL, + `setup_experience_script_id` int unsigned DEFAULT NULL, + `payload` json NOT NULL, + `created_at` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), + `updated_at` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), + PRIMARY KEY (`id`), + UNIQUE KEY `idx_upcoming_activities_execution_id` (`execution_id`), + KEY `idx_upcoming_activities_host_id_activity_type` (`host_id`,`priority`,`created_at`,`activity_type`), + KEY `fk_upcoming_activities_script_id` (`script_id`), + KEY `fk_upcoming_activities_script_content_id` (`script_content_id`), + KEY `fk_upcoming_activities_policy_id` (`policy_id`), + KEY `fk_upcoming_activities_setup_experience_script_id` (`setup_experience_script_id`), + KEY `fk_upcoming_activities_user_id` (`user_id`), + CONSTRAINT `fk_upcoming_activities_policy_id` FOREIGN KEY (`policy_id`) REFERENCES `policies` (`id`) ON DELETE SET NULL, + CONSTRAINT `fk_upcoming_activities_script_content_id` FOREIGN KEY (`script_content_id`) REFERENCES `script_contents` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_upcoming_activities_script_id` FOREIGN KEY (`script_id`) REFERENCES `scripts` (`id`) ON DELETE SET NULL, + CONSTRAINT `fk_upcoming_activities_setup_experience_script_id` FOREIGN KEY (`setup_experience_script_id`) REFERENCES `setup_experience_scripts` (`id`) ON DELETE SET NULL, + CONSTRAINT `fk_upcoming_activities_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `user_teams` ( `user_id` int unsigned NOT NULL, `team_id` int unsigned NOT NULL, diff --git a/server/datastore/mysql/scripts.go b/server/datastore/mysql/scripts.go index 53d162d524cf..6118f3786675 100644 --- a/server/datastore/mysql/scripts.go +++ b/server/datastore/mysql/scripts.go @@ -18,6 +18,8 @@ import ( "github.com/jmoiron/sqlx" ) +// TODO(mna): does it still make sense to have that sync/async distinction? +// A pending script is a pending script, no? const whereFilterPendingScript = ` exit_code IS NULL -- async requests + sync requests created within the given interval @@ -60,21 +62,55 @@ func (ds *Datastore) NewInternalScriptExecutionRequest(ctx context.Context, requ func newHostScriptExecutionRequest(ctx context.Context, tx sqlx.ExtContext, request *fleet.HostScriptRequestPayload, isInternal bool) (*fleet.HostScriptResult, error) { const ( - insStmt = `INSERT INTO host_script_results (host_id, execution_id, script_content_id, output, script_id, policy_id, user_id, sync_request, setup_experience_script_id, is_internal) VALUES (?, ?, ?, '', ?, ?, ?, ?, ?, ?)` - getStmt = `SELECT hsr.id, hsr.host_id, hsr.execution_id, hsr.created_at, hsr.script_id, hsr.policy_id, hsr.user_id, hsr.sync_request, sc.contents as script_contents, hsr.setup_experience_script_id FROM host_script_results hsr JOIN script_contents sc WHERE sc.id = hsr.script_content_id AND hsr.id = ?` + insStmt = ` +INSERT INTO upcoming_activities + ( + host_id, user_id, activity_type, execution_id, script_id, script_content_id, + policy_id, setup_experience_script_id, priority, payload + ) +VALUES + (?, ?, 'script', ?, ?, ?, ?, ?, ?, + JSON_OBJECT( + 'sync_request', ?, + 'is_internal', ?, + 'user', (SELECT JSON_OBJECT('name', name, 'email', email) FROM users WHERE id = ?) + ) + )` + + getStmt = ` +SELECT + ua.id, ua.host_id, ua.execution_id, ua.created_at, ua.script_id, ua.policy_id, ua.user_id, + JSON_EXTRACT(payload, '$.sync_request') AS sync_request, + sc.contents as script_contents, ua.setup_experience_script_id +FROM + upcoming_activities ua + INNER JOIN script_contents sc + ON ua.script_content_id = sc.id +WHERE + ua.id = ? +` ) + var priority int + if request.SetupExperienceScriptID != nil { + // a bit naive/simplistic for now, but we'll support user-provided + // priorities in a future story and we can improve on how we manage those. + priority = 100 + } + execID := uuid.New().String() result, err := tx.ExecContext(ctx, insStmt, request.HostID, + request.UserID, execID, - request.ScriptContentID, request.ScriptID, + request.ScriptContentID, request.PolicyID, - request.UserID, - request.SyncRequest, request.SetupExperienceScriptID, + priority, + request.SyncRequest, isInternal, + request.UserID, ) if err != nil { return nil, ctxerr.Wrap(ctx, err, "new host script execution request") @@ -86,7 +122,6 @@ func newHostScriptExecutionRequest(ctx context.Context, tx sqlx.ExtContext, requ if err != nil { return nil, ctxerr.Wrap(ctx, err, "getting the created host script result to return") } - return &script, nil } @@ -226,12 +261,14 @@ func (ds *Datastore) SetHostScriptExecutionResult(ctx context.Context, result *f } func (ds *Datastore) ListPendingHostScriptExecutions(ctx context.Context, hostID uint, onlyShowInternal bool) ([]*fleet.HostScriptResult, error) { + // pending host script executions are those without results in + // host_script_results UNION those in the upcoming activities queue internalWhere := "" if onlyShowInternal { internalWhere = " AND is_internal = TRUE" } - listStmt := fmt.Sprintf(` + listHSRStmt := fmt.Sprintf(` SELECT id, host_id, @@ -246,9 +283,33 @@ func (ds *Datastore) ListPendingHostScriptExecutions(ctx context.Context, hostID ORDER BY created_at ASC`, whereFilterPendingScript, internalWhere) + if onlyShowInternal { + internalWhere = " AND JSON_EXTRACT(payload, '$.is_internal') = 1" + } + listUAStmt := fmt.Sprintf(` + SELECT + id, + host_id, + execution_id, + script_id + FROM + upcoming_activities + WHERE + host_id = ? AND + activity_type = 'script' AND + ( + JSON_EXTRACT(payload, '$.sync_request') = 0 OR + created_at >= DATE_SUB(NOW(), INTERVAL ? SECOND) + ) + %s + ORDER BY + priority DESC, created_at ASC`, internalWhere) + + stmt := fmt.Sprintf(`(%s) UNION (%s)`, listHSRStmt, listUAStmt) + var results []*fleet.HostScriptResult seconds := int(constants.MaxServerWaitTime.Seconds()) - if err := sqlx.SelectContext(ctx, ds.reader(ctx), &results, listStmt, hostID, seconds); err != nil { + if err := sqlx.SelectContext(ctx, ds.reader(ctx), &results, stmt, hostID, seconds, hostID, seconds); err != nil { return nil, ctxerr.Wrap(ctx, err, "list pending host script executions") } return results, nil @@ -264,10 +325,19 @@ func (ds *Datastore) IsExecutionPendingForHost(ctx context.Context, hostID uint, host_id = ? AND script_id = ? AND exit_code IS NULL + UNION + SELECT + 1 + FROM + upcoming_activities + WHERE + host_id = ? AND + activity_type = 'script' AND + script_id = ? ` var results []*uint - if err := sqlx.SelectContext(ctx, ds.reader(ctx), &results, getStmt, hostID, scriptID); err != nil { + if err := sqlx.SelectContext(ctx, ds.reader(ctx), &results, getStmt, hostID, scriptID, hostID, scriptID); err != nil { return false, ctxerr.Wrap(ctx, err, "is execution pending for host") } return len(results) > 0, nil @@ -501,10 +571,15 @@ func (ds *Datastore) deletePendingHostScriptExecutionsForPolicy(ctx context.Cont globalOrTeamID = *teamID } - deleteStmt := fmt.Sprintf(` + deletePendingFunc := func(stmt string, args ...any) error { + _, err := ds.writer(ctx).ExecContext(ctx, stmt, args...) + return ctxerr.Wrap(ctx, err, "delete pending host script executions for policy") + } + + deleteHSRStmt := fmt.Sprintf(` DELETE FROM host_script_results - WHERE + WHERE policy_id = ? AND script_id IN ( SELECT id FROM scripts WHERE scripts.global_or_team_id = ? @@ -513,9 +588,22 @@ func (ds *Datastore) deletePendingHostScriptExecutionsForPolicy(ctx context.Cont `, whereFilterPendingScript) seconds := int(constants.MaxServerWaitTime.Seconds()) - _, err := ds.writer(ctx).ExecContext(ctx, deleteStmt, policyID, globalOrTeamID, seconds) - if err != nil { - return ctxerr.Wrap(ctx, err, "delete pending host script executions for policy") + if err := deletePendingFunc(deleteHSRStmt, policyID, globalOrTeamID, seconds); err != nil { + return err + } + + deleteUAStmt := ` + DELETE FROM + upcoming_activities + WHERE + policy_id = ? AND + activity_type = 'script' AND + script_id IN ( + SELECT id FROM scripts WHERE scripts.global_or_team_id = ? + ) +` + if err := deletePendingFunc(deleteUAStmt, policyID, globalOrTeamID); err != nil { + return err } return nil @@ -1312,6 +1400,9 @@ WHERE AND NOT EXISTS ( SELECT 1 FROM setup_experience_scripts WHERE script_content_id = script_contents.id ) + AND NOT EXISTS ( + SELECT 1 FROM upcoming_activities WHERE script_content_id = script_contents.id + ) ` _, err := ds.writer(ctx).ExecContext(ctx, deleteStmt) if err != nil { diff --git a/server/datastore/mysql/scripts_test.go b/server/datastore/mysql/scripts_test.go index 1a449e7ce6cc..b3c83e08e8a4 100644 --- a/server/datastore/mysql/scripts_test.go +++ b/server/datastore/mysql/scripts_test.go @@ -4,7 +4,6 @@ import ( "context" _ "embed" "fmt" - "math" "strings" "testing" "time" @@ -64,199 +63,237 @@ func testHostScriptResult(t *testing.T, ds *Datastore) { // create a createdScript execution request (with a user) u := test.NewUser(t, ds, "Bob", "bob@example.com", true) - createdScript, err := ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ + createdScript1, err := ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ HostID: 1, ScriptContents: "echo", UserID: &u.ID, SyncRequest: true, }) require.NoError(t, err) - require.NotZero(t, createdScript.ID) - require.NotEmpty(t, createdScript.ExecutionID) - require.Equal(t, uint(1), createdScript.HostID) - require.NotEmpty(t, createdScript.ExecutionID) - require.Equal(t, "echo", createdScript.ScriptContents) - require.Nil(t, createdScript.ExitCode) - require.Empty(t, createdScript.Output) - require.NotNil(t, createdScript.UserID) - require.Equal(t, u.ID, *createdScript.UserID) - require.True(t, createdScript.SyncRequest) + require.NotZero(t, createdScript1.ID) + require.NotEmpty(t, createdScript1.ExecutionID) + require.Equal(t, uint(1), createdScript1.HostID) + require.NotEmpty(t, createdScript1.ExecutionID) + require.Equal(t, "echo", createdScript1.ScriptContents) + require.Nil(t, createdScript1.ExitCode) + require.Empty(t, createdScript1.Output) + require.NotNil(t, createdScript1.UserID) + require.Equal(t, u.ID, *createdScript1.UserID) + require.True(t, createdScript1.SyncRequest) // the script execution is now listed as pending for this host pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false) require.NoError(t, err) require.Len(t, pending, 1) - require.Equal(t, createdScript.ID, pending[0].ID) + require.Equal(t, createdScript1.ID, pending[0].ID) // the script execution isn't visible when looking at internal-only scripts pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, true) require.NoError(t, err) require.Empty(t, pending) - // record a result for this execution - hsr, action, err := ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{ - HostID: 1, - ExecutionID: createdScript.ExecutionID, - Output: "foo", - Runtime: 2, - ExitCode: 0, - Timeout: 300, - }) - require.NoError(t, err) - assert.Empty(t, action) - assert.NotNil(t, hsr) - - // record a duplicate result for this execution, will be ignored - hsr, _, err = ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{ - HostID: 1, - ExecutionID: createdScript.ExecutionID, - Output: "foobarbaz", - Runtime: 22, - ExitCode: 1, - Timeout: 360, - }) - require.NoError(t, err) - require.Nil(t, hsr) + // TODO(mna): uncomment once unified queue processing is implemented + /* + // record a result for this execution + hsr, action, err := ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{ + HostID: 1, + ExecutionID: createdScript.ExecutionID, + Output: "foo", + Runtime: 2, + ExitCode: 0, + Timeout: 300, + }) + require.NoError(t, err) + assert.Empty(t, action) + assert.NotNil(t, hsr) + + // record a duplicate result for this execution, will be ignored + hsr, _, err = ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{ + HostID: 1, + ExecutionID: createdScript.ExecutionID, + Output: "foobarbaz", + Runtime: 22, + ExitCode: 1, + Timeout: 360, + }) + require.NoError(t, err) + require.Nil(t, hsr) - // it is not pending anymore - pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false) - require.NoError(t, err) - require.Empty(t, pending) + // it is not pending anymore + pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false) + require.NoError(t, err) + require.Empty(t, pending) - // the script result can be retrieved - script, err := ds.GetHostScriptExecutionResult(ctx, createdScript.ExecutionID) - require.NoError(t, err) - expectScript := *createdScript - expectScript.Output = "foo" - expectScript.Runtime = 2 - expectScript.ExitCode = ptr.Int64(0) - expectScript.Timeout = ptr.Int(300) - require.Equal(t, &expectScript, script) + // the script result can be retrieved + script, err := ds.GetHostScriptExecutionResult(ctx, createdScript.ExecutionID) + require.NoError(t, err) + expectScript := *createdScript + 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) - createdScript, err = ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ + createdScript2, err := ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ HostID: 1, ScriptContents: "echo2", }) require.NoError(t, err) - require.NotZero(t, createdScript.ID) - require.NotEmpty(t, createdScript.ExecutionID) - require.Nil(t, createdScript.UserID) - require.False(t, createdScript.SyncRequest) - - // the script result can be retrieved even if it has no result yet - script, err = ds.GetHostScriptExecutionResult(ctx, createdScript.ExecutionID) - require.NoError(t, err) - require.Equal(t, createdScript, script) - - // record a result for this execution, with an output that is too large - largeOutput := strings.Repeat("a", 1000) + - strings.Repeat("b", 1000) + - strings.Repeat("c", 1000) + - strings.Repeat("d", 1000) + - strings.Repeat("e", 1000) + - strings.Repeat("f", 1000) + - strings.Repeat("g", 1000) + - strings.Repeat("h", 1000) + - strings.Repeat("i", 1000) + - strings.Repeat("j", 1000) + - strings.Repeat("k", 1000) - expectedOutput := strings.Repeat("b", 1000) + - strings.Repeat("c", 1000) + - strings.Repeat("d", 1000) + - strings.Repeat("e", 1000) + - strings.Repeat("f", 1000) + - strings.Repeat("g", 1000) + - strings.Repeat("h", 1000) + - strings.Repeat("i", 1000) + - strings.Repeat("j", 1000) + - strings.Repeat("k", 1000) - - _, _, err = ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{ - HostID: 1, - ExecutionID: createdScript.ExecutionID, - Output: largeOutput, - Runtime: 10, - ExitCode: 1, - Timeout: 300, - }) - require.NoError(t, err) + require.NotZero(t, createdScript2.ID) + require.NotEmpty(t, createdScript2.ExecutionID) + require.Nil(t, createdScript2.UserID) + require.False(t, createdScript2.SyncRequest) - // the script result can be retrieved - script, err = ds.GetHostScriptExecutionResult(ctx, createdScript.ExecutionID) + // the script execution is now listed as pending for this host + pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false) require.NoError(t, err) - require.Equal(t, expectedOutput, script.Output) + require.Len(t, pending, 2) + require.Equal(t, createdScript1.ID, pending[0].ID) + require.Equal(t, createdScript2.ID, pending[1].ID) + + /* + // the script result can be retrieved even if it has no result yet + script, err = ds.GetHostScriptExecutionResult(ctx, createdScript.ExecutionID) + require.NoError(t, err) + require.Equal(t, createdScript, script) + + // record a result for this execution, with an output that is too large + largeOutput := strings.Repeat("a", 1000) + + strings.Repeat("b", 1000) + + strings.Repeat("c", 1000) + + strings.Repeat("d", 1000) + + strings.Repeat("e", 1000) + + strings.Repeat("f", 1000) + + strings.Repeat("g", 1000) + + strings.Repeat("h", 1000) + + strings.Repeat("i", 1000) + + strings.Repeat("j", 1000) + + strings.Repeat("k", 1000) + expectedOutput := strings.Repeat("b", 1000) + + strings.Repeat("c", 1000) + + strings.Repeat("d", 1000) + + strings.Repeat("e", 1000) + + strings.Repeat("f", 1000) + + strings.Repeat("g", 1000) + + strings.Repeat("h", 1000) + + strings.Repeat("i", 1000) + + strings.Repeat("j", 1000) + + strings.Repeat("k", 1000) + + _, _, err = ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{ + HostID: 1, + ExecutionID: createdScript.ExecutionID, + Output: largeOutput, + Runtime: 10, + ExitCode: 1, + Timeout: 300, + }) + require.NoError(t, err) + + // the script result can be retrieved + script, err = ds.GetHostScriptExecutionResult(ctx, createdScript.ExecutionID) + require.NoError(t, err) + require.Equal(t, expectedOutput, script.Output) + */ // create an async execution request - createdScript, err = ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ + createdScript3, err := ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ HostID: 1, ScriptContents: "echo 3", UserID: &u.ID, SyncRequest: false, }) require.NoError(t, err) - require.NotZero(t, createdScript.ID) - require.NotEmpty(t, createdScript.ExecutionID) - require.Equal(t, uint(1), createdScript.HostID) - require.NotEmpty(t, createdScript.ExecutionID) - require.Equal(t, "echo 3", createdScript.ScriptContents) - require.Nil(t, createdScript.ExitCode) - require.Empty(t, createdScript.Output) - require.NotNil(t, createdScript.UserID) - require.Equal(t, u.ID, *createdScript.UserID) - require.False(t, createdScript.SyncRequest) + require.NotZero(t, createdScript3.ID) + require.NotEmpty(t, createdScript3.ExecutionID) + require.Equal(t, uint(1), createdScript3.HostID) + require.NotEmpty(t, createdScript3.ExecutionID) + require.Equal(t, "echo 3", createdScript3.ScriptContents) + require.Nil(t, createdScript3.ExitCode) + require.Empty(t, createdScript3.Output) + require.NotNil(t, createdScript3.UserID) + require.Equal(t, u.ID, *createdScript3.UserID) + require.False(t, createdScript3.SyncRequest) // the script execution is now listed as pending for this host pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false) require.NoError(t, err) - require.Len(t, pending, 1) - require.Equal(t, createdScript.ID, pending[0].ID) + require.Len(t, pending, 3) + require.Equal(t, createdScript1.ID, pending[0].ID) + require.Equal(t, createdScript2.ID, pending[1].ID) + require.Equal(t, createdScript3.ID, pending[2].ID) + + /* + // modify the timestamp of the script to simulate an script that has + // been pending for a long time + ExecAdhocSQL(t, ds, func(tx sqlx.ExtContext) error { + _, err := tx.ExecContext(ctx, "UPDATE host_script_results SET created_at = ? WHERE id = ?", time.Now().Add(-24*time.Hour), createdScript3.ID) + return err + }) + */ - // modify the timestamp of the script to simulate an script that has + // modify the timestamp of the upcoming script to simulate an script that has // been pending for a long time ExecAdhocSQL(t, ds, func(tx sqlx.ExtContext) error { - _, err := tx.ExecContext(ctx, "UPDATE host_script_results SET created_at = ? WHERE id = ?", time.Now().Add(-24*time.Hour), createdScript.ID) + _, err := tx.ExecContext(ctx, "UPDATE upcoming_activities SET created_at = ? WHERE id = ?", time.Now().Add(-24*time.Hour), createdScript3.ID) return err }) - // the script execution still shows as pending + // the script execution still shows as pending (and is now next in line, oldest) pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false) require.NoError(t, err) - require.Len(t, pending, 1) - require.Equal(t, createdScript.ID, pending[0].ID) + require.Len(t, pending, 3) + require.Equal(t, createdScript3.ID, pending[0].ID) + require.Equal(t, createdScript1.ID, pending[1].ID) + require.Equal(t, createdScript2.ID, pending[2].ID) - // modify the script to be a sync script that has + /* + // modify the script to be a sync script that has + // been pending for a long time + ExecAdhocSQL(t, ds, func(tx sqlx.ExtContext) error { + _, err := tx.ExecContext(ctx, "UPDATE host_script_results SET sync_request = 1 WHERE id = ?", createdScript3.ID) + return err + }) + */ + + // modify the upcoming script to be a sync script that has // been pending for a long time ExecAdhocSQL(t, ds, func(tx sqlx.ExtContext) error { - _, err := tx.ExecContext(ctx, "UPDATE host_script_results SET sync_request = 1 WHERE id = ?", createdScript.ID) + _, err := tx.ExecContext(ctx, "UPDATE upcoming_activities SET payload = JSON_SET(payload, '$.sync_request', true) WHERE id = ?", createdScript3.ID) return err }) // the script is not pending anymore pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false) require.NoError(t, err) - require.Empty(t, pending, 0) + require.Len(t, pending, 2) + require.Equal(t, createdScript1.ID, pending[0].ID) + require.Equal(t, createdScript2.ID, pending[1].ID) - // check that scripts with large unsigned error codes get - // converted to signed error codes - createdUnsignedScript, err := ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ - HostID: 1, - ScriptContents: "echo", - UserID: &u.ID, - SyncRequest: true, - }) - require.NoError(t, err) + /* + // check that scripts with large unsigned error codes get + // converted to signed error codes + createdUnsignedScript, err := ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ + HostID: 1, + ScriptContents: "echo", + UserID: &u.ID, + SyncRequest: true, + }) + require.NoError(t, err) - unsignedScriptResult, _, err := ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{ - HostID: 1, - ExecutionID: createdUnsignedScript.ExecutionID, - Output: "foo", - Runtime: 1, - ExitCode: math.MaxUint32, - Timeout: 300, - }) - require.NoError(t, err) - require.EqualValues(t, -1, *unsignedScriptResult.ExitCode) + unsignedScriptResult, _, err := ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{ + HostID: 1, + ExecutionID: createdUnsignedScript.ExecutionID, + Output: "foo", + Runtime: 1, + ExitCode: math.MaxUint32, + Timeout: 300, + }) + require.NoError(t, err) + require.EqualValues(t, -1, *unsignedScriptResult.ExitCode) + */ } func testScripts(t *testing.T, ds *Datastore) { @@ -1508,32 +1545,35 @@ func testDeletePendingHostScriptExecutionsForPolicy(t *testing.T, ds *Datastore) require.NoError(t, err) require.Equal(t, 1, len(pending)) - // test not pending host script execution for correct policy - scriptExecution, err := ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ - HostID: 1, - ScriptContents: "echo", - UserID: &user.ID, - PolicyID: &p1.ID, - SyncRequest: true, - ScriptID: &script1.ID, - }) - require.NoError(t, err) - ExecAdhocSQL(t, ds, func(q sqlx.ExtContext) error { - _, err = q.ExecContext(ctx, `UPDATE host_script_results SET exit_code = 1 WHERE id = ?`, scriptExecution.ID) + // TODO(mna): adjust test once script execution via unified queue is implemented + /* + // test not pending host script execution for correct policy + scriptExecution, err := ds.NewHostScriptExecutionRequest(ctx, &fleet.HostScriptRequestPayload{ + HostID: 1, + ScriptContents: "echo", + UserID: &user.ID, + PolicyID: &p1.ID, + SyncRequest: true, + ScriptID: &script1.ID, + }) require.NoError(t, err) - return nil - }) + ExecAdhocSQL(t, ds, func(q sqlx.ExtContext) error { + _, err = q.ExecContext(ctx, `UPDATE host_script_results SET exit_code = 1 WHERE id = ?`, scriptExecution.ID) + require.NoError(t, err) + return nil + }) - err = ds.deletePendingHostScriptExecutionsForPolicy(ctx, &team1.ID, p1.ID) - require.NoError(t, err) + err = ds.deletePendingHostScriptExecutionsForPolicy(ctx, &team1.ID, p1.ID) + require.NoError(t, err) - var count int - err = sqlx.GetContext( - ctx, - ds.reader(ctx), - &count, - "SELECT count(1) FROM host_script_results WHERE id = ?", - scriptExecution.ID, - ) - require.Equal(t, 1, count) + var count int + err = sqlx.GetContext( + ctx, + ds.reader(ctx), + &count, + "SELECT count(1) FROM host_script_results WHERE id = ?", + scriptExecution.ID, + ) + require.Equal(t, 1, count) + */ }