fix: use nixos-version --json for configuration revision
- Use `nixos-version --json` command instead of reading files directly - Add nixpkgs_rev and nixos_version labels to nixos_flake_info metric - Show "unknown" for current_rev when system.configurationRevision not set - Document configurationRevision setup in README Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -14,7 +13,12 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const configRevisionPath = "/run/current-system/configuration-revision"
|
||||
// nixosVersionInfo holds the parsed output of nixos-version --json
|
||||
type nixosVersionInfo struct {
|
||||
ConfigurationRevision string `json:"configurationRevision"`
|
||||
NixosVersion string `json:"nixosVersion"`
|
||||
NixpkgsRevision string `json:"nixpkgsRevision"`
|
||||
}
|
||||
|
||||
type FlakeCollector struct {
|
||||
flakeURL string
|
||||
@@ -74,7 +78,7 @@ func NewFlakeCollector(flakeURL string, checkInterval time.Duration) *FlakeColle
|
||||
flakeInfo: prometheus.NewDesc(
|
||||
"nixos_flake_info",
|
||||
"Info gauge with current and remote flake revisions",
|
||||
[]string{"current_rev", "remote_rev"}, nil,
|
||||
[]string{"current_rev", "remote_rev", "nixpkgs_rev", "nixos_version"}, nil,
|
||||
),
|
||||
revisionBehind: prometheus.NewDesc(
|
||||
"nixos_flake_revision_behind",
|
||||
@@ -164,22 +168,35 @@ func (c *FlakeCollector) collectInputMetrics(ch chan<- prometheus.Metric, data *
|
||||
}
|
||||
|
||||
func (c *FlakeCollector) collectRevisionBehind(ch chan<- prometheus.Metric, data *flakeMetadata) {
|
||||
currentRev, err := getCurrentSystemRevision()
|
||||
versionInfo, err := getNixosVersionInfo()
|
||||
if err != nil {
|
||||
slog.Error("Failed to get current system revision", "error", err)
|
||||
slog.Error("Failed to get NixOS version info", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
currentRev := versionInfo.ConfigurationRevision
|
||||
if currentRev == "" {
|
||||
currentRev = "unknown"
|
||||
} else if len(currentRev) > 7 {
|
||||
currentRev = currentRev[:7]
|
||||
}
|
||||
|
||||
remoteRev := data.Revision
|
||||
if len(remoteRev) > 7 {
|
||||
remoteRev = remoteRev[:7]
|
||||
}
|
||||
|
||||
nixpkgsRev := versionInfo.NixpkgsRevision
|
||||
if len(nixpkgsRev) > 7 {
|
||||
nixpkgsRev = nixpkgsRev[:7]
|
||||
}
|
||||
|
||||
// Emit flake info metric with revisions
|
||||
ch <- prometheus.MustNewConstMetric(c.flakeInfo, prometheus.GaugeValue, 1, currentRev, remoteRev)
|
||||
ch <- prometheus.MustNewConstMetric(c.flakeInfo, prometheus.GaugeValue, 1,
|
||||
currentRev, remoteRev, nixpkgsRev, versionInfo.NixosVersion)
|
||||
|
||||
behind := 0.0
|
||||
if currentRev != "" && data.Revision != "" {
|
||||
if currentRev != "unknown" && data.Revision != "" {
|
||||
if currentRev != remoteRev && !strings.HasPrefix(data.Revision, currentRev) {
|
||||
behind = 1.0
|
||||
}
|
||||
@@ -209,19 +226,23 @@ func fetchFlakeMetadata(flakeURL string) (*flakeMetadata, error) {
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func getCurrentSystemRevision() (string, error) {
|
||||
data, err := os.ReadFile(configRevisionPath)
|
||||
func getNixosVersionInfo() (*nixosVersionInfo, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, "nixos-version", "--json")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// configuration-revision doesn't exist; user hasn't set system.configurationRevision
|
||||
return "", nil
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
return nil, fmt.Errorf("nixos-version failed: %s", strings.TrimSpace(string(exitErr.Stderr)))
|
||||
}
|
||||
return "", err
|
||||
return nil, fmt.Errorf("nixos-version failed: %w", err)
|
||||
}
|
||||
|
||||
rev := strings.TrimSpace(string(data))
|
||||
if len(rev) > 7 {
|
||||
rev = rev[:7]
|
||||
var info nixosVersionInfo
|
||||
if err := json.Unmarshal(output, &info); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse nixos-version output: %w", err)
|
||||
}
|
||||
return rev, nil
|
||||
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user