Skip to content

Commit 6614735

Browse files
committed
Added cli commands for recording management
1 parent 6f48bbe commit 6614735

2 files changed

Lines changed: 186 additions & 0 deletions

File tree

bbblb/cli/recording.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import click
2+
import sqlalchemy.orm
3+
4+
from bbblb import model
5+
6+
from bbblb.services import ServiceRegistry
7+
from bbblb.services.db import DBContext
8+
from bbblb.services.recording import RecordingManager
9+
10+
from . import main, async_command
11+
12+
13+
@main.group()
14+
def recording():
15+
"""Recording management."""
16+
17+
18+
@recording.command("list")
19+
@async_command()
20+
async def _list(obj: ServiceRegistry):
21+
"""List all recordings and their formats"""
22+
db = await obj.use("db", DBContext)
23+
async with db.session() as session, session.begin():
24+
stmt = model.Recording.select().options(
25+
sqlalchemy.orm.joinedload(model.Recording.tenant),
26+
sqlalchemy.orm.selectinload(model.Recording.formats),
27+
)
28+
for record in (await session.execute(stmt)).scalars():
29+
click.echo(
30+
f"{record.tenant.name} {record.record_id} {','.join(f.format for f in record.formats)}"
31+
)
32+
33+
34+
@recording.command("delete")
35+
@click.argument("record_id", nargs=-1)
36+
@async_command()
37+
async def _delete(obj: ServiceRegistry, record_id):
38+
"""Delete recordings (all formats)"""
39+
importer = await obj.use("importer", RecordingManager)
40+
41+
db = await obj.use("db", DBContext)
42+
async with db.session() as session, session.begin():
43+
stmt = model.Recording.select(model.Recording.record_id.in_(record_id))
44+
for record in (await session.execute(stmt)).scalars().all():
45+
await session.delete(record)
46+
importer.delete(record.tenant.name, record.record_id)
47+
click.echo(f"Deleted {record.record_id}")
48+
49+
50+
@recording.command("import")
51+
@click.option("--tenant", help="Override the tenant found in the recording")
52+
@click.argument("FILE", type=click.Path(dir_okay=True), default="-")
53+
@async_command()
54+
async def _import(obj: ServiceRegistry, tenant: str, file: str):
55+
"""Import one or more recordings from a tar archive"""
56+
obj.get("importer", RecordingManager, uninitialized_ok=True).auto_import = False
57+
importer = await obj.use("importer", RecordingManager)
58+
59+
async def reader(file):
60+
with click.open_file(file, "rb") as fp:
61+
while chunk := fp.read(1024 * 64):
62+
yield chunk
63+
64+
task = await importer.start_import(reader(file), force_tenant=tenant)
65+
await task.wait()
66+
if task.error:
67+
click.echo(f"ERROR {task.error}")
68+
raise SystemExit(1)
69+
click.echo("OK")
70+
71+
72+
@recording.command()
73+
@click.option(
74+
"--dry-run", "-n", help="Simulate changes without changing anything.", is_flag=True
75+
)
76+
@async_command()
77+
async def remove_orphans(obj: ServiceRegistry, dry_run: bool):
78+
"""Remove recording DB entries that do not exist on disk."""
79+
db = await obj.use("db", DBContext)
80+
importer = await obj.use("importer", RecordingManager)
81+
async with db.session() as session, session.begin():
82+
stmt = model.Recording.select().options(
83+
sqlalchemy.orm.joinedload(model.Recording.tenant),
84+
sqlalchemy.orm.selectinload(model.Recording.formats),
85+
)
86+
records = await session.execute(stmt)
87+
for record in records.scalars():
88+
populated = False
89+
for format in record.formats:
90+
sdir = importer.get_storage_dir(
91+
record.tenant.name,
92+
record.record_id,
93+
format.format,
94+
)
95+
if sdir.exists():
96+
populated = True
97+
continue
98+
click.echo(
99+
f"Deleting orphan format: {record.tenant.name}/{record.record_id}/{format.format}"
100+
)
101+
await session.delete(format)
102+
if not populated:
103+
click.echo(
104+
f"Deleting record without formats: {record.tenant.name}/{record.record_id}"
105+
)
106+
await session.delete(record)
107+
108+
if dry_run:
109+
click.echo("Rolling back changes (dry run)")
110+
await session.rollback()

docs/_click.rst

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ bbblb
2222
========= ===============================================================================
2323
db Manage database
2424
maketoken Generate an Admin Token that can be used to authenticate against the BBBLB API.
25+
recording Recording management.
2526
server Manage servers
2627
state Tools to export and import cluster state in JSON files.
2728
tenant Manage tenants
@@ -91,6 +92,81 @@ coded because tenants or servers can create their own tokens.
9192
SCOPE Optional argument
9293
==================== ======================================================================
9394

95+
recording
96+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
97+
98+
``Usage: bbblb recording [OPTIONS] COMMAND [ARGS]...``
99+
100+
Recording management.
101+
102+
.. table:: Sub-Commands
103+
:width: 100%
104+
105+
============== ======================================================
106+
Command Help
107+
============== ======================================================
108+
list List all recordings and their formats
109+
delete Delete recordings (all formats)
110+
import Import one or more recordings from a tar archive
111+
remove-orphans Remove recording DB entries that do not exist on disk.
112+
============== ======================================================
113+
114+
recording list
115+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116+
117+
``Usage: bbblb recording list [OPTIONS]``
118+
119+
List all recordings and their formats
120+
121+
recording delete
122+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123+
124+
``Usage: bbblb recording delete [OPTIONS] [RECORD_ID]...``
125+
126+
Delete recordings (all formats)
127+
128+
.. table:: Options
129+
:width: 100%
130+
131+
========= =================
132+
Option Help
133+
========= =================
134+
RECORD_ID Optional argument
135+
========= =================
136+
137+
recording import
138+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
139+
140+
``Usage: bbblb recording import [OPTIONS] [FILE]``
141+
142+
Import one or more recordings from a tar archive
143+
144+
.. table:: Options
145+
:width: 100%
146+
147+
============= ==========================================
148+
Option Help
149+
============= ==========================================
150+
--tenant TEXT Override the tenant found in the recording
151+
FILE Optional argument
152+
============= ==========================================
153+
154+
recording remove-orphans
155+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
156+
157+
``Usage: bbblb recording remove-orphans [OPTIONS]``
158+
159+
Remove recording DB entries that do not exist on disk.
160+
161+
.. table:: Options
162+
:width: 100%
163+
164+
============= ===========================================
165+
Option Help
166+
============= ===========================================
167+
-n, --dry-run Simulate changes without changing anything.
168+
============= ===========================================
169+
94170
server
95171
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
96172

0 commit comments

Comments
 (0)