Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

options: Report image format and virtual size #6

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions docs/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,25 @@ When using multiple writers, each writer should modify a distinct byte
range. If two writers modify the same byte range concurrently they will
overwrite each other data.

### transfer_format

The transfer data format. Always available when using the `nbd` and
`memory` backends, not available when using the `file` backend. When
using the `http` backend `transfer_format` is available only if the
remote server reports it.

Since 2.4.6.

### virtual_size

The underlying image virtual size. Available only when the backend is
using `raw` transfer format. Always available when using the `nbd` and
`memory` backends, not available when using the `file` backend. When
using the `http` backend the `virtual_size` is available only if the
remote server reports it.

Since 2.4.6.

### Errors

Specific errors for OPTIONS request:
Expand Down Expand Up @@ -112,9 +131,9 @@ Response:
Content-Length: 122

{"unix_socket": "\u0000/org/ovirt/imageio", "features": ["extents", "zero", "flush"],
"max_readers": 8, "max_writers": 8}
"max_readers": 8, "max_writers": 8, "transfer_format": "raw", "virtual_size": 53687091200}

Get options for ticket-id with read-write access using nbd backend:
Get options for ticket-id with read-write access using `nbd` backend:

$ curl -k -X OPTIONS https://server:54322/images/{ticket-id} | jq
{
Expand All @@ -125,11 +144,13 @@ Get options for ticket-id with read-write access using nbd backend:
"flush"
],
"max_readers": 8,
"max_writers": 8
"max_writers": 8,
"transfer_format": "raw",
"virtual_size": 53687091200
aesteve-rh marked this conversation as resolved.
Show resolved Hide resolved
}

The nbd backend is used when specifying the "raw" transfer format when
creating an image transfer in oVirt API.
The nbd backend is used when creating an image transfer with
format="raw" in oVirt API.

Get options for ticket-id with read-only access using file backend:

Expand All @@ -143,6 +164,9 @@ Get options for ticket-id with read-only access using file backend:
"max_writers": 1
}

Note that `virtual_size` and `transfer_format` are not reported, and this
backend does not support multiple writers.

Get all available options for the special `*` ticket:

$ curl -sk -X OPTIONS 'https://server:54322/images/*' | jq
Expand Down Expand Up @@ -268,7 +292,7 @@ Since 2.0

Request zero extents:

GET /images/{ticket-id}/extent
GET /images/{ticket-id}/extents

Response:

Expand All @@ -280,7 +304,7 @@ Response:

Request dirty extents:

GET /images/{ticket-id}/extent?context=dirty
GET /images/{ticket-id}/extents?context=dirty

Response:

Expand Down
7 changes: 7 additions & 0 deletions ovirt_imageio/_internal/backends/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ def __init__(self, fio, sparse=False, max_connections=8):
def max_readers(self):
return self._max_connections

@property
def format(self):
"""
Currently we don't have access to the underlying disk format.
aesteve-rh marked this conversation as resolved.
Show resolved Hide resolved
"""
return None

# io.FileIO interface

def readinto(self, buf):
Expand Down
36 changes: 29 additions & 7 deletions ovirt_imageio/_internal/backends/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ def __init__(self, url, cafile=None, secure=True, connect_timeout=10,
self._connect_timeout = connect_timeout
self._read_timeout = read_timeout
self._position = 0
self._size = None
self._extents = {}

# Initlized during connection.
Expand All @@ -74,6 +73,8 @@ def __init__(self, url, cafile=None, secure=True, connect_timeout=10,
self._can_flush = False
self._max_readers = 1
self._max_writers = 1
self._format = None
self._size = None

if connect:
self._connect()
Expand Down Expand Up @@ -104,8 +105,10 @@ def clone(self):
backend._can_flush = self._can_flush
backend._max_readers = self._max_readers
backend._max_writers = self._max_writers
backend._format = self._format

# Copy size and extents to save expensive EXTENTS calls.
# Copy extents and size to save expensive EXTENTS calls with old
# imageio servers.
backend._size = self._size
for ctx in list(self._extents):
backend._extents[ctx] = self._extents[ctx].copy()
Expand Down Expand Up @@ -133,6 +136,10 @@ def _connect(self):
# max_writers does not support multiple writers.
self._max_writers = options.get("max_writers", 1)

# Newer server reports also transfer_format and virtual_size.
self._format = options.get("transfer_format")
self._size = options.get("virtual_size")

self._optimize_connection(options.get("unix_socket"))
except Exception:
self._con.close()
Expand All @@ -155,6 +162,14 @@ def max_readers(self):
def max_writers(self):
return self._max_writers

@property
def format(self):
"""
Will be None for old server (imageio < 2.4.6) or when server is using
file backend.
"""
return self._format

# Preferred interface.

def read_from(self, reader, length, buf):
Expand Down Expand Up @@ -325,10 +340,17 @@ def seek(self, n, how=os.SEEK_SET):
return self._position

def size(self):
# We have 2 bad options:
# - Get last extent, may be slow, and may not be neded otherwise.
# - Emulate HEAD request, logging tracebacks in the remote server.
# Getting extents is more polite, so lets use it if we can.
"""
Return backend size in bytes.

With newer server (imageio >= 2.4.6) reporting the virtual size the
size is intialized in connect().

Otherwise we have 2 bad options:
- Get the last extent, may be slow, and may not be neded otherwise.
- Emulate HEAD request, logging tracebacks in the remote server.
Getting extents is more polite, so lets use it if we can.
"""
if self._size is None:
if self._can_extents:
last = list(self.extents())[-1]
Expand Down Expand Up @@ -454,7 +476,7 @@ def _put_header(self, length):
self._con.putheader("content-length", length)
self._con.putheader("content-type", "application/octet-stream")
self._con.putheader("content-range", "bytes {}-{}/*".format(
self._position, self._position + length - 1))
self._position, self._position + length - 1))

self._con.endheaders()

Expand Down
4 changes: 4 additions & 0 deletions ovirt_imageio/_internal/backends/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ def max_writers(self):
# support more than one writer concurrently.
return 1

@property
def format(self):
return "raw"

# io.BaseIO interface

def readinto(self, buf):
Expand Down
4 changes: 4 additions & 0 deletions ovirt_imageio/_internal/backends/nbd.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ def max_readers(self):
def max_writers(self):
return self._max_connections

@property
def format(self):
return "raw"

# Backend interface

def readinto(self, buf):
Expand Down
6 changes: 6 additions & 0 deletions ovirt_imageio/_internal/handlers/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,5 +268,11 @@ def options(self, req, resp, ticket_id):
options["max_readers"] = ctx.backend.max_readers
options["max_writers"] = ctx.backend.max_writers

# Optional backend options.
if ctx.backend.format is not None:
options["transfer_format"] = ctx.backend.format
if ctx.backend.format == "raw":
options["virtual_size"] = ctx.backend.size()

resp.headers["allow"] = ",".join(allow)
resp.send_json(options)
Loading