File: imageio.py

package info (click to toggle)
nbdkit 1.42.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 14,696 kB
  • sloc: ansic: 59,224; sh: 16,793; makefile: 6,463; python: 1,837; cpp: 1,116; ml: 504; perl: 502; tcl: 62
file content (175 lines) | stat: -rw-r--r-- 4,440 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# Example Python plugin.
#
# This example can be freely used for any purpose.
#
# Upload and download images to oVirt with nbdkit and qemu-img.
#
# This assumes you have an oVirt environment. If you don't please see
# https://ovirt.org/ for info on how to install oVirt.
#
# Install ovirt-release package:
#
#  dnf install http://resources.ovirt.org/pub/yum-repo/ovirt-release-master.rpm
#
# Install required packages:
#
#   dnf install ovirt-imageio-client python3-ovirt-engine-sdk4
#
# Note: python3-ovirt-engine-sdk4 is not available yet for Fedora 31 and 32.
#
# To upload or download images, you need to start an image transfer. The
# easiest way is using oVirt image_transfer.py example:
#
#  /usr/share/doc/python3-ovirt-engine-sdk4/examples/image_transfer.py \
#      --engine-url https://my.engine \
#      --username admin@internal \
#      --password-file password \
#      --cafile my.engine.pem \
#      upload disk-uuid
#
# This will print the transfer URL for this image transfer.
#
# Run this example from the build directory:
#
#   ./nbdkit -t4 -f -v -U /tmp/nbd.sock python \
#       ./plugins/python/examples/imageio.py \
#       transfer_url=https://server:54322/images/ticket-id \
#       connections=4 \
#       secure=no
#
# Note that number of nbdkit threads and imageio connections should match.
#
# To upload an image run:
#
#   qemu-img convert -n -f raw -O raw -W disk.img \
#       nbd+unix:///\?socket=/tmp/nbd.sock
#
# Downloading image is not efficient with this version, since we don't report
# extents yet.
#
# The -f -v arguments are optional.  They cause the server to stay in
# the foreground and print debugging, which is useful when testing.

import queue
from contextlib import contextmanager

from ovirt_imageio.client import ImageioClient

import nbdkit

# Using version 2 supporting the buffer protocol for better performance.
API_VERSION = 2

# Plugin configuration, can be set using key=value in the command line.
params = {
    "secure": True,
    "ca_file": "",
    "connections": 1,
    "transfer_url": None,
}


def config(key, value):
    """
    Parse the url parameter which contains the transfer URL that we want to
    serve.
    """
    if key == "transfer_url":
        params["transfer_url"] = value
    elif key == "connections":
        params["connections"] = int(value)
    elif key == "ca_file":
        params["ca_file"] = value
    elif key == "secure":
        params["secure"] = boolify(key, value)
    else:
        raise RuntimeError("unknown parameter: {!r}".format(key))


def boolify(key, value):
    v = value.lower()
    if v in ("yes", "true", "1"):
        return True
    if v in ("no", "false", 0):
        return False
    raise RuntimeError("Invalid boolean value for {}: {!r}".format(key, value))


def config_complete():
    """
    Called when configuration is completed.
    """
    if params["transfer_url"] is None:
        raise RuntimeError("'transfer_url' parameter is required")


def thread_model():
    """
    Using parallel model to speed up transfer with multiple connections to
    imageio server.
    """
    return nbdkit.THREAD_MODEL_PARALLEL


def open(readonly):
    """
    Called once when plugin is loaded. We create a pool of connected clients
    that will be used for requests later.
    """
    pool = queue.Queue()
    for i in range(params["connections"]):
        client = ImageioClient(
            params["transfer_url"],
            cafile=params["ca_file"],
            secure=params["secure"])
        pool.put(client)
    return {"pool": pool}


def close(h):
    """
    Called when plugin is closed. Close and remove all clients from the pool.
    """
    pool = h["pool"]
    while not pool.empty():
        client = pool.get()
        client.close()


@contextmanager
def client(h):
    """
    Context manager fetching an imageio client from the pool. Blocks until a
    client is available.
    """
    pool = h["pool"]
    client = pool.get()
    try:
        yield client
    finally:
        pool.put(client)


def get_size(h):
    with client(h) as c:
        return c.size()


def pread(h, buf, offset, flags):
    with client(h) as c:
        c.read(offset, buf)


def pwrite(h, buf, offset, flags):
    with client(h) as c:
        c.write(offset, buf)


def zero(h, count, offset, flags):
    with client(h) as c:
        c.zero(offset, count)


def flush(h, flags):
    with client(h) as c:
        c.flush()