mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 09:22:44 +00:00
force rbd image unlock if the image is not used
Signed-off-by: Huamin Chen <hchen@redhat.com>
This commit is contained in:
parent
2509ab0c7a
commit
71406aa4a6
@ -43,6 +43,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
imageWatcherStr = "watcher="
|
imageWatcherStr = "watcher="
|
||||||
|
kubeLockMagic = "kubelet_lock_magic_"
|
||||||
)
|
)
|
||||||
|
|
||||||
// search /sys/bus for rbd device that matches given pool and image
|
// search /sys/bus for rbd device that matches given pool and image
|
||||||
@ -114,8 +115,15 @@ func (util *RBDUtil) rbdLock(b rbdMounter, lock bool) error {
|
|||||||
} else {
|
} else {
|
||||||
secret_opt = []string{"-k", b.Keyring}
|
secret_opt = []string{"-k", b.Keyring}
|
||||||
}
|
}
|
||||||
|
if len(b.adminId) == 0 {
|
||||||
|
b.adminId = b.Id
|
||||||
|
}
|
||||||
|
if len(b.adminSecret) == 0 {
|
||||||
|
b.adminSecret = b.Secret
|
||||||
|
}
|
||||||
|
|
||||||
// construct lock id using host name and a magic prefix
|
// construct lock id using host name and a magic prefix
|
||||||
lock_id := "kubelet_lock_magic_" + node.GetHostname("")
|
lock_id := kubeLockMagic + node.GetHostname("")
|
||||||
|
|
||||||
l := len(b.Mon)
|
l := len(b.Mon)
|
||||||
// avoid mount storm, pick a host randomly
|
// avoid mount storm, pick a host randomly
|
||||||
@ -130,7 +138,7 @@ func (util *RBDUtil) rbdLock(b rbdMounter, lock bool) error {
|
|||||||
cmd, err = b.plugin.execCommand("rbd",
|
cmd, err = b.plugin.execCommand("rbd",
|
||||||
append([]string{"lock", "list", b.Image, "--pool", b.Pool, "--id", b.Id, "-m", mon}, secret_opt...))
|
append([]string{"lock", "list", b.Image, "--pool", b.Pool, "--id", b.Id, "-m", mon}, secret_opt...))
|
||||||
output = string(cmd)
|
output = string(cmd)
|
||||||
|
glog.Infof("lock list output %q", output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -142,6 +150,23 @@ func (util *RBDUtil) rbdLock(b rbdMounter, lock bool) error {
|
|||||||
glog.V(1).Infof("rbd: lock already held for %s", lock_id)
|
glog.V(1).Infof("rbd: lock already held for %s", lock_id)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// clean up orphaned lock if no watcher on the image
|
||||||
|
used, statusErr := util.rbdStatus(&b)
|
||||||
|
if statusErr == nil && !used {
|
||||||
|
re := regexp.MustCompile("client.* " + kubeLockMagic + ".*")
|
||||||
|
locks := re.FindAllStringSubmatch(output, -1)
|
||||||
|
for _, v := range locks {
|
||||||
|
if len(v) > 0 {
|
||||||
|
lockInfo := strings.Split(v[0], " ")
|
||||||
|
if len(lockInfo) > 2 {
|
||||||
|
cmd, err = b.plugin.execCommand("rbd",
|
||||||
|
append([]string{"lock", "remove", b.Image, lockInfo[1], lockInfo[0], "--pool", b.Pool, "--id", b.Id, "-m", mon}, secret_opt...))
|
||||||
|
glog.Infof("remove orphaned locker %s from client %s: err %v, output: %s", lockInfo[1], lockInfo[0], err, string(cmd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// hold a lock: rbd lock add
|
// hold a lock: rbd lock add
|
||||||
cmd, err = b.plugin.execCommand("rbd",
|
cmd, err = b.plugin.execCommand("rbd",
|
||||||
append([]string{"lock", "add", b.Image, lock_id, "--pool", b.Pool, "--id", b.Id, "-m", mon}, secret_opt...))
|
append([]string{"lock", "add", b.Image, lock_id, "--pool", b.Pool, "--id", b.Id, "-m", mon}, secret_opt...))
|
||||||
@ -220,6 +245,20 @@ func (util *RBDUtil) AttachDisk(b rbdMounter) error {
|
|||||||
var err error
|
var err error
|
||||||
var output []byte
|
var output []byte
|
||||||
|
|
||||||
|
// create mount point
|
||||||
|
globalPDPath := b.manager.MakeGlobalPDName(*b.rbd)
|
||||||
|
notMnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath)
|
||||||
|
// in the first time, the path shouldn't exist and IsLikelyNotMountPoint is expected to get NotExist
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("rbd: %s failed to check mountpoint", globalPDPath)
|
||||||
|
}
|
||||||
|
if !notMnt {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err = os.MkdirAll(globalPDPath, 0750); err != nil {
|
||||||
|
return fmt.Errorf("rbd: failed to mkdir %s, error", globalPDPath)
|
||||||
|
}
|
||||||
|
|
||||||
devicePath, found := waitForPath(b.Pool, b.Image, 1)
|
devicePath, found := waitForPath(b.Pool, b.Image, 1)
|
||||||
if !found {
|
if !found {
|
||||||
// modprobe
|
// modprobe
|
||||||
@ -227,6 +266,18 @@ func (util *RBDUtil) AttachDisk(b rbdMounter) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("rbd: failed to modprobe rbd error:%v", err)
|
return fmt.Errorf("rbd: failed to modprobe rbd error:%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fence off other mappers
|
||||||
|
if err = util.fencing(b); err != nil {
|
||||||
|
return fmt.Errorf("rbd: image %s is locked by other nodes", b.Image)
|
||||||
|
}
|
||||||
|
// rbd lock remove needs ceph and image config
|
||||||
|
// but kubelet doesn't get them from apiserver during teardown
|
||||||
|
// so persit rbd config so upon disk detach, rbd lock can be removed
|
||||||
|
// since rbd json is persisted in the same local directory that is used as rbd mountpoint later,
|
||||||
|
// the json file remains invisible during rbd mount and thus won't be removed accidentally.
|
||||||
|
util.persistRBD(b, globalPDPath)
|
||||||
|
|
||||||
// rbd map
|
// rbd map
|
||||||
l := len(b.Mon)
|
l := len(b.Mon)
|
||||||
// avoid mount storm, pick a host randomly
|
// avoid mount storm, pick a host randomly
|
||||||
@ -255,34 +306,8 @@ func (util *RBDUtil) AttachDisk(b rbdMounter) error {
|
|||||||
return errors.New("Could not map image: Timeout after 10s")
|
return errors.New("Could not map image: Timeout after 10s")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mount it
|
// mount it
|
||||||
globalPDPath := b.manager.MakeGlobalPDName(*b.rbd)
|
|
||||||
notMnt, err := b.mounter.IsLikelyNotMountPoint(globalPDPath)
|
|
||||||
// in the first time, the path shouldn't exist and IsLikelyNotMountPoint is expected to get NotExist
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("rbd: %s failed to check mountpoint", globalPDPath)
|
|
||||||
}
|
|
||||||
if !notMnt {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.MkdirAll(globalPDPath, 0750); err != nil {
|
|
||||||
return fmt.Errorf("rbd: failed to mkdir %s, error", globalPDPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fence off other mappers
|
|
||||||
if err := util.fencing(b); err != nil {
|
|
||||||
// rbd unmap before exit
|
|
||||||
b.plugin.execCommand("rbd", []string{"unmap", devicePath})
|
|
||||||
return fmt.Errorf("rbd: image %s is locked by other nodes", b.Image)
|
|
||||||
}
|
|
||||||
// rbd lock remove needs ceph and image config
|
|
||||||
// but kubelet doesn't get them from apiserver during teardown
|
|
||||||
// so persit rbd config so upon disk detach, rbd lock can be removed
|
|
||||||
// since rbd json is persisted in the same local directory that is used as rbd mountpoint later,
|
|
||||||
// the json file remains invisible during rbd mount and thus won't be removed accidentally.
|
|
||||||
util.persistRBD(b, globalPDPath)
|
|
||||||
|
|
||||||
if err = b.mounter.FormatAndMount(devicePath, globalPDPath, b.fsType, nil); err != nil {
|
if err = b.mounter.FormatAndMount(devicePath, globalPDPath, b.fsType, nil); err != nil {
|
||||||
err = fmt.Errorf("rbd: failed to mount rbd volume %s [%s] to %s, error %v", devicePath, b.fsType, globalPDPath, err)
|
err = fmt.Errorf("rbd: failed to mount rbd volume %s [%s] to %s, error %v", devicePath, b.fsType, globalPDPath, err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user