Remove hashicorp/go-multierror
Signed-off-by: Jin Dong <jin.dong@databricks.com>
This commit is contained in:
@@ -19,11 +19,11 @@
|
||||
package devmapper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
@@ -100,29 +100,29 @@ func (c *Config) parse() error {
|
||||
|
||||
// Validate makes sure configuration fields are valid
|
||||
func (c *Config) Validate() error {
|
||||
var result *multierror.Error
|
||||
var result []error
|
||||
|
||||
if c.PoolName == "" {
|
||||
result = multierror.Append(result, fmt.Errorf("pool_name is required"))
|
||||
result = append(result, fmt.Errorf("pool_name is required"))
|
||||
}
|
||||
|
||||
if c.RootPath == "" {
|
||||
result = multierror.Append(result, fmt.Errorf("root_path is required"))
|
||||
result = append(result, fmt.Errorf("root_path is required"))
|
||||
}
|
||||
|
||||
if c.BaseImageSize == "" {
|
||||
result = multierror.Append(result, fmt.Errorf("base_image_size is required"))
|
||||
result = append(result, fmt.Errorf("base_image_size is required"))
|
||||
}
|
||||
|
||||
if c.FileSystemType != "" {
|
||||
switch c.FileSystemType {
|
||||
case fsTypeExt4, fsTypeXFS, fsTypeExt2:
|
||||
default:
|
||||
result = multierror.Append(result, fmt.Errorf("unsupported Filesystem Type: %q", c.FileSystemType))
|
||||
result = append(result, fmt.Errorf("unsupported Filesystem Type: %q", c.FileSystemType))
|
||||
}
|
||||
} else {
|
||||
result = multierror.Append(result, fmt.Errorf("filesystem type cannot be empty"))
|
||||
result = append(result, fmt.Errorf("filesystem type cannot be empty"))
|
||||
}
|
||||
|
||||
return result.ErrorOrNil()
|
||||
return errors.Join(result...)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pelletier/go-toml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -80,13 +79,13 @@ func TestFieldValidation(t *testing.T) {
|
||||
err := config.Validate()
|
||||
assert.NotNil(t, err)
|
||||
|
||||
multErr := (err).(*multierror.Error)
|
||||
assert.Len(t, multErr.Errors, 4)
|
||||
multErr := err.(interface{ Unwrap() []error }).Unwrap()
|
||||
assert.Len(t, multErr, 4)
|
||||
|
||||
assert.NotNil(t, multErr.Errors[0], "pool_name is empty")
|
||||
assert.NotNil(t, multErr.Errors[1], "root_path is empty")
|
||||
assert.NotNil(t, multErr.Errors[2], "base_image_size is empty")
|
||||
assert.NotNil(t, multErr.Errors[3], "filesystem type cannot be empty")
|
||||
assert.NotNil(t, multErr[0], "pool_name is empty")
|
||||
assert.NotNil(t, multErr[1], "root_path is empty")
|
||||
assert.NotNil(t, multErr[2], "base_image_size is empty")
|
||||
assert.NotNil(t, multErr[3], "filesystem type cannot be empty")
|
||||
}
|
||||
|
||||
func TestExistingPoolFieldValidation(t *testing.T) {
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/containerd/containerd/log"
|
||||
@@ -145,7 +144,7 @@ func (p *PoolDevice) ensureDeviceStates(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to query devices from metastore: %w", err)
|
||||
}
|
||||
|
||||
var result *multierror.Error
|
||||
var result []error
|
||||
for _, dev := range activatedDevices {
|
||||
if p.IsActivated(dev.Name) {
|
||||
continue
|
||||
@@ -153,7 +152,7 @@ func (p *PoolDevice) ensureDeviceStates(ctx context.Context) error {
|
||||
|
||||
log.G(ctx).Warnf("devmapper device %q marked as %q but not active, activating it", dev.Name, dev.State)
|
||||
if err := p.activateDevice(ctx, dev); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
result = append(result, fmt.Errorf("devmapper: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,11 +164,11 @@ func (p *PoolDevice) ensureDeviceStates(ctx context.Context) error {
|
||||
Warnf("devmapper device %q has invalid state %q, marking as faulty", dev.Name, dev.State)
|
||||
|
||||
if err := p.metadata.MarkFaulty(ctx, dev.Name); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
result = append(result, fmt.Errorf("devmapper: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
return multierror.Prefix(result.ErrorOrNil(), "devmapper:")
|
||||
return errors.Join(result...)
|
||||
}
|
||||
|
||||
// transition invokes 'updateStateFn' callback to perform devmapper operation and reflects device state changes/errors in meta store.
|
||||
@@ -186,13 +185,13 @@ func (p *PoolDevice) transition(ctx context.Context, deviceName string, tryingSt
|
||||
return fmt.Errorf("failed to set device %q state to %q: %w", deviceName, tryingState, uerr)
|
||||
}
|
||||
|
||||
var result *multierror.Error
|
||||
var result []error
|
||||
|
||||
// Invoke devmapper operation
|
||||
err := updateStateFn()
|
||||
|
||||
if err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
result = append(result, err)
|
||||
}
|
||||
|
||||
// If operation succeeded transition to success state, otherwise save error details
|
||||
@@ -207,25 +206,23 @@ func (p *PoolDevice) transition(ctx context.Context, deviceName string, tryingSt
|
||||
})
|
||||
|
||||
if uerr != nil {
|
||||
result = multierror.Append(result, uerr)
|
||||
result = append(result, uerr)
|
||||
}
|
||||
|
||||
return unwrapError(result)
|
||||
return unwrapError(errors.Join(result...))
|
||||
}
|
||||
|
||||
// unwrapError converts multierror.Error to the original error when it is possible.
|
||||
// multierror 1.1.0 has the similar function named Unwrap, but it requires Go 1.14.
|
||||
func unwrapError(e *multierror.Error) error {
|
||||
func unwrapError(e error) error {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the error can be expressed without multierror, return the original error.
|
||||
if len(e.Errors) == 1 {
|
||||
return e.Errors[0]
|
||||
if joinErr, ok := e.(interface{ Unwrap() []error }); ok {
|
||||
if errs := joinErr.Unwrap(); len(errs) == 1 {
|
||||
return errs[0]
|
||||
}
|
||||
}
|
||||
|
||||
return e.ErrorOrNil()
|
||||
return e
|
||||
}
|
||||
|
||||
// CreateThinDevice creates new devmapper thin-device with given name and size.
|
||||
@@ -253,7 +250,7 @@ func (p *PoolDevice) CreateThinDevice(ctx context.Context, deviceName string, vi
|
||||
|
||||
// We're unable to create the devmapper device, most likely something wrong with the deviceID
|
||||
if devErr != nil {
|
||||
retErr = multierror.Append(retErr, p.metadata.MarkFaulty(ctx, info.Name))
|
||||
retErr = errors.Join(retErr, p.metadata.MarkFaulty(ctx, info.Name))
|
||||
return
|
||||
}
|
||||
}()
|
||||
@@ -285,12 +282,12 @@ func (p *PoolDevice) rollbackActivate(ctx context.Context, info *DeviceInfo, act
|
||||
if delErr != nil {
|
||||
// Failed to rollback, mark the device as faulty and keep metadata in order to
|
||||
// preserve the faulty device ID
|
||||
return multierror.Append(activateErr, delErr, p.metadata.MarkFaulty(ctx, info.Name))
|
||||
return errors.Join(activateErr, delErr, p.metadata.MarkFaulty(ctx, info.Name))
|
||||
}
|
||||
|
||||
// The devmapper device has been successfully deleted, deallocate device ID
|
||||
if err := p.RemoveDevice(ctx, info.Name); err != nil {
|
||||
return multierror.Append(activateErr, err)
|
||||
return errors.Join(activateErr, err)
|
||||
}
|
||||
|
||||
return activateErr
|
||||
@@ -347,7 +344,7 @@ func (p *PoolDevice) CreateSnapshotDevice(ctx context.Context, deviceName string
|
||||
|
||||
// We're unable to create the devmapper device, most likely something wrong with the deviceID
|
||||
if devErr != nil {
|
||||
retErr = multierror.Append(retErr, p.metadata.MarkFaulty(ctx, snapInfo.Name))
|
||||
retErr = errors.Join(retErr, p.metadata.MarkFaulty(ctx, snapInfo.Name))
|
||||
return
|
||||
}
|
||||
}()
|
||||
@@ -561,20 +558,20 @@ func (p *PoolDevice) RemovePool(ctx context.Context) error {
|
||||
return fmt.Errorf("can't query device names: %w", err)
|
||||
}
|
||||
|
||||
var result *multierror.Error
|
||||
var result []error
|
||||
|
||||
// Deactivate devices if any
|
||||
for _, name := range deviceNames {
|
||||
if err := p.DeactivateDevice(ctx, name, true, true); err != nil {
|
||||
result = multierror.Append(result, fmt.Errorf("failed to remove %q: %w", name, err))
|
||||
result = append(result, fmt.Errorf("failed to remove %q: %w", name, err))
|
||||
}
|
||||
}
|
||||
|
||||
if err := dmsetup.RemoveDevice(p.poolName, dmsetup.RemoveWithForce, dmsetup.RemoveWithRetries, dmsetup.RemoveDeferred); err != nil {
|
||||
result = multierror.Append(result, fmt.Errorf("failed to remove pool %q: %w", p.poolName, err))
|
||||
result = append(result, fmt.Errorf("failed to remove pool %q: %w", p.poolName, err))
|
||||
}
|
||||
|
||||
return result.ErrorOrNil()
|
||||
return errors.Join(result...)
|
||||
}
|
||||
|
||||
// MarkDeviceState changes the device's state in metastore
|
||||
|
||||
@@ -33,7 +33,6 @@ import (
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
"github.com/containerd/containerd/snapshots/devmapper/dmsetup"
|
||||
"github.com/containerd/containerd/snapshots/storage"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
exec "golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
@@ -344,14 +343,14 @@ func (s *Snapshotter) ResetPool(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var result *multierror.Error
|
||||
var result []error
|
||||
for _, name := range names {
|
||||
if err := s.pool.RemoveDevice(ctx, name); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
result = append(result, err)
|
||||
}
|
||||
}
|
||||
|
||||
return result.ErrorOrNil()
|
||||
return errors.Join(result...)
|
||||
}
|
||||
|
||||
// Close releases devmapper snapshotter resources.
|
||||
@@ -359,16 +358,16 @@ func (s *Snapshotter) ResetPool(ctx context.Context) error {
|
||||
func (s *Snapshotter) Close() error {
|
||||
log.L.Debug("close")
|
||||
|
||||
var result *multierror.Error
|
||||
var result []error
|
||||
s.closeOnce.Do(func() {
|
||||
for _, fn := range s.cleanupFn {
|
||||
if err := fn(); err != nil {
|
||||
result = multierror.Append(result, err)
|
||||
result = append(result, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return result.ErrorOrNil()
|
||||
return errors.Join(result...)
|
||||
}
|
||||
|
||||
func (s *Snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
|
||||
@@ -423,15 +422,15 @@ func (s *Snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, k
|
||||
}
|
||||
log.G(ctx).Debugf("Creating file system of type: %s with options: %s for thin device %q", s.config.FileSystemType, fsOptions, deviceName)
|
||||
if err := mkfs(ctx, s.config.FileSystemType, fsOptions, dmsetup.GetFullDevicePath(deviceName)); err != nil {
|
||||
errs := []error{err}
|
||||
status, sErr := dmsetup.Status(s.pool.poolName)
|
||||
if sErr != nil {
|
||||
multierror.Append(err, sErr)
|
||||
errs = append(errs, sErr)
|
||||
}
|
||||
|
||||
// Rollback thin device creation if mkfs failed
|
||||
log.G(ctx).WithError(err).Errorf("failed to initialize thin device %q for snapshot %s pool status %s", deviceName, snap.ID, status.RawOutput)
|
||||
return nil, multierror.Append(err,
|
||||
s.pool.RemoveDevice(ctx, deviceName))
|
||||
log.G(ctx).WithError(errors.Join(errs...)).Errorf("failed to initialize thin device %q for snapshot %s pool status %s", deviceName, snap.ID, status.RawOutput)
|
||||
return nil, errors.Join(append(errs, s.pool.RemoveDevice(ctx, deviceName))...)
|
||||
}
|
||||
} else {
|
||||
parentDeviceName := s.getDeviceName(snap.ParentIDs[0])
|
||||
@@ -551,16 +550,16 @@ func (s *Snapshotter) Cleanup(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var result *multierror.Error
|
||||
var result []error
|
||||
for _, dev := range removedDevices {
|
||||
log.G(ctx).WithField("device", dev.Name).Debug("cleanup device")
|
||||
if err := s.pool.RemoveDevice(ctx, dev.Name); err != nil {
|
||||
log.G(ctx).WithField("device", dev.Name).Error("failed to cleanup device")
|
||||
result = multierror.Append(result, err)
|
||||
result = append(result, err)
|
||||
} else {
|
||||
log.G(ctx).WithField("device", dev.Name).Debug("cleanuped device")
|
||||
}
|
||||
}
|
||||
|
||||
return result.ErrorOrNil()
|
||||
return errors.Join(result...)
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@ package devmapper
|
||||
import (
|
||||
"context"
|
||||
_ "crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/continuity/fs/fstest"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@@ -199,11 +199,11 @@ func createSnapshotter(ctx context.Context, t *testing.T, config *Config) (snaps
|
||||
|
||||
// Remove device mapper pool and detach loop devices after test completes
|
||||
removePool := func() error {
|
||||
result := multierror.Append(
|
||||
result := errors.Join(
|
||||
snap.pool.RemovePool(ctx),
|
||||
mount.DetachLoopDevice(loopDataDevice, loopMetaDevice))
|
||||
|
||||
return result.ErrorOrNil()
|
||||
return result
|
||||
}
|
||||
|
||||
// Pool cleanup should be called before closing metadata store (as we need to retrieve device names)
|
||||
|
||||
Reference in New Issue
Block a user