summaryrefslogtreecommitdiffstats
path: root/src/test/librbd/test_notify.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/librbd/test_notify.py')
-rwxr-xr-xsrc/test/librbd/test_notify.py183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/test/librbd/test_notify.py b/src/test/librbd/test_notify.py
new file mode 100755
index 000000000..4e929d74f
--- /dev/null
+++ b/src/test/librbd/test_notify.py
@@ -0,0 +1,183 @@
+#!/usr/bin/python3
+import os
+import sys
+import time
+
+from rados import Rados
+from rbd import (RBD,
+ Image,
+ ImageNotFound,
+ RBD_FEATURE_EXCLUSIVE_LOCK,
+ RBD_FEATURE_LAYERING,
+ RBD_FEATURE_OBJECT_MAP,
+ RBD_FEATURE_FAST_DIFF,
+ RBD_FLAG_OBJECT_MAP_INVALID)
+
+POOL_NAME='rbd'
+PARENT_IMG_NAME='test_notify_parent'
+CLONE_IMG_NAME='test_notify_clone'
+CLONE_IMG_RENAME='test_notify_clone2'
+IMG_SIZE = 16 << 20
+IMG_ORDER = 20
+
+def delete_image(ioctx, img_name):
+ image = Image(ioctx, img_name)
+ for snap in image.list_snaps():
+ snap_name = snap['name']
+ print("removing snapshot: %s@%s" % (img_name, snap_name))
+ if image.is_protected_snap(snap_name):
+ image.unprotect_snap(snap_name)
+ image.remove_snap(snap_name)
+ image.close()
+ print("removing image: %s" % img_name)
+ RBD().remove(ioctx, img_name)
+
+def safe_delete_image(ioctx, img_name):
+ try:
+ delete_image(ioctx, img_name)
+ except ImageNotFound:
+ pass
+
+def get_features():
+ features = os.getenv("RBD_FEATURES")
+ if features is not None:
+ features = int(features)
+ else:
+ features = int(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_LAYERING |
+ RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF)
+ assert((features & RBD_FEATURE_EXCLUSIVE_LOCK) != 0)
+ assert((features & RBD_FEATURE_LAYERING) != 0)
+ assert((features & RBD_FEATURE_OBJECT_MAP) != 0)
+ assert((features & RBD_FEATURE_FAST_DIFF) != 0)
+ return features
+
+def master(ioctx):
+ print("starting master")
+ safe_delete_image(ioctx, CLONE_IMG_RENAME)
+ safe_delete_image(ioctx, CLONE_IMG_NAME)
+ safe_delete_image(ioctx, PARENT_IMG_NAME)
+
+ features = get_features()
+ RBD().create(ioctx, PARENT_IMG_NAME, IMG_SIZE, IMG_ORDER, old_format=False,
+ features=features)
+ with Image(ioctx, PARENT_IMG_NAME) as image:
+ image.create_snap('snap1')
+ image.protect_snap('snap1')
+
+ features = features & ~(RBD_FEATURE_FAST_DIFF)
+ RBD().clone(ioctx, PARENT_IMG_NAME, 'snap1', ioctx, CLONE_IMG_NAME,
+ features=features)
+ with Image(ioctx, CLONE_IMG_NAME) as image:
+ print("acquiring exclusive lock")
+ offset = 0
+ data = os.urandom(512)
+ while offset < IMG_SIZE:
+ image.write(data, offset)
+ offset += (1 << IMG_ORDER)
+ image.write(b'1', IMG_SIZE - 1)
+ assert(image.is_exclusive_lock_owner())
+
+ print("waiting for slave to complete")
+ while image.is_exclusive_lock_owner():
+ time.sleep(5)
+
+ safe_delete_image(ioctx, CLONE_IMG_RENAME)
+ safe_delete_image(ioctx, CLONE_IMG_NAME)
+ delete_image(ioctx, PARENT_IMG_NAME)
+ print("finished")
+
+def slave(ioctx):
+ print("starting slave")
+
+ while True:
+ try:
+ with Image(ioctx, CLONE_IMG_NAME) as image:
+ if (image.list_lockers() != [] and
+ image.read(IMG_SIZE - 1, 1) == b'1'):
+ break
+ except Exception:
+ pass
+
+ print("detected master")
+
+ print("rename")
+ RBD().rename(ioctx, CLONE_IMG_NAME, CLONE_IMG_RENAME);
+
+ with Image(ioctx, CLONE_IMG_RENAME) as image:
+ print("flatten")
+ image.flatten()
+ assert(not image.is_exclusive_lock_owner())
+
+ print("resize")
+ image.resize(IMG_SIZE // 2)
+ assert(not image.is_exclusive_lock_owner())
+ assert(image.stat()['size'] == IMG_SIZE // 2)
+
+ print("create_snap")
+ image.create_snap('snap1')
+ assert(not image.is_exclusive_lock_owner())
+ assert(any(snap['name'] == 'snap1'
+ for snap in image.list_snaps()))
+
+ print("protect_snap")
+ image.protect_snap('snap1')
+ assert(not image.is_exclusive_lock_owner())
+ assert(image.is_protected_snap('snap1'))
+
+ print("unprotect_snap")
+ image.unprotect_snap('snap1')
+ assert(not image.is_exclusive_lock_owner())
+ assert(not image.is_protected_snap('snap1'))
+
+ print("rename_snap")
+ image.rename_snap('snap1', 'snap1-new')
+ assert(not image.is_exclusive_lock_owner())
+ assert(any(snap['name'] == 'snap1-new'
+ for snap in image.list_snaps()))
+
+ print("remove_snap")
+ image.remove_snap('snap1-new')
+ assert(not image.is_exclusive_lock_owner())
+ assert(list(image.list_snaps()) == [])
+
+ if 'RBD_DISABLE_UPDATE_FEATURES' not in os.environ:
+ print("update_features")
+ assert((image.features() & RBD_FEATURE_OBJECT_MAP) != 0)
+ image.update_features(RBD_FEATURE_OBJECT_MAP, False)
+ assert(not image.is_exclusive_lock_owner())
+ assert((image.features() & RBD_FEATURE_OBJECT_MAP) == 0)
+ image.update_features(RBD_FEATURE_OBJECT_MAP, True)
+ assert(not image.is_exclusive_lock_owner())
+ assert((image.features() & RBD_FEATURE_OBJECT_MAP) != 0)
+ assert((image.flags() & RBD_FLAG_OBJECT_MAP_INVALID) != 0)
+ else:
+ print("skipping update_features")
+
+ print("rebuild object map")
+ image.rebuild_object_map()
+ assert(not image.is_exclusive_lock_owner())
+ assert((image.flags() & RBD_FLAG_OBJECT_MAP_INVALID) == 0)
+
+ print("write")
+ data = os.urandom(512)
+ image.write(data, 0)
+ assert(image.is_exclusive_lock_owner())
+
+ print("finished")
+
+def main():
+ if len(sys.argv) != 2 or sys.argv[1] not in ['master', 'slave']:
+ print("usage: %s: [master/slave]" % sys.argv[0])
+ sys.exit(2)
+
+ rados = Rados(conffile='')
+ rados.connect()
+ ioctx = rados.open_ioctx(POOL_NAME)
+ if sys.argv[1] == 'master':
+ master(ioctx)
+ else:
+ slave(ioctx)
+ rados.shutdown()
+
+if __name__ == "__main__":
+ main()