Clean up failed Notarius extraction runs
This commit is contained in:
@@ -151,19 +151,25 @@ func (extractStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (re
|
|||||||
InputPath: inputPath, OutputRoot: outputRoot, WorkingDirectory: workingDirectory,
|
InputPath: inputPath, OutputRoot: outputRoot, WorkingDirectory: workingDirectory,
|
||||||
ReceiptPath: receiptPath, LogPath: logPath, Timeout: timeout, References: referenceBindings,
|
ReceiptPath: receiptPath, LogPath: logPath, Timeout: timeout, References: referenceBindings,
|
||||||
}
|
}
|
||||||
|
stageSucceeded := false
|
||||||
|
bundleMoved := false
|
||||||
|
defer func() {
|
||||||
|
if stageSucceeded {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if bundleMoved {
|
||||||
|
if cleanupErr := fileops.RemoveAllUnderRoot(filepath.Dir(durableBundle), durableBundle); cleanupErr != nil {
|
||||||
|
resultErr = errors.Join(resultErr, fmt.Errorf("extract: remove failed durable Notarius bundle: %w", cleanupErr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cleanupErr := fileops.RemoveAllUnderRoot(filepath.Dir(outputRoot), outputRoot); cleanupErr != nil {
|
||||||
|
resultErr = errors.Join(resultErr, fmt.Errorf("extract: remove failed Notarius output root: %w", cleanupErr))
|
||||||
|
}
|
||||||
|
}()
|
||||||
adapterResult, err := env.Notarius.Run(ctx, request)
|
adapterResult, err := env.Notarius.Run(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("extract: run notarius: %w", err)
|
return nil, fmt.Errorf("extract: run notarius: %w", err)
|
||||||
}
|
}
|
||||||
bundleInstalled := false
|
|
||||||
defer func() {
|
|
||||||
if bundleInstalled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cleanupErr := os.RemoveAll(outputRoot); cleanupErr != nil {
|
|
||||||
resultErr = errors.Join(resultErr, fmt.Errorf("extract: remove failed Notarius output root: %w", cleanupErr))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if strings.TrimSpace(adapterResult.BundleRoot) == "" || strings.TrimSpace(adapterResult.Index.Path) == "" {
|
if strings.TrimSpace(adapterResult.BundleRoot) == "" || strings.TrimSpace(adapterResult.Index.Path) == "" {
|
||||||
return nil, fmt.Errorf("extract: notarius result is missing bundle or index path")
|
return nil, fmt.Errorf("extract: notarius result is missing bundle or index path")
|
||||||
}
|
}
|
||||||
@@ -214,7 +220,7 @@ func (extractStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (re
|
|||||||
if err := os.Rename(adapterResult.BundleRoot, durableBundle); err != nil {
|
if err := os.Rename(adapterResult.BundleRoot, durableBundle); err != nil {
|
||||||
return nil, fmt.Errorf("extract: install Notarius bundle: %w", err)
|
return nil, fmt.Errorf("extract: install Notarius bundle: %w", err)
|
||||||
}
|
}
|
||||||
bundleInstalled = true
|
bundleMoved = true
|
||||||
if err := os.Remove(outputRoot); err != nil && !os.IsNotExist(err) {
|
if err := os.Remove(outputRoot); err != nil && !os.IsNotExist(err) {
|
||||||
return nil, fmt.Errorf("extract: remove empty Notarius output root: %w", err)
|
return nil, fmt.Errorf("extract: remove empty Notarius output root: %w", err)
|
||||||
}
|
}
|
||||||
@@ -312,11 +318,13 @@ func (extractStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (re
|
|||||||
"diagnostics": boundedDiagnosticMetadata(adapterResult.Diagnostics),
|
"diagnostics": boundedDiagnosticMetadata(adapterResult.Diagnostics),
|
||||||
"validation_summaries": boundedValidationMetadata(adapterResult.Receipt.ValidationSummaries),
|
"validation_summaries": boundedValidationMetadata(adapterResult.Receipt.ValidationSummaries),
|
||||||
}
|
}
|
||||||
return &StageResult{
|
result = &StageResult{
|
||||||
Outputs: outputs,
|
Outputs: outputs,
|
||||||
Logs: []string{receiptPath, logPath},
|
Logs: []string{receiptPath, logPath},
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
}, nil
|
}
|
||||||
|
stageSucceeded = true
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeNotariusBundle(root string) error {
|
func normalizeNotariusBundle(root string) error {
|
||||||
|
|||||||
@@ -492,11 +492,31 @@ func TestExtractStageValidatesSelectedLaneJSON(t *testing.T) {
|
|||||||
func TestExtractStageAdapterAndPromotionFailuresReturnNoOutputs(t *testing.T) {
|
func TestExtractStageAdapterAndPromotionFailuresReturnNoOutputs(t *testing.T) {
|
||||||
t.Run("adapter", func(t *testing.T) {
|
t.Run("adapter", func(t *testing.T) {
|
||||||
env, m, fake := setupExtractEnv(t)
|
env, m, fake := setupExtractEnv(t)
|
||||||
|
fixture := extractFixtureFromEnv(t, env, m)
|
||||||
|
receiptPath := artifacts.SessionRunNotariusReceiptPathForCampaign(fixture.workspace, fixture.campaign, fixture.sessionID, fixture.runID)
|
||||||
|
logPath := artifacts.SessionRunNotariusLogPathForCampaign(fixture.workspace, fixture.campaign, fixture.sessionID, fixture.runID)
|
||||||
|
for _, path := range []string{receiptPath, logPath} {
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||||
|
t.Fatalf("MkdirAll(diagnostic parent) error = %v", err)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(path, []byte("diagnostic"), 0o644); err != nil {
|
||||||
|
t.Fatalf("WriteFile(diagnostic) error = %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
fake.Err = errors.New("adapter failed")
|
fake.Err = errors.New("adapter failed")
|
||||||
result, err := (extractStage{}).Run(context.Background(), env, m)
|
result, err := (extractStage{}).Run(context.Background(), env, m)
|
||||||
if err == nil || !strings.Contains(err.Error(), "adapter failed") || result != nil {
|
if err == nil || !strings.Contains(err.Error(), "adapter failed") || result != nil {
|
||||||
t.Fatalf("Run() result = %#v error = %v", result, err)
|
t.Fatalf("Run() result = %#v error = %v", result, err)
|
||||||
}
|
}
|
||||||
|
outputRoot := artifacts.SessionRunNotariusOutputRootForCampaign(fixture.workspace, fixture.campaign, fixture.sessionID, fixture.runID)
|
||||||
|
if _, err := os.Stat(outputRoot); !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("failed adapter output root still exists: %v", err)
|
||||||
|
}
|
||||||
|
for _, path := range []string{receiptPath, logPath} {
|
||||||
|
if _, err := os.Stat(path); err != nil {
|
||||||
|
t.Fatalf("diagnostic %q was not retained: %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("promotion", func(t *testing.T) {
|
t.Run("promotion", func(t *testing.T) {
|
||||||
@@ -514,6 +534,27 @@ func TestExtractStageAdapterAndPromotionFailuresReturnNoOutputs(t *testing.T) {
|
|||||||
t.Fatalf("failed installation staging bundle still exists: %v", err)
|
t.Fatalf("failed installation staging bundle still exists: %v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("failure after rename", func(t *testing.T) {
|
||||||
|
env, m, _ := setupExtractEnv(t)
|
||||||
|
fixture := extractFixtureFromEnv(t, env, m)
|
||||||
|
outputRoot := artifacts.SessionRunNotariusOutputRootForCampaign(fixture.workspace, fixture.campaign, fixture.sessionID, fixture.runID)
|
||||||
|
if err := os.WriteFile(filepath.Join(outputRoot, "unexpected-sidecar"), []byte("unexpected"), 0o644); err != nil {
|
||||||
|
t.Fatalf("WriteFile(unexpected sidecar) error = %v", err)
|
||||||
|
}
|
||||||
|
destination := artifacts.SessionNotariusBundleDirForCampaign(fixture.workspace, fixture.campaign, fixture.sessionID, fixture.runID)
|
||||||
|
|
||||||
|
result, err := (extractStage{}).Run(context.Background(), env, m)
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "remove empty Notarius output root") || result != nil {
|
||||||
|
t.Fatalf("Run() result = %#v error = %v", result, err)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(destination); !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("failed stage durable bundle still exists: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(outputRoot); !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("failed stage output root still exists: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractionFingerprintIsIndependentOfOutputMapOrder(t *testing.T) {
|
func TestExtractionFingerprintIsIndependentOfOutputMapOrder(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user