소스 검색

devicemapper: Compare uuid of base device on startup

It is easy for one to use docker for a while, shut it down and restart
docker with different set of storage options for device mapper driver
which will effectively change the thin pool. That means any of the
metadata stored in /var/lib/docker/devicemapper/metadata/ is not valid
for the new pool and user will run into various kind of issues like
container not found in the pool etc.

Users think that their images or containers are lost but it might just
be the case of configuration issue. People might use wrong metadata
with wrong pool.

To detect such situations, save UUID of base image and once docker
starts later, query and compare the UUID of base image with the
stored one. If they don't match, fail the initialization with the
error that UUID failed to match.

That way user will be forced to cleanup /var/lib/docker/ directory
and start docker again.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Vivek Goyal 10 년 전
부모
커밋
c06b05b11e
1개의 변경된 파일67개의 추가작업 그리고 1개의 파일을 삭제
  1. 67 1
      daemon/graphdriver/devmapper/deviceset.go

+ 67 - 1
daemon/graphdriver/devmapper/deviceset.go

@@ -105,7 +105,8 @@ type DeviceSet struct {
 	thinPoolDevice        string
 	thinPoolDevice        string
 	Transaction           `json:"-"`
 	Transaction           `json:"-"`
 	overrideUdevSyncCheck bool
 	overrideUdevSyncCheck bool
-	deferredRemove        bool // use deferred removal
+	deferredRemove        bool   // use deferred removal
+	BaseDeviceUUID        string //save UUID of base device
 }
 }
 
 
 type DiskUsage struct {
 type DiskUsage struct {
@@ -669,9 +670,70 @@ func (devices *DeviceSet) loadMetadata(hash string) *DevInfo {
 	return info
 	return info
 }
 }
 
 
+func getDeviceUUID(device string) (string, error) {
+	out, err := exec.Command("blkid", "-s", "UUID", "-o", "value", device).Output()
+	if err != nil {
+		logrus.Debugf("Failed to find uuid for device %s:%v", device, err)
+		return "", err
+	}
+
+	uuid := strings.TrimSuffix(string(out), "\n")
+	uuid = strings.TrimSpace(uuid)
+	logrus.Debugf("UUID for device: %s is:%s", device, uuid)
+	return uuid, nil
+}
+
+func (devices *DeviceSet) verifyBaseDeviceUUID(baseInfo *DevInfo) error {
+	if err := devices.activateDeviceIfNeeded(baseInfo); err != nil {
+		return err
+	}
+
+	defer devices.deactivateDevice(baseInfo)
+
+	uuid, err := getDeviceUUID(baseInfo.DevName())
+	if err != nil {
+		return err
+	}
+
+	if devices.BaseDeviceUUID != uuid {
+		return fmt.Errorf("Current Base Device UUID:%s does not match with stored UUID:%s", uuid, devices.BaseDeviceUUID)
+	}
+
+	return nil
+}
+
+func (devices *DeviceSet) saveBaseDeviceUUID(baseInfo *DevInfo) error {
+	if err := devices.activateDeviceIfNeeded(baseInfo); err != nil {
+		return err
+	}
+
+	defer devices.deactivateDevice(baseInfo)
+
+	uuid, err := getDeviceUUID(baseInfo.DevName())
+	if err != nil {
+		return err
+	}
+
+	devices.BaseDeviceUUID = uuid
+	devices.saveDeviceSetMetaData()
+	return nil
+}
+
 func (devices *DeviceSet) setupBaseImage() error {
 func (devices *DeviceSet) setupBaseImage() error {
 	oldInfo, _ := devices.lookupDevice("")
 	oldInfo, _ := devices.lookupDevice("")
 	if oldInfo != nil && oldInfo.Initialized {
 	if oldInfo != nil && oldInfo.Initialized {
+		// If BaseDeviceUUID is nil (upgrade case), save it and
+		// return success.
+		if devices.BaseDeviceUUID == "" {
+			if err := devices.saveBaseDeviceUUID(oldInfo); err != nil {
+				return fmt.Errorf("Could not query and save base device UUID:%v", err)
+			}
+			return nil
+		}
+
+		if err := devices.verifyBaseDeviceUUID(oldInfo); err != nil {
+			return fmt.Errorf("Base Device UUID verification failed. Possibly using a different thin pool then last invocation:%v", err)
+		}
 		return nil
 		return nil
 	}
 	}
 
 
@@ -721,6 +783,10 @@ func (devices *DeviceSet) setupBaseImage() error {
 		return err
 		return err
 	}
 	}
 
 
+	if err := devices.saveBaseDeviceUUID(info); err != nil {
+		return fmt.Errorf("Could not query and save base device UUID:%v", err)
+	}
+
 	return nil
 	return nil
 }
 }