diff --git a/doc/usage.rst b/doc/usage.rst index 9d423d50b..9d4629ec9 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -872,3 +872,20 @@ like this: $ labgrid-client -p example allow sirius/john To remove the allow it is currently necessary to unlock and lock the place. + +Using places within a session +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +This workflow enables places and reservations to be released when a "session" is killed. +This is useful when running a session within a CI job, so that if the CI job is killed, +its places and reservations are freed. + +Use the ``labgrid-client monitor --session `` command to start a session. +The ``--session`` option can be used to tie reservations and place acquisitions to a session. +If the ``monitor`` process is killed then all reservations and place acquisitions will be freed. + +Example: +.. code-block:: bash + + $ labgrid-client monitor --session=my-session & + $ labgrid-client reserve --session=my-session tag=my-tag + $ labgrid-client -p + acquire --session=my-session diff --git a/labgrid/remote/client.py b/labgrid/remote/client.py index 5ab4f0683..696f70da2 100755 --- a/labgrid/remote/client.py +++ b/labgrid/remote/client.py @@ -120,6 +120,7 @@ async def start(self): msg = labgrid_coordinator_pb2.ClientInMessage() msg.startup.version = labgrid_version() msg.startup.name = f"{self.gethostname()}/{self.getuser()}" + msg.startup.session = self.args.monitor_session if hasattr(self.args, "monitor_session") else "" self.out_queue.put_nowait(msg) msg = labgrid_coordinator_pb2.ClientInMessage() msg.subscribe.all_places = True @@ -669,7 +670,7 @@ async def acquire(self): if not self.args.allow_unmatched: self.check_matches(place) - request = labgrid_coordinator_pb2.AcquirePlaceRequest(placename=place.name) + request = labgrid_coordinator_pb2.AcquirePlaceRequest(placename=place.name, session=self.args.session) try: await self.stub.AcquirePlace(request) @@ -1416,6 +1417,7 @@ def write_image(self): async def create_reservation(self): prio = self.args.prio + session = self.args.session fltr = {} for pair in self.args.filters: @@ -1433,7 +1435,7 @@ async def create_reservation(self): "main": labgrid_coordinator_pb2.Reservation.Filter(filter=fltr), } - request = labgrid_coordinator_pb2.CreateReservationRequest(filters=fltrs, prio=prio) + request = labgrid_coordinator_pb2.CreateReservationRequest(filters=fltrs, prio=prio, session=session) try: response: labgrid_coordinator_pb2.CreateReservationResponse = await self.stub.CreateReservation(request) @@ -1712,6 +1714,9 @@ def main(): subparser.set_defaults(func=ClientSession.complete) subparser = subparsers.add_parser("monitor", help="monitor events from the coordinator") + subparser.add_argument( + "--session", default="", dest="monitor_session", help="Create a session to book places and reservations under" + ) subparser.set_defaults(func=ClientSession.do_monitor) subparser = subparsers.add_parser("resources", aliases=("r",), help="list available resources") @@ -1778,6 +1783,7 @@ def main(): subparser.add_argument( "--allow-unmatched", action="store_true", help="allow missing resources for matches when locking the place" ) + subparser.add_argument("--session", default="", help="Acquire a place within a given session") subparser.set_defaults(func=ClientSession.acquire) subparser = subparsers.add_parser("release", aliases=("unlock",), help="release a place") @@ -2001,6 +2007,7 @@ def main(): "--prio", type=float, default=0.0, help="priority relative to other reservations (default 0)" ) subparser.add_argument("filters", metavar="KEY=VALUE", nargs="+", help="required tags") + subparser.add_argument("--session", default="", help="Make a reservation within a given session") subparser.set_defaults(func=ClientSession.create_reservation) subparser = subparsers.add_parser("cancel-reservation", help="cancel a reservation") diff --git a/labgrid/remote/common.py b/labgrid/remote/common.py index 93b6b22e7..44cc52485 100644 --- a/labgrid/remote/common.py +++ b/labgrid/remote/common.py @@ -230,6 +230,7 @@ class Place: created = attr.ib(default=attr.Factory(time.time)) changed = attr.ib(default=attr.Factory(time.time)) reservation = attr.ib(default=None) + session = attr.ib(default="") def asdict(self): # in the coordinator, we have resource objects, otherwise just a path @@ -251,6 +252,7 @@ def asdict(self): "created": self.created, "changed": self.changed, "reservation": self.reservation, + "session": self.session, } def update_from_pb2(self, place_pb2): @@ -298,6 +300,8 @@ def show(self, level=0): print(indent + f"changed: {datetime.fromtimestamp(self.changed)}") if self.reservation: print(indent + f"reservation: {self.reservation}") + if self.session: + print(indent + f"session: {self.session}") def getmatch(self, resource_path): """Return the ResourceMatch object for the given resource path or None if not found. @@ -350,6 +354,7 @@ def as_pb2(self): place.created = self.created if self.reservation: place.reservation = self.reservation + place.session = self.session for key, value in self.tags.items(): place.tags[key] = value return place @@ -377,6 +382,7 @@ def from_pb2(cls, pb2): created=pb2.created, changed=pb2.changed, reservation=pb2.reservation if pb2.HasField("reservation") else None, + session=pb2.session, ) @@ -406,6 +412,7 @@ class Reservation: allocations = attr.ib(default=attr.Factory(dict), validator=attr.validators.instance_of(dict)) created = attr.ib(default=attr.Factory(time.time)) timeout = attr.ib(default=attr.Factory(lambda: time.time() + 60)) + session = attr.ib(default="") def asdict(self): return { @@ -416,6 +423,7 @@ def asdict(self): "allocations": self.allocations, "created": self.created, "timeout": self.timeout, + "session": self.session, } def refresh(self, delta=60): @@ -441,6 +449,8 @@ def show(self, level=0): print(indent + f" {name}: {', '.join(allocation)}") print(indent + f"created: {datetime.fromtimestamp(self.created)}") print(indent + f"timeout: {datetime.fromtimestamp(self.timeout)}") + if self.session: + print(indent + f"session: {self.session}") def as_pb2(self): res = labgrid_coordinator_pb2.Reservation() @@ -459,6 +469,7 @@ def as_pb2(self): res.allocations.update({"main": allocation[0]}) res.created = self.created res.timeout = self.timeout + res.session = self.session return res @classmethod @@ -478,6 +489,7 @@ def from_pb2(cls, pb2: labgrid_coordinator_pb2.Reservation): allocations=allocations, created=pb2.created, timeout=pb2.timeout, + session=pb2.session, ) diff --git a/labgrid/remote/coordinator.py b/labgrid/remote/coordinator.py index eb081e0fc..a23d22eb7 100644 --- a/labgrid/remote/coordinator.py +++ b/labgrid/remote/coordinator.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 import argparse -import logging import asyncio +import logging import traceback +from copy import copy from enum import Enum from functools import wraps @@ -10,20 +11,19 @@ import grpc from grpc_reflection.v1alpha import reflection +from ..util import atomic_replace, labgrid_version, yaml from .common import ( - ResourceEntry, - ResourceMatch, + TAG_KEY, + TAG_VAL, Place, Reservation, ReservationState, + ResourceEntry, + ResourceMatch, queue_as_aiter, - TAG_KEY, - TAG_VAL, ) +from .generated import labgrid_coordinator_pb2, labgrid_coordinator_pb2_grpc from .scheduler import TagSet, schedule -from .generated import labgrid_coordinator_pb2 -from .generated import labgrid_coordinator_pb2_grpc -from ..util import atomic_replace, labgrid_version, yaml class Action(Enum): @@ -110,6 +110,8 @@ def get_resources(self): @attr.s(eq=False) class ClientSession(RemoteSession): + id = attr.ib() + def subscribe_places(self): # send initial places out_msg = labgrid_coordinator_pb2.ClientOutMessage() @@ -182,6 +184,53 @@ class ExporterError(Exception): pass +class _SessionManager: + def __init__(self): + self._sessions = {} + + def add_session(self, session): + assert session not in self._sessions, f"Session {session} already exists" + self._sessions[session] = { + "places": set(), + "reservations": set(), + } + + def remove_session(self, session): + self._assert_session(session) + del self._sessions[session] + + def get_session(self, session): + self._assert_session(session) + return ( + copy(self._sessions[session]["places"]), + copy(self._sessions[session]["reservations"]), + ) + + def add_place(self, place): + self._assert_session(place.session) + self._sessions[place.session]["places"].add(place) + + def add_reservation(self, reservation): + self._assert_session(reservation.session) + self._sessions[reservation.session]["reservations"].add(reservation) + + def remove_place(self, place): + self._assert_session(place.session) + places = self._sessions[place.session]["places"] + assert place in places, f"Session {place.session} does not contain place {place.name}" + + def remove_reservation(self, reservation): + self._assert_session(reservation.session) + reservations = self._sessions[reservation.session]["reservations"] + assert ( + reservation in reservations + ), f"Session {reservation.session} does not contain reservation {reservation.token}" + reservations.remove(reservation) + + def _assert_session(self, session): + assert session in self._sessions, f"Session {session} does not exist" + + class Coordinator(labgrid_coordinator_pb2_grpc.CoordinatorServicer): def __init__(self) -> None: self.places: dict[str, Place] = {} @@ -189,6 +238,8 @@ def __init__(self) -> None: self.poll_task = None self.save_scheduled = False + self.session_manager = _SessionManager() + self.lock = asyncio.Lock() self.exporters: dict[str, ExporterSession] = {} self.clients: dict[str, ClientSession] = {} @@ -268,6 +319,8 @@ def load(self): del config["allowed"] if "reservation" in config: del config["reservation"] + if "session" in config: + del config["session"] config["matches"] = [ResourceMatch(**match) for match in config["matches"]] place = Place(**config) self.places[placename] = place @@ -296,7 +349,10 @@ async def request_task(): elif kind == "startup": version = in_msg.startup.version name = in_msg.startup.name - session = self.clients[peer] = ClientSession(self, peer, name, out_msg_queue, version) + id_ = self._session_id(peer, in_msg.startup.session) + session = self.clients[peer] = ClientSession(self, peer, name, out_msg_queue, version, id_) + if id_: + self.session_manager.add_session(id_) logging.debug("Received startup from %s with %s", name, version) asyncio.current_task().set_name(f"client-{peer}-rx/started-{name}") elif kind == "subscribe": @@ -325,6 +381,9 @@ async def request_task(): logging.info("Never received startup from peer %s that disconnected", peer) return + if session.id: + await self._release_session(session) + running_request_task.cancel() await running_request_task logging.debug("client aborted %s, cancelled: %s", session, context.cancelled()) @@ -717,6 +776,11 @@ async def AcquirePlace(self, request, context): res = self.reservations[place.reservation] if not res.owner == username: await context.abort(grpc.StatusCode.PERMISSION_DENIED, f"Place {name} was not reserved for {username}") + if res.session and res.session != self._session_id(peer, request.session): + await context.abort( + grpc.StatusCode.PERMISSION_DENIED, + f'Place session "{request.session}" is not the same as the reservation session "{res.session}"', + ) # First try to reacquire orphaned resources to avoid conflicts. await self._reacquire_orphaned_resources() @@ -724,6 +788,9 @@ async def AcquirePlace(self, request, context): # FIXME use the session object instead? or something else which # survives disconnecting clients? place.acquired = username + place.session = self._session_id(peer, request.session) + if place.session: + self.session_manager.add_place(place) resources = [] for _, session in sorted(self.exporters.items()): for _, group in sorted(session.groups.items()): @@ -758,16 +825,23 @@ async def ReleasePlace(self, request, context): if fromuser and place.acquired != fromuser: return labgrid_coordinator_pb2.ReleasePlaceResponse() + await self._release_place(place) + return labgrid_coordinator_pb2.ReleasePlaceResponse() + + async def _release_place(self, place): await self._release_resources(place, place.acquired_resources) + if place.session: + self.session_manager.remove_place(place) + place.acquired = None + place.session = "" place.allowed = set() place.touch() self._publish_place(place) self.save_later() self.schedule_reservations() print(f"{place.name}: place released") - return labgrid_coordinator_pb2.ReleasePlaceResponse() @locked async def AllowPlace(self, request, context): @@ -929,7 +1003,11 @@ async def CreateReservation(self, request: labgrid_coordinator_pb2.CreateReserva fltr[k] = v owner = self.clients[peer].name - res = Reservation(owner=owner, prio=request.prio, filters=fltrs) + res = Reservation( + owner=owner, prio=request.prio, filters=fltrs, session=self._session_id(peer, request.session) + ) + if request.session: + self.session_manager.add_reservation(res) self.reservations[res.token] = res self.schedule_reservations() return labgrid_coordinator_pb2.CreateReservationResponse(reservation=res.as_pb2()) @@ -941,9 +1019,15 @@ async def CancelReservation(self, request: labgrid_coordinator_pb2.CancelReserva await context.abort(grpc.StatusCode.INVALID_ARGUMENT, f"Invalid token {token}") if token not in self.reservations: await context.abort(grpc.StatusCode.FAILED_PRECONDITION, f"Reservation {token} does not exist") + self._release_reservation(token) + return labgrid_coordinator_pb2.CancelReservationResponse() + + def _release_reservation(self, token): + reservation = self.reservations[token] + if reservation.session: + self.session_manager.remove_reservation(reservation) del self.reservations[token] self.schedule_reservations() - return labgrid_coordinator_pb2.CancelReservationResponse() @locked async def PollReservation(self, request: labgrid_coordinator_pb2.PollReservationRequest, context): @@ -960,6 +1044,23 @@ async def GetReservations(self, request: labgrid_coordinator_pb2.GetReservations reservations = [x.as_pb2() for x in self.reservations.values()] return labgrid_coordinator_pb2.GetReservationsResponse(reservations=reservations) + async def _release_session(self, client_session): + places, reservations = self.session_manager.get_session(client_session.id) + await self.lock.acquire() + for place in places: + await self._release_place(place) + for reservation in reservations: + self._release_reservation(reservation.token) + self.lock.release() + + self.session_manager.remove_session(client_session.id) + + def _session_id(self, peer, name): + if not name: + return "" + ip = ":".join(peer.split(":")[:2]) + return f"{ip}/{name}" + async def serve(listen, cleanup) -> None: asyncio.current_task().set_name("coordinator-serve") diff --git a/labgrid/remote/generated/labgrid_coordinator_pb2.py b/labgrid/remote/generated/labgrid_coordinator_pb2.py index 37652bff7..a84cadbfc 100644 --- a/labgrid/remote/generated/labgrid_coordinator_pb2.py +++ b/labgrid/remote/generated/labgrid_coordinator_pb2.py @@ -14,7 +14,7 @@ -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\"\xbe\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\x12\x32\n\x0fmonitor_session\x18\x04 \x01(\x0b\x32\x17.labgrid.MonitorSessionH\x00\x42\x06\n\x04kind\"\x12\n\x04Sync\x12\n\n\x02id\x18\x01 \x01(\x04\"N\n\x0bStartupDone\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x14\n\x07session\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\n\n\x08_session\"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\"!\n\x0eMonitorSession\x12\x0f\n\x07session\x18\x01 \x01(\t\"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\"\xf4\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\x12\x14\n\x07session\x18\x0c \x01(\tH\x02\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_reservationB\n\n\x08_session\"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\"J\n\x13\x41\x63quirePlaceRequest\x12\x11\n\tplacename\x18\x01 \x01(\t\x12\x14\n\x07session\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\n\n\x08_session\"\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\"\xd8\x01\n\x18\x43reateReservationRequest\x12?\n\x07\x66ilters\x18\x01 \x03(\x0b\x32..labgrid.CreateReservationRequest.FiltersEntry\x12\x0c\n\x04prio\x18\x02 \x01(\x01\x12\x14\n\x07session\x18\x03 \x01(\tH\x00\x88\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\x42\n\n\x08_session\"F\n\x19\x43reateReservationResponse\x12)\n\x0breservation\x18\x01 \x01(\x0b\x32\x14.labgrid.Reservation\"\xef\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\x12\x14\n\x07session\x18\t \x01(\tH\x00\x88\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\x42\n\n\x08_session\")\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) @@ -38,121 +38,123 @@ _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=229 + _globals['_SYNC']._serialized_start=231 + _globals['_SYNC']._serialized_end=249 + _globals['_STARTUPDONE']._serialized_start=251 + _globals['_STARTUPDONE']._serialized_end=329 + _globals['_SUBSCRIBE']._serialized_start=331 + _globals['_SUBSCRIBE']._serialized_end=445 + _globals['_MONITORSESSION']._serialized_start=447 + _globals['_MONITORSESSION']._serialized_end=480 + _globals['_CLIENTOUTMESSAGE']._serialized_start=482 + _globals['_CLIENTOUTMESSAGE']._serialized_end=585 + _globals['_UPDATERESPONSE']._serialized_start=588 + _globals['_UPDATERESPONSE']._serialized_end=753 + _globals['_EXPORTERINMESSAGE']._serialized_start=756 + _globals['_EXPORTERINMESSAGE']._serialized_end=910 + _globals['_RESOURCE']._serialized_start=913 + _globals['_RESOURCE']._serialized_end=1327 + _globals['_RESOURCE_PATH']._serialized_start=1101 + _globals['_RESOURCE_PATH']._serialized_end=1196 + _globals['_RESOURCE_PARAMSENTRY']._serialized_start=1198 + _globals['_RESOURCE_PARAMSENTRY']._serialized_end=1262 + _globals['_RESOURCE_EXTRAENTRY']._serialized_start=1264 + _globals['_RESOURCE_EXTRAENTRY']._serialized_end=1327 + _globals['_MAPVALUE']._serialized_start=1330 + _globals['_MAPVALUE']._serialized_end=1460 + _globals['_EXPORTERRESPONSE']._serialized_start=1462 + _globals['_EXPORTERRESPONSE']._serialized_end=1529 + _globals['_HELLO']._serialized_start=1531 + _globals['_HELLO']._serialized_end=1555 + _globals['_EXPORTEROUTMESSAGE']._serialized_start=1558 + _globals['_EXPORTEROUTMESSAGE']._serialized_end=1688 + _globals['_EXPORTERSETACQUIREDREQUEST']._serialized_start=1690 + _globals['_EXPORTERSETACQUIREDREQUEST']._serialized_end=1801 + _globals['_ADDPLACEREQUEST']._serialized_start=1803 + _globals['_ADDPLACEREQUEST']._serialized_end=1834 + _globals['_ADDPLACERESPONSE']._serialized_start=1836 + _globals['_ADDPLACERESPONSE']._serialized_end=1854 + _globals['_DELETEPLACEREQUEST']._serialized_start=1856 + _globals['_DELETEPLACEREQUEST']._serialized_end=1890 + _globals['_DELETEPLACERESPONSE']._serialized_start=1892 + _globals['_DELETEPLACERESPONSE']._serialized_end=1913 + _globals['_GETPLACESREQUEST']._serialized_start=1915 + _globals['_GETPLACESREQUEST']._serialized_end=1933 + _globals['_GETPLACESRESPONSE']._serialized_start=1935 + _globals['_GETPLACESRESPONSE']._serialized_end=1986 + _globals['_PLACE']._serialized_start=1989 + _globals['_PLACE']._serialized_end=2361 + _globals['_PLACE_TAGSENTRY']._serialized_start=2277 + _globals['_PLACE_TAGSENTRY']._serialized_end=2320 + _globals['_RESOURCEMATCH']._serialized_start=2363 + _globals['_RESOURCEMATCH']._serialized_end=2484 + _globals['_ADDPLACEALIASREQUEST']._serialized_start=2486 + _globals['_ADDPLACEALIASREQUEST']._serialized_end=2542 + _globals['_ADDPLACEALIASRESPONSE']._serialized_start=2544 + _globals['_ADDPLACEALIASRESPONSE']._serialized_end=2567 + _globals['_DELETEPLACEALIASREQUEST']._serialized_start=2569 + _globals['_DELETEPLACEALIASREQUEST']._serialized_end=2628 + _globals['_DELETEPLACEALIASRESPONSE']._serialized_start=2630 + _globals['_DELETEPLACEALIASRESPONSE']._serialized_end=2656 + _globals['_SETPLACETAGSREQUEST']._serialized_start=2659 + _globals['_SETPLACETAGSREQUEST']._serialized_end=2798 + _globals['_SETPLACETAGSREQUEST_TAGSENTRY']._serialized_start=2277 + _globals['_SETPLACETAGSREQUEST_TAGSENTRY']._serialized_end=2320 + _globals['_SETPLACETAGSRESPONSE']._serialized_start=2800 + _globals['_SETPLACETAGSRESPONSE']._serialized_end=2822 + _globals['_SETPLACECOMMENTREQUEST']._serialized_start=2824 + _globals['_SETPLACECOMMENTREQUEST']._serialized_end=2884 + _globals['_SETPLACECOMMENTRESPONSE']._serialized_start=2886 + _globals['_SETPLACECOMMENTRESPONSE']._serialized_end=2911 + _globals['_ADDPLACEMATCHREQUEST']._serialized_start=2913 + _globals['_ADDPLACEMATCHREQUEST']._serialized_end=3003 + _globals['_ADDPLACEMATCHRESPONSE']._serialized_start=3005 + _globals['_ADDPLACEMATCHRESPONSE']._serialized_end=3028 + _globals['_DELETEPLACEMATCHREQUEST']._serialized_start=3030 + _globals['_DELETEPLACEMATCHREQUEST']._serialized_end=3123 + _globals['_DELETEPLACEMATCHRESPONSE']._serialized_start=3125 + _globals['_DELETEPLACEMATCHRESPONSE']._serialized_end=3151 + _globals['_ACQUIREPLACEREQUEST']._serialized_start=3153 + _globals['_ACQUIREPLACEREQUEST']._serialized_end=3227 + _globals['_ACQUIREPLACERESPONSE']._serialized_start=3229 + _globals['_ACQUIREPLACERESPONSE']._serialized_end=3251 + _globals['_RELEASEPLACEREQUEST']._serialized_start=3253 + _globals['_RELEASEPLACEREQUEST']._serialized_end=3329 + _globals['_RELEASEPLACERESPONSE']._serialized_start=3331 + _globals['_RELEASEPLACERESPONSE']._serialized_end=3353 + _globals['_ALLOWPLACEREQUEST']._serialized_start=3355 + _globals['_ALLOWPLACEREQUEST']._serialized_end=3407 + _globals['_ALLOWPLACERESPONSE']._serialized_start=3409 + _globals['_ALLOWPLACERESPONSE']._serialized_end=3429 + _globals['_CREATERESERVATIONREQUEST']._serialized_start=3432 + _globals['_CREATERESERVATIONREQUEST']._serialized_end=3648 + _globals['_CREATERESERVATIONREQUEST_FILTERSENTRY']._serialized_start=3561 + _globals['_CREATERESERVATIONREQUEST_FILTERSENTRY']._serialized_end=3636 + _globals['_CREATERESERVATIONRESPONSE']._serialized_start=3650 + _globals['_CREATERESERVATIONRESPONSE']._serialized_end=3720 + _globals['_RESERVATION']._serialized_start=3723 + _globals['_RESERVATION']._serialized_end=4218 + _globals['_RESERVATION_FILTER']._serialized_start=3965 + _globals['_RESERVATION_FILTER']._serialized_end=4077 + _globals['_RESERVATION_FILTER_FILTERENTRY']._serialized_start=4032 + _globals['_RESERVATION_FILTER_FILTERENTRY']._serialized_end=4077 + _globals['_RESERVATION_FILTERSENTRY']._serialized_start=3561 + _globals['_RESERVATION_FILTERSENTRY']._serialized_end=3636 + _globals['_RESERVATION_ALLOCATIONSENTRY']._serialized_start=4156 + _globals['_RESERVATION_ALLOCATIONSENTRY']._serialized_end=4206 + _globals['_CANCELRESERVATIONREQUEST']._serialized_start=4220 + _globals['_CANCELRESERVATIONREQUEST']._serialized_end=4261 + _globals['_CANCELRESERVATIONRESPONSE']._serialized_start=4263 + _globals['_CANCELRESERVATIONRESPONSE']._serialized_end=4290 + _globals['_POLLRESERVATIONREQUEST']._serialized_start=4292 + _globals['_POLLRESERVATIONREQUEST']._serialized_end=4331 + _globals['_POLLRESERVATIONRESPONSE']._serialized_start=4333 + _globals['_POLLRESERVATIONRESPONSE']._serialized_end=4401 + _globals['_GETRESERVATIONSRESPONSE']._serialized_start=4403 + _globals['_GETRESERVATIONSRESPONSE']._serialized_end=4472 + _globals['_GETRESERVATIONSREQUEST']._serialized_start=4474 + _globals['_GETRESERVATIONSREQUEST']._serialized_end=4498 + _globals['_COORDINATOR']._serialized_start=4501 + _globals['_COORDINATOR']._serialized_end=5991 # @@protoc_insertion_point(module_scope) diff --git a/labgrid/remote/generated/labgrid_coordinator_pb2.pyi b/labgrid/remote/generated/labgrid_coordinator_pb2.pyi index 366f4e438..df3eb20ee 100644 --- a/labgrid/remote/generated/labgrid_coordinator_pb2.pyi +++ b/labgrid/remote/generated/labgrid_coordinator_pb2.pyi @@ -6,14 +6,16 @@ from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Map DESCRIPTOR: _descriptor.FileDescriptor class ClientInMessage(_message.Message): - __slots__ = ("sync", "startup", "subscribe") + __slots__ = ("sync", "startup", "subscribe", "monitor_session") SYNC_FIELD_NUMBER: _ClassVar[int] STARTUP_FIELD_NUMBER: _ClassVar[int] SUBSCRIBE_FIELD_NUMBER: _ClassVar[int] + MONITOR_SESSION_FIELD_NUMBER: _ClassVar[int] sync: Sync startup: StartupDone subscribe: Subscribe - def __init__(self, sync: _Optional[_Union[Sync, _Mapping]] = ..., startup: _Optional[_Union[StartupDone, _Mapping]] = ..., subscribe: _Optional[_Union[Subscribe, _Mapping]] = ...) -> None: ... + monitor_session: MonitorSession + def __init__(self, sync: _Optional[_Union[Sync, _Mapping]] = ..., startup: _Optional[_Union[StartupDone, _Mapping]] = ..., subscribe: _Optional[_Union[Subscribe, _Mapping]] = ..., monitor_session: _Optional[_Union[MonitorSession, _Mapping]] = ...) -> None: ... class Sync(_message.Message): __slots__ = ("id",) @@ -22,12 +24,14 @@ class Sync(_message.Message): def __init__(self, id: _Optional[int] = ...) -> None: ... class StartupDone(_message.Message): - __slots__ = ("version", "name") + __slots__ = ("version", "name", "session") VERSION_FIELD_NUMBER: _ClassVar[int] NAME_FIELD_NUMBER: _ClassVar[int] + SESSION_FIELD_NUMBER: _ClassVar[int] version: str name: str - def __init__(self, version: _Optional[str] = ..., name: _Optional[str] = ...) -> None: ... + session: str + def __init__(self, version: _Optional[str] = ..., name: _Optional[str] = ..., session: _Optional[str] = ...) -> None: ... class Subscribe(_message.Message): __slots__ = ("is_unsubscribe", "all_places", "all_resources") @@ -39,6 +43,12 @@ class Subscribe(_message.Message): all_resources: bool def __init__(self, is_unsubscribe: bool = ..., all_places: bool = ..., all_resources: bool = ...) -> None: ... +class MonitorSession(_message.Message): + __slots__ = ("session",) + SESSION_FIELD_NUMBER: _ClassVar[int] + session: str + def __init__(self, session: _Optional[str] = ...) -> None: ... + class ClientOutMessage(_message.Message): __slots__ = ("sync", "updates") SYNC_FIELD_NUMBER: _ClassVar[int] @@ -185,7 +195,7 @@ class GetPlacesResponse(_message.Message): def __init__(self, places: _Optional[_Iterable[_Union[Place, _Mapping]]] = ...) -> None: ... class Place(_message.Message): - __slots__ = ("name", "aliases", "comment", "tags", "matches", "acquired", "acquired_resources", "allowed", "created", "changed", "reservation") + __slots__ = ("name", "aliases", "comment", "tags", "matches", "acquired", "acquired_resources", "allowed", "created", "changed", "reservation", "session") class TagsEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -204,6 +214,7 @@ class Place(_message.Message): CREATED_FIELD_NUMBER: _ClassVar[int] CHANGED_FIELD_NUMBER: _ClassVar[int] RESERVATION_FIELD_NUMBER: _ClassVar[int] + SESSION_FIELD_NUMBER: _ClassVar[int] name: str aliases: _containers.RepeatedScalarFieldContainer[str] comment: str @@ -215,7 +226,8 @@ class Place(_message.Message): created: float changed: float reservation: str - def __init__(self, name: _Optional[str] = ..., aliases: _Optional[_Iterable[str]] = ..., comment: _Optional[str] = ..., tags: _Optional[_Mapping[str, str]] = ..., matches: _Optional[_Iterable[_Union[ResourceMatch, _Mapping]]] = ..., acquired: _Optional[str] = ..., acquired_resources: _Optional[_Iterable[str]] = ..., allowed: _Optional[_Iterable[str]] = ..., created: _Optional[float] = ..., changed: _Optional[float] = ..., reservation: _Optional[str] = ...) -> None: ... + session: str + def __init__(self, name: _Optional[str] = ..., aliases: _Optional[_Iterable[str]] = ..., comment: _Optional[str] = ..., tags: _Optional[_Mapping[str, str]] = ..., matches: _Optional[_Iterable[_Union[ResourceMatch, _Mapping]]] = ..., acquired: _Optional[str] = ..., acquired_resources: _Optional[_Iterable[str]] = ..., allowed: _Optional[_Iterable[str]] = ..., created: _Optional[float] = ..., changed: _Optional[float] = ..., reservation: _Optional[str] = ..., session: _Optional[str] = ...) -> None: ... class ResourceMatch(_message.Message): __slots__ = ("exporter", "group", "cls", "name", "rename") @@ -315,10 +327,12 @@ class DeletePlaceMatchResponse(_message.Message): def __init__(self) -> None: ... class AcquirePlaceRequest(_message.Message): - __slots__ = ("placename",) + __slots__ = ("placename", "session") PLACENAME_FIELD_NUMBER: _ClassVar[int] + SESSION_FIELD_NUMBER: _ClassVar[int] placename: str - def __init__(self, placename: _Optional[str] = ...) -> None: ... + session: str + def __init__(self, placename: _Optional[str] = ..., session: _Optional[str] = ...) -> None: ... class AcquirePlaceResponse(_message.Message): __slots__ = () @@ -349,7 +363,7 @@ class AllowPlaceResponse(_message.Message): def __init__(self) -> None: ... class CreateReservationRequest(_message.Message): - __slots__ = ("filters", "prio") + __slots__ = ("filters", "prio", "session") class FiltersEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -359,9 +373,11 @@ class CreateReservationRequest(_message.Message): def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Reservation.Filter, _Mapping]] = ...) -> None: ... FILTERS_FIELD_NUMBER: _ClassVar[int] PRIO_FIELD_NUMBER: _ClassVar[int] + SESSION_FIELD_NUMBER: _ClassVar[int] filters: _containers.MessageMap[str, Reservation.Filter] prio: float - def __init__(self, filters: _Optional[_Mapping[str, Reservation.Filter]] = ..., prio: _Optional[float] = ...) -> None: ... + session: str + def __init__(self, filters: _Optional[_Mapping[str, Reservation.Filter]] = ..., prio: _Optional[float] = ..., session: _Optional[str] = ...) -> None: ... class CreateReservationResponse(_message.Message): __slots__ = ("reservation",) @@ -370,7 +386,7 @@ class CreateReservationResponse(_message.Message): def __init__(self, reservation: _Optional[_Union[Reservation, _Mapping]] = ...) -> None: ... class Reservation(_message.Message): - __slots__ = ("owner", "token", "state", "prio", "filters", "allocations", "created", "timeout") + __slots__ = ("owner", "token", "state", "prio", "filters", "allocations", "created", "timeout", "session") class Filter(_message.Message): __slots__ = ("filter",) class FilterEntry(_message.Message): @@ -405,6 +421,7 @@ class Reservation(_message.Message): ALLOCATIONS_FIELD_NUMBER: _ClassVar[int] CREATED_FIELD_NUMBER: _ClassVar[int] TIMEOUT_FIELD_NUMBER: _ClassVar[int] + SESSION_FIELD_NUMBER: _ClassVar[int] owner: str token: str state: int @@ -413,7 +430,8 @@ class Reservation(_message.Message): allocations: _containers.ScalarMap[str, str] created: float timeout: float - def __init__(self, owner: _Optional[str] = ..., token: _Optional[str] = ..., state: _Optional[int] = ..., prio: _Optional[float] = ..., filters: _Optional[_Mapping[str, Reservation.Filter]] = ..., allocations: _Optional[_Mapping[str, str]] = ..., created: _Optional[float] = ..., timeout: _Optional[float] = ...) -> None: ... + session: str + def __init__(self, owner: _Optional[str] = ..., token: _Optional[str] = ..., state: _Optional[int] = ..., prio: _Optional[float] = ..., filters: _Optional[_Mapping[str, Reservation.Filter]] = ..., allocations: _Optional[_Mapping[str, str]] = ..., created: _Optional[float] = ..., timeout: _Optional[float] = ..., session: _Optional[str] = ...) -> None: ... class CancelReservationRequest(_message.Message): __slots__ = ("token",) diff --git a/labgrid/remote/proto/labgrid-coordinator.proto b/labgrid/remote/proto/labgrid-coordinator.proto index e0585f7e1..b2fcf49fa 100644 --- a/labgrid/remote/proto/labgrid-coordinator.proto +++ b/labgrid/remote/proto/labgrid-coordinator.proto @@ -55,6 +55,7 @@ message Sync { message StartupDone { string version = 1; string name = 2; + optional string session = 3; }; message Subscribe { @@ -167,6 +168,7 @@ message Place { double created = 9; double changed = 10; optional string reservation = 11; + optional string session = 12; }; message ResourceMatch { @@ -229,6 +231,7 @@ message DeletePlaceMatchResponse { message AcquirePlaceRequest { string placename = 1; + optional string session = 2; }; message AcquirePlaceResponse { @@ -254,6 +257,7 @@ message AllowPlaceResponse { message CreateReservationRequest { map filters = 1; double prio = 2; + optional string session = 3; }; message CreateReservationResponse { @@ -272,6 +276,7 @@ message Reservation { map allocations = 6; double created = 7; double timeout = 8; + optional string session = 9; }; message CancelReservationRequest { diff --git a/tests/test_coordinator.py b/tests/coordinator/test_coordinator.py similarity index 100% rename from tests/test_coordinator.py rename to tests/coordinator/test_coordinator.py diff --git a/tests/coordinator/test_sessions.py b/tests/coordinator/test_sessions.py new file mode 100644 index 000000000..18aaafa4d --- /dev/null +++ b/tests/coordinator/test_sessions.py @@ -0,0 +1,296 @@ +import grpc +import grpc._channel +import pytest + +import labgrid.remote.generated.labgrid_coordinator_pb2 as labgrid_coordinator_pb2 +import labgrid.remote.generated.labgrid_coordinator_pb2_grpc as labgrid_coordinator_pb2_grpc + + +class ChannelStub: + """Context that instantiates a ClientSession with an optional session name""" + + def __init__(self, session_name=""): + self._session_name = session_name + self._stream = None + self._channel = grpc.insecure_channel("127.0.0.1:20408", options=(("grpc.use_local_subchannel_pool", 1),)) + self._stub = labgrid_coordinator_pb2_grpc.CoordinatorStub(self._channel) + + def __enter__(self): + self.start() + return self.stub + + def __exit__(self, exc_type, exc_val, exc_tb): + self.stop() + + @property + def stub(self): + return self._stub + + def start(self): + import queue + + queue = queue.Queue() + + def generate_startup(queue): + msg = labgrid_coordinator_pb2.ClientInMessage() + msg.startup.version = "2.0.0" + msg.startup.name = "testclient" + msg.startup.session = self._session_name + messages = [msg] + for msg in messages: + yield msg + while True: + msg = queue.get() + yield msg + queue.task_done() + + self._stream = self._stub.ClientStream(generate_startup(queue)) + + def stop(self): + self._channel.close() + + +def _add_place(stub, name): + place = labgrid_coordinator_pb2.AddPlaceRequest(name=name) + res = stub.AddPlace(place) + assert res, f"There was an error: {res}" + + +def test_acquire_place(coordinator): + """A place can be acquired in a session""" + with ChannelStub("session_1") as stub: + _add_place(stub, "test") + res = stub.AcquirePlace(labgrid_coordinator_pb2.AcquirePlaceRequest(placename="test", session="session_1")) + assert res + + +def test_reservation(coordinator): + """A reservation can be created in a session""" + with ChannelStub("session_1") as stub: + _add_place(stub, "test") + tags = {"board": "test"} + res = stub.SetPlaceTags(labgrid_coordinator_pb2.SetPlaceTagsRequest(placename="test", tags=tags)) + res = stub.CreateReservation( + labgrid_coordinator_pb2.CreateReservationRequest( + filters={ + "main": labgrid_coordinator_pb2.Reservation.Filter(filter=tags), + }, + prio=1.0, + session="session_1", + ) + ) + assert res + + +def test_reserve_and_acquire(coordinator): + """A reservation can be created and place acquired in a session""" + with ChannelStub("session_1") as stub: + _add_place(stub, "test") + tags = {"board": "test"} + res = stub.SetPlaceTags(labgrid_coordinator_pb2.SetPlaceTagsRequest(placename="test", tags=tags)) + res = stub.CreateReservation( + labgrid_coordinator_pb2.CreateReservationRequest( + filters={ + "main": labgrid_coordinator_pb2.Reservation.Filter(filter=tags), + }, + prio=1.0, + session="session_1", + ) + ) + assert res + res = stub.AcquirePlace(labgrid_coordinator_pb2.AcquirePlaceRequest(placename="test", session="session_1")) + assert res + + +def test_acquire_place_release_session(coordinator): + """A place is unlocked if its session is closed""" + with ChannelStub("session_1") as stub: + _add_place(stub, "test") + res = stub.AcquirePlace(labgrid_coordinator_pb2.AcquirePlaceRequest(placename="test", session="session_1")) + assert res + + with ChannelStub() as stub: + with pytest.raises(grpc._channel._InactiveRpcError): + res = stub.AllowPlace(labgrid_coordinator_pb2.AllowPlaceRequest(placename="test")) + + +def test_reservation_release_session(coordinator): + """A reservation is cancelled if its session is closed""" + with ChannelStub("session_1") as stub: + tags = {"board": "test"} + _add_place(stub, "test") + res = stub.CreateReservation( + labgrid_coordinator_pb2.CreateReservationRequest( + filters={ + "main": labgrid_coordinator_pb2.Reservation.Filter(filter=tags), + }, + prio=1.0, + session="session_1", + ) + ) + assert res + token = res.reservation.token + + with ChannelStub() as stub: + with pytest.raises(grpc._channel._InactiveRpcError): + stub.PollReservation(labgrid_coordinator_pb2.PollReservationRequest(token=token)) + + +def test_reservation_acquire_place_release_session(coordinator): + """A place is unlocked and its reservation is cancelled if its session is closed""" + with ChannelStub("session_1") as stub: + _add_place(stub, "test") + tags = {"board": "test"} + res = stub.SetPlaceTags(labgrid_coordinator_pb2.SetPlaceTagsRequest(placename="test", tags=tags)) + assert res + res = stub.CreateReservation( + labgrid_coordinator_pb2.CreateReservationRequest( + filters={ + "main": labgrid_coordinator_pb2.Reservation.Filter(filter=tags), + }, + prio=1.0, + session="session_1", + ) + ) + assert res + token = res.reservation.token + res = stub.AcquirePlace(labgrid_coordinator_pb2.AcquirePlaceRequest(placename="test", session="session_1")) + assert res + + with ChannelStub() as stub: + with pytest.raises(grpc._channel._InactiveRpcError): + stub.PollReservation(labgrid_coordinator_pb2.PollReservationRequest(token=token)) + with pytest.raises(grpc._channel._InactiveRpcError): + res = stub.AllowPlace(labgrid_coordinator_pb2.AllowPlaceRequest(placename="test")) + + +def test_acquire_place_no_session(coordinator): + """A place cannot be acquired if the session doesn't exist""" + with ChannelStub() as stub: + _add_place(stub, "test") + with pytest.raises(grpc._channel._InactiveRpcError): + stub.AcquirePlace(labgrid_coordinator_pb2.AcquirePlaceRequest(placename="test", session="session_1")) + + +def test_reservation_no_session(coordinator): + """A reservation cannot be created if the session doesn't exist""" + with ChannelStub() as stub: + _add_place(stub, "test") + tags = {"board": "test"} + res = stub.SetPlaceTags(labgrid_coordinator_pb2.SetPlaceTagsRequest(placename="test", tags=tags)) + assert res + with pytest.raises(grpc._channel._InactiveRpcError): + res = stub.CreateReservation( + labgrid_coordinator_pb2.CreateReservationRequest( + filters={ + "main": labgrid_coordinator_pb2.Reservation.Filter(filter=tags), + }, + prio=1.0, + session="session_1", + ) + ) + + +def test_multiple_reservations_places(coordinator): + """Multiple reservations and places can be held in one session""" + with ChannelStub("session_1") as stub: + _add_place(stub, "test_1") + _add_place(stub, "test_2") + tags = {"board": "test"} + res = stub.SetPlaceTags(labgrid_coordinator_pb2.SetPlaceTagsRequest(placename="test_1", tags=tags)) + assert res + res = stub.SetPlaceTags(labgrid_coordinator_pb2.SetPlaceTagsRequest(placename="test_2", tags=tags)) + assert res + res = stub.CreateReservation( + labgrid_coordinator_pb2.CreateReservationRequest( + filters={ + "main": labgrid_coordinator_pb2.Reservation.Filter(filter=tags), + }, + prio=1.0, + session="session_1", + ) + ) + assert res + token_1 = res.reservation.token + res = stub.CreateReservation( + labgrid_coordinator_pb2.CreateReservationRequest( + filters={ + "main": labgrid_coordinator_pb2.Reservation.Filter(filter=tags), + }, + prio=1.0, + session="session_1", + ) + ) + assert res + token_2 = res.reservation.token + res = stub.AcquirePlace(labgrid_coordinator_pb2.AcquirePlaceRequest(placename="test_1", session="session_1")) + assert res + res = stub.AcquirePlace(labgrid_coordinator_pb2.AcquirePlaceRequest(placename="test_2", session="session_1")) + assert res + + with ChannelStub("") as stub: + with pytest.raises(grpc._channel._InactiveRpcError): + stub.PollReservation(labgrid_coordinator_pb2.PollReservationRequest(token=token_1)) + with pytest.raises(grpc._channel._InactiveRpcError): + stub.AllowPlace(labgrid_coordinator_pb2.AllowPlaceRequest(placename="test_1")) + with pytest.raises(grpc._channel._InactiveRpcError): + stub.PollReservation(labgrid_coordinator_pb2.PollReservationRequest(token=token_2)) + with pytest.raises(grpc._channel._InactiveRpcError): + stub.AllowPlace(labgrid_coordinator_pb2.AllowPlaceRequest(placename="test_2")) + + +def test_multiple_sessions(coordinator): + """Multiple sessions can coexist without interference""" + # Setup session 1, create reservation and acquire place + with ChannelStub("session_1") as stub_1: + _add_place(stub_1, "test_1") + tags = {"board_1": "test_1"} + res = stub_1.SetPlaceTags(labgrid_coordinator_pb2.SetPlaceTagsRequest(placename="test_1", tags=tags)) + assert res + res = stub_1.CreateReservation( + labgrid_coordinator_pb2.CreateReservationRequest( + filters={ + "main": labgrid_coordinator_pb2.Reservation.Filter(filter=tags), + }, + prio=1.0, + session="session_1", + ) + ) + assert res + token_1 = res.reservation.token + res = stub_1.AcquirePlace(labgrid_coordinator_pb2.AcquirePlaceRequest(placename="test_1", session="session_1")) + assert res + + # Setup session 2, create reservation and acquire place + with ChannelStub("session_2") as stub_2: + _add_place(stub_2, "test_2") + tags = {"board_2": "test_2"} + res = stub_2.SetPlaceTags(labgrid_coordinator_pb2.SetPlaceTagsRequest(placename="test_2", tags=tags)) + assert res + res = stub_2.CreateReservation( + labgrid_coordinator_pb2.CreateReservationRequest( + filters={ + "main": labgrid_coordinator_pb2.Reservation.Filter(filter=tags), + }, + prio=1.0, + session="session_2", + ) + ) + assert res + token_2 = res.reservation.token + res = stub_2.AcquirePlace( + labgrid_coordinator_pb2.AcquirePlaceRequest(placename="test_2", session="session_2") + ) + assert res + + # Assert the reservation and place under session 2 have been released + with pytest.raises(grpc._channel._InactiveRpcError): + stub_1.PollReservation(labgrid_coordinator_pb2.PollReservationRequest(token=token_2)) + with pytest.raises(grpc._channel._InactiveRpcError): + stub_1.AllowPlace(labgrid_coordinator_pb2.AllowPlaceRequest(placename="test_2")) + + # Assert the reservation and place under session 1 are held + res = stub_1.PollReservation(labgrid_coordinator_pb2.PollReservationRequest(token=token_1)) + assert res + res = stub_1.AllowPlace(labgrid_coordinator_pb2.AllowPlaceRequest(placename="test_1")) + assert res