diff --git a/changes/issue-1601-expose-disk-space b/changes/issue-1601-expose-disk-space new file mode 100644 index 0000000000..a2732d6cc6 --- /dev/null +++ b/changes/issue-1601-expose-disk-space @@ -0,0 +1 @@ +* Expose free disk space in gigs and percentage for hosts. diff --git a/cmd/fleetctl/get_test.go b/cmd/fleetctl/get_test.go index 0c024a1c07..2aab7cfd06 100644 --- a/cmd/fleetctl/get_test.go +++ b/cmd/fleetctl/get_test.go @@ -207,6 +207,7 @@ spec: detail_updated_at: "0001-01-01T00:00:00Z" display_text: test_host distributed_interval: 0 + gigs_disk_space_available: 0 hardware_model: "" hardware_serial: "" hardware_vendor: "" @@ -220,6 +221,7 @@ spec: os_version: "" osquery_version: "" pack_stats: null + percent_disk_space_available: 0 platform: "" platform_like: "" primary_ip: "" @@ -233,8 +235,7 @@ spec: uptime: 0 uuid: "" ` - expectedJson := `{"kind":"host","apiVersion":"v1","spec":{"created_at":"0001-01-01T00:00:00Z","updated_at":"0001-01-01T00:00:00Z","id":0,"detail_updated_at":"0001-01-01T00:00:00Z","label_updated_at":"0001-01-01T00:00:00Z","last_enrolled_at":"0001-01-01T00:00:00Z","seen_time":"0001-01-01T00:00:00Z","refetch_requested":false,"hostname":"test_host","uuid":"","platform":"","osquery_version":"","os_version":"","build":"","platform_like":"","code_name":"","uptime":0,"memory":0,"cpu_type":"","cpu_subtype":"","cpu_brand":"","cpu_physical_cores":0,"cpu_logical_cores":0,"hardware_vendor":"","hardware_model":"","hardware_version":"","hardware_serial":"","computer_name":"test_host","primary_ip":"","primary_mac":"","distributed_interval":0,"config_tls_refresh":0,"logger_tls_period":0,"team_id":null,"pack_stats":null,"team_name":null,"status":"mia","display_text":"test_host"}} -` + expectedJson := "{\"kind\":\"host\",\"apiVersion\":\"v1\",\"spec\":{\"created_at\":\"0001-01-01T00:00:00Z\",\"updated_at\":\"0001-01-01T00:00:00Z\",\"id\":0,\"detail_updated_at\":\"0001-01-01T00:00:00Z\",\"label_updated_at\":\"0001-01-01T00:00:00Z\",\"last_enrolled_at\":\"0001-01-01T00:00:00Z\",\"seen_time\":\"0001-01-01T00:00:00Z\",\"refetch_requested\":false,\"hostname\":\"test_host\",\"uuid\":\"\",\"platform\":\"\",\"osquery_version\":\"\",\"os_version\":\"\",\"build\":\"\",\"platform_like\":\"\",\"code_name\":\"\",\"uptime\":0,\"memory\":0,\"cpu_type\":\"\",\"cpu_subtype\":\"\",\"cpu_brand\":\"\",\"cpu_physical_cores\":0,\"cpu_logical_cores\":0,\"hardware_vendor\":\"\",\"hardware_model\":\"\",\"hardware_version\":\"\",\"hardware_serial\":\"\",\"computer_name\":\"test_host\",\"primary_ip\":\"\",\"primary_mac\":\"\",\"distributed_interval\":0,\"config_tls_refresh\":0,\"logger_tls_period\":0,\"team_id\":null,\"pack_stats\":null,\"team_name\":null,\"gigs_disk_space_available\":0,\"percent_disk_space_available\":0,\"status\":\"mia\",\"display_text\":\"test_host\"}}\n" assert.Equal(t, expectedText, runAppForTest(t, []string{"get", "hosts"})) assert.Equal(t, expectedYaml, runAppForTest(t, []string{"get", "hosts", "--yaml"})) diff --git a/server/datastore/mysql/hosts.go b/server/datastore/mysql/hosts.go index 5e2c263fd5..64ae4aa733 100644 --- a/server/datastore/mysql/hosts.go +++ b/server/datastore/mysql/hosts.go @@ -90,7 +90,9 @@ func (d *Datastore) SaveHost(host *fleet.Host) error { team_id = ?, primary_ip = ?, primary_mac = ?, - refetch_requested = ? + refetch_requested = ?, + gigs_disk_space_available = ?, + percent_disk_space_available = ? WHERE id = ? ` _, err := d.db.Exec(sqlStatement, @@ -125,6 +127,8 @@ func (d *Datastore) SaveHost(host *fleet.Host) error { host.PrimaryIP, host.PrimaryMac, host.RefetchRequested, + host.GigsDiskSpaceAvailable, + host.PercentDiskSpaceAvailable, host.ID, ) if err != nil { diff --git a/server/datastore/mysql/migrations/tables/20210818182258_AddDiskSpaceColumns.go b/server/datastore/mysql/migrations/tables/20210818182258_AddDiskSpaceColumns.go new file mode 100644 index 0000000000..971cca8079 --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20210818182258_AddDiskSpaceColumns.go @@ -0,0 +1,27 @@ +package tables + +import ( + "database/sql" + + "github.com/pkg/errors" +) + +func init() { + MigrationClient.AddMigration(Up_20210818182258, Down_20210818182258) +} + +func Up_20210818182258(tx *sql.Tx) error { + sql := ` + ALTER TABLE hosts + ADD COLUMN gigs_disk_space_available FLOAT NOT NULL DEFAULT 0, + ADD COLUMN percent_disk_space_available FLOAT NOT NULL DEFAULT 0 + ` + if _, err := tx.Exec(sql); err != nil { + return errors.Wrap(err, "add columns for disk_space") + } + return nil +} + +func Down_20210818182258(tx *sql.Tx) error { + return nil +} diff --git a/server/datastore/mysql/schema.sql b/server/datastore/mysql/schema.sql index fe51c43af6..96bd71d78c 100644 --- a/server/datastore/mysql/schema.sql +++ b/server/datastore/mysql/schema.sql @@ -23,7 +23,7 @@ CREATE TABLE `app_config_json` ( UNIQUE KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `app_config_json` VALUES (1,'{\"org_info\": {\"org_name\": \"\", \"org_logo_url\": \"\"}, \"sso_settings\": {\"idp_name\": \"\", \"metadata\": \"\", \"entity_id\": \"\", \"enable_sso\": false, \"issuer_uri\": \"\", \"metadata_url\": \"\", \"idp_image_url\": \"\", \"enable_sso_idp_login\": false}, \"agent_options\": {\"config\": {\"options\": {\"logger_plugin\": \"tls\", \"pack_delimiter\": \"/\", \"logger_tls_period\": 10, \"distributed_plugin\": \"tls\", \"disable_distributed\": false, \"logger_tls_endpoint\": \"/api/v1/osquery/log\", \"distributed_interval\": 10, \"distributed_tls_max_attempts\": 3}, \"decorators\": {\"load\": [\"SELECT uuid AS host_uuid FROM system_info;\", \"SELECT hostname AS hostname FROM system_info;\"]}}, \"overrides\": {}}, \"host_settings\": {\"enable_host_users\": true, \"enable_software_inventory\": false}, \"smtp_settings\": {\"port\": 587, \"domain\": \"\", \"server\": \"\", \"password\": \"\", \"user_name\": \"\", \"configured\": false, \"enable_smtp\": false, \"enable_ssl_tls\": true, \"sender_address\": \"\", \"enable_start_tls\": true, \"verify_ssl_certs\": true, \"authentication_type\": \"0\", \"authentication_method\": \"0\"}, \"server_settings\": {\"server_url\": \"\", \"enable_analytics\": false, \"live_query_disabled\": false}, \"host_expiry_settings\": {\"host_expiry_window\": 0, \"host_expiry_enabled\": false}, \"vulnerability_settings\": {\"databases_path\": \"\"}}','2021-08-20 11:56:14','2021-08-20 11:56:14'); +INSERT INTO `app_config_json` VALUES (1,'{\"org_info\": {\"org_name\": \"\", \"org_logo_url\": \"\"}, \"sso_settings\": {\"idp_name\": \"\", \"metadata\": \"\", \"entity_id\": \"\", \"enable_sso\": false, \"issuer_uri\": \"\", \"metadata_url\": \"\", \"idp_image_url\": \"\", \"enable_sso_idp_login\": false}, \"agent_options\": {\"config\": {\"options\": {\"logger_plugin\": \"tls\", \"pack_delimiter\": \"/\", \"logger_tls_period\": 10, \"distributed_plugin\": \"tls\", \"disable_distributed\": false, \"logger_tls_endpoint\": \"/api/v1/osquery/log\", \"distributed_interval\": 10, \"distributed_tls_max_attempts\": 3}, \"decorators\": {\"load\": [\"SELECT uuid AS host_uuid FROM system_info;\", \"SELECT hostname AS hostname FROM system_info;\"]}}, \"overrides\": {}}, \"host_settings\": {\"enable_host_users\": true, \"enable_software_inventory\": false}, \"smtp_settings\": {\"port\": 587, \"domain\": \"\", \"server\": \"\", \"password\": \"\", \"user_name\": \"\", \"configured\": false, \"enable_smtp\": false, \"enable_ssl_tls\": true, \"sender_address\": \"\", \"enable_start_tls\": true, \"verify_ssl_certs\": true, \"authentication_type\": \"0\", \"authentication_method\": \"0\"}, \"server_settings\": {\"server_url\": \"\", \"enable_analytics\": false, \"live_query_disabled\": false}, \"host_expiry_settings\": {\"host_expiry_window\": 0, \"host_expiry_enabled\": false}, \"vulnerability_settings\": {\"databases_path\": \"\"}}','2021-08-20 17:32:00','2021-08-20 17:32:00'); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `app_configs` ( @@ -158,7 +158,10 @@ CREATE TABLE `host_additional` ( CREATE TABLE `host_software` ( `host_id` int(10) unsigned NOT NULL, `software_id` bigint(20) unsigned NOT NULL, - PRIMARY KEY (`host_id`,`software_id`) + PRIMARY KEY (`host_id`,`software_id`), + KEY `host_software_software_fk` (`software_id`), + CONSTRAINT `host_software_ibfk_1` FOREIGN KEY (`host_id`) REFERENCES `hosts` (`id`) ON DELETE CASCADE, + CONSTRAINT `host_software_ibfk_2` FOREIGN KEY (`software_id`) REFERENCES `software` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET @saved_cs_client = @@character_set_client */; @@ -217,6 +220,8 @@ CREATE TABLE `hosts` ( `last_enrolled_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `refetch_requested` tinyint(1) NOT NULL DEFAULT '0', `team_id` int(10) unsigned DEFAULT NULL, + `gigs_disk_space_available` float NOT NULL DEFAULT '0', + `percent_disk_space_available` float NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `idx_osquery_host_id` (`osquery_host_id`), UNIQUE KEY `idx_host_unique_nodekey` (`node_key`), @@ -306,9 +311,9 @@ CREATE TABLE `migration_status_tables` ( `tstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `id` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=98 DEFAULT CHARSET=utf8mb4; +) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `migration_status_tables` VALUES (1,0,1,'2021-08-20 11:56:10'),(2,20161118193812,1,'2021-08-20 11:56:10'),(3,20161118211713,1,'2021-08-20 11:56:10'),(4,20161118212436,1,'2021-08-20 11:56:10'),(5,20161118212515,1,'2021-08-20 11:56:10'),(6,20161118212528,1,'2021-08-20 11:56:10'),(7,20161118212538,1,'2021-08-20 11:56:10'),(8,20161118212549,1,'2021-08-20 11:56:10'),(9,20161118212557,1,'2021-08-20 11:56:10'),(10,20161118212604,1,'2021-08-20 11:56:10'),(11,20161118212613,1,'2021-08-20 11:56:10'),(12,20161118212621,1,'2021-08-20 11:56:10'),(13,20161118212630,1,'2021-08-20 11:56:10'),(14,20161118212641,1,'2021-08-20 11:56:10'),(15,20161118212649,1,'2021-08-20 11:56:10'),(16,20161118212656,1,'2021-08-20 11:56:10'),(17,20161118212758,1,'2021-08-20 11:56:10'),(18,20161128234849,1,'2021-08-20 11:56:10'),(19,20161230162221,1,'2021-08-20 11:56:10'),(20,20170104113816,1,'2021-08-20 11:56:11'),(21,20170105151732,1,'2021-08-20 11:56:11'),(22,20170108191242,1,'2021-08-20 11:56:11'),(23,20170109094020,1,'2021-08-20 11:56:11'),(24,20170109130438,1,'2021-08-20 11:56:11'),(25,20170110202752,1,'2021-08-20 11:56:11'),(26,20170111133013,1,'2021-08-20 11:56:11'),(27,20170117025759,1,'2021-08-20 11:56:11'),(28,20170118191001,1,'2021-08-20 11:56:11'),(29,20170119234632,1,'2021-08-20 11:56:11'),(30,20170124230432,1,'2021-08-20 11:56:11'),(31,20170127014618,1,'2021-08-20 11:56:11'),(32,20170131232841,1,'2021-08-20 11:56:11'),(33,20170223094154,1,'2021-08-20 11:56:11'),(34,20170306075207,1,'2021-08-20 11:56:11'),(35,20170309100733,1,'2021-08-20 11:56:11'),(36,20170331111922,1,'2021-08-20 11:56:11'),(37,20170502143928,1,'2021-08-20 11:56:11'),(38,20170504130602,1,'2021-08-20 11:56:12'),(39,20170509132100,1,'2021-08-20 11:56:12'),(40,20170519105647,1,'2021-08-20 11:56:12'),(41,20170519105648,1,'2021-08-20 11:56:12'),(42,20170831234300,1,'2021-08-20 11:56:12'),(43,20170831234301,1,'2021-08-20 11:56:12'),(44,20170831234303,1,'2021-08-20 11:56:12'),(45,20171116163618,1,'2021-08-20 11:56:12'),(46,20171219164727,1,'2021-08-20 11:56:12'),(47,20180620164811,1,'2021-08-20 11:56:12'),(48,20180620175054,1,'2021-08-20 11:56:12'),(49,20180620175055,1,'2021-08-20 11:56:12'),(50,20191010101639,1,'2021-08-20 11:56:12'),(51,20191010155147,1,'2021-08-20 11:56:12'),(52,20191220130734,1,'2021-08-20 11:56:12'),(53,20200311140000,1,'2021-08-20 11:56:12'),(54,20200405120000,1,'2021-08-20 11:56:12'),(55,20200407120000,1,'2021-08-20 11:56:12'),(56,20200420120000,1,'2021-08-20 11:56:12'),(57,20200504120000,1,'2021-08-20 11:56:12'),(58,20200512120000,1,'2021-08-20 11:56:12'),(59,20200707120000,1,'2021-08-20 11:56:12'),(60,20201011162341,1,'2021-08-20 11:56:13'),(61,20201021104586,1,'2021-08-20 11:56:13'),(62,20201102112520,1,'2021-08-20 11:56:13'),(63,20201208121729,1,'2021-08-20 11:56:13'),(64,20201215091637,1,'2021-08-20 11:56:13'),(65,20210119174155,1,'2021-08-20 11:56:13'),(66,20210326182902,1,'2021-08-20 11:56:13'),(67,20210421112652,1,'2021-08-20 11:56:13'),(68,20210506095025,1,'2021-08-20 11:56:13'),(69,20210513115729,1,'2021-08-20 11:56:13'),(70,20210526113559,1,'2021-08-20 11:56:13'),(71,20210601000001,1,'2021-08-20 11:56:13'),(72,20210601000002,1,'2021-08-20 11:56:13'),(73,20210601000003,1,'2021-08-20 11:56:13'),(74,20210601000004,1,'2021-08-20 11:56:13'),(75,20210601000005,1,'2021-08-20 11:56:13'),(76,20210601000006,1,'2021-08-20 11:56:13'),(77,20210601000007,1,'2021-08-20 11:56:13'),(78,20210601000008,1,'2021-08-20 11:56:13'),(79,20210606151329,1,'2021-08-20 11:56:13'),(80,20210616163757,1,'2021-08-20 11:56:13'),(81,20210617174723,1,'2021-08-20 11:56:13'),(82,20210622160235,1,'2021-08-20 11:56:14'),(83,20210623100031,1,'2021-08-20 11:56:14'),(84,20210623133615,1,'2021-08-20 11:56:14'),(85,20210708143152,1,'2021-08-20 11:56:14'),(86,20210709124443,1,'2021-08-20 11:56:14'),(87,20210712155608,1,'2021-08-20 11:56:14'),(88,20210714102108,1,'2021-08-20 11:56:14'),(89,20210719153709,1,'2021-08-20 11:56:14'),(90,20210721171531,1,'2021-08-20 11:56:14'),(91,20210723135713,1,'2021-08-20 11:56:14'),(92,20210802135933,1,'2021-08-20 11:56:14'),(93,20210806112844,1,'2021-08-20 11:56:14'),(94,20210810095603,1,'2021-08-20 11:56:14'),(95,20210811150223,1,'2021-08-20 11:56:14'),(96,20210816141251,1,'2021-08-20 11:56:14'),(97,20210818151827,1,'2021-08-20 11:56:14'); +INSERT INTO `migration_status_tables` VALUES (1,0,1,'2021-08-20 17:31:56'),(2,20161118193812,1,'2021-08-20 17:31:56'),(3,20161118211713,1,'2021-08-20 17:31:56'),(4,20161118212436,1,'2021-08-20 17:31:56'),(5,20161118212515,1,'2021-08-20 17:31:56'),(6,20161118212528,1,'2021-08-20 17:31:56'),(7,20161118212538,1,'2021-08-20 17:31:57'),(8,20161118212549,1,'2021-08-20 17:31:57'),(9,20161118212557,1,'2021-08-20 17:31:57'),(10,20161118212604,1,'2021-08-20 17:31:57'),(11,20161118212613,1,'2021-08-20 17:31:57'),(12,20161118212621,1,'2021-08-20 17:31:57'),(13,20161118212630,1,'2021-08-20 17:31:57'),(14,20161118212641,1,'2021-08-20 17:31:57'),(15,20161118212649,1,'2021-08-20 17:31:57'),(16,20161118212656,1,'2021-08-20 17:31:57'),(17,20161118212758,1,'2021-08-20 17:31:57'),(18,20161128234849,1,'2021-08-20 17:31:57'),(19,20161230162221,1,'2021-08-20 17:31:57'),(20,20170104113816,1,'2021-08-20 17:31:57'),(21,20170105151732,1,'2021-08-20 17:31:57'),(22,20170108191242,1,'2021-08-20 17:31:57'),(23,20170109094020,1,'2021-08-20 17:31:57'),(24,20170109130438,1,'2021-08-20 17:31:57'),(25,20170110202752,1,'2021-08-20 17:31:57'),(26,20170111133013,1,'2021-08-20 17:31:57'),(27,20170117025759,1,'2021-08-20 17:31:57'),(28,20170118191001,1,'2021-08-20 17:31:57'),(29,20170119234632,1,'2021-08-20 17:31:57'),(30,20170124230432,1,'2021-08-20 17:31:57'),(31,20170127014618,1,'2021-08-20 17:31:57'),(32,20170131232841,1,'2021-08-20 17:31:57'),(33,20170223094154,1,'2021-08-20 17:31:57'),(34,20170306075207,1,'2021-08-20 17:31:58'),(35,20170309100733,1,'2021-08-20 17:31:58'),(36,20170331111922,1,'2021-08-20 17:31:58'),(37,20170502143928,1,'2021-08-20 17:31:58'),(38,20170504130602,1,'2021-08-20 17:31:58'),(39,20170509132100,1,'2021-08-20 17:31:58'),(40,20170519105647,1,'2021-08-20 17:31:58'),(41,20170519105648,1,'2021-08-20 17:31:58'),(42,20170831234300,1,'2021-08-20 17:31:58'),(43,20170831234301,1,'2021-08-20 17:31:58'),(44,20170831234303,1,'2021-08-20 17:31:58'),(45,20171116163618,1,'2021-08-20 17:31:58'),(46,20171219164727,1,'2021-08-20 17:31:58'),(47,20180620164811,1,'2021-08-20 17:31:58'),(48,20180620175054,1,'2021-08-20 17:31:58'),(49,20180620175055,1,'2021-08-20 17:31:58'),(50,20191010101639,1,'2021-08-20 17:31:58'),(51,20191010155147,1,'2021-08-20 17:31:59'),(52,20191220130734,1,'2021-08-20 17:31:59'),(53,20200311140000,1,'2021-08-20 17:31:59'),(54,20200405120000,1,'2021-08-20 17:31:59'),(55,20200407120000,1,'2021-08-20 17:31:59'),(56,20200420120000,1,'2021-08-20 17:31:59'),(57,20200504120000,1,'2021-08-20 17:31:59'),(58,20200512120000,1,'2021-08-20 17:31:59'),(59,20200707120000,1,'2021-08-20 17:31:59'),(60,20201011162341,1,'2021-08-20 17:31:59'),(61,20201021104586,1,'2021-08-20 17:31:59'),(62,20201102112520,1,'2021-08-20 17:31:59'),(63,20201208121729,1,'2021-08-20 17:31:59'),(64,20201215091637,1,'2021-08-20 17:31:59'),(65,20210119174155,1,'2021-08-20 17:31:59'),(66,20210326182902,1,'2021-08-20 17:31:59'),(67,20210421112652,1,'2021-08-20 17:31:59'),(68,20210506095025,1,'2021-08-20 17:31:59'),(69,20210513115729,1,'2021-08-20 17:32:00'),(70,20210526113559,1,'2021-08-20 17:32:00'),(71,20210601000001,1,'2021-08-20 17:32:00'),(72,20210601000002,1,'2021-08-20 17:32:00'),(73,20210601000003,1,'2021-08-20 17:32:00'),(74,20210601000004,1,'2021-08-20 17:32:00'),(75,20210601000005,1,'2021-08-20 17:32:00'),(76,20210601000006,1,'2021-08-20 17:32:00'),(77,20210601000007,1,'2021-08-20 17:32:00'),(78,20210601000008,1,'2021-08-20 17:32:00'),(79,20210606151329,1,'2021-08-20 17:32:00'),(80,20210616163757,1,'2021-08-20 17:32:00'),(81,20210617174723,1,'2021-08-20 17:32:00'),(82,20210622160235,1,'2021-08-20 17:32:00'),(83,20210623100031,1,'2021-08-20 17:32:00'),(84,20210623133615,1,'2021-08-20 17:32:00'),(85,20210708143152,1,'2021-08-20 17:32:00'),(86,20210709124443,1,'2021-08-20 17:32:00'),(87,20210712155608,1,'2021-08-20 17:32:00'),(88,20210714102108,1,'2021-08-20 17:32:00'),(89,20210719153709,1,'2021-08-20 17:32:00'),(90,20210721171531,1,'2021-08-20 17:32:00'),(91,20210723135713,1,'2021-08-20 17:32:00'),(92,20210802135933,1,'2021-08-20 17:32:00'),(93,20210806112844,1,'2021-08-20 17:32:00'),(94,20210810095603,1,'2021-08-20 17:32:00'),(95,20210811150223,1,'2021-08-20 17:32:00'),(96,20210816141251,1,'2021-08-20 17:32:00'),(97,20210818151827,1,'2021-08-20 17:32:00'),(98,20210818182258,1,'2021-08-20 17:32:01'),(99,20210819131107,1,'2021-08-20 17:32:01'); /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `network_interfaces` ( diff --git a/server/fleet/hosts.go b/server/fleet/hosts.go index c249530c8b..220a07f986 100644 --- a/server/fleet/hosts.go +++ b/server/fleet/hosts.go @@ -178,6 +178,9 @@ type Host struct { // Users currently in the host Users []HostUser `json:"users,omitempty"` + GigsDiskSpaceAvailable float64 `json:"gigs_disk_space_available" db:"gigs_disk_space_available"` + PercentDiskSpaceAvailable float64 `json:"percent_disk_space_available" db:"percent_disk_space_available"` + Modified bool `json:"-"` } diff --git a/server/service/osquery_utils/queries.go b/server/service/osquery_utils/queries.go index f342674958..104d3a7cb6 100644 --- a/server/service/osquery_utils/queries.go +++ b/server/service/osquery_utils/queries.go @@ -336,6 +336,22 @@ var detailQueries = map[string]DetailQuery{ return nil }, }, + "disk_space_unix": { + Query: ` +SELECT (blocks_available * 100 / blocks) AS percent_disk_space_available, + round((blocks_available * blocks_size *10e-10),2) AS gigs_disk_space_available +FROM mounts WHERE path = '/';`, + Platforms: []string{"darwin", "linux", "rhel", "ubuntu", "centos"}, + IngestFunc: ingestDiskSpace, + }, + "disk_space_windows": { + Query: ` +SELECT ROUND((sum(free_space) * 100 * 10e-10) / (sum(size) * 10e-10)) AS percent_disk_space_available, + ROUND(sum(free_space) * 10e-10) AS gigs_disk_space_available +FROM logical_drives WHERE file_system = 'NTFS';`, + Platforms: []string{"windows"}, + IngestFunc: ingestDiskSpace, + }, } var softwareMacOS = DetailQuery{ @@ -556,6 +572,25 @@ func ingestSoftware(logger log.Logger, host *fleet.Host, rows []map[string]strin return nil } +func ingestDiskSpace(logger log.Logger, host *fleet.Host, rows []map[string]string) error { + if len(rows) != 1 { + logger.Log("component", "service", "method", "ingestDiskSpace", "err", + fmt.Sprintf("detail_query_disk_space expected single result got %d", len(rows))) + return nil + } + + var err error + host.GigsDiskSpaceAvailable, err = strconv.ParseFloat(EmptyToZero(rows[0]["gigs_disk_space_available"]), 64) + if err != nil { + return err + } + host.PercentDiskSpaceAvailable, err = strconv.ParseFloat(EmptyToZero(rows[0]["percent_disk_space_available"]), 64) + if err != nil { + return err + } + return nil +} + func GetDetailQueries(ac *fleet.AppConfig) map[string]DetailQuery { generatedMap := make(map[string]DetailQuery) for key, query := range detailQueries { diff --git a/server/service/osquery_utils/queries_test.go b/server/service/osquery_utils/queries_test.go index 1ed30bfa03..a2073121a1 100644 --- a/server/service/osquery_utils/queries_test.go +++ b/server/service/osquery_utils/queries_test.go @@ -276,7 +276,7 @@ func sortedKeysCompare(t *testing.T, m map[string]DetailQuery, expectedKeys []st func TestGetDetailQueries(t *testing.T) { queriesNoConfig := GetDetailQueries(nil) - require.Len(t, queriesNoConfig, 7) + require.Len(t, queriesNoConfig, 9) baseQueries := []string{ "network_interface", "os_version", @@ -285,17 +285,19 @@ func TestGetDetailQueries(t *testing.T) { "scheduled_query_stats", "system_info", "uptime", + "disk_space_unix", + "disk_space_windows", } sortedKeysCompare(t, queriesNoConfig, baseQueries) queriesWithUsers := GetDetailQueries(&fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true}}) - require.Len(t, queriesWithUsers, 8) + require.Len(t, queriesWithUsers, 10) sortedKeysCompare(t, queriesWithUsers, append(baseQueries, "users")) require.NoError(t, os.Setenv("FLEET_BETA_SOFTWARE_INVENTORY", "1")) queriesWithUsersAndSoftware := GetDetailQueries(&fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true}}) - require.Len(t, queriesWithUsersAndSoftware, 11) + require.Len(t, queriesWithUsersAndSoftware, 13) sortedKeysCompare(t, queriesWithUsersAndSoftware, append(baseQueries, "users", "software_macos", "software_linux", "software_windows")) diff --git a/server/service/service_osquery_test.go b/server/service/service_osquery_test.go index 734ee197b6..b79b03a7a8 100644 --- a/server/service/service_osquery_test.go +++ b/server/service/service_osquery_test.go @@ -31,8 +31,9 @@ import ( "github.com/stretchr/testify/require" ) +// One of these queries is the disk space, only one of the two works in a platform var expectedDetailQueries = len(osquery_utils.GetDetailQueries( - &fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true}})) + &fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true}})) - 1 func TestEnrollAgent(t *testing.T) { ds := new(mock.Store) @@ -816,6 +817,12 @@ func TestDetailQueries(t *testing.T) { "type": "sometype", "groupname": "somegroup" } +], +"fleet_detail_query_disk_space_unix": [ + { + "percent_disk_space_available": "56", + "gigs_disk_space_available": "277.0" + } ] } ` @@ -871,6 +878,9 @@ func TestDetailQueries(t *testing.T) { GroupName: "somegroup", }, gotHost.Users[0]) + assert.Equal(t, 56.0, gotHost.PercentDiskSpaceAvailable) + assert.Equal(t, 277.0, gotHost.GigsDiskSpaceAvailable) + host.Hostname = "computer.local" host.Platform = "darwin" host.DetailUpdatedAt = mockClock.Now()