Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit 502f9d8

Browse files
show lease expected release time instead of start time
"jmp get exporters --with leases" shows lease status and when is the lease expiring. That's more useful that current start time which doesn't tell you for how long it may be held. "jmp get leases" now shows lease begin time (the time it was acquired) in addition to duration.
1 parent eee77e6 commit 502f9d8

2 files changed

Lines changed: 37 additions & 22 deletions

File tree

packages/jumpstarter/jumpstarter/client/grpc.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def add_display_columns(table, options: WithOptions = None):
3232
if options.show_leases:
3333
table.add_column("LEASED BY")
3434
table.add_column("LEASE STATUS")
35-
table.add_column("START TIME")
35+
table.add_column("EXPECTED RELEASE")
3636

3737

3838
def add_exporter_row(table, exporter, options: WithOptions = None, lease_info: tuple[str, str, str] | None = None):
@@ -45,10 +45,10 @@ def add_exporter_row(table, exporter, options: WithOptions = None, lease_info: t
4545
row_data.append(",".join(("{}={}".format(k, v) for k, v in sorted(exporter.labels.items()))))
4646
if options.show_leases:
4747
if lease_info:
48-
lease_client, lease_status, start_time = lease_info
48+
lease_client, lease_status, expected_release = lease_info
4949
else:
50-
lease_client, lease_status, start_time = "", "Available", ""
51-
row_data.extend([lease_client, lease_status, start_time])
50+
lease_client, lease_status, expected_release = "", "Available", ""
51+
row_data.extend([lease_client, lease_status, expected_release])
5252

5353
table.add_row(*row_data)
5454

@@ -97,10 +97,11 @@ def rich_add_rows(self, table, options: WithOptions = None):
9797
if options and options.show_leases and self.lease:
9898
lease_client = self.lease.client
9999
lease_status = self.lease.get_status()
100-
start_time = ""
101-
if self.lease.effective_begin_time:
102-
start_time = self.lease.effective_begin_time.strftime("%Y-%m-%d %H:%M:%S")
103-
lease_info = (lease_client, lease_status, start_time)
100+
expected_release = ""
101+
if self.lease.effective_begin_time and self.lease.effective_duration:
102+
release_time = self.lease.effective_begin_time + self.lease.effective_duration
103+
expected_release = release_time.strftime("%Y-%m-%d %H:%M:%S")
104+
lease_info = (lease_client, lease_status, expected_release)
104105
elif options and options.show_leases:
105106
lease_info = ("", "Available", "")
106107
add_exporter_row(table, self, options, lease_info)
@@ -165,15 +166,25 @@ def from_protobuf(cls, data: client_pb2.Lease) -> Lease:
165166
def rich_add_columns(cls, table):
166167
table.add_column("NAME", no_wrap=True)
167168
table.add_column("SELECTOR")
169+
table.add_column("BEGIN TIME")
168170
table.add_column("DURATION")
169171
table.add_column("CLIENT")
170172
table.add_column("EXPORTER")
171173

172174
def rich_add_rows(self, table):
175+
begin_time = ""
176+
if self.effective_begin_time:
177+
begin_time = self.effective_begin_time.strftime("%Y-%m-%d %H:%M:%S")
178+
179+
duration = ""
180+
if self.effective_duration:
181+
duration = str(self.effective_duration)
182+
173183
table.add_row(
174184
self.name,
175185
self.selector,
176-
str(self.duration),
186+
begin_time,
187+
duration,
177188
self.client,
178189
self.exporter,
179190
)

packages/jumpstarter/jumpstarter/client/grpc_test.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from datetime import datetime
1+
from datetime import datetime, timedelta
22
from io import StringIO
33
from unittest.mock import Mock
44

@@ -48,15 +48,15 @@ def test_with_leases_columns(self):
4848
add_display_columns(table, options)
4949

5050
columns = [col.header for col in table.columns]
51-
assert columns == ["NAME", "LABELS", "LEASED BY", "LEASE STATUS", "START TIME"]
51+
assert columns == ["NAME", "LABELS", "LEASED BY", "LEASE STATUS", "EXPECTED RELEASE"]
5252

5353
def test_with_all_columns(self):
5454
table = Table()
5555
options = WithOptions(show_online=True, show_leases=True)
5656
add_display_columns(table, options)
5757

5858
columns = [col.header for col in table.columns]
59-
assert columns == ["NAME", "ONLINE", "LABELS", "LEASED BY", "LEASE STATUS", "START TIME"]
59+
assert columns == ["NAME", "ONLINE", "LABELS", "LEASED BY", "LEASE STATUS", "EXPECTED RELEASE"]
6060

6161

6262
class TestAddExporterRow:
@@ -91,7 +91,7 @@ def test_row_with_lease_info(self):
9191
add_exporter_row(table, exporter, options, lease_info)
9292

9393
assert len(table.rows) == 1
94-
assert len(table.columns) == 5 # NAME, LABELS, LEASED BY, LEASE STATUS, START TIME
94+
assert len(table.columns) == 5 # NAME, LABELS, LEASED BY, LEASE STATUS, EXPECTED RELEASE
9595

9696
def test_row_with_lease_info_available(self):
9797
table = Table()
@@ -115,7 +115,7 @@ def test_row_with_all_options(self):
115115
add_exporter_row(table, exporter, options, lease_info)
116116

117117
assert len(table.rows) == 1
118-
assert len(table.columns) == 6 # NAME, ONLINE, LABELS, LEASED BY, LEASE STATUS, START TIME
118+
assert len(table.columns) == 6 # NAME, ONLINE, LABELS, LEASED BY, LEASE STATUS, EXPECTED RELEASE
119119

120120

121121
class TestExporterList:
@@ -124,6 +124,7 @@ def create_test_lease(self, client="test-client", status="Active"):
124124
lease.client = client
125125
lease.get_status.return_value = status
126126
lease.effective_begin_time = datetime(2023, 1, 1, 10, 0, 0)
127+
lease.effective_duration = timedelta(hours=1)
127128
return lease
128129

129130
def test_exporter_without_lease(self):
@@ -175,7 +176,7 @@ def test_exporter_with_lease_display(self):
175176
exporter.rich_add_rows(table, options)
176177

177178
assert len(table.rows) == 1
178-
assert len(table.columns) == 5 # NAME, LABELS, LEASED BY, LEASE STATUS, START TIME
179+
assert len(table.columns) == 5 # NAME, LABELS, LEASED BY, LEASE STATUS, EXPECTED RELEASE
179180

180181
# Test actual table content by rendering it
181182
console = Console(file=StringIO(), width=120)
@@ -187,7 +188,7 @@ def test_exporter_with_lease_display(self):
187188
assert "type=device" in output
188189
assert "test-client" in output
189190
assert "Active" in output
190-
assert "2023-01-01 10:00:00" in output
191+
assert "2023-01-01 11:00:00" in output # Expected release: begin_time (10:00:00) + duration (1h)
191192

192193
def test_exporter_without_lease_but_show_leases(self):
193194
exporter = Exporter(
@@ -203,7 +204,7 @@ def test_exporter_without_lease_but_show_leases(self):
203204
exporter.rich_add_rows(table, options)
204205

205206
assert len(table.rows) == 1
206-
assert len(table.columns) == 5 # NAME, LABELS, LEASED BY, LEASE STATUS, START TIME
207+
assert len(table.columns) == 5 # NAME, LABELS, LEASED BY, LEASE STATUS, EXPECTED RELEASE
207208

208209
# Test actual table content by rendering it
209210
console = Console(file=StringIO(), width=120)
@@ -285,7 +286,7 @@ def test_exporter_all_features_display(self):
285286
exporter_offline_no_lease.rich_add_rows(table, options)
286287

287288
assert len(table.rows) == 2
288-
assert len(table.columns) == 6 # NAME, ONLINE, LABELS, LEASED BY, LEASE STATUS, START TIME
289+
assert len(table.columns) == 6 # NAME, ONLINE, LABELS, LEASED BY, LEASE STATUS, EXPECTED RELEASE
289290

290291
# Test actual table content by rendering it
291292
console = Console(file=StringIO(), width=150)
@@ -302,7 +303,7 @@ def test_exporter_all_features_display(self):
302303
assert "full-test-client" in output # Lease client
303304
assert "Active" in output # Lease status
304305
assert "Available" in output # Available status for no lease
305-
assert "2023-01-01 10:00:00" in output # Lease start time
306+
assert "2023-01-01 11:00:00" in output # Expected release time (begin_time + duration)
306307

307308
def test_exporter_lease_info_extraction(self):
308309
"""Test that lease information is correctly extracted from lease objects"""
@@ -325,10 +326,13 @@ def test_exporter_lease_info_extraction(self):
325326
if options.show_leases and exporter.lease:
326327
lease_client = exporter.lease.client
327328
lease_status = exporter.lease.get_status()
328-
start_time = exporter.lease.effective_begin_time.strftime("%Y-%m-%d %H:%M:%S")
329-
lease_info = (lease_client, lease_status, start_time)
329+
expected_release = ""
330+
if exporter.lease.effective_begin_time and exporter.lease.effective_duration:
331+
release_time = exporter.lease.effective_begin_time + exporter.lease.effective_duration
332+
expected_release = release_time.strftime("%Y-%m-%d %H:%M:%S")
333+
lease_info = (lease_client, lease_status, expected_release)
330334

331-
assert lease_info == ("my-client", "Expired", "2023-01-01 10:00:00")
335+
assert lease_info == ("my-client", "Expired", "2023-01-01 11:00:00")
332336

333337
def test_exporter_no_lease_info_extraction(self):
334338
"""Test that default lease information is used when no lease exists"""

0 commit comments

Comments
 (0)