Browse Source

Merge pull request #35919 from yongtang/35333-carry

Carry #35333: Devicemapper: ignore Nodata errors when delete thin device
Sebastiaan van Stijn 7 years ago
parent
commit
db5c006bc8

+ 74 - 0
integration/container/stop_test.go

@@ -0,0 +1,74 @@
+package container
+
+import (
+	"context"
+	"fmt"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/api/types/network"
+	"github.com/docker/docker/client"
+	"github.com/docker/docker/integration/util/request"
+	"github.com/gotestyourself/gotestyourself/icmd"
+	"github.com/gotestyourself/gotestyourself/poll"
+	"github.com/gotestyourself/gotestyourself/skip"
+	"github.com/stretchr/testify/require"
+)
+
+func TestDeleteDevicemapper(t *testing.T) {
+	skip.IfCondition(t, testEnv.DaemonInfo.Driver != "devicemapper")
+
+	defer setupTest(t)()
+	client := request.NewAPIClient(t)
+	ctx := context.Background()
+
+	foo, err := client.ContainerCreate(ctx,
+		&container.Config{
+			Cmd:   []string{"echo"},
+			Image: "busybox",
+		},
+		&container.HostConfig{},
+		&network.NetworkingConfig{},
+		"foo",
+	)
+	require.NoError(t, err)
+
+	err = client.ContainerStart(ctx, foo.ID, types.ContainerStartOptions{})
+	require.NoError(t, err)
+
+	inspect, err := client.ContainerInspect(ctx, foo.ID)
+	require.NoError(t, err)
+
+	poll.WaitOn(t, containerIsStopped(ctx, client, foo.ID), poll.WithDelay(100*time.Millisecond))
+
+	deviceID := inspect.GraphDriver.Data["DeviceId"]
+
+	// Find pool name from device name
+	deviceName := inspect.GraphDriver.Data["DeviceName"]
+	devicePrefix := deviceName[:strings.LastIndex(deviceName, "-")]
+	devicePool := fmt.Sprintf("/dev/mapper/%s-pool", devicePrefix)
+
+	result := icmd.RunCommand("dmsetup", "message", devicePool, "0", fmt.Sprintf("delete %s", deviceID))
+	result.Assert(t, icmd.Success)
+
+	err = client.ContainerRemove(ctx, foo.ID, types.ContainerRemoveOptions{})
+	require.NoError(t, err)
+}
+
+func containerIsStopped(ctx context.Context, client client.APIClient, containerID string) func(log poll.LogT) poll.Result {
+	return func(log poll.LogT) poll.Result {
+		inspect, err := client.ContainerInspect(ctx, containerID)
+
+		switch {
+		case err != nil:
+			return poll.Error(err)
+		case !inspect.State.Running:
+			return poll.Success()
+		default:
+			return poll.Continue("waiting for container to be stopped")
+		}
+	}
+}

+ 10 - 3
pkg/devicemapper/devmapper.go

@@ -67,12 +67,14 @@ var (
 	ErrBusy                 = errors.New("Device is Busy")
 	ErrDeviceIDExists       = errors.New("Device Id Exists")
 	ErrEnxio                = errors.New("No such device or address")
+	ErrEnoData              = errors.New("No data available")
 )
 
 var (
-	dmSawBusy  bool
-	dmSawExist bool
-	dmSawEnxio bool // No Such Device or Address
+	dmSawBusy    bool
+	dmSawExist   bool
+	dmSawEnxio   bool // No Such Device or Address
+	dmSawEnoData bool // No data available
 )
 
 type (
@@ -708,10 +710,15 @@ func DeleteDevice(poolName string, deviceID int) error {
 	}
 
 	dmSawBusy = false
+	dmSawEnoData = false
 	if err := task.run(); err != nil {
 		if dmSawBusy {
 			return ErrBusy
 		}
+		if dmSawEnoData {
+			logrus.Debugf("devicemapper: Device(id: %d) from pool(%s) does not exist", deviceID, poolName)
+			return nil
+		}
 		return fmt.Errorf("devicemapper: Error running DeleteDevice %s", err)
 	}
 	return nil

+ 3 - 0
pkg/devicemapper/devmapper_log.go

@@ -55,6 +55,9 @@ func DevmapperLogCallback(level C.int, file *C.char, line, dmErrnoOrClass C.int,
 		if strings.Contains(msg, "No such device or address") {
 			dmSawEnxio = true
 		}
+		if strings.Contains(msg, "No data available") {
+			dmSawEnoData = true
+		}
 	}
 
 	if dmLogger != nil {