Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
32562b2
update API types
Sep 23, 2025
7b5cf2c
include new fields in summary data, pass to DiskSpaceIndicator
Sep 23, 2025
e244964
render new data
Sep 23, 2025
655192d
wip
Sep 24, 2025
edf783c
wip
Sep 24, 2025
686f97c
wip
Oct 8, 2025
6211035
wip - proposed query
jacobshandling Oct 10, 2025
6b7c0e7
bump migration, make dump test
jacobshandling Oct 14, 2025
c68c86c
improve comments
jacobshandling Oct 14, 2025
290306d
update datastore call
jacobshandling Oct 14, 2025
ee167f0
add data to hosts toble
jacobshandling Oct 14, 2025
7c91b33
include new field in ListHosts, allow `nil`
jacobshandling Oct 14, 2025
d51f14c
update tests
jacobshandling Oct 14, 2025
7a0bf13
update ds mocks
jacobshandling Oct 14, 2025
3d9e6c0
update docs
jacobshandling Oct 14, 2025
ff38404
fix migration test
jacobshandling Oct 14, 2025
d916676
add FE test
jacobshandling Oct 14, 2025
e737ea8
update fleetctl tests
jacobshandling Oct 14, 2025
32807dd
update
jacobshandling Oct 14, 2025
9ca92ce
add missing args to ds hosts_test
jacobshandling Oct 16, 2025
263a830
update integration tests
jacobshandling Oct 16, 2025
fdee373
Merge branch 'main' into 31671-linux-disk-space
jacobshandling Oct 16, 2025
48b2883
make dump-test-schema
jacobshandling Oct 16, 2025
38ee386
update labels_test
jacobshandling Oct 16, 2025
973d6ec
update expected rows count
jacobshandling Oct 16, 2025
964c496
include new field in search hosts endpoint
jacobshandling Oct 16, 2025
e79f70e
fix query
jacobshandling Oct 17, 2025
c295861
make generate-doc
jacobshandling Oct 17, 2025
9fd7406
change file
jacobshandling Oct 17, 2025
7cdec65
fix datastore mock
jacobshandling Oct 17, 2025
58de894
allow `nil` value for empty string returned from osquery
jacobshandling Oct 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/31671-gigs-all-disk-space
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add `gigs_all_disk_space` vital collection, storage, service, and UI rendering for Linux hosts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"gigs_disk_space_available": 0,
"percent_disk_space_available": 0,
"gigs_total_disk_space": 0,
"gigs_all_disk_space": null,
"issues": {
"total_issues_count": 0,
"failing_policies_count": 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ spec:
fleet_desktop_version: null
gigs_disk_space_available: 0
gigs_total_disk_space: 0
gigs_all_disk_space: null
hardware_model: ""
hardware_serial: ""
hardware_vendor: ""
Expand Down
2 changes: 2 additions & 0 deletions cmd/fleetctl/fleetctl/testdata/expectedListHostsJson.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"gigs_disk_space_available": 0,
"percent_disk_space_available": 0,
"gigs_total_disk_space": 0,
"gigs_all_disk_space": null,
"issues": {
"total_issues_count": 0,
"failing_policies_count": 0
Expand Down Expand Up @@ -136,6 +137,7 @@
"gigs_disk_space_available": 0,
"percent_disk_space_available": 0,
"gigs_total_disk_space": 0,
"gigs_all_disk_space": null,
"issues": {
"total_issues_count": 0,
"failing_policies_count": 0
Expand Down
2 changes: 2 additions & 0 deletions cmd/fleetctl/fleetctl/testdata/expectedListHostsMDM.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"gigs_disk_space_available": 0,
"percent_disk_space_available": 0,
"gigs_total_disk_space": 0,
"gigs_all_disk_space": null,
"issues": {
"total_issues_count": 0,
"failing_policies_count": 0
Expand Down Expand Up @@ -137,6 +138,7 @@
"gigs_disk_space_available": 0,
"percent_disk_space_available": 0,
"gigs_total_disk_space": 0,
"gigs_all_disk_space": null,
"issues": {
"total_issues_count": 0,
"failing_policies_count": 0
Expand Down
1 change: 1 addition & 0 deletions cmd/fleetctl/fleetctl/testdata/expectedListHostsYaml.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ spec:
fleet_desktop_version: null
gigs_disk_space_available: 0
gigs_total_disk_space: 0
gigs_all_disk_space: null
hardware_model: ""
hardware_serial: ""
hardware_vendor: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,58 @@ WITH encrypted(enabled) AS (
- Query:
```sql
SELECT (blocks_available * 100 / blocks) AS percent_disk_space_available,
round((blocks_available * blocks_size * 10e-10),2) AS gigs_disk_space_available,
round((blocks * blocks_size * 10e-10),2) AS gigs_total_disk_space
FROM mounts WHERE path = '/' LIMIT 1;
round((blocks_available * blocks_size * 10e-10),2) AS gigs_disk_space_available,
round((blocks * blocks_size * 10e-10),2) AS gigs_total_disk_space,
(SELECT round(SUM(blocks * blocks_size) * 10e-10, 2) FROM mounts WHERE
-- exclude mounts with no space
blocks > 0
AND blocks_size > 0

-- exclude external storage
AND path NOT LIKE '/media%' AND path NOT LIKE '/mnt%'

-- exclude device drivers
AND path NOT LIKE '/dev%'

-- exclude kernel-related mounts
AND path NOT LIKE '/proc%'
AND path NOT LIKE '/sys%'

-- exclude process files
AND path NOT LIKE '/run%'
AND path NOT LIKE '/var/run%'

-- exclude boot files
AND path NOT LIKE '/boot%'

-- exclude snap packages
AND path NOT LIKE '/snap%' AND path NOT LIKE '/var/snap%'

-- exclude virtualized mounts, would double-count bare metal storage
AND path NOT LIKE '/var/lib/docker%'
AND path NOT LIKE '/var/lib/containers%'

AND type IN (
'ext4',
'ext3',
'ext2',
'xfs',
'btrfs',
'ntfs',
'vfat',
'fuseblk', --seen on NTFS and exFAT volumes mounted via FUSE
'zfs' --also valid storage
)
AND (
device LIKE '/dev/sd%'
OR device LIKE '/dev/hd%'
OR device LIKE '/dev/vd%'
OR device LIKE '/dev/nvme%'
OR device LIKE '/dev/mapper%'
OR device LIKE '/dev/md%'
OR device LIKE '/dev/dm-%'
)) AS gigs_all_disk_space
FROM mounts WHERE path = '/' LIMIT 1;
```

## disk_space_windows
Expand Down
8 changes: 8 additions & 0 deletions frontend/interfaces/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export default PropTypes.shape({
additional: PropTypes.object, // eslint-disable-line react/forbid-prop-types
percent_disk_space_available: PropTypes.number,
gigs_disk_space_available: PropTypes.number,
// On Linux hosts, `gigs_total_disk_space` only includes disk space from the "/" partition
gigs_total_disk_space: PropTypes.number,
// `gigs_all_disk_space` includes disk space from all partitions
gigs_all_disk_space: PropTypes.number,
labels: PropTypes.arrayOf(labelInterface),
packs: PropTypes.arrayOf(packInterface),
software: PropTypes.arrayOf(softwareInterface),
Expand Down Expand Up @@ -280,6 +284,10 @@ export interface IHost {
additional?: object; // eslint-disable-line @typescript-eslint/ban-types
percent_disk_space_available: number;
gigs_disk_space_available: number;
// On Linux hosts, `gigs_total_disk_space` only includes disk space from the "/" partition
gigs_total_disk_space?: number;
// `gigs_all_disk_space` includes disk space from all partitions
gigs_all_disk_space?: number;
labels: ILabel[];
packs: IPack[];
software?: ISoftware[];
Expand Down
13 changes: 10 additions & 3 deletions frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,18 +284,25 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [
isSortedDesc={cellProps.column.isSortedDesc}
/>
),
accessor: "gigs_disk_space_available",
id: "gigs_disk_space_available",
Cell: (cellProps: IHostTableNumberCellProps) => {
const { platform, percent_disk_space_available } = cellProps.row.original;
const {
platform,
percent_disk_space_available,
gigs_disk_space_available,
gigs_total_disk_space,
gigs_all_disk_space,
} = cellProps.row.original;
if (platform === "chrome") {
return NotSupported;
}
return (
<DiskSpaceIndicator
inTableCell
gigsDiskSpaceAvailable={cellProps.cell.value}
gigsDiskSpaceAvailable={gigs_disk_space_available}
percentDiskSpaceAvailable={percent_disk_space_available}
gigsTotalDiskSpace={gigs_total_disk_space}
gigsAllDiskSpace={gigs_all_disk_space}
platform={platform}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,25 @@ describe("Disk space Indicator", () => {
expect(tooltip).toBeInTheDocument();
});
});
it("renders tooltip over anchor for Linux hosts with gigs all disk space and gigs total disk space", async () => {
const { user } = renderWithSetup(
<DiskSpaceIndicator
gigsDiskSpaceAvailable={20}
percentDiskSpaceAvailable={20}
gigsTotalDiskSpace={100}
gigsAllDiskSpace={120}
platform="linux"
/>
);

await user.hover(screen.getByText(/GB/));

await waitFor(() => {
const totalTip = screen.getByText(/System disk space/);
expect(totalTip).toBeInTheDocument();
});

const allTip = screen.getByText(/All partitions/);
expect(allTip).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import React from "react";

import ReactTooltip from "react-tooltip";
import { PlacesType } from "react-tooltip-5";
import NotSupported from "components/NotSupported";

import { COLORS } from "styles/var/colors";

import ProgressBar from "components/ProgressBar";
import TooltipWrapper from "components/TooltipWrapper";
import { isLinuxLike } from "interfaces/platform";

const baseClass = "disk-space-indicator";
interface IDiskSpaceIndicatorProps {
gigsDiskSpaceAvailable: number | "---";
percentDiskSpaceAvailable: number;
gigsTotalDiskSpace?: number;
gigsAllDiskSpace?: number;
platform: string;
inTableCell?: boolean;
tooltipPosition?: PlacesType;
Expand All @@ -21,6 +23,8 @@ interface IDiskSpaceIndicatorProps {
const DiskSpaceIndicator = ({
gigsDiskSpaceAvailable,
percentDiskSpaceAvailable,
gigsTotalDiskSpace,
gigsAllDiskSpace,
platform,
inTableCell = false,
tooltipPosition = "top",
Expand Down Expand Up @@ -73,6 +77,31 @@ const DiskSpaceIndicator = ({
/>
);

// get disk space tooltip content for Linux hosts
const totalDiskSpaceContent = gigsTotalDiskSpace ? (
<>
System disk space: {gigsTotalDiskSpace} GB
<br />
</>
) : null;
const allPartitionsContent = gigsAllDiskSpace ? (
<>All partitions: {gigsAllDiskSpace} GB</>
) : null;

const copyTootltipContent =
totalDiskSpaceContent || allPartitionsContent ? (
<>
{totalDiskSpaceContent}
{allPartitionsContent}
</>
) : null;

const renderCopy = () => (
<>
{gigsDiskSpaceAvailable} GB{!inTableCell && " available"}
</>
);

return (
<span className={baseClass}>
{diskSpaceTooltipText ? (
Expand All @@ -88,7 +117,16 @@ const DiskSpaceIndicator = ({
) : (
renderBar()
)}
{gigsDiskSpaceAvailable} GB{!inTableCell && " available"}
{copyTootltipContent && isLinuxLike(platform) ? (
<TooltipWrapper
tooltipClass="copy-tooltip-content"
tipContent={copyTootltipContent}
>
{renderCopy()}
</TooltipWrapper>
) : (
renderCopy()
)}
</span>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
gap: $pad-small;
white-space: nowrap;

.react-tooltip {
.react-tooltip :not(.copy-tooltip-content) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeRabbit had an interesting observation here about the space before :not(), which makes this a descendant selector. And it does seem like .copy-tooltip-content is a class added to the same element as .react-tooltip, which makes it a sibling rather than a descendant. But it seems to work both with and without the space so 🤷

max-width: px-to-rem(160);
text-align: center;
font-size: px-to-rem(13);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ const HostSummary = ({
<DiskSpaceIndicator
gigsDiskSpaceAvailable={summaryData.gigs_disk_space_available}
percentDiskSpaceAvailable={summaryData.percent_disk_space_available}
gigsTotalDiskSpace={summaryData.gigs_total_disk_space}
gigsAllDiskSpace={summaryData.gigs_all_disk_space}
platform={platform}
tooltipPosition="bottom"
/>
Expand Down
6 changes: 4 additions & 2 deletions frontend/utilities/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React from "react";
import { IDropdownOption } from "interfaces/dropdownOption";
import { ICampaign } from "interfaces/campaign";
import { MdmEnrollmentStatus } from "interfaces/mdm";
import { IHost } from "interfaces/host";

const { origin } = global.window.location;
export const BASE_URL = `${origin}${URL_PREFIX}/api`;
Expand Down Expand Up @@ -405,7 +406,7 @@ export const DEFAULT_EMPTY_CELL_VALUE = "---";

export const DOCUMENT_TITLE_SUFFIX = "Fleet";

export const HOST_SUMMARY_DATA = [
export const HOST_SUMMARY_DATA: (keyof IHost)[] = [
"id",
"status",
"issues",
Expand All @@ -416,10 +417,11 @@ export const HOST_SUMMARY_DATA = [
"osquery_version",
"orbit_version",
"fleet_desktop_version",
"enroll_secret_name",
"detail_updated_at",
"percent_disk_space_available",
"gigs_disk_space_available",
"gigs_total_disk_space",
"gigs_all_disk_space",
"team_name",
"disk_encryption_enabled",
"display_name", // Not rendered on my device page
Expand Down
6 changes: 4 additions & 2 deletions server/datastore/mysql/android.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ func (ds *Datastore) NewAndroidHost(ctx context.Context, host *fleet.AndroidHost
err = ds.SetOrUpdateHostDisksSpace(ctx, host.Host.ID,
host.Host.GigsDiskSpaceAvailable,
host.Host.PercentDiskSpaceAvailable,
host.Host.GigsTotalDiskSpace)
host.Host.GigsTotalDiskSpace,
nil)
if err != nil {
return ctxerr.Wrap(ctx, err, "setting Android host disk space")
}
Expand Down Expand Up @@ -232,7 +233,8 @@ func (ds *Datastore) UpdateAndroidHost(ctx context.Context, host *fleet.AndroidH
err = ds.SetOrUpdateHostDisksSpace(ctx, host.Host.ID,
host.Host.GigsDiskSpaceAvailable,
host.Host.PercentDiskSpaceAvailable,
host.Host.GigsTotalDiskSpace)
host.Host.GigsTotalDiskSpace,
nil)
if err != nil {
return ctxerr.Wrap(ctx, err, "updating Android host disk space")
}
Expand Down
11 changes: 7 additions & 4 deletions server/datastore/mysql/hosts.go
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@ SELECT
COALESCE(hd.gigs_disk_space_available, 0) as gigs_disk_space_available,
COALESCE(hd.percent_disk_space_available, 0) as percent_disk_space_available,
COALESCE(hd.gigs_total_disk_space, 0) as gigs_total_disk_space,
hd.gigs_all_disk_space,
hd.encrypted as disk_encryption_enabled,
COALESCE(hst.seen_time, h.created_at) AS seen_time,
t.name AS team_name,
Expand Down Expand Up @@ -1019,6 +1020,7 @@ func (ds *Datastore) ListHosts(ctx context.Context, filter fleet.TeamFilter, opt
COALESCE(hd.gigs_disk_space_available, 0) as gigs_disk_space_available,
COALESCE(hd.percent_disk_space_available, 0) as percent_disk_space_available,
COALESCE(hd.gigs_total_disk_space, 0) as gigs_total_disk_space,
hd.gigs_all_disk_space,
COALESCE(hst.seen_time, h.created_at) AS seen_time,
t.name AS team_name,
COALESCE(hu.software_updated_at, h.created_at) AS software_updated_at,
Expand Down Expand Up @@ -2981,6 +2983,7 @@ func (ds *Datastore) SearchHosts(ctx context.Context, filter fleet.TeamFilter, m
COALESCE(hd.gigs_disk_space_available, 0) as gigs_disk_space_available,
COALESCE(hd.percent_disk_space_available, 0) as percent_disk_space_available,
COALESCE(hd.gigs_total_disk_space, 0) as gigs_total_disk_space,
hd.gigs_all_disk_space as gigs_all_disk_space,
COALESCE(hst.seen_time, h.created_at) AS seen_time,
COALESCE(hu.software_updated_at, h.created_at) AS software_updated_at
` + hostMDMSelect + `
Expand Down Expand Up @@ -4332,12 +4335,12 @@ func (ds *Datastore) GetHostEmails(ctx context.Context, hostUUID string, source

// SetOrUpdateHostDisksSpace sets the available gigs and percentage of the
// disks for the specified host.
func (ds *Datastore) SetOrUpdateHostDisksSpace(ctx context.Context, hostID uint, gigsAvailable, percentAvailable, gigsTotal float64) error {
func (ds *Datastore) SetOrUpdateHostDisksSpace(ctx context.Context, hostID uint, gigsAvailable, percentAvailable, gigsTotal float64, gigsAll *float64) error {
return ds.updateOrInsert(
ctx,
`UPDATE host_disks SET gigs_disk_space_available = ?, percent_disk_space_available = ?, gigs_total_disk_space = ? WHERE host_id = ?`,
`INSERT INTO host_disks (gigs_disk_space_available, percent_disk_space_available, gigs_total_disk_space, host_id) VALUES (?, ?, ?, ?)`,
gigsAvailable, percentAvailable, gigsTotal, hostID,
`UPDATE host_disks SET gigs_disk_space_available = ?, percent_disk_space_available = ?, gigs_total_disk_space = ?, gigs_all_disk_space = ? WHERE host_id = ?`,
`INSERT INTO host_disks (gigs_disk_space_available, percent_disk_space_available, gigs_total_disk_space, gigs_all_disk_space, host_id) VALUES (?, ?, ?, ?, ?)`,
gigsAvailable, percentAvailable, gigsTotal, gigsAll, hostID,
)
}

Expand Down
Loading
Loading