summaryrefslogtreecommitdiff
path: root/examples/sparsestream.py
diff options
context:
space:
mode:
authorMichal Privoznik <mprivozn@redhat.com>2017-05-22 11:10:09 +0200
committerMichal Privoznik <mprivozn@redhat.com>2017-05-24 13:32:41 +0200
commit9b98fe2d6f1dbd51d9689f1a730f20fc2fe1ee1d (patch)
tree0fe579107dc7bcf1c84f660fe0be20a69cb04ce6 /examples/sparsestream.py
parentd7e1c976f483df9dc21e4ae8814970e21e1ae9da (diff)
downloadlibvirt-python-9b98fe2d6f1dbd51d9689f1a730f20fc2fe1ee1d.tar.gz
examples: Introduce sparsestream.py
Sparse streams are not that straight forward to use for the very first time. Especially the sparseRecvAll() and sparseSendAll() methods which expects callbacks. What we can do to make it easier for developers is to have an example where they can take an inspiration from. Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Diffstat (limited to 'examples/sparsestream.py')
-rwxr-xr-xexamples/sparsestream.py117
1 files changed, 117 insertions, 0 deletions
diff --git a/examples/sparsestream.py b/examples/sparsestream.py
new file mode 100755
index 0000000..e960c40
--- /dev/null
+++ b/examples/sparsestream.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+# Example of sparse streams usage
+#
+# Authors:
+# Michal Privoznik <mprivozn@redhat.com>
+
+import libvirt, sys, os
+
+def bytesWriteHandler(stream, buf, opaque):
+ fd = opaque
+ return os.write(fd, buf)
+
+def bytesReadHandler(stream, nbytes, opaque):
+ fd = opaque
+ return os.read(fd, nbytes)
+
+def recvSkipHandler(stream, length, opaque):
+ fd = opaque
+ cur = os.lseek(fd, length, os.SEEK_CUR)
+ return os.ftruncate(fd, cur)
+
+def sendSkipHandler(stream, length, opaque):
+ fd = opaque
+ return os.lseek(fd, length, os.SEEK_CUR)
+
+def holeHandler(stream, opaque):
+ fd = opaque
+ cur = os.lseek(fd, 0, os.SEEK_CUR)
+
+ try:
+ data = os.lseek(fd, cur, os.SEEK_DATA)
+ except OSError as e:
+ if e.errno != 6:
+ raise e
+ else:
+ data = -1;
+ # There are three options:
+ # 1) data == cur; @cur is in data
+ # 2) data > cur; @cur is in a hole, next data at @data
+ # 3) data < 0; either @cur is in trailing hole, or @cur is beyond EOF.
+ if data < 0:
+ # case 3
+ inData = False
+ eof = os.lseek(fd, 0, os.SEEK_END)
+ if (eof < cur):
+ raise RuntimeError("Current position in file after EOF: %d" % cur)
+ sectionLen = eof - cur
+ else:
+ if (data > cur):
+ # case 2
+ inData = False
+ sectionLen = data - cur
+ else:
+ # case 1
+ inData = True
+
+ # We don't know where does the next hole start. Let's find out.
+ # Here we get the same options as above
+ hole = os.lseek(fd, data, os.SEEK_HOLE)
+ if hole < 0:
+ # case 3. But wait a second. There is always a trailing hole.
+ # Do the best what we can here
+ raise RuntimeError("No trailing hole")
+
+ if (hole == data):
+ # case 1. Again, this is suspicious. The reason we are here is
+ # because we are in data. But at the same time we are in a
+ # hole. WAT?
+ raise RuntimeError("Impossible happened")
+ else:
+ # case 2
+ sectionLen = hole - data
+ os.lseek(fd, cur, os.SEEK_SET)
+ return [inData, sectionLen]
+
+def download(vol, st, filename):
+ offset = 0
+ length = 0
+
+ fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, mode=0o0660)
+ vol.download(st, offset, length, libvirt.VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM)
+ st.sparseRecvAll(bytesWriteHandler, recvSkipHandler, fd)
+
+ os.close(fd)
+
+def upload(vol, st, filename):
+ offset = 0
+ length = 0
+
+ fd = os.open(filename, os.O_RDONLY)
+ vol.upload(st, offset, length, libvirt.VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM)
+ st.sparseSendAll(bytesReadHandler, holeHandler, sendSkipHandler, fd)
+
+ os.close(fd)
+
+# main
+if len(sys.argv) != 5:
+ print("Usage: ", sys.argv[0], " URI --upload/--download VOLUME FILE")
+ print("Either uploads local FILE to libvirt VOLUME, or downloads libvirt ")
+ print("VOLUME into local FILE while preserving FILE/VOLUME sparseness")
+ sys.exit(1)
+
+conn = libvirt.open(sys.argv[1])
+vol = conn.storageVolLookupByKey(sys.argv[3])
+
+st = conn.newStream()
+
+if sys.argv[2] == "--download":
+ download(vol, st, sys.argv[4])
+elif sys.argv[2] == "--upload":
+ upload(vol, st, sys.argv[4])
+else:
+ print("Unknown operation: %s " % sys.argv[1])
+ sys.exit(1)
+
+st.finish()
+conn.close()