Skip to content

Commit

Permalink
ovirt-img: support json output
Browse files Browse the repository at this point in the history
Add json as an output option, to print
the progress in jsonlines[1] format.
A consistent machine readable format, that
can be later parsed.

$ ovirt-img  download-disk -c engine --output json <disk_id> download.raw
{"transferred": 0, elapsed: 0.0, "description": "setting up"}
...
{"transferred": 249561088, "size": 261095424, elapsed: 1.234567, "description": "downloading image"}
{"transferred": 256901120, "size": 261095424, elapsed: 1.345678, "description": "downloading image"}
{"transferred": 261095424, "size": 261095424, elapsed: 1.456789, "description": "finalizing transfer"}
...

[1] https://jsonlines.org/

Fixes: #154
Signed-off-by: Albert Esteve <aesteve@redhat.com>
  • Loading branch information
aesteve-rh committed Nov 24, 2022
1 parent e0fcbb2 commit 84d96fd
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 2 deletions.
2 changes: 1 addition & 1 deletion ovirt_imageio/client/_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __repr__(self):


log_level = Choices("log_level", ("debug", "info", "warning", "error"))
output_format = Choices("output_format", ("text",))
output_format = Choices("output_format", ("text", "json"))


def bool_string(value):
Expand Down
19 changes: 19 additions & 0 deletions ovirt_imageio/client/_ui.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-FileCopyrightText: Red Hat, Inc.
# SPDX-License-Identifier: GPL-2.0-or-later

import json
import sys
import threading
import time
Expand All @@ -9,6 +10,7 @@


FORMAT_TEXT = "text"
FORMAT_JSON = "json"

DEFAULT_WIDTH = 79

Expand Down Expand Up @@ -54,8 +56,25 @@ def draw(self, elapsed, value, transferred, size=None,
self._write_line(line, end)


class JsonFormat(OutputFormat):

def draw(self, elapsed, value, transferred, size=None,
phase=None, last=False):
progress = {
'transferred': transferred,
'elapsed': elapsed,
'description': phase or "",
}
if size is not None:
progress["size"] = size

line = json.dumps(progress)
self._write_line(line)


OUTPUT_FORMAT = {
FORMAT_TEXT: TextFormat,
FORMAT_JSON: JsonFormat,
}


Expand Down
1 change: 1 addition & 0 deletions test/client_options_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ def test_transfer_options_disabled(config):

@pytest.mark.parametrize("output", [
"text",
"json",
])
def test_output_option(config, output):
parser = _options.Parser()
Expand Down
65 changes: 64 additions & 1 deletion test/client_ui_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later

import pytest
import json

from ovirt_imageio import client
from ovirt_imageio._internal.units import MiB, GiB
Expand All @@ -28,7 +29,7 @@ def flush(self):
pass


def test_draw():
def test_draw_text():
fake_time = FakeTime()
f = FakeFile()

Expand Down Expand Up @@ -84,6 +85,68 @@ def test_draw():
assert f.last == line.ljust(79) + "\n"


def test_draw_json():
fake_time = FakeTime()
f = FakeFile()

# Size is unknown at this point.
pb = client.ProgressBar(
phase="setting up", output=f, format="json", now=fake_time)
assert json.loads(f.last) == {
"transferred": 0,
"elapsed": 0.0,
"description": "setting up",
}

# Size was updated, but no bytes were transferred yet.
fake_time.now += 0.1
pb.size = 3 * GiB
assert json.loads(f.last) == {
"transferred": 0,
"elapsed": fake_time.now,
"description": "setting up",
"size": 3 * GiB,
}

# Phase was updated.
fake_time.now += 0.2
pb.phase = "downloading image"
assert json.loads(f.last) == {
"transferred": 0,
"elapsed": fake_time.now,
"description": "downloading image",
"size": 3 * GiB,
}

# All data transferred.
fake_time.now += 2.0
pb.update(3 * GiB)
assert json.loads(f.last) == {
"transferred": 3 * GiB,
"elapsed": fake_time.now,
"description": "downloading image",
"size": 3 * GiB,
}

# Cleaning up after download.
pb.phase = "cleaning up"
assert json.loads(f.last) == {
"transferred": 3 * GiB,
"elapsed": fake_time.now,
"description": "cleaning up",
"size": 3 * GiB,
}

# Closing prints the final line.
pb.close()
assert json.loads(f.last) == {
"transferred": 3 * GiB,
"elapsed": fake_time.now,
"description": "cleaning up",
"size": 3 * GiB,
}


def test_with_size():
fake_time = FakeTime()
f = FakeFile()
Expand Down

0 comments on commit 84d96fd

Please sign in to comment.