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

Commit 7f52e46

Browse files
committed
Use Lease related methods from client service
1 parent 4447987 commit 7f52e46

5 files changed

Lines changed: 28 additions & 241 deletions

File tree

packages/jumpstarter/conftest.py

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from jumpstarter_protocol import (
1717
jumpstarter_pb2,
1818
jumpstarter_pb2_grpc,
19-
kubernetes_pb2,
2019
router_pb2_grpc,
2120
)
2221

@@ -59,60 +58,6 @@ async def Register(self, request, context):
5958
async def Unregister(self, request, context):
6059
return jumpstarter_pb2.UnregisterResponse()
6160

62-
async def RequestLease(self, request, context):
63-
lease_name = str(uuid4())
64-
if "unsatisfiable" in request.selector.match_labels:
65-
self.leases[lease_name] = "unsatisfiable"
66-
else:
67-
self.leases[lease_name] = 0
68-
await self.status[0].send(
69-
jumpstarter_pb2.StatusResponse(leased=True, lease_name=lease_name, client_name="dummy")
70-
)
71-
return jumpstarter_pb2.RequestLeaseResponse(name=lease_name)
72-
73-
async def GetLease(self, request, context):
74-
if self.leases[request.name] == "unsatisfiable":
75-
return jumpstarter_pb2.GetLeaseResponse(
76-
exporter_uuid=str(uuid4()),
77-
conditions=[
78-
kubernetes_pb2.Condition(
79-
type="Unsatisfiable",
80-
status="True",
81-
),
82-
],
83-
)
84-
85-
self.leases[request.name] += 1
86-
if self.leases[request.name] == 1:
87-
return jumpstarter_pb2.GetLeaseResponse(
88-
exporter_uuid=str(uuid4()),
89-
conditions=[],
90-
)
91-
if self.leases[request.name] == 2:
92-
return jumpstarter_pb2.GetLeaseResponse(
93-
exporter_uuid=str(uuid4()),
94-
conditions=[
95-
kubernetes_pb2.Condition(
96-
type="Pending",
97-
status="True",
98-
),
99-
],
100-
)
101-
else:
102-
return jumpstarter_pb2.GetLeaseResponse(
103-
exporter_uuid=str(uuid4()),
104-
conditions=[
105-
kubernetes_pb2.Condition(
106-
type="Ready",
107-
status="True",
108-
),
109-
],
110-
)
111-
112-
async def ReleaseLease(self, request, context):
113-
await self.status[0].send(jumpstarter_pb2.StatusResponse(leased=False))
114-
return jumpstarter_pb2.ReleaseLeaseResponse()
115-
11661
async def Dial(self, request, context):
11762
token = str(uuid4())
11863
await self.queue[0].send(token)

packages/jumpstarter/jumpstarter/client/lease.py

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77
contextmanager,
88
)
99
from dataclasses import dataclass, field
10+
from datetime import timedelta
1011

1112
from anyio import fail_after, sleep
1213
from anyio.from_thread import BlockingPortal
13-
from google.protobuf import duration_pb2
1414
from grpc.aio import Channel
15-
from jumpstarter_protocol import jumpstarter_pb2, jumpstarter_pb2_grpc, kubernetes_pb2
15+
from jumpstarter_protocol import jumpstarter_pb2, jumpstarter_pb2_grpc
1616

1717
from .exceptions import LeaseError
1818
from jumpstarter.client import client_from_path
19+
from jumpstarter.client.grpc import ClientService
1920
from jumpstarter.common import MetadataFilter, TemporaryUnixListener
2021
from jumpstarter.common.condition import condition_false, condition_message, condition_present_and_equal, condition_true
2122
from jumpstarter.common.grpc import translate_grpc_exceptions
@@ -31,6 +32,7 @@ class Lease(AbstractContextManager, AbstractAsyncContextManager):
3132
timeout: int = 1800
3233
metadata_filter: MetadataFilter = field(default_factory=MetadataFilter)
3334
portal: BlockingPortal
35+
namespace: str
3436
name: str | None = field(default=None)
3537
allow: list[str]
3638
unsafe: bool
@@ -43,24 +45,23 @@ def __post_init__(self):
4345
super().__post_init__()
4446

