diff --git a/go.mod b/go.mod index 90f756ef12c1..d89d31068266 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,6 @@ require ( go.etcd.io/etcd/client/pkg/v3 v3.5.13 go.etcd.io/etcd/client/v3 v3.5.13 go.etcd.io/etcd/etcdutl/v3 v3.5.13 - go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.23.0 golang.org/x/mod v0.17.0 @@ -255,6 +254,7 @@ require ( go.opentelemetry.io/otel/trace v1.20.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb // indirect golang.org/x/net v0.25.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect diff --git a/internal/pkg/file/file.go b/internal/pkg/file/file.go index 2d345c8042a6..2b382d5cf705 100644 --- a/internal/pkg/file/file.go +++ b/internal/pkg/file/file.go @@ -25,8 +25,6 @@ import ( "path/filepath" "github.com/k0sproject/k0s/internal/pkg/users" - - "go.uber.org/multierr" ) // Exists checks if a file exists and is not a directory before we @@ -60,7 +58,7 @@ func Copy(src, dst string) (err error) { if err != nil { return err } - defer multierr.AppendInvoke(&err, multierr.Close(in)) + defer func() { err = errors.Join(err, in.Close()) }() sourceFileStat, err := in.Stat() if err != nil { @@ -97,19 +95,32 @@ func WriteAtomically(fileName string, perm os.FileMode, write func(file io.Write tmpFileName := fd.Name() close := true defer func() { - remove := err != nil + var errs []error + if err != nil { + errs = append(errs, err) + } + if close { - err = multierr.Append(err, fd.Close()) + if err := fd.Close(); err != nil { + errs = append(errs, err) + } } - if remove { - removeErr := os.Remove(tmpFileName) + + if err != nil { + err := os.Remove(tmpFileName) // Don't propagate any fs.ErrNotExist errors. There is no point in // doing this, since the desired state is already reached: The // temporary file is no longer present on the file system. - if removeErr != nil && !errors.Is(err, fs.ErrNotExist) { - err = multierr.Append(err, removeErr) + if err != nil && !errors.Is(err, fs.ErrNotExist) { + errs = append(errs, err) } } + + if len(errs) == 1 { + err = errs[0] + } else { + err = errors.Join(errs...) + } }() err = write(fd) diff --git a/internal/pkg/file/file_test.go b/internal/pkg/file/file_test.go index cbb70eb4666f..993f09148590 100644 --- a/internal/pkg/file/file_test.go +++ b/internal/pkg/file/file_test.go @@ -29,7 +29,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.uber.org/multierr" ) func TestWriteAtomically(t *testing.T) { @@ -103,7 +102,7 @@ func TestWriteAtomically(t *testing.T) { dir := t.TempDir() file := filepath.Join(dir, "file") - errs := multierr.Errors(WriteAtomically(file, 0644, func(file io.Writer) error { + errs := unwrap(WriteAtomically(file, 0644, func(file io.Writer) error { c, ok := file.(io.Closer) require.True(t, ok, "Not closeable: %T", file) require.NoError(t, c.Close()) @@ -150,7 +149,7 @@ func TestWriteAtomically(t *testing.T) { return nil }) - assert.Len(t, multierr.Errors(err), 1) + assert.Len(t, unwrap(err), 1) // The error should be about the failed chmod. if err, ok := assertPathError(t, err, "chmod", dir); ok { @@ -168,7 +167,7 @@ func TestWriteAtomically(t *testing.T) { // Obstruct the file path, so that the rename fails. require.NoError(t, os.Mkdir(file, 0700)) - errs := multierr.Errors(WriteAtomically(file, 0644, func(file io.Writer) error { + errs := unwrap(WriteAtomically(file, 0644, func(file io.Writer) error { _, err := file.Write([]byte("obstructed")) return err })) @@ -176,7 +175,7 @@ func TestWriteAtomically(t *testing.T) { require.Len(t, errs, 1) var linkErr *os.LinkError - if assert.True(t, errors.As(errs[0], &linkErr), "Not a LinkError: %v", linkErr) { + if assert.True(t, errors.As(errs[0], &linkErr), "Not a LinkError: %#+v", errs[0]) { assert.Equal(t, "rename", linkErr.Op) assert.Equal( t, dir, filepath.Dir(linkErr.Old), @@ -214,7 +213,7 @@ func TestWriteAtomically(t *testing.T) { require.NoError(t, os.Mkdir(file, 0700)) var tempPath string - errs := multierr.Errors(WriteAtomically(file, 0755, func(file io.Writer) error { + errs := unwrap(WriteAtomically(file, 0755, func(file io.Writer) error { n, ok := file.(interface{ Name() string }) require.True(t, ok, "Doesn't have a name: %T", file) tempPath = n.Name() @@ -307,3 +306,13 @@ func TestExists(t *testing.T) { } }) } + +func unwrap(err error) []error { + if err, ok := err.(interface{ Unwrap() []error }); ok { + if errs := err.Unwrap(); len(errs) > 0 { + return errs + } + } + + return []error{err} +} diff --git a/internal/pkg/iptablesutils/iptables.go b/internal/pkg/iptablesutils/iptables.go index 763a66494445..9ad4dc3c0190 100644 --- a/internal/pkg/iptablesutils/iptables.go +++ b/internal/pkg/iptablesutils/iptables.go @@ -18,13 +18,13 @@ package iptablesutils import ( "bufio" + "errors" "fmt" "os/exec" "path/filepath" "strings" "github.com/sirupsen/logrus" - "go.uber.org/multierr" ) const ( @@ -68,12 +68,12 @@ func DetectHostIPTablesMode(k0sBinPath string) (string, error) { iptablesPath, err := exec.LookPath("iptables") if err != nil { - return "", multierr.Combine(err, nftErr, legacyErr) + return "", errors.Join(err, nftErr, legacyErr) } out, err := exec.Command(iptablesPath, "--version").CombinedOutput() if err != nil { - return "", multierr.Combine(err, nftErr, legacyErr) + return "", errors.Join(err, nftErr, legacyErr) } outStr := strings.TrimSpace(string(out)) @@ -119,10 +119,7 @@ func findMatchingEntries(k0sBinPath, mode string, entries ...string) (entriesFou v4Err, v6Err := findMatches("iptables-save"), findMatches("ip6tables-save") if v4Err != nil && v6Err != nil { - return false, 0, multierr.Combine( - fmt.Errorf("iptables-save: %w", v4Err), - fmt.Errorf("ip6tables-save: %w", v6Err), - ) + return false, 0, fmt.Errorf("iptables-save: %w; ip6tables-save: %w", v4Err, v6Err) } return entriesFound, total, nil diff --git a/internal/pkg/iptablesutils/iptables_test.go b/internal/pkg/iptablesutils/iptables_test.go index b2492750b692..26bb2f660c42 100644 --- a/internal/pkg/iptablesutils/iptables_test.go +++ b/internal/pkg/iptablesutils/iptables_test.go @@ -30,7 +30,6 @@ import ( "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.uber.org/multierr" ) func TestDetectHostIPTablesMode(t *testing.T) { @@ -173,7 +172,9 @@ func TestDetectHostIPTablesMode(t *testing.T) { writeXtables(t, binDir, "legacy", "exit 77", "exit 66") _, err := iptablesutils.DetectHostIPTablesMode(binDir) - errs := multierr.Errors(err) + var composite interface{ Unwrap() []error } + require.ErrorAs(t, err, &composite, "No wrapped errors") + errs := composite.Unwrap() require.Len(t, errs, 3) assert.ErrorIs(t, errs[0], exec.ErrNotFound) assert.ErrorContains(t, errs[1], "99") diff --git a/inttest/common/airgap.go b/inttest/common/airgap.go index 62ee385bfd62..8e2bb0367142 100644 --- a/inttest/common/airgap.go +++ b/inttest/common/airgap.go @@ -18,13 +18,12 @@ package common import ( "context" + "errors" "fmt" "net" "os" "os/exec" "strings" - - "go.uber.org/multierr" ) type Airgap struct { @@ -63,13 +62,15 @@ func tryBlockIPv6() error { err = exec.Command("modprobe", "ip6table_filter").Run() if err != nil && os.Geteuid() != 0 { + errs := []error{err} for _, cmd := range []string{"sudo", "doas"} { - userErr := exec.Command(cmd, "-n", "modprobe", "ip6table_filter").Run() - if userErr == nil { + err := exec.Command(cmd, "-n", "modprobe", "ip6table_filter").Run() + if err == nil { return nil } - err = multierr.Append(err, userErr) + errs = append(errs, err) } + err = errors.Join(errs...) } return err diff --git a/inttest/common/bootloosesuite.go b/inttest/common/bootloosesuite.go index c684439d822e..599f9119ac47 100644 --- a/inttest/common/bootloosesuite.go +++ b/inttest/common/bootloosesuite.go @@ -62,7 +62,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "go.uber.org/multierr" "golang.org/x/sync/errgroup" ) @@ -444,18 +443,18 @@ func (s *BootlooseSuite) dumpNodeLogs(ctx context.Context, t *testing.T, node, d outLog, errLog := log{path: outPath}, log{path: errPath} for _, log := range []*log{&outLog, &errLog} { - file, err := os.Create(log.path) - if err != nil { - t.Logf("Failed to create log file: %s", err.Error()) + file, createErr := os.Create(log.path) + if createErr != nil { + t.Log("Failed to create log file:", createErr) continue } - defer multierr.AppendInvoke(&err, multierr.Close(file)) buf := bufio.NewWriter(file) defer func() { if err == nil { err = buf.Flush() } + err = errors.Join(err, file.Close()) }() log.writer = buf } diff --git a/inttest/common/launchdelegate.go b/inttest/common/launchdelegate.go index 028f3810d0ba..f148d58dd97b 100644 --- a/inttest/common/launchdelegate.go +++ b/inttest/common/launchdelegate.go @@ -18,13 +18,12 @@ package common import ( "context" + "errors" "fmt" "io" "runtime" "strings" "sync" - - "go.uber.org/multierr" ) type LaunchMode string @@ -248,7 +247,7 @@ func (*openRCLaunchDelegate) ReadK0sLogs(ctx context.Context, conn *SSHConnectio wg.Wait() - return multierr.Append(outErr, errErr) + return errors.Join(outErr, errErr) } // installK0sServiceOpenRC will install an OpenRC k0s-type service (controller/worker) diff --git a/inttest/nllb/nllb_test.go b/inttest/nllb/nllb_test.go index 68b9d2d21019..4917d9a196b5 100644 --- a/inttest/nllb/nllb_test.go +++ b/inttest/nllb/nllb_test.go @@ -39,7 +39,6 @@ import ( kubeletv1beta1 "k8s.io/kubelet/config/v1beta1" testifysuite "github.com/stretchr/testify/suite" - "go.uber.org/multierr" "golang.org/x/sync/errgroup" "sigs.k8s.io/yaml" ) @@ -272,7 +271,7 @@ func (s *suite) checkClusterReadiness(ctx context.Context, clients *kubernetes.C } return true, logs.Close() }); err != nil { - return multierr.Append(fmt.Errorf("failed to get pod logs from %s/%s", kubeSystem, nllbPodName), logsErr) + return fmt.Errorf("failed to get pod logs from %s/%s: %w", kubeSystem, nllbPodName, logsErr) } s.T().Logf("Got some pod logs from %s/%s", kubeSystem, nllbPodName) diff --git a/pkg/component/controller/clusterConfig.go b/pkg/component/controller/clusterConfig.go index 814d25d4a071..23e1b1da6cdc 100644 --- a/pkg/component/controller/clusterConfig.go +++ b/pkg/component/controller/clusterConfig.go @@ -18,6 +18,7 @@ package controller import ( "context" + "errors" "fmt" "os" "time" @@ -32,12 +33,11 @@ import ( kubeutil "github.com/k0sproject/k0s/pkg/kubernetes" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" "github.com/sirupsen/logrus" - "go.uber.org/multierr" ) // ClusterConfigReconciler reconciles a ClusterConfig object @@ -89,7 +89,7 @@ func (r *ClusterConfigReconciler) Start(ctx context.Context) error { r.log.Debug("Cluster configuration created") return true, nil } - if errors.IsAlreadyExists(err) { + if apierrors.IsAlreadyExists(err) { // An already existing configuration is just fine. r.log.Debug("Cluster configuration already exists") return true, nil @@ -121,7 +121,7 @@ func (r *ClusterConfigReconciler) Start(ctx context.Context) error { r.log.Debug("config source closed channel") return } - err := multierr.Combine(cfg.Validate()...) + err := errors.Join(cfg.Validate()...) if err != nil { err = fmt.Errorf("failed to validate cluster configuration: %w", err) } else { diff --git a/pkg/component/controller/workerconfig/reconciler.go b/pkg/component/controller/workerconfig/reconciler.go index 04e4f01d0ad5..9122e8f4c281 100644 --- a/pkg/component/controller/workerconfig/reconciler.go +++ b/pkg/component/controller/workerconfig/reconciler.go @@ -52,7 +52,6 @@ import ( "k8s.io/utils/ptr" "github.com/sirupsen/logrus" - "go.uber.org/multierr" "sigs.k8s.io/yaml" ) @@ -413,7 +412,7 @@ func (r *Reconciler) reconcileAPIServers(ctx context.Context, updates chan<- upd } func extractAPIServerAddresses(endpoints *corev1.Endpoints) ([]k0snet.HostPort, error) { - var warnings error + var warnings []error apiServers := []k0snet.HostPort{} for sIdx, subset := range endpoints.Subsets { @@ -428,7 +427,7 @@ func extractAPIServerAddresses(endpoints *corev1.Endpoints) ([]k0snet.HostPort, if port.Port < 0 || port.Port > math.MaxUint16 { path := field.NewPath("subsets").Index(sIdx).Child("ports").Index(pIdx).Child("port") warning := field.Invalid(path, port.Port, "out of range") - warnings = multierr.Append(warnings, warning) + warnings = append(warnings, warning) continue } @@ -438,7 +437,7 @@ func extractAPIServerAddresses(endpoints *corev1.Endpoints) ([]k0snet.HostPort, if len(ports) < 1 { path := field.NewPath("subsets").Index(sIdx) warning := field.Forbidden(path, "no suitable TCP/https ports found") - warnings = multierr.Append(warnings, warning) + warnings = append(warnings, warning) continue } @@ -450,14 +449,14 @@ func extractAPIServerAddresses(endpoints *corev1.Endpoints) ([]k0snet.HostPort, if host == "" { path := field.NewPath("addresses").Index(aIdx) warning := field.Forbidden(path, "neither ip nor hostname specified") - warnings = multierr.Append(warnings, warning) + warnings = append(warnings, warning) continue } for _, port := range ports { apiServer, err := k0snet.NewHostPort(host, port) if err != nil { - warnings = multierr.Append(warnings, fmt.Errorf("%s:%d: %w", host, port, err)) + warnings = append(warnings, fmt.Errorf("%s:%d: %w", host, port, err)) continue } @@ -469,7 +468,11 @@ func extractAPIServerAddresses(endpoints *corev1.Endpoints) ([]k0snet.HostPort, if len(apiServers) < 1 { // Never update the API servers with an empty list. This cannot // be right in any case, and would never recover. - return nil, multierr.Append(errors.New("no API server addresses discovered"), warnings) + err := errors.New("no API server addresses discovered") + if warnings := errors.Join(warnings...); warnings != nil { + err = fmt.Errorf("%w: %w", err, warnings) + } + return nil, err } return apiServers, nil diff --git a/pkg/component/worker/config/config.go b/pkg/component/worker/config/config.go index 5affd2f543e2..c4aa5d0a7d4e 100644 --- a/pkg/component/worker/config/config.go +++ b/pkg/component/worker/config/config.go @@ -30,7 +30,6 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" kubeletv1beta1 "k8s.io/kubelet/config/v1beta1" - "go.uber.org/multierr" "sigs.k8s.io/yaml" ) @@ -96,18 +95,18 @@ func (k *Konnectivity) Validate(path *field.Path) (errs field.ErrorList) { func FromConfigMapData(data map[string]string) (*Profile, error) { var config Profile - var errs error + var errs []error forEachConfigMapEntry(&config, func(fieldName string, ptr any) { data, ok := data[fieldName] if ok { if err := yaml.Unmarshal([]byte(data), ptr); err != nil { - errs = multierr.Append(errs, fmt.Errorf("%s: %w", fieldName, err)) + errs = append(errs, fmt.Errorf("%s: %w", fieldName, err)) } } }) - if errs != nil { - return nil, errs + if err := errors.Join(errs...); err != nil { + return nil, err } if errs := config.Validate(nil); len(errs) > 0 { @@ -127,22 +126,22 @@ func ToConfigMapData(profile *Profile) (map[string]string, error) { data := make(map[string]string) - var errs error + var errs []error forEachConfigMapEntry(profile, func(fieldName string, ptr any) { if reflect.ValueOf(ptr).Elem().IsZero() { return } bytes, err := json.Marshal(ptr) if err != nil { - errs = multierr.Append(errs, fmt.Errorf("%s: %w", fieldName, err)) + errs = append(errs, fmt.Errorf("%s: %w", fieldName, err)) return } data[fieldName] = string(bytes) }) - if errs != nil { - return nil, errs + if err := errors.Join(errs...); err != nil { + return nil, err } return data, nil diff --git a/pkg/component/worker/config/config_test.go b/pkg/component/worker/config/config_test.go index e35b016ddfeb..d438aabe1f02 100644 --- a/pkg/component/worker/config/config_test.go +++ b/pkg/component/worker/config/config_test.go @@ -61,9 +61,9 @@ func TestFromConfigMapData(t *testing.T) { } config, err := FromConfigMapData(data) - var composite interface{ Errors() []error } + var composite interface{ Unwrap() []error } if assert.ErrorAs(t, err, &composite) { - errs := composite.Errors() + errs := composite.Unwrap() assert.Len(t, errs, 4) for i, err := range errs { assert.ErrorContains(t, err, "json: cannot unmarshal number into Go value of type", "For error #%d", i+1) diff --git a/pkg/component/worker/config/loader.go b/pkg/component/worker/config/loader.go index 5964caca9d0c..4319ecd6366f 100644 --- a/pkg/component/worker/config/loader.go +++ b/pkg/component/worker/config/loader.go @@ -18,6 +18,7 @@ package config import ( "context" + "errors" "fmt" "os" "path/filepath" @@ -38,7 +39,6 @@ import ( "github.com/avast/retry-go" "github.com/sirupsen/logrus" - "go.uber.org/multierr" "sigs.k8s.io/yaml" ) @@ -282,5 +282,5 @@ func loadConcurrently(ctx context.Context, addresses []string, loadWorkerConfig return *workerConfigPtr, nil } - return nil, multierr.Combine(errs...) + return nil, errors.Join(errs...) } diff --git a/pkg/component/worker/nllb/envoy.go b/pkg/component/worker/nllb/envoy.go index c9f2c90a6f18..eb5622c1d1cf 100644 --- a/pkg/component/worker/nllb/envoy.go +++ b/pkg/component/worker/nllb/envoy.go @@ -41,7 +41,6 @@ import ( "k8s.io/utils/ptr" "github.com/sirupsen/logrus" - "go.uber.org/multierr" ) // envoyProxy is a load balancer [backend] that's managing a static Envoy pod to @@ -229,7 +228,7 @@ func writeEnvoyConfigFiles(params *envoyParams, filesParams *envoyFilesParams) e UpstreamServers: filesParams.apiServers, } - var errs error + var errs []error for fileName, template := range map[string]*template.Template{ envoyBootstrapFile: envoyBootstrapConfig, envoyCDSFile: envoyClustersConfig, @@ -242,11 +241,11 @@ func writeEnvoyConfigFiles(params *envoyParams, filesParams *envoyFilesParams) e return bufferedWriter.Flush() }) if err != nil { - errs = multierr.Append(errs, fmt.Errorf("failed to write %s: %w", fileName, err)) + errs = append(errs, fmt.Errorf("failed to write %s: %w", fileName, err)) } } - return errs + return errors.Join(errs...) } func (e *envoyProxy) provision() error { diff --git a/pkg/component/worker/nllb/envoy_test.go b/pkg/component/worker/nllb/envoy_test.go index ad54292077c5..14ce1826bab3 100644 --- a/pkg/component/worker/nllb/envoy_test.go +++ b/pkg/component/worker/nllb/envoy_test.go @@ -25,7 +25,6 @@ import ( "testing" k0snet "github.com/k0sproject/k0s/internal/pkg/net" - "go.uber.org/multierr" "k8s.io/client-go/util/jsonpath" @@ -84,7 +83,7 @@ func TestWriteEnvoyConfigFiles(t *testing.T) { for i, ep := range eps { host, herr := evalJSONPath[string](ep, ".endpoint.address.socket_address.address") port, perr := evalJSONPath[float64](ep, ".endpoint.address.socket_address.port_value") - if assert.NoError(t, multierr.Append(herr, perr), "For endpoint %d", i) { + if assert.NoError(t, errors.Join(herr, perr), "For endpoint %d", i) { iport := int64(port) if assert.Equal(t, float64(iport), port, "Port is not an integer for endpoint %d", i) { addrs = append(addrs, fmt.Sprintf("%s:%d", host, iport)) diff --git a/pkg/component/worker/utils.go b/pkg/component/worker/utils.go index f801e7254941..282bee2335ce 100644 --- a/pkg/component/worker/utils.go +++ b/pkg/component/worker/utils.go @@ -20,6 +20,7 @@ import ( "context" "errors" "fmt" + "io/fs" "os" "path" "path/filepath" @@ -41,7 +42,6 @@ import ( "github.com/avast/retry-go" "github.com/sirupsen/logrus" - "go.uber.org/multierr" ) func BootstrapKubeletKubeconfig(ctx context.Context, k0sVars *config.CfgVars, workerOpts *config.WorkerOptions) error { @@ -202,14 +202,19 @@ func writeKubeletBootstrapKubeconfig(kubeconfig []byte) (string, error) { return "", err } - _, err = bootstrapFile.Write(kubeconfig) - err = multierr.Append(err, bootstrapFile.Close()) - if err != nil { - if rmErr := os.Remove(bootstrapFile.Name()); rmErr != nil && !os.IsNotExist(rmErr) { - err = multierr.Append(err, rmErr) + _, writeErr := bootstrapFile.Write(kubeconfig) + closeErr := bootstrapFile.Close() + + if writeErr != nil || closeErr != nil { + rmErr := os.Remove(bootstrapFile.Name()) + // Don't propagate any fs.ErrNotExist errors. There is no point in doing + // this, since the desired state is already reached: The bootstrap file + // file is no longer present on the file system. + if errors.Is(rmErr, fs.ErrNotExist) { + rmErr = nil } - return "", err + return "", errors.Join(writeErr, closeErr, rmErr) } return bootstrapFile.Name(), nil diff --git a/pkg/supervisor/pingpong_unix.go b/pkg/supervisor/pingpong_unix.go index 3303c2cc00d3..d60bc8ea61d9 100644 --- a/pkg/supervisor/pingpong_unix.go +++ b/pkg/supervisor/pingpong_unix.go @@ -19,6 +19,7 @@ limitations under the License. package supervisor import ( + "errors" "os" "os/exec" "path/filepath" @@ -26,7 +27,6 @@ import ( "testing" "github.com/stretchr/testify/require" - "go.uber.org/multierr" ) type pingPong struct { @@ -65,7 +65,7 @@ func (pp *pingPong) awaitPing() (err error) { if err != nil { return err } - defer func() { err = multierr.Append(err, f.Close()) }() + defer func() { err = errors.Join(err, f.Close()) }() // The write will block until the process reads from the FIFO file. if _, err := f.Write([]byte("ping\n")); err != nil { diff --git a/pkg/supervisor/pingpong_windows.go b/pkg/supervisor/pingpong_windows.go index bb349c0b4d29..33330be90d20 100644 --- a/pkg/supervisor/pingpong_windows.go +++ b/pkg/supervisor/pingpong_windows.go @@ -17,6 +17,7 @@ limitations under the License. package supervisor import ( + "errors" "io" "net" "os/exec" @@ -29,7 +30,6 @@ import ( "github.com/Microsoft/go-winio/pkg/guid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.uber.org/multierr" ) type pingPong struct { @@ -77,7 +77,7 @@ func (pp *pingPong) awaitPing() (err error) { if err != nil { return err } - defer func() { err = multierr.Append(err, conn.Close()) }() + defer func() { err = errors.Join(err, conn.Close()) }() _, err = io.ReadAll(conn) return err @@ -88,7 +88,7 @@ func (pp *pingPong) sendPong() (err error) { if err != nil { return err } - defer func() { err = multierr.Append(err, conn.Close()) }() + defer func() { err = errors.Join(err, conn.Close()) }() _, err = conn.Write([]byte("pong\n")) return err