From 8abb16a43035591d284ecfe70dc0af1d1398c4b4 Mon Sep 17 00:00:00 2001 From: Asher Pemberton Date: Thu, 9 Apr 2026 15:02:47 +0100 Subject: [PATCH 1/2] remote: add metadata-based gRPC client identity Add client and server interceptors which attach labgrid identity metadata to gRPC calls and expose it to coordinator RPC handlers. Use the metadata identity to register client and exporter stream sessions while keeping startup-message handling as a deprecated fallback for older clients and exporters. Signed-off-by: Asher Pemberton Reviewed-by: Asher Pemberton # gatekeeper Co-authored-by: Luke Beardsmore --- labgrid/remote/client.py | 15 +++++ labgrid/remote/common.py | 17 +++++ labgrid/remote/coordinator.py | 10 +++ labgrid/remote/exporter.py | 10 +++ labgrid/remote/grpc/__init__.py | 0 labgrid/remote/grpc/interceptor/__init__.py | 0 labgrid/remote/grpc/interceptor/client.py | 32 +++++++++ labgrid/remote/grpc/interceptor/server.py | 33 ++++++++++ labgrid/remote/identity.py | 48 ++++++++++++++ pyproject.toml | 3 + tests/test_interceptor_client.py | 73 +++++++++++++++++++++ tests/test_interceptor_server.py | 33 ++++++++++ tests/test_remote.py | 52 +++++++++++++++ 13 files changed, 326 insertions(+) create mode 100644 labgrid/remote/grpc/__init__.py create mode 100644 labgrid/remote/grpc/interceptor/__init__.py create mode 100644 labgrid/remote/grpc/interceptor/client.py create mode 100644 labgrid/remote/grpc/interceptor/server.py create mode 100644 labgrid/remote/identity.py create mode 100644 tests/test_interceptor_client.py create mode 100644 tests/test_interceptor_server.py diff --git a/labgrid/remote/client.py b/labgrid/remote/client.py index 1576d39f1..ef8a3bfc8 100755 --- a/labgrid/remote/client.py +++ b/labgrid/remote/client.py @@ -32,6 +32,11 @@ # TODO: drop if Python >= 3.11 guaranteed from exceptiongroup import ExceptionGroup # pylint: disable=redefined-builtin +from labgrid.remote.grpc.interceptor.client import ( + IdentityClientStreamStreamInterceptor, + IdentityClientUnaryUnaryInterceptor, +) + from .common import ( ResourceEntry, ResourceMatch, @@ -121,9 +126,19 @@ def __attrs_post_init__(self): ("grpc.http2.max_pings_without_data", 0), # no limit ] + identity = { + "username": self.getuser(), + "hostname": self.gethostname(), + "user_agent": f"labgrid-client {labgrid_version()}", + } + interceptors = [ + IdentityClientUnaryUnaryInterceptor(**identity), + IdentityClientStreamStreamInterceptor(**identity), + ] self.channel = grpc.aio.insecure_channel( target=self.address, options=channel_options, + interceptors=interceptors, ) self.stub = labgrid_coordinator_pb2_grpc.CoordinatorStub(self.channel) diff --git a/labgrid/remote/common.py b/labgrid/remote/common.py index 6601e0d2f..87dbb2f78 100644 --- a/labgrid/remote/common.py +++ b/labgrid/remote/common.py @@ -7,6 +7,8 @@ import logging from datetime import datetime from fnmatch import fnmatchcase +from typing import Optional +import warnings import attr @@ -487,6 +489,21 @@ def from_pb2(cls, pb2: labgrid_coordinator_pb2.Reservation): ) +def get_metadata_single_value_by_key(metadata, key: str) -> Optional[str]: + """Look up a single value by key in a metadata sequence of (key, value) pairs.""" + values = [v for k, v in metadata or () if k == key] + + if not values: + return None + + if len(values) > 1: + warnings.warn( + "Multiple metadata KV pairs with the same key. The value of the first matching KV pair will be returned." + ) + + return values[0] + + async def queue_as_aiter(q, logger=logging.getLogger()): try: while True: diff --git a/labgrid/remote/coordinator.py b/labgrid/remote/coordinator.py index 3423f3cef..dae1a3d34 100644 --- a/labgrid/remote/coordinator.py +++ b/labgrid/remote/coordinator.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import argparse +import contextvars import logging import asyncio import traceback @@ -10,11 +11,15 @@ import copy import random import signal +from typing import Optional import attr import grpc from grpc_reflection.v1alpha import reflection +from labgrid.remote.grpc.interceptor.server import IdentityServerInterceptor +from labgrid.remote.identity import ClientIdentity + from .common import ( ResourceEntry, ResourceMatch, @@ -30,6 +35,10 @@ from .generated import labgrid_coordinator_pb2_grpc from ..util import atomic_replace, labgrid_version, yaml, Timeout +client_identity_context: contextvars.ContextVar[Optional[ClientIdentity]] = contextvars.ContextVar( + "client_identity", default=None +) + @contextmanager def warn_if_slow(prefix, *, level=logging.WARNING, limit=0.1): @@ -1127,6 +1136,7 @@ async def serve(listen, cleanup) -> None: ] server = grpc.aio.server( options=channel_options, + interceptors=[IdentityServerInterceptor(client_identity_context)], ) coordinator = Coordinator() labgrid_coordinator_pb2_grpc.add_CoordinatorServicer_to_server(coordinator, server) diff --git a/labgrid/remote/exporter.py b/labgrid/remote/exporter.py index 149b183ad..f660a7e94 100755 --- a/labgrid/remote/exporter.py +++ b/labgrid/remote/exporter.py @@ -20,6 +20,11 @@ import attr import grpc +from labgrid.remote.grpc.interceptor.client import ( + IdentityClientStreamStreamInterceptor, + IdentityClientUnaryUnaryInterceptor, +) + from .config import ResourceConfig from .common import ResourceEntry, queue_as_aiter from .generated import labgrid_coordinator_pb2, labgrid_coordinator_pb2_grpc @@ -913,9 +918,14 @@ def __init__(self, config) -> None: if urlsplit(f"//{config['coordinator']}").port is None: config["coordinator"] += ":20408" + identity = (None, self.name, f"labgrid-exporter {labgrid_version()}") self.channel = grpc.aio.insecure_channel( target=config["coordinator"], options=channel_options, + interceptors=[ + IdentityClientUnaryUnaryInterceptor(*identity), + IdentityClientStreamStreamInterceptor(*identity), + ], ) self.stub = labgrid_coordinator_pb2_grpc.CoordinatorStub(self.channel) self.out_queue = asyncio.Queue() diff --git a/labgrid/remote/grpc/__init__.py b/labgrid/remote/grpc/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/labgrid/remote/grpc/interceptor/__init__.py b/labgrid/remote/grpc/interceptor/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/labgrid/remote/grpc/interceptor/client.py b/labgrid/remote/grpc/interceptor/client.py new file mode 100644 index 000000000..478c6dd63 --- /dev/null +++ b/labgrid/remote/grpc/interceptor/client.py @@ -0,0 +1,32 @@ +from typing import Optional + +from grpc.aio import ClientCallDetails, ClientInterceptor, StreamStreamClientInterceptor, UnaryUnaryClientInterceptor + +from labgrid.remote.identity import HOSTNAME_KEY, USER_AGENT_KEY, USERNAME_KEY + + +class BaseIdentityClientInterceptor(ClientInterceptor): + def __init__(self, username: Optional[str], hostname: str, user_agent: Optional[str]): + super().__init__() + self.username = username + self.hostname = hostname + self.user_agent = user_agent + + def _inject(self, client_call_details: ClientCallDetails): + if self.username: + client_call_details.metadata.add(USERNAME_KEY, self.username) + client_call_details.metadata.add(HOSTNAME_KEY, self.hostname) + if self.user_agent: + client_call_details.metadata.add(USER_AGENT_KEY, self.user_agent) + + +class IdentityClientUnaryUnaryInterceptor(UnaryUnaryClientInterceptor, BaseIdentityClientInterceptor): + async def intercept_unary_unary(self, continuation, client_call_details, request): + self._inject(client_call_details) + return await continuation(client_call_details, request) + + +class IdentityClientStreamStreamInterceptor(StreamStreamClientInterceptor, BaseIdentityClientInterceptor): + async def intercept_stream_stream(self, continuation, client_call_details, request_iterator): + self._inject(client_call_details) + return await continuation(client_call_details, request_iterator) diff --git a/labgrid/remote/grpc/interceptor/server.py b/labgrid/remote/grpc/interceptor/server.py new file mode 100644 index 000000000..3727fced6 --- /dev/null +++ b/labgrid/remote/grpc/interceptor/server.py @@ -0,0 +1,33 @@ +import contextvars +import logging +from asyncio import iscoroutine + +from grpc.aio import ServerInterceptor + +from labgrid.remote.identity import ClientIdentity, NoIdentityPresent + + +class IdentityServerInterceptor(ServerInterceptor): + def __init__(self, client_identity_contextvar: contextvars.ContextVar): + super().__init__() + self.client_identity_contextvar = client_identity_contextvar + + async def intercept_service(self, continuation, handler_call_details): + # continuation may return a handler + # OR an awaitable depending on grpcio build + maybe_handler = continuation(handler_call_details) + handler = await maybe_handler if iscoroutine(maybe_handler) else maybe_handler + if handler is None: + return None + + metadata = handler_call_details.invocation_metadata + logging.debug(metadata) + + try: + client_identity = ClientIdentity.from_metadata(metadata) + logging.debug(client_identity) + self.client_identity_contextvar.set(client_identity) + except NoIdentityPresent: + pass + + return handler diff --git a/labgrid/remote/identity.py b/labgrid/remote/identity.py new file mode 100644 index 000000000..535373ee4 --- /dev/null +++ b/labgrid/remote/identity.py @@ -0,0 +1,48 @@ +from typing import Optional + +from labgrid.remote.common import get_metadata_single_value_by_key + +USERNAME_KEY = "x-lg-username" +HOSTNAME_KEY = "x-lg-hostname" +USER_AGENT_KEY = "x-lg-user-agent" + + +class NoIdentityPresent(Exception): + """Raised when metadata-based identity information is missing from the request.""" + + +class ClientIdentity: + """Represents the identity of a connected client, derived from gRPC metadata.""" + + def __init__(self, identity_id: str, user_agent: Optional[str]): + self.id = identity_id + self.user_agent = user_agent + + def __str__(self): + return f"ClientIdentity(id={self.id}, user_agent={self.user_agent})" + + @classmethod + def from_metadata(cls, metadata: tuple): + """Construct a ClientIdentity from gRPC request metadata. + + Args: + metadata: A sequence of (key, value) pairs from the gRPC context. + + Returns: + A ClientIdentity with id set to ``hostname/username`` (or just + ``hostname`` if no username is present) and (optional) user_agent. + + Raises: + NoIdentityPresent: If the hostname key is missing from metadata. + """ + username = get_metadata_single_value_by_key(metadata, USERNAME_KEY) + hostname = get_metadata_single_value_by_key(metadata, HOSTNAME_KEY) + user_agent = get_metadata_single_value_by_key(metadata, USER_AGENT_KEY) + + if not hostname: + raise NoIdentityPresent() + + if username: + return cls(f"{hostname}/{username}", user_agent) + + return cls(hostname, user_agent) diff --git a/pyproject.toml b/pyproject.toml index 499d1f087..e6ffd49b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,6 +84,7 @@ dev = [ # additional dev dependencies "psutil>=5.8.0", + "pytest-asyncio>=1.3.0", "pytest-benchmark>=4.0.0", "pytest-cov>=3.0.0", "pytest-dependency>=0.5.1", @@ -121,6 +122,8 @@ packages = [ "labgrid.pytestplugin", "labgrid.remote", "labgrid.remote.generated", + "labgrid.remote.grpc", + "labgrid.remote.grpc.interceptor", "labgrid.resource", "labgrid.strategy", "labgrid.util", diff --git a/tests/test_interceptor_client.py b/tests/test_interceptor_client.py new file mode 100644 index 000000000..eb8623618 --- /dev/null +++ b/tests/test_interceptor_client.py @@ -0,0 +1,73 @@ +import pytest + +from labgrid.remote.grpc.interceptor.client import ( + BaseIdentityClientInterceptor, + IdentityClientUnaryUnaryInterceptor, + IdentityClientStreamStreamInterceptor, +) +from labgrid.remote.identity import USERNAME_KEY, HOSTNAME_KEY, USER_AGENT_KEY + + +class DummyMetadata: + def __init__(self): + self.items = [] + + def add(self, key, value): + self.items.append((key, value)) + + +class DummyClientCallDetails: + def __init__(self): + self.metadata = DummyMetadata() + + +def test_base_identity_client_interceptor_injects_all_fields(): + interceptor = BaseIdentityClientInterceptor( + username="test_username", + hostname="test_hostname", + user_agent="test_agent", + ) + + client_call_details = DummyClientCallDetails() + + interceptor._inject(client_call_details) + + assert client_call_details.metadata.items == [ + (USERNAME_KEY, "test_username"), + (HOSTNAME_KEY, "test_hostname"), + (USER_AGENT_KEY, "test_agent"), + ] + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "impl,method", + [ + (IdentityClientUnaryUnaryInterceptor, "intercept_unary_unary"), + (IdentityClientStreamStreamInterceptor, "intercept_stream_stream"), + ], +) +async def test_client_interceptor_implementations(impl, method): + interceptor = impl("test_username", "test_hostname", "test_agent") + + client_call_details = DummyClientCallDetails() + request_or_iterator = object() + sentinel_response = object() + + received = {} + + async def continuation(ccd, req): + received["ccd"] = ccd + received["req"] = req + return sentinel_response + + interceptor_method = getattr(interceptor, method) + result = await interceptor_method(continuation, client_call_details, request_or_iterator) + + assert result is sentinel_response + assert received["ccd"] is client_call_details + assert client_call_details.metadata.items == [ + (USERNAME_KEY, "test_username"), + (HOSTNAME_KEY, "test_hostname"), + (USER_AGENT_KEY, "test_agent"), + ] diff --git a/tests/test_interceptor_server.py b/tests/test_interceptor_server.py new file mode 100644 index 000000000..0b9741712 --- /dev/null +++ b/tests/test_interceptor_server.py @@ -0,0 +1,33 @@ +import contextvars, pytest +from types import SimpleNamespace +from unittest.mock import Mock +from labgrid.remote.grpc.interceptor.server import IdentityServerInterceptor + + +@pytest.fixture +def cv(): + return contextvars.ContextVar("client_identity", default=None) + + +@pytest.fixture +def interceptor(cv): + return IdentityServerInterceptor(cv) + + +def handler_call_details(metadata): + return SimpleNamespace(invocation_metadata=tuple(metadata)) + + +@pytest.mark.asyncio +async def test_server_interceptor_sets_contextvar(interceptor, cv): + handler = object() + continuation = Mock(return_value=handler) + + metadata = (("x-lg-hostname", "h"), ("x-lg-username", "u"), ("x-lg-user-agent", "ua")) + + ret = await interceptor.intercept_service(continuation, handler_call_details(metadata)) + assert ret is handler + + identity = cv.get() + assert identity.id == "h/u" + assert identity.user_agent == "ua" diff --git a/tests/test_remote.py b/tests/test_remote.py index 76a1da434..76021c63f 100644 --- a/tests/test_remote.py +++ b/tests/test_remote.py @@ -1,4 +1,9 @@ +import warnings + import pexpect +import pytest + +from labgrid.remote.common import get_metadata_single_value_by_key def test_client_help(): @@ -48,3 +53,50 @@ def test_exporter_coordinator_becomes_unreachable(coordinator, exporter): assert exporter.exitstatus == 100 coordinator.resume_tree() + + +def test_get_metadata_single_value_by_key_returns_value_for_existing_key(): + metadata = [("key1", "value1"), ("key2", "value2")] + assert get_metadata_single_value_by_key(metadata, "key1") == "value1" + assert get_metadata_single_value_by_key(metadata, "key2") == "value2" + + +def test_get_metadata_single_value_by_key_returns_none_for_missing_key(): + metadata = [("key1", "value1")] + assert get_metadata_single_value_by_key(metadata, "other") is None + + +def test_get_metadata_single_value_by_key_returns_none_for_empty_metadata(): + assert get_metadata_single_value_by_key((), "key") is None + + +def test_get_metadata_single_value_by_key_returns_none_for_none_metadata(): + assert get_metadata_single_value_by_key(None, "key") is None + + +def test_get_metadata_single_value_by_key_returns_first_value_on_duplicate_keys(): + metadata = [("key", "first"), ("key", "second")] + with pytest.warns(UserWarning, match="Multiple metadata KV pairs"): + result = get_metadata_single_value_by_key(metadata, "key") + assert result == "first" + + +def test_get_metadata_single_value_by_key_no_warning_on_single_match(): + metadata = [("key", "value")] + with warnings.catch_warnings(record=True) as caught: + warnings.simplefilter("always") + get_metadata_single_value_by_key(metadata, "key") + assert len(caught) == 0 + + +def test_get_metadata_single_value_by_key_returns_first_value_for_non_adjacent_duplicates(): + metadata = [("key", "first"), ("other", "value"), ("key", "second")] + with pytest.warns(UserWarning, match="Multiple metadata KV pairs"): + result = get_metadata_single_value_by_key(metadata, "key") + assert result == "first" + + +def test_get_metadata_single_value_by_key_is_case_sensitive(): + metadata = [("Key", "value")] + assert get_metadata_single_value_by_key(metadata, "key") is None + assert get_metadata_single_value_by_key(metadata, "Key") == "value" From 24624ba9b17ee636d1e28be6c8355efd56479651 Mon Sep 17 00:00:00 2001 From: Asher Pemberton Date: Fri, 10 Apr 2026 09:21:44 +0100 Subject: [PATCH 2/2] remote/coordinator: detach place RPCs from ClientStream Allow AcquirePlace, AllowPlace and CreateReservation to identify the caller from gRPC metadata instead of requiring identity to come only from an established ClientStream session. ClientStream should remain the ordered place/resource update channel. Unary-only callers should not need to establish and synchronize that stream merely to provide identity. This reduces startup and state management overhead for short-lived tools and services. Keep the existing ClientStream session lookup as a fallback so older clients which still send startup messages on the stream continue to work. Signed-off-by: Asher Pemberton Reviewed-by: Asher Pemberton # gatekeeper Co-authored-by: Luke Beardsmore --- labgrid/remote/coordinator.py | 47 +++- .../generated/labgrid_coordinator_pb2.py | 242 +++++++++--------- labgrid/remote/identity.py | 14 + .../remote/proto/labgrid-coordinator.proto | 6 +- 4 files changed, 183 insertions(+), 126 deletions(-) diff --git a/labgrid/remote/coordinator.py b/labgrid/remote/coordinator.py index dae1a3d34..62038a18b 100644 --- a/labgrid/remote/coordinator.py +++ b/labgrid/remote/coordinator.py @@ -18,7 +18,7 @@ from grpc_reflection.v1alpha import reflection from labgrid.remote.grpc.interceptor.server import IdentityServerInterceptor -from labgrid.remote.identity import ClientIdentity +from labgrid.remote.identity import ClientIdentity, infer_peer_identity from .common import ( ResourceEntry, @@ -326,9 +326,15 @@ async def ClientStream(self, request_iterator, context): assert peer not in self.clients out_msg_queue = asyncio.Queue() + identity = client_identity_context.get() + if identity: + logging.debug("client identity provided in gRPC metadata: %s", identity) + self.clients[peer] = ClientSession(self, peer, identity.id, out_msg_queue, identity.user_agent) + async def request_task(): name = None version = None + session = self.clients.get(peer) try: async for in_msg in request_iterator: in_msg: labgrid_coordinator_pb2.ClientInMessage @@ -339,8 +345,15 @@ async def request_task(): out_msg.sync.id = in_msg.sync.id out_msg_queue.put_nowait(out_msg) elif kind == "startup": - version = in_msg.startup.version + if session: + logging.debug("ignoring legacy startup message from client %s", peer) + continue name = in_msg.startup.name + version = in_msg.startup.version + logging.warning( + "client %s did not provide identity metadata; using deprecated startup identity", + peer, + ) session = self.clients[peer] = ClientSession(self, peer, name, out_msg_queue, version) logging.debug("Received startup from %s with %s", name, version) asyncio.current_task().set_name(f"client-{peer}-rx/started-{name}") @@ -418,9 +431,21 @@ async def ExporterStream(self, request_iterator, context): out_msg.hello.version = labgrid_version() yield out_msg + identity = client_identity_context.get() + if identity: + logging.debug("exporter identity provided in gRPC metadata: %s", identity) + if existing := self.get_exporter_by_name(identity.id): + await context.abort( + grpc.StatusCode.ALREADY_EXISTS, + f"startup failed: exporter with name '{identity.id}' is already connected from {existing.peer}", + ) + self.exporters[peer] = ExporterSession(self, peer, identity.id, command_queue, identity.user_agent) + startup_done.set() + async def request_task(): name = None version = None + session = self.exporters.get(peer) try: async for in_msg in request_iterator: in_msg: labgrid_coordinator_pb2.ExporterInMessage @@ -431,8 +456,15 @@ async def request_task(): cmd.complete(in_msg.response) logging.debug("Command %s is done", cmd) elif kind == "startup": - version = in_msg.startup.version + if session: + logging.debug("ignoring legacy startup message from exporter %s", peer) + continue name = in_msg.startup.name + version = in_msg.startup.version + logging.warning( + "exporter %s did not provide identity metadata; using deprecated startup identity", + peer, + ) if existing := self.get_exporter_by_name(name): raise ExporterError( f"exporter with name '{name}' is already connected from {existing.peer}" @@ -861,7 +893,7 @@ async def AcquirePlace(self, request, context): peer = context.peer() name = request.placename try: - username = self.clients[peer].name + username = infer_peer_identity(self.clients, context, client_identity_context) except KeyError: await context.abort(grpc.StatusCode.FAILED_PRECONDITION, f"Peer {peer} does not have a valid session") print(request) @@ -931,7 +963,7 @@ async def AllowPlace(self, request, context): user = request.user peer = context.peer() try: - username = self.clients[peer].name + username = infer_peer_identity(self.clients, context, client_identity_context) except KeyError: await context.abort(grpc.StatusCode.FAILED_PRECONDITION, f"Peer {peer} does not have a valid session") try: @@ -1086,7 +1118,10 @@ async def CreateReservation(self, request: labgrid_coordinator_pb2.CreateReserva await context.abort(grpc.StatusCode.INVALID_ARGUMENT, f"Value {v} is invalid") fltr[k] = v - owner = self.clients[peer].name + try: + owner = infer_peer_identity(self.clients, context, client_identity_context) + except KeyError: + await context.abort(grpc.StatusCode.FAILED_PRECONDITION, f"Peer {peer} does not have a valid session") res = Reservation(owner=owner, prio=request.prio, filters=fltrs) self.reservations[res.token] = res self.schedule_reservations() diff --git a/labgrid/remote/generated/labgrid_coordinator_pb2.py b/labgrid/remote/generated/labgrid_coordinator_pb2.py index 37652bff7..6c75474f7 100644 --- a/labgrid/remote/generated/labgrid_coordinator_pb2.py +++ b/labgrid/remote/generated/labgrid_coordinator_pb2.py @@ -14,13 +14,19 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19labgrid-coordinator.proto\x12\x07labgrid\"\x8a\x01\n\x0f\x43lientInMessage\x12\x1d\n\x04sync\x18\x01 \x01(\x0b\x32\r.labgrid.SyncH\x00\x12\'\n\x07startup\x18\x02 \x01(\x0b\x32\x14.labgrid.StartupDoneH\x00\x12\'\n\tsubscribe\x18\x03 \x01(\x0b\x32\x12.labgrid.SubscribeH\x00\x42\x06\n\x04kind\"\x12\n\x04Sync\x12\n\n\x02id\x18\x01 \x01(\x04\",\n\x0bStartupDone\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"r\n\tSubscribe\x12\x1b\n\x0eis_unsubscribe\x18\x01 \x01(\x08H\x01\x88\x01\x01\x12\x14\n\nall_places\x18\x02 \x01(\x08H\x00\x12\x17\n\rall_resources\x18\x03 \x01(\x08H\x00\x42\x06\n\x04kindB\x11\n\x0f_is_unsubscribe\"g\n\x10\x43lientOutMessage\x12 \n\x04sync\x18\x01 \x01(\x0b\x32\r.labgrid.SyncH\x00\x88\x01\x01\x12(\n\x07updates\x18\x02 \x03(\x0b\x32\x17.labgrid.UpdateResponseB\x07\n\x05_sync\"\xa5\x01\n\x0eUpdateResponse\x12%\n\x08resource\x18\x01 \x01(\x0b\x32\x11.labgrid.ResourceH\x00\x12.\n\x0c\x64\x65l_resource\x18\x02 \x01(\x0b\x32\x16.labgrid.Resource.PathH\x00\x12\x1f\n\x05place\x18\x03 \x01(\x0b\x32\x0e.labgrid.PlaceH\x00\x12\x13\n\tdel_place\x18\x04 \x01(\tH\x00\x42\x06\n\x04kind\"\x9a\x01\n\x11\x45xporterInMessage\x12%\n\x08resource\x18\x01 \x01(\x0b\x32\x11.labgrid.ResourceH\x00\x12\'\n\x07startup\x18\x02 \x01(\x0b\x32\x14.labgrid.StartupDoneH\x00\x12-\n\x08response\x18\x03 \x01(\x0b\x32\x19.labgrid.ExporterResponseH\x00\x42\x06\n\x04kind\"\x9e\x03\n\x08Resource\x12$\n\x04path\x18\x01 \x01(\x0b\x32\x16.labgrid.Resource.Path\x12\x0b\n\x03\x63ls\x18\x02 \x01(\t\x12-\n\x06params\x18\x03 \x03(\x0b\x32\x1d.labgrid.Resource.ParamsEntry\x12+\n\x05\x65xtra\x18\x04 \x03(\x0b\x32\x1c.labgrid.Resource.ExtraEntry\x12\x10\n\x08\x61\x63quired\x18\x05 \x01(\t\x12\r\n\x05\x61vail\x18\x06 \x01(\x08\x1a_\n\x04Path\x12\x1a\n\rexporter_name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x12\n\ngroup_name\x18\x02 \x01(\t\x12\x15\n\rresource_name\x18\x03 \x01(\tB\x10\n\x0e_exporter_name\x1a@\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.labgrid.MapValue:\x02\x38\x01\x1a?\n\nExtraEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.labgrid.MapValue:\x02\x38\x01\"\x82\x01\n\x08MapValue\x12\x14\n\nbool_value\x18\x01 \x01(\x08H\x00\x12\x13\n\tint_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nuint_value\x18\x03 \x01(\x04H\x00\x12\x15\n\x0b\x66loat_value\x18\x04 \x01(\x01H\x00\x12\x16\n\x0cstring_value\x18\x05 \x01(\tH\x00\x42\x06\n\x04kind\"C\n\x10\x45xporterResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x06reason\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_reason\"\x18\n\x05Hello\x12\x0f\n\x07version\x18\x01 \x01(\t\"\x82\x01\n\x12\x45xporterOutMessage\x12\x1f\n\x05hello\x18\x01 \x01(\x0b\x32\x0e.labgrid.HelloH\x00\x12\x43\n\x14set_acquired_request\x18\x02 \x01(\x0b\x32#.labgrid.ExporterSetAcquiredRequestH\x00\x42\x06\n\x04kind\"o\n\x1a\x45xporterSetAcquiredRequest\x12\x12\n\ngroup_name\x18\x01 \x01(\t\x12\x15\n\rresource_name\x18\x02 \x01(\t\x12\x17\n\nplace_name\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\r\n\x0b_place_name\"\x1f\n\x0f\x41\x64\x64PlaceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x12\n\x10\x41\x64\x64PlaceResponse\"\"\n\x12\x44\x65letePlaceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x15\n\x13\x44\x65letePlaceResponse\"\x12\n\x10GetPlacesRequest\"3\n\x11GetPlacesResponse\x12\x1e\n\x06places\x18\x01 \x03(\x0b\x32\x0e.labgrid.Place\"\xd2\x02\n\x05Place\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x61liases\x18\x02 \x03(\t\x12\x0f\n\x07\x63omment\x18\x03 \x01(\t\x12&\n\x04tags\x18\x04 \x03(\x0b\x32\x18.labgrid.Place.TagsEntry\x12\'\n\x07matches\x18\x05 \x03(\x0b\x32\x16.labgrid.ResourceMatch\x12\x15\n\x08\x61\x63quired\x18\x06 \x01(\tH\x00\x88\x01\x01\x12\x1a\n\x12\x61\x63quired_resources\x18\x07 \x03(\t\x12\x0f\n\x07\x61llowed\x18\x08 \x03(\t\x12\x0f\n\x07\x63reated\x18\t \x01(\x01\x12\x0f\n\x07\x63hanged\x18\n \x01(\x01\x12\x18\n\x0breservation\x18\x0b \x01(\tH\x01\x88\x01\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0b\n\t_acquiredB\x0e\n\x0c_reservation\"y\n\rResourceMatch\x12\x10\n\x08\x65xporter\x18\x01 \x01(\t\x12\r\n\x05group\x18\x02 \x01(\t\x12\x0b\n\x03\x63ls\x18\x03 \x01(\t\x12\x11\n\x04name\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06rename\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05_nameB\t\n\x07_rename\"8\n\x14\x41\x64\x64PlaceAliasRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\r\n\x05\x61lias\x18\x02 \x01(\t\"\x17\n\x15\x41\x64\x64PlaceAliasResponse\";\n\x17\x44\x65letePlaceAliasRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\r\n\x05\x61lias\x18\x02 \x01(\t\"\x1a\n\x18\x44\x65letePlaceAliasResponse\"\x8b\x01\n\x13SetPlaceTagsRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x34\n\x04tags\x18\x02 \x03(\x0b\x32&.labgrid.SetPlaceTagsRequest.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x16\n\x14SetPlaceTagsResponse\"<\n\x16SetPlaceCommentRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x0f\n\x07\x63omment\x18\x02 \x01(\t\"\x19\n\x17SetPlaceCommentResponse\"Z\n\x14\x41\x64\x64PlaceMatchRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x0f\n\x07pattern\x18\x02 \x01(\t\x12\x13\n\x06rename\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_rename\"\x17\n\x15\x41\x64\x64PlaceMatchResponse\"]\n\x17\x44\x65letePlaceMatchRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x0f\n\x07pattern\x18\x02 \x01(\t\x12\x13\n\x06rename\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_rename\"\x1a\n\x18\x44\x65letePlaceMatchResponse\"(\n\x13\x41\x63quirePlaceRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\"\x16\n\x14\x41\x63quirePlaceResponse\"L\n\x13ReleasePlaceRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x15\n\x08\x66romuser\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0b\n\t_fromuser\"\x16\n\x14ReleasePlaceResponse\"4\n\x11\x41llowPlaceRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x0c\n\x04user\x18\x02 \x01(\t\"\x14\n\x12\x41llowPlaceResponse\"\xb6\x01\n\x18\x43reateReservationRequest\x12?\n\x07\x66ilters\x18\x01 \x03(\x0b\x32..labgrid.CreateReservationRequest.FiltersEntry\x12\x0c\n\x04prio\x18\x02 \x01(\x01\x1aK\n\x0c\x46iltersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12*\n\x05value\x18\x02 \x01(\x0b\x32\x1b.labgrid.Reservation.Filter:\x02\x38\x01\"F\n\x19\x43reateReservationResponse\x12)\n\x0breservation\x18\x01 \x01(\x0b\x32\x14.labgrid.Reservation\"\xcd\x03\n\x0bReservation\x12\r\n\x05owner\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\r\n\x05state\x18\x03 \x01(\x05\x12\x0c\n\x04prio\x18\x04 \x01(\x01\x12\x32\n\x07\x66ilters\x18\x05 \x03(\x0b\x32!.labgrid.Reservation.FiltersEntry\x12:\n\x0b\x61llocations\x18\x06 \x03(\x0b\x32%.labgrid.Reservation.AllocationsEntry\x12\x0f\n\x07\x63reated\x18\x07 \x01(\x01\x12\x0f\n\x07timeout\x18\x08 \x01(\x01\x1ap\n\x06\x46ilter\x12\x37\n\x06\x66ilter\x18\x01 \x03(\x0b\x32\'.labgrid.Reservation.Filter.FilterEntry\x1a-\n\x0b\x46ilterEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1aK\n\x0c\x46iltersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12*\n\x05value\x18\x02 \x01(\x0b\x32\x1b.labgrid.Reservation.Filter:\x02\x38\x01\x1a\x32\n\x10\x41llocationsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\")\n\x18\x43\x61ncelReservationRequest\x12\r\n\x05token\x18\x01 \x01(\t\"\x1b\n\x19\x43\x61ncelReservationResponse\"\'\n\x16PollReservationRequest\x12\r\n\x05token\x18\x01 \x01(\t\"D\n\x17PollReservationResponse\x12)\n\x0breservation\x18\x01 \x01(\x0b\x32\x14.labgrid.Reservation\"E\n\x17GetReservationsResponse\x12*\n\x0creservations\x18\x01 \x03(\x0b\x32\x14.labgrid.Reservation\"\x18\n\x16GetReservationsRequest2\xd2\x0b\n\x0b\x43oordinator\x12I\n\x0c\x43lientStream\x12\x18.labgrid.ClientInMessage\x1a\x19.labgrid.ClientOutMessage\"\x00(\x01\x30\x01\x12O\n\x0e\x45xporterStream\x12\x1a.labgrid.ExporterInMessage\x1a\x1b.labgrid.ExporterOutMessage\"\x00(\x01\x30\x01\x12\x41\n\x08\x41\x64\x64Place\x12\x18.labgrid.AddPlaceRequest\x1a\x19.labgrid.AddPlaceResponse\"\x00\x12J\n\x0b\x44\x65letePlace\x12\x1b.labgrid.DeletePlaceRequest\x1a\x1c.labgrid.DeletePlaceResponse\"\x00\x12\x44\n\tGetPlaces\x12\x19.labgrid.GetPlacesRequest\x1a\x1a.labgrid.GetPlacesResponse\"\x00\x12P\n\rAddPlaceAlias\x12\x1d.labgrid.AddPlaceAliasRequest\x1a\x1e.labgrid.AddPlaceAliasResponse\"\x00\x12Y\n\x10\x44\x65letePlaceAlias\x12 .labgrid.DeletePlaceAliasRequest\x1a!.labgrid.DeletePlaceAliasResponse\"\x00\x12M\n\x0cSetPlaceTags\x12\x1c.labgrid.SetPlaceTagsRequest\x1a\x1d.labgrid.SetPlaceTagsResponse\"\x00\x12V\n\x0fSetPlaceComment\x12\x1f.labgrid.SetPlaceCommentRequest\x1a .labgrid.SetPlaceCommentResponse\"\x00\x12P\n\rAddPlaceMatch\x12\x1d.labgrid.AddPlaceMatchRequest\x1a\x1e.labgrid.AddPlaceMatchResponse\"\x00\x12Y\n\x10\x44\x65letePlaceMatch\x12 .labgrid.DeletePlaceMatchRequest\x1a!.labgrid.DeletePlaceMatchResponse\"\x00\x12M\n\x0c\x41\x63quirePlace\x12\x1c.labgrid.AcquirePlaceRequest\x1a\x1d.labgrid.AcquirePlaceResponse\"\x00\x12M\n\x0cReleasePlace\x12\x1c.labgrid.ReleasePlaceRequest\x1a\x1d.labgrid.ReleasePlaceResponse\"\x00\x12G\n\nAllowPlace\x12\x1a.labgrid.AllowPlaceRequest\x1a\x1b.labgrid.AllowPlaceResponse\"\x00\x12\\\n\x11\x43reateReservation\x12!.labgrid.CreateReservationRequest\x1a\".labgrid.CreateReservationResponse\"\x00\x12\\\n\x11\x43\x61ncelReservation\x12!.labgrid.CancelReservationRequest\x1a\".labgrid.CancelReservationResponse\"\x00\x12V\n\x0fPollReservation\x12\x1f.labgrid.PollReservationRequest\x1a .labgrid.PollReservationResponse\"\x00\x12V\n\x0fGetReservations\x12\x1f.labgrid.GetReservationsRequest\x1a .labgrid.GetReservationsResponse\"\x00\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19labgrid-coordinator.proto\x12\x07labgrid\"\x8e\x01\n\x0f\x43lientInMessage\x12\x1d\n\x04sync\x18\x01 \x01(\x0b\x32\r.labgrid.SyncH\x00\x12+\n\x07startup\x18\x02 \x01(\x0b\x32\x14.labgrid.StartupDoneB\x02\x18\x01H\x00\x12\'\n\tsubscribe\x18\x03 \x01(\x0b\x32\x12.labgrid.SubscribeH\x00\x42\x06\n\x04kind\"\x12\n\x04Sync\x12\n\n\x02id\x18\x01 \x01(\x04\"0\n\x0bStartupDone\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t:\x02\x18\x01\"r\n\tSubscribe\x12\x1b\n\x0eis_unsubscribe\x18\x01 \x01(\x08H\x01\x88\x01\x01\x12\x14\n\nall_places\x18\x02 \x01(\x08H\x00\x12\x17\n\rall_resources\x18\x03 \x01(\x08H\x00\x42\x06\n\x04kindB\x11\n\x0f_is_unsubscribe\"g\n\x10\x43lientOutMessage\x12 \n\x04sync\x18\x01 \x01(\x0b\x32\r.labgrid.SyncH\x00\x88\x01\x01\x12(\n\x07updates\x18\x02 \x03(\x0b\x32\x17.labgrid.UpdateResponseB\x07\n\x05_sync\"\xa5\x01\n\x0eUpdateResponse\x12%\n\x08resource\x18\x01 \x01(\x0b\x32\x11.labgrid.ResourceH\x00\x12.\n\x0c\x64\x65l_resource\x18\x02 \x01(\x0b\x32\x16.labgrid.Resource.PathH\x00\x12\x1f\n\x05place\x18\x03 \x01(\x0b\x32\x0e.labgrid.PlaceH\x00\x12\x13\n\tdel_place\x18\x04 \x01(\tH\x00\x42\x06\n\x04kind\"\x9e\x01\n\x11\x45xporterInMessage\x12%\n\x08resource\x18\x01 \x01(\x0b\x32\x11.labgrid.ResourceH\x00\x12+\n\x07startup\x18\x02 \x01(\x0b\x32\x14.labgrid.StartupDoneB\x02\x18\x01H\x00\x12-\n\x08response\x18\x03 \x01(\x0b\x32\x19.labgrid.ExporterResponseH\x00\x42\x06\n\x04kind\"\x9e\x03\n\x08Resource\x12$\n\x04path\x18\x01 \x01(\x0b\x32\x16.labgrid.Resource.Path\x12\x0b\n\x03\x63ls\x18\x02 \x01(\t\x12-\n\x06params\x18\x03 \x03(\x0b\x32\x1d.labgrid.Resource.ParamsEntry\x12+\n\x05\x65xtra\x18\x04 \x03(\x0b\x32\x1c.labgrid.Resource.ExtraEntry\x12\x10\n\x08\x61\x63quired\x18\x05 \x01(\t\x12\r\n\x05\x61vail\x18\x06 \x01(\x08\x1a_\n\x04Path\x12\x1a\n\rexporter_name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x12\n\ngroup_name\x18\x02 \x01(\t\x12\x15\n\rresource_name\x18\x03 \x01(\tB\x10\n\x0e_exporter_name\x1a@\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.labgrid.MapValue:\x02\x38\x01\x1a?\n\nExtraEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.labgrid.MapValue:\x02\x38\x01\"\x82\x01\n\x08MapValue\x12\x14\n\nbool_value\x18\x01 \x01(\x08H\x00\x12\x13\n\tint_value\x18\x02 \x01(\x03H\x00\x12\x14\n\nuint_value\x18\x03 \x01(\x04H\x00\x12\x15\n\x0b\x66loat_value\x18\x04 \x01(\x01H\x00\x12\x16\n\x0cstring_value\x18\x05 \x01(\tH\x00\x42\x06\n\x04kind\"C\n\x10\x45xporterResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x13\n\x06reason\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_reason\"\x18\n\x05Hello\x12\x0f\n\x07version\x18\x01 \x01(\t\"\x82\x01\n\x12\x45xporterOutMessage\x12\x1f\n\x05hello\x18\x01 \x01(\x0b\x32\x0e.labgrid.HelloH\x00\x12\x43\n\x14set_acquired_request\x18\x02 \x01(\x0b\x32#.labgrid.ExporterSetAcquiredRequestH\x00\x42\x06\n\x04kind\"o\n\x1a\x45xporterSetAcquiredRequest\x12\x12\n\ngroup_name\x18\x01 \x01(\t\x12\x15\n\rresource_name\x18\x02 \x01(\t\x12\x17\n\nplace_name\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\r\n\x0b_place_name\"\x1f\n\x0f\x41\x64\x64PlaceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x12\n\x10\x41\x64\x64PlaceResponse\"\"\n\x12\x44\x65letePlaceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x15\n\x13\x44\x65letePlaceResponse\"\x12\n\x10GetPlacesRequest\"3\n\x11GetPlacesResponse\x12\x1e\n\x06places\x18\x01 \x03(\x0b\x32\x0e.labgrid.Place\"\xd2\x02\n\x05Place\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x61liases\x18\x02 \x03(\t\x12\x0f\n\x07\x63omment\x18\x03 \x01(\t\x12&\n\x04tags\x18\x04 \x03(\x0b\x32\x18.labgrid.Place.TagsEntry\x12\'\n\x07matches\x18\x05 \x03(\x0b\x32\x16.labgrid.ResourceMatch\x12\x15\n\x08\x61\x63quired\x18\x06 \x01(\tH\x00\x88\x01\x01\x12\x1a\n\x12\x61\x63quired_resources\x18\x07 \x03(\t\x12\x0f\n\x07\x61llowed\x18\x08 \x03(\t\x12\x0f\n\x07\x63reated\x18\t \x01(\x01\x12\x0f\n\x07\x63hanged\x18\n \x01(\x01\x12\x18\n\x0breservation\x18\x0b \x01(\tH\x01\x88\x01\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0b\n\t_acquiredB\x0e\n\x0c_reservation\"y\n\rResourceMatch\x12\x10\n\x08\x65xporter\x18\x01 \x01(\t\x12\r\n\x05group\x18\x02 \x01(\t\x12\x0b\n\x03\x63ls\x18\x03 \x01(\t\x12\x11\n\x04name\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06rename\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05_nameB\t\n\x07_rename\"8\n\x14\x41\x64\x64PlaceAliasRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\r\n\x05\x61lias\x18\x02 \x01(\t\"\x17\n\x15\x41\x64\x64PlaceAliasResponse\";\n\x17\x44\x65letePlaceAliasRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\r\n\x05\x61lias\x18\x02 \x01(\t\"\x1a\n\x18\x44\x65letePlaceAliasResponse\"\x8b\x01\n\x13SetPlaceTagsRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x34\n\x04tags\x18\x02 \x03(\x0b\x32&.labgrid.SetPlaceTagsRequest.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x16\n\x14SetPlaceTagsResponse\"<\n\x16SetPlaceCommentRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x0f\n\x07\x63omment\x18\x02 \x01(\t\"\x19\n\x17SetPlaceCommentResponse\"Z\n\x14\x41\x64\x64PlaceMatchRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x0f\n\x07pattern\x18\x02 \x01(\t\x12\x13\n\x06rename\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_rename\"\x17\n\x15\x41\x64\x64PlaceMatchResponse\"]\n\x17\x44\x65letePlaceMatchRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x0f\n\x07pattern\x18\x02 \x01(\t\x12\x13\n\x06rename\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_rename\"\x1a\n\x18\x44\x65letePlaceMatchResponse\"(\n\x13\x41\x63quirePlaceRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\"\x16\n\x14\x41\x63quirePlaceResponse\"L\n\x13ReleasePlaceRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x15\n\x08\x66romuser\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0b\n\t_fromuser\"\x16\n\x14ReleasePlaceResponse\"4\n\x11\x41llowPlaceRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x0c\n\x04user\x18\x02 \x01(\t\"\x14\n\x12\x41llowPlaceResponse\"\xb6\x01\n\x18\x43reateReservationRequest\x12?\n\x07\x66ilters\x18\x01 \x03(\x0b\x32..labgrid.CreateReservationRequest.FiltersEntry\x12\x0c\n\x04prio\x18\x02 \x01(\x01\x1aK\n\x0c\x46iltersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12*\n\x05value\x18\x02 \x01(\x0b\x32\x1b.labgrid.Reservation.Filter:\x02\x38\x01\"F\n\x19\x43reateReservationResponse\x12)\n\x0breservation\x18\x01 \x01(\x0b\x32\x14.labgrid.Reservation\"\xcd\x03\n\x0bReservation\x12\r\n\x05owner\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\r\n\x05state\x18\x03 \x01(\x05\x12\x0c\n\x04prio\x18\x04 \x01(\x01\x12\x32\n\x07\x66ilters\x18\x05 \x03(\x0b\x32!.labgrid.Reservation.FiltersEntry\x12:\n\x0b\x61llocations\x18\x06 \x03(\x0b\x32%.labgrid.Reservation.AllocationsEntry\x12\x0f\n\x07\x63reated\x18\x07 \x01(\x01\x12\x0f\n\x07timeout\x18\x08 \x01(\x01\x1ap\n\x06\x46ilter\x12\x37\n\x06\x66ilter\x18\x01 \x03(\x0b\x32\'.labgrid.Reservation.Filter.FilterEntry\x1a-\n\x0b\x46ilterEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1aK\n\x0c\x46iltersEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12*\n\x05value\x18\x02 \x01(\x0b\x32\x1b.labgrid.Reservation.Filter:\x02\x38\x01\x1a\x32\n\x10\x41llocationsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\")\n\x18\x43\x61ncelReservationRequest\x12\r\n\x05token\x18\x01 \x01(\t\"\x1b\n\x19\x43\x61ncelReservationResponse\"\'\n\x16PollReservationRequest\x12\r\n\x05token\x18\x01 \x01(\t\"D\n\x17PollReservationResponse\x12)\n\x0breservation\x18\x01 \x01(\x0b\x32\x14.labgrid.Reservation\"E\n\x17GetReservationsResponse\x12*\n\x0creservations\x18\x01 \x03(\x0b\x32\x14.labgrid.Reservation\"\x18\n\x16GetReservationsRequest2\xd2\x0b\n\x0b\x43oordinator\x12I\n\x0c\x43lientStream\x12\x18.labgrid.ClientInMessage\x1a\x19.labgrid.ClientOutMessage\"\x00(\x01\x30\x01\x12O\n\x0e\x45xporterStream\x12\x1a.labgrid.ExporterInMessage\x1a\x1b.labgrid.ExporterOutMessage\"\x00(\x01\x30\x01\x12\x41\n\x08\x41\x64\x64Place\x12\x18.labgrid.AddPlaceRequest\x1a\x19.labgrid.AddPlaceResponse\"\x00\x12J\n\x0b\x44\x65letePlace\x12\x1b.labgrid.DeletePlaceRequest\x1a\x1c.labgrid.DeletePlaceResponse\"\x00\x12\x44\n\tGetPlaces\x12\x19.labgrid.GetPlacesRequest\x1a\x1a.labgrid.GetPlacesResponse\"\x00\x12P\n\rAddPlaceAlias\x12\x1d.labgrid.AddPlaceAliasRequest\x1a\x1e.labgrid.AddPlaceAliasResponse\"\x00\x12Y\n\x10\x44\x65letePlaceAlias\x12 .labgrid.DeletePlaceAliasRequest\x1a!.labgrid.DeletePlaceAliasResponse\"\x00\x12M\n\x0cSetPlaceTags\x12\x1c.labgrid.SetPlaceTagsRequest\x1a\x1d.labgrid.SetPlaceTagsResponse\"\x00\x12V\n\x0fSetPlaceComment\x12\x1f.labgrid.SetPlaceCommentRequest\x1a .labgrid.SetPlaceCommentResponse\"\x00\x12P\n\rAddPlaceMatch\x12\x1d.labgrid.AddPlaceMatchRequest\x1a\x1e.labgrid.AddPlaceMatchResponse\"\x00\x12Y\n\x10\x44\x65letePlaceMatch\x12 .labgrid.DeletePlaceMatchRequest\x1a!.labgrid.DeletePlaceMatchResponse\"\x00\x12M\n\x0c\x41\x63quirePlace\x12\x1c.labgrid.AcquirePlaceRequest\x1a\x1d.labgrid.AcquirePlaceResponse\"\x00\x12M\n\x0cReleasePlace\x12\x1c.labgrid.ReleasePlaceRequest\x1a\x1d.labgrid.ReleasePlaceResponse\"\x00\x12G\n\nAllowPlace\x12\x1a.labgrid.AllowPlaceRequest\x1a\x1b.labgrid.AllowPlaceResponse\"\x00\x12\\\n\x11\x43reateReservation\x12!.labgrid.CreateReservationRequest\x1a\".labgrid.CreateReservationResponse\"\x00\x12\\\n\x11\x43\x61ncelReservation\x12!.labgrid.CancelReservationRequest\x1a\".labgrid.CancelReservationResponse\"\x00\x12V\n\x0fPollReservation\x12\x1f.labgrid.PollReservationRequest\x1a .labgrid.PollReservationResponse\"\x00\x12V\n\x0fGetReservations\x12\x1f.labgrid.GetReservationsRequest\x1a .labgrid.GetReservationsResponse\"\x00\x62\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'labgrid_coordinator_pb2', _globals) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None + _globals['_CLIENTINMESSAGE'].fields_by_name['startup']._options = None + _globals['_CLIENTINMESSAGE'].fields_by_name['startup']._serialized_options = b'\030\001' + _globals['_STARTUPDONE']._options = None + _globals['_STARTUPDONE']._serialized_options = b'\030\001' + _globals['_EXPORTERINMESSAGE'].fields_by_name['startup']._options = None + _globals['_EXPORTERINMESSAGE'].fields_by_name['startup']._serialized_options = b'\030\001' _globals['_RESOURCE_PARAMSENTRY']._options = None _globals['_RESOURCE_PARAMSENTRY']._serialized_options = b'8\001' _globals['_RESOURCE_EXTRAENTRY']._options = None @@ -38,121 +44,121 @@ _globals['_RESERVATION_ALLOCATIONSENTRY']._options = None _globals['_RESERVATION_ALLOCATIONSENTRY']._serialized_options = b'8\001' _globals['_CLIENTINMESSAGE']._serialized_start=39 - _globals['_CLIENTINMESSAGE']._serialized_end=177 - _globals['_SYNC']._serialized_start=179 - _globals['_SYNC']._serialized_end=197 - _globals['_STARTUPDONE']._serialized_start=199 - _globals['_STARTUPDONE']._serialized_end=243 - _globals['_SUBSCRIBE']._serialized_start=245 - _globals['_SUBSCRIBE']._serialized_end=359 - _globals['_CLIENTOUTMESSAGE']._serialized_start=361 - _globals['_CLIENTOUTMESSAGE']._serialized_end=464 - _globals['_UPDATERESPONSE']._serialized_start=467 - _globals['_UPDATERESPONSE']._serialized_end=632 - _globals['_EXPORTERINMESSAGE']._serialized_start=635 - _globals['_EXPORTERINMESSAGE']._serialized_end=789 - _globals['_RESOURCE']._serialized_start=792 - _globals['_RESOURCE']._serialized_end=1206 - _globals['_RESOURCE_PATH']._serialized_start=980 - _globals['_RESOURCE_PATH']._serialized_end=1075 - _globals['_RESOURCE_PARAMSENTRY']._serialized_start=1077 - _globals['_RESOURCE_PARAMSENTRY']._serialized_end=1141 - _globals['_RESOURCE_EXTRAENTRY']._serialized_start=1143 - _globals['_RESOURCE_EXTRAENTRY']._serialized_end=1206 - _globals['_MAPVALUE']._serialized_start=1209 - _globals['_MAPVALUE']._serialized_end=1339 - _globals['_EXPORTERRESPONSE']._serialized_start=1341 - _globals['_EXPORTERRESPONSE']._serialized_end=1408 - _globals['_HELLO']._serialized_start=1410 - _globals['_HELLO']._serialized_end=1434 - _globals['_EXPORTEROUTMESSAGE']._serialized_start=1437 - _globals['_EXPORTEROUTMESSAGE']._serialized_end=1567 - _globals['_EXPORTERSETACQUIREDREQUEST']._serialized_start=1569 - _globals['_EXPORTERSETACQUIREDREQUEST']._serialized_end=1680 - _globals['_ADDPLACEREQUEST']._serialized_start=1682 - _globals['_ADDPLACEREQUEST']._serialized_end=1713 - _globals['_ADDPLACERESPONSE']._serialized_start=1715 - _globals['_ADDPLACERESPONSE']._serialized_end=1733 - _globals['_DELETEPLACEREQUEST']._serialized_start=1735 - _globals['_DELETEPLACEREQUEST']._serialized_end=1769 - _globals['_DELETEPLACERESPONSE']._serialized_start=1771 - _globals['_DELETEPLACERESPONSE']._serialized_end=1792 - _globals['_GETPLACESREQUEST']._serialized_start=1794 - _globals['_GETPLACESREQUEST']._serialized_end=1812 - _globals['_GETPLACESRESPONSE']._serialized_start=1814 - _globals['_GETPLACESRESPONSE']._serialized_end=1865 - _globals['_PLACE']._serialized_start=1868 - _globals['_PLACE']._serialized_end=2206 - _globals['_PLACE_TAGSENTRY']._serialized_start=2134 - _globals['_PLACE_TAGSENTRY']._serialized_end=2177 - _globals['_RESOURCEMATCH']._serialized_start=2208 - _globals['_RESOURCEMATCH']._serialized_end=2329 - _globals['_ADDPLACEALIASREQUEST']._serialized_start=2331 - _globals['_ADDPLACEALIASREQUEST']._serialized_end=2387 - _globals['_ADDPLACEALIASRESPONSE']._serialized_start=2389 - _globals['_ADDPLACEALIASRESPONSE']._serialized_end=2412 - _globals['_DELETEPLACEALIASREQUEST']._serialized_start=2414 - _globals['_DELETEPLACEALIASREQUEST']._serialized_end=2473 - _globals['_DELETEPLACEALIASRESPONSE']._serialized_start=2475 - _globals['_DELETEPLACEALIASRESPONSE']._serialized_end=2501 - _globals['_SETPLACETAGSREQUEST']._serialized_start=2504 - _globals['_SETPLACETAGSREQUEST']._serialized_end=2643 - _globals['_SETPLACETAGSREQUEST_TAGSENTRY']._serialized_start=2134 - _globals['_SETPLACETAGSREQUEST_TAGSENTRY']._serialized_end=2177 - _globals['_SETPLACETAGSRESPONSE']._serialized_start=2645 - _globals['_SETPLACETAGSRESPONSE']._serialized_end=2667 - _globals['_SETPLACECOMMENTREQUEST']._serialized_start=2669 - _globals['_SETPLACECOMMENTREQUEST']._serialized_end=2729 - _globals['_SETPLACECOMMENTRESPONSE']._serialized_start=2731 - _globals['_SETPLACECOMMENTRESPONSE']._serialized_end=2756 - _globals['_ADDPLACEMATCHREQUEST']._serialized_start=2758 - _globals['_ADDPLACEMATCHREQUEST']._serialized_end=2848 - _globals['_ADDPLACEMATCHRESPONSE']._serialized_start=2850 - _globals['_ADDPLACEMATCHRESPONSE']._serialized_end=2873 - _globals['_DELETEPLACEMATCHREQUEST']._serialized_start=2875 - _globals['_DELETEPLACEMATCHREQUEST']._serialized_end=2968 - _globals['_DELETEPLACEMATCHRESPONSE']._serialized_start=2970 - _globals['_DELETEPLACEMATCHRESPONSE']._serialized_end=2996 - _globals['_ACQUIREPLACEREQUEST']._serialized_start=2998 - _globals['_ACQUIREPLACEREQUEST']._serialized_end=3038 - _globals['_ACQUIREPLACERESPONSE']._serialized_start=3040 - _globals['_ACQUIREPLACERESPONSE']._serialized_end=3062 - _globals['_RELEASEPLACEREQUEST']._serialized_start=3064 - _globals['_RELEASEPLACEREQUEST']._serialized_end=3140 - _globals['_RELEASEPLACERESPONSE']._serialized_start=3142 - _globals['_RELEASEPLACERESPONSE']._serialized_end=3164 - _globals['_ALLOWPLACEREQUEST']._serialized_start=3166 - _globals['_ALLOWPLACEREQUEST']._serialized_end=3218 - _globals['_ALLOWPLACERESPONSE']._serialized_start=3220 - _globals['_ALLOWPLACERESPONSE']._serialized_end=3240 - _globals['_CREATERESERVATIONREQUEST']._serialized_start=3243 - _globals['_CREATERESERVATIONREQUEST']._serialized_end=3425 - _globals['_CREATERESERVATIONREQUEST_FILTERSENTRY']._serialized_start=3350 - _globals['_CREATERESERVATIONREQUEST_FILTERSENTRY']._serialized_end=3425 - _globals['_CREATERESERVATIONRESPONSE']._serialized_start=3427 - _globals['_CREATERESERVATIONRESPONSE']._serialized_end=3497 - _globals['_RESERVATION']._serialized_start=3500 - _globals['_RESERVATION']._serialized_end=3961 - _globals['_RESERVATION_FILTER']._serialized_start=3720 - _globals['_RESERVATION_FILTER']._serialized_end=3832 - _globals['_RESERVATION_FILTER_FILTERENTRY']._serialized_start=3787 - _globals['_RESERVATION_FILTER_FILTERENTRY']._serialized_end=3832 - _globals['_RESERVATION_FILTERSENTRY']._serialized_start=3350 - _globals['_RESERVATION_FILTERSENTRY']._serialized_end=3425 - _globals['_RESERVATION_ALLOCATIONSENTRY']._serialized_start=3911 - _globals['_RESERVATION_ALLOCATIONSENTRY']._serialized_end=3961 - _globals['_CANCELRESERVATIONREQUEST']._serialized_start=3963 - _globals['_CANCELRESERVATIONREQUEST']._serialized_end=4004 - _globals['_CANCELRESERVATIONRESPONSE']._serialized_start=4006 - _globals['_CANCELRESERVATIONRESPONSE']._serialized_end=4033 - _globals['_POLLRESERVATIONREQUEST']._serialized_start=4035 - _globals['_POLLRESERVATIONREQUEST']._serialized_end=4074 - _globals['_POLLRESERVATIONRESPONSE']._serialized_start=4076 - _globals['_POLLRESERVATIONRESPONSE']._serialized_end=4144 - _globals['_GETRESERVATIONSRESPONSE']._serialized_start=4146 - _globals['_GETRESERVATIONSRESPONSE']._serialized_end=4215 - _globals['_GETRESERVATIONSREQUEST']._serialized_start=4217 - _globals['_GETRESERVATIONSREQUEST']._serialized_end=4241 - _globals['_COORDINATOR']._serialized_start=4244 - _globals['_COORDINATOR']._serialized_end=5734 + _globals['_CLIENTINMESSAGE']._serialized_end=181 + _globals['_SYNC']._serialized_start=183 + _globals['_SYNC']._serialized_end=201 + _globals['_STARTUPDONE']._serialized_start=203 + _globals['_STARTUPDONE']._serialized_end=251 + _globals['_SUBSCRIBE']._serialized_start=253 + _globals['_SUBSCRIBE']._serialized_end=367 + _globals['_CLIENTOUTMESSAGE']._serialized_start=369 + _globals['_CLIENTOUTMESSAGE']._serialized_end=472 + _globals['_UPDATERESPONSE']._serialized_start=475 + _globals['_UPDATERESPONSE']._serialized_end=640 + _globals['_EXPORTERINMESSAGE']._serialized_start=643 + _globals['_EXPORTERINMESSAGE']._serialized_end=801 + _globals['_RESOURCE']._serialized_start=804 + _globals['_RESOURCE']._serialized_end=1218 + _globals['_RESOURCE_PATH']._serialized_start=992 + _globals['_RESOURCE_PATH']._serialized_end=1087 + _globals['_RESOURCE_PARAMSENTRY']._serialized_start=1089 + _globals['_RESOURCE_PARAMSENTRY']._serialized_end=1153 + _globals['_RESOURCE_EXTRAENTRY']._serialized_start=1155 + _globals['_RESOURCE_EXTRAENTRY']._serialized_end=1218 + _globals['_MAPVALUE']._serialized_start=1221 + _globals['_MAPVALUE']._serialized_end=1351 + _globals['_EXPORTERRESPONSE']._serialized_start=1353 + _globals['_EXPORTERRESPONSE']._serialized_end=1420 + _globals['_HELLO']._serialized_start=1422 + _globals['_HELLO']._serialized_end=1446 + _globals['_EXPORTEROUTMESSAGE']._serialized_start=1449 + _globals['_EXPORTEROUTMESSAGE']._serialized_end=1579 + _globals['_EXPORTERSETACQUIREDREQUEST']._serialized_start=1581 + _globals['_EXPORTERSETACQUIREDREQUEST']._serialized_end=1692 + _globals['_ADDPLACEREQUEST']._serialized_start=1694 + _globals['_ADDPLACEREQUEST']._serialized_end=1725 + _globals['_ADDPLACERESPONSE']._serialized_start=1727 + _globals['_ADDPLACERESPONSE']._serialized_end=1745 + _globals['_DELETEPLACEREQUEST']._serialized_start=1747 + _globals['_DELETEPLACEREQUEST']._serialized_end=1781 + _globals['_DELETEPLACERESPONSE']._serialized_start=1783 + _globals['_DELETEPLACERESPONSE']._serialized_end=1804 + _globals['_GETPLACESREQUEST']._serialized_start=1806 + _globals['_GETPLACESREQUEST']._serialized_end=1824 + _globals['_GETPLACESRESPONSE']._serialized_start=1826 + _globals['_GETPLACESRESPONSE']._serialized_end=1877 + _globals['_PLACE']._serialized_start=1880 + _globals['_PLACE']._serialized_end=2218 + _globals['_PLACE_TAGSENTRY']._serialized_start=2146 + _globals['_PLACE_TAGSENTRY']._serialized_end=2189 + _globals['_RESOURCEMATCH']._serialized_start=2220 + _globals['_RESOURCEMATCH']._serialized_end=2341 + _globals['_ADDPLACEALIASREQUEST']._serialized_start=2343 + _globals['_ADDPLACEALIASREQUEST']._serialized_end=2399 + _globals['_ADDPLACEALIASRESPONSE']._serialized_start=2401 + _globals['_ADDPLACEALIASRESPONSE']._serialized_end=2424 + _globals['_DELETEPLACEALIASREQUEST']._serialized_start=2426 + _globals['_DELETEPLACEALIASREQUEST']._serialized_end=2485 + _globals['_DELETEPLACEALIASRESPONSE']._serialized_start=2487 + _globals['_DELETEPLACEALIASRESPONSE']._serialized_end=2513 + _globals['_SETPLACETAGSREQUEST']._serialized_start=2516 + _globals['_SETPLACETAGSREQUEST']._serialized_end=2655 + _globals['_SETPLACETAGSREQUEST_TAGSENTRY']._serialized_start=2146 + _globals['_SETPLACETAGSREQUEST_TAGSENTRY']._serialized_end=2189 + _globals['_SETPLACETAGSRESPONSE']._serialized_start=2657 + _globals['_SETPLACETAGSRESPONSE']._serialized_end=2679 + _globals['_SETPLACECOMMENTREQUEST']._serialized_start=2681 + _globals['_SETPLACECOMMENTREQUEST']._serialized_end=2741 + _globals['_SETPLACECOMMENTRESPONSE']._serialized_start=2743 + _globals['_SETPLACECOMMENTRESPONSE']._serialized_end=2768 + _globals['_ADDPLACEMATCHREQUEST']._serialized_start=2770 + _globals['_ADDPLACEMATCHREQUEST']._serialized_end=2860 + _globals['_ADDPLACEMATCHRESPONSE']._serialized_start=2862 + _globals['_ADDPLACEMATCHRESPONSE']._serialized_end=2885 + _globals['_DELETEPLACEMATCHREQUEST']._serialized_start=2887 + _globals['_DELETEPLACEMATCHREQUEST']._serialized_end=2980 + _globals['_DELETEPLACEMATCHRESPONSE']._serialized_start=2982 + _globals['_DELETEPLACEMATCHRESPONSE']._serialized_end=3008 + _globals['_ACQUIREPLACEREQUEST']._serialized_start=3010 + _globals['_ACQUIREPLACEREQUEST']._serialized_end=3050 + _globals['_ACQUIREPLACERESPONSE']._serialized_start=3052 + _globals['_ACQUIREPLACERESPONSE']._serialized_end=3074 + _globals['_RELEASEPLACEREQUEST']._serialized_start=3076 + _globals['_RELEASEPLACEREQUEST']._serialized_end=3152 + _globals['_RELEASEPLACERESPONSE']._serialized_start=3154 + _globals['_RELEASEPLACERESPONSE']._serialized_end=3176 + _globals['_ALLOWPLACEREQUEST']._serialized_start=3178 + _globals['_ALLOWPLACEREQUEST']._serialized_end=3230 + _globals['_ALLOWPLACERESPONSE']._serialized_start=3232 + _globals['_ALLOWPLACERESPONSE']._serialized_end=3252 + _globals['_CREATERESERVATIONREQUEST']._serialized_start=3255 + _globals['_CREATERESERVATIONREQUEST']._serialized_end=3437 + _globals['_CREATERESERVATIONREQUEST_FILTERSENTRY']._serialized_start=3362 + _globals['_CREATERESERVATIONREQUEST_FILTERSENTRY']._serialized_end=3437 + _globals['_CREATERESERVATIONRESPONSE']._serialized_start=3439 + _globals['_CREATERESERVATIONRESPONSE']._serialized_end=3509 + _globals['_RESERVATION']._serialized_start=3512 + _globals['_RESERVATION']._serialized_end=3973 + _globals['_RESERVATION_FILTER']._serialized_start=3732 + _globals['_RESERVATION_FILTER']._serialized_end=3844 + _globals['_RESERVATION_FILTER_FILTERENTRY']._serialized_start=3799 + _globals['_RESERVATION_FILTER_FILTERENTRY']._serialized_end=3844 + _globals['_RESERVATION_FILTERSENTRY']._serialized_start=3362 + _globals['_RESERVATION_FILTERSENTRY']._serialized_end=3437 + _globals['_RESERVATION_ALLOCATIONSENTRY']._serialized_start=3923 + _globals['_RESERVATION_ALLOCATIONSENTRY']._serialized_end=3973 + _globals['_CANCELRESERVATIONREQUEST']._serialized_start=3975 + _globals['_CANCELRESERVATIONREQUEST']._serialized_end=4016 + _globals['_CANCELRESERVATIONRESPONSE']._serialized_start=4018 + _globals['_CANCELRESERVATIONRESPONSE']._serialized_end=4045 + _globals['_POLLRESERVATIONREQUEST']._serialized_start=4047 + _globals['_POLLRESERVATIONREQUEST']._serialized_end=4086 + _globals['_POLLRESERVATIONRESPONSE']._serialized_start=4088 + _globals['_POLLRESERVATIONRESPONSE']._serialized_end=4156 + _globals['_GETRESERVATIONSRESPONSE']._serialized_start=4158 + _globals['_GETRESERVATIONSRESPONSE']._serialized_end=4227 + _globals['_GETRESERVATIONSREQUEST']._serialized_start=4229 + _globals['_GETRESERVATIONSREQUEST']._serialized_end=4253 + _globals['_COORDINATOR']._serialized_start=4256 + _globals['_COORDINATOR']._serialized_end=5746 # @@protoc_insertion_point(module_scope) diff --git a/labgrid/remote/identity.py b/labgrid/remote/identity.py index 535373ee4..8344665f3 100644 --- a/labgrid/remote/identity.py +++ b/labgrid/remote/identity.py @@ -1,3 +1,5 @@ +import contextvars +import logging from typing import Optional from labgrid.remote.common import get_metadata_single_value_by_key @@ -46,3 +48,15 @@ def from_metadata(cls, metadata: tuple): return cls(f"{hostname}/{username}", user_agent) return cls(hostname, user_agent) + + +def infer_peer_identity(clients, context, identity_contextvar: contextvars.ContextVar[Optional[ClientIdentity]]): + logger = logging.getLogger("infer_peer_identity") + + user = identity_contextvar.get() + if user: + logger.debug("identity sourced from metadata") + return user.id + + logger.debug("identity sourced from self.clients") + return clients[context.peer()].name diff --git a/labgrid/remote/proto/labgrid-coordinator.proto b/labgrid/remote/proto/labgrid-coordinator.proto index e0585f7e1..8d633b160 100644 --- a/labgrid/remote/proto/labgrid-coordinator.proto +++ b/labgrid/remote/proto/labgrid-coordinator.proto @@ -43,7 +43,7 @@ service Coordinator { message ClientInMessage { oneof kind { Sync sync = 1; - StartupDone startup = 2; + StartupDone startup = 2 [deprecated = true]; Subscribe subscribe = 3; }; }; @@ -53,6 +53,8 @@ message Sync { }; message StartupDone { + option deprecated = true; + string version = 1; string name = 2; }; @@ -82,7 +84,7 @@ message UpdateResponse { message ExporterInMessage { oneof kind { Resource resource = 1; - StartupDone startup = 2; + StartupDone startup = 2 [deprecated = true]; ExporterResponse response = 3; }; };