diff --git a/chi_edge/cli.py b/chi_edge/cli.py index 74cf579..e2a6a0a 100644 --- a/chi_edge/cli.py +++ b/chi_edge/cli.py @@ -203,7 +203,14 @@ def register( @device.command("list", cls=BaseCommand, short_help="list registered devices") -def list_all(): +@click.option( + "--long", + "long_", + is_flag=True, + default=False, + help="Show additional columns including project restrictions and contact.", +) +def list_all(long_: "bool" = False): with doni_error_handler("failed to list devices"): devices = doni_client().get("/v1/hardware/").json()["hardware"] table = make_table() @@ -212,6 +219,11 @@ def list_all(): table.add_column("Registered at") table.add_column("Health") table.add_column("Last seen") + if long_: + table.add_column("Type") + table.add_column("Restricted to") + table.add_column("Contact") + table.add_column("Local egress") for device in devices: balena_worker = None ok_workers, total_workers = 0, 0 @@ -222,7 +234,7 @@ def list_all(): if worker["worker_type"] == "balena": balena_worker = worker registration_state = f"{ok_workers}/{total_workers}" - table.add_row( + row = [ device["name"], device["uuid"], localize(device["created_at"]), @@ -230,7 +242,14 @@ def list_all(): localize(balena_worker["state_details"].get("last_seen", "--")) if balena_worker else "--", - ) + ] + if long_: + projects = device["properties"].get("authorized_projects") or [] + row.append(device["properties"].get("machine_name") or "--") + row.append(", ".join(projects) if projects else "public") + row.append(device["properties"].get("contact_email") or "--") + row.append(device["properties"].get("local_egress") or "--") + table.add_row(*row) console.print(table) diff --git a/tests/test_cli.py b/tests/test_cli.py index 80a7714..5b8c617 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,6 +1,7 @@ from unittest.mock import patch, MagicMock from click.testing import CliRunner +from rich.console import Console from chi_edge.cli import cli @@ -113,6 +114,52 @@ def test_device_list(): result = runner.invoke(cli, ["device", "list"]) assert result.exit_code == 0, result.output assert "iot-rpi4-01" in result.output + assert "Restricted" not in result.output + assert "Contact" not in result.output + + +def test_device_list_long_shows_extra_columns(): + restricted = { + **FAKE_DEVICE, + "name": "iot-rpi4-restricted", + "uuid": "11111111-1111-1111-1111-111111111111", + "properties": { + **FAKE_DEVICE["properties"], + "authorized_projects": ["proj-a", "proj-b"], + "local_egress": "allowed", + }, + } + public = { + **FAKE_DEVICE, + "name": "iot-rpi4-public", + "uuid": "22222222-2222-2222-2222-222222222222", + "properties": { + k: v + for k, v in FAKE_DEVICE["properties"].items() + if k != "authorized_projects" + }, + } + + mock_adapter = MagicMock() + mock_adapter.get.return_value.json.return_value = { + "hardware": [restricted, public], + } + + runner = CliRunner() + with ( + patch("chi_edge.cli.doni_client", return_value=mock_adapter), + patch("chi_edge.cli.console", Console(width=300)), + ): + result = runner.invoke(cli, ["device", "list", "--long"]) + assert result.exit_code == 0, result.output + for header in ("Type", "Restricted to", "Contact", "Local egress"): + assert header in result.output + assert "raspberrypi4-64" in result.output + assert "proj-a" in result.output + assert "proj-b" in result.output + assert "public" in result.output + assert "test@example.com" in result.output + assert "allowed" in result.output def test_device_show():