fix: finish progressive Target detection
This commit is contained in:
+39
-13
@@ -155,32 +155,54 @@ func (a *Adapter) DiagnosticChecks(ctx context.Context, _ *profile.Profile) []ta
|
||||
}
|
||||
|
||||
func (a *Adapter) Availability(ctx context.Context) target.Availability {
|
||||
availability, _ := a.detectAvailability(ctx)
|
||||
availability, _, _ := a.detectAvailability(ctx)
|
||||
return availability
|
||||
}
|
||||
|
||||
func (a *Adapter) detectAvailability(ctx context.Context) (target.Availability, error) {
|
||||
// detectAvailability returns the effective dump used to prove capability so a
|
||||
// progressive Detect can classify state without running apt-config twice.
|
||||
func (a *Adapter) detectAvailability(ctx context.Context) (target.Availability, []byte, error) {
|
||||
marker, err := os.Stat(a.configuration.DebianVersionFile)
|
||||
if err != nil || !marker.Mode().IsRegular() {
|
||||
return target.Availability{Evidence: "Debian-family marker /etc/debian_version was not detected"}, nil
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return target.Availability{Evidence: "Debian-family marker /etc/debian_version was not detected"}, nil, nil
|
||||
}
|
||||
return target.Availability{Evidence: "Debian-family marker /etc/debian_version could not be inspected"}, nil, fmt.Errorf("inspect Debian-family marker: %w", err)
|
||||
}
|
||||
if !marker.Mode().IsRegular() {
|
||||
return target.Availability{Evidence: "Debian-family marker /etc/debian_version was not detected"}, nil, nil
|
||||
}
|
||||
directory, err := os.Stat(a.configuration.ConfigDirectory)
|
||||
if err != nil || !directory.IsDir() {
|
||||
return target.Availability{Evidence: "APT configuration directory apt.conf.d was not detected"}, nil
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return target.Availability{Evidence: "APT configuration directory apt.conf.d was not detected"}, nil, nil
|
||||
}
|
||||
return target.Availability{Evidence: "APT configuration directory apt.conf.d could not be inspected"}, nil, fmt.Errorf("inspect APT configuration directory: %w", err)
|
||||
}
|
||||
if !directory.IsDir() {
|
||||
return target.Availability{Evidence: "APT configuration directory apt.conf.d was not detected"}, nil, nil
|
||||
}
|
||||
command, err := a.runner.LookPath("apt-config")
|
||||
if err != nil {
|
||||
return target.Availability{Evidence: "Debian APT tool apt-config was not detected"}, nil
|
||||
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, exec.ErrNotFound) {
|
||||
return target.Availability{Evidence: "Debian APT tool apt-config was not detected"}, nil, nil
|
||||
}
|
||||
return target.Availability{Evidence: "Debian APT tool apt-config could not be inspected"}, nil, fmt.Errorf("locate apt-config: %w", err)
|
||||
}
|
||||
if _, err := a.runner.Output(ctx, command, "dump"); err != nil {
|
||||
return target.Availability{Evidence: "apt-config could not inspect effective APT configuration"}, fmt.Errorf("inspect effective APT configuration: %w", err)
|
||||
effective, err := a.runner.Output(ctx, command, "dump")
|
||||
if err != nil {
|
||||
return target.Availability{Evidence: "apt-config could not inspect effective APT configuration"}, nil, fmt.Errorf("inspect effective APT configuration: %w", err)
|
||||
}
|
||||
return target.Availability{Available: true, Evidence: "Debian marker, apt-config, and apt.conf.d configuration capability detected"}, nil
|
||||
return target.Availability{Available: true, Evidence: "Debian marker, apt-config, and apt.conf.d configuration capability detected"}, effective, nil
|
||||
}
|
||||
|
||||
func (a *Adapter) Detect(ctx context.Context, active *profile.Profile) target.Detection {
|
||||
availability, availabilityErr := a.detectAvailability(ctx)
|
||||
inspection, inspectionErr := a.inspect(ctx, active)
|
||||
availability, effective, availabilityErr := a.detectAvailability(ctx)
|
||||
if !availability.Available && availabilityErr == nil {
|
||||
return target.Detection{Availability: availability}
|
||||
}
|
||||
overlay, overlayErr := a.files.ReadFile(a.configuration.OverlayFile)
|
||||
inspection, inspectionErr := a.inspectObserved(active, overlay, overlayErr, effective, availabilityErr)
|
||||
return target.Detection{Availability: availability, Inspection: inspection, Err: errors.Join(availabilityErr, inspectionErr)}
|
||||
}
|
||||
|
||||
@@ -193,11 +215,15 @@ func (a *Adapter) Inspect(ctx context.Context, active *profile.Profile) target.I
|
||||
|
||||
func (a *Adapter) inspect(ctx context.Context, active *profile.Profile) (target.Inspection, error) {
|
||||
overlay, overlayErr := a.files.ReadFile(a.configuration.OverlayFile)
|
||||
effective, dumpErr := a.dump(ctx)
|
||||
return a.inspectObserved(active, overlay, overlayErr, effective, dumpErr)
|
||||
}
|
||||
|
||||
func (a *Adapter) inspectObserved(active *profile.Profile, overlay []byte, overlayErr error, effective []byte, dumpErr error) (target.Inspection, error) {
|
||||
managed := overlayErr == nil && isOwnedOverlay(overlay)
|
||||
if overlayErr != nil && !errors.Is(overlayErr, fs.ErrNotExist) {
|
||||
return target.Inspection{State: target.Drifted, Evidence: "managed APT overlay cannot be read"}, fmt.Errorf("read managed APT overlay: %w", overlayErr)
|
||||
}
|
||||
effective, dumpErr := a.dump(ctx)
|
||||
if dumpErr != nil {
|
||||
if managed {
|
||||
return target.Inspection{State: target.Drifted, Evidence: "managed APT overlay exists but effective configuration cannot be inspected"}, dumpErr
|
||||
|
||||
@@ -46,6 +46,19 @@ func TestAvailabilityRequiresDebianMarkerAPTToolAndConfigurationDirectory(t *tes
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectClassifiesInspectionFailureAndUsesOneEffectiveConfigurationProbe(t *testing.T) {
|
||||
a, runner := newAdapter(t, nil)
|
||||
runner.outputError = true
|
||||
|
||||
detection := a.Detect(context.Background(), compatibleProfile())
|
||||
if detection.Err == nil || detection.Inspection.State != target.Disabled {
|
||||
t.Fatalf("detection = %#v, want failed Disabled inspection", detection)
|
||||
}
|
||||
if runner.outputs != 1 {
|
||||
t.Fatalf("Detect issued %d apt-config dumps, want one", runner.outputs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiagnosticChecksCoverCommandSchemaAndAuthorityWithoutMutation(t *testing.T) {
|
||||
a, _ := newAdapter(t, nil)
|
||||
checks := a.DiagnosticChecks(context.Background(), compatibleProfile())
|
||||
@@ -442,6 +455,7 @@ func newFailingAdapter(t *testing.T, files *failingFS) (*apt.Adapter, *fakeRunne
|
||||
type fakeRunner struct {
|
||||
available, outputError bool
|
||||
overlay, external, override, failDumpAfterWrite string
|
||||
outputs int
|
||||
}
|
||||
|
||||
func (r *fakeRunner) LookPath(string) (string, error) {
|
||||
@@ -451,6 +465,7 @@ func (r *fakeRunner) LookPath(string) (string, error) {
|
||||
return "/usr/bin/apt-config", nil
|
||||
}
|
||||
func (r *fakeRunner) Output(context.Context, string, ...string) ([]byte, error) {
|
||||
r.outputs++
|
||||
if r.outputError {
|
||||
return nil, errors.New("apt-config dump failed")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user