diff --git a/pkg/arc/consts.go b/pkg/arc/consts.go index 0ad71bd3..d2766e11 100644 --- a/pkg/arc/consts.go +++ b/pkg/arc/consts.go @@ -19,7 +19,15 @@ var ( } // Arc services that may be present (not all are guaranteed to exist on every installation) - arcServices = []string{"himdsd", "gcarcservice", "extd"} + arcServices = []string{"himdsd", "gcarcservice", "gcad", "extd"} + + // Arc service groups required for installation verification. At least one + // service in each group must be active. + arcRequiredServiceGroups = [][]string{ + {"himdsd"}, + {"gcarcservice", "gcad"}, + {"extd"}, + } // Arc agent binary paths arcBinaryPaths = []string{ @@ -42,7 +50,9 @@ var ( arcServiceFiles = []string{ "/lib/systemd/system/himdsd.service", "/lib/systemd/system/gcarcservice.service", + "/lib/systemd/system/gcad.service", "/etc/systemd/system/himdsd.service", "/etc/systemd/system/gcarcservice.service", + "/etc/systemd/system/gcad.service", } ) diff --git a/pkg/arc/helpers.go b/pkg/arc/helpers.go index 839900d4..5440d20f 100644 --- a/pkg/arc/helpers.go +++ b/pkg/arc/helpers.go @@ -28,12 +28,31 @@ func isArcServicesRunning(ctx context.Context, logger *slog.Logger) bool { if !isArcAgentInstalled() { return false } - for _, service := range arcServices { - if !utilexec.IsServiceActive(ctx, logger, service) { + if !areArcServiceGroupsActive(ctx, logger, arcRequiredServiceGroups, utilexec.IsServiceActive) { + return false + } + return utilexec.RunCmdAt(ctx, logger, slog.LevelDebug, utilexec.Pgrep(), "-f", "azcmagent") == nil +} + +func areArcServiceGroupsActive( + ctx context.Context, + logger *slog.Logger, + serviceGroups [][]string, + isServiceActive func(context.Context, *slog.Logger, string) bool, +) bool { + for _, serviceGroup := range serviceGroups { + serviceGroupActive := false + for _, service := range serviceGroup { + if isServiceActive(ctx, logger, service) { + serviceGroupActive = true + break + } + } + if !serviceGroupActive { return false } } - return utilexec.RunCmdAt(ctx, logger, slog.LevelDebug, utilexec.Pgrep(), "-f", "azcmagent") == nil + return true } func ptrDeref[T any](p *T) T { diff --git a/pkg/arc/helpers_test.go b/pkg/arc/helpers_test.go new file mode 100644 index 00000000..82d49a23 --- /dev/null +++ b/pkg/arc/helpers_test.go @@ -0,0 +1,87 @@ +package arc + +import ( + "context" + "io" + "log/slog" + "slices" + "testing" +) + +func TestAreArcServiceGroupsActive(t *testing.T) { + t.Parallel() + + ctx := context.Background() + logger := slog.New(slog.NewTextHandler(io.Discard, nil)) + + tests := []struct { + name string + activeServices map[string]bool + want bool + }{ + { + name: "legacy service active", + activeServices: map[string]bool{ + "himdsd": true, + "gcarcservice": true, + "extd": true, + }, + want: true, + }, + { + name: "renamed service active", + activeServices: map[string]bool{ + "himdsd": true, + "gcad": true, + "extd": true, + }, + want: true, + }, + { + name: "neither service active", + activeServices: map[string]bool{ + "himdsd": true, + "extd": true, + }, + want: false, + }, + { + name: "required service inactive", + activeServices: map[string]bool{ + "gcad": true, + "extd": true, + }, + want: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + got := areArcServiceGroupsActive(ctx, logger, arcRequiredServiceGroups, func(_ context.Context, _ *slog.Logger, service string) bool { + return tt.activeServices[service] + }) + if got != tt.want { + t.Fatalf("areArcServiceGroupsActive() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestArcServiceConstantsIncludeRenamedService(t *testing.T) { + t.Parallel() + + const renamedService = "gcad" + + if !slices.Contains(arcServices, renamedService) { + t.Fatalf("arcServices must include gcad for azcmagent v1.62+ cleanup") + } + if !slices.Contains(arcServiceFiles, "/lib/systemd/system/"+renamedService+".service") { + t.Fatalf("arcServiceFiles must include /lib/systemd/system/gcad.service") + } + if !slices.Contains(arcServiceFiles, "/etc/systemd/system/"+renamedService+".service") { + t.Fatalf("arcServiceFiles must include /etc/systemd/system/gcad.service") + } +}