4547
self.controller = jumpstarter_pb2_grpc.ControllerServiceStub(self.channel)
48+
self.svc = ClientService(channel=self.channel)
4649
self.manager = self.portal.wrap_async_context_manager(self)
4750

4851
async def _create(self):
49-
duration = duration_pb2.Duration()
50-
duration.FromSeconds(self.timeout)
51-
duration_str = str(duration.ToTimedelta())
52+
duration = timedelta(seconds=self.timeout)
53+
selector = ",".join(("{}={}".format(label[0], label[1]) for label in self.metadata_filter.labels.items()))
5254

53-
logger.debug("Creating lease request for labels %s for %s", self.metadata_filter.labels, duration_str)
55+
logger.debug("Creating lease request for selector %s for duration %s", selector, duration)
5456
with translate_grpc_exceptions():
5557
self.name = (
56-
await self.controller.RequestLease(
57-
jumpstarter_pb2.RequestLeaseRequest(
58-
duration=duration,
59-
selector=kubernetes_pb2.LabelSelector(match_labels=self.metadata_filter.labels),
60-
)
58+
await self.svc.CreateLease(
59+
namespace=self.namespace,
60+
selector=selector,
61+
duration=timedelta(seconds=self.timeout),
6162
)
6263
).name
63-
logger.info("Created lease request for labels %s for %s", self.metadata_filter.labels, duration_str)
64+
logger.info("Created lease request for selector %s for duration %s", selector, duration)
6465

6566
def request(self):
6667
"""Request a lease, or verifies a lease which was already created.
@@ -97,7 +98,10 @@ async def _acquire(self):
9798
while True:
9899
logger.debug("Polling Lease %s", self.name)
99100
with translate_grpc_exceptions():
100-
result = await self.controller.GetLease(jumpstarter_pb2.GetLeaseRequest(name=self.name))
101+
result = await self.svc.GetLease(
102+
namespace=self.namespace,
103+
name=self.name,
104+
)
101105

102106
# lease ready
103107
if condition_true(result.conditions, "Ready"):
@@ -131,7 +135,10 @@ async def __aenter__(self):
131135
async def __aexit__(self, exc_type, exc_value, traceback):
132136
if self.release:
133137
logger.info("Releasing Lease %s", self.name)
134-
await self.controller.ReleaseLease(jumpstarter_pb2.ReleaseLeaseRequest(name=self.name))
138+
await self.svc.DeleteLease(
139+
namespace=self.namespace,
140+
name=self.name,
141+
)
135142

136143
def __enter__(self):
137144
# wraps the async context manager enter

packages/jumpstarter/jumpstarter/config/client.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import grpc
77
import yaml
88
from anyio.from_thread import BlockingPortal, start_blocking_portal
9-
from jumpstarter_protocol import jumpstarter_pb2, jumpstarter_pb2_grpc
109
from pydantic import BaseModel, ConfigDict, Field, ValidationError
1110

1211
from .common import CONFIG_PATH, ObjectMeta
@@ -118,6 +117,7 @@ async def request_lease_async(
118117

119118
lease = Lease(
120119
channel=await self.channel(),
120+
namespace=self.metadata.namespace,
121121
name=None,
122122
metadata_filter=metadata_filter,
123123
portal=portal,
@@ -129,14 +129,15 @@ async def request_lease_async(
129129
return await lease.request_async()
130130

131131
async def list_leases_async(self):
132-
controller = jumpstarter_pb2_grpc.ControllerServiceStub(await self.channel())
132+
svc = ClientService(channel=await self.channel())
133133
with translate_grpc_exceptions():
134-
return (await controller.ListLeases(jumpstarter_pb2.ListLeasesRequest())).names
134+
result = await svc.ListLeases(namespace=self.metadata.namespace)
135+
return [lease.name for lease in result.leases]
135136

136137
async def release_lease_async(self, name):
137-
controller = jumpstarter_pb2_grpc.ControllerServiceStub(await self.channel())
138+
svc = ClientService(channel=await self.channel())
138139
with translate_grpc_exceptions():
139-
await controller.ReleaseLease(jumpstarter_pb2.ReleaseLeaseRequest(name=name))
140+
await svc.DeleteLease(namespace=self.metadata.namespace, name=name)
140141

141142
@asynccontextmanager
142143
async def lease_async(
@@ -154,6 +155,7 @@ async def lease_async(
154155

155156
async with Lease(
156157
channel=await self.channel(),
158+
namespace=self.metadata.namespace,
157159
name=lease_name,
158160
metadata_filter=metadata_filter,
159161
portal=portal,

packages/jumpstarter/jumpstarter/config/exporter_test.py

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,14 @@
1-
from contextlib import ExitStack
21
from pathlib import Path
32

43
import pytest
5-
from anyio import create_task_group
6-
from anyio.from_thread import start_blocking_portal
74

8-
from .client import ClientConfigV1Alpha1, ClientConfigV1Alpha1Drivers
95
from .common import ObjectMeta
106
from .exporter import ExporterConfigV1Alpha1, ExporterConfigV1Alpha1DriverInstance
117
from .tls import TLSConfigV1Alpha1
12-
from jumpstarter.common import MetadataFilter
138

149
pytestmark = pytest.mark.anyio
1510

1611

17-
async def test_exporter_serve(mock_controller):
18-
exporter = ExporterConfigV1Alpha1(
19-
apiVersion="jumpstarter.dev/v1alpha1",
20-
kind="ExporterConfig",
21-
metadata=ObjectMeta(namespace="default", name="test"),
22-
endpoint=mock_controller,
23-
token="dummy-exporter-token",
24-
export={
25-
"power": ExporterConfigV1Alpha1DriverInstance(
26-
type="jumpstarter_driver_power.driver.MockPower",
27-
),
28-
"nested": ExporterConfigV1Alpha1DriverInstance(
29-
children={
30-
"tcp": ExporterConfigV1Alpha1DriverInstance(
31-
type="jumpstarter_driver_network.driver.TcpNetwork",
32-
config={
33-
"host": "127.0.0.1",
34-
"port": 8080,
35-
},
36-
)
37-
}
38-
),
39-
},
40-
)
41-
42-
client = ClientConfigV1Alpha1(
43-
name="testclient",
44-
metadata=ObjectMeta(namespace="default", name="testclient"),
45-
endpoint=mock_controller,
46-
token="dummy-client-token",
47-
drivers=ClientConfigV1Alpha1Drivers(allow=[], unsafe=True),
48-
tls=TLSConfigV1Alpha1(insecure=True),
49-
)
50-
51-
async with create_task_group() as tg:
52-
tg.start_soon(exporter.serve)
53-
54-
with start_blocking_portal() as portal:
55-
async with client.lease_async(
56-
metadata_filter=MetadataFilter(),
57-
lease_name=None,
58-
portal=portal,
59-
) as lease:
60-
with ExitStack() as stack:
61-
async with lease.connect_async(stack) as client:
62-
await client.power.call_async("on")
63-
assert hasattr(client.nested, "tcp")
64-
65-
tg.cancel_scope.cancel()
66-
67-
6812
def test_exporter_config(monkeypatch: pytest.MonkeyPatch, tmp_path: Path):
6913
monkeypatch.setattr(ExporterConfigV1Alpha1, "BASE_PATH", tmp_path)
7014

packages/jumpstarter/jumpstarter/listener_test.py

Lines changed: 0 additions & 111 deletions
This file was deleted.

0 commit comments

Comments
 (0)