diff --git a/docs/source/cli/run-tests.md b/docs/source/cli/run-tests.md index bd02d1e40..9706e7951 100644 --- a/docs/source/cli/run-tests.md +++ b/docs/source/cli/run-tests.md @@ -46,7 +46,7 @@ the base class will attempt to: 1. Use a local connection based on the `JUMPSTARTER_HOST` environment variable 2. Use an existing lease based on the `JMP_LEASE` environment variable, and existing credentials. See the cli reference for [jmp lease request](../cli-reference/jmp.md#jmp-lease-request). -3. Request a lease based on the `filter_labels` provided in the test class. +3. Request a lease based on the `selector` provided in the test class. ```{eval-rst} .. autoclass:: jumpstarter_testing.pytest.JumpstarterTest diff --git a/examples/soc-pytest/jumpstarter_example_soc_pytest/test_on_rpi4.py b/examples/soc-pytest/jumpstarter_example_soc_pytest/test_on_rpi4.py index 9b40f1c02..353ac8bf6 100644 --- a/examples/soc-pytest/jumpstarter_example_soc_pytest/test_on_rpi4.py +++ b/examples/soc-pytest/jumpstarter_example_soc_pytest/test_on_rpi4.py @@ -14,7 +14,7 @@ class TestResource(JumpstarterTest): - filter_labels = {"board": "rpi4"} + selector = "board=rpi4" @pytest.fixture() def console(self, client): diff --git a/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py b/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py index 5d0168f73..985c10000 100644 --- a/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py +++ b/packages/jumpstarter-cli-client/jumpstarter_cli_client/client_shell.py @@ -3,8 +3,7 @@ import asyncclick as click from jumpstarter_cli_common.exceptions import handle_exceptions -from .common import opt_config, opt_selector_simple, selector_to_labels -from jumpstarter.common import MetadataFilter +from .common import opt_config, opt_selector_simple from jumpstarter.common.utils import launch_shell @@ -18,9 +17,7 @@ def client_shell(config, selector: str, lease_name): exit_code = 0 - with config.lease( - metadata_filter=MetadataFilter(labels=selector_to_labels(selector)), lease_name=lease_name - ) as lease: + with config.lease(selector=selector, lease_name=lease_name) as lease: with lease.serve_unix() as path: with lease.monitor(): exit_code = launch_shell(path, "remote", config.drivers.allow, config.drivers.unsafe) diff --git a/packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py b/packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py index 665f2fe84..26c9fd64e 100644 --- a/packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py +++ b/packages/jumpstarter-cli-client/jumpstarter_cli_client/common.py @@ -24,11 +24,6 @@ ) -def selector_to_labels(selector: str): - # TODO: support complex selectors (e.g. !=) - return dict([term.split("=") for term in selector.split(",")]) - - class ClientParamType(click.ParamType): name = "client" diff --git a/packages/jumpstarter-driver-dutlink/examples/dutlink.py b/packages/jumpstarter-driver-dutlink/examples/dutlink.py index 80add81a9..bda1994d0 100755 --- a/packages/jumpstarter-driver-dutlink/examples/dutlink.py +++ b/packages/jumpstarter-driver-dutlink/examples/dutlink.py @@ -8,9 +8,8 @@ from jumpstarter.common.utils import env # initialize client from exporter config -# from jumpstarter.common import MetadataFilter # from jumpstarter.config.client import ClientConfigV1Alpha1 -# with ClientConfigV1Alpha1.load("default").lease(metadata_filter=MetadataFilter()) as lease: +# with ClientConfigV1Alpha1.load("default").lease(selector="example.com/board=dutlink") as lease: # with lease.connect() as client: # initialize client from environment diff --git a/packages/jumpstarter-driver-tftp/examples/tftp_test.py b/packages/jumpstarter-driver-tftp/examples/tftp_test.py index c5aa221cb..5423fb4ad 100644 --- a/packages/jumpstarter-driver-tftp/examples/tftp_test.py +++ b/packages/jumpstarter-driver-tftp/examples/tftp_test.py @@ -8,7 +8,7 @@ class TestResource(JumpstarterTest): - filter_labels = {"board": "rpi4"} + selector = "board=rpi4" @pytest.fixture() def setup_tftp(self, client): diff --git a/packages/jumpstarter-testing/jumpstarter_testing/pytest.py b/packages/jumpstarter-testing/jumpstarter_testing/pytest.py index 7d3908c8d..660496120 100644 --- a/packages/jumpstarter-testing/jumpstarter_testing/pytest.py +++ b/packages/jumpstarter-testing/jumpstarter_testing/pytest.py @@ -4,7 +4,6 @@ import pytest -from jumpstarter.common import MetadataFilter from jumpstarter.common.utils import env from jumpstarter.config.client import ClientConfigV1Alpha1 @@ -19,7 +18,7 @@ class JumpstarterTest: Looks for the `JUMPSTARTER_HOST` environment variable to connect to an established Jumpstarter shell, otherwise it will try to acquire a lease - for a single exporter using the filter_labels annotation. + for a single exporter using the selector annotation. i.e.: .. code-block:: python @@ -33,7 +32,7 @@ class JumpstarterTest: log = logging.getLogger(__name__) class TestResource(JumpstarterTest): - filter_labels = {"board":"rpi4"} + selector = "board=rpi4" @pytest.fixture() def console(self, client): @@ -49,7 +48,7 @@ def test_setup_device(self, client, console): """ - filter_labels: ClassVar[dict[str, str]] + selector: ClassVar[str] @pytest.fixture(scope="class") def client(self): @@ -57,9 +56,9 @@ def client(self): with env() as client: yield client except RuntimeError: - labels = getattr(self, "filter_labels", {}) + selector = getattr(self, "selector", None) config = ClientConfigV1Alpha1.load("default") - with config.lease(metadata_filter=MetadataFilter(labels=labels)) as lease: + with config.lease(selector=selector) as lease: with lease.connect() as client: yield client # BUG workaround: make sure that grpc servers get the client/lease release properly diff --git a/packages/jumpstarter/jumpstarter/client/lease.py b/packages/jumpstarter/jumpstarter/client/lease.py index 3ae519678..dc4cbcab7 100644 --- a/packages/jumpstarter/jumpstarter/client/lease.py +++ b/packages/jumpstarter/jumpstarter/client/lease.py @@ -18,7 +18,7 @@ from .exceptions import LeaseError from jumpstarter.client import client_from_path from jumpstarter.client.grpc import ClientService -from jumpstarter.common import MetadataFilter, TemporaryUnixListener +from jumpstarter.common import TemporaryUnixListener from jumpstarter.common.condition import condition_false, condition_message, condition_present_and_equal, condition_true from jumpstarter.common.grpc import translate_grpc_exceptions from jumpstarter.common.streams import connect_router_stream @@ -31,7 +31,7 @@ class Lease(AbstractContextManager, AbstractAsyncContextManager): channel: Channel timeout: int = 1800 - metadata_filter: MetadataFilter = field(default_factory=MetadataFilter) + selector: str portal: BlockingPortal namespace: str name: str | None = field(default=None) @@ -52,17 +52,16 @@ def __post_init__(self): async def _create(self): duration = timedelta(seconds=self.timeout) - selector = ",".join(("{}={}".format(label[0], label[1]) for label in self.metadata_filter.labels.items())) - logger.debug("Creating lease request for selector %s for duration %s", selector, duration) + logger.debug("Creating lease request for selector %s for duration %s", self.selector, duration) with translate_grpc_exceptions(): self.name = ( await self.svc.CreateLease( - selector=selector, + selector=self.selector, duration=timedelta(seconds=self.timeout), ) ).name - logger.info("Created lease request for selector %s for duration %s", selector, duration) + logger.info("Created lease request for selector %s for duration %s", self.selector, duration) async def get(self): with translate_grpc_exceptions(): diff --git a/packages/jumpstarter/jumpstarter/common/__init__.py b/packages/jumpstarter/jumpstarter/common/__init__.py index f4960f4eb..13058cb09 100644 --- a/packages/jumpstarter/jumpstarter/common/__init__.py +++ b/packages/jumpstarter/jumpstarter/common/__init__.py @@ -1,4 +1,4 @@ -from .metadata import Metadata, MetadataFilter +from .metadata import Metadata from .tempfile import TemporarySocket, TemporaryTcpListener, TemporaryUnixListener -__all__ = ["Metadata", "MetadataFilter", "TemporarySocket", "TemporaryUnixListener", "TemporaryTcpListener"] +__all__ = ["Metadata", "TemporarySocket", "TemporaryUnixListener", "TemporaryTcpListener"] diff --git a/packages/jumpstarter/jumpstarter/common/metadata.py b/packages/jumpstarter/jumpstarter/common/metadata.py index fbacc96e6..cb9309fff 100644 --- a/packages/jumpstarter/jumpstarter/common/metadata.py +++ b/packages/jumpstarter/jumpstarter/common/metadata.py @@ -12,8 +12,3 @@ class Metadata: @property def name(self): return self.labels.get("jumpstarter.dev/name", "unknown") - - -@dataclass(kw_only=True, slots=True) -class MetadataFilter: - labels: dict[str, str] = field(default_factory=dict) diff --git a/packages/jumpstarter/jumpstarter/config/client.py b/packages/jumpstarter/jumpstarter/config/client.py index 715038daf..7c2ddf88c 100644 --- a/packages/jumpstarter/jumpstarter/config/client.py +++ b/packages/jumpstarter/jumpstarter/config/client.py @@ -14,7 +14,6 @@ from .grpc import call_credentials from .tls import TLSConfigV1Alpha1 from jumpstarter.client.grpc import ClientService -from jumpstarter.common import MetadataFilter from jumpstarter.common.exceptions import FileNotFoundError from jumpstarter.common.grpc import aio_secure_channel, ssl_channel_credentials, translate_grpc_exceptions @@ -62,9 +61,9 @@ async def channel(self): return aio_secure_channel(self.endpoint, credentials, self.grpcOptions) @contextmanager - def lease(self, metadata_filter: MetadataFilter, lease_name: str | None = None): + def lease(self, selector: str | None = None, lease_name: str | None = None): with start_blocking_portal() as portal: - with portal.wrap_async_context_manager(self.lease_async(metadata_filter, lease_name, portal)) as lease: + with portal.wrap_async_context_manager(self.lease_async(selector, lease_name, portal)) as lease: yield lease def get_exporter(self, name: str): @@ -80,9 +79,9 @@ def list_exporters( with start_blocking_portal() as portal: return portal.call(self.list_exporters_async, page_size, page_token, filter) - def request_lease(self, metadata_filter: MetadataFilter): + def request_lease(self, selector: str): with start_blocking_portal() as portal: - return portal.call(self.request_lease_async, metadata_filter, portal) + return portal.call(self.request_lease_async, selector, portal) def list_leases(self, filter: str): with start_blocking_portal() as portal: @@ -147,7 +146,7 @@ async def delete_lease_async(self, name: str): async def request_lease_async( self, - metadata_filter: MetadataFilter, + selector: str, portal: BlockingPortal, ): # dynamically import to avoid circular imports @@ -157,7 +156,7 @@ async def request_lease_async( channel=await self.channel(), namespace=self.metadata.namespace, name=None, - metadata_filter=metadata_filter, + selector=selector, portal=portal, allow=self.drivers.allow, unsafe=self.drivers.unsafe, @@ -185,7 +184,7 @@ async def release_lease_async(self, name): @asynccontextmanager async def lease_async( self, - metadata_filter: MetadataFilter, + selector: str, lease_name: str | None, portal: BlockingPortal, ): @@ -200,7 +199,7 @@ async def lease_async( channel=await self.channel(), namespace=self.metadata.namespace, name=lease_name, - metadata_filter=metadata_filter, + selector=selector, portal=portal, allow=self.drivers.allow, unsafe=self.drivers.unsafe,