Skip to content

Commit

Permalink
feat: capture swap entries
Browse files Browse the repository at this point in the history
- introduces a `--swap,s` flag which controls whether `/proc/swaps` is captured in the report, `false` by default.
- introduces a `--ephemeral,e` flag which controls whether ephemeral properties are captured in the report, `false` by default and only includes `swap` for now.
- refactors the `basic` vm test to use Disko's testLib and checks more properties of the report output.

Closes #8.

Signed-off-by: Brian McGee <brian@bmcgee.ie>
  • Loading branch information
brianmcgee committed Aug 13, 2024
1 parent 6532af4 commit 6b16886
Show file tree
Hide file tree
Showing 14 changed files with 522 additions and 22 deletions.
17 changes: 11 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ var (
cfgFile string
outputPath string
hardwareFeatures []string

scanner = facter.Scanner{}
)

// rootCmd represents the base command when called without any subcommands
Expand All @@ -29,16 +31,15 @@ var rootCmd = &cobra.Command{
// todo add Long description
RunE: func(cmd *cobra.Command, args []string) error {
// convert the hardware features into probe features
var hardwareProbes []hwinfo.ProbeFeature
for _, str := range hardwareFeatures {
probe, err := hwinfo.ProbeFeatureString(str)
if err != nil {
return fmt.Errorf("invalid hardware feature: %w", err)
}
hardwareProbes = append(hardwareProbes, probe)
scanner.Features = append(scanner.Features, probe)
}

report, err := facter.GenerateReport(hardwareProbes)
report, err := scanner.Scan()
if err != nil {
return err
}
Expand Down Expand Up @@ -81,7 +82,11 @@ func init() {

// Cobra also supports local flags, which will only run when this action is called directly.
f := rootCmd.Flags()
f.StringVarP(&outputPath, "output", "o", "", "Path to write the report")
f.StringVarP(&outputPath, "output", "o", "", "path to write the report")

// Options for optional ephemeral system properties.
f.BoolVarP(&scanner.Swap, "swap", "s", false, "capture swap entries")
f.BoolVarP(&scanner.Ephemeral, "ephemeral", "e", false, "capture all ephemeral properties e.g. swap, filesystems and so on")

// We currently support all probe features at a high level as they share some generic information,
// but we do not have mappings for all of their detail sections.
Expand All @@ -105,11 +110,11 @@ func init() {

f.StringSliceVarP(
&hardwareFeatures,
"hardware-features",
"hardware",
"f",
defaultFeatures,
fmt.Sprintf(
"Hardware features to probe. Possible values are %s",
"Hardware items to probe. Possible values are %s",
strings.Join(allFeatures, ","),
),
)
Expand Down
43 changes: 39 additions & 4 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
url = "github:numtide/treefmt-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
disko.url = "github:nix-community/disko";
};

# Keep the magic invocations to minimum.
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ require (
github.com/klauspost/cpuid/v2 v2.2.9-0.20240805145549-92d5326f011e
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
)

require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/lipgloss v0.10.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
Expand All @@ -24,6 +26,7 @@ require (
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
Expand Down
4 changes: 3 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ Copyright © 2024 NAME HERE <EMAIL ADDRESS>
*/
package main

import "github.com/numtide/nixos-facter/cmd"
import (
"github.com/numtide/nixos-facter/cmd"
)

func main() {
cmd.Execute()
Expand Down
9 changes: 7 additions & 2 deletions nix/packages/nixos-facter/default.nix
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
args @ {
{
flake,
# We need the following pragma to ensure deadnix doesn't remove inputs.
# This package is being called with newScope/callPackage, which means it is only being passed args it defines.
# We do not use inputs directly in this file, but need it for passing to the tests.
# deadnix: skip
inputs,
perSystem,
system,
pkgs,
pname,
...
}: let
} @ args: let
inherit (pkgs) go lib;
fs = lib.fileset;
in
Expand Down
9 changes: 9 additions & 0 deletions nix/packages/nixos-facter/gomod2nix.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ schema = 3
[mod."github.com/charmbracelet/log"]
version = "v0.4.0"
hash = "sha256-VQerB44vC646n3fe3haJ3DHa9L5+GRhCfDfm1p3QnZk="
[mod."github.com/davecgh/go-spew"]
version = "v1.1.2-0.20180830191138-d8f796af33cc"
hash = "sha256-fV9oI51xjHdOmEx6+dlq7Ku2Ag+m/bmbzPo6A4Y74qc="
[mod."github.com/fsnotify/fsnotify"]
version = "v1.7.0"
hash = "sha256-MdT2rQyQHspPJcx6n9ozkLbsktIOJutOqDuKpNAtoZY="
Expand Down Expand Up @@ -49,6 +52,9 @@ schema = 3
[mod."github.com/pelletier/go-toml/v2"]
version = "v2.2.2"
hash = "sha256-ukxk1Cfm6cQW18g/aa19tLcUu5BnF7VmfAvrDHAOl6A="
[mod."github.com/pmezard/go-difflib"]
version = "v1.0.1-0.20181226105442-5d4384ee4fb2"
hash = "sha256-XA4Oj1gdmdV/F/+8kMI+DBxKPthZ768hbKsO3d9Gx90="
[mod."github.com/rivo/uniseg"]
version = "v0.4.7"
hash = "sha256-rDcdNYH6ZD8KouyyiZCUEy8JrjOQoAkxHBhugrfHjFo="
Expand Down Expand Up @@ -76,6 +82,9 @@ schema = 3
[mod."github.com/spf13/viper"]
version = "v1.19.0"
hash = "sha256-MZ8EAvdgpGbw6kmUz8UOaAAAMdPPGd14TrCBAY+A1T4="
[mod."github.com/stretchr/testify"]
version = "v1.9.0"
hash = "sha256-uUp/On+1nK+lARkTVtb5RxlW15zxtw2kaAFuIASA+J0="
[mod."github.com/subosito/gotenv"]
version = "v1.6.0"
hash = "sha256-LspbjTniiq2xAICSXmgqP7carwlNaLqnCTQfw2pa80A="
Expand Down
69 changes: 62 additions & 7 deletions nix/packages/nixos-facter/tests/default.nix
Original file line number Diff line number Diff line change
@@ -1,21 +1,76 @@
{
pkgs,
flake,
inputs,
system,
perSystem,
...
}: let
inherit (flake.packages.${system}) nixos-facter;
# we have to import diskoLib like this because there are some impure default imports e.g. <nixpkgs>
diskoLib = import "${inputs.disko}/lib" {
inherit (pkgs) lib;
makeTest = import "${inputs.nixpkgs}/nixos/tests/make-test-python.nix";
eval-config = import "${inputs.nixpkgs}/nixos/lib/eval-config.nix";
};
in
# for now we only run the tests in x86_64-linux since we don't have access to a bare-metal ARM box or a VM that supports nested
# virtualization which makes the test take forever and ultimately fail
pkgs.lib.optionalAttrs pkgs.stdenv.isx86_64 {
basic = pkgs.nixosTest {
basic = diskoLib.testLib.makeDiskoTest {
inherit pkgs;
name = "basic";
nodes.machine = {
environment.systemPackages = [nixos-facter];
disko-config = ./disko.nix;
extraSystemConfig = {
environment.systemPackages = [
perSystem.self.nixos-facter
];

systemd.services = {
create-swap-files = {
serviceConfig.Type = "oneshot";
wantedBy = ["multi-user.target"];
path = with pkgs; [
coreutils
util-linux
];
script = ''
# create some swap files
mkdir -p /swap
for (( i=1; i<=3; i++ )); do
out="/swap/swapfile-$i"
dd if=/dev/zero of="$out" bs=1MB count=10
chmod 600 "$out"
mkswap "$out"
swapon "$out"
done
'';
};
};
};
testScript = ''
machine.succeed("nixos-facter generate report -o /report.json")

extraTestScript = ''
import json
report = json.loads(machine.succeed("nixos-facter -e"))
with subtest("Capture system"):
assert report['system'] == '${system}'
with subtest("Capture virtualisation"):
virt = report['virtualisation']
# kvm for systems that support it, otherwise the vm test should present itself as qemu
# todo double-check this is the same for intel
assert virt in ("kvm", "qemu"), f"expected virtualisation to be either kvm or qemu, got {virt}"
with subtest("Capture swap entries"):
assert 'swap' in report, "'swap' not found in the report"
assert report['swap'] == [
{ 'path': '/dev/vda4', 'type': 'partition', 'size': 1048572, 'used': 0, 'priority': -2 },
{ 'path': '/dev/dm-0', 'type': 'partition', 'size': 10236, 'used': 0, 'priority': 100 },
{ 'path': '/swap/swapfile-1', 'type': 'file', 'size': 9760, 'used': 0, 'priority': -3 },
{ 'path': '/swap/swapfile-2', 'type': 'file', 'size': 9760, 'used': 0, 'priority': -4 },
{ 'path': '/swap/swapfile-3', 'type': 'file', 'size': 9760, 'used': 0, 'priority': -5 }
], "swap entries did not match what we expected"
# todo is there a nice way of showing a diff?
'';
};
}
50 changes: 50 additions & 0 deletions nix/packages/nixos-facter/tests/disko.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
disko = {
devices = {
disk = {
main = {
device = "/dev/vdb";
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = {
size = "500M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
end = "-1G";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
encryptedSwap = {
size = "10M";
content = {
type = "swap";
randomEncryption = true;
priority = 100; # prefer to encrypt as long as we have space for it
};
};
plainSwap = {
size = "100%";
content = {
type = "swap";
discardPolicy = "both";
resumeDevice = true; # resume from hiberation from this device
};
};
};
};
};
};
};
};
}
Loading

0 comments on commit 6b16886

Please sign in to comment.