Skip to content

Commit b30219c

Browse files
committed
Address copilot review comments
Signed-off-by: Aravindhan Ayyanathan <aravindhan.a@est.tech>
1 parent 13ed78f commit b30219c

5 files changed

Lines changed: 60 additions & 45 deletions

File tree

e2e/testdata/fn-render/exec-without-permissions/.expected/diff.patch

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
diff --git a/Kptfile b/Kptfile
2-
index 0d98dbb..885a1d0 100644
2+
index 0d98dbb..a70d5e2 100644
33
--- a/Kptfile
44
+++ b/Kptfile
55
@@ -4,4 +4,18 @@ metadata:
@@ -20,5 +20,5 @@ index 0d98dbb..885a1d0 100644
2020
+ mutationSteps:
2121
+ - exec: sed -e 's/foo/bar/'
2222
+ executionError: must run with `--allow-exec` option to allow running function binaries
23-
+ exitCode: 0
23+
+ exitCode: 1
2424
+ errorSummary: 'sed -e ''s/foo/bar/'': must run with `--allow-exec` option to allow running function binaries'

internal/util/render/executor.go

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,14 @@ func buildRenderStatus(hctx *hydrationContext, hydErr error) *kptfilev1.RenderSt
246246
}
247247
if hydErr != nil {
248248
var errLines []string
249-
for _, s := range append(hctx.mutationSteps, hctx.validationSteps...) {
249+
for _, s := range hctx.mutationSteps {
250+
if s.ExecutionError != "" {
251+
errLines = append(errLines, fmt.Sprintf("%s: %s", stepName(s), s.ExecutionError))
252+
} else if s.ExitCode != 0 {
253+
errLines = append(errLines, fmt.Sprintf("%s: exit code %d", stepName(s), s.ExitCode))
254+
}
255+
}
256+
for _, s := range hctx.validationSteps {
250257
if s.ExecutionError != "" {
251258
errLines = append(errLines, fmt.Sprintf("%s: %s", stepName(s), s.ExecutionError))
252259
} else if s.ExitCode != 0 {
@@ -286,7 +293,7 @@ func setRenderStatus(fs filesys.FileSystem, pkgPath string, condition kptfilev1.
286293
kf.Status.Conditions = append(kf.Status.Conditions, condition)
287294
kf.Status.RenderStatus = renderStatus
288295
if err := kptfileutil.WriteKptfileToFS(fs, pkgPath, kf); err != nil {
289-
klog.V(3).Infof("failed to write render status condition to Kptfile at %s: %v", pkgPath, err)
296+
klog.V(3).Infof("failed to write render status to Kptfile at %s: %v", pkgPath, err)
290297
}
291298
}
292299

@@ -743,10 +750,10 @@ func (pn *pkgNode) runMutators(ctx context.Context, hctx *hydrationContext, inpu
743750
return input, nil
744751
}
745752

746-
mutators, err := fnChain(ctx, hctx, pn.pkg.UniquePath, pl.Mutators)
753+
mutators, failIdx, err := fnChain(ctx, hctx, pn.pkg.UniquePath, pl.Mutators)
747754
if err != nil {
748755
// Capture execution error (e.g. missing exec, image resolution failure)
749-
hctx.mutationSteps = append(hctx.mutationSteps, executionErrorStep(pl.Mutators, err))
756+
hctx.mutationSteps = append(hctx.mutationSteps, preExecFailureStep(pl.Mutators[failIdx], err))
750757
return nil, err
751758
}
752759

@@ -802,11 +809,11 @@ func (pn *pkgNode) runMutators(ctx context.Context, hctx *hydrationContext, inpu
802809
err = mutation.Execute()
803810
if err != nil {
804811
clearAnnotationsOnMutFailure(input)
805-
hctx.mutationSteps = append(hctx.mutationSteps, captureStepResult(pl.Mutators[i], hctx.fnResults, prevLen))
812+
hctx.mutationSteps = append(hctx.mutationSteps, captureStepResult(pl.Mutators[i], hctx.fnResults, prevLen, err))
806813
return input, err
807814
}
808815
hctx.executedFunctionCnt++
809-
hctx.mutationSteps = append(hctx.mutationSteps, captureStepResult(pl.Mutators[i], hctx.fnResults, prevLen))
816+
hctx.mutationSteps = append(hctx.mutationSteps, captureStepResult(pl.Mutators[i], hctx.fnResults, prevLen, nil))
810817

811818
if len(selectors) > 0 || len(exclusions) > 0 {
812819
// merge the output resources with input resources
@@ -852,23 +859,23 @@ func (pn *pkgNode) runValidators(ctx context.Context, hctx *hydrationContext, in
852859
displayResourceCount = true
853860
}
854861
if function.Exec != "" && !hctx.runnerOptions.AllowExec {
855-
hctx.validationSteps = append(hctx.validationSteps, executionErrorStep([]kptfilev1.Function{function}, errAllowedExecNotSpecified))
862+
hctx.validationSteps = append(hctx.validationSteps, preExecFailureStep(function, errAllowedExecNotSpecified))
856863
return errAllowedExecNotSpecified
857864
}
858865
opts := hctx.runnerOptions
859866
opts.SetPkgPathAnnotation = true
860867
opts.DisplayResourceCount = displayResourceCount
861868
validator, err = fnruntime.NewRunner(ctx, hctx.fileSystem, &function, pn.pkg.UniquePath, hctx.fnResults, opts, hctx.runtime)
862869
if err != nil {
863-
hctx.validationSteps = append(hctx.validationSteps, executionErrorStep([]kptfilev1.Function{function}, err))
870+
hctx.validationSteps = append(hctx.validationSteps, preExecFailureStep(function, err))
864871
return err
865872
}
866873
if _, err = validator.Filter(cloneResources(selectedResources)); err != nil {
867-
hctx.validationSteps = append(hctx.validationSteps, captureStepResult(function, hctx.fnResults, prevLen))
874+
hctx.validationSteps = append(hctx.validationSteps, captureStepResult(function, hctx.fnResults, prevLen, err))
868875
return err
869876
}
870877
hctx.executedFunctionCnt++
871-
hctx.validationSteps = append(hctx.validationSteps, captureStepResult(function, hctx.fnResults, prevLen))
878+
hctx.validationSteps = append(hctx.validationSteps, captureStepResult(function, hctx.fnResults, prevLen, nil))
872879
}
873880
return nil
874881
}
@@ -970,7 +977,7 @@ func pathRelToRoot(rootPkgPath, subPkgPath, resourcePath string) (relativePath s
970977
}
971978

972979
// fnChain returns a slice of function runners given a list of functions defined in pipeline.
973-
func fnChain(ctx context.Context, hctx *hydrationContext, pkgPath types.UniquePath, fns []kptfilev1.Function) ([]*fnruntime.FunctionRunner, error) {
980+
func fnChain(ctx context.Context, hctx *hydrationContext, pkgPath types.UniquePath, fns []kptfilev1.Function) ([]*fnruntime.FunctionRunner, int, error) {
974981
var runners []*fnruntime.FunctionRunner
975982
for i := range fns {
976983
var err error
@@ -981,18 +988,18 @@ func fnChain(ctx context.Context, hctx *hydrationContext, pkgPath types.UniquePa
981988
displayResourceCount = true
982989
}
983990
if function.Exec != "" && !hctx.runnerOptions.AllowExec {
984-
return nil, errAllowedExecNotSpecified
991+
return nil, i, errAllowedExecNotSpecified
985992
}
986993
opts := hctx.runnerOptions
987994
opts.SetPkgPathAnnotation = true
988995
opts.DisplayResourceCount = displayResourceCount
989996
runner, err = fnruntime.NewRunner(ctx, hctx.fileSystem, &function, pkgPath, hctx.fnResults, opts, hctx.runtime)
990997
if err != nil {
991-
return nil, err
998+
return nil, i, err
992999
}
9931000
runners = append(runners, runner)
9941001
}
995-
return runners, nil
1002+
return runners, -1, nil
9961003
}
9971004

9981005
// trackInputFiles records file paths of input resources in the hydration context.
@@ -1041,7 +1048,7 @@ func pruneResources(fsys filesys.FileSystem, hctx *hydrationContext) error {
10411048

10421049
// captureStepResult builds a PipelineStepResult from the fnresult.Result items
10431050
// appended since prevLen.
1044-
func captureStepResult(fn kptfilev1.Function, fnResults *fnresult.ResultList, prevLen int) kptfilev1.PipelineStepResult {
1051+
func captureStepResult(fn kptfilev1.Function, fnResults *fnresult.ResultList, prevLen int, execErr error) kptfilev1.PipelineStepResult {
10451052
step := kptfilev1.PipelineStepResult{
10461053
Name: fn.Name,
10471054
Image: fn.Image,
@@ -1057,22 +1064,23 @@ func captureStepResult(fn kptfilev1.Function, fnResults *fnresult.ResultList, pr
10571064
step.ErrorResults = append(step.ErrorResults, ri)
10581065
}
10591066
}
1067+
} else if execErr != nil {
1068+
step.ExitCode = 1
1069+
step.ExecutionError = execErr.Error()
10601070
}
10611071
return step
10621072
}
10631073

1064-
// executionErrorStep creates a PipelineStepResult for errors that occur before
1065-
// function execution (e.g. image pull failure, missing exec).
1066-
func executionErrorStep(fns []kptfilev1.Function, err error) kptfilev1.PipelineStepResult {
1067-
if len(fns) == 0 {
1068-
return kptfilev1.PipelineStepResult{ExecutionError: err.Error()}
1069-
}
1070-
// Use the first function in the list that failed to resolve
1071-
fn := fns[0]
1074+
// preExecFailureStep creates a PipelineStepResult for errors that occur before
1075+
// the function is executed (e.g. image pull failure, missing exec permission).
1076+
// ExitCode is set to 1 to indicate failure; the executionError field provides
1077+
// the specific reason the function could not be started.
1078+
func preExecFailureStep(fn kptfilev1.Function, err error) kptfilev1.PipelineStepResult {
10721079
return kptfilev1.PipelineStepResult{
10731080
Name: fn.Name,
10741081
Image: fn.Image,
10751082
ExecPath: fn.Exec,
1083+
ExitCode: 1,
10761084
ExecutionError: err.Error(),
10771085
}
10781086
}

internal/util/render/executor_test.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ func TestCaptureStepResult_FromFnResults(t *testing.T) {
808808
})
809809

810810
fn := kptfilev1.Function{Name: "validate", Image: "gatekeeper:latest"}
811-
step := captureStepResult(fn, fnResults, 0)
811+
step := captureStepResult(fn, fnResults, 0, nil)
812812

813813
assert.Equal(t, "validate", step.Name)
814814
assert.Equal(t, "gatekeeper:latest", step.Image)
@@ -839,30 +839,28 @@ func TestCaptureStepResult_FromFnResults(t *testing.T) {
839839
func TestCaptureStepResult_NoNewItems(t *testing.T) {
840840
fnResults := fnresult.NewResultList()
841841
fn := kptfilev1.Function{Image: "set-namespace:v1"}
842-
step := captureStepResult(fn, fnResults, 0)
842+
step := captureStepResult(fn, fnResults, 0, fmt.Errorf("output resource list must contain only KRM resources"))
843843

844844
assert.Equal(t, "set-namespace:v1", step.Image)
845-
assert.Equal(t, 0, step.ExitCode)
846-
assert.Empty(t, step.Stderr)
845+
assert.Equal(t, 1, step.ExitCode)
846+
assert.Equal(t, "output resource list must contain only KRM resources", step.ExecutionError)
847847
assert.Nil(t, step.Results)
848848
assert.Nil(t, step.ErrorResults)
849849
}
850850

851-
func TestExecutionErrorStep(t *testing.T) {
852-
fns := []kptfilev1.Function{
853-
{Name: "my-fn", Image: "bad-image:v1", Exec: ""},
854-
}
855-
step := executionErrorStep(fns, fmt.Errorf("pull access denied"))
851+
func TestPreExecFailureStep(t *testing.T) {
852+
fn := kptfilev1.Function{Name: "my-fn", Image: "bad-image:v1", Exec: ""}
853+
step := preExecFailureStep(fn, fmt.Errorf("pull access denied"))
856854

857855
assert.Equal(t, "my-fn", step.Name)
858856
assert.Equal(t, "bad-image:v1", step.Image)
859857
assert.Equal(t, "pull access denied", step.ExecutionError)
860-
assert.Equal(t, 0, step.ExitCode)
858+
assert.Equal(t, 1, step.ExitCode)
861859
assert.Nil(t, step.Results)
862860
}
863861

864-
func TestExecutionErrorStep_EmptyFns(t *testing.T) {
865-
step := executionErrorStep(nil, fmt.Errorf("no functions"))
862+
func TestPreExecFailureStep_EmptyFn(t *testing.T) {
863+
step := preExecFailureStep(kptfilev1.Function{}, fmt.Errorf("no functions"))
866864
assert.Empty(t, step.Name)
867865
assert.Empty(t, step.Image)
868866
assert.Empty(t, step.ExecPath)

pkg/test/runner/config.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ type TestCaseConfig struct {
5858
// ActualStripLines is a list of lines that should be ignored on the actual function output
5959
ActualStripLines []string `json:"actualStripLines,omitempty" yaml:"actualStripLines,omitempty"`
6060

61-
// DiffStripRegEx is a regular expression. Matching text is removed from
62-
// both actual and expected diffs before comparison, making tests
63-
// resilient to environment-specific output such as docker daemon errors.
61+
// DiffStripRegEx is a regular expression. Lines matching this pattern are
62+
// removed from both actual and expected diffs before comparison, making
63+
// tests resilient to environment-specific output such as docker daemon errors.
6464
DiffStripRegEx string `json:"diffStripRegEx,omitempty" yaml:"diffStripRegEx,omitempty"`
6565

6666
// StdErr is the expected standard error output and should be checked

pkg/test/runner/runner.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,14 @@ func (r *Runner) compareResult(exitErr error, stdout string, inStderr string, tm
480480
}
481481
expectedDiff := expected.Diff
482482
if r.testCase.Config.DiffStripRegEx != "" {
483-
actualDiff = normalizeDiff(actualDiff, r.testCase.Config.DiffStripRegEx)
484-
expectedDiff = normalizeDiff(expectedDiff, r.testCase.Config.DiffStripRegEx)
483+
actualDiff, err = normalizeDiff(actualDiff, r.testCase.Config.DiffStripRegEx)
484+
if err != nil {
485+
return err
486+
}
487+
expectedDiff, err = normalizeDiff(expectedDiff, r.testCase.Config.DiffStripRegEx)
488+
if err != nil {
489+
return err
490+
}
485491
}
486492
if actualDiff != expectedDiff {
487493
diffOfDiff, err := diffStrings(actualDiff, expectedDiff)
@@ -644,8 +650,11 @@ func (r *Runner) stripLines(string2Strip string, linesToStrip []string) string {
644650
// normalizeDiff removes lines matching stripRegEx and normalizes index/hunk
645651
// headers in the diff string so that environment-specific output does not
646652
// cause comparison failures.
647-
func normalizeDiff(diff, stripRegEx string) string {
648-
re := regexp.MustCompile(stripRegEx)
653+
func normalizeDiff(diff, stripRegEx string) (string, error) {
654+
re, err := regexp.Compile(stripRegEx)
655+
if err != nil {
656+
return "", fmt.Errorf("unable to compile DiffStripRegEx %q: %w", stripRegEx, err)
657+
}
649658
indexRE := regexp.MustCompile(`^index [0-9a-f]+\.\.[0-9a-f]+`)
650659
hunkRE := regexp.MustCompile(`^@@ -\d+,\d+ \+\d+,\d+ @@`)
651660
var out []string
@@ -657,5 +666,5 @@ func normalizeDiff(diff, stripRegEx string) string {
657666
line = hunkRE.ReplaceAllString(line, "@@ NORMALIZED @@")
658667
out = append(out, line)
659668
}
660-
return strings.Join(out, "\n")
669+
return strings.Join(out, "\n"), nil
661670
}

0 commit comments

Comments
 (0)