Browse code

Merge pull request #35919 from yongtang/35333-carry

Carry #35333: Devicemapper: ignore Nodata errors when delete thin device

Sebastiaan van Stijn authored on 2018/01/21 02:47:16
Showing 3 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,74 @@
0
+package container
1
+
2
+import (
3
+	"context"
4
+	"fmt"
5
+	"strings"
6
+	"testing"
7
+	"time"
8
+
9
+	"github.com/docker/docker/api/types"
10
+	"github.com/docker/docker/api/types/container"
11
+	"github.com/docker/docker/api/types/network"
12
+	"github.com/docker/docker/client"
13
+	"github.com/docker/docker/integration/util/request"
14
+	"github.com/gotestyourself/gotestyourself/icmd"
15
+	"github.com/gotestyourself/gotestyourself/poll"
16
+	"github.com/gotestyourself/gotestyourself/skip"
17
+	"github.com/stretchr/testify/require"
18
+)
19
+
20
+func TestDeleteDevicemapper(t *testing.T) {
21
+	skip.IfCondition(t, testEnv.DaemonInfo.Driver != "devicemapper")
22
+
23
+	defer setupTest(t)()
24
+	client := request.NewAPIClient(t)
25
+	ctx := context.Background()
26
+
27
+	foo, err := client.ContainerCreate(ctx,
28
+		&container.Config{
29
+			Cmd:   []string{"echo"},
30
+			Image: "busybox",
31
+		},
32
+		&container.HostConfig{},
33
+		&network.NetworkingConfig{},
34
+		"foo",
35
+	)
36
+	require.NoError(t, err)
37
+
38
+	err = client.ContainerStart(ctx, foo.ID, types.ContainerStartOptions{})
39
+	require.NoError(t, err)
40
+
41
+	inspect, err := client.ContainerInspect(ctx, foo.ID)
42
+	require.NoError(t, err)
43
+
44
+	poll.WaitOn(t, containerIsStopped(ctx, client, foo.ID), poll.WithDelay(100*time.Millisecond))
45
+
46
+	deviceID := inspect.GraphDriver.Data["DeviceId"]
47
+
48
+	// Find pool name from device name
49
+	deviceName := inspect.GraphDriver.Data["DeviceName"]
50
+	devicePrefix := deviceName[:strings.LastIndex(deviceName, "-")]
51
+	devicePool := fmt.Sprintf("/dev/mapper/%s-pool", devicePrefix)
52
+
53
+	result := icmd.RunCommand("dmsetup", "message", devicePool, "0", fmt.Sprintf("delete %s", deviceID))
54
+	result.Assert(t, icmd.Success)
55
+
56
+	err = client.ContainerRemove(ctx, foo.ID, types.ContainerRemoveOptions{})
57
+	require.NoError(t, err)
58
+}
59
+
60
+func containerIsStopped(ctx context.Context, client client.APIClient, containerID string) func(log poll.LogT) poll.Result {
61
+	return func(log poll.LogT) poll.Result {
62
+		inspect, err := client.ContainerInspect(ctx, containerID)
63
+
64
+		switch {
65
+		case err != nil:
66
+			return poll.Error(err)
67
+		case !inspect.State.Running:
68
+			return poll.Success()
69
+		default:
70
+			return poll.Continue("waiting for container to be stopped")
71
+		}
72
+	}
73
+}
... ...
@@ -67,12 +67,14 @@ var (
67 67
 	ErrBusy                 = errors.New("Device is Busy")
68 68
 	ErrDeviceIDExists       = errors.New("Device Id Exists")
69 69
 	ErrEnxio                = errors.New("No such device or address")
70
+	ErrEnoData              = errors.New("No data available")
70 71
 )
71 72
 
72 73
 var (
73
-	dmSawBusy  bool
74
-	dmSawExist bool
75
-	dmSawEnxio bool // No Such Device or Address
74
+	dmSawBusy    bool
75
+	dmSawExist   bool
76
+	dmSawEnxio   bool // No Such Device or Address
77
+	dmSawEnoData bool // No data available
76 78
 )
77 79
 
78 80
 type (
... ...
@@ -708,10 +710,15 @@ func DeleteDevice(poolName string, deviceID int) error {
708 708
 	}
709 709
 
710 710
 	dmSawBusy = false
711
+	dmSawEnoData = false
711 712
 	if err := task.run(); err != nil {
712 713
 		if dmSawBusy {
713 714
 			return ErrBusy
714 715
 		}
716
+		if dmSawEnoData {
717
+			logrus.Debugf("devicemapper: Device(id: %d) from pool(%s) does not exist", deviceID, poolName)
718
+			return nil
719
+		}
715 720
 		return fmt.Errorf("devicemapper: Error running DeleteDevice %s", err)
716 721
 	}
717 722
 	return nil
... ...
@@ -55,6 +55,9 @@ func DevmapperLogCallback(level C.int, file *C.char, line, dmErrnoOrClass C.int,
55 55
 		if strings.Contains(msg, "No such device or address") {
56 56
 			dmSawEnxio = true
57 57
 		}
58
+		if strings.Contains(msg, "No data available") {
59
+			dmSawEnoData = true
60
+		}
58 61
 	}
59 62
 
60 63
 	if dmLogger != nil {