Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/crossplane/render/op/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func (c *Cmd) Run(k *kong.Context, log logging.Logger, sp terminal.SpinnerPrinte
if err != nil {
return errors.Wrap(err, "cannot start function runtimes")
}
defer render.StopFunctionRuntimes(log, fnAddrs)
defer render.StopFunctionRuntimesAndWarn(k.Stderr, log, fnAddrs)

// Build and execute the render request.
in := render.OperationInputs{
Expand Down
27 changes: 25 additions & 2 deletions cmd/crossplane/render/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ package render

import (
"context"
"fmt"
"io"
"strings"
"time"

Expand Down Expand Up @@ -169,14 +171,35 @@ func injectNetworkAnnotation(fns []pkgv1.Function, networkName string) {

// StopFunctionRuntimes stops all function runtimes with a timeout.
func StopFunctionRuntimes(log logging.Logger, fa *FunctionAddresses) {
_ = stopFunctionRuntimes(log, fa)
}

// StopFunctionRuntimesAndWarn stops all function runtimes with a timeout, like
// StopFunctionRuntimes, and additionally writes a warning to w if they could
// not be cleaned up. Use it where the logger may be a no-op (e.g. without
// --verbose) so cleanup failures aren't silently swallowed.
func StopFunctionRuntimesAndWarn(w io.Writer, log logging.Logger, fa *FunctionAddresses) {
warnFunctionRuntimeCleanupFailure(w, stopFunctionRuntimes(log, fa))
}

func stopFunctionRuntimes(log logging.Logger, fa *FunctionAddresses) error {
if fa == nil {
return
return nil
}
stopCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := fa.Stop(stopCtx); err != nil {
err := fa.Stop(stopCtx)
if err != nil {
log.Info("Error stopping function runtimes", "error", err)
}
return err
}

func warnFunctionRuntimeCleanupFailure(w io.Writer, err error) {
if err == nil || w == nil {
return
}
_, _ = fmt.Fprintf(w, "warning: failed to clean up function runtimes; some resources (e.g. containers) may need to be removed manually: %v\n", err)
}

// OverrideFunctionAnnotations applies annotation overrides from flags to
Expand Down
37 changes: 37 additions & 0 deletions cmd/crossplane/render/render_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package render

import (
"bytes"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/crossplane/crossplane-runtime/v2/pkg/errors"
"github.com/crossplane/crossplane-runtime/v2/pkg/logging"

pkgv1 "github.com/crossplane/crossplane/apis/v2/pkg/v1"
)

Expand Down Expand Up @@ -91,3 +95,36 @@ func TestOverrideFunctionAnnotations(t *testing.T) {
func functionWithAnnotations(annotations map[string]string) pkgv1.Function {
return pkgv1.Function{ObjectMeta: metav1.ObjectMeta{Annotations: annotations}}
}

func TestWarnFunctionRuntimeCleanupFailure(t *testing.T) {
cases := map[string]struct {
err error
want string
}{
"NoError": {
err: nil,
want: "",
},
"Error": {
err: errors.New("boom"),
want: "warning: failed to clean up function runtimes; some resources (e.g. containers) may need to be removed manually: boom\n",
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
b := &bytes.Buffer{}
warnFunctionRuntimeCleanupFailure(b, tc.err)
if diff := cmp.Diff(tc.want, b.String()); diff != "" {
t.Errorf("warnFunctionRuntimeCleanupFailure(...): -want, +got:\n%s", diff)
}
})
}
}

func TestStopFunctionRuntimesAndWarnNil(t *testing.T) {
b := &bytes.Buffer{}
StopFunctionRuntimesAndWarn(b, logging.NewNopLogger(), nil)
if b.Len() != 0 {
t.Errorf("StopFunctionRuntimesAndWarn(nil): expected no output, got %q", b.String())
}
}
2 changes: 1 addition & 1 deletion cmd/crossplane/render/xr/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ func (c *Cmd) Run(k *kong.Context, log logging.Logger, sp terminal.SpinnerPrinte
if err != nil {
return errors.Wrap(err, "cannot start function runtimes")
}
defer render.StopFunctionRuntimes(log, fnAddrs)
defer render.StopFunctionRuntimesAndWarn(k.Stderr, log, fnAddrs)

// Build and execute the render request.
in := render.CompositionInputs{
Expand Down
Loading