Skip to content

[FEA]: Executed unit coverage for the interrupt implementations (NodeRestart, ServiceRestart, RestartAllServices) #678

Description

@rice-riley

Summary

Give the Go agent's three interrupt implementations executed unit coverage. Today NodeRestart.Run, ServiceRestart.RunPending, and RestartAllServices.run sit at 0–17% because each constructs its own command.Runner internally (command.NewRunner(command.WithChroot(config.RootMount()))), so the only way to execute them is with a real reboot or systemctl inside a real chroot. Nothing does, so nothing has.

Motivation

These are the highest-consequence paths in the agent and the most novel code in the rewrite. NodeRestart carries the .pending / boot-ID reboot confirmation that has no Python equivalent, and the SIGTERM-as-success path that #673 just changed. None of it has ever executed: unit tests cannot run the commands, and the only interrupt type the operator-agent e2e suite runs against a real agent is noop. The main chainsaw suite's ten type: reboot cases run against the agentless image and cover the operator's side only. #222 ships this code as the production agent.

Proposed direction

Inject the runner through execution.Config, which is already the injection point for the execution environment (WithRootMount, WithRunOutput). Add a factory rather than a runner, because steps need two (chroot for on_host: true, plain otherwise):

func WithRunnerFactory(f func(...command.RunnerOption) command.Runner) Option
func (c Config) NewRunner(opts ...command.RunnerOption) command.Runner // default: command.NewRunner(opts...)

The five call sites (step/shared.go ×2, service_restart.go, node_restart.go, restart_all_services.go) call config.NewRunner(...) instead. Production behaviour is unchanged. command.Runner is already the interface NewRunner returns, so make generate-mocks provides the fake once command is added to .mockery.yaml.

Specs, table-driven per the package convention:

  • ServiceRestart with [a, b]: exactly systemctl daemon-reload, systemctl restart a, systemctl restart b, in order, each with the chroot root and SkyhookDir as working directory; markCompleted(i) after each success and never after a failure; a failure on a stops before b; completed=[true,true,false] runs only b. The resume path a retry depends on has never executed.
  • RestartAllServices: service procps force-reload, same marker discipline.
  • NodeRestart, all four outcomes: Signal: SIGTERM → success; exit 0 → waitForNodeRestart (millisecond timeout, assert the "did not restart" error); non-zero → failed; runner error → error. Plus Signal: SIGKILL must not be success, pinning the race fix(agent): let the running step finish on SIGTERM so gracefulShutdown holds #673 removed.
  • runInterrupt with the real NodeRestart against a temp root and a fake proc/sys/kernel/random/boot_id: pending→complete promotion when the ID changes; stale pending rerun when it does not; and a pre-existing Python-style node_restart_0.complete being honoured without running anything — the Python→Go handoff as a test.
  • A stability spec for step.Fingerprint, which is the Go agent's on-disk flag filename and currently has no direct test.

The factory that records the options it was asked for also lets a step spec assert that on_host: false selected the non-chroot runner, closing that gap as a side effect.

Acceptance criteria

  • command.Runner is injectable through execution.Config; default behaviour unchanged.
  • internal/interrupts and the interrupt orchestration in internal/agent are above 85% with the specs above present.
  • make test and make lint in agent/go are clean.

Code of Conduct

  • I agree to follow Skyhook's Code of Conduct

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    component/operatorSkyhook operator (controller-manager)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions