diff --git a/internal/health/dependencies.go b/internal/health/dependencies.go index 883b8137..bc9319d8 100644 --- a/internal/health/dependencies.go +++ b/internal/health/dependencies.go @@ -2,8 +2,10 @@ package health import ( "context" + "fmt" "github.com/arm/topo/internal/runner" + "github.com/arm/topo/internal/ssh" "github.com/arm/topo/internal/version" ) @@ -83,55 +85,57 @@ var HostRequiredDependencies = []Dependency{ }, } -var TargetRequiredDependencies = []Dependency{ - { - Binary: "docker", - Label: "Container Engine", - SoftwareEnumID: Docker, - Checks: []Check{ - BinaryExists{}, - CommandSuccessful{ - Cmd: "docker info", - Fix: &Fix{Description: "Ensure current user can run docker commands"}, +func TargetRequiredDependencies(target ssh.Destination) []Dependency { + return []Dependency{ + { + Binary: "docker", + Label: "Container Engine", + SoftwareEnumID: Docker, + Checks: []Check{ + BinaryExists{}, + CommandSuccessful{ + Cmd: "docker info", + Fix: &Fix{Description: "Ensure current user can run docker commands"}, + }, }, }, - }, - { - Binary: "remoteproc-runtime", - Label: "Remoteproc Runtime", - SoftwarePrerequisites: []SoftwareDependency{Docker}, - HardwarePrerequisite: []HardwareCapability{Remoteproc}, - Checks: []Check{ - BinaryExists{ - Severity: SeverityWarning, - Fix: &Fix{ - Description: "Install the remoteproc runtime", - Command: "topo install remoteproc-runtime", + { + Binary: "remoteproc-runtime", + Label: "Remoteproc Runtime", + SoftwarePrerequisites: []SoftwareDependency{Docker}, + HardwarePrerequisite: []HardwareCapability{Remoteproc}, + Checks: []Check{ + BinaryExists{ + Severity: SeverityWarning, + Fix: &Fix{ + Description: "Install the remoteproc runtime", + Command: fmt.Sprintf("topo install remoteproc-runtime --target %s", target), + }, }, }, }, - }, - { - Binary: "containerd-shim-remoteproc-v1", - Label: "Remoteproc Shim", - SoftwarePrerequisites: []SoftwareDependency{Docker}, - HardwarePrerequisite: []HardwareCapability{Remoteproc}, - Checks: []Check{ - BinaryExists{ - Severity: SeverityWarning, - Fix: &Fix{ - Description: "Install the remoteproc runtime", - Command: "topo install remoteproc-runtime", + { + Binary: "containerd-shim-remoteproc-v1", + Label: "Remoteproc Shim", + SoftwarePrerequisites: []SoftwareDependency{Docker}, + HardwarePrerequisite: []HardwareCapability{Remoteproc}, + Checks: []Check{ + BinaryExists{ + Severity: SeverityWarning, + Fix: &Fix{ + Description: "Install the remoteproc runtime", + Command: fmt.Sprintf("topo install remoteproc-runtime --target %s", target), + }, }, }, }, - }, - { - Binary: "lscpu", - Label: "Hardware Info", - SoftwareEnumID: Lscpu, - Checks: []Check{BinaryExists{}}, - }, + { + Binary: "lscpu", + Label: "Hardware Info", + SoftwareEnumID: Lscpu, + Checks: []Check{BinaryExists{}}, + }, + } } type DependencyStatus struct { diff --git a/internal/health/dependencies_test.go b/internal/health/dependencies_test.go index 8b8f6255..75dd1677 100644 --- a/internal/health/dependencies_test.go +++ b/internal/health/dependencies_test.go @@ -8,6 +8,7 @@ import ( "github.com/arm/topo/internal/command" "github.com/arm/topo/internal/health" "github.com/arm/topo/internal/runner" + "github.com/arm/topo/internal/ssh" "github.com/stretchr/testify/assert" ) @@ -19,7 +20,7 @@ func TestDependencyFormat(t *testing.T) { }) t.Run("target dependencies are of the correct format", func(t *testing.T) { - for _, dep := range health.TargetRequiredDependencies { + for _, dep := range health.TargetRequiredDependencies(ssh.NewDestination("does-not-matter-for-this-test")) { assert.NoError(t, command.ValidateBinaryName(dep.Binary)) } }) @@ -29,7 +30,7 @@ func TestDependencyFormat(t *testing.T) { seenEnums := make(map[health.SoftwareDependency]string) t.Run("There are no duplicate SoftwareEnumID assignments", func(t *testing.T) { - for _, dep := range health.TargetRequiredDependencies { + for _, dep := range health.TargetRequiredDependencies(ssh.NewDestination("user@my-target")) { if dep.SoftwareEnumID != health.UnsetSoftwareDependency { if existingDep, exists := seenEnums[dep.SoftwareEnumID]; exists { t.Errorf("Duplicate SoftwareEnumID %d assigned to both %q and %q", dep.SoftwareEnumID, existingDep, dep.Binary) @@ -41,7 +42,7 @@ func TestDependencyFormat(t *testing.T) { }) t.Run("all SoftwarePrerequisites reference valid SoftwareEnumID", func(t *testing.T) { - for _, dep := range health.TargetRequiredDependencies { + for _, dep := range health.TargetRequiredDependencies(ssh.NewDestination("user@my-target")) { for _, prereq := range dep.SoftwarePrerequisites { assert.True(t, availableEnums[prereq], "%q has SoftwarePrerequisites %v which is not provided by any dependency's SoftwareEnumID", dep.Binary, prereq) } @@ -50,6 +51,23 @@ func TestDependencyFormat(t *testing.T) { }) } +func TestTargetRequiredDependencies(t *testing.T) { + t.Run("remoteproc install fix command includes the target", func(t *testing.T) { + deps := health.TargetRequiredDependencies(ssh.NewDestination("user@my-target")) + + dep, err := findDependencyByBinary(t, deps, "remoteproc-runtime") + assert.NoError(t, err) + wantBinaryExistsCheck := health.BinaryExists{ + Severity: health.SeverityWarning, + Fix: &health.Fix{ + Description: "Install the remoteproc runtime", + Command: "topo install remoteproc-runtime --target ssh://user@my-target", + }, + } + assert.Contains(t, dep.Checks, wantBinaryExistsCheck) + }) +} + func TestPerformChecks(t *testing.T) { t.Run("when no dependencies are found, statuses show not installed", func(t *testing.T) { fooDependency := health.Dependency{Binary: "foo", Label: "bar", Checks: []health.Check{health.BinaryExists{}}} @@ -311,3 +329,15 @@ func TestFilterByHardware(t *testing.T) { assert.Equal(t, want, got) }) } + +func findDependencyByBinary(t *testing.T, deps []health.Dependency, binary string) (health.Dependency, error) { + t.Helper() + + for _, dep := range deps { + if dep.Binary == binary { + return dep, nil + } + } + + return health.Dependency{}, errors.New("dependency not found") +} diff --git a/internal/health/health.go b/internal/health/health.go index fce79a0a..e9cf759c 100644 --- a/internal/health/health.go +++ b/internal/health/health.go @@ -96,7 +96,7 @@ func CheckTarget(ctx context.Context, dest ssh.Destination, acceptNewHostKeys bo r, connErr := prepareRunner(ctx, dest, acceptNewHostKeys) status := Status{Connection: ConnectionStatus{Destination: dest, Error: connErr}} if connErr == nil { - hs := ProbeHealthStatus(ctx, r) + hs := ProbeHealthStatus(ctx, r, dest) status.Dependencies = hs.Dependencies status.Hardware = hs.Hardware } diff --git a/internal/health/status.go b/internal/health/status.go index 5e25f9b4..0ebc07e5 100644 --- a/internal/health/status.go +++ b/internal/health/status.go @@ -5,6 +5,7 @@ import ( "github.com/arm/topo/internal/probe" "github.com/arm/topo/internal/runner" + "github.com/arm/topo/internal/ssh" ) type HardwareProfile struct { @@ -25,14 +26,14 @@ type HealthStatus struct { Hardware HardwareProfile } -func ProbeHealthStatus(ctx context.Context, r runner.Runner) HealthStatus { +func ProbeHealthStatus(ctx context.Context, r runner.Runner, target ssh.Destination) HealthStatus { var hs HealthStatus remoteProcessors, err := probe.Remoteproc(ctx, r) hs.Hardware.RemoteProcessors = remoteProcessors hs.Hardware.Err = err - dependenciesToCheck := FilterByHardware(TargetRequiredDependencies, hs.Hardware.Capabilities()) + dependenciesToCheck := FilterByHardware(TargetRequiredDependencies(target), hs.Hardware.Capabilities()) hs.Dependencies = PerformChecks(ctx, dependenciesToCheck, r) return hs