diff --git a/cmd/status.go b/cmd/status.go index 55a47a3..6932a7c 100644 --- a/cmd/status.go +++ b/cmd/status.go @@ -102,6 +102,11 @@ var statusCmd = &cobra.Command{ logrus.Fatal(err) } fmt.Printf("Status of the machine %s\n", status.Hostname) + needToReboot := "no" + if status.NeedToReboot { + needToReboot = "yes" + } + fmt.Printf(" Need to reboot: %s\n", needToReboot) for _, r := range status.RepositoryStatus.Remotes { fmt.Printf(" Remote %s fetched %s\n", r.Url, humanize.Time(r.FetchedAt), diff --git a/internal/manager/manager.go b/internal/manager/manager.go index 713a8f7..b48974a 100644 --- a/internal/manager/manager.go +++ b/internal/manager/manager.go @@ -22,6 +22,7 @@ type State struct { IsRunning bool `json:"is_running"` Deployment deployment.Deployment `json:"deployment"` Hostname string `json:"hostname"` + NeedToReboot bool `json:"need_to_reboot"` } type Manager struct { @@ -44,6 +45,7 @@ type Manager struct { // for a first iteration: this needs to be removed isRunning bool needToBeRestarted bool + needToReboot bool cominServiceRestartFunc func() error evalFunc generation.EvalFunc @@ -107,6 +109,7 @@ func (m Manager) toState() State { IsRunning: m.isRunning, Deployment: m.deployment, Hostname: m.hostname, + NeedToReboot: m.needToReboot, } } @@ -153,6 +156,8 @@ func (m Manager) onDeployment(ctx context.Context, deploymentResult deployment.D if getsEvicted && evicted.ProfilePath != "" { profile.RemoveProfilePath(evicted.ProfilePath) } + m.needToReboot = utils.NeedToReboot() + m.prometheus.SetHostInfo(m.needToReboot) return m } @@ -211,6 +216,9 @@ func (m Manager) Run() { logrus.Infof(" machineId = %s", m.machineId) logrus.Infof(" repositoryPath = %s", m.repositoryPath) + m.needToReboot = utils.NeedToReboot() + m.prometheus.SetHostInfo(m.needToReboot) + for { select { case <-m.stateRequestCh: diff --git a/internal/prometheus/prometheus.go b/internal/prometheus/prometheus.go index d4f2297..a7a6305 100644 --- a/internal/prometheus/prometheus.go +++ b/internal/prometheus/prometheus.go @@ -12,6 +12,7 @@ type Prometheus struct { buildInfo *prometheus.GaugeVec deploymentInfo *prometheus.GaugeVec fetchCounter *prometheus.CounterVec + hostInfo *prometheus.GaugeVec } func New() Prometheus { @@ -19,7 +20,7 @@ func New() Prometheus { buildInfo := prometheus.NewGaugeVec(prometheus.GaugeOpts{ Name: "comin_build_info", Help: "Build info for comin.", - }, []string{"version"}) + }, []string{"version"}) deploymentInfo := prometheus.NewGaugeVec(prometheus.GaugeOpts{ Name: "comin_deployment_info", Help: "Info of the last deployment.", @@ -28,14 +29,20 @@ func New() Prometheus { Name: "comin_fetch_count", Help: "Number of fetches per status", }, []string{"remote_name", "status"}) + hostInfo := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "comin_host_info", + Help: "Info of the host.", + }, []string{"need_to_reboot"}) promReg.MustRegister(buildInfo) promReg.MustRegister(deploymentInfo) promReg.MustRegister(fetchCounter) + promReg.MustRegister(hostInfo) return Prometheus{ promRegistry: promReg, buildInfo: buildInfo, deploymentInfo: deploymentInfo, fetchCounter: fetchCounter, + hostInfo: hostInfo, } } @@ -60,3 +67,14 @@ func (m Prometheus) SetDeploymentInfo(commitId, status string) { m.deploymentInfo.Reset() m.deploymentInfo.With(prometheus.Labels{"commit_id": commitId, "status": status}).Set(1) } + +func (m Prometheus) SetHostInfo(needToReboot bool) { + m.hostInfo.Reset() + var value string + if needToReboot { + value = "1" + } else { + value = "0" + } + m.hostInfo.With(prometheus.Labels{"need_to_reboot": value}).Set(1) +} diff --git a/internal/utils/reboot.go b/internal/utils/reboot.go new file mode 100644 index 0000000..1727ec1 --- /dev/null +++ b/internal/utils/reboot.go @@ -0,0 +1,28 @@ +package utils + +import ( + "os" + + "github.com/sirupsen/logrus" +) + +// NeedToReboot return true when the current deployed kernel is not +// the booted kernel. Note we should implement something smarter such +// as described in +// https://discourse.nixos.org/t/nixos-needsreboot-determine-if-you-need-to-reboot-your-nixos-machine/40790 +func NeedToReboot() (reboot bool) { + current, err := os.Readlink("/run/current-system/kernel") + if err != nil { + logrus.Errorf("Failed to read the symlink /run/current-system/kernel: %s", err) + return + } + booted, err := os.Readlink("/run/booted-system/kernel") + if err != nil { + logrus.Errorf("Failed to read the symlink /run/booted-system/kernel: %s", err) + return + } + if current != booted { + reboot = true + } + return +}