Mirror of https://github.com/roostorg/osprey github.com/roostorg/osprey
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Remove labels proto (for real this time) (#24)

authored by

Ethan Breder and committed by
GitHub
5e9e5773 10557212

+176 -1813
+2
.gitignore
··· 304 304 *.pdb 305 305 306 306 # End of https://www.toptal.com/developers/gitignore/api/python,rust,pycharm 307 + 308 + .claude
osprey_rpc/src/osprey/rpc/labels/__init__.py

This is a binary file and will not be displayed.

osprey_rpc/src/osprey/rpc/labels/v1/__init__.py

This is a binary file and will not be displayed.

-109
osprey_rpc/src/osprey/rpc/labels/v1/service_pb2.py
··· 1 - # -*- coding: utf-8 -*- 2 - # Generated by the protocol buffer compiler. DO NOT EDIT! 3 - # source: osprey/rpc/labels/v1/service.proto 4 - """Generated protocol buffer code.""" 5 - from google.protobuf.internal import builder as _builder 6 - from google.protobuf import descriptor as _descriptor 7 - from google.protobuf import descriptor_pool as _descriptor_pool 8 - from google.protobuf import symbol_database as _symbol_database 9 - # @@protoc_insertion_point(imports) 10 - 11 - _sym_db = _symbol_database.Default() 12 - 13 - 14 - from osprey.rpc.pigeon.v1 import options_pb2 as osprey_dot_rpc_dot_pigeon_dot_v1_dot_options__pb2 15 - from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 16 - 17 - 18 - DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"osprey/rpc/labels/v1/service.proto\x12\x14osprey.rpc.labels.v1\x1a\"osprey/rpc/pigeon/v1/options.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x87\x02\n\x0bLabelReason\x12\x0f\n\x07pending\x18\x01 \x01(\x08\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x41\n\x08\x66\x65\x61tures\x18\x03 \x03(\x0b\x32/.osprey.rpc.labels.v1.LabelReason.FeaturesEntry\x12.\n\ncreated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nexpires_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a/\n\rFeaturesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xdc\x01\n\x0fLabelStateInner\x12\x31\n\x06status\x18\x01 \x01(\x0e\x32!.osprey.rpc.labels.v1.LabelStatus\x12\x43\n\x07reasons\x18\x02 \x03(\x0b\x32\x32.osprey.rpc.labels.v1.LabelStateInner.ReasonsEntry\x1aQ\n\x0cReasonsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x30\n\x05value\x18\x02 \x01(\x0b\x32!.osprey.rpc.labels.v1.LabelReason:\x02\x38\x01\"\x92\x02\n\nLabelState\x12\x31\n\x06status\x18\x01 \x01(\x0e\x32!.osprey.rpc.labels.v1.LabelStatus\x12>\n\x07reasons\x18\x02 \x03(\x0b\x32-.osprey.rpc.labels.v1.LabelState.ReasonsEntry\x12>\n\x0fprevious_states\x18\x03 \x03(\x0b\x32%.osprey.rpc.labels.v1.LabelStateInner\x1aQ\n\x0cReasonsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x30\n\x05value\x18\x02 \x01(\x0b\x32!.osprey.rpc.labels.v1.LabelReason:\x02\x38\x01\"\xc3\x01\n\x06Labels\x12\x38\n\x06labels\x18\x01 \x03(\x0b\x32(.osprey.rpc.labels.v1.Labels.LabelsEntry\x12.\n\nexpires_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1aO\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12/\n\x05value\x18\x02 \x01(\x0b\x32 .osprey.rpc.labels.v1.LabelState:\x02\x38\x01\"%\n\tEntityKey\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\t\"d\n\x06\x45ntity\x12,\n\x03key\x18\x02 \x01(\x0b\x32\x1f.osprey.rpc.labels.v1.EntityKey\x12,\n\x06labels\x18\x01 \x01(\x0b\x32\x1c.osprey.rpc.labels.v1.Labels\"\x1e\n\x0fTakeDataRequest\x12\x0b\n\x03key\x18\x01 \x01(\t\"\x15\n\x04\x44\x61ta\x12\r\n\x05\x62ytes\x18\x01 \x01(\x0c\"<\n\x10TakeDataResponse\x12(\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x1a.osprey.rpc.labels.v1.Data\"[\n\x15GetEntityBatchRequest\x12\x13\n\x0brouting_key\x18\x02 \x01(\t\x12-\n\x04keys\x18\x01 \x03(\x0b\x32\x1f.osprey.rpc.labels.v1.EntityKey\"T\n\x16GetEntityBatchResponse\x12:\n\tresponses\x18\x01 \x03(\x0b\x32\'.osprey.rpc.labels.v1.GetEntityResponse\"U\n\x10GetEntityRequest\x12\x13\n\x0brouting_key\x18\x02 \x01(\t\x12,\n\x03key\x18\x01 \x01(\x0b\x32\x1f.osprey.rpc.labels.v1.EntityKey\"A\n\x11GetEntityResponse\x12,\n\x06\x65ntity\x18\x01 \x01(\x0b\x32\x1c.osprey.rpc.labels.v1.Entity\"\xb9\x02\n\x0e\x45ntityMutation\x12\x12\n\nlabel_name\x18\x01 \x01(\t\x12\x13\n\x0breason_name\x18\x02 \x01(\t\x12\x31\n\x06status\x18\x03 \x01(\x0e\x32!.osprey.rpc.labels.v1.LabelStatus\x12\x0f\n\x07pending\x18\x04 \x01(\x08\x12\x13\n\x0b\x64\x65scription\x18\x05 \x01(\t\x12\x44\n\x08\x66\x65\x61tures\x18\x06 \x03(\x0b\x32\x32.osprey.rpc.labels.v1.EntityMutation.FeaturesEntry\x12.\n\nexpires_at\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a/\n\rFeaturesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x98\x01\n\x1a\x41pplyEntityMutationRequest\x12\x13\n\x0brouting_key\x18\x03 \x01(\t\x12,\n\x03key\x18\x01 \x01(\x0b\x32\x1f.osprey.rpc.labels.v1.EntityKey\x12\x37\n\tmutations\x18\x02 \x03(\x0b\x32$.osprey.rpc.labels.v1.EntityMutation\"\x84\x01\n\x18\x41pplyEntityMutationReply\x12\r\n\x05\x61\x64\x64\x65\x64\x18\x01 \x03(\t\x12\x0f\n\x07removed\x18\x02 \x03(\t\x12\x11\n\tunchanged\x18\x03 \x03(\t\x12\x35\n\x07\x64ropped\x18\x04 \x03(\x0b\x32$.osprey.rpc.labels.v1.EntityMutation\"!\n\x0fTokenRangeQuery\x12\x0e\n\x06opaque\x18\x01 \x01(\t\"\x1d\n\x1bGetTokenRangeQueriesRequest\"\x7f\n\x1aGetTokenRangeQueriesResult\x12\x1d\n\x15max_query_concurrency\x18\x01 \x01(\x04\x12\x42\n\x13token_range_queries\x18\x02 \x03(\x0b\x32%.osprey.rpc.labels.v1.TokenRangeQuery\"Y\n\x15ScanTokenRangeRequest\x12@\n\x11token_range_query\x18\x01 \x01(\x0b\x32%.osprey.rpc.labels.v1.TokenRangeQuery\"\x89\x01\n\x14ScanTokenRangeResult\x12\x41\n\x12\x63ontinuation_token\x18\x01 \x01(\x0b\x32%.osprey.rpc.labels.v1.TokenRangeQuery\x12.\n\x08\x65ntities\x18\x02 \x03(\x0b\x32\x1c.osprey.rpc.labels.v1.Entity\"\xca\x01\n\x19LabelReasonMutationResult\x12:\n\toperation\x18\x01 \x01(\x0e\x32\'.osprey.rpc.labels.v1.MutationOperation\x12\x36\n\x0bprev_reason\x18\x02 \x01(\x0b\x32!.osprey.rpc.labels.v1.LabelReason\x12\x39\n\x0e\x63urrent_reason\x18\x03 \x01(\x0b\x32!.osprey.rpc.labels.v1.LabelReason\"\xae\x02\n\x13LabelMutationResult\x12\x31\n\x06status\x18\x01 \x01(\x0e\x32!.osprey.rpc.labels.v1.LabelStatus\x12:\n\toperation\x18\x02 \x01(\x0e\x32\'.osprey.rpc.labels.v1.MutationOperation\x12G\n\x07reasons\x18\x03 \x03(\x0b\x32\x36.osprey.rpc.labels.v1.LabelMutationResult.ReasonsEntry\x1a_\n\x0cReasonsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12>\n\x05value\x18\x02 \x01(\x0b\x32/.osprey.rpc.labels.v1.LabelReasonMutationResult:\x02\x38\x01\"\x9e\x02\n\x1f\x41pplyEntityMutationReplyUpdated\x12\x62\n\x0flabel_mutations\x18\x01 \x03(\x0b\x32I.osprey.rpc.labels.v1.ApplyEntityMutationReplyUpdated.LabelMutationsEntry\x12\x35\n\x07\x64ropped\x18\x02 \x03(\x0b\x32$.osprey.rpc.labels.v1.EntityMutation\x1a`\n\x13LabelMutationsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).osprey.rpc.labels.v1.LabelMutationResult:\x02\x38\x01*O\n\x0bLabelStatus\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x00\x12\x0b\n\x07REMOVED\x10\x01\x12\x12\n\x0eMANUALLY_ADDED\x10\x02\x12\x14\n\x10MANUALLY_REMOVED\x10\x03*\xb7\x01\n\x11MutationOperation\x12\"\n\x1eMUTATION_OPERATION_UNSPECIFIED\x10\x00\x12\x1c\n\x18MUTATION_OPERATION_ADDED\x10\x01\x12\x1e\n\x1aMUTATION_OPERATION_UPDATED\x10\x02\x12 \n\x1cMUTATION_OPERATION_UNCHANGED\x10\x03\x12\x1e\n\x1aMUTATION_OPERATION_REMOVED\x10\x04\x32\xa5\x06\n\x0cLabelService\x12Y\n\x08TakeData\x12%.osprey.rpc.labels.v1.TakeDataRequest\x1a&.osprey.rpc.labels.v1.TakeDataResponse\x12\\\n\tGetEntity\x12&.osprey.rpc.labels.v1.GetEntityRequest\x1a\'.osprey.rpc.labels.v1.GetEntityResponse\x12w\n\x13\x41pplyEntityMutation\x12\x30.osprey.rpc.labels.v1.ApplyEntityMutationRequest\x1a..osprey.rpc.labels.v1.ApplyEntityMutationReply\x12\x85\x01\n\x1a\x41pplyEntityMutationUpdated\x12\x30.osprey.rpc.labels.v1.ApplyEntityMutationRequest\x1a\x35.osprey.rpc.labels.v1.ApplyEntityMutationReplyUpdated\x12k\n\x0eGetEntityBatch\x12+.osprey.rpc.labels.v1.GetEntityBatchRequest\x1a,.osprey.rpc.labels.v1.GetEntityBatchResponse\x12{\n\x14GetTokenRangeQueries\x12\x31.osprey.rpc.labels.v1.GetTokenRangeQueriesRequest\x1a\x30.osprey.rpc.labels.v1.GetTokenRangeQueriesResult\x12i\n\x0eScanTokenRange\x12+.osprey.rpc.labels.v1.ScanTokenRangeRequest\x1a*.osprey.rpc.labels.v1.ScanTokenRangeResult\x1a\x06\xca\xf0\x19\x02\x10\x02\x62\x06proto3') 19 - 20 - _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 21 - _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'osprey.rpc.labels.v1.service_pb2', globals()) 22 - if _descriptor._USE_C_DESCRIPTORS == False: 23 - 24 - DESCRIPTOR._options = None 25 - _LABELREASON_FEATURESENTRY._options = None 26 - _LABELREASON_FEATURESENTRY._serialized_options = b'8\001' 27 - _LABELSTATEINNER_REASONSENTRY._options = None 28 - _LABELSTATEINNER_REASONSENTRY._serialized_options = b'8\001' 29 - _LABELSTATE_REASONSENTRY._options = None 30 - _LABELSTATE_REASONSENTRY._serialized_options = b'8\001' 31 - _LABELS_LABELSENTRY._options = None 32 - _LABELS_LABELSENTRY._serialized_options = b'8\001' 33 - _ENTITYMUTATION_FEATURESENTRY._options = None 34 - _ENTITYMUTATION_FEATURESENTRY._serialized_options = b'8\001' 35 - _LABELMUTATIONRESULT_REASONSENTRY._options = None 36 - _LABELMUTATIONRESULT_REASONSENTRY._serialized_options = b'8\001' 37 - _APPLYENTITYMUTATIONREPLYUPDATED_LABELMUTATIONSENTRY._options = None 38 - _APPLYENTITYMUTATIONREPLYUPDATED_LABELMUTATIONSENTRY._serialized_options = b'8\001' 39 - _LABELSERVICE._options = None 40 - _LABELSERVICE._serialized_options = b'\312\360\031\002\020\002' 41 - _LABELSTATUS._serialized_start=3515 42 - _LABELSTATUS._serialized_end=3594 43 - _MUTATIONOPERATION._serialized_start=3597 44 - _MUTATIONOPERATION._serialized_end=3780 45 - _LABELREASON._serialized_start=130 46 - _LABELREASON._serialized_end=393 47 - _LABELREASON_FEATURESENTRY._serialized_start=346 48 - _LABELREASON_FEATURESENTRY._serialized_end=393 49 - _LABELSTATEINNER._serialized_start=396 50 - _LABELSTATEINNER._serialized_end=616 51 - _LABELSTATEINNER_REASONSENTRY._serialized_start=535 52 - _LABELSTATEINNER_REASONSENTRY._serialized_end=616 53 - _LABELSTATE._serialized_start=619 54 - _LABELSTATE._serialized_end=893 55 - _LABELSTATE_REASONSENTRY._serialized_start=535 56 - _LABELSTATE_REASONSENTRY._serialized_end=616 57 - _LABELS._serialized_start=896 58 - _LABELS._serialized_end=1091 59 - _LABELS_LABELSENTRY._serialized_start=1012 60 - _LABELS_LABELSENTRY._serialized_end=1091 61 - _ENTITYKEY._serialized_start=1093 62 - _ENTITYKEY._serialized_end=1130 63 - _ENTITY._serialized_start=1132 64 - _ENTITY._serialized_end=1232 65 - _TAKEDATAREQUEST._serialized_start=1234 66 - _TAKEDATAREQUEST._serialized_end=1264 67 - _DATA._serialized_start=1266 68 - _DATA._serialized_end=1287 69 - _TAKEDATARESPONSE._serialized_start=1289 70 - _TAKEDATARESPONSE._serialized_end=1349 71 - _GETENTITYBATCHREQUEST._serialized_start=1351 72 - _GETENTITYBATCHREQUEST._serialized_end=1442 73 - _GETENTITYBATCHRESPONSE._serialized_start=1444 74 - _GETENTITYBATCHRESPONSE._serialized_end=1528 75 - _GETENTITYREQUEST._serialized_start=1530 76 - _GETENTITYREQUEST._serialized_end=1615 77 - _GETENTITYRESPONSE._serialized_start=1617 78 - _GETENTITYRESPONSE._serialized_end=1682 79 - _ENTITYMUTATION._serialized_start=1685 80 - _ENTITYMUTATION._serialized_end=1998 81 - _ENTITYMUTATION_FEATURESENTRY._serialized_start=346 82 - _ENTITYMUTATION_FEATURESENTRY._serialized_end=393 83 - _APPLYENTITYMUTATIONREQUEST._serialized_start=2001 84 - _APPLYENTITYMUTATIONREQUEST._serialized_end=2153 85 - _APPLYENTITYMUTATIONREPLY._serialized_start=2156 86 - _APPLYENTITYMUTATIONREPLY._serialized_end=2288 87 - _TOKENRANGEQUERY._serialized_start=2290 88 - _TOKENRANGEQUERY._serialized_end=2323 89 - _GETTOKENRANGEQUERIESREQUEST._serialized_start=2325 90 - _GETTOKENRANGEQUERIESREQUEST._serialized_end=2354 91 - _GETTOKENRANGEQUERIESRESULT._serialized_start=2356 92 - _GETTOKENRANGEQUERIESRESULT._serialized_end=2483 93 - _SCANTOKENRANGEREQUEST._serialized_start=2485 94 - _SCANTOKENRANGEREQUEST._serialized_end=2574 95 - _SCANTOKENRANGERESULT._serialized_start=2577 96 - _SCANTOKENRANGERESULT._serialized_end=2714 97 - _LABELREASONMUTATIONRESULT._serialized_start=2717 98 - _LABELREASONMUTATIONRESULT._serialized_end=2919 99 - _LABELMUTATIONRESULT._serialized_start=2922 100 - _LABELMUTATIONRESULT._serialized_end=3224 101 - _LABELMUTATIONRESULT_REASONSENTRY._serialized_start=3129 102 - _LABELMUTATIONRESULT_REASONSENTRY._serialized_end=3224 103 - _APPLYENTITYMUTATIONREPLYUPDATED._serialized_start=3227 104 - _APPLYENTITYMUTATIONREPLYUPDATED._serialized_end=3513 105 - _APPLYENTITYMUTATIONREPLYUPDATED_LABELMUTATIONSENTRY._serialized_start=3417 106 - _APPLYENTITYMUTATIONREPLYUPDATED_LABELMUTATIONSENTRY._serialized_end=3513 107 - _LABELSERVICE._serialized_start=3783 108 - _LABELSERVICE._serialized_end=4588 109 - # @@protoc_insertion_point(module_scope)
-673
osprey_rpc/src/osprey/rpc/labels/v1/service_pb2.pyi
··· 1 - """ 2 - @generated by mypy-protobuf. Do not edit manually! 3 - isort:skip_file 4 - """ 5 - 6 - import builtins 7 - import collections.abc 8 - import google.protobuf.descriptor 9 - import google.protobuf.internal.containers 10 - import google.protobuf.internal.enum_type_wrapper 11 - import google.protobuf.message 12 - import google.protobuf.timestamp_pb2 13 - import sys 14 - import typing 15 - 16 - if sys.version_info >= (3, 10): 17 - import typing as typing_extensions 18 - else: 19 - import typing_extensions 20 - 21 - DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 22 - 23 - class _LabelStatus: 24 - ValueType = typing.NewType("ValueType", builtins.int) 25 - V: typing_extensions.TypeAlias = ValueType 26 - 27 - class _LabelStatusEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_LabelStatus.ValueType], builtins.type): 28 - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor 29 - ADDED: _LabelStatus.ValueType # 0 30 - REMOVED: _LabelStatus.ValueType # 1 31 - MANUALLY_ADDED: _LabelStatus.ValueType # 2 32 - MANUALLY_REMOVED: _LabelStatus.ValueType # 3 33 - 34 - class LabelStatus(_LabelStatus, metaclass=_LabelStatusEnumTypeWrapper): ... 35 - 36 - ADDED: LabelStatus.ValueType # 0 37 - REMOVED: LabelStatus.ValueType # 1 38 - MANUALLY_ADDED: LabelStatus.ValueType # 2 39 - MANUALLY_REMOVED: LabelStatus.ValueType # 3 40 - global___LabelStatus = LabelStatus 41 - 42 - class _MutationOperation: 43 - ValueType = typing.NewType("ValueType", builtins.int) 44 - V: typing_extensions.TypeAlias = ValueType 45 - 46 - class _MutationOperationEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_MutationOperation.ValueType], builtins.type): 47 - DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor 48 - MUTATION_OPERATION_UNSPECIFIED: _MutationOperation.ValueType # 0 49 - MUTATION_OPERATION_ADDED: _MutationOperation.ValueType # 1 50 - MUTATION_OPERATION_UPDATED: _MutationOperation.ValueType # 2 51 - MUTATION_OPERATION_UNCHANGED: _MutationOperation.ValueType # 3 52 - MUTATION_OPERATION_REMOVED: _MutationOperation.ValueType # 4 53 - 54 - class MutationOperation(_MutationOperation, metaclass=_MutationOperationEnumTypeWrapper): ... 55 - 56 - MUTATION_OPERATION_UNSPECIFIED: MutationOperation.ValueType # 0 57 - MUTATION_OPERATION_ADDED: MutationOperation.ValueType # 1 58 - MUTATION_OPERATION_UPDATED: MutationOperation.ValueType # 2 59 - MUTATION_OPERATION_UNCHANGED: MutationOperation.ValueType # 3 60 - MUTATION_OPERATION_REMOVED: MutationOperation.ValueType # 4 61 - global___MutationOperation = MutationOperation 62 - 63 - @typing.final 64 - class LabelReason(google.protobuf.message.Message): 65 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 66 - 67 - @typing.final 68 - class FeaturesEntry(google.protobuf.message.Message): 69 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 70 - 71 - KEY_FIELD_NUMBER: builtins.int 72 - VALUE_FIELD_NUMBER: builtins.int 73 - key: builtins.str 74 - value: builtins.str 75 - def __init__( 76 - self, 77 - *, 78 - key: builtins.str = ..., 79 - value: builtins.str = ..., 80 - ) -> None: ... 81 - def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... 82 - 83 - PENDING_FIELD_NUMBER: builtins.int 84 - DESCRIPTION_FIELD_NUMBER: builtins.int 85 - FEATURES_FIELD_NUMBER: builtins.int 86 - CREATED_AT_FIELD_NUMBER: builtins.int 87 - EXPIRES_AT_FIELD_NUMBER: builtins.int 88 - pending: builtins.bool 89 - description: builtins.str 90 - @property 91 - def features(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]: ... 92 - @property 93 - def created_at(self) -> google.protobuf.timestamp_pb2.Timestamp: ... 94 - @property 95 - def expires_at(self) -> google.protobuf.timestamp_pb2.Timestamp: ... 96 - def __init__( 97 - self, 98 - *, 99 - pending: builtins.bool = ..., 100 - description: builtins.str = ..., 101 - features: collections.abc.Mapping[builtins.str, builtins.str] | None = ..., 102 - created_at: google.protobuf.timestamp_pb2.Timestamp | None = ..., 103 - expires_at: google.protobuf.timestamp_pb2.Timestamp | None = ..., 104 - ) -> None: ... 105 - def HasField(self, field_name: typing.Literal["created_at", b"created_at", "expires_at", b"expires_at"]) -> builtins.bool: ... 106 - def ClearField(self, field_name: typing.Literal["created_at", b"created_at", "description", b"description", "expires_at", b"expires_at", "features", b"features", "pending", b"pending"]) -> None: ... 107 - 108 - global___LabelReason = LabelReason 109 - 110 - @typing.final 111 - class LabelStateInner(google.protobuf.message.Message): 112 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 113 - 114 - @typing.final 115 - class ReasonsEntry(google.protobuf.message.Message): 116 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 117 - 118 - KEY_FIELD_NUMBER: builtins.int 119 - VALUE_FIELD_NUMBER: builtins.int 120 - key: builtins.str 121 - @property 122 - def value(self) -> global___LabelReason: ... 123 - def __init__( 124 - self, 125 - *, 126 - key: builtins.str = ..., 127 - value: global___LabelReason | None = ..., 128 - ) -> None: ... 129 - def HasField(self, field_name: typing.Literal["value", b"value"]) -> builtins.bool: ... 130 - def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... 131 - 132 - STATUS_FIELD_NUMBER: builtins.int 133 - REASONS_FIELD_NUMBER: builtins.int 134 - status: global___LabelStatus.ValueType 135 - @property 136 - def reasons(self) -> google.protobuf.internal.containers.MessageMap[builtins.str, global___LabelReason]: ... 137 - def __init__( 138 - self, 139 - *, 140 - status: global___LabelStatus.ValueType = ..., 141 - reasons: collections.abc.Mapping[builtins.str, global___LabelReason] | None = ..., 142 - ) -> None: ... 143 - def ClearField(self, field_name: typing.Literal["reasons", b"reasons", "status", b"status"]) -> None: ... 144 - 145 - global___LabelStateInner = LabelStateInner 146 - 147 - @typing.final 148 - class LabelState(google.protobuf.message.Message): 149 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 150 - 151 - @typing.final 152 - class ReasonsEntry(google.protobuf.message.Message): 153 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 154 - 155 - KEY_FIELD_NUMBER: builtins.int 156 - VALUE_FIELD_NUMBER: builtins.int 157 - key: builtins.str 158 - @property 159 - def value(self) -> global___LabelReason: ... 160 - def __init__( 161 - self, 162 - *, 163 - key: builtins.str = ..., 164 - value: global___LabelReason | None = ..., 165 - ) -> None: ... 166 - def HasField(self, field_name: typing.Literal["value", b"value"]) -> builtins.bool: ... 167 - def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... 168 - 169 - STATUS_FIELD_NUMBER: builtins.int 170 - REASONS_FIELD_NUMBER: builtins.int 171 - PREVIOUS_STATES_FIELD_NUMBER: builtins.int 172 - status: global___LabelStatus.ValueType 173 - @property 174 - def reasons(self) -> google.protobuf.internal.containers.MessageMap[builtins.str, global___LabelReason]: ... 175 - @property 176 - def previous_states(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___LabelStateInner]: ... 177 - def __init__( 178 - self, 179 - *, 180 - status: global___LabelStatus.ValueType = ..., 181 - reasons: collections.abc.Mapping[builtins.str, global___LabelReason] | None = ..., 182 - previous_states: collections.abc.Iterable[global___LabelStateInner] | None = ..., 183 - ) -> None: ... 184 - def ClearField(self, field_name: typing.Literal["previous_states", b"previous_states", "reasons", b"reasons", "status", b"status"]) -> None: ... 185 - 186 - global___LabelState = LabelState 187 - 188 - @typing.final 189 - class Labels(google.protobuf.message.Message): 190 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 191 - 192 - @typing.final 193 - class LabelsEntry(google.protobuf.message.Message): 194 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 195 - 196 - KEY_FIELD_NUMBER: builtins.int 197 - VALUE_FIELD_NUMBER: builtins.int 198 - key: builtins.str 199 - @property 200 - def value(self) -> global___LabelState: ... 201 - def __init__( 202 - self, 203 - *, 204 - key: builtins.str = ..., 205 - value: global___LabelState | None = ..., 206 - ) -> None: ... 207 - def HasField(self, field_name: typing.Literal["value", b"value"]) -> builtins.bool: ... 208 - def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... 209 - 210 - LABELS_FIELD_NUMBER: builtins.int 211 - EXPIRES_AT_FIELD_NUMBER: builtins.int 212 - @property 213 - def labels(self) -> google.protobuf.internal.containers.MessageMap[builtins.str, global___LabelState]: ... 214 - @property 215 - def expires_at(self) -> google.protobuf.timestamp_pb2.Timestamp: ... 216 - def __init__( 217 - self, 218 - *, 219 - labels: collections.abc.Mapping[builtins.str, global___LabelState] | None = ..., 220 - expires_at: google.protobuf.timestamp_pb2.Timestamp | None = ..., 221 - ) -> None: ... 222 - def HasField(self, field_name: typing.Literal["expires_at", b"expires_at"]) -> builtins.bool: ... 223 - def ClearField(self, field_name: typing.Literal["expires_at", b"expires_at", "labels", b"labels"]) -> None: ... 224 - 225 - global___Labels = Labels 226 - 227 - @typing.final 228 - class EntityKey(google.protobuf.message.Message): 229 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 230 - 231 - TYPE_FIELD_NUMBER: builtins.int 232 - ID_FIELD_NUMBER: builtins.int 233 - type: builtins.str 234 - id: builtins.str 235 - def __init__( 236 - self, 237 - *, 238 - type: builtins.str = ..., 239 - id: builtins.str = ..., 240 - ) -> None: ... 241 - def ClearField(self, field_name: typing.Literal["id", b"id", "type", b"type"]) -> None: ... 242 - 243 - global___EntityKey = EntityKey 244 - 245 - @typing.final 246 - class Entity(google.protobuf.message.Message): 247 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 248 - 249 - KEY_FIELD_NUMBER: builtins.int 250 - LABELS_FIELD_NUMBER: builtins.int 251 - @property 252 - def key(self) -> global___EntityKey: ... 253 - @property 254 - def labels(self) -> global___Labels: ... 255 - def __init__( 256 - self, 257 - *, 258 - key: global___EntityKey | None = ..., 259 - labels: global___Labels | None = ..., 260 - ) -> None: ... 261 - def HasField(self, field_name: typing.Literal["key", b"key", "labels", b"labels"]) -> builtins.bool: ... 262 - def ClearField(self, field_name: typing.Literal["key", b"key", "labels", b"labels"]) -> None: ... 263 - 264 - global___Entity = Entity 265 - 266 - @typing.final 267 - class TakeDataRequest(google.protobuf.message.Message): 268 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 269 - 270 - KEY_FIELD_NUMBER: builtins.int 271 - key: builtins.str 272 - def __init__( 273 - self, 274 - *, 275 - key: builtins.str = ..., 276 - ) -> None: ... 277 - def ClearField(self, field_name: typing.Literal["key", b"key"]) -> None: ... 278 - 279 - global___TakeDataRequest = TakeDataRequest 280 - 281 - @typing.final 282 - class Data(google.protobuf.message.Message): 283 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 284 - 285 - BYTES_FIELD_NUMBER: builtins.int 286 - bytes: builtins.bytes 287 - def __init__( 288 - self, 289 - *, 290 - bytes: builtins.bytes = ..., 291 - ) -> None: ... 292 - def ClearField(self, field_name: typing.Literal["bytes", b"bytes"]) -> None: ... 293 - 294 - global___Data = Data 295 - 296 - @typing.final 297 - class TakeDataResponse(google.protobuf.message.Message): 298 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 299 - 300 - DATA_FIELD_NUMBER: builtins.int 301 - @property 302 - def data(self) -> global___Data: ... 303 - def __init__( 304 - self, 305 - *, 306 - data: global___Data | None = ..., 307 - ) -> None: ... 308 - def HasField(self, field_name: typing.Literal["data", b"data"]) -> builtins.bool: ... 309 - def ClearField(self, field_name: typing.Literal["data", b"data"]) -> None: ... 310 - 311 - global___TakeDataResponse = TakeDataResponse 312 - 313 - @typing.final 314 - class GetEntityBatchRequest(google.protobuf.message.Message): 315 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 316 - 317 - ROUTING_KEY_FIELD_NUMBER: builtins.int 318 - KEYS_FIELD_NUMBER: builtins.int 319 - routing_key: builtins.str 320 - @property 321 - def keys(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___EntityKey]: ... 322 - def __init__( 323 - self, 324 - *, 325 - routing_key: builtins.str = ..., 326 - keys: collections.abc.Iterable[global___EntityKey] | None = ..., 327 - ) -> None: ... 328 - def ClearField(self, field_name: typing.Literal["keys", b"keys", "routing_key", b"routing_key"]) -> None: ... 329 - 330 - global___GetEntityBatchRequest = GetEntityBatchRequest 331 - 332 - @typing.final 333 - class GetEntityBatchResponse(google.protobuf.message.Message): 334 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 335 - 336 - RESPONSES_FIELD_NUMBER: builtins.int 337 - @property 338 - def responses(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___GetEntityResponse]: ... 339 - def __init__( 340 - self, 341 - *, 342 - responses: collections.abc.Iterable[global___GetEntityResponse] | None = ..., 343 - ) -> None: ... 344 - def ClearField(self, field_name: typing.Literal["responses", b"responses"]) -> None: ... 345 - 346 - global___GetEntityBatchResponse = GetEntityBatchResponse 347 - 348 - @typing.final 349 - class GetEntityRequest(google.protobuf.message.Message): 350 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 351 - 352 - ROUTING_KEY_FIELD_NUMBER: builtins.int 353 - KEY_FIELD_NUMBER: builtins.int 354 - routing_key: builtins.str 355 - @property 356 - def key(self) -> global___EntityKey: ... 357 - def __init__( 358 - self, 359 - *, 360 - routing_key: builtins.str = ..., 361 - key: global___EntityKey | None = ..., 362 - ) -> None: ... 363 - def HasField(self, field_name: typing.Literal["key", b"key"]) -> builtins.bool: ... 364 - def ClearField(self, field_name: typing.Literal["key", b"key", "routing_key", b"routing_key"]) -> None: ... 365 - 366 - global___GetEntityRequest = GetEntityRequest 367 - 368 - @typing.final 369 - class GetEntityResponse(google.protobuf.message.Message): 370 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 371 - 372 - ENTITY_FIELD_NUMBER: builtins.int 373 - @property 374 - def entity(self) -> global___Entity: ... 375 - def __init__( 376 - self, 377 - *, 378 - entity: global___Entity | None = ..., 379 - ) -> None: ... 380 - def HasField(self, field_name: typing.Literal["entity", b"entity"]) -> builtins.bool: ... 381 - def ClearField(self, field_name: typing.Literal["entity", b"entity"]) -> None: ... 382 - 383 - global___GetEntityResponse = GetEntityResponse 384 - 385 - @typing.final 386 - class EntityMutation(google.protobuf.message.Message): 387 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 388 - 389 - @typing.final 390 - class FeaturesEntry(google.protobuf.message.Message): 391 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 392 - 393 - KEY_FIELD_NUMBER: builtins.int 394 - VALUE_FIELD_NUMBER: builtins.int 395 - key: builtins.str 396 - value: builtins.str 397 - def __init__( 398 - self, 399 - *, 400 - key: builtins.str = ..., 401 - value: builtins.str = ..., 402 - ) -> None: ... 403 - def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... 404 - 405 - LABEL_NAME_FIELD_NUMBER: builtins.int 406 - REASON_NAME_FIELD_NUMBER: builtins.int 407 - STATUS_FIELD_NUMBER: builtins.int 408 - PENDING_FIELD_NUMBER: builtins.int 409 - DESCRIPTION_FIELD_NUMBER: builtins.int 410 - FEATURES_FIELD_NUMBER: builtins.int 411 - EXPIRES_AT_FIELD_NUMBER: builtins.int 412 - label_name: builtins.str 413 - """The label name to apply.""" 414 - reason_name: builtins.str 415 - """The reason the label was applied, generally this is the label name.""" 416 - status: global___LabelStatus.ValueType 417 - pending: builtins.bool 418 - description: builtins.str 419 - @property 420 - def features(self) -> google.protobuf.internal.containers.ScalarMap[builtins.str, builtins.str]: ... 421 - @property 422 - def expires_at(self) -> google.protobuf.timestamp_pb2.Timestamp: ... 423 - def __init__( 424 - self, 425 - *, 426 - label_name: builtins.str = ..., 427 - reason_name: builtins.str = ..., 428 - status: global___LabelStatus.ValueType = ..., 429 - pending: builtins.bool = ..., 430 - description: builtins.str = ..., 431 - features: collections.abc.Mapping[builtins.str, builtins.str] | None = ..., 432 - expires_at: google.protobuf.timestamp_pb2.Timestamp | None = ..., 433 - ) -> None: ... 434 - def HasField(self, field_name: typing.Literal["expires_at", b"expires_at"]) -> builtins.bool: ... 435 - def ClearField(self, field_name: typing.Literal["description", b"description", "expires_at", b"expires_at", "features", b"features", "label_name", b"label_name", "pending", b"pending", "reason_name", b"reason_name", "status", b"status"]) -> None: ... 436 - 437 - global___EntityMutation = EntityMutation 438 - 439 - @typing.final 440 - class ApplyEntityMutationRequest(google.protobuf.message.Message): 441 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 442 - 443 - ROUTING_KEY_FIELD_NUMBER: builtins.int 444 - KEY_FIELD_NUMBER: builtins.int 445 - MUTATIONS_FIELD_NUMBER: builtins.int 446 - routing_key: builtins.str 447 - @property 448 - def key(self) -> global___EntityKey: ... 449 - @property 450 - def mutations(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___EntityMutation]: ... 451 - def __init__( 452 - self, 453 - *, 454 - routing_key: builtins.str = ..., 455 - key: global___EntityKey | None = ..., 456 - mutations: collections.abc.Iterable[global___EntityMutation] | None = ..., 457 - ) -> None: ... 458 - def HasField(self, field_name: typing.Literal["key", b"key"]) -> builtins.bool: ... 459 - def ClearField(self, field_name: typing.Literal["key", b"key", "mutations", b"mutations", "routing_key", b"routing_key"]) -> None: ... 460 - 461 - global___ApplyEntityMutationRequest = ApplyEntityMutationRequest 462 - 463 - @typing.final 464 - class ApplyEntityMutationReply(google.protobuf.message.Message): 465 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 466 - 467 - ADDED_FIELD_NUMBER: builtins.int 468 - REMOVED_FIELD_NUMBER: builtins.int 469 - UNCHANGED_FIELD_NUMBER: builtins.int 470 - DROPPED_FIELD_NUMBER: builtins.int 471 - @property 472 - def added(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... 473 - @property 474 - def removed(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... 475 - @property 476 - def unchanged(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ... 477 - @property 478 - def dropped(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___EntityMutation]: ... 479 - def __init__( 480 - self, 481 - *, 482 - added: collections.abc.Iterable[builtins.str] | None = ..., 483 - removed: collections.abc.Iterable[builtins.str] | None = ..., 484 - unchanged: collections.abc.Iterable[builtins.str] | None = ..., 485 - dropped: collections.abc.Iterable[global___EntityMutation] | None = ..., 486 - ) -> None: ... 487 - def ClearField(self, field_name: typing.Literal["added", b"added", "dropped", b"dropped", "removed", b"removed", "unchanged", b"unchanged"]) -> None: ... 488 - 489 - global___ApplyEntityMutationReply = ApplyEntityMutationReply 490 - 491 - @typing.final 492 - class TokenRangeQuery(google.protobuf.message.Message): 493 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 494 - 495 - OPAQUE_FIELD_NUMBER: builtins.int 496 - opaque: builtins.str 497 - def __init__( 498 - self, 499 - *, 500 - opaque: builtins.str = ..., 501 - ) -> None: ... 502 - def ClearField(self, field_name: typing.Literal["opaque", b"opaque"]) -> None: ... 503 - 504 - global___TokenRangeQuery = TokenRangeQuery 505 - 506 - @typing.final 507 - class GetTokenRangeQueriesRequest(google.protobuf.message.Message): 508 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 509 - 510 - def __init__( 511 - self, 512 - ) -> None: ... 513 - 514 - global___GetTokenRangeQueriesRequest = GetTokenRangeQueriesRequest 515 - 516 - @typing.final 517 - class GetTokenRangeQueriesResult(google.protobuf.message.Message): 518 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 519 - 520 - MAX_QUERY_CONCURRENCY_FIELD_NUMBER: builtins.int 521 - TOKEN_RANGE_QUERIES_FIELD_NUMBER: builtins.int 522 - max_query_concurrency: builtins.int 523 - @property 524 - def token_range_queries(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___TokenRangeQuery]: ... 525 - def __init__( 526 - self, 527 - *, 528 - max_query_concurrency: builtins.int = ..., 529 - token_range_queries: collections.abc.Iterable[global___TokenRangeQuery] | None = ..., 530 - ) -> None: ... 531 - def ClearField(self, field_name: typing.Literal["max_query_concurrency", b"max_query_concurrency", "token_range_queries", b"token_range_queries"]) -> None: ... 532 - 533 - global___GetTokenRangeQueriesResult = GetTokenRangeQueriesResult 534 - 535 - @typing.final 536 - class ScanTokenRangeRequest(google.protobuf.message.Message): 537 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 538 - 539 - TOKEN_RANGE_QUERY_FIELD_NUMBER: builtins.int 540 - @property 541 - def token_range_query(self) -> global___TokenRangeQuery: ... 542 - def __init__( 543 - self, 544 - *, 545 - token_range_query: global___TokenRangeQuery | None = ..., 546 - ) -> None: ... 547 - def HasField(self, field_name: typing.Literal["token_range_query", b"token_range_query"]) -> builtins.bool: ... 548 - def ClearField(self, field_name: typing.Literal["token_range_query", b"token_range_query"]) -> None: ... 549 - 550 - global___ScanTokenRangeRequest = ScanTokenRangeRequest 551 - 552 - @typing.final 553 - class ScanTokenRangeResult(google.protobuf.message.Message): 554 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 555 - 556 - CONTINUATION_TOKEN_FIELD_NUMBER: builtins.int 557 - ENTITIES_FIELD_NUMBER: builtins.int 558 - @property 559 - def continuation_token(self) -> global___TokenRangeQuery: ... 560 - @property 561 - def entities(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Entity]: ... 562 - def __init__( 563 - self, 564 - *, 565 - continuation_token: global___TokenRangeQuery | None = ..., 566 - entities: collections.abc.Iterable[global___Entity] | None = ..., 567 - ) -> None: ... 568 - def HasField(self, field_name: typing.Literal["continuation_token", b"continuation_token"]) -> builtins.bool: ... 569 - def ClearField(self, field_name: typing.Literal["continuation_token", b"continuation_token", "entities", b"entities"]) -> None: ... 570 - 571 - global___ScanTokenRangeResult = ScanTokenRangeResult 572 - 573 - @typing.final 574 - class LabelReasonMutationResult(google.protobuf.message.Message): 575 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 576 - 577 - OPERATION_FIELD_NUMBER: builtins.int 578 - PREV_REASON_FIELD_NUMBER: builtins.int 579 - CURRENT_REASON_FIELD_NUMBER: builtins.int 580 - operation: global___MutationOperation.ValueType 581 - @property 582 - def prev_reason(self) -> global___LabelReason: ... 583 - @property 584 - def current_reason(self) -> global___LabelReason: ... 585 - def __init__( 586 - self, 587 - *, 588 - operation: global___MutationOperation.ValueType = ..., 589 - prev_reason: global___LabelReason | None = ..., 590 - current_reason: global___LabelReason | None = ..., 591 - ) -> None: ... 592 - def HasField(self, field_name: typing.Literal["current_reason", b"current_reason", "prev_reason", b"prev_reason"]) -> builtins.bool: ... 593 - def ClearField(self, field_name: typing.Literal["current_reason", b"current_reason", "operation", b"operation", "prev_reason", b"prev_reason"]) -> None: ... 594 - 595 - global___LabelReasonMutationResult = LabelReasonMutationResult 596 - 597 - @typing.final 598 - class LabelMutationResult(google.protobuf.message.Message): 599 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 600 - 601 - @typing.final 602 - class ReasonsEntry(google.protobuf.message.Message): 603 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 604 - 605 - KEY_FIELD_NUMBER: builtins.int 606 - VALUE_FIELD_NUMBER: builtins.int 607 - key: builtins.str 608 - @property 609 - def value(self) -> global___LabelReasonMutationResult: ... 610 - def __init__( 611 - self, 612 - *, 613 - key: builtins.str = ..., 614 - value: global___LabelReasonMutationResult | None = ..., 615 - ) -> None: ... 616 - def HasField(self, field_name: typing.Literal["value", b"value"]) -> builtins.bool: ... 617 - def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... 618 - 619 - STATUS_FIELD_NUMBER: builtins.int 620 - OPERATION_FIELD_NUMBER: builtins.int 621 - REASONS_FIELD_NUMBER: builtins.int 622 - status: global___LabelStatus.ValueType 623 - operation: global___MutationOperation.ValueType 624 - @property 625 - def reasons(self) -> google.protobuf.internal.containers.MessageMap[builtins.str, global___LabelReasonMutationResult]: ... 626 - def __init__( 627 - self, 628 - *, 629 - status: global___LabelStatus.ValueType = ..., 630 - operation: global___MutationOperation.ValueType = ..., 631 - reasons: collections.abc.Mapping[builtins.str, global___LabelReasonMutationResult] | None = ..., 632 - ) -> None: ... 633 - def ClearField(self, field_name: typing.Literal["operation", b"operation", "reasons", b"reasons", "status", b"status"]) -> None: ... 634 - 635 - global___LabelMutationResult = LabelMutationResult 636 - 637 - @typing.final 638 - class ApplyEntityMutationReplyUpdated(google.protobuf.message.Message): 639 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 640 - 641 - @typing.final 642 - class LabelMutationsEntry(google.protobuf.message.Message): 643 - DESCRIPTOR: google.protobuf.descriptor.Descriptor 644 - 645 - KEY_FIELD_NUMBER: builtins.int 646 - VALUE_FIELD_NUMBER: builtins.int 647 - key: builtins.str 648 - @property 649 - def value(self) -> global___LabelMutationResult: ... 650 - def __init__( 651 - self, 652 - *, 653 - key: builtins.str = ..., 654 - value: global___LabelMutationResult | None = ..., 655 - ) -> None: ... 656 - def HasField(self, field_name: typing.Literal["value", b"value"]) -> builtins.bool: ... 657 - def ClearField(self, field_name: typing.Literal["key", b"key", "value", b"value"]) -> None: ... 658 - 659 - LABEL_MUTATIONS_FIELD_NUMBER: builtins.int 660 - DROPPED_FIELD_NUMBER: builtins.int 661 - @property 662 - def label_mutations(self) -> google.protobuf.internal.containers.MessageMap[builtins.str, global___LabelMutationResult]: ... 663 - @property 664 - def dropped(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___EntityMutation]: ... 665 - def __init__( 666 - self, 667 - *, 668 - label_mutations: collections.abc.Mapping[builtins.str, global___LabelMutationResult] | None = ..., 669 - dropped: collections.abc.Iterable[global___EntityMutation] | None = ..., 670 - ) -> None: ... 671 - def ClearField(self, field_name: typing.Literal["dropped", b"dropped", "label_mutations", b"label_mutations"]) -> None: ... 672 - 673 - global___ApplyEntityMutationReplyUpdated = ApplyEntityMutationReplyUpdated
-269
osprey_rpc/src/osprey/rpc/labels/v1/service_pb2_grpc.py
··· 1 - # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 - """Client and server classes corresponding to protobuf-defined services.""" 3 - import grpc 4 - 5 - from osprey.rpc.labels.v1 import service_pb2 as osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2 6 - 7 - 8 - class LabelServiceStub(object): 9 - """Missing associated documentation comment in .proto file.""" 10 - 11 - def __init__(self, channel): 12 - """Constructor. 13 - 14 - Args: 15 - channel: A grpc.Channel. 16 - """ 17 - self.TakeData = channel.unary_unary( 18 - '/osprey.rpc.labels.v1.LabelService/TakeData', 19 - request_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.TakeDataRequest.SerializeToString, 20 - response_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.TakeDataResponse.FromString, 21 - ) 22 - self.GetEntity = channel.unary_unary( 23 - '/osprey.rpc.labels.v1.LabelService/GetEntity', 24 - request_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityRequest.SerializeToString, 25 - response_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityResponse.FromString, 26 - ) 27 - self.ApplyEntityMutation = channel.unary_unary( 28 - '/osprey.rpc.labels.v1.LabelService/ApplyEntityMutation', 29 - request_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationRequest.SerializeToString, 30 - response_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationReply.FromString, 31 - ) 32 - self.ApplyEntityMutationUpdated = channel.unary_unary( 33 - '/osprey.rpc.labels.v1.LabelService/ApplyEntityMutationUpdated', 34 - request_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationRequest.SerializeToString, 35 - response_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationReplyUpdated.FromString, 36 - ) 37 - self.GetEntityBatch = channel.unary_unary( 38 - '/osprey.rpc.labels.v1.LabelService/GetEntityBatch', 39 - request_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityBatchRequest.SerializeToString, 40 - response_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityBatchResponse.FromString, 41 - ) 42 - self.GetTokenRangeQueries = channel.unary_unary( 43 - '/osprey.rpc.labels.v1.LabelService/GetTokenRangeQueries', 44 - request_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetTokenRangeQueriesRequest.SerializeToString, 45 - response_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetTokenRangeQueriesResult.FromString, 46 - ) 47 - self.ScanTokenRange = channel.unary_unary( 48 - '/osprey.rpc.labels.v1.LabelService/ScanTokenRange', 49 - request_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ScanTokenRangeRequest.SerializeToString, 50 - response_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ScanTokenRangeResult.FromString, 51 - ) 52 - 53 - 54 - class LabelServiceServicer(object): 55 - """Missing associated documentation comment in .proto file.""" 56 - 57 - def TakeData(self, request, context): 58 - """-- Internal take_data API 59 - """ 60 - context.set_code(grpc.StatusCode.UNIMPLEMENTED) 61 - context.set_details('Method not implemented!') 62 - raise NotImplementedError('Method not implemented!') 63 - 64 - def GetEntity(self, request, context): 65 - """-- External APIs 66 - -- Label Read/Mutation 67 - """ 68 - context.set_code(grpc.StatusCode.UNIMPLEMENTED) 69 - context.set_details('Method not implemented!') 70 - raise NotImplementedError('Method not implemented!') 71 - 72 - def ApplyEntityMutation(self, request, context): 73 - """Missing associated documentation comment in .proto file.""" 74 - context.set_code(grpc.StatusCode.UNIMPLEMENTED) 75 - context.set_details('Method not implemented!') 76 - raise NotImplementedError('Method not implemented!') 77 - 78 - def ApplyEntityMutationUpdated(self, request, context): 79 - """Missing associated documentation comment in .proto file.""" 80 - context.set_code(grpc.StatusCode.UNIMPLEMENTED) 81 - context.set_details('Method not implemented!') 82 - raise NotImplementedError('Method not implemented!') 83 - 84 - def GetEntityBatch(self, request, context): 85 - """-- Batches 86 - """ 87 - context.set_code(grpc.StatusCode.UNIMPLEMENTED) 88 - context.set_details('Method not implemented!') 89 - raise NotImplementedError('Method not implemented!') 90 - 91 - def GetTokenRangeQueries(self, request, context): 92 - """-- Label Iteration 93 - """ 94 - context.set_code(grpc.StatusCode.UNIMPLEMENTED) 95 - context.set_details('Method not implemented!') 96 - raise NotImplementedError('Method not implemented!') 97 - 98 - def ScanTokenRange(self, request, context): 99 - """Missing associated documentation comment in .proto file.""" 100 - context.set_code(grpc.StatusCode.UNIMPLEMENTED) 101 - context.set_details('Method not implemented!') 102 - raise NotImplementedError('Method not implemented!') 103 - 104 - 105 - def add_LabelServiceServicer_to_server(servicer, server): 106 - rpc_method_handlers = { 107 - 'TakeData': grpc.unary_unary_rpc_method_handler( 108 - servicer.TakeData, 109 - request_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.TakeDataRequest.FromString, 110 - response_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.TakeDataResponse.SerializeToString, 111 - ), 112 - 'GetEntity': grpc.unary_unary_rpc_method_handler( 113 - servicer.GetEntity, 114 - request_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityRequest.FromString, 115 - response_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityResponse.SerializeToString, 116 - ), 117 - 'ApplyEntityMutation': grpc.unary_unary_rpc_method_handler( 118 - servicer.ApplyEntityMutation, 119 - request_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationRequest.FromString, 120 - response_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationReply.SerializeToString, 121 - ), 122 - 'ApplyEntityMutationUpdated': grpc.unary_unary_rpc_method_handler( 123 - servicer.ApplyEntityMutationUpdated, 124 - request_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationRequest.FromString, 125 - response_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationReplyUpdated.SerializeToString, 126 - ), 127 - 'GetEntityBatch': grpc.unary_unary_rpc_method_handler( 128 - servicer.GetEntityBatch, 129 - request_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityBatchRequest.FromString, 130 - response_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityBatchResponse.SerializeToString, 131 - ), 132 - 'GetTokenRangeQueries': grpc.unary_unary_rpc_method_handler( 133 - servicer.GetTokenRangeQueries, 134 - request_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetTokenRangeQueriesRequest.FromString, 135 - response_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetTokenRangeQueriesResult.SerializeToString, 136 - ), 137 - 'ScanTokenRange': grpc.unary_unary_rpc_method_handler( 138 - servicer.ScanTokenRange, 139 - request_deserializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ScanTokenRangeRequest.FromString, 140 - response_serializer=osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ScanTokenRangeResult.SerializeToString, 141 - ), 142 - } 143 - generic_handler = grpc.method_handlers_generic_handler( 144 - 'osprey.rpc.labels.v1.LabelService', rpc_method_handlers) 145 - server.add_generic_rpc_handlers((generic_handler,)) 146 - 147 - 148 - # This class is part of an EXPERIMENTAL API. 149 - class LabelService(object): 150 - """Missing associated documentation comment in .proto file.""" 151 - 152 - @staticmethod 153 - def TakeData(request, 154 - target, 155 - options=(), 156 - channel_credentials=None, 157 - call_credentials=None, 158 - insecure=False, 159 - compression=None, 160 - wait_for_ready=None, 161 - timeout=None, 162 - metadata=None): 163 - return grpc.experimental.unary_unary(request, target, '/osprey.rpc.labels.v1.LabelService/TakeData', 164 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.TakeDataRequest.SerializeToString, 165 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.TakeDataResponse.FromString, 166 - options, channel_credentials, 167 - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 168 - 169 - @staticmethod 170 - def GetEntity(request, 171 - target, 172 - options=(), 173 - channel_credentials=None, 174 - call_credentials=None, 175 - insecure=False, 176 - compression=None, 177 - wait_for_ready=None, 178 - timeout=None, 179 - metadata=None): 180 - return grpc.experimental.unary_unary(request, target, '/osprey.rpc.labels.v1.LabelService/GetEntity', 181 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityRequest.SerializeToString, 182 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityResponse.FromString, 183 - options, channel_credentials, 184 - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 185 - 186 - @staticmethod 187 - def ApplyEntityMutation(request, 188 - target, 189 - options=(), 190 - channel_credentials=None, 191 - call_credentials=None, 192 - insecure=False, 193 - compression=None, 194 - wait_for_ready=None, 195 - timeout=None, 196 - metadata=None): 197 - return grpc.experimental.unary_unary(request, target, '/osprey.rpc.labels.v1.LabelService/ApplyEntityMutation', 198 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationRequest.SerializeToString, 199 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationReply.FromString, 200 - options, channel_credentials, 201 - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 202 - 203 - @staticmethod 204 - def ApplyEntityMutationUpdated(request, 205 - target, 206 - options=(), 207 - channel_credentials=None, 208 - call_credentials=None, 209 - insecure=False, 210 - compression=None, 211 - wait_for_ready=None, 212 - timeout=None, 213 - metadata=None): 214 - return grpc.experimental.unary_unary(request, target, '/osprey.rpc.labels.v1.LabelService/ApplyEntityMutationUpdated', 215 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationRequest.SerializeToString, 216 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ApplyEntityMutationReplyUpdated.FromString, 217 - options, channel_credentials, 218 - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 219 - 220 - @staticmethod 221 - def GetEntityBatch(request, 222 - target, 223 - options=(), 224 - channel_credentials=None, 225 - call_credentials=None, 226 - insecure=False, 227 - compression=None, 228 - wait_for_ready=None, 229 - timeout=None, 230 - metadata=None): 231 - return grpc.experimental.unary_unary(request, target, '/osprey.rpc.labels.v1.LabelService/GetEntityBatch', 232 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityBatchRequest.SerializeToString, 233 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetEntityBatchResponse.FromString, 234 - options, channel_credentials, 235 - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 236 - 237 - @staticmethod 238 - def GetTokenRangeQueries(request, 239 - target, 240 - options=(), 241 - channel_credentials=None, 242 - call_credentials=None, 243 - insecure=False, 244 - compression=None, 245 - wait_for_ready=None, 246 - timeout=None, 247 - metadata=None): 248 - return grpc.experimental.unary_unary(request, target, '/osprey.rpc.labels.v1.LabelService/GetTokenRangeQueries', 249 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetTokenRangeQueriesRequest.SerializeToString, 250 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.GetTokenRangeQueriesResult.FromString, 251 - options, channel_credentials, 252 - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) 253 - 254 - @staticmethod 255 - def ScanTokenRange(request, 256 - target, 257 - options=(), 258 - channel_credentials=None, 259 - call_credentials=None, 260 - insecure=False, 261 - compression=None, 262 - wait_for_ready=None, 263 - timeout=None, 264 - metadata=None): 265 - return grpc.experimental.unary_unary(request, target, '/osprey.rpc.labels.v1.LabelService/ScanTokenRange', 266 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ScanTokenRangeRequest.SerializeToString, 267 - osprey_dot_rpc_dot_labels_dot_v1_dot_service__pb2.ScanTokenRangeResult.FromString, 268 - options, channel_credentials, 269 - insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+6 -7
osprey_worker/src/osprey/engine/executor/execution_context.py
··· 26 26 from osprey.engine.executor.custom_extracted_features import ( 27 27 CustomExtractedFeature, 28 28 ) 29 + from osprey.engine.executor.dependency_chain import DependencyChain 30 + from osprey.engine.executor.execution_graph import ExecutionGraph 31 + from osprey.engine.executor.external_service_utils import ExternalService, ExternalServiceAccessor, KeyT, ValueT 32 + from osprey.engine.executor.topological_sorter import TopologicalSorter 33 + from osprey.engine.executor.udf_execution_helpers import HasHelperInternal, HelperT, UDFHelpers 29 34 from osprey.engine.language_types.effects import ( 30 35 EffectBase, 31 36 EffectToCustomExtractedFeatureBase, ··· 34 39 from osprey.engine.language_types.verdicts import VerdictEffect 35 40 from osprey.engine.utils.types import add_slots, cached_property 36 41 from osprey.rpc.common.v1.verdicts_pb2 import Verdicts 37 - from osprey.rpc.labels.v1.service_pb2 import EntityMutation 42 + from osprey.worker.lib.osprey_shared.labels import EntityMutation 38 43 from result import Result, UnwrapError 39 - 40 - from .dependency_chain import DependencyChain 41 - from .execution_graph import ExecutionGraph 42 - from .external_service_utils import ExternalService, ExternalServiceAccessor, KeyT, ValueT 43 - from .topological_sorter import TopologicalSorter 44 - from .udf_execution_helpers import HasHelperInternal, HelperT, UDFHelpers 45 44 46 45 if TYPE_CHECKING: 47 46 from osprey.engine.ast_validator.validation_context import ValidatedSources
+21 -2
osprey_worker/src/osprey/engine/language_types/labels.py
··· 1 1 from dataclasses import dataclass 2 2 from datetime import timedelta 3 + from enum import IntEnum 3 4 from typing import Any, List, Optional, Self, cast 4 5 5 6 from osprey.engine.executor.custom_extracted_features import CustomExtractedFeature ··· 8 9 ENTITY_LABEL_MUTATION_DIMENSION_NAME, 9 10 ENTITY_LABEL_MUTATION_DIMENSION_VALUE, 10 11 ) 11 - from osprey.rpc.labels.v1.service_pb2 import LabelStatus 12 12 13 13 from .entities import EntityT 14 14 from .rules import RuleT, add_slots 15 15 16 16 17 + class LabelStatus(IntEnum): 18 + ADDED = 0 19 + REMOVED = 1 20 + MANUALLY_ADDED = 2 21 + MANUALLY_REMOVED = 3 22 + 23 + def effective_label_status(self) -> 'LabelStatus': 24 + """ 25 + Returns the effective status of the label, which is what the upstreams that are observing label 26 + status changes will see. Which is to say, the upstreams will currently not see if the label status was 27 + manually added or manually removed, just that it was added or removed. 28 + """ 29 + match self: 30 + case LabelStatus.ADDED | LabelStatus.MANUALLY_ADDED: 31 + return LabelStatus.ADDED 32 + case LabelStatus.REMOVED | LabelStatus.MANUALLY_REMOVED: 33 + return LabelStatus.REMOVED 34 + 35 + 17 36 @add_slots 18 37 @dataclass 19 38 class LabelEffect(EffectToCustomExtractedFeatureBase[List[str]]): ··· 23 42 entity: EntityT[Any] 24 43 """The entity that the effect will be applied on.""" 25 44 26 - status: LabelStatus.ValueType 45 + status: LabelStatus 27 46 """The status of the label that will be applied by this effect.""" 28 47 29 48 name: str
+3 -4
osprey_worker/src/osprey/engine/query_language/udfs/did_mutate_label.py
··· 1 1 from typing import Dict 2 2 3 + from osprey.engine import shared_constants 3 4 from osprey.engine.ast_validator.validation_context import ValidationContext 5 + from osprey.engine.language_types.labels import LabelStatus 6 + from osprey.engine.query_language.udfs.registry import register 4 7 from osprey.engine.udf.arguments import ArgumentsBase, ConstExpr 5 8 from osprey.engine.udf.base import QueryUdfBase 6 - from osprey.rpc.labels.v1.service_pb2 import LabelStatus 7 - 8 - from ... import shared_constants 9 - from .registry import register 10 9 11 10 12 11 class Arguments(ArgumentsBase):
+4 -4
osprey_worker/src/osprey/engine/shared_constants.py
··· 1 + import typing 1 2 from enum import StrEnum 2 3 3 - from osprey.rpc.labels.v1.service_pb2 import LabelStatus 4 + if typing.TYPE_CHECKING: 5 + from osprey.engine.language_types.labels import LabelStatus 4 6 5 7 ENTITY_LABEL_MUTATION_DIMENSION_NAME = '__entity_label_mutations' 6 8 VERDICT_DIMENSION_NAME = '__verdicts' 7 9 8 10 9 - def ENTITY_LABEL_MUTATION_DIMENSION_VALUE( 10 - entity_type: str, label_name: str, label_status: LabelStatus.ValueType 11 - ) -> str: 11 + def ENTITY_LABEL_MUTATION_DIMENSION_VALUE(entity_type: str, label_name: str, label_status: 'LabelStatus') -> str: 12 12 return f'{entity_type}/{label_name}/{label_status}' 13 13 14 14
+18 -21
osprey_worker/src/osprey/engine/stdlib/udfs/labels.py
··· 8 8 EffectBase, 9 9 ) 10 10 from osprey.engine.language_types.entities import EntityT 11 - from osprey.engine.language_types.labels import LabelEffect 11 + from osprey.engine.language_types.labels import LabelEffect, LabelStatus 12 12 from osprey.engine.language_types.rules import RuleT 13 13 from osprey.engine.language_types.time_delta import TimeDeltaT 14 14 from osprey.engine.stdlib.configs.labels_config import LabelsConfig ··· 24 24 from osprey.engine.utils.get_closest_string_within_threshold import ( 25 25 get_closest_string_within_threshold, 26 26 ) 27 - from osprey.rpc.labels.v1.service_pb2 import Labels, LabelStatus 28 - from osprey.worker.lib.storage.labels import LabelProvider, get_label_routing_key 27 + from osprey.worker.lib.osprey_shared.labels import Labels 28 + from osprey.worker.lib.storage.labels import LabelProvider 29 29 from result import Err, Ok, Result 30 30 31 31 ··· 43 43 """Optional: Automatically expire the mutation after a specified `TimeDeltaT` time.""" 44 44 45 45 46 - def synthesize_effect(status: 'LabelStatus.ValueType', arguments: LabelArguments) -> LabelEffect: 46 + def synthesize_effect(status: LabelStatus, arguments: LabelArguments) -> LabelEffect: 47 47 return LabelEffect( 48 48 entity=arguments.entity, 49 49 status=status, ··· 138 138 139 139 hint = f'expected `{_SimpleStatus.ADDED.value}` or `{_SimpleStatus.REMOVED.value}`, got `{status_name}`' 140 140 if status_name.upper() in ( 141 - LabelStatus.Name(LabelStatus.MANUALLY_ADDED), 142 - LabelStatus.Name(LabelStatus.MANUALLY_REMOVED), 141 + LabelStatus.MANUALLY_ADDED.name, 142 + LabelStatus.MANUALLY_REMOVED.name, 143 143 ): 144 144 hint += '\nto specify a manually set label, set `manual=True`' 145 145 ··· 162 162 desired_manual = _ManualType.get(arguments.manual) 163 163 desired_delay = TimeDeltaT.inner_from_optional(arguments.min_label_age) 164 164 label_state = entity_labels.labels.get(arguments.label) 165 + now = datetime.now() 166 + 165 167 if label_state is not None: 166 - now = datetime.now() 167 168 # Check to see if all reasons have expired, if so, the label should be considered as expired. 168 169 # Only consider a reason expired if it has a meaningful expires_at timestamp (not default/epoch) 169 170 all_reasons_expired = all( 170 - reason.HasField('expires_at') 171 - and reason.expires_at.seconds > 0 # Check if timestamp is not default/epoch 172 - and reason.expires_at.ToDatetime() <= now 171 + reason.expires_at 172 + and reason.expires_at.second > 0 # Check if timestamp is not default/epoch 173 + and reason.expires_at <= now 173 174 for reason in label_state.reasons.values() 174 175 ) 175 176 if all_reasons_expired: ··· 196 197 if desired_delay is not None: 197 198 # Get the oldest non-expired label 198 199 oldest_non_expired = min( 199 - reason.created_at.ToDatetime() 200 + reason.created_at 200 201 for reason in label_state.reasons.values() 201 - if reason.HasField('created_at') 202 + if reason.created_at 202 203 and ( 203 - not reason.HasField('expires_at') 204 - or reason.expires_at.seconds == 0 # No meaningful expiration set 205 - or reason.expires_at.ToDatetime() > now 204 + not reason.expires_at 205 + or reason.expires_at.second == 0 # No meaningful expiration set 206 + or reason.expires_at > now 206 207 ) 207 208 ) 208 209 actual_delay = now - oldest_non_expired ··· 216 217 def execute(self, execution_context: ExecutionContext, arguments: HasLabelArguments) -> bool: 217 218 label_provider = execution_context.get_udf_helper(self) 218 219 accessor = execution_context.get_external_service_accessor(label_provider) 219 - entity_labels_pb2_internal = accessor.get(arguments.entity) 220 - entity_labels_pb2 = entity_labels_pb2_internal 221 - return self._execute(execution_context, self.get_batchable_arguments(arguments), entity_labels_pb2) 220 + entity_labels = accessor.get(arguments.entity) 221 + return self._execute(execution_context, self.get_batchable_arguments(arguments), entity_labels) 222 222 223 223 def get_batchable_arguments(self, arguments: HasLabelArguments) -> BatchableHasLabelArguments: 224 224 return BatchableHasLabelArguments( ··· 229 229 min_label_age=arguments.min_label_age, 230 230 desired_status=self.desired_status, 231 231 ) 232 - 233 - def get_batch_routing_key(self, arguments: BatchableHasLabelArguments) -> str: 234 - return get_label_routing_key(arguments.entity) 235 232 236 233 def execute_batch( 237 234 self,
-4
osprey_worker/src/osprey/worker/_stdlibplugin/udf_register.py
··· 15 15 from osprey.engine.stdlib.udfs.import_ import Import 16 16 from osprey.engine.stdlib.udfs.ip_network import IpNetwork 17 17 from osprey.engine.stdlib.udfs.json_data import JsonData 18 - from osprey.engine.stdlib.udfs.labels import HasLabel, LabelAdd, LabelRemove 19 18 from osprey.engine.stdlib.udfs.list_length import ListLength 20 19 from osprey.engine.stdlib.udfs.list_read import ListRead 21 20 from osprey.engine.stdlib.udfs.list_sort import ListSort ··· 83 82 ExperimentsBucketAssignment, 84 83 ExtractCookie, 85 84 GetActionName, 86 - HasLabel, 87 85 Import, 88 86 IpNetwork, 89 87 JsonData, 90 - LabelAdd, 91 - LabelRemove, 92 88 ListLength, 93 89 ListRead, 94 90 ListSort,
+7
osprey_worker/src/osprey/worker/adaptor/hookspecs/osprey_hooks.py
··· 8 8 from osprey.engine.udf.base import UDFBase 9 9 from osprey.worker.adaptor.constants import OSPREY_ADAPTOR 10 10 from osprey.worker.lib.action_proto_deserializer import ActionProtoDeserializer 11 + from osprey.worker.lib.storage.labels import LabelProvider 11 12 from osprey.worker.sinks.sink.input_stream import BaseInputStream 12 13 from osprey.worker.sinks.utils.acking_contexts import BaseAckingContext 13 14 ··· 52 53 def register_execution_result_store(config: Config) -> ExecutionResultStore: 53 54 """Register an execution result storage backend instance.""" 54 55 raise NotImplementedError('register_execution_result_store must be implemented by the plugin') 56 + 57 + 58 + @hookspec(firstresult=True) 59 + def register_label_provider(config: Config) -> LabelProvider: 60 + """Register an execution result storage backend instance.""" 61 + raise NotImplementedError('register_label_provider must be implemented by the plugin')
+30 -5
osprey_worker/src/osprey/worker/adaptor/plugin_manager.py
··· 12 12 from osprey.worker.adaptor.constants import OSPREY_ADAPTOR 13 13 from osprey.worker.adaptor.hookspecs import osprey_hooks 14 14 from osprey.worker.lib.action_proto_deserializer import ActionProtoDeserializer 15 - from osprey.worker.lib.storage.labels import HasLabelProvider 15 + from osprey.worker.lib.storage.labels import LabelProvider 16 16 from osprey.worker.sinks.sink.input_stream import BaseInputStream 17 - from osprey.worker.sinks.sink.output_sink import BaseOutputSink, MultiOutputSink 17 + from osprey.worker.sinks.sink.output_sink import BaseOutputSink, LabelOutputSink, MultiOutputSink 18 18 from osprey.worker.sinks.utils.acking_contexts import BaseAckingContext 19 19 20 20 if TYPE_CHECKING: ··· 39 39 return sum(seq, []) 40 40 41 41 42 + def _has_labels_provider() -> bool: 43 + return hasattr(plugin_manager.hook, 'register_labels_provider') 44 + 45 + 42 46 def bootstrap_udfs() -> tuple[UDFRegistry, UDFHelpers]: 43 47 load_all_osprey_plugins() 44 48 udf_helpers = UDFHelpers() ··· 50 54 if issubclass(udf, HasHelper): 51 55 udf_helpers.set_udf_helper(udf, udf.create_provider()) 52 56 53 - # ayu change this one - note that referencing HasLabel has some odd circular imports so its done here 54 - from osprey.engine.stdlib.udfs.labels import HasLabel 57 + # Label udfs should only be registered if the labels provider is available 58 + if _has_labels_provider(): 59 + # Imports kinda circular. Imports here are to avoid that. 60 + from osprey.engine.stdlib.udfs.labels import HasLabel, LabelAdd, LabelRemove 61 + 62 + udfs.extend([HasLabel, LabelAdd, LabelRemove]) 55 63 56 - udf_helpers.set_udf_helper(HasLabel, HasLabelProvider()) 64 + labels_provider = plugin_manager.hook.register_labels_provider() 65 + udf_helpers.set_udf_helper(HasLabel, labels_provider) 57 66 58 67 return udf_registry, udf_helpers 59 68 ··· 61 70 def bootstrap_output_sinks(config: Config) -> BaseOutputSink: 62 71 load_all_osprey_plugins() 63 72 sinks = flatten(plugin_manager.hook.register_output_sinks(config=config)) 73 + 74 + # Label udfs should only be registered if the labels provider is available 75 + if _has_labels_provider(): 76 + sinks.append(LabelOutputSink(bootstrap_label_provider())) 77 + 64 78 return MultiOutputSink(sinks) 79 + 80 + 81 + def bootstrap_label_provider() -> LabelProvider: 82 + """ 83 + Generates a bootstrapped label provider using the registered plugin. 84 + Calling this is not necessary if you already called bootstrap_output_sinks, but is available for convenience. 85 + """ 86 + load_all_osprey_plugins() 87 + if not _has_labels_provider(): 88 + raise NotImplementedError('Label provider assumes register_labels_provider is implemented.') 89 + return plugin_manager.hook.register_labels_provider() 65 90 66 91 67 92 def bootstrap_ast_validators() -> None:
+2 -2
osprey_worker/src/osprey/worker/cli/sinks.py
··· 3 3 4 4 from osprey.worker.lib.patcher import patch_all 5 5 from osprey.worker.sinks.input_stream_chooser import get_rules_sink_input_stream 6 - from osprey.worker.sinks.sink.output_sink import EventEffectsOutputSink 6 + from osprey.worker.sinks.sink.output_sink import LabelOutputSink 7 7 8 8 patch_all(ddtrace_args={'cassandra': True, 'psycopg': True}) 9 9 ··· 271 271 osprey_webhook_pubsub_topic = config.get_str('PUBSUB_OSPREY_WEBHOOKS_TOPIC_ID', 'osprey-webhooks') 272 272 webhooks_publisher = PubSubPublisher(osprey_webhook_pubsub_project, osprey_webhook_pubsub_topic) 273 273 274 - event_effects_output_sink = EventEffectsOutputSink(engine, analytics_publisher, webhooks_publisher) 274 + event_effects_output_sink = LabelOutputSink(engine, analytics_publisher, webhooks_publisher) 275 275 276 276 def factory() -> BulkLabelSink: 277 277 # NOTE: It's very important the input stream is created per-webhook sink
+3 -3
osprey_worker/src/osprey/worker/lib/cli.py
··· 46 46 stored_execution_result, 47 47 ) 48 48 from osprey.worker.lib.utils.click_utils import EnumChoicePb2 # noqa: E402 49 - from osprey.worker.sinks.sink.output_sink import EventEffectsOutputSink # noqa: E402 49 + from osprey.worker.sinks.sink.output_sink import LabelOutputSink # noqa: E402 50 50 from osprey.worker.sinks.sink.output_sink_utils.constants import MutationEventType # noqa: E402 51 51 52 52 if TYPE_CHECKING: ··· 266 266 print(result) 267 267 268 268 269 - def get_event_effects_output_sink() -> EventEffectsOutputSink: 269 + def get_event_effects_output_sink() -> LabelOutputSink: 270 270 config = CONFIG.instance() 271 271 config.configure_from_env() 272 272 ··· 279 279 osprey_webhook_pubsub_project = config.get_str('PUBSUB_OSPREY_WEBHOOKS_PROJECT_ID', 'osprey-dev') 280 280 osprey_webhook_pubsub_topic = config.get_str('PUBSUB_OSPREY_WEBHOOKS_TOPIC_ID', 'osprey-webhooks') 281 281 webhooks_publisher = PubSubPublisher(osprey_webhook_pubsub_project, osprey_webhook_pubsub_topic) 282 - return EventEffectsOutputSink(engine, analytics_publisher, webhooks_publisher) 282 + return LabelOutputSink(engine, analytics_publisher, webhooks_publisher) 283 283 284 284 285 285 @cli.command()
+1 -1
osprey_worker/src/osprey/worker/lib/osprey_shared/abilities.py
··· 3 3 from urllib.parse import urlencode 4 4 5 5 import requests 6 - from osprey.rpc.labels.v1.service_pb2 import EntityKey 7 6 from osprey.worker.lib.utils.flask_signing import Signer 7 + from osprey.worker.ui_api.osprey.validators.entities import EntityKey 8 8 from pydantic.main import BaseModel 9 9 from requests import ConnectionError, HTTPError, Timeout 10 10 from requests.models import ChunkedEncodingError
+5 -153
osprey_worker/src/osprey/worker/lib/osprey_shared/labels.py
··· 1 1 from dataclasses import dataclass, field 2 2 from datetime import datetime 3 - from enum import Enum, IntEnum 4 - from typing import TYPE_CHECKING, Dict, List, Mapping, Optional, cast 3 + from enum import Enum 4 + from typing import TYPE_CHECKING, Dict, List, Mapping, Optional 5 5 6 - from osprey.rpc.labels.v1 import service_pb2 6 + from osprey.engine.language_types.labels import LabelStatus 7 7 from osprey.worker.lib.osprey_shared.logging import get_logger 8 8 from osprey.worker.lib.utils.request_utils import SessionWithRetries 9 9 from pydantic import BaseModel ··· 28 28 NEUTRAL = 'neutral' 29 29 30 30 31 - class LabelStatus(IntEnum): 32 - ADDED = service_pb2.LabelStatus.ADDED 33 - REMOVED = service_pb2.LabelStatus.REMOVED 34 - MANUALLY_ADDED = service_pb2.LabelStatus.MANUALLY_ADDED 35 - MANUALLY_REMOVED = service_pb2.LabelStatus.MANUALLY_REMOVED 36 - 37 - 38 31 # Pydantic-compatible versions of pb2 types 39 32 @dataclass 40 33 class LabelReason: ··· 44 37 created_at: datetime | None = None 45 38 expires_at: datetime | None = None 46 39 47 - @classmethod 48 - def from_pb2(cls, pb2_reason: service_pb2.LabelReason) -> 'LabelReason': 49 - """Convert from pb2 LabelReason to dataclass.""" 50 - created_at = None 51 - if pb2_reason.HasField('created_at'): 52 - created_at = pb2_reason.created_at.ToDatetime() 53 - 54 - expires_at = None 55 - if pb2_reason.HasField('expires_at'): 56 - expires_at = pb2_reason.expires_at.ToDatetime() 57 - 58 - return cls( 59 - pending=pb2_reason.pending, 60 - description=pb2_reason.description, 61 - features=dict(pb2_reason.features), 62 - created_at=created_at, 63 - expires_at=expires_at, 64 - ) 65 - 66 - def to_pb2(self) -> service_pb2.LabelReason: 67 - """Convert to pb2 LabelReason.""" 68 - pb2_reason = service_pb2.LabelReason( 69 - pending=self.pending, 70 - description=self.description, 71 - features=self.features, 72 - ) 73 - 74 - if self.created_at is not None: 75 - pb2_reason.created_at.FromDatetime(self.created_at) 76 - if self.expires_at is not None: 77 - pb2_reason.expires_at.FromDatetime(self.expires_at) 78 - 79 - return pb2_reason 80 - 81 40 82 41 @dataclass 83 42 class LabelStateInner: 84 43 status: LabelStatus 85 44 reasons: Dict[str, LabelReason] 86 45 87 - @classmethod 88 - def from_pb2(cls, pb2_state: service_pb2.LabelStateInner) -> 'LabelStateInner': 89 - """Convert from pb2 LabelStateInner to dataclass.""" 90 - return cls( 91 - status=LabelStatus(pb2_state.status), 92 - reasons={key: LabelReason.from_pb2(pb2_state.reasons[key]) for key in pb2_state.reasons}, 93 - ) 94 - 95 - def to_pb2(self) -> service_pb2.LabelStateInner: 96 - """Convert to pb2 LabelStateInner.""" 97 - pb2_state = service_pb2.LabelStateInner(status=self.status.value) 98 - for key, reason in self.reasons.items(): 99 - pb2_state.reasons[key].CopyFrom(reason.to_pb2()) 100 - return pb2_state 101 - 102 46 103 47 @dataclass 104 48 class LabelState: ··· 106 50 reasons: Dict[str, LabelReason] 107 51 previous_states: List[LabelStateInner] = field(default_factory=list) 108 52 109 - @classmethod 110 - def from_pb2(cls, pb2_state: service_pb2.LabelState) -> 'LabelState': 111 - """Convert from pb2 LabelState to dataclass.""" 112 - return cls( 113 - status=LabelStatus(pb2_state.status), 114 - reasons={key: LabelReason.from_pb2(pb2_state.reasons[key]) for key in pb2_state.reasons}, 115 - previous_states=[LabelStateInner.from_pb2(state) for state in pb2_state.previous_states], 116 - ) 117 - 118 - def to_pb2(self) -> service_pb2.LabelState: 119 - """Convert to pb2 LabelState.""" 120 - pb2_state = service_pb2.LabelState(status=self.status.value) 121 - for key, reason in self.reasons.items(): 122 - pb2_state.reasons[key].CopyFrom(reason.to_pb2()) 123 - for prev_state in self.previous_states: 124 - pb2_state.previous_states.append(prev_state.to_pb2()) 125 - return pb2_state 126 - 127 53 128 54 @dataclass 129 55 class Labels: 130 56 labels: Dict[str, LabelState] = field(default_factory=dict) 131 57 expires_at: Optional[datetime] = None 132 58 133 - @classmethod 134 - def from_pb2(cls, pb2_labels: service_pb2.Labels) -> 'Labels': 135 - """Convert from pb2 Labels to dataclass.""" 136 - expires_at = None 137 - if pb2_labels.HasField('expires_at'): 138 - expires_at = pb2_labels.expires_at.ToDatetime() 139 - 140 - return cls( 141 - labels={key: LabelState.from_pb2(pb2_labels.labels[key]) for key in pb2_labels.labels}, 142 - expires_at=expires_at, 143 - ) 144 - 145 - def to_pb2(self) -> service_pb2.Labels: 146 - """Convert to pb2 Labels.""" 147 - pb2_labels = service_pb2.Labels() 148 - for key, label_state in self.labels.items(): 149 - pb2_labels.labels[key].CopyFrom(label_state.to_pb2()) 150 - if self.expires_at is not None: 151 - pb2_labels.expires_at.FromDatetime(self.expires_at) 152 - return pb2_labels 153 - 154 59 155 60 class LabelsAndConnotationsResponse(BaseModel): 156 61 labels: Labels ··· 179 84 class EntityMutation: 180 85 label_name: str = '' 181 86 reason_name: str = '' 182 - status: int = 0 87 + status: LabelStatus = LabelStatus.ADDED 183 88 pending: bool = False 184 89 description: str = '' 185 - features: Dict[str, 'str'] = field(default_factory=dict) 90 + features: Dict[str, str] = field(default_factory=dict) 186 91 expires_at: Optional[datetime] = None 187 92 188 - @classmethod 189 - def from_pb2(cls, pb2_mutation: service_pb2.EntityMutation) -> 'EntityMutation': 190 - """Convert from pb2 EntityMutation to dataclass.""" 191 - expires_at = None 192 - if pb2_mutation.HasField('expires_at'): 193 - expires_at = pb2_mutation.expires_at.ToDatetime() 194 - 195 - return cls( 196 - label_name=pb2_mutation.label_name, 197 - reason_name=pb2_mutation.reason_name, 198 - status=pb2_mutation.status, 199 - pending=pb2_mutation.pending, 200 - description=pb2_mutation.description, 201 - features=dict(pb2_mutation.features), 202 - expires_at=expires_at, 203 - ) 204 - 205 - def to_pb2(self) -> service_pb2.EntityMutation: 206 - """Convert to pb2 EntityMutation.""" 207 - pb2_mutation = service_pb2.EntityMutation( 208 - label_name=self.label_name, 209 - reason_name=self.reason_name, 210 - status=cast('service_pb2.LabelStatus.ValueType', self.status), 211 - pending=self.pending, 212 - description=self.description, 213 - features=self.features, 214 - ) 215 - 216 - if self.expires_at is not None: 217 - pb2_mutation.expires_at.FromDatetime(self.expires_at) 218 - 219 - return pb2_mutation 220 - 221 93 222 94 @dataclass 223 95 class ApplyEntityMutationReply: ··· 225 97 removed: List[str] = field(default_factory=list) 226 98 unchanged: List[str] = field(default_factory=list) 227 99 dropped: List[EntityMutation] = field(default_factory=list) 228 - 229 - @classmethod 230 - def from_pb2(cls, pb2_reply: service_pb2.ApplyEntityMutationReply) -> 'ApplyEntityMutationReply': 231 - """Convert from pb2 ApplyEntityMutationReply to dataclass.""" 232 - return cls( 233 - added=list(pb2_reply.added), 234 - removed=list(pb2_reply.removed), 235 - unchanged=list(pb2_reply.unchanged), 236 - dropped=[EntityMutation.from_pb2(mutation) for mutation in pb2_reply.dropped], 237 - ) 238 - 239 - def to_pb2(self) -> service_pb2.ApplyEntityMutationReply: 240 - """Convert to pb2 ApplyEntityMutationReply.""" 241 - pb2_reply = service_pb2.ApplyEntityMutationReply() 242 - pb2_reply.added.extend(self.added) 243 - pb2_reply.removed.extend(self.removed) 244 - pb2_reply.unchanged.extend(self.unchanged) 245 - for mutation in self.dropped: 246 - pb2_reply.dropped.append(mutation.to_pb2()) 247 - return pb2_reply 248 100 249 101 250 102 class EntityLabelDisagreeResponse(BaseModel):
+1 -2
osprey_worker/src/osprey/worker/lib/storage/bulk_label_task.py
··· 6 6 from random import random 7 7 from typing import Any, Dict, Iterator, List, Optional 8 8 9 - from osprey.rpc.labels.v1 import service_pb2 10 9 from osprey.worker.lib.osprey_shared.labels import LabelStatus 11 10 from osprey.worker.lib.storage.types import Enum 12 11 from sqlalchemy import BigInteger, Boolean, Column, DateTime, Integer, Text, and_, func, or_ ··· 63 62 initiated_by: str, 64 63 label_name: str, 65 64 label_reason: str, 66 - label_status: 'service_pb2.LabelStatus.ValueType', # NOTE: this could use regular LabelStatus, would just take a bit of refactoring 65 + label_status: LabelStatus, 67 66 label_expiry: Optional[datetime], 68 67 excluded_entities: List[str], 69 68 expected_total_entities_to_label: int,
+16 -82
osprey_worker/src/osprey/worker/lib/storage/labels.py
··· 1 - from abc import ABC 1 + from abc import ABC, abstractmethod 2 2 from datetime import timedelta 3 - from typing import Any, List, Optional, Sequence, Union 3 + from typing import Any, List, Optional, Sequence 4 4 5 5 from osprey.engine.executor.external_service_utils import ExternalService 6 6 from osprey.engine.language_types.entities import EntityT 7 - from osprey.rpc.labels.v1 import service_pb2 as pb2 8 - from osprey.rpc.labels.v1.service_pb2 import LabelStatus 9 - from osprey.rpc.labels.v1.service_pb2_grpc import LabelServiceStub 10 - from osprey.worker.lib.pigeon.client import RoutedClient, RoutingType 11 - from osprey.worker.lib.utils.grpc import DATA_SERVICES_RETRY_POLICY 12 - from osprey.worker.lib.utils.grpc_client_pool import GrpcClientPool 13 - from result import Err, Ok, Result 14 - 15 - _grpc_client_pool = GrpcClientPool( 16 - # pls do profiling if you wish to modify this size! 17 - size=1, 18 - func=lambda seq: RoutedClient( 19 - 'osprey_labels', 20 - stub_cls=LabelServiceStub, 21 - request_field='routing_key', 22 - secondaries=2, 23 - routing_type=RoutingType.SCALAR, 24 - read_timeout=0.6, 25 - acceptable_duration_ms=40, 26 - grpc_options={'grpc.http2.initial_sequence_number': seq}, 27 - ), 28 - ) 29 - 30 - 31 - def get_label_routing_key(entity_key: Union[pb2.EntityKey, EntityT[Any]]) -> str: 32 - if isinstance(entity_key, pb2.EntityKey): 33 - return entity_key.type + '/' + entity_key.id 34 - return entity_key.type + '/' + str(entity_key.id) 35 - 36 - 37 - def get_for_entity(entity_key: pb2.EntityKey) -> pb2.Labels: 38 - request = pb2.GetEntityRequest(routing_key=get_label_routing_key(entity_key), key=entity_key) 39 - response: pb2.GetEntityResponse = _grpc_client_pool.get().GetEntity( 40 - request, retry_policy=DATA_SERVICES_RETRY_POLICY 41 - ) 42 - return response.entity.labels 43 - 44 - 45 - def batch_get_for_entity(entity_keys: Sequence[pb2.EntityKey]) -> Sequence[Result[pb2.Labels, Exception]]: 46 - request = pb2.GetEntityBatchRequest(routing_key=get_label_routing_key(entity_keys[0]), keys=list(entity_keys)) 47 - response: pb2.GetEntityBatchResponse = _grpc_client_pool.get().GetEntityBatch( 48 - request, retry_policy=DATA_SERVICES_RETRY_POLICY 49 - ) 50 - return [ 51 - Ok(response.entity.labels) if response.HasField('entity') else Err(KeyError(entity_keys[i])) 52 - for i, response in enumerate(response.responses) 53 - ] 7 + from osprey.worker.lib.osprey_shared.labels import ApplyEntityMutationReply, EntityMutation, Labels 8 + from result import Result 54 9 55 10 56 - def apply_entity_mutation( 57 - entity_key: pb2.EntityKey, mutations: List[pb2.EntityMutation] 58 - ) -> pb2.ApplyEntityMutationReply: 59 - request = pb2.ApplyEntityMutationRequest( 60 - routing_key=get_label_routing_key(entity_key), key=entity_key, mutations=mutations 61 - ) 62 - response: pb2.ApplyEntityMutationReply = _grpc_client_pool.get().ApplyEntityMutation( 63 - request, retry_policy=DATA_SERVICES_RETRY_POLICY 64 - ) 65 - return response 66 - 67 - 68 - def get_effective_label_status(label_status: LabelStatus.ValueType) -> LabelStatus.ValueType: 69 - """ 70 - Returns the effective status of the label, which is what the upstreams that are observing label 71 - status changes will see. Which is to say, the upstreams will currently not see if the label status was 72 - manually added or manually removed, just that it was added or removed. 73 - """ 74 - 75 - if label_status in (pb2.LabelStatus.ADDED, pb2.LabelStatus.MANUALLY_ADDED): 76 - return pb2.LabelStatus.ADDED 77 - elif label_status in (pb2.LabelStatus.REMOVED, pb2.LabelStatus.MANUALLY_REMOVED): 78 - return pb2.LabelStatus.REMOVED 79 - 80 - raise ValueError(f'Unexpected LabelStatus: {label_status!r}') 81 - 82 - 83 - class LabelProvider(ExternalService[EntityT[Any], pb2.Labels], ABC): 11 + class LabelProvider(ExternalService[EntityT[Any], Labels], ABC): 84 12 def cache_ttl(self) -> Optional[timedelta]: 85 13 return timedelta(minutes=5) 86 14 15 + @abstractmethod 16 + def get_from_service(self, key: EntityT[Any]) -> Labels: 17 + raise NotImplementedError() 87 18 88 - class HasLabelProvider(LabelProvider): 89 - def get_from_service(self, key: EntityT[Any]) -> pb2.Labels: 90 - return get_for_entity(pb2.EntityKey(type=key.type, id=str(key.id))) 19 + @abstractmethod 20 + def batch_get_from_service(self, keys: Sequence[EntityT[Any]]) -> Sequence[Result[Labels, Exception]]: 21 + raise NotImplementedError() 91 22 92 - def batch_get_from_service(self, keys: Sequence[EntityT[Any]]) -> Sequence[Result[pb2.Labels, Exception]]: 93 - return batch_get_for_entity([pb2.EntityKey(type=key.type, id=str(key.id)) for key in keys]) 23 + @abstractmethod 24 + def apply_entity_mutation( 25 + self, entity_key: EntityT[Any], mutations: List[EntityMutation] 26 + ) -> ApplyEntityMutationReply: 27 + raise NotImplementedError()
+22
osprey_worker/src/osprey/worker/lib/storage/local_label_provider.py
··· 1 + from typing import Any, Dict, List, Sequence 2 + 3 + from osprey.engine.language_types.entities import EntityT 4 + from osprey.worker.lib.osprey_shared.labels import ApplyEntityMutationReply, EntityMutation, Labels 5 + from osprey.worker.lib.storage.labels import LabelProvider 6 + from result import Result 7 + 8 + 9 + class LocalLabelProvider(LabelProvider): 10 + def __init__(self): 11 + self._labels: Dict[str, Labels] = {} 12 + 13 + def batch_get_from_service(self, keys: Sequence[EntityT[Any]]) -> Sequence[Result[Labels, Exception]]: 14 + raise NotImplementedError() 15 + 16 + def apply_entity_mutation( 17 + self, entity_key: EntityT[Any], mutations: List[EntityMutation] 18 + ) -> ApplyEntityMutationReply: 19 + raise NotImplementedError() 20 + 21 + def get_from_service(self, key: EntityT[Any]) -> Labels: 22 + raise NotImplementedError()
+16 -14
osprey_worker/src/osprey/worker/sinks/sink/bulk_label_sink.py
··· 4 4 5 5 import sentry_sdk 6 6 from osprey.engine.executor.execution_context import ExtendedEntityMutation 7 - from osprey.engine.utils.proto_utils import optional_datetime_to_timestamp 8 - from osprey.rpc.labels.v1.service_pb2 import EntityKey, EntityMutation, LabelStatus 7 + from osprey.engine.language_types.labels import LabelStatus 9 8 from osprey.worker.lib.bulk_label import TaskStatus 10 9 from osprey.worker.lib.discovery.exceptions import ServiceUnavailable 11 10 from osprey.worker.lib.instruments import metrics ··· 14 13 from osprey.worker.lib.pigeon.exceptions import RPCException 15 14 from osprey.worker.lib.publisher import BasePublisher 16 15 from osprey.worker.lib.storage.bulk_label_task import BASE_DELAY_SECONDS, MAX_ATTEMPTS, BulkLabelTask 17 - from osprey.worker.lib.storage.labels import get_for_entity 18 16 from osprey.worker.sinks.sink.input_stream import BaseInputStream 19 - from osprey.worker.sinks.sink.output_sink import EventEffectsOutputSink 17 + from osprey.worker.sinks.sink.output_sink import LabelOutputSink 20 18 from osprey.worker.sinks.sink.output_sink_utils.constants import MutationEventType 21 19 from osprey.worker.sinks.sink.output_sink_utils.models import OspreyBulkJobAnalyticsEvent 22 20 from osprey.worker.ui_api.osprey.lib.druid import PeriodData, TopNDruidQuery, TopNPoPResponse 23 21 from tenacity import RetryCallState, retry, retry_if_exception_type, stop_after_attempt, wait_exponential 24 22 23 + from ...adaptor.plugin_manager import bootstrap_label_provider 24 + from ...lib.osprey_shared.labels import EntityMutation 25 + from ...lib.storage.labels import LabelProvider 26 + from ...ui_api.osprey.validators.entities import EntityKey 25 27 from .base_sink import BaseSink 26 28 27 29 logger = get_logger() ··· 67 69 def __init__( 68 70 self, 69 71 input_stream: BaseInputStream[BulkLabelTask], 70 - event_effects_output_sink: EventEffectsOutputSink, 72 + label_provider: LabelProvider, 71 73 engine: OspreyEngine, 72 74 analytics_publisher: BasePublisher, 73 75 send_status_webhook: bool = True, 74 76 ): 75 77 self._input_stream = input_stream 76 - self._event_effects_output_sink = event_effects_output_sink 78 + self._label_provider = label_provider 79 + self._label_output_sink = LabelOutputSink(self._label_provider) 77 80 self._engine = engine 78 81 self._metric_tags = [f'sink:{self.__class__.__name__}'] 79 82 self._analytics_publisher = analytics_publisher ··· 364 367 assert isinstance(task.dimension, str) 365 368 assert isinstance(task.excluded_entities, Iterable) 366 369 367 - self._event_effects_output_sink.apply_label_mutations_pb2( 370 + self._label_output_sink.apply_label_mutations( 368 371 mutation_event_type=MutationEventType.BULK_ACTION, 369 372 mutation_event_id=str(task.id), 370 373 entity_key=entity_key, ··· 373 376 mutation=EntityMutation( 374 377 label_name=task.label_name, 375 378 reason_name=BULK_LABEL_REASON, 376 - expires_at=optional_datetime_to_timestamp(task.label_expiry), 379 + expires_at=task.label_expiry, 377 380 status=task.label_status, # type: ignore 378 381 description='Bulk label (id={BulkLabelTaskId}) by {AdminEmail}: {Reason}', 379 382 features={ ··· 430 433 rows_rolled_back = 0 431 434 432 435 feature_name_to_entity_type_mapping = engine.get_feature_name_to_entity_type_mapping() 433 - event_effects_output_sink = EventEffectsOutputSink( 434 - engine=engine, analytics_publisher=analytics_publisher, webhooks_publisher=webhooks_publisher 435 - ) 436 + label_provider = bootstrap_label_provider() 437 + label_output_sink = LabelOutputSink(label_provider) 436 438 feature_name = task.dimension 437 439 entity_type = feature_name_to_entity_type_mapping[feature_name] 438 440 ··· 458 460 rows_excluded += 1 459 461 continue 460 462 461 - labels = get_for_entity(entity_key) 463 + labels = label_provider.get_from_service(entity_key) 462 464 463 465 # No label anymore, nothing to do. 464 466 label_state = labels.labels.get(task.label_name) ··· 478 480 continue 479 481 480 482 # Apply the inverse effect of the rollback. 481 - event_effects_output_sink.apply_label_mutations_pb2( 483 + label_output_sink.apply_label_mutations( 482 484 mutation_event_type=MutationEventType.BULK_ACTION, 483 485 mutation_event_id=str(task.id), 484 486 entity_key=entity_key, ··· 488 490 label_name=task.label_name, 489 491 reason_name='_BulkLabelRollback', 490 492 status=LabelStatus.MANUALLY_REMOVED, 491 - expires_at=optional_datetime_to_timestamp(datetime.now() + timedelta(hours=2)), 493 + expires_at=datetime.now() + timedelta(hours=2), 492 494 description=( 493 495 'Bulk label rollback of (id={BulkLabelTaskId}) ' 494 496 '(initial reason: {Reason}, initially initiated by: {AdminEmail})'
+14 -256
osprey_worker/src/osprey/worker/sinks/sink/output_sink.py
··· 1 1 import abc 2 2 from collections import defaultdict 3 - from datetime import datetime, timedelta 3 + from datetime import datetime 4 4 from typing import Any, DefaultDict, Dict, List, Mapping, Optional, Sequence 5 5 6 6 import gevent 7 7 import sentry_sdk 8 - import sqlalchemy 9 8 from osprey.engine.executor.execution_context import ( 10 9 ExecutionResult, 11 10 ExtendedEntityMutation, 12 11 ) 13 12 from osprey.engine.language_types.entities import EntityT 14 13 from osprey.engine.language_types.labels import LabelEffect 15 - from osprey.engine.stdlib.configs.analytics_config import AnalyticsConfig 16 - from osprey.engine.stdlib.configs.feature_flags_config import ( 17 - WEBHOOKS_USE_PUBSUB, 18 - FeatureFlagsConfig, 19 - ) 20 - from osprey.engine.stdlib.configs.webhook_config import WebhookConfig 21 14 from osprey.engine.stdlib.udfs.rules import RuleT 22 - from osprey.engine.utils.proto_utils import optional_datetime_to_timestamp 23 - from osprey.rpc.labels.v1.service_pb2 import ApplyEntityMutationReply, EntityKey, EntityMutation 24 - from osprey.rpc.labels.v1.service_pb2 import LabelStatus as LabelStatusPb2 25 15 from osprey.worker.lib.ddtrace_utils import trace 26 16 from osprey.worker.lib.instruments import metrics 27 - from osprey.worker.lib.osprey_engine import OspreyEngine 28 - from osprey.worker.lib.osprey_shared.labels import LabelStatus 17 + from osprey.worker.lib.osprey_shared.labels import ApplyEntityMutationReply, EntityMutation 29 18 from osprey.worker.lib.osprey_shared.logging import DynamicLogSampler, get_logger 30 - from osprey.worker.lib.publisher import BasePublisher 31 - from osprey.worker.lib.storage import labels 32 - from osprey.worker.lib.storage.entity_label_webhook import EntityLabelWebhook as StoredEntityLabelWebhook 33 - from osprey.worker.lib.storage.postgres import scoped_session 34 - from osprey.worker.lib.webhooks import WebhookStatus 19 + from osprey.worker.lib.storage.labels import LabelProvider 35 20 from osprey.worker.sinks.sink.output_sink_utils.constants import MutationEventType 36 - from osprey.worker.sinks.sink.output_sink_utils.helpers import get_user_id 37 - from osprey.worker.sinks.sink.output_sink_utils.models import ( 38 - OspreyEntityLabelWebhook, 39 - OspreyLabelMutationAnalyticsEvent, 40 - ) 21 + from osprey.worker.ui_api.osprey.validators.entities import EntityKey 41 22 from tenacity import retry, stop_after_attempt, wait_exponential 42 23 43 24 logger = get_logger() ··· 131 112 status=label_effect.status, 132 113 description=rule.description, 133 114 features=rule.features, 134 - expires_at=optional_datetime_to_timestamp(expires_at), 115 + expires_at=expires_at, 135 116 ), 136 117 delay_action_by=label_effect.delay_action_by, 137 118 ) ··· 173 154 return dict(effects) 174 155 175 156 176 - class EventEffectsOutputSink(BaseOutputSink): 177 - """An output sink that will send event effects to the label service, and also, enqueue any applied or removed label 178 - state mutations that there is an interested webhook listener. 179 - """ 157 + class LabelOutputSink(BaseOutputSink): 158 + """An output sink that will send event effects to the label service.""" 180 159 181 - def __init__( 182 - self, engine: OspreyEngine, analytics_publisher: BasePublisher, webhooks_publisher: BasePublisher 183 - ) -> None: 184 - self._engine = engine 185 - self._analytics_publisher = analytics_publisher 186 - self._webhooks_publisher = webhooks_publisher 160 + def __init__(self, label_provider: LabelProvider) -> None: 161 + self._label_provider = label_provider 187 162 188 163 def will_do_work(self, result: ExecutionResult) -> bool: 189 164 return len(_get_label_effects_from_result(result)) > 0 ··· 200 175 mutation_event_action_name=result.action.action_name, 201 176 ) 202 177 203 - @staticmethod 204 178 @retry(wait=wait_exponential(min=0.5, max=5), stop=stop_after_attempt(3)) 205 179 def apply_entity_mutation_with_retry( 206 - entity_key: EntityKey, mutations: Sequence[ExtendedEntityMutation] 207 - ) -> ApplyEntityMutationReply: 208 - return labels.apply_entity_mutation( 209 - entity_key=entity_key, mutations=[mutation.mutation for mutation in mutations] 210 - ) 211 - 212 - def apply_label_mutations_pb2( 213 - self, 214 - mutation_event_type: MutationEventType, 215 - mutation_event_id: str, 216 - entity_key: EntityKey, 217 - mutations: Sequence[ExtendedEntityMutation], 218 - features: Optional[Dict[str, Any]] = None, 219 - mutation_event_action_name: str = '', 180 + self, entity_key: EntityKey, mutations: Sequence[ExtendedEntityMutation] 220 181 ) -> ApplyEntityMutationReply: 221 - return self.apply_label_mutations( 222 - mutation_event_type=mutation_event_type, 223 - mutation_event_id=mutation_event_id, 224 - entity_key=entity_key, 225 - mutations=mutations, 226 - features=features, 227 - mutation_event_action_name=mutation_event_action_name, 182 + return self._label_provider.apply_entity_mutation( 183 + entity_key=entity_key, mutations=[extended_mutation.mutation for extended_mutation in mutations] 228 184 ) 229 185 230 186 def apply_label_mutations( ··· 245 201 unchanged=[mutation.mutation.label_name for mutation in mutations], 246 202 ) 247 203 248 - if not features: 249 - features = {} 250 - 251 204 try: 252 - result: ApplyEntityMutationReply = EventEffectsOutputSink.apply_entity_mutation_with_retry( 253 - entity_key, mutations 254 - ) 205 + result: ApplyEntityMutationReply = self.apply_entity_mutation_with_retry(entity_key, mutations) 255 206 metrics.increment('output_sink.apply_entity_mutation', tags=['status:success']) 256 207 except Exception as e: 257 208 logger.error( ··· 261 212 metrics.increment('output_sink.apply_entity_mutation', tags=['status:failure']) 262 213 raise e 263 214 264 - added = set(result.added) 265 - removed = set(result.removed) 266 - updated_labels = added | removed 267 - 268 - if not updated_labels: 269 - metrics.increment('output_sink.no_updated_labels') 270 - return result 271 - 272 - # These analytics and metrics placed in this sink because we need to know when label states changes. 273 - self._send_label_mutation_analytics_event( 274 - mutation_event_type, 275 - mutation_event_id, 276 - mutation_event_action_name or mutation_event_type.value, 277 - entity_key, 278 - result, 279 - mutations, 280 - ) 281 - self._send_monitored_rules_metrics( 282 - mutations, action_name=mutation_event_action_name or mutation_event_type.value 283 - ) 284 - 285 - webhook_config = self._engine.get_config_subkey(WebhookConfig) 286 - updated_labels_with_downstream = [ 287 - label_name for label_name in updated_labels if label_name in webhook_config.outgoing_labels 288 - ] 289 - 290 - if not updated_labels_with_downstream: 291 - metrics.increment('output_sink.no_updated_labels_with_downstream') 292 - return result 293 - 294 - delay_action_by_per_label = self._get_action_delay_by_per_label(mutations, updated_labels_with_downstream) 295 - 296 - # if the pgbouncer pod is restarted, the connection pool will be cleared and the session will be invalid 297 - # we need to retry the transaction in this case 298 - @retry( 299 - wait=wait_exponential(min=0.5, max=5), 300 - stop=stop_after_attempt(3), 301 - ) 302 - def run_transaction(_features: Dict[str, Any]) -> None: 303 - with scoped_session(commit=True) as session: 304 - for label_name in updated_labels_with_downstream: 305 - feature_flags = self._engine.get_config_subkey(FeatureFlagsConfig) 306 - 307 - label_status = LabelStatus.ADDED if label_name in added else LabelStatus.REMOVED 308 - metrics.increment('labels', tags=[f'label:{label_name}', f'status:{label_status.name}']) 309 - 310 - filtered_features = { 311 - feature_name: _features[feature_name] 312 - for feature_name in webhook_config.outgoing_labels_features_to_include.get(label_name, []) 313 - if feature_name in _features 314 - } 315 - 316 - delay_action_by = delay_action_by_per_label[label_name] 317 - 318 - if delay_action_by is None and feature_flags.is_percentage_enabled(WEBHOOKS_USE_PUBSUB): 319 - # Pubsub path 320 - pubsub_webhook = OspreyEntityLabelWebhook( 321 - entity_type=entity_key.type, 322 - entity_id=entity_key.id, 323 - label_name=label_name, 324 - label_status=label_status, 325 - webhook_name=label_name, 326 - features=filtered_features, 327 - created_at=datetime.now(), 328 - ) 329 - 330 - self._webhooks_publisher.publish(pubsub_webhook) 331 - metrics.increment('webhook_pubsub_writes', tags=['status:success']) 332 - else: 333 - # Traditional Postgres path 334 - postgres_webhook = EventEffectsOutputSink._create_webhook( 335 - entity_key, label_name, label_status, filtered_features, delay_action_by 336 - ) 337 - session.add(postgres_webhook) 338 - 339 - try: 340 - # lol, this half step is necessary to get the mypy linters passing or else it will complain about 341 - # subcripting on a NoneType. Therefore the argument to run_transaction is not an optional in order to pass. 342 - run_transaction(features) 343 - # database operation has been committed, increment success metric 344 - metrics.increment('webhook_queue_postgres_writes', tags=['status:success']) 345 - except Exception: 346 - # increment failure metric 347 - metrics.increment('webhook_queue_postgres_writes', tags=['status:failure']) 348 - logger.error( 349 - f'Failed to write webhooks to database for labels: {updated_labels_with_downstream} ' 350 - f'on entity of type: {entity_key.type} with id: {entity_key.id}', 351 - exc_info=True, 352 - ) 353 - # re-raise the exception so that outer function (multi-output sink) can handle it 354 - raise 355 - 356 215 return result 357 216 358 - def _send_label_mutation_analytics_event( 359 - self, 360 - mutation_event_type: MutationEventType, 361 - mutation_event_id: str, 362 - mutation_event_action_name: str, 363 - entity_key: EntityKey, 364 - label_mutation_result: ApplyEntityMutationReply, 365 - mutations: Sequence[ExtendedEntityMutation], 366 - ) -> None: 367 - analytics_properties = OspreyLabelMutationAnalyticsEvent( 368 - mutation_event_type=mutation_event_type, 369 - mutation_event_id=mutation_event_id, 370 - mutation_event_action_name=mutation_event_action_name, 371 - user_id=get_user_id(entity_key.id, entity_key.type), 372 - entity_id_v2=entity_key.id, 373 - entity_type=entity_key.type, 374 - labels=[], 375 - label_statuses=[], 376 - label_reasons=[], 377 - ) 378 - 379 - config = self._engine.get_config_subkey(AnalyticsConfig) 380 - filtered_labels_for_analytics = config.filtered_labels 381 - for mutation in mutations: 382 - label_name = mutation.mutation.label_name 383 - if ( 384 - label_name not in (set(label_mutation_result.added) | set(label_mutation_result.removed)) 385 - or label_name in filtered_labels_for_analytics 386 - ): 387 - continue 388 - 389 - # it is possible to have no reasons, usually due to bad test state, this gives a sane default 390 - reason = mutation.mutation.reason_name or 'unknown' 391 - analytics_properties.labels.append(label_name) 392 - analytics_properties.label_statuses.append('LabelStatus.' + LabelStatusPb2.Name(mutation.mutation.status)) 393 - analytics_properties.label_reasons.append(reason) 394 - 395 - self._analytics_publisher.publish(analytics_properties) 396 - 397 - def _get_action_delay_by_per_label( 398 - self, 399 - mutations: Sequence[ExtendedEntityMutation], 400 - updated_labels_with_downstream: List[str], 401 - ) -> Dict[str, Optional[timedelta]]: 402 - # Build mapping from label to action delay 403 - delay_action_by_per_label: Dict[str, Optional[timedelta]] = {} 404 - for mutation in mutations: 405 - label_name = mutation.mutation.label_name 406 - if label_name in updated_labels_with_downstream: 407 - if label_name not in delay_action_by_per_label: 408 - new_value = mutation.delay_action_by 409 - else: 410 - # Take the minimum, where None (no delay) takes precedence 411 - existing = delay_action_by_per_label[label_name] 412 - if existing is None or mutation.delay_action_by is None: 413 - new_value = None 414 - else: 415 - new_value = min(existing, mutation.delay_action_by) 416 - delay_action_by_per_label[label_name] = new_value 417 - return delay_action_by_per_label 418 - 419 - @classmethod 420 - def _create_webhook( 421 - cls, 422 - entity_key: EntityKey, 423 - label_name: str, 424 - label_status: LabelStatus, 425 - features: Dict[str, Any], 426 - delay_action_by: Optional[timedelta], 427 - ) -> StoredEntityLabelWebhook: 428 - webhook = StoredEntityLabelWebhook() 429 - webhook.entity_id = entity_key.id 430 - webhook.entity_type = entity_key.type 431 - # The webhook name is currently the label name, which means there is no specifier to only listen to 432 - # entity effects by entity type. Just by label name. 433 - webhook.webhook_name = label_name 434 - webhook.label_name = label_name 435 - webhook.label_status = LabelStatus(labels.get_effective_label_status(label_status.value)) 436 - webhook.features = features 437 - webhook.claim_until = webhook.created_at = webhook.updated_at = sqlalchemy.func.now() 438 - webhook.status = WebhookStatus.QUEUED 439 - if delay_action_by is not None: 440 - # Use the claim to prevent sending this webhook until the allotted time. 441 - webhook.claim_until = sqlalchemy.func.now() + delay_action_by 442 - return webhook 443 - 444 - def _send_monitored_rules_metrics(self, mutations: Sequence[ExtendedEntityMutation], action_name: str) -> None: 445 - analytics_config = self._engine.get_config_subkey(AnalyticsConfig) 446 - for mutation in mutations: 447 - label_name = mutation.mutation.label_name 448 - if label_name in analytics_config.monitored_labels: 449 - metrics.increment( 450 - 'monitored_rules', 451 - tags=[ 452 - f'rule:{mutation.mutation.reason_name}', 453 - f'label:{label_name}', 454 - f'status:{mutation.mutation.status}', 455 - f'action:{action_name}', 456 - ], 457 - ) 458 - 459 217 def stop(self) -> None: 460 - self._analytics_publisher.stop() 218 + pass
+1 -17
osprey_worker/src/osprey/worker/ui_api/osprey/singletons.py
··· 1 1 from osprey.worker.lib.publisher import PubSubPublisher 2 2 from osprey.worker.lib.singleton import Singleton 3 - from osprey.worker.lib.singletons import CONFIG, ENGINE 4 - from osprey.worker.sinks.sink.output_sink import EventEffectsOutputSink 3 + from osprey.worker.lib.singletons import CONFIG 5 4 6 5 from .lib.druid_client_holder import DruidClientHolder 7 6 8 7 DRUID: Singleton[DruidClientHolder] = Singleton(DruidClientHolder) 9 - 10 - config = CONFIG.instance() 11 - EVENT_EFFECT_SINK: Singleton[EventEffectsOutputSink] = Singleton( 12 - lambda: EventEffectsOutputSink( 13 - engine=ENGINE.instance(), 14 - analytics_publisher=PubSubPublisher( 15 - config.get_str('PUBSUB_DATA_PROJECT_ID', 'osprey-dev'), 16 - config.get_str('PUBSUB_ANALYTICS_EVENT_TOPIC_ID', 'osprey-analytics'), 17 - ), 18 - webhooks_publisher=PubSubPublisher( 19 - config.get_str('PUBSUB_OSPREY_WEBHOOKS_PROJECT_ID', 'osprey-dev'), 20 - config.get_str('PUBSUB_OSPREY_WEBHOOKS_TOPIC_ID', 'osprey-webhooks'), 21 - ), 22 - ) 23 - ) 24 8 25 9 26 10 def _init_analytics_publisher() -> PubSubPublisher:
+4 -14
osprey_worker/src/osprey/worker/ui_api/osprey/validators/entities.py
··· 3 3 from typing import List, Optional, Type 4 4 5 5 from flask import Request 6 - from osprey.rpc.labels.v1 import service_pb2 6 + from osprey.engine.language_types.entities import EntityT 7 7 from osprey.worker.lib.osprey_shared.labels import LabelStatus 8 8 from osprey.worker.ui_api.osprey.lib.druid import TimeseriesDruidQuery 9 9 from osprey.worker.ui_api.osprey.lib.marshal import FlaskRequestMarshaller, T 10 10 from pydantic import BaseModel 11 11 12 12 13 - # This type exists in addition to the pb2 one because pb2 EntityKey cannot be 14 - # used in pydantic models 15 - @dataclass 16 - class EntityKey: 17 - id: str 18 - type: str 19 - 20 - @classmethod 21 - def from_proto(cls, proto: service_pb2.EntityKey): 22 - return cls(id=proto.id, type=proto.type) 23 - 24 - def to_proto(self) -> service_pb2.EntityKey: 25 - return service_pb2.EntityKey(id=self.id, type=self.type) 13 + @dataclass(frozen=True) 14 + class EntityKey(EntityT[str]): 15 + pass 26 16 27 17 28 18 class EntityMarshaller(FlaskRequestMarshaller):
-171
proto/osprey/rpc/labels/v1/service.proto
··· 1 - syntax = "proto3"; 2 - 3 - package osprey.rpc.labels.v1; 4 - 5 - import "osprey/rpc/pigeon/v1/options.proto"; 6 - import "google/protobuf/timestamp.proto"; 7 - 8 - message LabelReason { 9 - bool pending = 1; 10 - string description = 2; 11 - map<string, string> features = 3; 12 - google.protobuf.Timestamp created_at = 4; 13 - google.protobuf.Timestamp expires_at = 5; 14 - } 15 - 16 - enum LabelStatus { 17 - ADDED = 0; 18 - REMOVED = 1; 19 - MANUALLY_ADDED = 2; 20 - MANUALLY_REMOVED = 3; 21 - } 22 - 23 - message LabelStateInner { 24 - LabelStatus status = 1; 25 - map<string, LabelReason> reasons = 2; 26 - } 27 - 28 - message LabelState { 29 - LabelStatus status = 1; 30 - map<string, LabelReason> reasons = 2; 31 - repeated LabelStateInner previous_states = 3; 32 - } 33 - 34 - message Labels { 35 - map<string, LabelState> labels = 1; 36 - google.protobuf.Timestamp expires_at = 2; 37 - } 38 - 39 - message EntityKey { 40 - string type = 1; 41 - string id = 2; 42 - } 43 - 44 - message Entity { 45 - EntityKey key = 2; 46 - Labels labels = 1; 47 - } 48 - 49 - message TakeDataRequest { 50 - string key = 1; 51 - } 52 - 53 - message Data { 54 - bytes bytes = 1; 55 - } 56 - 57 - message TakeDataResponse { 58 - Data data = 2; 59 - } 60 - 61 - service LabelService { 62 - option (osprey.rpc.pigeon.v1.default_routing_config) = { 63 - type: ROUTING_TYPE_SCALAR 64 - }; 65 - // -- Internal take_data API 66 - rpc TakeData(TakeDataRequest) returns (TakeDataResponse); 67 - // -- External APIs 68 - // -- Label Read/Mutation 69 - rpc GetEntity(GetEntityRequest) returns (GetEntityResponse); 70 - rpc ApplyEntityMutation(ApplyEntityMutationRequest) 71 - returns (ApplyEntityMutationReply); 72 - rpc ApplyEntityMutationUpdated(ApplyEntityMutationRequest) 73 - returns (ApplyEntityMutationReplyUpdated); 74 - 75 - // -- Batches 76 - rpc GetEntityBatch(GetEntityBatchRequest) returns (GetEntityBatchResponse); 77 - 78 - // -- Label Iteration 79 - rpc GetTokenRangeQueries(GetTokenRangeQueriesRequest) 80 - returns (GetTokenRangeQueriesResult); 81 - rpc ScanTokenRange(ScanTokenRangeRequest) returns (ScanTokenRangeResult); 82 - } 83 - 84 - message GetEntityBatchRequest { 85 - string routing_key = 2; 86 - repeated EntityKey keys = 1; 87 - } 88 - 89 - message GetEntityBatchResponse { 90 - repeated GetEntityResponse responses = 1; 91 - } 92 - 93 - message GetEntityRequest { 94 - string routing_key = 2; 95 - EntityKey key = 1; 96 - } 97 - 98 - message GetEntityResponse { 99 - Entity entity = 1; 100 - } 101 - 102 - message EntityMutation { 103 - // The label name to apply. 104 - string label_name = 1; 105 - // The reason the label was applied, generally this is the label name. 106 - string reason_name = 2; 107 - LabelStatus status = 3; 108 - bool pending = 4; 109 - string description = 5; 110 - map<string, string> features = 6; 111 - google.protobuf.Timestamp expires_at = 7; 112 - } 113 - 114 - message ApplyEntityMutationRequest { 115 - string routing_key = 3; 116 - EntityKey key = 1; 117 - repeated EntityMutation mutations = 2; 118 - } 119 - 120 - message ApplyEntityMutationReply { 121 - repeated string added = 1; 122 - repeated string removed = 2; 123 - repeated string unchanged = 3; 124 - repeated EntityMutation dropped = 4; 125 - } 126 - 127 - message TokenRangeQuery { 128 - string opaque = 1; 129 - } 130 - 131 - message GetTokenRangeQueriesRequest { 132 - } 133 - 134 - message GetTokenRangeQueriesResult { 135 - uint64 max_query_concurrency = 1; 136 - repeated TokenRangeQuery token_range_queries = 2; 137 - } 138 - 139 - message ScanTokenRangeRequest { 140 - TokenRangeQuery token_range_query = 1; 141 - } 142 - 143 - message ScanTokenRangeResult { 144 - TokenRangeQuery continuation_token = 1; 145 - repeated Entity entities = 2; 146 - } 147 - 148 - enum MutationOperation { 149 - MUTATION_OPERATION_UNSPECIFIED = 0; 150 - MUTATION_OPERATION_ADDED = 1; 151 - MUTATION_OPERATION_UPDATED = 2; 152 - MUTATION_OPERATION_UNCHANGED = 3; 153 - MUTATION_OPERATION_REMOVED = 4; 154 - } 155 - 156 - message LabelReasonMutationResult { 157 - MutationOperation operation = 1; 158 - LabelReason prev_reason = 2; 159 - LabelReason current_reason = 3; 160 - } 161 - 162 - message LabelMutationResult { 163 - LabelStatus status = 1; 164 - MutationOperation operation = 2; 165 - map<string, LabelReasonMutationResult> reasons = 3; 166 - } 167 - 168 - message ApplyEntityMutationReplyUpdated { 169 - map<string, LabelMutationResult> label_mutations = 1; 170 - repeated EntityMutation dropped = 2; 171 - }