diff --git a/builder/go.mod b/builder/go.mod index d26f064b..9855c60f 100644 --- a/builder/go.mod +++ b/builder/go.mod @@ -49,7 +49,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/ebitengine/purego v0.10.0 // indirect + github.com/ebitengine/purego v0.10.2 // indirect github.com/elastic/go-ucfg v0.9.1 // indirect github.com/elastic/gosigar v0.14.4 // indirect github.com/elastic/lunes v0.2.2 // indirect @@ -61,7 +61,7 @@ require ( github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.6 // indirect @@ -90,7 +90,7 @@ require ( github.com/knadh/koanf/v2 v2.3.5 // indirect github.com/leodido/go-syslog/v4 v4.6.0 // indirect github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b // indirect - github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect + github.com/lufia/plan9stats v0.0.0-20260802145828-341c2f0c90b5 // indirect github.com/magefile/mage v1.17.2 // indirect github.com/michel-laterman/proxy-connect-dialer-go v0.1.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -119,12 +119,12 @@ require ( github.com/prometheus/procfs v0.21.0 // indirect github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect github.com/rs/cors v1.11.1 // indirect - github.com/shirou/gopsutil/v4 v4.26.6 // indirect + github.com/shirou/gopsutil/v4 v4.26.7 // indirect github.com/sirupsen/logrus v1.9.4 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/testify v1.11.1 // indirect - github.com/tklauser/go-sysconf v0.3.16 // indirect - github.com/tklauser/numcpus v0.11.0 // indirect + github.com/tklauser/go-sysconf v0.4.0 // indirect + github.com/tklauser/numcpus v0.12.0 // indirect github.com/valyala/fastjson v1.6.10 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.etcd.io/bbolt v1.5.0 // indirect diff --git a/builder/go.sum b/builder/go.sum index 8efd57c2..918239a7 100644 --- a/builder/go.sum +++ b/builder/go.sum @@ -23,8 +23,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= -github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.10.2 h1:W809HbnvzAxgdm+aOvlSekrM16wGCdT/e76+9tS7gzE= +github.com/ebitengine/purego v0.10.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/elastic/go-ucfg v0.9.1 h1:OwbVLC9pAmHqlBDq5owRC7HbfldsLuqPqrwg23n17BQ= github.com/elastic/go-ucfg v0.9.1/go.mod h1:6Z66LNkFK5xAlWg3Ny7qgtrvBUadaAcor+kYxw2pXBk= github.com/elastic/gosigar v0.14.4 h1:7NRnWJDFjEKpOjnHhtzrPGZWr9EMrYFsLjF4q0Czosk= @@ -50,8 +50,9 @@ github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -123,8 +124,8 @@ github.com/leodido/go-syslog/v4 v4.6.0 h1:3o9H6K0cj9ITrNt7MG6CJ/Ae+vXmZcEPhI/N30 github.com/leodido/go-syslog/v4 v4.6.0/go.mod h1:BOEXCJSgy32THF4eZWwtZ11w6LrrFVBj+nMtv06ge4w= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b h1:11UHH39z1RhZ5dc4y4r/4koJo6IYFgTRMe/LlwRTEw0= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg= -github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k= -github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/lufia/plan9stats v0.0.0-20260802145828-341c2f0c90b5 h1:eveIIGn4BGM3qknO74omf6HYr30/exH+eVUTuAgwjZ0= +github.com/lufia/plan9stats v0.0.0-20260802145828-341c2f0c90b5/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/madflojo/testcerts v1.5.0 h1:GhQllyAiGzXVZU+i8O/cQkPTHzN59RxMGtm3uETgXnU= github.com/madflojo/testcerts v1.5.0/go.mod h1:MW8sh39gLnkKh4K0Nc55AyHEDl9l/FBLDUsQhpmkuo0= github.com/magefile/mage v1.17.2 h1:fyXVu1eadI8Ap1HCCNgEhJ5McIWiYhLR8uol64ZZc40= @@ -210,8 +211,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7 github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shirou/gopsutil/v4 v4.26.6 h1:Mzr/npDtQC/xpeEuQKHZt8Zo9CmPvhTj8nkR8w5TLDs= -github.com/shirou/gopsutil/v4 v4.26.6/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= +github.com/shirou/gopsutil/v4 v4.26.7 h1:IXzpHz/dkMRYAhKkOXr1HB6SuzWU3eoyyeWe7g3bNZc= +github.com/shirou/gopsutil/v4 v4.26.7/go.mod h1:5O9FjBiXoTDFatIWjZZosqj4pV0DRtLx598xGbBehzM= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= @@ -225,10 +226,10 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= -github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= -github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= -github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= +github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU= +github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI= +github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4= +github.com/tklauser/numcpus v0.12.0/go.mod h1:ABHeXzJnr/qqwguhClkZKT1/8VABcYrsyUiUGobwWJg= github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -476,6 +477,7 @@ golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= diff --git a/changelog/unreleased/pr-87.toml b/changelog/unreleased/pr-87.toml new file mode 100644 index 00000000..8a88f6ea --- /dev/null +++ b/changelog/unreleased/pr-87.toml @@ -0,0 +1,5 @@ +type = "a" +message = "Add `os.description` attribute to Collector information." + +issues = ["Graylog2/graylog2-server#25176"] +pulls = ["87"] diff --git a/superv/go.mod b/superv/go.mod index 260ad5b8..b5c335bf 100644 --- a/superv/go.mod +++ b/superv/go.mod @@ -18,6 +18,7 @@ require ( github.com/knadh/koanf/providers/structs v1.0.0 github.com/knadh/koanf/v2 v2.3.5 github.com/open-telemetry/opamp-go v0.23.0 + github.com/shirou/gopsutil/v4 v4.26.7 github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/contrib/bridges/otelzap v0.19.0 @@ -37,19 +38,26 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/ebitengine/purego v0.10.2 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/klauspost/compress v1.19.1 // indirect + github.com/lufia/plan9stats v0.0.0-20260802145828-341c2f0c90b5 // indirect github.com/michel-laterman/proxy-connect-dialer-go v0.1.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/spf13/pflag v1.0.10 // indirect + github.com/tklauser/go-sysconf v0.4.0 // indirect + github.com/tklauser/numcpus v0.12.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel/log v0.20.0 // indirect go.opentelemetry.io/otel/metric v1.44.0 // indirect diff --git a/superv/go.sum b/superv/go.sum index d2c9a58d..ff728883 100644 --- a/superv/go.sum +++ b/superv/go.sum @@ -9,6 +9,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ebitengine/purego v0.10.2 h1:W809HbnvzAxgdm+aOvlSekrM16wGCdT/e76+9tS7gzE= +github.com/ebitengine/purego v0.10.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -20,6 +22,9 @@ github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= @@ -60,6 +65,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lufia/plan9stats v0.0.0-20260802145828-341c2f0c90b5 h1:eveIIGn4BGM3qknO74omf6HYr30/exH+eVUTuAgwjZ0= +github.com/lufia/plan9stats v0.0.0-20260802145828-341c2f0c90b5/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/madflojo/testcerts v1.5.0 h1:GhQllyAiGzXVZU+i8O/cQkPTHzN59RxMGtm3uETgXnU= github.com/madflojo/testcerts v1.5.0/go.mod h1:MW8sh39gLnkKh4K0Nc55AyHEDl9l/FBLDUsQhpmkuo0= github.com/michel-laterman/proxy-connect-dialer-go v0.1.0 h1:Q8asukpmyrEheocd+R+6YEI4jcm62sHHalgTMG+LoLw= @@ -72,9 +79,13 @@ github.com/open-telemetry/opamp-go v0.23.0 h1:k7h7w/muprut9/DAhUC4anX4v7hIdgO02g github.com/open-telemetry/opamp-go v0.23.0/go.mod h1:DIIVdkLefdqPW5L+4I2twmAicVrTB0Bp5XJAfedZzAM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil/v4 v4.26.7 h1:IXzpHz/dkMRYAhKkOXr1HB6SuzWU3eoyyeWe7g3bNZc= +github.com/shirou/gopsutil/v4 v4.26.7/go.mod h1:5O9FjBiXoTDFatIWjZZosqj4pV0DRtLx598xGbBehzM= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -84,6 +95,12 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU= +github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI= +github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4= +github.com/tklauser/numcpus v0.12.0/go.mod h1:ABHeXzJnr/qqwguhClkZKT1/8VABcYrsyUiUGobwWJg= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/otelzap v0.19.0 h1:48Eq3xxFx2KlL/tF7lnl42kKJBDlhNTLRzv0h154JnM= @@ -125,6 +142,9 @@ golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= diff --git a/superv/internal/testfixtures/fixtures.go b/superv/internal/testfixtures/fixtures.go new file mode 100644 index 00000000..807e0fab --- /dev/null +++ b/superv/internal/testfixtures/fixtures.go @@ -0,0 +1,31 @@ +// Copyright (C) 2026 Graylog, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the Server Side Public License, version 1, +// as published by MongoDB, Inc. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Server Side Public License for more details. +// +// You should have received a copy of the Server Side Public License +// along with this program. If not, see +// . +// +// SPDX-License-Identifier: SSPL-1.0 + +// Package testfixtures provides fixtures as embed.FS instances for reusability from different packages. +package testfixtures + +import ( + "embed" +) + +// OsReleaseFS provides /etc/os-release file fixtures. +// +//go:embed testdata/os-release/*.txt +var OsReleaseFS embed.FS + +//go:embed testdata/hostinfo/*.json +var HostInfoFS embed.FS diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-almalinux-10.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-almalinux-10.json new file mode 100644 index 00000000..5224d23f --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-almalinux-10.json @@ -0,0 +1,15 @@ +{ + "hostname": "60fb66970fa2", + "uptime": 17955, + "bootTime": 1785485632, + "procs": 1, + "os": "linux", + "platform": "almalinux", + "platformFamily": "rhel", + "platformVersion": "10.1", + "kernelVersion": "7.0.0-28-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "docker", + "virtualizationRole": "guest", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-almalinux-8.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-almalinux-8.json new file mode 100644 index 00000000..682ceecb --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-almalinux-8.json @@ -0,0 +1,15 @@ +{ + "hostname": "1a3f2327d015", + "uptime": 17940, + "bootTime": 1785485632, + "procs": 1, + "os": "linux", + "platform": "almalinux", + "platformFamily": "rhel", + "platformVersion": "8.10", + "kernelVersion": "7.0.0-28-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "docker", + "virtualizationRole": "guest", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-almalinux-9.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-almalinux-9.json new file mode 100644 index 00000000..a2b83170 --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-almalinux-9.json @@ -0,0 +1,15 @@ +{ + "hostname": "83fcd2bc3eac", + "uptime": 17904, + "bootTime": 1785485632, + "procs": 1, + "os": "linux", + "platform": "almalinux", + "platformFamily": "rhel", + "platformVersion": "9.7", + "kernelVersion": "7.0.0-28-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "docker", + "virtualizationRole": "guest", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-alpine-3.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-alpine-3.json new file mode 100644 index 00000000..cde82abd --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-alpine-3.json @@ -0,0 +1,15 @@ +{ + "hostname": "65444f511f5a", + "uptime": 17977, + "bootTime": 1785485632, + "procs": 1, + "os": "linux", + "platform": "alpine", + "platformFamily": "alpine", + "platformVersion": "3.23.3", + "kernelVersion": "7.0.0-28-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "docker", + "virtualizationRole": "guest", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-amazonlinux-2023.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-amazonlinux-2023.json new file mode 100644 index 00000000..4e359b92 --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-amazonlinux-2023.json @@ -0,0 +1,15 @@ +{ + "hostname": "09425185f0ec", + "uptime": 436414, + "bootTime": 1785324667, + "procs": 1, + "os": "linux", + "platform": "amazon", + "platformFamily": "rhel", + "platformVersion": "2023.12.20260724", + "kernelVersion": "7.0.0-28-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "docker", + "virtualizationRole": "guest", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-arch-2026-08.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-arch-2026-08.json new file mode 100644 index 00000000..0c84506c --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-arch-2026-08.json @@ -0,0 +1,15 @@ +{ + "hostname": "6b5cc7679706", + "uptime": 436271, + "bootTime": 1785324667, + "procs": 1, + "os": "linux", + "platform": "arch", + "platformFamily": "arch", + "platformVersion": "20260726.0.562117", + "kernelVersion": "7.0.0-28-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "docker", + "virtualizationRole": "guest", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-debian-13.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-debian-13.json new file mode 100644 index 00000000..73fa6af0 --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-debian-13.json @@ -0,0 +1,15 @@ +{ + "hostname": "23789806c978", + "uptime": 17856, + "bootTime": 1785485632, + "procs": 1, + "os": "linux", + "platform": "debian", + "platformFamily": "debian", + "platformVersion": "13.3", + "kernelVersion": "7.0.0-28-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "docker", + "virtualizationRole": "guest", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-macos-26.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-macos-26.json new file mode 100644 index 00000000..c2bfd2c6 --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-macos-26.json @@ -0,0 +1,15 @@ +{ + "hostname": "HOSTNAME-MP", + "uptime": 969219, + "bootTime": 1784534644, + "procs": 704, + "os": "darwin", + "platform": "darwin", + "platformFamily": "Standalone Workstation", + "platformVersion": "26.5.2", + "kernelVersion": "25.5.0", + "kernelArch": "x86_64", + "virtualizationSystem": "", + "virtualizationRole": "", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-opensuse-tumbleweed-2026-08.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-opensuse-tumbleweed-2026-08.json new file mode 100644 index 00000000..2b3dbc2c --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-opensuse-tumbleweed-2026-08.json @@ -0,0 +1,15 @@ +{ + "hostname": "bbf8cd358a87", + "uptime": 436346, + "bootTime": 1785324667, + "procs": 1, + "os": "linux", + "platform": "opensuse-tumbleweed", + "platformFamily": "suse", + "platformVersion": "20260802", + "kernelVersion": "7.0.0-28-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "docker", + "virtualizationRole": "guest", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-ubuntu-24.04.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-ubuntu-24.04.json new file mode 100644 index 00000000..e0bacd08 --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-ubuntu-24.04.json @@ -0,0 +1,15 @@ +{ + "hostname": "nc", + "uptime": 703486, + "bootTime": 1784799975, + "procs": 148, + "os": "linux", + "platform": "ubuntu", + "platformFamily": "debian", + "platformVersion": "24.04", + "kernelVersion": "6.8.0-136-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "", + "virtualizationRole": "guest", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-ubuntu-26.04.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-ubuntu-26.04.json new file mode 100644 index 00000000..f34bb926 --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-ubuntu-26.04.json @@ -0,0 +1,15 @@ +{ + "hostname": "t14s5", + "uptime": 17700, + "bootTime": 1785485632, + "procs": 502, + "os": "linux", + "platform": "ubuntu", + "platformFamily": "debian", + "platformVersion": "26.04", + "kernelVersion": "7.0.0-28-generic", + "kernelArch": "x86_64", + "virtualizationSystem": "kvm", + "virtualizationRole": "host", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-windows-2019.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-windows-2019.json new file mode 100644 index 00000000..95d1f7dd --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-windows-2019.json @@ -0,0 +1,15 @@ +{ + "hostname": "win2019", + "uptime": 13397856, + "bootTime": 1772105492, + "procs": 110, + "os": "windows", + "platform": "Microsoft Windows Server 2019 Datacenter", + "platformFamily": "Server", + "platformVersion": "", + "kernelVersion": "10.0.17763.8389 Build 17763.8389", + "kernelArch": "x86_64", + "virtualizationSystem": "", + "virtualizationRole": "", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-windows-2022.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-windows-2022.json new file mode 100644 index 00000000..0bcf8e19 --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-windows-2022.json @@ -0,0 +1,15 @@ +{ + "hostname": "win2022", + "uptime": 13398027, + "bootTime": 1772105348, + "procs": 117, + "os": "windows", + "platform": "Microsoft Windows Server 2022 Datacenter", + "platformFamily": "Server", + "platformVersion": "21H2", + "kernelVersion": "10.0.20348.4773 Build 20348.4773", + "kernelArch": "x86_64", + "virtualizationSystem": "", + "virtualizationRole": "", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/hostinfo/hostinfo-windows-2025.json b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-windows-2025.json new file mode 100644 index 00000000..b952705e --- /dev/null +++ b/superv/internal/testfixtures/testdata/hostinfo/hostinfo-windows-2025.json @@ -0,0 +1,15 @@ +{ + "hostname": "win2025", + "uptime": 12094781, + "bootTime": 1773408613, + "procs": 144, + "os": "windows", + "platform": "Microsoft Windows Server 2025 Datacenter", + "platformFamily": "Server", + "platformVersion": "24H2", + "kernelVersion": "10.0.26100.32370 Build 26100.32370", + "kernelArch": "x86_64", + "virtualizationSystem": "", + "virtualizationRole": "", + "hostId": "bd5b5796-fec7-454b-9483-5eb014ea99cf" +} diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-almalinux-10.txt b/superv/internal/testfixtures/testdata/os-release/os-release-almalinux-10.txt new file mode 100644 index 00000000..7fc3c1d0 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-almalinux-10.txt @@ -0,0 +1,22 @@ +NAME="AlmaLinux" +VERSION="10.2 (Lavender Lion)" +RELEASE_TYPE=stable +ID="almalinux" +ID_LIKE="rhel centos fedora" +VERSION_ID="10.2" +PLATFORM_ID="platform:el10" +PRETTY_NAME="AlmaLinux 10.2 (Lavender Lion)" +ANSI_COLOR="0;34" +LOGO="fedora-logo-icon" +CPE_NAME="cpe:/o:almalinux:almalinux:10.2" +HOME_URL="https://almalinux.org/" +DOCUMENTATION_URL="https://wiki.almalinux.org/" +VENDOR_NAME="AlmaLinux" +VENDOR_URL="https://almalinux.org/" +BUG_REPORT_URL="https://bugs.almalinux.org/" + +ALMALINUX_MANTISBT_PROJECT="AlmaLinux-10" +ALMALINUX_MANTISBT_PROJECT_VERSION="10.2" +REDHAT_SUPPORT_PRODUCT="AlmaLinux" +REDHAT_SUPPORT_PRODUCT_VERSION="10.2" +SUPPORT_END=2035-06-01 diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-almalinux-8.txt b/superv/internal/testfixtures/testdata/os-release/os-release-almalinux-8.txt new file mode 100644 index 00000000..6b594068 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-almalinux-8.txt @@ -0,0 +1,19 @@ +NAME="AlmaLinux" +VERSION="8.10 (Cerulean Leopard)" +ID="almalinux" +ID_LIKE="rhel centos fedora" +VERSION_ID="8.10" +PLATFORM_ID="platform:el8" +PRETTY_NAME="AlmaLinux 8.10 (Cerulean Leopard)" +ANSI_COLOR="0;34" +LOGO="fedora-logo-icon" +CPE_NAME="cpe:/o:almalinux:almalinux:8::baseos" +HOME_URL="https://almalinux.org/" +DOCUMENTATION_URL="https://wiki.almalinux.org/" +BUG_REPORT_URL="https://bugs.almalinux.org/" + +ALMALINUX_MANTISBT_PROJECT="AlmaLinux-8" +ALMALINUX_MANTISBT_PROJECT_VERSION="8.10" +REDHAT_SUPPORT_PRODUCT="AlmaLinux" +REDHAT_SUPPORT_PRODUCT_VERSION="8.10" +SUPPORT_END=2029-06-01 diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-almalinux-9.txt b/superv/internal/testfixtures/testdata/os-release/os-release-almalinux-9.txt new file mode 100644 index 00000000..f5914a97 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-almalinux-9.txt @@ -0,0 +1,19 @@ +NAME="AlmaLinux" +VERSION="9.7 (Moss Jungle Cat)" +ID="almalinux" +ID_LIKE="rhel centos fedora" +VERSION_ID="9.7" +PLATFORM_ID="platform:el9" +PRETTY_NAME="AlmaLinux 9.7 (Moss Jungle Cat)" +ANSI_COLOR="0;34" +LOGO="fedora-logo-icon" +CPE_NAME="cpe:/o:almalinux:almalinux:9::baseos" +HOME_URL="https://almalinux.org/" +DOCUMENTATION_URL="https://wiki.almalinux.org/" +BUG_REPORT_URL="https://bugs.almalinux.org/" + +ALMALINUX_MANTISBT_PROJECT="AlmaLinux-9" +ALMALINUX_MANTISBT_PROJECT_VERSION="9.7" +REDHAT_SUPPORT_PRODUCT="AlmaLinux" +REDHAT_SUPPORT_PRODUCT_VERSION="9.7" +SUPPORT_END=2032-06-01 diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-alpine-3.txt b/superv/internal/testfixtures/testdata/os-release/os-release-alpine-3.txt new file mode 100644 index 00000000..76489be1 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-alpine-3.txt @@ -0,0 +1,6 @@ +NAME="Alpine Linux" +ID=alpine +VERSION_ID=3.23.3 +PRETTY_NAME="Alpine Linux v3.23" +HOME_URL="https://alpinelinux.org/" +BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-amazonlinux-2.txt b/superv/internal/testfixtures/testdata/os-release/os-release-amazonlinux-2.txt new file mode 100644 index 00000000..e97399d9 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-amazonlinux-2.txt @@ -0,0 +1,10 @@ +NAME="Amazon Linux" +VERSION="2" +ID="amzn" +ID_LIKE="centos rhel fedora" +VERSION_ID="2" +PRETTY_NAME="Amazon Linux 2" +ANSI_COLOR="0;33" +CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2" +HOME_URL="https://amazonlinux.com/" +SUPPORT_END="2026-06-30" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-amazonlinux-2023.txt b/superv/internal/testfixtures/testdata/os-release/os-release-amazonlinux-2023.txt new file mode 100644 index 00000000..d76ac4ca --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-amazonlinux-2023.txt @@ -0,0 +1,16 @@ +NAME="Amazon Linux" +VERSION="2023" +ID="amzn" +ID_LIKE="fedora" +VERSION_ID="2023" +PLATFORM_ID="platform:al2023" +PRETTY_NAME="Amazon Linux 2023.12.20260724" +ANSI_COLOR="0;33" +CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2023" +HOME_URL="https://aws.amazon.com/linux/amazon-linux-2023/" +DOCUMENTATION_URL="https://docs.aws.amazon.com/linux/" +SUPPORT_URL="https://aws.amazon.com/premiumsupport/" +BUG_REPORT_URL="https://github.com/amazonlinux/amazon-linux-2023" +VENDOR_NAME="AWS" +VENDOR_URL="https://aws.amazon.com/" +SUPPORT_END="2029-06-30" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-arch-2026-08.txt b/superv/internal/testfixtures/testdata/os-release/os-release-arch-2026-08.txt new file mode 100644 index 00000000..2c59bef4 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-arch-2026-08.txt @@ -0,0 +1,12 @@ +NAME="Arch Linux" +PRETTY_NAME="Arch Linux" +ID=arch +BUILD_ID=rolling +VERSION_ID=20260726.0.562117 +ANSI_COLOR="38;2;23;147;209" +HOME_URL="https://archlinux.org/" +DOCUMENTATION_URL="https://wiki.archlinux.org/" +SUPPORT_URL="https://bbs.archlinux.org/" +BUG_REPORT_URL="https://gitlab.archlinux.org/groups/archlinux/-/issues" +PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/" +LOGO=archlinux-logo diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-debian-12.txt b/superv/internal/testfixtures/testdata/os-release/os-release-debian-12.txt new file mode 100644 index 00000000..33208621 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-debian-12.txt @@ -0,0 +1,9 @@ +PRETTY_NAME="Debian GNU/Linux 12 (bookworm)" +NAME="Debian GNU/Linux" +VERSION_ID="12" +VERSION="12 (bookworm)" +VERSION_CODENAME=bookworm +ID=debian +HOME_URL="https://www.debian.org/" +SUPPORT_URL="https://www.debian.org/support" +BUG_REPORT_URL="https://bugs.debian.org/" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-debian-13.txt b/superv/internal/testfixtures/testdata/os-release/os-release-debian-13.txt new file mode 100644 index 00000000..2c83cc99 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-debian-13.txt @@ -0,0 +1,10 @@ +PRETTY_NAME="Debian GNU/Linux 13 (trixie)" +NAME="Debian GNU/Linux" +VERSION_ID="13" +VERSION="13 (trixie)" +VERSION_CODENAME=trixie +DEBIAN_VERSION_FULL=13.2 +ID=debian +HOME_URL="https://www.debian.org/" +SUPPORT_URL="https://www.debian.org/support" +BUG_REPORT_URL="https://bugs.debian.org/" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-fedora-44.txt b/superv/internal/testfixtures/testdata/os-release/os-release-fedora-44.txt new file mode 100644 index 00000000..a4356331 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-fedora-44.txt @@ -0,0 +1,21 @@ +NAME="Fedora Linux" +VERSION="44 (Server Edition)" +RELEASE_TYPE=stable +ID=fedora +VERSION_ID=44 +VERSION_CODENAME="" +PRETTY_NAME="Fedora Linux 44 (Server Edition)" +ANSI_COLOR="0;38;2;60;110;180" +LOGO=fedora-logo-icon +CPE_NAME="cpe:/o:fedoraproject:fedora:44" +HOME_URL="https://fedoraproject.org/" +DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f44/" +SUPPORT_URL="https://ask.fedoraproject.org/" +BUG_REPORT_URL="https://bugzilla.redhat.com/" +REDHAT_BUGZILLA_PRODUCT="Fedora" +REDHAT_BUGZILLA_PRODUCT_VERSION=44 +REDHAT_SUPPORT_PRODUCT="Fedora" +REDHAT_SUPPORT_PRODUCT_VERSION=44 +SUPPORT_END=2027-05-19 +VARIANT="Server Edition" +VARIANT_ID=server diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-fedora-container-44.txt b/superv/internal/testfixtures/testdata/os-release/os-release-fedora-container-44.txt new file mode 100644 index 00000000..f9bcc3ea --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-fedora-container-44.txt @@ -0,0 +1,22 @@ +NAME="Fedora Linux" +VERSION="44 (Container Image)" +RELEASE_TYPE=stable +ID=fedora +VERSION_ID=44 +VERSION_CODENAME="" +PRETTY_NAME="Fedora Linux 44 (Container Image)" +ANSI_COLOR="0;38;2;60;110;180" +LOGO=fedora-logo-icon +CPE_NAME="cpe:/o:fedoraproject:fedora:44" +DEFAULT_HOSTNAME="fedora" +HOME_URL="https://fedoraproject.org/" +DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f44/" +SUPPORT_URL="https://ask.fedoraproject.org/" +BUG_REPORT_URL="https://bugzilla.redhat.com/" +REDHAT_BUGZILLA_PRODUCT="Fedora" +REDHAT_BUGZILLA_PRODUCT_VERSION=44 +REDHAT_SUPPORT_PRODUCT="Fedora" +REDHAT_SUPPORT_PRODUCT_VERSION=44 +SUPPORT_END=2027-05-19 +VARIANT="Container Image" +VARIANT_ID=container diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-opensuse-tumbleweed-2026-08.txt b/superv/internal/testfixtures/testdata/os-release/os-release-opensuse-tumbleweed-2026-08.txt new file mode 100644 index 00000000..f88f3111 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-opensuse-tumbleweed-2026-08.txt @@ -0,0 +1,16 @@ +NAME="openSUSE Tumbleweed" +# VERSION="20260802" +ID="opensuse-tumbleweed" +ID_LIKE="opensuse suse" +VERSION_ID="20260802" +PRETTY_NAME="openSUSE Tumbleweed" +ANSI_COLOR="0;32" +# CPE 2.3 format, boo#1217921 +CPE_NAME="cpe:2.3:o:opensuse:tumbleweed:20260802:*:*:*:*:*:*:*" +#CPE 2.2 format +#CPE_NAME="cpe:/o:opensuse:tumbleweed:20260802" +BUG_REPORT_URL="https://bugzilla.opensuse.org" +SUPPORT_URL="https://bugs.opensuse.org" +HOME_URL="https://www.opensuse.org" +DOCUMENTATION_URL="https://en.opensuse.org/Portal:Tumbleweed" +LOGO="distributor-logo-Tumbleweed" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-oraclelinux-10.txt b/superv/internal/testfixtures/testdata/os-release/os-release-oraclelinux-10.txt new file mode 100644 index 00000000..2a57f448 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-oraclelinux-10.txt @@ -0,0 +1,18 @@ +NAME="Oracle Linux Server" +VERSION="10.2" +ID="ol" +ID_LIKE="fedora" +VARIANT="Server" +VARIANT_ID="server" +VERSION_ID="10.2" +PLATFORM_ID="platform:el10" +PRETTY_NAME="Oracle Linux Server 10.2" +ANSI_COLOR="0;31" +CPE_NAME="cpe:/o:oracle:linux:10:2:server" +HOME_URL="https://linux.oracle.com/" +BUG_REPORT_URL="https://github.com/oracle/oracle-linux" + +ORACLE_BUGZILLA_PRODUCT="Oracle Linux 10" +ORACLE_BUGZILLA_PRODUCT_VERSION=10.2 +ORACLE_SUPPORT_PRODUCT="Oracle Linux" +ORACLE_SUPPORT_PRODUCT_VERSION=10.2 diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-oraclelinux-8.txt b/superv/internal/testfixtures/testdata/os-release/os-release-oraclelinux-8.txt new file mode 100644 index 00000000..81c29c07 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-oraclelinux-8.txt @@ -0,0 +1,18 @@ +NAME="Oracle Linux Server" +VERSION="8.10" +ID="ol" +ID_LIKE="fedora" +VARIANT="Server" +VARIANT_ID="server" +VERSION_ID="8.10" +PLATFORM_ID="platform:el8" +PRETTY_NAME="Oracle Linux Server 8.10" +ANSI_COLOR="0;31" +CPE_NAME="cpe:/o:oracle:linux:8:10:server" +HOME_URL="https://linux.oracle.com/" +BUG_REPORT_URL="https://github.com/oracle/oracle-linux" + +ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8" +ORACLE_BUGZILLA_PRODUCT_VERSION=8.10 +ORACLE_SUPPORT_PRODUCT="Oracle Linux" +ORACLE_SUPPORT_PRODUCT_VERSION=8.10 diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-oraclelinux-9.txt b/superv/internal/testfixtures/testdata/os-release/os-release-oraclelinux-9.txt new file mode 100644 index 00000000..3fa60342 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-oraclelinux-9.txt @@ -0,0 +1,18 @@ +NAME="Oracle Linux Server" +VERSION="9.8" +ID="ol" +ID_LIKE="fedora" +VARIANT="Server" +VARIANT_ID="server" +VERSION_ID="9.8" +PLATFORM_ID="platform:el9" +PRETTY_NAME="Oracle Linux Server 9.8" +ANSI_COLOR="0;31" +CPE_NAME="cpe:/o:oracle:linux:9:8:server" +HOME_URL="https://linux.oracle.com/" +BUG_REPORT_URL="https://github.com/oracle/oracle-linux" + +ORACLE_BUGZILLA_PRODUCT="Oracle Linux 9" +ORACLE_BUGZILLA_PRODUCT_VERSION=9.8 +ORACLE_SUPPORT_PRODUCT="Oracle Linux" +ORACLE_SUPPORT_PRODUCT_VERSION=9.8 diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-redhat-8.txt b/superv/internal/testfixtures/testdata/os-release/os-release-redhat-8.txt new file mode 100644 index 00000000..346e2966 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-redhat-8.txt @@ -0,0 +1,17 @@ +NAME="Red Hat Enterprise Linux" +VERSION="8.5 (Ootpa)" +ID="rhel" +ID_LIKE="fedora" +VERSION_ID="8.5" +PLATFORM_ID="platform:el8" +PRETTY_NAME="Red Hat Enterprise Linux 8.5 (Ootpa)" +ANSI_COLOR="0;31" +CPE_NAME="cpe:/o:redhat:enterprise_linux:8::baseos" +HOME_URL="https://www.redhat.com/" +DOCUMENTATION_URL="https://access.redhat.com/documentation/red_hat_enterprise_linux/8/" +BUG_REPORT_URL="https://bugzilla.redhat.com/" + +REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8" +REDHAT_BUGZILLA_PRODUCT_VERSION=8.5 +REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux" +REDHAT_SUPPORT_PRODUCT_VERSION="8.5" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-redhat-9.txt b/superv/internal/testfixtures/testdata/os-release/os-release-redhat-9.txt new file mode 100644 index 00000000..66458c56 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-redhat-9.txt @@ -0,0 +1,18 @@ +NAME="Red Hat Enterprise Linux" +VERSION="9.4 (Plow)" +ID="rhel" +ID_LIKE="fedora" +VERSION_ID="9.4" +PLATFORM_ID="platform:el9" +PRETTY_NAME="Red Hat Enterprise Linux 9.4 (Plow)" +ANSI_COLOR="0;31" +LOGO="fedora-logo-icon" +CPE_NAME="cpe:/o:redhat:enterprise_linux:9::baseos" +HOME_URL="https://www.redhat.com/" +DOCUMENTATION_URL="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9" +BUG_REPORT_URL="https://issues.redhat.com/" + +REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 9" +REDHAT_BUGZILLA_PRODUCT_VERSION=9.4 +REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux" +REDHAT_SUPPORT_PRODUCT_VERSION="9.4" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-rockylinux-8.txt b/superv/internal/testfixtures/testdata/os-release/os-release-rockylinux-8.txt new file mode 100644 index 00000000..4782b1e5 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-rockylinux-8.txt @@ -0,0 +1,17 @@ +NAME="Rocky Linux" +VERSION="8.9 (Green Obsidian)" +ID="rocky" +ID_LIKE="rhel centos fedora" +VERSION_ID="8.9" +PLATFORM_ID="platform:el8" +PRETTY_NAME="Rocky Linux 8.9 (Green Obsidian)" +ANSI_COLOR="0;32" +LOGO="fedora-logo-icon" +CPE_NAME="cpe:/o:rocky:rocky:8:GA" +HOME_URL="https://rockylinux.org/" +BUG_REPORT_URL="https://bugs.rockylinux.org/" +SUPPORT_END="2029-05-31" +ROCKY_SUPPORT_PRODUCT="Rocky-Linux-8" +ROCKY_SUPPORT_PRODUCT_VERSION="8.9" +REDHAT_SUPPORT_PRODUCT="Rocky Linux" +REDHAT_SUPPORT_PRODUCT_VERSION="8.9" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-rockylinux-9.txt b/superv/internal/testfixtures/testdata/os-release/os-release-rockylinux-9.txt new file mode 100644 index 00000000..615382df --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-rockylinux-9.txt @@ -0,0 +1,17 @@ +NAME="Rocky Linux" +VERSION="9.3 (Blue Onyx)" +ID="rocky" +ID_LIKE="rhel centos fedora" +VERSION_ID="9.3" +PLATFORM_ID="platform:el9" +PRETTY_NAME="Rocky Linux 9.3 (Blue Onyx)" +ANSI_COLOR="0;32" +LOGO="fedora-logo-icon" +CPE_NAME="cpe:/o:rocky:rocky:9::baseos" +HOME_URL="https://rockylinux.org/" +BUG_REPORT_URL="https://bugs.rockylinux.org/" +SUPPORT_END="2032-05-31" +ROCKY_SUPPORT_PRODUCT="Rocky-Linux-9" +ROCKY_SUPPORT_PRODUCT_VERSION="9.3" +REDHAT_SUPPORT_PRODUCT="Rocky Linux" +REDHAT_SUPPORT_PRODUCT_VERSION="9.3" diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-ubuntu-24.04.txt b/superv/internal/testfixtures/testdata/os-release/os-release-ubuntu-24.04.txt new file mode 100644 index 00000000..18cf4770 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-ubuntu-24.04.txt @@ -0,0 +1,13 @@ +PRETTY_NAME="Ubuntu 24.04.1 LTS" +NAME="Ubuntu" +VERSION_ID="24.04" +VERSION="24.04.1 LTS (Noble Numbat)" +VERSION_CODENAME=noble +ID=ubuntu +ID_LIKE=debian +HOME_URL="https://www.ubuntu.com/" +SUPPORT_URL="https://help.ubuntu.com/" +BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" +PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" +UBUNTU_CODENAME=noble +LOGO=ubuntu-logo diff --git a/superv/internal/testfixtures/testdata/os-release/os-release-ubuntu-26.04.txt b/superv/internal/testfixtures/testdata/os-release/os-release-ubuntu-26.04.txt new file mode 100644 index 00000000..e89ba547 --- /dev/null +++ b/superv/internal/testfixtures/testdata/os-release/os-release-ubuntu-26.04.txt @@ -0,0 +1,13 @@ +PRETTY_NAME="Ubuntu 26.04 LTS" +NAME="Ubuntu" +VERSION_ID="26.04" +VERSION="26.04 LTS (Resolute Raccoon)" +VERSION_CODENAME=resolute +ID=ubuntu +ID_LIKE=debian +HOME_URL="https://www.ubuntu.com/" +SUPPORT_URL="https://help.ubuntu.com/" +BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" +PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" +UBUNTU_CODENAME=resolute +LOGO=ubuntu-logo diff --git a/superv/internal/testsysinfo/os_release.go b/superv/internal/testsysinfo/os_release.go new file mode 100644 index 00000000..d4ed5ce7 --- /dev/null +++ b/superv/internal/testsysinfo/os_release.go @@ -0,0 +1,50 @@ +// Copyright (C) 2026 Graylog, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the Server Side Public License, version 1, +// as published by MongoDB, Inc. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Server Side Public License for more details. +// +// You should have received a copy of the Server Side Public License +// along with this program. If not, see +// . +// +// SPDX-License-Identifier: SSPL-1.0 + +package testsysinfo + +import ( + "path" + "strings" + "testing" + + "github.com/Graylog2/collector/superv/internal/testfixtures" + "github.com/Graylog2/collector/superv/sysinfo" + "github.com/stretchr/testify/require" +) + +func GetOSReleaseSupplier(t *testing.T, name string) func() (sysinfo.OSRelease, error) { + t.Helper() + + // os-release files only exist on Linux + if name == "" || strings.Contains(name, "macos") || strings.Contains(name, "windows") { + return func() (sysinfo.OSRelease, error) { + return sysinfo.OSRelease{}, nil + } + } + + // Using path.Join to avoid backslashes on windows. The embed.FS always uses slashes. + file, err := testfixtures.OsReleaseFS.Open(path.Join("testdata", "os-release", "os-release-"+name+".txt")) + require.NoError(t, err) + + osRelease, err := sysinfo.ParseOSRelease(file) + require.NoError(t, err) + + return func() (sysinfo.OSRelease, error) { + return osRelease, nil + } +} diff --git a/superv/ownlogs/resource.go b/superv/ownlogs/resource.go index e34f0f7a..b625a1b4 100644 --- a/superv/ownlogs/resource.go +++ b/superv/ownlogs/resource.go @@ -22,7 +22,7 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" - semconv "go.opentelemetry.io/otel/semconv/v1.39.0" + semconv "go.opentelemetry.io/otel/semconv/v1.41.0" ) // BuildResource creates an OTel resource with service identifying attributes diff --git a/superv/supervisor/opamp_agent_description.go b/superv/supervisor/opamp_agent_description.go new file mode 100644 index 00000000..36a1fbe0 --- /dev/null +++ b/superv/supervisor/opamp_agent_description.go @@ -0,0 +1,115 @@ +// Copyright (C) 2026 Graylog, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the Server Side Public License, version 1, +// as published by MongoDB, Inc. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Server Side Public License for more details. +// +// You should have received a copy of the Server Side Public License +// along with this program. If not, see +// . +// +// SPDX-License-Identifier: SSPL-1.0 + +package supervisor + +import ( + "cmp" + "os" + "runtime" + "strings" + + "github.com/Graylog2/collector/superv/sysinfo" + "github.com/Graylog2/collector/superv/version" + "github.com/open-telemetry/opamp-go/protobufs" + "go.opentelemetry.io/otel/attribute" + semconv "go.opentelemetry.io/otel/semconv/v1.41.0" + "go.uber.org/zap" +) + +// createAgentDescription creates the initial agent description for OpAMP. +func (s *Supervisor) createAgentDescription() *protobufs.AgentDescription { + hostname, _ := os.Hostname() + + return &protobufs.AgentDescription{ + IdentifyingAttributes: []*protobufs.KeyValue{ + attributeStringKv(semconv.ServiceNameKey, ServiceName), + attributeStringKv(semconv.ServiceInstanceIDKey, s.instanceUID), + }, + NonIdentifyingAttributes: s.nonIdentifyingAttributes(hostname), + } +} + +// nonIdentifyingAttributes builds the list of non-identifying attributes for the agent description. +func (s *Supervisor) nonIdentifyingAttributes(hostname string) []*protobufs.KeyValue { + attrs := []*protobufs.KeyValue{ + attributeStringKv(semconv.HostArchKey, runtime.GOARCH), + attributeStringKv(semconv.HostNameKey, hostname), + attributeStringKv(semconv.OSTypeKey, runtime.GOOS), + attributeStringKv(semconv.ServiceVersionKey, version.Version()), + } + + if description, err := getOSDescription(runtime.GOOS, sysinfo.GetPlatformInfo, sysinfo.GetOSRelease); err == nil { + attrs = append(attrs, attributeStringKv(semconv.OSDescriptionKey, description)) + } else { + s.logger.Warn("Failed to determine the OS description", zap.Error(err)) + } + + if s.collectorVersion != "" { + attrs = append(attrs, stringKv("collector.version", s.collectorVersion)) + } + + return attrs +} + +// getOSDescription builds an "os.description" value for each platform. +func getOSDescription(goos string, infoSupplier func() (sysinfo.PlatformInfo, error), osReleaseSupplier func() (sysinfo.OSRelease, error)) (string, error) { + // On Linux we prefer data from the /etc/os-release file to get properly + // formatted distribution names. All os-release fields are optional per the + // spec, so we fall through to the generic host info data if the file can't + // be read or yields nothing. + if goos == "linux" { + if osRelease, err := osReleaseSupplier(); err == nil { + // Prefer NAME + VERSION_ID only when both are present; a partial + // combination would mask the more complete PRETTY_NAME. A bare + // NAME still beats the generic host info data. + var nameAndVersion string + if osRelease.Name != "" && osRelease.VersionID != "" { + nameAndVersion = osRelease.Name + " " + osRelease.VersionID + } + if description := cmp.Or(nameAndVersion, osRelease.PrettyName, osRelease.Name); description != "" { + return description, nil + } + } + } + + info, err := infoSupplier() + if err != nil { + return "", err + } + switch goos { + case "darwin": + return strings.TrimSpace("macOS " + info.Version), nil + case "windows": + return strings.TrimSpace(info.Name + " " + info.Version), nil + default: + return cmp.Or(strings.TrimSpace(info.Name+" "+info.Version), "Unknown "+info.OS), nil + } +} + +// stringKv returns a protobufs.KeyValue for the given key and value. +func stringKv(key, value string) *protobufs.KeyValue { + return &protobufs.KeyValue{ + Key: key, + Value: &protobufs.AnyValue{Value: &protobufs.AnyValue_StringValue{StringValue: value}}, + } +} + +// attributeStringKv returns a protobufs.KeyValue for the given attribute.Key and string value. +func attributeStringKv(key attribute.Key, value string) *protobufs.KeyValue { + return stringKv(string(key), value) +} diff --git a/superv/supervisor/opamp_agent_description_test.go b/superv/supervisor/opamp_agent_description_test.go new file mode 100644 index 00000000..8644d761 --- /dev/null +++ b/superv/supervisor/opamp_agent_description_test.go @@ -0,0 +1,226 @@ +// Copyright (C) 2026 Graylog, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the Server Side Public License, version 1, +// as published by MongoDB, Inc. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Server Side Public License for more details. +// +// You should have received a copy of the Server Side Public License +// along with this program. If not, see +// . +// +// SPDX-License-Identifier: SSPL-1.0 + +package supervisor + +import ( + "encoding/json" + "errors" + "path" + "testing" + + "github.com/Graylog2/collector/superv/internal/testfixtures" + "github.com/Graylog2/collector/superv/internal/testsysinfo" + "github.com/Graylog2/collector/superv/sysinfo" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap" +) + +func TestSupervisor_NonIdentifyingAttributes_WithCollectorVersion(t *testing.T) { + s := &Supervisor{ + collectorVersion: "2.0.0-alpha.0", + logger: zap.NewNop(), + } + + attrs := s.nonIdentifyingAttributes("test-host") + + attrMap := make(map[string]string) + for _, kv := range attrs { + attrMap[kv.GetKey()] = kv.GetValue().GetStringValue() + } + + require.Equal(t, "test-host", attrMap["host.name"]) + require.NotEmpty(t, attrMap["service.version"]) + require.NotEmpty(t, attrMap["os.type"]) + require.NotEmpty(t, attrMap["host.arch"]) + require.Equal(t, "2.0.0-alpha.0", attrMap["collector.version"]) +} + +func TestSupervisor_NonIdentifyingAttributes_WithoutCollectorVersion(t *testing.T) { + s := &Supervisor{logger: zap.NewNop()} + + attrs := s.nonIdentifyingAttributes("test-host") + + attrMap := make(map[string]string) + for _, kv := range attrs { + attrMap[kv.GetKey()] = kv.GetValue().GetStringValue() + } + + require.Equal(t, "test-host", attrMap["host.name"]) + require.NotEmpty(t, attrMap["service.version"]) + _, hasCollectorVersion := attrMap["collector.version"] + require.False(t, hasCollectorVersion, "collector.version should not be present when empty") +} + +// loadPlatformInfo loads a gopsutil host.Info capture from the hostinfo +// testdata and maps it to a sysinfo.PlatformInfo. +func loadPlatformInfo(t *testing.T, name string) sysinfo.PlatformInfo { + t.Helper() + + // Using path.Join to avoid backslashes on windows. The embed.FS always uses slashes. + data, err := testfixtures.HostInfoFS.ReadFile(path.Join("testdata", "hostinfo", "hostinfo-"+name+".json")) + require.NoError(t, err) + + var info struct { + OS string `json:"os"` + Platform string `json:"platform"` + PlatformFamily string `json:"platformFamily"` + PlatformVersion string `json:"platformVersion"` + } + require.NoError(t, json.Unmarshal(data, &info)) + + return sysinfo.PlatformInfo{ + OS: info.OS, + Name: info.Platform, + Family: info.PlatformFamily, + Version: info.PlatformVersion, + } +} + +func TestGetOSDescription(t *testing.T) { + tests := []struct { + os string + fixture string + want string + }{ + {"linux", "almalinux-8", "AlmaLinux 8.10"}, + {"linux", "almalinux-9", "AlmaLinux 9.7"}, + {"linux", "almalinux-10", "AlmaLinux 10.2"}, + {"linux", "alpine-3", "Alpine Linux 3.23.3"}, + {"linux", "amazonlinux-2023", "Amazon Linux 2023"}, + {"linux", "arch-2026-08", "Arch Linux 20260726.0.562117"}, + {"linux", "debian-13", "Debian GNU/Linux 13"}, + {"linux", "opensuse-tumbleweed-2026-08", "openSUSE Tumbleweed 20260802"}, + {"linux", "ubuntu-24.04", "Ubuntu 24.04"}, + {"linux", "ubuntu-26.04", "Ubuntu 26.04"}, + {"darwin", "macos-26", "macOS 26.5.2"}, + {"windows", "windows-2019", "Microsoft Windows Server 2019 Datacenter"}, + {"windows", "windows-2022", "Microsoft Windows Server 2022 Datacenter 21H2"}, + {"windows", "windows-2025", "Microsoft Windows Server 2025 Datacenter 24H2"}, + } + + for _, tc := range tests { + t.Run(tc.fixture, func(t *testing.T) { + description, err := getOSDescription(tc.os, func() (sysinfo.PlatformInfo, error) { + return loadPlatformInfo(t, tc.fixture), nil + }, testsysinfo.GetOSReleaseSupplier(t, tc.fixture)) + require.NoError(t, err) + require.Equal(t, tc.want, description) + }) + } + + t.Run("all hostinfo testdata files are covered", func(t *testing.T) { + // Using path.Join to avoid backslashes on windows. The embed.FS always uses slashes. + files, err := testfixtures.HostInfoFS.ReadDir(path.Join("testdata", "hostinfo")) + require.NoError(t, err) + require.NotEmpty(t, files) + + covered := make(map[string]bool, len(tests)) + for _, tc := range tests { + covered["hostinfo-"+tc.fixture+".json"] = true + } + for _, file := range files { + assert.True(t, covered[file.Name()], "missing test case for %s", file.Name()) + } + }) +} + +func TestGetOSDescription_UnknownOS(t *testing.T) { + description, err := getOSDescription("freebsd", func() (sysinfo.PlatformInfo, error) { + return sysinfo.PlatformInfo{ + OS: "freebsd", + Name: "freebsd", + Version: "14.1", + }, nil + }, testsysinfo.GetOSReleaseSupplier(t, "")) + require.NoError(t, err) + require.Equal(t, "freebsd 14.1", description) +} + +func TestGetOSDescription_UnknownOSWithoutPlatform(t *testing.T) { + description, err := getOSDescription("freebsd", func() (sysinfo.PlatformInfo, error) { + return sysinfo.PlatformInfo{OS: "freebsd"}, nil + }, testsysinfo.GetOSReleaseSupplier(t, "")) + require.NoError(t, err) + require.Equal(t, "Unknown freebsd", description) +} + +func TestGetOSDescription_LinuxPrettyNameFallback(t *testing.T) { + description, err := getOSDescription("linux", nil, func() (sysinfo.OSRelease, error) { + return sysinfo.OSRelease{PrettyName: "Foo Linux 1.0 (Bar)"}, nil + }) + require.NoError(t, err) + require.Equal(t, "Foo Linux 1.0 (Bar)", description) +} + +func TestGetOSDescription_LinuxPrettyNamePreferredOverPartialName(t *testing.T) { + // Without a VERSION_ID, PRETTY_NAME is the better presentation value. + description, err := getOSDescription("linux", nil, func() (sysinfo.OSRelease, error) { + return sysinfo.OSRelease{Name: "Gentoo", PrettyName: "Gentoo Linux"}, nil + }) + require.NoError(t, err) + require.Equal(t, "Gentoo Linux", description) +} + +func TestGetOSDescription_LinuxNameOnly(t *testing.T) { + description, err := getOSDescription("linux", nil, func() (sysinfo.OSRelease, error) { + return sysinfo.OSRelease{Name: "Gentoo"}, nil + }) + require.NoError(t, err) + require.Equal(t, "Gentoo", description) +} + +func TestGetOSDescription_LinuxVersionIDOnlyFallsBackToHostInfo(t *testing.T) { + // A bare version number is useless as a description. + description, err := getOSDescription("linux", func() (sysinfo.PlatformInfo, error) { + return sysinfo.PlatformInfo{OS: "linux", Name: "ubuntu", Version: "24.04"}, nil + }, func() (sysinfo.OSRelease, error) { + return sysinfo.OSRelease{VersionID: "24.04"}, nil + }) + require.NoError(t, err) + require.Equal(t, "ubuntu 24.04", description) +} + +func TestGetOSDescription_LinuxEmptyOSReleaseFallsBackToHostInfo(t *testing.T) { + description, err := getOSDescription("linux", func() (sysinfo.PlatformInfo, error) { + return sysinfo.PlatformInfo{OS: "linux", Name: "ubuntu", Version: "24.04"}, nil + }, func() (sysinfo.OSRelease, error) { + return sysinfo.OSRelease{}, nil + }) + require.NoError(t, err) + require.Equal(t, "ubuntu 24.04", description) +} + +func TestGetOSDescription_LinuxOSReleaseErrorFallsBackToHostInfo(t *testing.T) { + description, err := getOSDescription("linux", func() (sysinfo.PlatformInfo, error) { + return sysinfo.PlatformInfo{OS: "linux", Name: "ubuntu", Version: "24.04"}, nil + }, func() (sysinfo.OSRelease, error) { + return sysinfo.OSRelease{}, errors.New("no os-release file") + }) + require.NoError(t, err) + require.Equal(t, "ubuntu 24.04", description) +} + +func TestGetOSDescription_LinuxAllSourcesFailing(t *testing.T) { + _, err := getOSDescription("linux", func() (sysinfo.PlatformInfo, error) { + return sysinfo.PlatformInfo{}, errors.New("no platform info") + }, func() (sysinfo.OSRelease, error) { + return sysinfo.OSRelease{}, errors.New("no os-release file") + }) + require.Error(t, err) +} diff --git a/superv/supervisor/opamp_client.go b/superv/supervisor/opamp_client.go index 8e5fe4a2..30ee4820 100644 --- a/superv/supervisor/opamp_client.go +++ b/superv/supervisor/opamp_client.go @@ -21,14 +21,11 @@ import ( "context" "crypto/tls" "fmt" - "os" - "runtime" "time" "github.com/Graylog2/collector/superv/components" "github.com/Graylog2/collector/superv/opamp" "github.com/Graylog2/collector/superv/supervisor/connection" - "github.com/Graylog2/collector/superv/version" "github.com/open-telemetry/opamp-go/protobufs" "go.uber.org/zap" ) @@ -210,56 +207,6 @@ func (s *Supervisor) createOpAMPCallbacks() *opamp.Callbacks { } } -// createAgentDescription creates the initial agent description for OpAMP. -func (s *Supervisor) createAgentDescription() *protobufs.AgentDescription { - hostname, _ := os.Hostname() - - return &protobufs.AgentDescription{ - IdentifyingAttributes: []*protobufs.KeyValue{ - { - Key: "service.name", - Value: &protobufs.AnyValue{Value: &protobufs.AnyValue_StringValue{StringValue: ServiceName}}, - }, - { - Key: "service.instance.id", - Value: &protobufs.AnyValue{Value: &protobufs.AnyValue_StringValue{StringValue: s.instanceUID}}, - }, - }, - NonIdentifyingAttributes: s.nonIdentifyingAttributes(hostname), - } -} - -// nonIdentifyingAttributes builds the list of non-identifying attributes for the agent description. -func (s *Supervisor) nonIdentifyingAttributes(hostname string) []*protobufs.KeyValue { - attrs := []*protobufs.KeyValue{ - { - Key: "service.version", - Value: &protobufs.AnyValue{Value: &protobufs.AnyValue_StringValue{StringValue: version.Version()}}, - }, - { - Key: "host.name", - Value: &protobufs.AnyValue{Value: &protobufs.AnyValue_StringValue{StringValue: hostname}}, - }, - { - Key: "os.type", - Value: &protobufs.AnyValue{Value: &protobufs.AnyValue_StringValue{StringValue: runtime.GOOS}}, - }, - { - Key: "host.arch", - Value: &protobufs.AnyValue{Value: &protobufs.AnyValue_StringValue{StringValue: runtime.GOARCH}}, - }, - } - - if s.collectorVersion != "" { - attrs = append(attrs, &protobufs.KeyValue{ - Key: "collector.version", - Value: &protobufs.AnyValue{Value: &protobufs.AnyValue_StringValue{StringValue: s.collectorVersion}}, - }) - } - - return attrs -} - // setClientAvailableComponents discovers and sets available components on the given client. // It also stores the discovered collector version for use in agent descriptions. func (s *Supervisor) setClientAvailableComponents(ctx context.Context, client *opamp.Client) error { diff --git a/superv/supervisor/opamp_client_test.go b/superv/supervisor/opamp_client_test.go index cded6325..c1834511 100644 --- a/superv/supervisor/opamp_client_test.go +++ b/superv/supervisor/opamp_client_test.go @@ -29,41 +29,6 @@ import ( "go.uber.org/zap" ) -func TestSupervisor_NonIdentifyingAttributes_WithCollectorVersion(t *testing.T) { - s := &Supervisor{ - collectorVersion: "2.0.0-alpha.0", - } - - attrs := s.nonIdentifyingAttributes("test-host") - - attrMap := make(map[string]string) - for _, kv := range attrs { - attrMap[kv.GetKey()] = kv.GetValue().GetStringValue() - } - - require.Equal(t, "test-host", attrMap["host.name"]) - require.NotEmpty(t, attrMap["service.version"]) - require.NotEmpty(t, attrMap["os.type"]) - require.NotEmpty(t, attrMap["host.arch"]) - require.Equal(t, "2.0.0-alpha.0", attrMap["collector.version"]) -} - -func TestSupervisor_NonIdentifyingAttributes_WithoutCollectorVersion(t *testing.T) { - s := &Supervisor{} - - attrs := s.nonIdentifyingAttributes("test-host") - - attrMap := make(map[string]string) - for _, kv := range attrs { - attrMap[kv.GetKey()] = kv.GetValue().GetStringValue() - } - - require.Equal(t, "test-host", attrMap["host.name"]) - require.NotEmpty(t, attrMap["service.version"]) - _, hasCollectorVersion := attrMap["collector.version"] - require.False(t, hasCollectorVersion, "collector.version should not be present when empty") -} - func TestSupervisor_InitialComponentHealth_DefaultHealthyWithoutMonitor(t *testing.T) { supervisor := &Supervisor{} diff --git a/superv/supervisor/supervisor.go b/superv/supervisor/supervisor.go index bd7742be..d637bf81 100644 --- a/superv/supervisor/supervisor.go +++ b/superv/supervisor/supervisor.go @@ -68,7 +68,7 @@ type Supervisor struct { maxHeartbeatInterval time.Duration persistenceDir string instanceUID string - collectorVersion string + collectorVersion string // TODO: Remove separate collector.version field authManager *auth.Manager connectionSettingsManager *connection.SettingsManager configManager *configmanager.Manager diff --git a/superv/sysinfo/os_release.go b/superv/sysinfo/os_release.go new file mode 100644 index 00000000..7e131474 --- /dev/null +++ b/superv/sysinfo/os_release.go @@ -0,0 +1,124 @@ +// Copyright (C) 2026 Graylog, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the Server Side Public License, version 1, +// as published by MongoDB, Inc. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Server Side Public License for more details. +// +// You should have received a copy of the Server Side Public License +// along with this program. If not, see +// . +// +// SPDX-License-Identifier: SSPL-1.0 + +package sysinfo + +import ( + "bufio" + "errors" + "fmt" + "io" + "io/fs" + "os" + "strings" +) + +// OSRelease holds a subset of the fields defined in the os-release +// specification: https://www.freedesktop.org/software/systemd/man/latest/os-release.html +type OSRelease struct { + Name string // NAME + Version string // VERSION + ID string // ID + IDLike string // ID_LIKE (space-separated list) + VersionID string // VERSION_ID + PrettyName string // PRETTY_NAME +} + +// GetOSRelease reads the os-release information of the current host, +// preferring /etc/os-release over the /usr/lib/os-release fallback. +func GetOSRelease() (OSRelease, error) { + return getOSRelease("/etc/os-release", "/usr/lib/os-release") +} + +func getOSRelease(etcPath, usrLibPath string) (OSRelease, error) { + release, err := ReadOSRelease(etcPath) + if errors.Is(err, fs.ErrNotExist) { + return ReadOSRelease(usrLibPath) + } + return release, err +} + +// ReadOSRelease reads and parses the os-release file at the given path. +func ReadOSRelease(path string) (OSRelease, error) { + f, err := os.Open(path) + if err != nil { + return OSRelease{}, fmt.Errorf("opening os-release file: %w", err) + } + defer f.Close() + + return ParseOSRelease(f) +} + +// ParseOSRelease parses os-release formatted content. Comments, blank +// lines, malformed lines, and unknown fields are ignored. +func ParseOSRelease(r io.Reader) (OSRelease, error) { + var release OSRelease + + scanner := bufio.NewScanner(r) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + + key, value, found := strings.Cut(line, "=") + if !found { + continue + } + value = trimQuotes(value) + + switch key { + case "NAME": + release.Name = value + case "VERSION": + release.Version = value + case "ID": + release.ID = value + case "ID_LIKE": + release.IDLike = value + case "VERSION_ID": + release.VersionID = value + case "PRETTY_NAME": + release.PrettyName = value + } + } + if err := scanner.Err(); err != nil { + return OSRelease{}, fmt.Errorf("reading os-release content: %w", err) + } + + return release, nil +} + +// unescaper reverses the backslash escapes that shell-style double quoting +// requires for "$", quotes, backslashes, and backticks. Backslashes before +// any other character are retained, matching shell semantics. +var unescaper = strings.NewReplacer(`\"`, `"`, `\\`, `\`, `\$`, `$`, "\\`", "`") + +// trimQuotes removes matching surrounding double or single quotes. Escape +// sequences are only interpreted inside double quotes; single-quoted values +// are taken literally. Trailing content after a closing quote is kept +// verbatim (such input is invalid per the os-release spec). +func trimQuotes(s string) string { + if len(s) >= 2 && (s[0] == '"' || s[0] == '\'') && s[len(s)-1] == s[0] { + inner := s[1 : len(s)-1] + if s[0] == '"' { + return unescaper.Replace(inner) + } + return inner + } + return s +} diff --git a/superv/sysinfo/os_release_test.go b/superv/sysinfo/os_release_test.go new file mode 100644 index 00000000..e92a6ab5 --- /dev/null +++ b/superv/sysinfo/os_release_test.go @@ -0,0 +1,426 @@ +// Copyright (C) 2026 Graylog, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the Server Side Public License, version 1, +// as published by MongoDB, Inc. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Server Side Public License for more details. +// +// You should have received a copy of the Server Side Public License +// along with this program. If not, see +// . +// +// SPDX-License-Identifier: SSPL-1.0 + +package sysinfo + +import ( + "os" + "path" + "path/filepath" + "strings" + "testing" + + "github.com/Graylog2/collector/superv/internal/testfixtures" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestParseOSRelease(t *testing.T) { + tests := []struct { + name string + input string + want OSRelease + }{ + { + name: "unquoted values", + input: strings.Join([]string{ + `ID=ubuntu`, + `ID_LIKE=debian`, + `VERSION_ID=24.04`, + }, "\n"), + want: OSRelease{ID: "ubuntu", IDLike: "debian", VersionID: "24.04"}, + }, + { + name: "quoted values", + input: strings.Join([]string{ + `NAME="Red Hat Enterprise Linux"`, + `VERSION="9.4 (Plow)"`, + `ID="rhel"`, + }, "\n"), + want: OSRelease{Name: "Red Hat Enterprise Linux", Version: "9.4 (Plow)", ID: "rhel"}, + }, + { + name: "single-quoted values", + input: `NAME='Test Linux'`, + want: OSRelease{Name: "Test Linux"}, + }, + { + name: "comments and blank lines are skipped", + input: strings.Join([]string{ + `# VERSION="20260802"`, + ``, + `ID="opensuse-tumbleweed"`, + }, "\n"), + want: OSRelease{ID: "opensuse-tumbleweed"}, + }, + { + name: "value containing equals sign", + input: `PRETTY_NAME="Test a=b"`, + want: OSRelease{PrettyName: "Test a=b"}, + }, + { + name: "unknown fields are ignored", + input: "HOME_URL=\"https://example.com/\"\nID=test", + want: OSRelease{ID: "test"}, + }, + { + name: "malformed lines are skipped", + input: "GARBAGE\nID=test", + want: OSRelease{ID: "test"}, + }, + { + name: "surrounding whitespace is trimmed", + input: " ID=test \n", + want: OSRelease{ID: "test"}, + }, + { + name: "empty input", + input: "", + want: OSRelease{}, + }, + { + name: "escaped quotes in double-quoted value", + input: `NAME="Foo \"Bar\""`, + want: OSRelease{Name: `Foo "Bar"`}, + }, + { + name: "escaped backslash and dollar in double-quoted value", + input: `NAME="a \\ b \$c"`, + want: OSRelease{Name: `a \ b $c`}, + }, + { + name: "escaped backtick in double-quoted value", + input: "NAME=\"run \\`cmd\\`\"", + want: OSRelease{Name: "run `cmd`"}, + }, + { + name: "backslash before other characters is retained", + input: `NAME="a\nb"`, + want: OSRelease{Name: `a\nb`}, + }, + { + name: "escapes are literal in single-quoted values", + input: `NAME='a \"b\"'`, + want: OSRelease{Name: `a \"b\"`}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseOSRelease(strings.NewReader(tt.input)) + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestParseOSReleaseFromFixture(t *testing.T) { + tests := []struct { + file string + want OSRelease + }{ + { + file: "os-release-almalinux-8.txt", + want: OSRelease{ + Name: "AlmaLinux", + Version: "8.10 (Cerulean Leopard)", + ID: "almalinux", + IDLike: "rhel centos fedora", + VersionID: "8.10", + PrettyName: "AlmaLinux 8.10 (Cerulean Leopard)", + }, + }, + { + file: "os-release-almalinux-9.txt", + want: OSRelease{ + Name: "AlmaLinux", + Version: "9.7 (Moss Jungle Cat)", + ID: "almalinux", + IDLike: "rhel centos fedora", + VersionID: "9.7", + PrettyName: "AlmaLinux 9.7 (Moss Jungle Cat)", + }, + }, + { + file: "os-release-almalinux-10.txt", + want: OSRelease{ + Name: "AlmaLinux", + Version: "10.2 (Lavender Lion)", + ID: "almalinux", + IDLike: "rhel centos fedora", + VersionID: "10.2", + PrettyName: "AlmaLinux 10.2 (Lavender Lion)", + }, + }, + { + file: "os-release-alpine-3.txt", + want: OSRelease{ + Name: "Alpine Linux", + ID: "alpine", + VersionID: "3.23.3", + PrettyName: "Alpine Linux v3.23", + }, + }, + { + file: "os-release-amazonlinux-2.txt", + want: OSRelease{ + Name: "Amazon Linux", + Version: "2", + ID: "amzn", + IDLike: "centos rhel fedora", + VersionID: "2", + PrettyName: "Amazon Linux 2", + }, + }, + { + file: "os-release-amazonlinux-2023.txt", + want: OSRelease{ + Name: "Amazon Linux", + Version: "2023", + ID: "amzn", + IDLike: "fedora", + VersionID: "2023", + PrettyName: "Amazon Linux 2023.12.20260724", + }, + }, + { + file: "os-release-arch-2026-08.txt", + want: OSRelease{ + Name: "Arch Linux", + ID: "arch", + VersionID: "20260726.0.562117", + PrettyName: "Arch Linux", + }, + }, + { + file: "os-release-debian-12.txt", + want: OSRelease{ + Name: "Debian GNU/Linux", + Version: "12 (bookworm)", + ID: "debian", + VersionID: "12", + PrettyName: "Debian GNU/Linux 12 (bookworm)", + }, + }, + { + file: "os-release-debian-13.txt", + want: OSRelease{ + Name: "Debian GNU/Linux", + Version: "13 (trixie)", + ID: "debian", + VersionID: "13", + PrettyName: "Debian GNU/Linux 13 (trixie)", + }, + }, + { + file: "os-release-fedora-44.txt", + want: OSRelease{ + Name: "Fedora Linux", + Version: "44 (Server Edition)", + ID: "fedora", + VersionID: "44", + PrettyName: "Fedora Linux 44 (Server Edition)", + }, + }, + { + file: "os-release-fedora-container-44.txt", + want: OSRelease{ + Name: "Fedora Linux", + Version: "44 (Container Image)", + ID: "fedora", + VersionID: "44", + PrettyName: "Fedora Linux 44 (Container Image)", + }, + }, + { + file: "os-release-opensuse-tumbleweed-2026-08.txt", + want: OSRelease{ + Name: "openSUSE Tumbleweed", + ID: "opensuse-tumbleweed", + IDLike: "opensuse suse", + VersionID: "20260802", + PrettyName: "openSUSE Tumbleweed", + }, + }, + { + file: "os-release-oraclelinux-8.txt", + want: OSRelease{ + Name: "Oracle Linux Server", + Version: "8.10", + ID: "ol", + IDLike: "fedora", + VersionID: "8.10", + PrettyName: "Oracle Linux Server 8.10", + }, + }, + { + file: "os-release-oraclelinux-9.txt", + want: OSRelease{ + Name: "Oracle Linux Server", + Version: "9.8", + ID: "ol", + IDLike: "fedora", + VersionID: "9.8", + PrettyName: "Oracle Linux Server 9.8", + }, + }, + { + file: "os-release-oraclelinux-10.txt", + want: OSRelease{ + Name: "Oracle Linux Server", + Version: "10.2", + ID: "ol", + IDLike: "fedora", + VersionID: "10.2", + PrettyName: "Oracle Linux Server 10.2", + }, + }, + { + file: "os-release-redhat-8.txt", + want: OSRelease{ + Name: "Red Hat Enterprise Linux", + Version: "8.5 (Ootpa)", + ID: "rhel", + IDLike: "fedora", + VersionID: "8.5", + PrettyName: "Red Hat Enterprise Linux 8.5 (Ootpa)", + }, + }, + { + file: "os-release-redhat-9.txt", + want: OSRelease{ + Name: "Red Hat Enterprise Linux", + Version: "9.4 (Plow)", + ID: "rhel", + IDLike: "fedora", + VersionID: "9.4", + PrettyName: "Red Hat Enterprise Linux 9.4 (Plow)", + }, + }, + { + file: "os-release-rockylinux-8.txt", + want: OSRelease{ + Name: "Rocky Linux", + Version: "8.9 (Green Obsidian)", + ID: "rocky", + IDLike: "rhel centos fedora", + VersionID: "8.9", + PrettyName: "Rocky Linux 8.9 (Green Obsidian)", + }, + }, + { + file: "os-release-rockylinux-9.txt", + want: OSRelease{ + Name: "Rocky Linux", + Version: "9.3 (Blue Onyx)", + ID: "rocky", + IDLike: "rhel centos fedora", + VersionID: "9.3", + PrettyName: "Rocky Linux 9.3 (Blue Onyx)", + }, + }, + { + file: "os-release-ubuntu-24.04.txt", + want: OSRelease{ + Name: "Ubuntu", + Version: "24.04.1 LTS (Noble Numbat)", + ID: "ubuntu", + IDLike: "debian", + VersionID: "24.04", + PrettyName: "Ubuntu 24.04.1 LTS", + }, + }, + { + file: "os-release-ubuntu-26.04.txt", + want: OSRelease{ + Name: "Ubuntu", + Version: "26.04 LTS (Resolute Raccoon)", + ID: "ubuntu", + IDLike: "debian", + VersionID: "26.04", + PrettyName: "Ubuntu 26.04 LTS", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.file, func(t *testing.T) { + // Using path.Join to avoid backslashes on windows. The embed.FS always uses slashes. + file, err := testfixtures.OsReleaseFS.Open(path.Join("testdata", "os-release", tt.file)) + require.NoError(t, err) + got, err := ParseOSRelease(file) + require.NoError(t, err) + assert.Equal(t, tt.want, got) + require.NoError(t, file.Close()) + }) + } + + t.Run("all testdata files are covered", func(t *testing.T) { + // Using path.Join to avoid backslashes on windows. The embed.FS always uses slashes. + files, err := testfixtures.OsReleaseFS.ReadDir(path.Join("testdata", "os-release")) + require.NoError(t, err) + require.NotEmpty(t, files) + + covered := make(map[string]bool, len(tests)) + for _, tt := range tests { + covered[tt.file] = true + } + for _, file := range files { + assert.True(t, covered[file.Name()], "missing test case for %s", file.Name()) + } + }) + + t.Run("missing file returns error", func(t *testing.T) { + _, err := ReadOSRelease(filepath.Join(t.TempDir(), "does-not-exist")) + require.Error(t, err) + }) +} + +func TestGetOSRelease(t *testing.T) { + writeFile := func(t *testing.T, content string) string { + t.Helper() + path := filepath.Join(t.TempDir(), "os-release") + require.NoError(t, os.WriteFile(path, []byte(content), 0o600)) + return path + } + missing := func(t *testing.T) string { + t.Helper() + return filepath.Join(t.TempDir(), "does-not-exist") + } + + t.Run("prefers the etc path", func(t *testing.T) { + etcPath := writeFile(t, "ID=etc\n") + usrLibPath := writeFile(t, "ID=usrlib\n") + + release, err := getOSRelease(etcPath, usrLibPath) + require.NoError(t, err) + assert.Equal(t, "etc", release.ID) + }) + + t.Run("falls back to the usr lib path when the etc path is missing", func(t *testing.T) { + usrLibPath := writeFile(t, "ID=usrlib\n") + + release, err := getOSRelease(missing(t), usrLibPath) + require.NoError(t, err) + assert.Equal(t, "usrlib", release.ID) + }) + + t.Run("returns an error when both paths are missing", func(t *testing.T) { + _, err := getOSRelease(missing(t), missing(t)) + require.Error(t, err) + }) +} diff --git a/superv/sysinfo/platform_info.go b/superv/sysinfo/platform_info.go new file mode 100644 index 00000000..21e7dcd6 --- /dev/null +++ b/superv/sysinfo/platform_info.go @@ -0,0 +1,49 @@ +// Copyright (C) 2026 Graylog, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the Server Side Public License, version 1, +// as published by MongoDB, Inc. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Server Side Public License for more details. +// +// You should have received a copy of the Server Side Public License +// along with this program. If not, see +// . +// +// SPDX-License-Identifier: SSPL-1.0 + +package sysinfo + +import ( + "fmt" + "runtime" + + "github.com/shirou/gopsutil/v4/host" +) + +type PlatformInfo struct { + OS string + Name string + Family string + Version string +} + +// GetPlatformInfo returns host platform data using the narrow +// host.PlatformInformation probe. host.Info would fail if any of its +// unrelated probes (host ID, boot time, uptime, ...) fails, and would +// query the host ID on a code path that only needs non-identifying data. +func GetPlatformInfo() (PlatformInfo, error) { + platform, family, version, err := host.PlatformInformation() + if err != nil { + return PlatformInfo{}, fmt.Errorf("couldn't retrieve platform information: %w", err) + } + return PlatformInfo{ + OS: runtime.GOOS, + Name: platform, + Family: family, + Version: version, + }, nil +} diff --git a/superv/sysinfo/platform_info_test.go b/superv/sysinfo/platform_info_test.go new file mode 100644 index 00000000..550777c0 --- /dev/null +++ b/superv/sysinfo/platform_info_test.go @@ -0,0 +1,33 @@ +// Copyright (C) 2026 Graylog, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the Server Side Public License, version 1, +// as published by MongoDB, Inc. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// Server Side Public License for more details. +// +// You should have received a copy of the Server Side Public License +// along with this program. If not, see +// . +// +// SPDX-License-Identifier: SSPL-1.0 + +package sysinfo + +import ( + "runtime" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGetPlatformInfo(t *testing.T) { + info, err := GetPlatformInfo() + require.NoError(t, err) + require.Equal(t, runtime.GOOS, info.OS) + require.NotEmpty(t, info.Name) + t.Logf("platform info: %+v", info) +}