From 21d3696488f2180984e01fdd215ae937b748194a Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Thu, 15 Jan 2026 15:23:54 -0800 Subject: [PATCH 1/3] Add support for requesting OpenAPI schemas Crossplane PR #7022 adds support for composition functions to request OpenAPI schemas for resource kinds. When a function needs to validate or introspect a resource's schema, it can request the schema from Crossplane and receive it in subsequent invocations. This commit updates the protobuf definitions from PR #7022 and adds helper functions to work with schema requirements: - response.require_schema() declares a schema requirement - request.get_required_schema() retrieves the resolved schema The schema is returned as a plain dict, allowing callers to use it directly with validation libraries like openapi-schema-validator or jsonschema. Both get_required_resources() and get_required_schema() docstrings now document how to distinguish between "not yet resolved" and "resolved but not found" using the `name in req.required_*` pattern. Ref: https://github.com/crossplane/crossplane/pull/7022 Signed-off-by: Nic Cope --- .../function/proto/v1/run_function.proto | 30 ++++- .../function/proto/v1/run_function_pb2.py | 124 ++++++++++-------- .../function/proto/v1/run_function_pb2.pyi | 40 +++++- .../function/proto/v1beta1/run_function.proto | 28 ++++ .../proto/v1beta1/run_function_pb2.py | 124 ++++++++++-------- .../proto/v1beta1/run_function_pb2.pyi | 40 +++++- crossplane/function/request.py | 58 ++++++++ crossplane/function/response.py | 29 ++++ tests/test_request.py | 65 +++++++++ tests/test_response.py | 53 ++++++++ 10 files changed, 470 insertions(+), 121 deletions(-) diff --git a/crossplane/function/proto/v1/run_function.proto b/crossplane/function/proto/v1/run_function.proto index a6ca33a..4c3d092 100644 --- a/crossplane/function/proto/v1/run_function.proto +++ b/crossplane/function/proto/v1/run_function.proto @@ -90,6 +90,13 @@ message RunFunctionRequest { // satisfy the request. This field is only populated when the function uses // resources in its requirements. map required_resources = 8; + + // Optional schemas that the function specified in its requirements. The map + // key corresponds to the key in a RunFunctionResponse's requirements.schemas + // field. If a function requested a schema that could not be found, Crossplane + // sets the map key to an empty Schema message to indicate that it attempted + // to satisfy the request. + map required_schemas = 9; } // Credentials that a function may use to communicate with an external system. @@ -169,6 +176,27 @@ message Requirements { // Resources that this function requires. The map key uniquely identifies the // group of resources. map resources = 2; + + // Schemas that this function requires. The map key uniquely identifies the + // schema request. + map schemas = 3; +} + +// SchemaSelector identifies a resource kind whose OpenAPI schema is requested. +message SchemaSelector { + // API version of the resource kind, e.g. "example.org/v1". + string api_version = 1; + + // Kind of resource, e.g. "MyResource". + string kind = 2; +} + +// Schema represents the OpenAPI schema for a resource kind. +message Schema { + // The OpenAPI v3 schema of the resource kind as unstructured JSON. + // For CRDs this is the spec.versions[].schema.openAPIV3Schema field. + // Empty if Crossplane could not find a schema for the requested kind. + optional google.protobuf.Struct openapi_v3 = 1; } // ResourceSelector selects a group of resources, either by name or by label. @@ -367,4 +395,4 @@ enum Status { STATUS_CONDITION_TRUE = 2; STATUS_CONDITION_FALSE = 3; -} \ No newline at end of file +} diff --git a/crossplane/function/proto/v1/run_function_pb2.py b/crossplane/function/proto/v1/run_function_pb2.py index 9c51896..27506ae 100644 --- a/crossplane/function/proto/v1/run_function_pb2.py +++ b/crossplane/function/proto/v1/run_function_pb2.py @@ -26,7 +26,7 @@ from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n/crossplane/function/proto/v1/run_function.proto\x12\x19\x61piextensions.fn.proto.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xd3\x06\n\x12RunFunctionRequest\x12\x34\n\x04meta\x18\x01 \x01(\x0b\x32&.apiextensions.fn.proto.v1.RequestMeta\x12\x32\n\x08observed\x18\x02 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12\x31\n\x07\x64\x65sired\x18\x03 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12-\n\x07\x63ontext\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x12^\n\x0f\x65xtra_resources\x18\x06 \x03(\x0b\x32\x41.apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntryB\x02\x18\x01\x12S\n\x0b\x63redentials\x18\x07 \x03(\x0b\x32>.apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry\x12`\n\x12required_resources\x18\x08 \x03(\x0b\x32\x44.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry\x1a[\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x33\n\x05value\x18\x02 \x01(\x0b\x32$.apiextensions.fn.proto.v1.Resources:\x02\x38\x01\x1aZ\n\x10\x43redentialsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.apiextensions.fn.proto.v1.Credentials:\x02\x38\x01\x1a^\n\x16RequiredResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x33\n\x05value\x18\x02 \x01(\x0b\x32$.apiextensions.fn.proto.v1.Resources:\x02\x38\x01\x42\x08\n\x06_inputB\n\n\x08_context\"]\n\x0b\x43redentials\x12\x44\n\x0f\x63redential_data\x18\x01 \x01(\x0b\x32).apiextensions.fn.proto.v1.CredentialDataH\x00\x42\x08\n\x06source\"\x80\x01\n\x0e\x43redentialData\x12\x41\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x33.apiextensions.fn.proto.v1.CredentialData.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"?\n\tResources\x12\x32\n\x05items\x18\x01 \x03(\x0b\x32#.apiextensions.fn.proto.v1.Resource\"\xa0\x03\n\x13RunFunctionResponse\x12\x35\n\x04meta\x18\x01 \x01(\x0b\x32\'.apiextensions.fn.proto.v1.ResponseMeta\x12\x31\n\x07\x64\x65sired\x18\x02 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12\x32\n\x07results\x18\x03 \x03(\x0b\x32!.apiextensions.fn.proto.v1.Result\x12-\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12=\n\x0crequirements\x18\x05 \x01(\x0b\x32\'.apiextensions.fn.proto.v1.Requirements\x12\x38\n\nconditions\x18\x06 \x03(\x0b\x32$.apiextensions.fn.proto.v1.Condition\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x42\n\n\x08_contextB\t\n\x07_output\"\x1a\n\x0bRequestMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\"\xf6\x02\n\x0cRequirements\x12X\n\x0f\x65xtra_resources\x18\x01 \x03(\x0b\x32;.apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntryB\x02\x18\x01\x12I\n\tresources\x18\x02 \x03(\x0b\x32\x36.apiextensions.fn.proto.v1.Requirements.ResourcesEntry\x1a\x62\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1.ResourceSelector:\x02\x38\x01\x1a]\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1.ResourceSelector:\x02\x38\x01\"\xba\x01\n\x10ResourceSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x14\n\nmatch_name\x18\x03 \x01(\tH\x00\x12>\n\x0cmatch_labels\x18\x04 \x01(\x0b\x32&.apiextensions.fn.proto.v1.MatchLabelsH\x00\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05matchB\x0c\n\n_namespace\"\x80\x01\n\x0bMatchLabels\x12\x42\n\x06labels\x18\x01 \x03(\x0b\x32\x32.apiextensions.fn.proto.v1.MatchLabels.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"P\n\x0cResponseMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12+\n\x03ttl\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x88\x01\x01\x42\x06\n\x04_ttl\"\xda\x01\n\x05State\x12\x36\n\tcomposite\x18\x01 \x01(\x0b\x32#.apiextensions.fn.proto.v1.Resource\x12\x42\n\tresources\x18\x02 \x03(\x0b\x32/.apiextensions.fn.proto.v1.State.ResourcesEntry\x1aU\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32#.apiextensions.fn.proto.v1.Resource:\x02\x38\x01\"\xf8\x01\n\x08Resource\x12)\n\x08resource\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12V\n\x12\x63onnection_details\x18\x02 \x03(\x0b\x32:.apiextensions.fn.proto.v1.Resource.ConnectionDetailsEntry\x12/\n\x05ready\x18\x03 \x01(\x0e\x32 .apiextensions.fn.proto.v1.Ready\x1a\x38\n\x16\x43onnectionDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"\xb3\x01\n\x06Result\x12\x35\n\x08severity\x18\x01 \x01(\x0e\x32#.apiextensions.fn.proto.v1.Severity\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x13\n\x06reason\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x36\n\x06target\x18\x04 \x01(\x0e\x32!.apiextensions.fn.proto.v1.TargetH\x01\x88\x01\x01\x42\t\n\x07_reasonB\t\n\x07_target\"\xc1\x01\n\tCondition\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x31\n\x06status\x18\x02 \x01(\x0e\x32!.apiextensions.fn.proto.v1.Status\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x14\n\x07message\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x36\n\x06target\x18\x05 \x01(\x0e\x32!.apiextensions.fn.proto.v1.TargetH\x01\x88\x01\x01\x42\n\n\x08_messageB\t\n\x07_target*?\n\x05Ready\x12\x15\n\x11READY_UNSPECIFIED\x10\x00\x12\x0e\n\nREADY_TRUE\x10\x01\x12\x0f\n\x0bREADY_FALSE\x10\x02*c\n\x08Severity\x12\x18\n\x14SEVERITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eSEVERITY_FATAL\x10\x01\x12\x14\n\x10SEVERITY_WARNING\x10\x02\x12\x13\n\x0fSEVERITY_NORMAL\x10\x03*V\n\x06Target\x12\x16\n\x12TARGET_UNSPECIFIED\x10\x00\x12\x14\n\x10TARGET_COMPOSITE\x10\x01\x12\x1e\n\x1aTARGET_COMPOSITE_AND_CLAIM\x10\x02*\x7f\n\x06Status\x12 \n\x1cSTATUS_CONDITION_UNSPECIFIED\x10\x00\x12\x1c\n\x18STATUS_CONDITION_UNKNOWN\x10\x01\x12\x19\n\x15STATUS_CONDITION_TRUE\x10\x02\x12\x1a\n\x16STATUS_CONDITION_FALSE\x10\x03\x32\x87\x01\n\x15\x46unctionRunnerService\x12n\n\x0bRunFunction\x12-.apiextensions.fn.proto.v1.RunFunctionRequest\x1a..apiextensions.fn.proto.v1.RunFunctionResponse\"\x00\x42\x31Z/github.com/crossplane/crossplane/v2/proto/fn/v1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n/crossplane/function/proto/v1/run_function.proto\x12\x19\x61piextensions.fn.proto.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x8c\x08\n\x12RunFunctionRequest\x12\x34\n\x04meta\x18\x01 \x01(\x0b\x32&.apiextensions.fn.proto.v1.RequestMeta\x12\x32\n\x08observed\x18\x02 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12\x31\n\x07\x64\x65sired\x18\x03 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12-\n\x07\x63ontext\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x12^\n\x0f\x65xtra_resources\x18\x06 \x03(\x0b\x32\x41.apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntryB\x02\x18\x01\x12S\n\x0b\x63redentials\x18\x07 \x03(\x0b\x32>.apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry\x12`\n\x12required_resources\x18\x08 \x03(\x0b\x32\x44.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry\x12\\\n\x10required_schemas\x18\t \x03(\x0b\x32\x42.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntry\x1a[\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x33\n\x05value\x18\x02 \x01(\x0b\x32$.apiextensions.fn.proto.v1.Resources:\x02\x38\x01\x1aZ\n\x10\x43redentialsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.apiextensions.fn.proto.v1.Credentials:\x02\x38\x01\x1a^\n\x16RequiredResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x33\n\x05value\x18\x02 \x01(\x0b\x32$.apiextensions.fn.proto.v1.Resources:\x02\x38\x01\x1aY\n\x14RequiredSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x30\n\x05value\x18\x02 \x01(\x0b\x32!.apiextensions.fn.proto.v1.Schema:\x02\x38\x01\x42\x08\n\x06_inputB\n\n\x08_context\"]\n\x0b\x43redentials\x12\x44\n\x0f\x63redential_data\x18\x01 \x01(\x0b\x32).apiextensions.fn.proto.v1.CredentialDataH\x00\x42\x08\n\x06source\"\x80\x01\n\x0e\x43redentialData\x12\x41\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x33.apiextensions.fn.proto.v1.CredentialData.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"?\n\tResources\x12\x32\n\x05items\x18\x01 \x03(\x0b\x32#.apiextensions.fn.proto.v1.Resource\"\xa0\x03\n\x13RunFunctionResponse\x12\x35\n\x04meta\x18\x01 \x01(\x0b\x32\'.apiextensions.fn.proto.v1.ResponseMeta\x12\x31\n\x07\x64\x65sired\x18\x02 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12\x32\n\x07results\x18\x03 \x03(\x0b\x32!.apiextensions.fn.proto.v1.Result\x12-\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12=\n\x0crequirements\x18\x05 \x01(\x0b\x32\'.apiextensions.fn.proto.v1.Requirements\x12\x38\n\nconditions\x18\x06 \x03(\x0b\x32$.apiextensions.fn.proto.v1.Condition\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x42\n\n\x08_contextB\t\n\x07_output\"\x1a\n\x0bRequestMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\"\x98\x04\n\x0cRequirements\x12X\n\x0f\x65xtra_resources\x18\x01 \x03(\x0b\x32;.apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntryB\x02\x18\x01\x12I\n\tresources\x18\x02 \x03(\x0b\x32\x36.apiextensions.fn.proto.v1.Requirements.ResourcesEntry\x12\x45\n\x07schemas\x18\x03 \x03(\x0b\x32\x34.apiextensions.fn.proto.v1.Requirements.SchemasEntry\x1a\x62\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1.ResourceSelector:\x02\x38\x01\x1a]\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1.ResourceSelector:\x02\x38\x01\x1aY\n\x0cSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1.SchemaSelector:\x02\x38\x01\"3\n\x0eSchemaSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\"I\n\x06Schema\x12\x30\n\nopenapi_v3\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x42\r\n\x0b_openapi_v3\"\xba\x01\n\x10ResourceSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x14\n\nmatch_name\x18\x03 \x01(\tH\x00\x12>\n\x0cmatch_labels\x18\x04 \x01(\x0b\x32&.apiextensions.fn.proto.v1.MatchLabelsH\x00\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05matchB\x0c\n\n_namespace\"\x80\x01\n\x0bMatchLabels\x12\x42\n\x06labels\x18\x01 \x03(\x0b\x32\x32.apiextensions.fn.proto.v1.MatchLabels.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"P\n\x0cResponseMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12+\n\x03ttl\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x88\x01\x01\x42\x06\n\x04_ttl\"\xda\x01\n\x05State\x12\x36\n\tcomposite\x18\x01 \x01(\x0b\x32#.apiextensions.fn.proto.v1.Resource\x12\x42\n\tresources\x18\x02 \x03(\x0b\x32/.apiextensions.fn.proto.v1.State.ResourcesEntry\x1aU\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32#.apiextensions.fn.proto.v1.Resource:\x02\x38\x01\"\xf8\x01\n\x08Resource\x12)\n\x08resource\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12V\n\x12\x63onnection_details\x18\x02 \x03(\x0b\x32:.apiextensions.fn.proto.v1.Resource.ConnectionDetailsEntry\x12/\n\x05ready\x18\x03 \x01(\x0e\x32 .apiextensions.fn.proto.v1.Ready\x1a\x38\n\x16\x43onnectionDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"\xb3\x01\n\x06Result\x12\x35\n\x08severity\x18\x01 \x01(\x0e\x32#.apiextensions.fn.proto.v1.Severity\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x13\n\x06reason\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x36\n\x06target\x18\x04 \x01(\x0e\x32!.apiextensions.fn.proto.v1.TargetH\x01\x88\x01\x01\x42\t\n\x07_reasonB\t\n\x07_target\"\xc1\x01\n\tCondition\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x31\n\x06status\x18\x02 \x01(\x0e\x32!.apiextensions.fn.proto.v1.Status\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x14\n\x07message\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x36\n\x06target\x18\x05 \x01(\x0e\x32!.apiextensions.fn.proto.v1.TargetH\x01\x88\x01\x01\x42\n\n\x08_messageB\t\n\x07_target*?\n\x05Ready\x12\x15\n\x11READY_UNSPECIFIED\x10\x00\x12\x0e\n\nREADY_TRUE\x10\x01\x12\x0f\n\x0bREADY_FALSE\x10\x02*c\n\x08Severity\x12\x18\n\x14SEVERITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eSEVERITY_FATAL\x10\x01\x12\x14\n\x10SEVERITY_WARNING\x10\x02\x12\x13\n\x0fSEVERITY_NORMAL\x10\x03*V\n\x06Target\x12\x16\n\x12TARGET_UNSPECIFIED\x10\x00\x12\x14\n\x10TARGET_COMPOSITE\x10\x01\x12\x1e\n\x1aTARGET_COMPOSITE_AND_CLAIM\x10\x02*\x7f\n\x06Status\x12 \n\x1cSTATUS_CONDITION_UNSPECIFIED\x10\x00\x12\x1c\n\x18STATUS_CONDITION_UNKNOWN\x10\x01\x12\x19\n\x15STATUS_CONDITION_TRUE\x10\x02\x12\x1a\n\x16STATUS_CONDITION_FALSE\x10\x03\x32\x87\x01\n\x15\x46unctionRunnerService\x12n\n\x0bRunFunction\x12-.apiextensions.fn.proto.v1.RunFunctionRequest\x1a..apiextensions.fn.proto.v1.RunFunctionResponse\"\x00\x42\x31Z/github.com/crossplane/crossplane/v2/proto/fn/v1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -40,6 +40,8 @@ _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_options = b'8\001' _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._loaded_options = None _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_options = b'8\001' + _globals['_RUNFUNCTIONREQUEST_REQUIREDSCHEMASENTRY']._loaded_options = None + _globals['_RUNFUNCTIONREQUEST_REQUIREDSCHEMASENTRY']._serialized_options = b'8\001' _globals['_RUNFUNCTIONREQUEST'].fields_by_name['extra_resources']._loaded_options = None _globals['_RUNFUNCTIONREQUEST'].fields_by_name['extra_resources']._serialized_options = b'\030\001' _globals['_CREDENTIALDATA_DATAENTRY']._loaded_options = None @@ -48,6 +50,8 @@ _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_options = b'8\001' _globals['_REQUIREMENTS_RESOURCESENTRY']._loaded_options = None _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_options = b'8\001' + _globals['_REQUIREMENTS_SCHEMASENTRY']._loaded_options = None + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_options = b'8\001' _globals['_REQUIREMENTS'].fields_by_name['extra_resources']._loaded_options = None _globals['_REQUIREMENTS'].fields_by_name['extra_resources']._serialized_options = b'\030\001' _globals['_MATCHLABELS_LABELSENTRY']._loaded_options = None @@ -56,60 +60,68 @@ _globals['_STATE_RESOURCESENTRY']._serialized_options = b'8\001' _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._loaded_options = None _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_options = b'8\001' - _globals['_READY']._serialized_start=3361 - _globals['_READY']._serialized_end=3424 - _globals['_SEVERITY']._serialized_start=3426 - _globals['_SEVERITY']._serialized_end=3525 - _globals['_TARGET']._serialized_start=3527 - _globals['_TARGET']._serialized_end=3613 - _globals['_STATUS']._serialized_start=3615 - _globals['_STATUS']._serialized_end=3742 + _globals['_READY']._serialized_start=3836 + _globals['_READY']._serialized_end=3899 + _globals['_SEVERITY']._serialized_start=3901 + _globals['_SEVERITY']._serialized_end=4000 + _globals['_TARGET']._serialized_start=4002 + _globals['_TARGET']._serialized_end=4088 + _globals['_STATUS']._serialized_start=4090 + _globals['_STATUS']._serialized_end=4217 _globals['_RUNFUNCTIONREQUEST']._serialized_start=141 - _globals['_RUNFUNCTIONREQUEST']._serialized_end=992 - _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_start=691 - _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_end=782 - _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_start=784 - _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_end=874 - _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_start=876 - _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_end=970 - _globals['_CREDENTIALS']._serialized_start=994 - _globals['_CREDENTIALS']._serialized_end=1087 - _globals['_CREDENTIALDATA']._serialized_start=1090 - _globals['_CREDENTIALDATA']._serialized_end=1218 - _globals['_CREDENTIALDATA_DATAENTRY']._serialized_start=1175 - _globals['_CREDENTIALDATA_DATAENTRY']._serialized_end=1218 - _globals['_RESOURCES']._serialized_start=1220 - _globals['_RESOURCES']._serialized_end=1283 - _globals['_RUNFUNCTIONRESPONSE']._serialized_start=1286 - _globals['_RUNFUNCTIONRESPONSE']._serialized_end=1702 - _globals['_REQUESTMETA']._serialized_start=1704 - _globals['_REQUESTMETA']._serialized_end=1730 - _globals['_REQUIREMENTS']._serialized_start=1733 - _globals['_REQUIREMENTS']._serialized_end=2107 - _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_start=1914 - _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_end=2012 - _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_start=2014 - _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_end=2107 - _globals['_RESOURCESELECTOR']._serialized_start=2110 - _globals['_RESOURCESELECTOR']._serialized_end=2296 - _globals['_MATCHLABELS']._serialized_start=2299 - _globals['_MATCHLABELS']._serialized_end=2427 - _globals['_MATCHLABELS_LABELSENTRY']._serialized_start=2382 - _globals['_MATCHLABELS_LABELSENTRY']._serialized_end=2427 - _globals['_RESPONSEMETA']._serialized_start=2429 - _globals['_RESPONSEMETA']._serialized_end=2509 - _globals['_STATE']._serialized_start=2512 - _globals['_STATE']._serialized_end=2730 - _globals['_STATE_RESOURCESENTRY']._serialized_start=2645 - _globals['_STATE_RESOURCESENTRY']._serialized_end=2730 - _globals['_RESOURCE']._serialized_start=2733 - _globals['_RESOURCE']._serialized_end=2981 - _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_start=2925 - _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_end=2981 - _globals['_RESULT']._serialized_start=2984 - _globals['_RESULT']._serialized_end=3163 - _globals['_CONDITION']._serialized_start=3166 - _globals['_CONDITION']._serialized_end=3359 - _globals['_FUNCTIONRUNNERSERVICE']._serialized_start=3745 - _globals['_FUNCTIONRUNNERSERVICE']._serialized_end=3880 + _globals['_RUNFUNCTIONREQUEST']._serialized_end=1177 + _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_start=785 + _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_end=876 + _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_start=878 + _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_end=968 + _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_start=970 + _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_end=1064 + _globals['_RUNFUNCTIONREQUEST_REQUIREDSCHEMASENTRY']._serialized_start=1066 + _globals['_RUNFUNCTIONREQUEST_REQUIREDSCHEMASENTRY']._serialized_end=1155 + _globals['_CREDENTIALS']._serialized_start=1179 + _globals['_CREDENTIALS']._serialized_end=1272 + _globals['_CREDENTIALDATA']._serialized_start=1275 + _globals['_CREDENTIALDATA']._serialized_end=1403 + _globals['_CREDENTIALDATA_DATAENTRY']._serialized_start=1360 + _globals['_CREDENTIALDATA_DATAENTRY']._serialized_end=1403 + _globals['_RESOURCES']._serialized_start=1405 + _globals['_RESOURCES']._serialized_end=1468 + _globals['_RUNFUNCTIONRESPONSE']._serialized_start=1471 + _globals['_RUNFUNCTIONRESPONSE']._serialized_end=1887 + _globals['_REQUESTMETA']._serialized_start=1889 + _globals['_REQUESTMETA']._serialized_end=1915 + _globals['_REQUIREMENTS']._serialized_start=1918 + _globals['_REQUIREMENTS']._serialized_end=2454 + _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_start=2170 + _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_end=2268 + _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_start=2270 + _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_end=2363 + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_start=2365 + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_end=2454 + _globals['_SCHEMASELECTOR']._serialized_start=2456 + _globals['_SCHEMASELECTOR']._serialized_end=2507 + _globals['_SCHEMA']._serialized_start=2509 + _globals['_SCHEMA']._serialized_end=2582 + _globals['_RESOURCESELECTOR']._serialized_start=2585 + _globals['_RESOURCESELECTOR']._serialized_end=2771 + _globals['_MATCHLABELS']._serialized_start=2774 + _globals['_MATCHLABELS']._serialized_end=2902 + _globals['_MATCHLABELS_LABELSENTRY']._serialized_start=2857 + _globals['_MATCHLABELS_LABELSENTRY']._serialized_end=2902 + _globals['_RESPONSEMETA']._serialized_start=2904 + _globals['_RESPONSEMETA']._serialized_end=2984 + _globals['_STATE']._serialized_start=2987 + _globals['_STATE']._serialized_end=3205 + _globals['_STATE_RESOURCESENTRY']._serialized_start=3120 + _globals['_STATE_RESOURCESENTRY']._serialized_end=3205 + _globals['_RESOURCE']._serialized_start=3208 + _globals['_RESOURCE']._serialized_end=3456 + _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_start=3400 + _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_end=3456 + _globals['_RESULT']._serialized_start=3459 + _globals['_RESULT']._serialized_end=3638 + _globals['_CONDITION']._serialized_start=3641 + _globals['_CONDITION']._serialized_end=3834 + _globals['_FUNCTIONRUNNERSERVICE']._serialized_start=4220 + _globals['_FUNCTIONRUNNERSERVICE']._serialized_end=4355 # @@protoc_insertion_point(module_scope) diff --git a/crossplane/function/proto/v1/run_function_pb2.pyi b/crossplane/function/proto/v1/run_function_pb2.pyi index 534fe30..30ad04f 100644 --- a/crossplane/function/proto/v1/run_function_pb2.pyi +++ b/crossplane/function/proto/v1/run_function_pb2.pyi @@ -52,7 +52,7 @@ STATUS_CONDITION_TRUE: Status STATUS_CONDITION_FALSE: Status class RunFunctionRequest(_message.Message): - __slots__ = ("meta", "observed", "desired", "input", "context", "extra_resources", "credentials", "required_resources") + __slots__ = ("meta", "observed", "desired", "input", "context", "extra_resources", "credentials", "required_resources", "required_schemas") class ExtraResourcesEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -74,6 +74,13 @@ class RunFunctionRequest(_message.Message): key: str value: Resources def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Resources, _Mapping]] = ...) -> None: ... + class RequiredSchemasEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: Schema + def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Schema, _Mapping]] = ...) -> None: ... META_FIELD_NUMBER: _ClassVar[int] OBSERVED_FIELD_NUMBER: _ClassVar[int] DESIRED_FIELD_NUMBER: _ClassVar[int] @@ -82,6 +89,7 @@ class RunFunctionRequest(_message.Message): EXTRA_RESOURCES_FIELD_NUMBER: _ClassVar[int] CREDENTIALS_FIELD_NUMBER: _ClassVar[int] REQUIRED_RESOURCES_FIELD_NUMBER: _ClassVar[int] + REQUIRED_SCHEMAS_FIELD_NUMBER: _ClassVar[int] meta: RequestMeta observed: State desired: State @@ -90,7 +98,8 @@ class RunFunctionRequest(_message.Message): extra_resources: _containers.MessageMap[str, Resources] credentials: _containers.MessageMap[str, Credentials] required_resources: _containers.MessageMap[str, Resources] - def __init__(self, meta: _Optional[_Union[RequestMeta, _Mapping]] = ..., observed: _Optional[_Union[State, _Mapping]] = ..., desired: _Optional[_Union[State, _Mapping]] = ..., input: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., context: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., extra_resources: _Optional[_Mapping[str, Resources]] = ..., credentials: _Optional[_Mapping[str, Credentials]] = ..., required_resources: _Optional[_Mapping[str, Resources]] = ...) -> None: ... + required_schemas: _containers.MessageMap[str, Schema] + def __init__(self, meta: _Optional[_Union[RequestMeta, _Mapping]] = ..., observed: _Optional[_Union[State, _Mapping]] = ..., desired: _Optional[_Union[State, _Mapping]] = ..., input: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., context: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., extra_resources: _Optional[_Mapping[str, Resources]] = ..., credentials: _Optional[_Mapping[str, Credentials]] = ..., required_resources: _Optional[_Mapping[str, Resources]] = ..., required_schemas: _Optional[_Mapping[str, Schema]] = ...) -> None: ... class Credentials(_message.Message): __slots__ = ("credential_data",) @@ -142,7 +151,7 @@ class RequestMeta(_message.Message): def __init__(self, tag: _Optional[str] = ...) -> None: ... class Requirements(_message.Message): - __slots__ = ("extra_resources", "resources") + __slots__ = ("extra_resources", "resources", "schemas") class ExtraResourcesEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -157,11 +166,34 @@ class Requirements(_message.Message): key: str value: ResourceSelector def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[ResourceSelector, _Mapping]] = ...) -> None: ... + class SchemasEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: SchemaSelector + def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[SchemaSelector, _Mapping]] = ...) -> None: ... EXTRA_RESOURCES_FIELD_NUMBER: _ClassVar[int] RESOURCES_FIELD_NUMBER: _ClassVar[int] + SCHEMAS_FIELD_NUMBER: _ClassVar[int] extra_resources: _containers.MessageMap[str, ResourceSelector] resources: _containers.MessageMap[str, ResourceSelector] - def __init__(self, extra_resources: _Optional[_Mapping[str, ResourceSelector]] = ..., resources: _Optional[_Mapping[str, ResourceSelector]] = ...) -> None: ... + schemas: _containers.MessageMap[str, SchemaSelector] + def __init__(self, extra_resources: _Optional[_Mapping[str, ResourceSelector]] = ..., resources: _Optional[_Mapping[str, ResourceSelector]] = ..., schemas: _Optional[_Mapping[str, SchemaSelector]] = ...) -> None: ... + +class SchemaSelector(_message.Message): + __slots__ = ("api_version", "kind") + API_VERSION_FIELD_NUMBER: _ClassVar[int] + KIND_FIELD_NUMBER: _ClassVar[int] + api_version: str + kind: str + def __init__(self, api_version: _Optional[str] = ..., kind: _Optional[str] = ...) -> None: ... + +class Schema(_message.Message): + __slots__ = ("openapi_v3",) + OPENAPI_V3_FIELD_NUMBER: _ClassVar[int] + openapi_v3: _struct_pb2.Struct + def __init__(self, openapi_v3: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ... class ResourceSelector(_message.Message): __slots__ = ("api_version", "kind", "match_name", "match_labels", "namespace") diff --git a/crossplane/function/proto/v1beta1/run_function.proto b/crossplane/function/proto/v1beta1/run_function.proto index e53ded4..2815d5b 100644 --- a/crossplane/function/proto/v1beta1/run_function.proto +++ b/crossplane/function/proto/v1beta1/run_function.proto @@ -92,6 +92,13 @@ message RunFunctionRequest { // satisfy the request. This field is only populated when the function uses // resources in its requirements. map required_resources = 8; + + // Optional schemas that the function specified in its requirements. The map + // key corresponds to the key in a RunFunctionResponse's requirements.schemas + // field. If a function requested a schema that could not be found, Crossplane + // sets the map key to an empty Schema message to indicate that it attempted + // to satisfy the request. + map required_schemas = 9; } // Credentials that a function may use to communicate with an external system. @@ -171,6 +178,27 @@ message Requirements { // Resources that this function requires. The map key uniquely identifies the // group of resources. map resources = 2; + + // Schemas that this function requires. The map key uniquely identifies the + // schema request. + map schemas = 3; +} + +// SchemaSelector identifies a resource kind whose OpenAPI schema is requested. +message SchemaSelector { + // API version of the resource kind, e.g. "example.org/v1". + string api_version = 1; + + // Kind of resource, e.g. "MyResource". + string kind = 2; +} + +// Schema represents the OpenAPI schema for a resource kind. +message Schema { + // The OpenAPI v3 schema of the resource kind as unstructured JSON. + // For CRDs this is the spec.versions[].schema.openAPIV3Schema field. + // Empty if Crossplane could not find a schema for the requested kind. + optional google.protobuf.Struct openapi_v3 = 1; } // ResourceSelector selects a group of resources, either by name or by label. diff --git a/crossplane/function/proto/v1beta1/run_function_pb2.py b/crossplane/function/proto/v1beta1/run_function_pb2.py index 9907f35..8e23ac4 100644 --- a/crossplane/function/proto/v1beta1/run_function_pb2.py +++ b/crossplane/function/proto/v1beta1/run_function_pb2.py @@ -26,7 +26,7 @@ from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n4crossplane/function/proto/v1beta1/run_function.proto\x12\x1e\x61piextensions.fn.proto.v1beta1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x80\x07\n\x12RunFunctionRequest\x12\x39\n\x04meta\x18\x01 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.RequestMeta\x12\x37\n\x08observed\x18\x02 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12\x36\n\x07\x64\x65sired\x18\x03 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12-\n\x07\x63ontext\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x12\x63\n\x0f\x65xtra_resources\x18\x06 \x03(\x0b\x32\x46.apiextensions.fn.proto.v1beta1.RunFunctionRequest.ExtraResourcesEntryB\x02\x18\x01\x12X\n\x0b\x63redentials\x18\x07 \x03(\x0b\x32\x43.apiextensions.fn.proto.v1beta1.RunFunctionRequest.CredentialsEntry\x12\x65\n\x12required_resources\x18\x08 \x03(\x0b\x32I.apiextensions.fn.proto.v1beta1.RunFunctionRequest.RequiredResourcesEntry\x1a`\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1beta1.Resources:\x02\x38\x01\x1a_\n\x10\x43redentialsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.Credentials:\x02\x38\x01\x1a\x63\n\x16RequiredResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1beta1.Resources:\x02\x38\x01\x42\x08\n\x06_inputB\n\n\x08_context\"b\n\x0b\x43redentials\x12I\n\x0f\x63redential_data\x18\x01 \x01(\x0b\x32..apiextensions.fn.proto.v1beta1.CredentialDataH\x00\x42\x08\n\x06source\"\x85\x01\n\x0e\x43redentialData\x12\x46\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x38.apiextensions.fn.proto.v1beta1.CredentialData.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"D\n\tResources\x12\x37\n\x05items\x18\x01 \x03(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource\"\xb9\x03\n\x13RunFunctionResponse\x12:\n\x04meta\x18\x01 \x01(\x0b\x32,.apiextensions.fn.proto.v1beta1.ResponseMeta\x12\x36\n\x07\x64\x65sired\x18\x02 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12\x37\n\x07results\x18\x03 \x03(\x0b\x32&.apiextensions.fn.proto.v1beta1.Result\x12-\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12\x42\n\x0crequirements\x18\x05 \x01(\x0b\x32,.apiextensions.fn.proto.v1beta1.Requirements\x12=\n\nconditions\x18\x06 \x03(\x0b\x32).apiextensions.fn.proto.v1beta1.Condition\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x42\n\n\x08_contextB\t\n\x07_output\"\x1a\n\x0bRequestMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\"\x8a\x03\n\x0cRequirements\x12]\n\x0f\x65xtra_resources\x18\x01 \x03(\x0b\x32@.apiextensions.fn.proto.v1beta1.Requirements.ExtraResourcesEntryB\x02\x18\x01\x12N\n\tresources\x18\x02 \x03(\x0b\x32;.apiextensions.fn.proto.v1beta1.Requirements.ResourcesEntry\x1ag\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.apiextensions.fn.proto.v1beta1.ResourceSelector:\x02\x38\x01\x1a\x62\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.apiextensions.fn.proto.v1beta1.ResourceSelector:\x02\x38\x01\"\xbf\x01\n\x10ResourceSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x14\n\nmatch_name\x18\x03 \x01(\tH\x00\x12\x43\n\x0cmatch_labels\x18\x04 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.MatchLabelsH\x00\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05matchB\x0c\n\n_namespace\"\x85\x01\n\x0bMatchLabels\x12G\n\x06labels\x18\x01 \x03(\x0b\x32\x37.apiextensions.fn.proto.v1beta1.MatchLabels.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"P\n\x0cResponseMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12+\n\x03ttl\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x88\x01\x01\x42\x06\n\x04_ttl\"\xe9\x01\n\x05State\x12;\n\tcomposite\x18\x01 \x01(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource\x12G\n\tresources\x18\x02 \x03(\x0b\x32\x34.apiextensions.fn.proto.v1beta1.State.ResourcesEntry\x1aZ\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x37\n\x05value\x18\x02 \x01(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource:\x02\x38\x01\"\x82\x02\n\x08Resource\x12)\n\x08resource\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12[\n\x12\x63onnection_details\x18\x02 \x03(\x0b\x32?.apiextensions.fn.proto.v1beta1.Resource.ConnectionDetailsEntry\x12\x34\n\x05ready\x18\x03 \x01(\x0e\x32%.apiextensions.fn.proto.v1beta1.Ready\x1a\x38\n\x16\x43onnectionDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"\xbd\x01\n\x06Result\x12:\n\x08severity\x18\x01 \x01(\x0e\x32(.apiextensions.fn.proto.v1beta1.Severity\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x13\n\x06reason\x18\x03 \x01(\tH\x00\x88\x01\x01\x12;\n\x06target\x18\x04 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.TargetH\x01\x88\x01\x01\x42\t\n\x07_reasonB\t\n\x07_target\"\xcb\x01\n\tCondition\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x36\n\x06status\x18\x02 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.Status\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x14\n\x07message\x18\x04 \x01(\tH\x00\x88\x01\x01\x12;\n\x06target\x18\x05 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.TargetH\x01\x88\x01\x01\x42\n\n\x08_messageB\t\n\x07_target*?\n\x05Ready\x12\x15\n\x11READY_UNSPECIFIED\x10\x00\x12\x0e\n\nREADY_TRUE\x10\x01\x12\x0f\n\x0bREADY_FALSE\x10\x02*c\n\x08Severity\x12\x18\n\x14SEVERITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eSEVERITY_FATAL\x10\x01\x12\x14\n\x10SEVERITY_WARNING\x10\x02\x12\x13\n\x0fSEVERITY_NORMAL\x10\x03*V\n\x06Target\x12\x16\n\x12TARGET_UNSPECIFIED\x10\x00\x12\x14\n\x10TARGET_COMPOSITE\x10\x01\x12\x1e\n\x1aTARGET_COMPOSITE_AND_CLAIM\x10\x02*\x7f\n\x06Status\x12 \n\x1cSTATUS_CONDITION_UNSPECIFIED\x10\x00\x12\x1c\n\x18STATUS_CONDITION_UNKNOWN\x10\x01\x12\x19\n\x15STATUS_CONDITION_TRUE\x10\x02\x12\x1a\n\x16STATUS_CONDITION_FALSE\x10\x03\x32\x91\x01\n\x15\x46unctionRunnerService\x12x\n\x0bRunFunction\x12\x32.apiextensions.fn.proto.v1beta1.RunFunctionRequest\x1a\x33.apiextensions.fn.proto.v1beta1.RunFunctionResponse\"\x00\x42\x36Z4github.com/crossplane/crossplane/v2/proto/fn/v1beta1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n4crossplane/function/proto/v1beta1/run_function.proto\x12\x1e\x61piextensions.fn.proto.v1beta1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xc3\x08\n\x12RunFunctionRequest\x12\x39\n\x04meta\x18\x01 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.RequestMeta\x12\x37\n\x08observed\x18\x02 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12\x36\n\x07\x64\x65sired\x18\x03 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12-\n\x07\x63ontext\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x12\x63\n\x0f\x65xtra_resources\x18\x06 \x03(\x0b\x32\x46.apiextensions.fn.proto.v1beta1.RunFunctionRequest.ExtraResourcesEntryB\x02\x18\x01\x12X\n\x0b\x63redentials\x18\x07 \x03(\x0b\x32\x43.apiextensions.fn.proto.v1beta1.RunFunctionRequest.CredentialsEntry\x12\x65\n\x12required_resources\x18\x08 \x03(\x0b\x32I.apiextensions.fn.proto.v1beta1.RunFunctionRequest.RequiredResourcesEntry\x12\x61\n\x10required_schemas\x18\t \x03(\x0b\x32G.apiextensions.fn.proto.v1beta1.RunFunctionRequest.RequiredSchemasEntry\x1a`\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1beta1.Resources:\x02\x38\x01\x1a_\n\x10\x43redentialsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.Credentials:\x02\x38\x01\x1a\x63\n\x16RequiredResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1beta1.Resources:\x02\x38\x01\x1a^\n\x14RequiredSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.apiextensions.fn.proto.v1beta1.Schema:\x02\x38\x01\x42\x08\n\x06_inputB\n\n\x08_context\"b\n\x0b\x43redentials\x12I\n\x0f\x63redential_data\x18\x01 \x01(\x0b\x32..apiextensions.fn.proto.v1beta1.CredentialDataH\x00\x42\x08\n\x06source\"\x85\x01\n\x0e\x43redentialData\x12\x46\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x38.apiextensions.fn.proto.v1beta1.CredentialData.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"D\n\tResources\x12\x37\n\x05items\x18\x01 \x03(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource\"\xb9\x03\n\x13RunFunctionResponse\x12:\n\x04meta\x18\x01 \x01(\x0b\x32,.apiextensions.fn.proto.v1beta1.ResponseMeta\x12\x36\n\x07\x64\x65sired\x18\x02 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12\x37\n\x07results\x18\x03 \x03(\x0b\x32&.apiextensions.fn.proto.v1beta1.Result\x12-\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12\x42\n\x0crequirements\x18\x05 \x01(\x0b\x32,.apiextensions.fn.proto.v1beta1.Requirements\x12=\n\nconditions\x18\x06 \x03(\x0b\x32).apiextensions.fn.proto.v1beta1.Condition\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x42\n\n\x08_contextB\t\n\x07_output\"\x1a\n\x0bRequestMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\"\xb6\x04\n\x0cRequirements\x12]\n\x0f\x65xtra_resources\x18\x01 \x03(\x0b\x32@.apiextensions.fn.proto.v1beta1.Requirements.ExtraResourcesEntryB\x02\x18\x01\x12N\n\tresources\x18\x02 \x03(\x0b\x32;.apiextensions.fn.proto.v1beta1.Requirements.ResourcesEntry\x12J\n\x07schemas\x18\x03 \x03(\x0b\x32\x39.apiextensions.fn.proto.v1beta1.Requirements.SchemasEntry\x1ag\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.apiextensions.fn.proto.v1beta1.ResourceSelector:\x02\x38\x01\x1a\x62\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.apiextensions.fn.proto.v1beta1.ResourceSelector:\x02\x38\x01\x1a^\n\x0cSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12=\n\x05value\x18\x02 \x01(\x0b\x32..apiextensions.fn.proto.v1beta1.SchemaSelector:\x02\x38\x01\"3\n\x0eSchemaSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\"I\n\x06Schema\x12\x30\n\nopenapi_v3\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x42\r\n\x0b_openapi_v3\"\xbf\x01\n\x10ResourceSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x14\n\nmatch_name\x18\x03 \x01(\tH\x00\x12\x43\n\x0cmatch_labels\x18\x04 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.MatchLabelsH\x00\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05matchB\x0c\n\n_namespace\"\x85\x01\n\x0bMatchLabels\x12G\n\x06labels\x18\x01 \x03(\x0b\x32\x37.apiextensions.fn.proto.v1beta1.MatchLabels.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"P\n\x0cResponseMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12+\n\x03ttl\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x88\x01\x01\x42\x06\n\x04_ttl\"\xe9\x01\n\x05State\x12;\n\tcomposite\x18\x01 \x01(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource\x12G\n\tresources\x18\x02 \x03(\x0b\x32\x34.apiextensions.fn.proto.v1beta1.State.ResourcesEntry\x1aZ\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x37\n\x05value\x18\x02 \x01(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource:\x02\x38\x01\"\x82\x02\n\x08Resource\x12)\n\x08resource\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12[\n\x12\x63onnection_details\x18\x02 \x03(\x0b\x32?.apiextensions.fn.proto.v1beta1.Resource.ConnectionDetailsEntry\x12\x34\n\x05ready\x18\x03 \x01(\x0e\x32%.apiextensions.fn.proto.v1beta1.Ready\x1a\x38\n\x16\x43onnectionDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"\xbd\x01\n\x06Result\x12:\n\x08severity\x18\x01 \x01(\x0e\x32(.apiextensions.fn.proto.v1beta1.Severity\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x13\n\x06reason\x18\x03 \x01(\tH\x00\x88\x01\x01\x12;\n\x06target\x18\x04 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.TargetH\x01\x88\x01\x01\x42\t\n\x07_reasonB\t\n\x07_target\"\xcb\x01\n\tCondition\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x36\n\x06status\x18\x02 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.Status\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x14\n\x07message\x18\x04 \x01(\tH\x00\x88\x01\x01\x12;\n\x06target\x18\x05 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.TargetH\x01\x88\x01\x01\x42\n\n\x08_messageB\t\n\x07_target*?\n\x05Ready\x12\x15\n\x11READY_UNSPECIFIED\x10\x00\x12\x0e\n\nREADY_TRUE\x10\x01\x12\x0f\n\x0bREADY_FALSE\x10\x02*c\n\x08Severity\x12\x18\n\x14SEVERITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eSEVERITY_FATAL\x10\x01\x12\x14\n\x10SEVERITY_WARNING\x10\x02\x12\x13\n\x0fSEVERITY_NORMAL\x10\x03*V\n\x06Target\x12\x16\n\x12TARGET_UNSPECIFIED\x10\x00\x12\x14\n\x10TARGET_COMPOSITE\x10\x01\x12\x1e\n\x1aTARGET_COMPOSITE_AND_CLAIM\x10\x02*\x7f\n\x06Status\x12 \n\x1cSTATUS_CONDITION_UNSPECIFIED\x10\x00\x12\x1c\n\x18STATUS_CONDITION_UNKNOWN\x10\x01\x12\x19\n\x15STATUS_CONDITION_TRUE\x10\x02\x12\x1a\n\x16STATUS_CONDITION_FALSE\x10\x03\x32\x91\x01\n\x15\x46unctionRunnerService\x12x\n\x0bRunFunction\x12\x32.apiextensions.fn.proto.v1beta1.RunFunctionRequest\x1a\x33.apiextensions.fn.proto.v1beta1.RunFunctionResponse\"\x00\x42\x36Z4github.com/crossplane/crossplane/v2/proto/fn/v1beta1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -40,6 +40,8 @@ _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_options = b'8\001' _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._loaded_options = None _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_options = b'8\001' + _globals['_RUNFUNCTIONREQUEST_REQUIREDSCHEMASENTRY']._loaded_options = None + _globals['_RUNFUNCTIONREQUEST_REQUIREDSCHEMASENTRY']._serialized_options = b'8\001' _globals['_RUNFUNCTIONREQUEST'].fields_by_name['extra_resources']._loaded_options = None _globals['_RUNFUNCTIONREQUEST'].fields_by_name['extra_resources']._serialized_options = b'\030\001' _globals['_CREDENTIALDATA_DATAENTRY']._loaded_options = None @@ -48,6 +50,8 @@ _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_options = b'8\001' _globals['_REQUIREMENTS_RESOURCESENTRY']._loaded_options = None _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_options = b'8\001' + _globals['_REQUIREMENTS_SCHEMASENTRY']._loaded_options = None + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_options = b'8\001' _globals['_REQUIREMENTS'].fields_by_name['extra_resources']._loaded_options = None _globals['_REQUIREMENTS'].fields_by_name['extra_resources']._serialized_options = b'\030\001' _globals['_MATCHLABELS_LABELSENTRY']._loaded_options = None @@ -56,60 +60,68 @@ _globals['_STATE_RESOURCESENTRY']._serialized_options = b'8\001' _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._loaded_options = None _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_options = b'8\001' - _globals['_READY']._serialized_start=3531 - _globals['_READY']._serialized_end=3594 - _globals['_SEVERITY']._serialized_start=3596 - _globals['_SEVERITY']._serialized_end=3695 - _globals['_TARGET']._serialized_start=3697 - _globals['_TARGET']._serialized_end=3783 - _globals['_STATUS']._serialized_start=3785 - _globals['_STATUS']._serialized_end=3912 + _globals['_READY']._serialized_start=4026 + _globals['_READY']._serialized_end=4089 + _globals['_SEVERITY']._serialized_start=4091 + _globals['_SEVERITY']._serialized_end=4190 + _globals['_TARGET']._serialized_start=4192 + _globals['_TARGET']._serialized_end=4278 + _globals['_STATUS']._serialized_start=4280 + _globals['_STATUS']._serialized_end=4407 _globals['_RUNFUNCTIONREQUEST']._serialized_start=151 - _globals['_RUNFUNCTIONREQUEST']._serialized_end=1047 - _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_start=731 - _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_end=827 - _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_start=829 - _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_end=924 - _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_start=926 - _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_end=1025 - _globals['_CREDENTIALS']._serialized_start=1049 - _globals['_CREDENTIALS']._serialized_end=1147 - _globals['_CREDENTIALDATA']._serialized_start=1150 - _globals['_CREDENTIALDATA']._serialized_end=1283 - _globals['_CREDENTIALDATA_DATAENTRY']._serialized_start=1240 - _globals['_CREDENTIALDATA_DATAENTRY']._serialized_end=1283 - _globals['_RESOURCES']._serialized_start=1285 - _globals['_RESOURCES']._serialized_end=1353 - _globals['_RUNFUNCTIONRESPONSE']._serialized_start=1356 - _globals['_RUNFUNCTIONRESPONSE']._serialized_end=1797 - _globals['_REQUESTMETA']._serialized_start=1799 - _globals['_REQUESTMETA']._serialized_end=1825 - _globals['_REQUIREMENTS']._serialized_start=1828 - _globals['_REQUIREMENTS']._serialized_end=2222 - _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_start=2019 - _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_end=2122 - _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_start=2124 - _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_end=2222 - _globals['_RESOURCESELECTOR']._serialized_start=2225 - _globals['_RESOURCESELECTOR']._serialized_end=2416 - _globals['_MATCHLABELS']._serialized_start=2419 - _globals['_MATCHLABELS']._serialized_end=2552 - _globals['_MATCHLABELS_LABELSENTRY']._serialized_start=2507 - _globals['_MATCHLABELS_LABELSENTRY']._serialized_end=2552 - _globals['_RESPONSEMETA']._serialized_start=2554 - _globals['_RESPONSEMETA']._serialized_end=2634 - _globals['_STATE']._serialized_start=2637 - _globals['_STATE']._serialized_end=2870 - _globals['_STATE_RESOURCESENTRY']._serialized_start=2780 - _globals['_STATE_RESOURCESENTRY']._serialized_end=2870 - _globals['_RESOURCE']._serialized_start=2873 - _globals['_RESOURCE']._serialized_end=3131 - _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_start=3075 - _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_end=3131 - _globals['_RESULT']._serialized_start=3134 - _globals['_RESULT']._serialized_end=3323 - _globals['_CONDITION']._serialized_start=3326 - _globals['_CONDITION']._serialized_end=3529 - _globals['_FUNCTIONRUNNERSERVICE']._serialized_start=3915 - _globals['_FUNCTIONRUNNERSERVICE']._serialized_end=4060 + _globals['_RUNFUNCTIONREQUEST']._serialized_end=1242 + _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_start=830 + _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_end=926 + _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_start=928 + _globals['_RUNFUNCTIONREQUEST_CREDENTIALSENTRY']._serialized_end=1023 + _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_start=1025 + _globals['_RUNFUNCTIONREQUEST_REQUIREDRESOURCESENTRY']._serialized_end=1124 + _globals['_RUNFUNCTIONREQUEST_REQUIREDSCHEMASENTRY']._serialized_start=1126 + _globals['_RUNFUNCTIONREQUEST_REQUIREDSCHEMASENTRY']._serialized_end=1220 + _globals['_CREDENTIALS']._serialized_start=1244 + _globals['_CREDENTIALS']._serialized_end=1342 + _globals['_CREDENTIALDATA']._serialized_start=1345 + _globals['_CREDENTIALDATA']._serialized_end=1478 + _globals['_CREDENTIALDATA_DATAENTRY']._serialized_start=1435 + _globals['_CREDENTIALDATA_DATAENTRY']._serialized_end=1478 + _globals['_RESOURCES']._serialized_start=1480 + _globals['_RESOURCES']._serialized_end=1548 + _globals['_RUNFUNCTIONRESPONSE']._serialized_start=1551 + _globals['_RUNFUNCTIONRESPONSE']._serialized_end=1992 + _globals['_REQUESTMETA']._serialized_start=1994 + _globals['_REQUESTMETA']._serialized_end=2020 + _globals['_REQUIREMENTS']._serialized_start=2023 + _globals['_REQUIREMENTS']._serialized_end=2589 + _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_start=2290 + _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_end=2393 + _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_start=2395 + _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_end=2493 + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_start=2495 + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_end=2589 + _globals['_SCHEMASELECTOR']._serialized_start=2591 + _globals['_SCHEMASELECTOR']._serialized_end=2642 + _globals['_SCHEMA']._serialized_start=2644 + _globals['_SCHEMA']._serialized_end=2717 + _globals['_RESOURCESELECTOR']._serialized_start=2720 + _globals['_RESOURCESELECTOR']._serialized_end=2911 + _globals['_MATCHLABELS']._serialized_start=2914 + _globals['_MATCHLABELS']._serialized_end=3047 + _globals['_MATCHLABELS_LABELSENTRY']._serialized_start=3002 + _globals['_MATCHLABELS_LABELSENTRY']._serialized_end=3047 + _globals['_RESPONSEMETA']._serialized_start=3049 + _globals['_RESPONSEMETA']._serialized_end=3129 + _globals['_STATE']._serialized_start=3132 + _globals['_STATE']._serialized_end=3365 + _globals['_STATE_RESOURCESENTRY']._serialized_start=3275 + _globals['_STATE_RESOURCESENTRY']._serialized_end=3365 + _globals['_RESOURCE']._serialized_start=3368 + _globals['_RESOURCE']._serialized_end=3626 + _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_start=3570 + _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_end=3626 + _globals['_RESULT']._serialized_start=3629 + _globals['_RESULT']._serialized_end=3818 + _globals['_CONDITION']._serialized_start=3821 + _globals['_CONDITION']._serialized_end=4024 + _globals['_FUNCTIONRUNNERSERVICE']._serialized_start=4410 + _globals['_FUNCTIONRUNNERSERVICE']._serialized_end=4555 # @@protoc_insertion_point(module_scope) diff --git a/crossplane/function/proto/v1beta1/run_function_pb2.pyi b/crossplane/function/proto/v1beta1/run_function_pb2.pyi index 534fe30..30ad04f 100644 --- a/crossplane/function/proto/v1beta1/run_function_pb2.pyi +++ b/crossplane/function/proto/v1beta1/run_function_pb2.pyi @@ -52,7 +52,7 @@ STATUS_CONDITION_TRUE: Status STATUS_CONDITION_FALSE: Status class RunFunctionRequest(_message.Message): - __slots__ = ("meta", "observed", "desired", "input", "context", "extra_resources", "credentials", "required_resources") + __slots__ = ("meta", "observed", "desired", "input", "context", "extra_resources", "credentials", "required_resources", "required_schemas") class ExtraResourcesEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -74,6 +74,13 @@ class RunFunctionRequest(_message.Message): key: str value: Resources def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Resources, _Mapping]] = ...) -> None: ... + class RequiredSchemasEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: Schema + def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Schema, _Mapping]] = ...) -> None: ... META_FIELD_NUMBER: _ClassVar[int] OBSERVED_FIELD_NUMBER: _ClassVar[int] DESIRED_FIELD_NUMBER: _ClassVar[int] @@ -82,6 +89,7 @@ class RunFunctionRequest(_message.Message): EXTRA_RESOURCES_FIELD_NUMBER: _ClassVar[int] CREDENTIALS_FIELD_NUMBER: _ClassVar[int] REQUIRED_RESOURCES_FIELD_NUMBER: _ClassVar[int] + REQUIRED_SCHEMAS_FIELD_NUMBER: _ClassVar[int] meta: RequestMeta observed: State desired: State @@ -90,7 +98,8 @@ class RunFunctionRequest(_message.Message): extra_resources: _containers.MessageMap[str, Resources] credentials: _containers.MessageMap[str, Credentials] required_resources: _containers.MessageMap[str, Resources] - def __init__(self, meta: _Optional[_Union[RequestMeta, _Mapping]] = ..., observed: _Optional[_Union[State, _Mapping]] = ..., desired: _Optional[_Union[State, _Mapping]] = ..., input: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., context: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., extra_resources: _Optional[_Mapping[str, Resources]] = ..., credentials: _Optional[_Mapping[str, Credentials]] = ..., required_resources: _Optional[_Mapping[str, Resources]] = ...) -> None: ... + required_schemas: _containers.MessageMap[str, Schema] + def __init__(self, meta: _Optional[_Union[RequestMeta, _Mapping]] = ..., observed: _Optional[_Union[State, _Mapping]] = ..., desired: _Optional[_Union[State, _Mapping]] = ..., input: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., context: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., extra_resources: _Optional[_Mapping[str, Resources]] = ..., credentials: _Optional[_Mapping[str, Credentials]] = ..., required_resources: _Optional[_Mapping[str, Resources]] = ..., required_schemas: _Optional[_Mapping[str, Schema]] = ...) -> None: ... class Credentials(_message.Message): __slots__ = ("credential_data",) @@ -142,7 +151,7 @@ class RequestMeta(_message.Message): def __init__(self, tag: _Optional[str] = ...) -> None: ... class Requirements(_message.Message): - __slots__ = ("extra_resources", "resources") + __slots__ = ("extra_resources", "resources", "schemas") class ExtraResourcesEntry(_message.Message): __slots__ = ("key", "value") KEY_FIELD_NUMBER: _ClassVar[int] @@ -157,11 +166,34 @@ class Requirements(_message.Message): key: str value: ResourceSelector def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[ResourceSelector, _Mapping]] = ...) -> None: ... + class SchemasEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: SchemaSelector + def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[SchemaSelector, _Mapping]] = ...) -> None: ... EXTRA_RESOURCES_FIELD_NUMBER: _ClassVar[int] RESOURCES_FIELD_NUMBER: _ClassVar[int] + SCHEMAS_FIELD_NUMBER: _ClassVar[int] extra_resources: _containers.MessageMap[str, ResourceSelector] resources: _containers.MessageMap[str, ResourceSelector] - def __init__(self, extra_resources: _Optional[_Mapping[str, ResourceSelector]] = ..., resources: _Optional[_Mapping[str, ResourceSelector]] = ...) -> None: ... + schemas: _containers.MessageMap[str, SchemaSelector] + def __init__(self, extra_resources: _Optional[_Mapping[str, ResourceSelector]] = ..., resources: _Optional[_Mapping[str, ResourceSelector]] = ..., schemas: _Optional[_Mapping[str, SchemaSelector]] = ...) -> None: ... + +class SchemaSelector(_message.Message): + __slots__ = ("api_version", "kind") + API_VERSION_FIELD_NUMBER: _ClassVar[int] + KIND_FIELD_NUMBER: _ClassVar[int] + api_version: str + kind: str + def __init__(self, api_version: _Optional[str] = ..., kind: _Optional[str] = ...) -> None: ... + +class Schema(_message.Message): + __slots__ = ("openapi_v3",) + OPENAPI_V3_FIELD_NUMBER: _ClassVar[int] + openapi_v3: _struct_pb2.Struct + def __init__(self, openapi_v3: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ... class ResourceSelector(_message.Message): __slots__ = ("api_version", "kind", "match_name", "match_labels", "namespace") diff --git a/crossplane/function/request.py b/crossplane/function/request.py index ad408c9..59c7695 100644 --- a/crossplane/function/request.py +++ b/crossplane/function/request.py @@ -41,6 +41,21 @@ def get_required_resources(req: fnv1.RunFunctionRequest, name: str) -> list[dict Required resources are previously called "extra resources" in composition functions. For operation functions, there are no observed resources, so all resources are "required" resources that the function requested. + + Note: This returns an empty list both when the requirement hasn't been + resolved yet, and when it was resolved but no resources matched. To + distinguish between these cases, check whether Crossplane resolved the + requirement using `name in req.required_resources`: + + # Always declare requirements - Crossplane considers them satisfied + # when they stabilize across calls. + response.require_resources(rsp, name, ...) + + if name in req.required_resources: + resources = request.get_required_resources(req, name) + if not resources: + # Crossplane resolved the requirement, but found no matches + response.fatal(rsp, "no matching resources found") """ if name not in req.required_resources: return [] @@ -116,3 +131,46 @@ def get_credentials(req: fnv1.RunFunctionRequest, name: str) -> Credentials: # If no recognized source type is set, return empty return empty + + +def get_required_schema(req: fnv1.RunFunctionRequest, name: str) -> dict | None: + """Get a required OpenAPI schema by name from the request. + + Args: + req: The RunFunctionRequest containing required schemas. + name: The name of the required schema to get. + + Returns: + The OpenAPI v3 schema as a dictionary, or None if not found. + + Note: This returns None both when the requirement hasn't been resolved yet, + and when it was resolved but the schema wasn't found. To distinguish between + these cases, check whether Crossplane resolved the requirement using + `name in req.required_schemas`: + + # Always declare requirements - Crossplane considers them satisfied + # when they stabilize across calls. + response.require_schema(rsp, name, "example.org/v1", "MyKind") + + if name in req.required_schemas: + schema = request.get_required_schema(req, name) + if schema is None: + # Crossplane resolved the requirement, but couldn't find it + response.fatal(rsp, "schema not found") + + The returned schema can be used with libraries like openapi-schema-validator + or jsonschema for validation: + + schema = request.get_required_schema(req, "my-schema") + if schema: + from openapi_schema_validator import validate + validate(resource, schema) + """ + if name not in req.required_schemas: + return None + + schema = req.required_schemas[name] + if not schema.HasField("openapi_v3"): + return None + + return resource.struct_to_dict(schema.openapi_v3) diff --git a/crossplane/function/response.py b/crossplane/function/response.py index 72222b6..5392d36 100644 --- a/crossplane/function/response.py +++ b/crossplane/function/response.py @@ -149,3 +149,32 @@ def require_resources( # noqa: PLR0913 selector.namespace = namespace rsp.requirements.resources[name].CopyFrom(selector) + + +def require_schema( + rsp: fnv1.RunFunctionResponse, + name: str, + api_version: str, + kind: str, +) -> None: + """Add a schema requirement to the response. + + Args: + rsp: The RunFunctionResponse to update. + name: The name to use for this requirement. + api_version: The API version of the resource kind, e.g. "example.org/v1". + kind: The kind of resource, e.g. "MyResource". + + This tells Crossplane to fetch the OpenAPI schema for the specified resource + kind and include it in the next call to the function in + req.required_schemas[name]. Use request.get_required_schema to retrieve it. + + For CRDs, Crossplane returns the spec.versions[].schema.openAPIV3Schema field. + If Crossplane cannot find a schema for the requested kind, the schema will be + empty (get_required_schema will return None). + """ + selector = fnv1.SchemaSelector( + api_version=api_version, + kind=kind, + ) + rsp.requirements.schemas[name].CopyFrom(selector) diff --git a/tests/test_request.py b/tests/test_request.py index a517814..0e497ba 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -264,6 +264,71 @@ class TestCase: dataclasses.asdict(case.want), dataclasses.asdict(got), case.reason ) + def test_get_required_schema(self) -> None: + @dataclasses.dataclass + class TestCase: + reason: str + req: fnv1.RunFunctionRequest + name: str + want: dict | None + + cases = [ + TestCase( + reason="Should return None when schema name not found.", + req=fnv1.RunFunctionRequest(), + name="non-existent", + want=None, + ), + TestCase( + reason="Should return None when schema exists but is empty.", + req=fnv1.RunFunctionRequest( + required_schemas={ + "empty-schema": fnv1.Schema(), + } + ), + name="empty-schema", + want=None, + ), + TestCase( + reason="Should return schema when it exists.", + req=fnv1.RunFunctionRequest( + required_schemas={ + "my-schema": fnv1.Schema( + openapi_v3=resource.dict_to_struct( + { + "type": "object", + "properties": { + "spec": { + "type": "object", + "properties": { + "replicas": {"type": "integer"}, + }, + }, + }, + } + ) + ), + } + ), + name="my-schema", + want={ + "type": "object", + "properties": { + "spec": { + "type": "object", + "properties": { + "replicas": {"type": "integer"}, + }, + }, + }, + }, + ), + ] + + for case in cases: + got = request.get_required_schema(case.req, case.name) + self.assertEqual(case.want, got, case.reason) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_response.py b/tests/test_response.py index 9e33153..763a37f 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -215,6 +215,59 @@ def test_require_resources_invalid_args(self) -> None: match_labels=None, ) + def test_require_schema(self) -> None: + @dataclasses.dataclass + class TestCase: + reason: str + rsp: fnv1.RunFunctionResponse + name: str + api_version: str + kind: str + want_selector: fnv1.SchemaSelector + + cases = [ + TestCase( + reason="Should create schema requirement.", + rsp=fnv1.RunFunctionResponse(), + name="bucket-schema", + api_version="s3.aws.upbound.io/v1beta2", + kind="Bucket", + want_selector=fnv1.SchemaSelector( + api_version="s3.aws.upbound.io/v1beta2", + kind="Bucket", + ), + ), + TestCase( + reason="Should create schema requirement for core types.", + rsp=fnv1.RunFunctionResponse(), + name="pod-schema", + api_version="v1", + kind="Pod", + want_selector=fnv1.SchemaSelector( + api_version="v1", + kind="Pod", + ), + ), + ] + + for case in cases: + response.require_schema( + case.rsp, + case.name, + case.api_version, + case.kind, + ) + + # Check that the requirement was added + self.assertIn(case.name, case.rsp.requirements.schemas, case.reason) + got_selector = case.rsp.requirements.schemas[case.name] + + self.assertEqual( + json_format.MessageToJson(case.want_selector, sort_keys=True), + json_format.MessageToJson(got_selector, sort_keys=True), + case.reason, + ) + if __name__ == "__main__": unittest.main() From d726ccaaecdfd2f54400dd231222121ec8f53ad2 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Thu, 5 Feb 2026 15:28:00 -0800 Subject: [PATCH 2/3] Add support for capability detection Crossplane v2.2 introduces capability advertisement. Crossplane sends the capabilities it supports in the request metadata, allowing functions to detect whether the calling Crossplane will honor particular request or response fields (e.g. schema requirements, conditions). This commit updates the protos to include the new Capability enum and RequestMeta.capabilities field, and adds a request.has_capability helper that checks whether a specific capability is present. Signed-off-by: Nic Cope --- .../function/proto/v1/run_function.proto | 40 ++++++++- .../function/proto/v1/run_function_pb2.py | 90 ++++++++++--------- .../function/proto/v1/run_function_pb2.pyi | 21 ++++- .../function/proto/v1beta1/run_function.proto | 40 ++++++++- .../proto/v1beta1/run_function_pb2.py | 90 ++++++++++--------- .../proto/v1beta1/run_function_pb2.pyi | 21 ++++- crossplane/function/request.py | 27 ++++++ tests/test_request.py | 47 ++++++++++ 8 files changed, 282 insertions(+), 94 deletions(-) diff --git a/crossplane/function/proto/v1/run_function.proto b/crossplane/function/proto/v1/run_function.proto index 4c3d092..e58a4b5 100644 --- a/crossplane/function/proto/v1/run_function.proto +++ b/crossplane/function/proto/v1/run_function.proto @@ -163,6 +163,44 @@ message RequestMeta { // An opaque string identifying a request. Requests with identical tags will // be otherwise identical. string tag = 1; + + // Capabilities supported by this version of Crossplane. Functions may use + // this to determine whether Crossplane will honor certain fields in their + // response, or populate certain fields in their request. + repeated Capability capabilities = 2; +} + +// Capability indicates that Crossplane supports a particular feature. +// Functions can check for capabilities to determine whether Crossplane will +// honor a particular request or response field. +enum Capability { + CAPABILITY_UNSPECIFIED = 0; + + // Crossplane sends capabilities in RequestMeta. If this capability is + // present, the function knows that if another capability is absent, it's + // because Crossplane doesn't support it (not because Crossplane predates + // capability advertisement). Added in Crossplane v2.2. + CAPABILITY_CAPABILITIES = 1; + + // Crossplane supports the requirements.resources field. Functions can return + // resource requirements and Crossplane will fetch the requested resources and + // return them in required_resources. Added in Crossplane v1.15. + CAPABILITY_REQUIRED_RESOURCES = 2; + + // Crossplane supports the credentials field. Functions can receive + // credentials from secrets specified in the Composition. Added in Crossplane + // v1.16. + CAPABILITY_CREDENTIALS = 3; + + // Crossplane supports the conditions field. Functions can return status + // conditions to be applied to the XR and optionally its claim. Added in + // Crossplane v1.17. + CAPABILITY_CONDITIONS = 4; + + // Crossplane supports the requirements.schemas field. Functions can request + // OpenAPI schemas and Crossplane will return them in required_schemas. Added + // in Crossplane v2.2. + CAPABILITY_REQUIRED_SCHEMAS = 5; } // Requirements that must be satisfied for a function to run successfully. @@ -295,7 +333,7 @@ message Resource { // * A function should set this field to READY_TRUE in a RunFunctionResponse // to indicate that a desired XR is ready. This overwrites the standard // readiness detection that determines the ready state of the composite by the - // ready state of the the composed resources. + // ready state of the composed resources. // // Ready is only used for composition. It's ignored by Operations. Ready ready = 3; diff --git a/crossplane/function/proto/v1/run_function_pb2.py b/crossplane/function/proto/v1/run_function_pb2.py index 27506ae..5fe00b0 100644 --- a/crossplane/function/proto/v1/run_function_pb2.py +++ b/crossplane/function/proto/v1/run_function_pb2.py @@ -26,7 +26,7 @@ from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n/crossplane/function/proto/v1/run_function.proto\x12\x19\x61piextensions.fn.proto.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x8c\x08\n\x12RunFunctionRequest\x12\x34\n\x04meta\x18\x01 \x01(\x0b\x32&.apiextensions.fn.proto.v1.RequestMeta\x12\x32\n\x08observed\x18\x02 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12\x31\n\x07\x64\x65sired\x18\x03 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12-\n\x07\x63ontext\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x12^\n\x0f\x65xtra_resources\x18\x06 \x03(\x0b\x32\x41.apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntryB\x02\x18\x01\x12S\n\x0b\x63redentials\x18\x07 \x03(\x0b\x32>.apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry\x12`\n\x12required_resources\x18\x08 \x03(\x0b\x32\x44.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry\x12\\\n\x10required_schemas\x18\t \x03(\x0b\x32\x42.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntry\x1a[\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x33\n\x05value\x18\x02 \x01(\x0b\x32$.apiextensions.fn.proto.v1.Resources:\x02\x38\x01\x1aZ\n\x10\x43redentialsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.apiextensions.fn.proto.v1.Credentials:\x02\x38\x01\x1a^\n\x16RequiredResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x33\n\x05value\x18\x02 \x01(\x0b\x32$.apiextensions.fn.proto.v1.Resources:\x02\x38\x01\x1aY\n\x14RequiredSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x30\n\x05value\x18\x02 \x01(\x0b\x32!.apiextensions.fn.proto.v1.Schema:\x02\x38\x01\x42\x08\n\x06_inputB\n\n\x08_context\"]\n\x0b\x43redentials\x12\x44\n\x0f\x63redential_data\x18\x01 \x01(\x0b\x32).apiextensions.fn.proto.v1.CredentialDataH\x00\x42\x08\n\x06source\"\x80\x01\n\x0e\x43redentialData\x12\x41\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x33.apiextensions.fn.proto.v1.CredentialData.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"?\n\tResources\x12\x32\n\x05items\x18\x01 \x03(\x0b\x32#.apiextensions.fn.proto.v1.Resource\"\xa0\x03\n\x13RunFunctionResponse\x12\x35\n\x04meta\x18\x01 \x01(\x0b\x32\'.apiextensions.fn.proto.v1.ResponseMeta\x12\x31\n\x07\x64\x65sired\x18\x02 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12\x32\n\x07results\x18\x03 \x03(\x0b\x32!.apiextensions.fn.proto.v1.Result\x12-\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12=\n\x0crequirements\x18\x05 \x01(\x0b\x32\'.apiextensions.fn.proto.v1.Requirements\x12\x38\n\nconditions\x18\x06 \x03(\x0b\x32$.apiextensions.fn.proto.v1.Condition\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x42\n\n\x08_contextB\t\n\x07_output\"\x1a\n\x0bRequestMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\"\x98\x04\n\x0cRequirements\x12X\n\x0f\x65xtra_resources\x18\x01 \x03(\x0b\x32;.apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntryB\x02\x18\x01\x12I\n\tresources\x18\x02 \x03(\x0b\x32\x36.apiextensions.fn.proto.v1.Requirements.ResourcesEntry\x12\x45\n\x07schemas\x18\x03 \x03(\x0b\x32\x34.apiextensions.fn.proto.v1.Requirements.SchemasEntry\x1a\x62\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1.ResourceSelector:\x02\x38\x01\x1a]\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1.ResourceSelector:\x02\x38\x01\x1aY\n\x0cSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1.SchemaSelector:\x02\x38\x01\"3\n\x0eSchemaSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\"I\n\x06Schema\x12\x30\n\nopenapi_v3\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x42\r\n\x0b_openapi_v3\"\xba\x01\n\x10ResourceSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x14\n\nmatch_name\x18\x03 \x01(\tH\x00\x12>\n\x0cmatch_labels\x18\x04 \x01(\x0b\x32&.apiextensions.fn.proto.v1.MatchLabelsH\x00\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05matchB\x0c\n\n_namespace\"\x80\x01\n\x0bMatchLabels\x12\x42\n\x06labels\x18\x01 \x03(\x0b\x32\x32.apiextensions.fn.proto.v1.MatchLabels.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"P\n\x0cResponseMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12+\n\x03ttl\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x88\x01\x01\x42\x06\n\x04_ttl\"\xda\x01\n\x05State\x12\x36\n\tcomposite\x18\x01 \x01(\x0b\x32#.apiextensions.fn.proto.v1.Resource\x12\x42\n\tresources\x18\x02 \x03(\x0b\x32/.apiextensions.fn.proto.v1.State.ResourcesEntry\x1aU\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32#.apiextensions.fn.proto.v1.Resource:\x02\x38\x01\"\xf8\x01\n\x08Resource\x12)\n\x08resource\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12V\n\x12\x63onnection_details\x18\x02 \x03(\x0b\x32:.apiextensions.fn.proto.v1.Resource.ConnectionDetailsEntry\x12/\n\x05ready\x18\x03 \x01(\x0e\x32 .apiextensions.fn.proto.v1.Ready\x1a\x38\n\x16\x43onnectionDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"\xb3\x01\n\x06Result\x12\x35\n\x08severity\x18\x01 \x01(\x0e\x32#.apiextensions.fn.proto.v1.Severity\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x13\n\x06reason\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x36\n\x06target\x18\x04 \x01(\x0e\x32!.apiextensions.fn.proto.v1.TargetH\x01\x88\x01\x01\x42\t\n\x07_reasonB\t\n\x07_target\"\xc1\x01\n\tCondition\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x31\n\x06status\x18\x02 \x01(\x0e\x32!.apiextensions.fn.proto.v1.Status\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x14\n\x07message\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x36\n\x06target\x18\x05 \x01(\x0e\x32!.apiextensions.fn.proto.v1.TargetH\x01\x88\x01\x01\x42\n\n\x08_messageB\t\n\x07_target*?\n\x05Ready\x12\x15\n\x11READY_UNSPECIFIED\x10\x00\x12\x0e\n\nREADY_TRUE\x10\x01\x12\x0f\n\x0bREADY_FALSE\x10\x02*c\n\x08Severity\x12\x18\n\x14SEVERITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eSEVERITY_FATAL\x10\x01\x12\x14\n\x10SEVERITY_WARNING\x10\x02\x12\x13\n\x0fSEVERITY_NORMAL\x10\x03*V\n\x06Target\x12\x16\n\x12TARGET_UNSPECIFIED\x10\x00\x12\x14\n\x10TARGET_COMPOSITE\x10\x01\x12\x1e\n\x1aTARGET_COMPOSITE_AND_CLAIM\x10\x02*\x7f\n\x06Status\x12 \n\x1cSTATUS_CONDITION_UNSPECIFIED\x10\x00\x12\x1c\n\x18STATUS_CONDITION_UNKNOWN\x10\x01\x12\x19\n\x15STATUS_CONDITION_TRUE\x10\x02\x12\x1a\n\x16STATUS_CONDITION_FALSE\x10\x03\x32\x87\x01\n\x15\x46unctionRunnerService\x12n\n\x0bRunFunction\x12-.apiextensions.fn.proto.v1.RunFunctionRequest\x1a..apiextensions.fn.proto.v1.RunFunctionResponse\"\x00\x42\x31Z/github.com/crossplane/crossplane/v2/proto/fn/v1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n/crossplane/function/proto/v1/run_function.proto\x12\x19\x61piextensions.fn.proto.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x8c\x08\n\x12RunFunctionRequest\x12\x34\n\x04meta\x18\x01 \x01(\x0b\x32&.apiextensions.fn.proto.v1.RequestMeta\x12\x32\n\x08observed\x18\x02 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12\x31\n\x07\x64\x65sired\x18\x03 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12-\n\x07\x63ontext\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x12^\n\x0f\x65xtra_resources\x18\x06 \x03(\x0b\x32\x41.apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntryB\x02\x18\x01\x12S\n\x0b\x63redentials\x18\x07 \x03(\x0b\x32>.apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry\x12`\n\x12required_resources\x18\x08 \x03(\x0b\x32\x44.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry\x12\\\n\x10required_schemas\x18\t \x03(\x0b\x32\x42.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntry\x1a[\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x33\n\x05value\x18\x02 \x01(\x0b\x32$.apiextensions.fn.proto.v1.Resources:\x02\x38\x01\x1aZ\n\x10\x43redentialsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.apiextensions.fn.proto.v1.Credentials:\x02\x38\x01\x1a^\n\x16RequiredResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x33\n\x05value\x18\x02 \x01(\x0b\x32$.apiextensions.fn.proto.v1.Resources:\x02\x38\x01\x1aY\n\x14RequiredSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x30\n\x05value\x18\x02 \x01(\x0b\x32!.apiextensions.fn.proto.v1.Schema:\x02\x38\x01\x42\x08\n\x06_inputB\n\n\x08_context\"]\n\x0b\x43redentials\x12\x44\n\x0f\x63redential_data\x18\x01 \x01(\x0b\x32).apiextensions.fn.proto.v1.CredentialDataH\x00\x42\x08\n\x06source\"\x80\x01\n\x0e\x43redentialData\x12\x41\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x33.apiextensions.fn.proto.v1.CredentialData.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"?\n\tResources\x12\x32\n\x05items\x18\x01 \x03(\x0b\x32#.apiextensions.fn.proto.v1.Resource\"\xa0\x03\n\x13RunFunctionResponse\x12\x35\n\x04meta\x18\x01 \x01(\x0b\x32\'.apiextensions.fn.proto.v1.ResponseMeta\x12\x31\n\x07\x64\x65sired\x18\x02 \x01(\x0b\x32 .apiextensions.fn.proto.v1.State\x12\x32\n\x07results\x18\x03 \x03(\x0b\x32!.apiextensions.fn.proto.v1.Result\x12-\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12=\n\x0crequirements\x18\x05 \x01(\x0b\x32\'.apiextensions.fn.proto.v1.Requirements\x12\x38\n\nconditions\x18\x06 \x03(\x0b\x32$.apiextensions.fn.proto.v1.Condition\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x42\n\n\x08_contextB\t\n\x07_output\"W\n\x0bRequestMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12;\n\x0c\x63\x61pabilities\x18\x02 \x03(\x0e\x32%.apiextensions.fn.proto.v1.Capability\"\x98\x04\n\x0cRequirements\x12X\n\x0f\x65xtra_resources\x18\x01 \x03(\x0b\x32;.apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntryB\x02\x18\x01\x12I\n\tresources\x18\x02 \x03(\x0b\x32\x36.apiextensions.fn.proto.v1.Requirements.ResourcesEntry\x12\x45\n\x07schemas\x18\x03 \x03(\x0b\x32\x34.apiextensions.fn.proto.v1.Requirements.SchemasEntry\x1a\x62\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1.ResourceSelector:\x02\x38\x01\x1a]\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1.ResourceSelector:\x02\x38\x01\x1aY\n\x0cSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1.SchemaSelector:\x02\x38\x01\"3\n\x0eSchemaSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\"I\n\x06Schema\x12\x30\n\nopenapi_v3\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x42\r\n\x0b_openapi_v3\"\xba\x01\n\x10ResourceSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x14\n\nmatch_name\x18\x03 \x01(\tH\x00\x12>\n\x0cmatch_labels\x18\x04 \x01(\x0b\x32&.apiextensions.fn.proto.v1.MatchLabelsH\x00\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05matchB\x0c\n\n_namespace\"\x80\x01\n\x0bMatchLabels\x12\x42\n\x06labels\x18\x01 \x03(\x0b\x32\x32.apiextensions.fn.proto.v1.MatchLabels.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"P\n\x0cResponseMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12+\n\x03ttl\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x88\x01\x01\x42\x06\n\x04_ttl\"\xda\x01\n\x05State\x12\x36\n\tcomposite\x18\x01 \x01(\x0b\x32#.apiextensions.fn.proto.v1.Resource\x12\x42\n\tresources\x18\x02 \x03(\x0b\x32/.apiextensions.fn.proto.v1.State.ResourcesEntry\x1aU\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x32\n\x05value\x18\x02 \x01(\x0b\x32#.apiextensions.fn.proto.v1.Resource:\x02\x38\x01\"\xf8\x01\n\x08Resource\x12)\n\x08resource\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12V\n\x12\x63onnection_details\x18\x02 \x03(\x0b\x32:.apiextensions.fn.proto.v1.Resource.ConnectionDetailsEntry\x12/\n\x05ready\x18\x03 \x01(\x0e\x32 .apiextensions.fn.proto.v1.Ready\x1a\x38\n\x16\x43onnectionDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"\xb3\x01\n\x06Result\x12\x35\n\x08severity\x18\x01 \x01(\x0e\x32#.apiextensions.fn.proto.v1.Severity\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x13\n\x06reason\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x36\n\x06target\x18\x04 \x01(\x0e\x32!.apiextensions.fn.proto.v1.TargetH\x01\x88\x01\x01\x42\t\n\x07_reasonB\t\n\x07_target\"\xc1\x01\n\tCondition\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x31\n\x06status\x18\x02 \x01(\x0e\x32!.apiextensions.fn.proto.v1.Status\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x14\n\x07message\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x36\n\x06target\x18\x05 \x01(\x0e\x32!.apiextensions.fn.proto.v1.TargetH\x01\x88\x01\x01\x42\n\n\x08_messageB\t\n\x07_target*\xc0\x01\n\nCapability\x12\x1a\n\x16\x43\x41PABILITY_UNSPECIFIED\x10\x00\x12\x1b\n\x17\x43\x41PABILITY_CAPABILITIES\x10\x01\x12!\n\x1d\x43\x41PABILITY_REQUIRED_RESOURCES\x10\x02\x12\x1a\n\x16\x43\x41PABILITY_CREDENTIALS\x10\x03\x12\x19\n\x15\x43\x41PABILITY_CONDITIONS\x10\x04\x12\x1f\n\x1b\x43\x41PABILITY_REQUIRED_SCHEMAS\x10\x05*?\n\x05Ready\x12\x15\n\x11READY_UNSPECIFIED\x10\x00\x12\x0e\n\nREADY_TRUE\x10\x01\x12\x0f\n\x0bREADY_FALSE\x10\x02*c\n\x08Severity\x12\x18\n\x14SEVERITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eSEVERITY_FATAL\x10\x01\x12\x14\n\x10SEVERITY_WARNING\x10\x02\x12\x13\n\x0fSEVERITY_NORMAL\x10\x03*V\n\x06Target\x12\x16\n\x12TARGET_UNSPECIFIED\x10\x00\x12\x14\n\x10TARGET_COMPOSITE\x10\x01\x12\x1e\n\x1aTARGET_COMPOSITE_AND_CLAIM\x10\x02*\x7f\n\x06Status\x12 \n\x1cSTATUS_CONDITION_UNSPECIFIED\x10\x00\x12\x1c\n\x18STATUS_CONDITION_UNKNOWN\x10\x01\x12\x19\n\x15STATUS_CONDITION_TRUE\x10\x02\x12\x1a\n\x16STATUS_CONDITION_FALSE\x10\x03\x32\x87\x01\n\x15\x46unctionRunnerService\x12n\n\x0bRunFunction\x12-.apiextensions.fn.proto.v1.RunFunctionRequest\x1a..apiextensions.fn.proto.v1.RunFunctionResponse\"\x00\x42\x31Z/github.com/crossplane/crossplane/v2/proto/fn/v1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -60,14 +60,16 @@ _globals['_STATE_RESOURCESENTRY']._serialized_options = b'8\001' _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._loaded_options = None _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_options = b'8\001' - _globals['_READY']._serialized_start=3836 - _globals['_READY']._serialized_end=3899 - _globals['_SEVERITY']._serialized_start=3901 - _globals['_SEVERITY']._serialized_end=4000 - _globals['_TARGET']._serialized_start=4002 - _globals['_TARGET']._serialized_end=4088 - _globals['_STATUS']._serialized_start=4090 - _globals['_STATUS']._serialized_end=4217 + _globals['_CAPABILITY']._serialized_start=3898 + _globals['_CAPABILITY']._serialized_end=4090 + _globals['_READY']._serialized_start=4092 + _globals['_READY']._serialized_end=4155 + _globals['_SEVERITY']._serialized_start=4157 + _globals['_SEVERITY']._serialized_end=4256 + _globals['_TARGET']._serialized_start=4258 + _globals['_TARGET']._serialized_end=4344 + _globals['_STATUS']._serialized_start=4346 + _globals['_STATUS']._serialized_end=4473 _globals['_RUNFUNCTIONREQUEST']._serialized_start=141 _globals['_RUNFUNCTIONREQUEST']._serialized_end=1177 _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_start=785 @@ -89,39 +91,39 @@ _globals['_RUNFUNCTIONRESPONSE']._serialized_start=1471 _globals['_RUNFUNCTIONRESPONSE']._serialized_end=1887 _globals['_REQUESTMETA']._serialized_start=1889 - _globals['_REQUESTMETA']._serialized_end=1915 - _globals['_REQUIREMENTS']._serialized_start=1918 - _globals['_REQUIREMENTS']._serialized_end=2454 - _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_start=2170 - _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_end=2268 - _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_start=2270 - _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_end=2363 - _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_start=2365 - _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_end=2454 - _globals['_SCHEMASELECTOR']._serialized_start=2456 - _globals['_SCHEMASELECTOR']._serialized_end=2507 - _globals['_SCHEMA']._serialized_start=2509 - _globals['_SCHEMA']._serialized_end=2582 - _globals['_RESOURCESELECTOR']._serialized_start=2585 - _globals['_RESOURCESELECTOR']._serialized_end=2771 - _globals['_MATCHLABELS']._serialized_start=2774 - _globals['_MATCHLABELS']._serialized_end=2902 - _globals['_MATCHLABELS_LABELSENTRY']._serialized_start=2857 - _globals['_MATCHLABELS_LABELSENTRY']._serialized_end=2902 - _globals['_RESPONSEMETA']._serialized_start=2904 - _globals['_RESPONSEMETA']._serialized_end=2984 - _globals['_STATE']._serialized_start=2987 - _globals['_STATE']._serialized_end=3205 - _globals['_STATE_RESOURCESENTRY']._serialized_start=3120 - _globals['_STATE_RESOURCESENTRY']._serialized_end=3205 - _globals['_RESOURCE']._serialized_start=3208 - _globals['_RESOURCE']._serialized_end=3456 - _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_start=3400 - _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_end=3456 - _globals['_RESULT']._serialized_start=3459 - _globals['_RESULT']._serialized_end=3638 - _globals['_CONDITION']._serialized_start=3641 - _globals['_CONDITION']._serialized_end=3834 - _globals['_FUNCTIONRUNNERSERVICE']._serialized_start=4220 - _globals['_FUNCTIONRUNNERSERVICE']._serialized_end=4355 + _globals['_REQUESTMETA']._serialized_end=1976 + _globals['_REQUIREMENTS']._serialized_start=1979 + _globals['_REQUIREMENTS']._serialized_end=2515 + _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_start=2231 + _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_end=2329 + _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_start=2331 + _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_end=2424 + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_start=2426 + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_end=2515 + _globals['_SCHEMASELECTOR']._serialized_start=2517 + _globals['_SCHEMASELECTOR']._serialized_end=2568 + _globals['_SCHEMA']._serialized_start=2570 + _globals['_SCHEMA']._serialized_end=2643 + _globals['_RESOURCESELECTOR']._serialized_start=2646 + _globals['_RESOURCESELECTOR']._serialized_end=2832 + _globals['_MATCHLABELS']._serialized_start=2835 + _globals['_MATCHLABELS']._serialized_end=2963 + _globals['_MATCHLABELS_LABELSENTRY']._serialized_start=2918 + _globals['_MATCHLABELS_LABELSENTRY']._serialized_end=2963 + _globals['_RESPONSEMETA']._serialized_start=2965 + _globals['_RESPONSEMETA']._serialized_end=3045 + _globals['_STATE']._serialized_start=3048 + _globals['_STATE']._serialized_end=3266 + _globals['_STATE_RESOURCESENTRY']._serialized_start=3181 + _globals['_STATE_RESOURCESENTRY']._serialized_end=3266 + _globals['_RESOURCE']._serialized_start=3269 + _globals['_RESOURCE']._serialized_end=3517 + _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_start=3461 + _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_end=3517 + _globals['_RESULT']._serialized_start=3520 + _globals['_RESULT']._serialized_end=3699 + _globals['_CONDITION']._serialized_start=3702 + _globals['_CONDITION']._serialized_end=3895 + _globals['_FUNCTIONRUNNERSERVICE']._serialized_start=4476 + _globals['_FUNCTIONRUNNERSERVICE']._serialized_end=4611 # @@protoc_insertion_point(module_scope) diff --git a/crossplane/function/proto/v1/run_function_pb2.pyi b/crossplane/function/proto/v1/run_function_pb2.pyi index 30ad04f..d0d29ca 100644 --- a/crossplane/function/proto/v1/run_function_pb2.pyi +++ b/crossplane/function/proto/v1/run_function_pb2.pyi @@ -11,6 +11,15 @@ from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union DESCRIPTOR: _descriptor.FileDescriptor +class Capability(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + CAPABILITY_UNSPECIFIED: _ClassVar[Capability] + CAPABILITY_CAPABILITIES: _ClassVar[Capability] + CAPABILITY_REQUIRED_RESOURCES: _ClassVar[Capability] + CAPABILITY_CREDENTIALS: _ClassVar[Capability] + CAPABILITY_CONDITIONS: _ClassVar[Capability] + CAPABILITY_REQUIRED_SCHEMAS: _ClassVar[Capability] + class Ready(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): __slots__ = () READY_UNSPECIFIED: _ClassVar[Ready] @@ -36,6 +45,12 @@ class Status(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): STATUS_CONDITION_UNKNOWN: _ClassVar[Status] STATUS_CONDITION_TRUE: _ClassVar[Status] STATUS_CONDITION_FALSE: _ClassVar[Status] +CAPABILITY_UNSPECIFIED: Capability +CAPABILITY_CAPABILITIES: Capability +CAPABILITY_REQUIRED_RESOURCES: Capability +CAPABILITY_CREDENTIALS: Capability +CAPABILITY_CONDITIONS: Capability +CAPABILITY_REQUIRED_SCHEMAS: Capability READY_UNSPECIFIED: Ready READY_TRUE: Ready READY_FALSE: Ready @@ -145,10 +160,12 @@ class RunFunctionResponse(_message.Message): def __init__(self, meta: _Optional[_Union[ResponseMeta, _Mapping]] = ..., desired: _Optional[_Union[State, _Mapping]] = ..., results: _Optional[_Iterable[_Union[Result, _Mapping]]] = ..., context: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., requirements: _Optional[_Union[Requirements, _Mapping]] = ..., conditions: _Optional[_Iterable[_Union[Condition, _Mapping]]] = ..., output: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ... class RequestMeta(_message.Message): - __slots__ = ("tag",) + __slots__ = ("tag", "capabilities") TAG_FIELD_NUMBER: _ClassVar[int] + CAPABILITIES_FIELD_NUMBER: _ClassVar[int] tag: str - def __init__(self, tag: _Optional[str] = ...) -> None: ... + capabilities: _containers.RepeatedScalarFieldContainer[Capability] + def __init__(self, tag: _Optional[str] = ..., capabilities: _Optional[_Iterable[_Union[Capability, str]]] = ...) -> None: ... class Requirements(_message.Message): __slots__ = ("extra_resources", "resources", "schemas") diff --git a/crossplane/function/proto/v1beta1/run_function.proto b/crossplane/function/proto/v1beta1/run_function.proto index 2815d5b..667c740 100644 --- a/crossplane/function/proto/v1beta1/run_function.proto +++ b/crossplane/function/proto/v1beta1/run_function.proto @@ -165,6 +165,44 @@ message RequestMeta { // An opaque string identifying a request. Requests with identical tags will // be otherwise identical. string tag = 1; + + // Capabilities supported by this version of Crossplane. Functions may use + // this to determine whether Crossplane will honor certain fields in their + // response, or populate certain fields in their request. + repeated Capability capabilities = 2; +} + +// Capability indicates that Crossplane supports a particular feature. +// Functions can check for capabilities to determine whether Crossplane will +// honor a particular request or response field. +enum Capability { + CAPABILITY_UNSPECIFIED = 0; + + // Crossplane sends capabilities in RequestMeta. If this capability is + // present, the function knows that if another capability is absent, it's + // because Crossplane doesn't support it (not because Crossplane predates + // capability advertisement). Added in Crossplane v2.2. + CAPABILITY_CAPABILITIES = 1; + + // Crossplane supports the requirements.resources field. Functions can return + // resource requirements and Crossplane will fetch the requested resources and + // return them in required_resources. Added in Crossplane v1.15. + CAPABILITY_REQUIRED_RESOURCES = 2; + + // Crossplane supports the credentials field. Functions can receive + // credentials from secrets specified in the Composition. Added in Crossplane + // v1.16. + CAPABILITY_CREDENTIALS = 3; + + // Crossplane supports the conditions field. Functions can return status + // conditions to be applied to the XR and optionally its claim. Added in + // Crossplane v1.17. + CAPABILITY_CONDITIONS = 4; + + // Crossplane supports the requirements.schemas field. Functions can request + // OpenAPI schemas and Crossplane will return them in required_schemas. Added + // in Crossplane v2.2. + CAPABILITY_REQUIRED_SCHEMAS = 5; } // Requirements that must be satisfied for a function to run successfully. @@ -297,7 +335,7 @@ message Resource { // * A function should set this field to READY_TRUE in a RunFunctionResponse // to indicate that a desired XR is ready. This overwrites the standard // readiness detection that determines the ready state of the composite by the - // ready state of the the composed resources. + // ready state of the composed resources. // // Ready is only used for composition. It's ignored by Operations. Ready ready = 3; diff --git a/crossplane/function/proto/v1beta1/run_function_pb2.py b/crossplane/function/proto/v1beta1/run_function_pb2.py index 8e23ac4..3f3ebd4 100644 --- a/crossplane/function/proto/v1beta1/run_function_pb2.py +++ b/crossplane/function/proto/v1beta1/run_function_pb2.py @@ -26,7 +26,7 @@ from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n4crossplane/function/proto/v1beta1/run_function.proto\x12\x1e\x61piextensions.fn.proto.v1beta1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xc3\x08\n\x12RunFunctionRequest\x12\x39\n\x04meta\x18\x01 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.RequestMeta\x12\x37\n\x08observed\x18\x02 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12\x36\n\x07\x64\x65sired\x18\x03 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12-\n\x07\x63ontext\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x12\x63\n\x0f\x65xtra_resources\x18\x06 \x03(\x0b\x32\x46.apiextensions.fn.proto.v1beta1.RunFunctionRequest.ExtraResourcesEntryB\x02\x18\x01\x12X\n\x0b\x63redentials\x18\x07 \x03(\x0b\x32\x43.apiextensions.fn.proto.v1beta1.RunFunctionRequest.CredentialsEntry\x12\x65\n\x12required_resources\x18\x08 \x03(\x0b\x32I.apiextensions.fn.proto.v1beta1.RunFunctionRequest.RequiredResourcesEntry\x12\x61\n\x10required_schemas\x18\t \x03(\x0b\x32G.apiextensions.fn.proto.v1beta1.RunFunctionRequest.RequiredSchemasEntry\x1a`\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1beta1.Resources:\x02\x38\x01\x1a_\n\x10\x43redentialsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.Credentials:\x02\x38\x01\x1a\x63\n\x16RequiredResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1beta1.Resources:\x02\x38\x01\x1a^\n\x14RequiredSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.apiextensions.fn.proto.v1beta1.Schema:\x02\x38\x01\x42\x08\n\x06_inputB\n\n\x08_context\"b\n\x0b\x43redentials\x12I\n\x0f\x63redential_data\x18\x01 \x01(\x0b\x32..apiextensions.fn.proto.v1beta1.CredentialDataH\x00\x42\x08\n\x06source\"\x85\x01\n\x0e\x43redentialData\x12\x46\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x38.apiextensions.fn.proto.v1beta1.CredentialData.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"D\n\tResources\x12\x37\n\x05items\x18\x01 \x03(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource\"\xb9\x03\n\x13RunFunctionResponse\x12:\n\x04meta\x18\x01 \x01(\x0b\x32,.apiextensions.fn.proto.v1beta1.ResponseMeta\x12\x36\n\x07\x64\x65sired\x18\x02 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12\x37\n\x07results\x18\x03 \x03(\x0b\x32&.apiextensions.fn.proto.v1beta1.Result\x12-\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12\x42\n\x0crequirements\x18\x05 \x01(\x0b\x32,.apiextensions.fn.proto.v1beta1.Requirements\x12=\n\nconditions\x18\x06 \x03(\x0b\x32).apiextensions.fn.proto.v1beta1.Condition\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x42\n\n\x08_contextB\t\n\x07_output\"\x1a\n\x0bRequestMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\"\xb6\x04\n\x0cRequirements\x12]\n\x0f\x65xtra_resources\x18\x01 \x03(\x0b\x32@.apiextensions.fn.proto.v1beta1.Requirements.ExtraResourcesEntryB\x02\x18\x01\x12N\n\tresources\x18\x02 \x03(\x0b\x32;.apiextensions.fn.proto.v1beta1.Requirements.ResourcesEntry\x12J\n\x07schemas\x18\x03 \x03(\x0b\x32\x39.apiextensions.fn.proto.v1beta1.Requirements.SchemasEntry\x1ag\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.apiextensions.fn.proto.v1beta1.ResourceSelector:\x02\x38\x01\x1a\x62\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.apiextensions.fn.proto.v1beta1.ResourceSelector:\x02\x38\x01\x1a^\n\x0cSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12=\n\x05value\x18\x02 \x01(\x0b\x32..apiextensions.fn.proto.v1beta1.SchemaSelector:\x02\x38\x01\"3\n\x0eSchemaSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\"I\n\x06Schema\x12\x30\n\nopenapi_v3\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x42\r\n\x0b_openapi_v3\"\xbf\x01\n\x10ResourceSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x14\n\nmatch_name\x18\x03 \x01(\tH\x00\x12\x43\n\x0cmatch_labels\x18\x04 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.MatchLabelsH\x00\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05matchB\x0c\n\n_namespace\"\x85\x01\n\x0bMatchLabels\x12G\n\x06labels\x18\x01 \x03(\x0b\x32\x37.apiextensions.fn.proto.v1beta1.MatchLabels.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"P\n\x0cResponseMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12+\n\x03ttl\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x88\x01\x01\x42\x06\n\x04_ttl\"\xe9\x01\n\x05State\x12;\n\tcomposite\x18\x01 \x01(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource\x12G\n\tresources\x18\x02 \x03(\x0b\x32\x34.apiextensions.fn.proto.v1beta1.State.ResourcesEntry\x1aZ\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x37\n\x05value\x18\x02 \x01(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource:\x02\x38\x01\"\x82\x02\n\x08Resource\x12)\n\x08resource\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12[\n\x12\x63onnection_details\x18\x02 \x03(\x0b\x32?.apiextensions.fn.proto.v1beta1.Resource.ConnectionDetailsEntry\x12\x34\n\x05ready\x18\x03 \x01(\x0e\x32%.apiextensions.fn.proto.v1beta1.Ready\x1a\x38\n\x16\x43onnectionDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"\xbd\x01\n\x06Result\x12:\n\x08severity\x18\x01 \x01(\x0e\x32(.apiextensions.fn.proto.v1beta1.Severity\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x13\n\x06reason\x18\x03 \x01(\tH\x00\x88\x01\x01\x12;\n\x06target\x18\x04 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.TargetH\x01\x88\x01\x01\x42\t\n\x07_reasonB\t\n\x07_target\"\xcb\x01\n\tCondition\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x36\n\x06status\x18\x02 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.Status\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x14\n\x07message\x18\x04 \x01(\tH\x00\x88\x01\x01\x12;\n\x06target\x18\x05 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.TargetH\x01\x88\x01\x01\x42\n\n\x08_messageB\t\n\x07_target*?\n\x05Ready\x12\x15\n\x11READY_UNSPECIFIED\x10\x00\x12\x0e\n\nREADY_TRUE\x10\x01\x12\x0f\n\x0bREADY_FALSE\x10\x02*c\n\x08Severity\x12\x18\n\x14SEVERITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eSEVERITY_FATAL\x10\x01\x12\x14\n\x10SEVERITY_WARNING\x10\x02\x12\x13\n\x0fSEVERITY_NORMAL\x10\x03*V\n\x06Target\x12\x16\n\x12TARGET_UNSPECIFIED\x10\x00\x12\x14\n\x10TARGET_COMPOSITE\x10\x01\x12\x1e\n\x1aTARGET_COMPOSITE_AND_CLAIM\x10\x02*\x7f\n\x06Status\x12 \n\x1cSTATUS_CONDITION_UNSPECIFIED\x10\x00\x12\x1c\n\x18STATUS_CONDITION_UNKNOWN\x10\x01\x12\x19\n\x15STATUS_CONDITION_TRUE\x10\x02\x12\x1a\n\x16STATUS_CONDITION_FALSE\x10\x03\x32\x91\x01\n\x15\x46unctionRunnerService\x12x\n\x0bRunFunction\x12\x32.apiextensions.fn.proto.v1beta1.RunFunctionRequest\x1a\x33.apiextensions.fn.proto.v1beta1.RunFunctionResponse\"\x00\x42\x36Z4github.com/crossplane/crossplane/v2/proto/fn/v1beta1b\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n4crossplane/function/proto/v1beta1/run_function.proto\x12\x1e\x61piextensions.fn.proto.v1beta1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xc3\x08\n\x12RunFunctionRequest\x12\x39\n\x04meta\x18\x01 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.RequestMeta\x12\x37\n\x08observed\x18\x02 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12\x36\n\x07\x64\x65sired\x18\x03 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12+\n\x05input\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12-\n\x07\x63ontext\x18\x05 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x12\x63\n\x0f\x65xtra_resources\x18\x06 \x03(\x0b\x32\x46.apiextensions.fn.proto.v1beta1.RunFunctionRequest.ExtraResourcesEntryB\x02\x18\x01\x12X\n\x0b\x63redentials\x18\x07 \x03(\x0b\x32\x43.apiextensions.fn.proto.v1beta1.RunFunctionRequest.CredentialsEntry\x12\x65\n\x12required_resources\x18\x08 \x03(\x0b\x32I.apiextensions.fn.proto.v1beta1.RunFunctionRequest.RequiredResourcesEntry\x12\x61\n\x10required_schemas\x18\t \x03(\x0b\x32G.apiextensions.fn.proto.v1beta1.RunFunctionRequest.RequiredSchemasEntry\x1a`\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1beta1.Resources:\x02\x38\x01\x1a_\n\x10\x43redentialsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.Credentials:\x02\x38\x01\x1a\x63\n\x16RequiredResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x38\n\x05value\x18\x02 \x01(\x0b\x32).apiextensions.fn.proto.v1beta1.Resources:\x02\x38\x01\x1a^\n\x14RequiredSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x35\n\x05value\x18\x02 \x01(\x0b\x32&.apiextensions.fn.proto.v1beta1.Schema:\x02\x38\x01\x42\x08\n\x06_inputB\n\n\x08_context\"b\n\x0b\x43redentials\x12I\n\x0f\x63redential_data\x18\x01 \x01(\x0b\x32..apiextensions.fn.proto.v1beta1.CredentialDataH\x00\x42\x08\n\x06source\"\x85\x01\n\x0e\x43redentialData\x12\x46\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x38.apiextensions.fn.proto.v1beta1.CredentialData.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"D\n\tResources\x12\x37\n\x05items\x18\x01 \x03(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource\"\xb9\x03\n\x13RunFunctionResponse\x12:\n\x04meta\x18\x01 \x01(\x0b\x32,.apiextensions.fn.proto.v1beta1.ResponseMeta\x12\x36\n\x07\x64\x65sired\x18\x02 \x01(\x0b\x32%.apiextensions.fn.proto.v1beta1.State\x12\x37\n\x07results\x18\x03 \x03(\x0b\x32&.apiextensions.fn.proto.v1beta1.Result\x12-\n\x07\x63ontext\x18\x04 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x12\x42\n\x0crequirements\x18\x05 \x01(\x0b\x32,.apiextensions.fn.proto.v1beta1.Requirements\x12=\n\nconditions\x18\x06 \x03(\x0b\x32).apiextensions.fn.proto.v1beta1.Condition\x12,\n\x06output\x18\x07 \x01(\x0b\x32\x17.google.protobuf.StructH\x01\x88\x01\x01\x42\n\n\x08_contextB\t\n\x07_output\"\\\n\x0bRequestMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12@\n\x0c\x63\x61pabilities\x18\x02 \x03(\x0e\x32*.apiextensions.fn.proto.v1beta1.Capability\"\xb6\x04\n\x0cRequirements\x12]\n\x0f\x65xtra_resources\x18\x01 \x03(\x0b\x32@.apiextensions.fn.proto.v1beta1.Requirements.ExtraResourcesEntryB\x02\x18\x01\x12N\n\tresources\x18\x02 \x03(\x0b\x32;.apiextensions.fn.proto.v1beta1.Requirements.ResourcesEntry\x12J\n\x07schemas\x18\x03 \x03(\x0b\x32\x39.apiextensions.fn.proto.v1beta1.Requirements.SchemasEntry\x1ag\n\x13\x45xtraResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.apiextensions.fn.proto.v1beta1.ResourceSelector:\x02\x38\x01\x1a\x62\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.apiextensions.fn.proto.v1beta1.ResourceSelector:\x02\x38\x01\x1a^\n\x0cSchemasEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12=\n\x05value\x18\x02 \x01(\x0b\x32..apiextensions.fn.proto.v1beta1.SchemaSelector:\x02\x38\x01\"3\n\x0eSchemaSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\"I\n\x06Schema\x12\x30\n\nopenapi_v3\x18\x01 \x01(\x0b\x32\x17.google.protobuf.StructH\x00\x88\x01\x01\x42\r\n\x0b_openapi_v3\"\xbf\x01\n\x10ResourceSelector\x12\x13\n\x0b\x61pi_version\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x14\n\nmatch_name\x18\x03 \x01(\tH\x00\x12\x43\n\x0cmatch_labels\x18\x04 \x01(\x0b\x32+.apiextensions.fn.proto.v1beta1.MatchLabelsH\x00\x12\x16\n\tnamespace\x18\x05 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05matchB\x0c\n\n_namespace\"\x85\x01\n\x0bMatchLabels\x12G\n\x06labels\x18\x01 \x03(\x0b\x32\x37.apiextensions.fn.proto.v1beta1.MatchLabels.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"P\n\x0cResponseMeta\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12+\n\x03ttl\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationH\x00\x88\x01\x01\x42\x06\n\x04_ttl\"\xe9\x01\n\x05State\x12;\n\tcomposite\x18\x01 \x01(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource\x12G\n\tresources\x18\x02 \x03(\x0b\x32\x34.apiextensions.fn.proto.v1beta1.State.ResourcesEntry\x1aZ\n\x0eResourcesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x37\n\x05value\x18\x02 \x01(\x0b\x32(.apiextensions.fn.proto.v1beta1.Resource:\x02\x38\x01\"\x82\x02\n\x08Resource\x12)\n\x08resource\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\x12[\n\x12\x63onnection_details\x18\x02 \x03(\x0b\x32?.apiextensions.fn.proto.v1beta1.Resource.ConnectionDetailsEntry\x12\x34\n\x05ready\x18\x03 \x01(\x0e\x32%.apiextensions.fn.proto.v1beta1.Ready\x1a\x38\n\x16\x43onnectionDetailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\"\xbd\x01\n\x06Result\x12:\n\x08severity\x18\x01 \x01(\x0e\x32(.apiextensions.fn.proto.v1beta1.Severity\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x13\n\x06reason\x18\x03 \x01(\tH\x00\x88\x01\x01\x12;\n\x06target\x18\x04 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.TargetH\x01\x88\x01\x01\x42\t\n\x07_reasonB\t\n\x07_target\"\xcb\x01\n\tCondition\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x36\n\x06status\x18\x02 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.Status\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x14\n\x07message\x18\x04 \x01(\tH\x00\x88\x01\x01\x12;\n\x06target\x18\x05 \x01(\x0e\x32&.apiextensions.fn.proto.v1beta1.TargetH\x01\x88\x01\x01\x42\n\n\x08_messageB\t\n\x07_target*\xc0\x01\n\nCapability\x12\x1a\n\x16\x43\x41PABILITY_UNSPECIFIED\x10\x00\x12\x1b\n\x17\x43\x41PABILITY_CAPABILITIES\x10\x01\x12!\n\x1d\x43\x41PABILITY_REQUIRED_RESOURCES\x10\x02\x12\x1a\n\x16\x43\x41PABILITY_CREDENTIALS\x10\x03\x12\x19\n\x15\x43\x41PABILITY_CONDITIONS\x10\x04\x12\x1f\n\x1b\x43\x41PABILITY_REQUIRED_SCHEMAS\x10\x05*?\n\x05Ready\x12\x15\n\x11READY_UNSPECIFIED\x10\x00\x12\x0e\n\nREADY_TRUE\x10\x01\x12\x0f\n\x0bREADY_FALSE\x10\x02*c\n\x08Severity\x12\x18\n\x14SEVERITY_UNSPECIFIED\x10\x00\x12\x12\n\x0eSEVERITY_FATAL\x10\x01\x12\x14\n\x10SEVERITY_WARNING\x10\x02\x12\x13\n\x0fSEVERITY_NORMAL\x10\x03*V\n\x06Target\x12\x16\n\x12TARGET_UNSPECIFIED\x10\x00\x12\x14\n\x10TARGET_COMPOSITE\x10\x01\x12\x1e\n\x1aTARGET_COMPOSITE_AND_CLAIM\x10\x02*\x7f\n\x06Status\x12 \n\x1cSTATUS_CONDITION_UNSPECIFIED\x10\x00\x12\x1c\n\x18STATUS_CONDITION_UNKNOWN\x10\x01\x12\x19\n\x15STATUS_CONDITION_TRUE\x10\x02\x12\x1a\n\x16STATUS_CONDITION_FALSE\x10\x03\x32\x91\x01\n\x15\x46unctionRunnerService\x12x\n\x0bRunFunction\x12\x32.apiextensions.fn.proto.v1beta1.RunFunctionRequest\x1a\x33.apiextensions.fn.proto.v1beta1.RunFunctionResponse\"\x00\x42\x36Z4github.com/crossplane/crossplane/v2/proto/fn/v1beta1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -60,14 +60,16 @@ _globals['_STATE_RESOURCESENTRY']._serialized_options = b'8\001' _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._loaded_options = None _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_options = b'8\001' - _globals['_READY']._serialized_start=4026 - _globals['_READY']._serialized_end=4089 - _globals['_SEVERITY']._serialized_start=4091 - _globals['_SEVERITY']._serialized_end=4190 - _globals['_TARGET']._serialized_start=4192 - _globals['_TARGET']._serialized_end=4278 - _globals['_STATUS']._serialized_start=4280 - _globals['_STATUS']._serialized_end=4407 + _globals['_CAPABILITY']._serialized_start=4093 + _globals['_CAPABILITY']._serialized_end=4285 + _globals['_READY']._serialized_start=4287 + _globals['_READY']._serialized_end=4350 + _globals['_SEVERITY']._serialized_start=4352 + _globals['_SEVERITY']._serialized_end=4451 + _globals['_TARGET']._serialized_start=4453 + _globals['_TARGET']._serialized_end=4539 + _globals['_STATUS']._serialized_start=4541 + _globals['_STATUS']._serialized_end=4668 _globals['_RUNFUNCTIONREQUEST']._serialized_start=151 _globals['_RUNFUNCTIONREQUEST']._serialized_end=1242 _globals['_RUNFUNCTIONREQUEST_EXTRARESOURCESENTRY']._serialized_start=830 @@ -89,39 +91,39 @@ _globals['_RUNFUNCTIONRESPONSE']._serialized_start=1551 _globals['_RUNFUNCTIONRESPONSE']._serialized_end=1992 _globals['_REQUESTMETA']._serialized_start=1994 - _globals['_REQUESTMETA']._serialized_end=2020 - _globals['_REQUIREMENTS']._serialized_start=2023 - _globals['_REQUIREMENTS']._serialized_end=2589 - _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_start=2290 - _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_end=2393 - _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_start=2395 - _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_end=2493 - _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_start=2495 - _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_end=2589 - _globals['_SCHEMASELECTOR']._serialized_start=2591 - _globals['_SCHEMASELECTOR']._serialized_end=2642 - _globals['_SCHEMA']._serialized_start=2644 - _globals['_SCHEMA']._serialized_end=2717 - _globals['_RESOURCESELECTOR']._serialized_start=2720 - _globals['_RESOURCESELECTOR']._serialized_end=2911 - _globals['_MATCHLABELS']._serialized_start=2914 - _globals['_MATCHLABELS']._serialized_end=3047 - _globals['_MATCHLABELS_LABELSENTRY']._serialized_start=3002 - _globals['_MATCHLABELS_LABELSENTRY']._serialized_end=3047 - _globals['_RESPONSEMETA']._serialized_start=3049 - _globals['_RESPONSEMETA']._serialized_end=3129 - _globals['_STATE']._serialized_start=3132 - _globals['_STATE']._serialized_end=3365 - _globals['_STATE_RESOURCESENTRY']._serialized_start=3275 - _globals['_STATE_RESOURCESENTRY']._serialized_end=3365 - _globals['_RESOURCE']._serialized_start=3368 - _globals['_RESOURCE']._serialized_end=3626 - _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_start=3570 - _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_end=3626 - _globals['_RESULT']._serialized_start=3629 - _globals['_RESULT']._serialized_end=3818 - _globals['_CONDITION']._serialized_start=3821 - _globals['_CONDITION']._serialized_end=4024 - _globals['_FUNCTIONRUNNERSERVICE']._serialized_start=4410 - _globals['_FUNCTIONRUNNERSERVICE']._serialized_end=4555 + _globals['_REQUESTMETA']._serialized_end=2086 + _globals['_REQUIREMENTS']._serialized_start=2089 + _globals['_REQUIREMENTS']._serialized_end=2655 + _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_start=2356 + _globals['_REQUIREMENTS_EXTRARESOURCESENTRY']._serialized_end=2459 + _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_start=2461 + _globals['_REQUIREMENTS_RESOURCESENTRY']._serialized_end=2559 + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_start=2561 + _globals['_REQUIREMENTS_SCHEMASENTRY']._serialized_end=2655 + _globals['_SCHEMASELECTOR']._serialized_start=2657 + _globals['_SCHEMASELECTOR']._serialized_end=2708 + _globals['_SCHEMA']._serialized_start=2710 + _globals['_SCHEMA']._serialized_end=2783 + _globals['_RESOURCESELECTOR']._serialized_start=2786 + _globals['_RESOURCESELECTOR']._serialized_end=2977 + _globals['_MATCHLABELS']._serialized_start=2980 + _globals['_MATCHLABELS']._serialized_end=3113 + _globals['_MATCHLABELS_LABELSENTRY']._serialized_start=3068 + _globals['_MATCHLABELS_LABELSENTRY']._serialized_end=3113 + _globals['_RESPONSEMETA']._serialized_start=3115 + _globals['_RESPONSEMETA']._serialized_end=3195 + _globals['_STATE']._serialized_start=3198 + _globals['_STATE']._serialized_end=3431 + _globals['_STATE_RESOURCESENTRY']._serialized_start=3341 + _globals['_STATE_RESOURCESENTRY']._serialized_end=3431 + _globals['_RESOURCE']._serialized_start=3434 + _globals['_RESOURCE']._serialized_end=3692 + _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_start=3636 + _globals['_RESOURCE_CONNECTIONDETAILSENTRY']._serialized_end=3692 + _globals['_RESULT']._serialized_start=3695 + _globals['_RESULT']._serialized_end=3884 + _globals['_CONDITION']._serialized_start=3887 + _globals['_CONDITION']._serialized_end=4090 + _globals['_FUNCTIONRUNNERSERVICE']._serialized_start=4671 + _globals['_FUNCTIONRUNNERSERVICE']._serialized_end=4816 # @@protoc_insertion_point(module_scope) diff --git a/crossplane/function/proto/v1beta1/run_function_pb2.pyi b/crossplane/function/proto/v1beta1/run_function_pb2.pyi index 30ad04f..d0d29ca 100644 --- a/crossplane/function/proto/v1beta1/run_function_pb2.pyi +++ b/crossplane/function/proto/v1beta1/run_function_pb2.pyi @@ -11,6 +11,15 @@ from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union DESCRIPTOR: _descriptor.FileDescriptor +class Capability(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + CAPABILITY_UNSPECIFIED: _ClassVar[Capability] + CAPABILITY_CAPABILITIES: _ClassVar[Capability] + CAPABILITY_REQUIRED_RESOURCES: _ClassVar[Capability] + CAPABILITY_CREDENTIALS: _ClassVar[Capability] + CAPABILITY_CONDITIONS: _ClassVar[Capability] + CAPABILITY_REQUIRED_SCHEMAS: _ClassVar[Capability] + class Ready(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): __slots__ = () READY_UNSPECIFIED: _ClassVar[Ready] @@ -36,6 +45,12 @@ class Status(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): STATUS_CONDITION_UNKNOWN: _ClassVar[Status] STATUS_CONDITION_TRUE: _ClassVar[Status] STATUS_CONDITION_FALSE: _ClassVar[Status] +CAPABILITY_UNSPECIFIED: Capability +CAPABILITY_CAPABILITIES: Capability +CAPABILITY_REQUIRED_RESOURCES: Capability +CAPABILITY_CREDENTIALS: Capability +CAPABILITY_CONDITIONS: Capability +CAPABILITY_REQUIRED_SCHEMAS: Capability READY_UNSPECIFIED: Ready READY_TRUE: Ready READY_FALSE: Ready @@ -145,10 +160,12 @@ class RunFunctionResponse(_message.Message): def __init__(self, meta: _Optional[_Union[ResponseMeta, _Mapping]] = ..., desired: _Optional[_Union[State, _Mapping]] = ..., results: _Optional[_Iterable[_Union[Result, _Mapping]]] = ..., context: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., requirements: _Optional[_Union[Requirements, _Mapping]] = ..., conditions: _Optional[_Iterable[_Union[Condition, _Mapping]]] = ..., output: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ... class RequestMeta(_message.Message): - __slots__ = ("tag",) + __slots__ = ("tag", "capabilities") TAG_FIELD_NUMBER: _ClassVar[int] + CAPABILITIES_FIELD_NUMBER: _ClassVar[int] tag: str - def __init__(self, tag: _Optional[str] = ...) -> None: ... + capabilities: _containers.RepeatedScalarFieldContainer[Capability] + def __init__(self, tag: _Optional[str] = ..., capabilities: _Optional[_Iterable[_Union[Capability, str]]] = ...) -> None: ... class Requirements(_message.Message): __slots__ = ("extra_resources", "resources", "schemas") diff --git a/crossplane/function/request.py b/crossplane/function/request.py index 59c7695..a9188b6 100644 --- a/crossplane/function/request.py +++ b/crossplane/function/request.py @@ -133,6 +133,33 @@ def get_credentials(req: fnv1.RunFunctionRequest, name: str) -> Credentials: return empty +def has_capability( + req: fnv1.RunFunctionRequest, + cap: fnv1.Capability.ValueType, +) -> bool: + """Check whether Crossplane advertises a particular capability. + + Args: + req: The RunFunctionRequest to check. + cap: The capability to check for, e.g. fnv1.CAPABILITY_REQUIRED_SCHEMAS. + + Returns: + True if the capability is present in the request metadata. + + Crossplane sends its capabilities in the request metadata. Functions can use + this to determine whether Crossplane will honor certain fields in their + response, or populate certain fields in their request. + + If CAPABILITY_CAPABILITIES is absent, the calling Crossplane predates + capability advertisement (pre-v2.2). In this case has_capability always + returns False, even for features the older Crossplane does support. + + if request.has_capability(req, fnv1.CAPABILITY_REQUIRED_SCHEMAS): + response.require_schema(rsp, "xr", xr_api_version, xr_kind) + """ + return cap in req.meta.capabilities + + def get_required_schema(req: fnv1.RunFunctionRequest, name: str) -> dict | None: """Get a required OpenAPI schema by name from the request. diff --git a/tests/test_request.py b/tests/test_request.py index 0e497ba..c33419d 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -264,6 +264,53 @@ class TestCase: dataclasses.asdict(case.want), dataclasses.asdict(got), case.reason ) + def test_has_capability(self) -> None: + @dataclasses.dataclass + class TestCase: + reason: str + req: fnv1.RunFunctionRequest + cap: fnv1.Capability.ValueType + want: bool + + cases = [ + TestCase( + reason="Should return False when no capabilities are advertised.", + req=fnv1.RunFunctionRequest(), + cap=fnv1.CAPABILITY_REQUIRED_SCHEMAS, + want=False, + ), + TestCase( + reason="Should return True when the capability is present.", + req=fnv1.RunFunctionRequest( + meta=fnv1.RequestMeta( + capabilities=[ + fnv1.CAPABILITY_CAPABILITIES, + fnv1.CAPABILITY_REQUIRED_SCHEMAS, + ], + ), + ), + cap=fnv1.CAPABILITY_REQUIRED_SCHEMAS, + want=True, + ), + TestCase( + reason="Should return False when a different capability is present.", + req=fnv1.RunFunctionRequest( + meta=fnv1.RequestMeta( + capabilities=[ + fnv1.CAPABILITY_CAPABILITIES, + fnv1.CAPABILITY_CREDENTIALS, + ], + ), + ), + cap=fnv1.CAPABILITY_REQUIRED_SCHEMAS, + want=False, + ), + ] + + for case in cases: + got = request.has_capability(case.req, case.cap) + self.assertEqual(case.want, got, case.reason) + def test_get_required_schema(self) -> None: @dataclasses.dataclass class TestCase: From f91254e2f08f6e6c88ce6dda5f931500953db099 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Thu, 5 Feb 2026 15:35:48 -0800 Subject: [PATCH 3/3] Add advertises_capabilities and has_capability helpers Functions need to know whether Crossplane will honor particular request or response fields, like schema requirements. Crossplane v2.2 and later advertise their capabilities in the request metadata, but older versions don't advertise capabilities at all. This commit adds two helpers. advertises_capabilities checks whether the calling Crossplane advertises its capabilities. has_capability checks whether a specific capability is present. Functions should check advertises_capabilities first, since has_capability returns False both when a capability is absent and when Crossplane predates capability advertisement. Signed-off-by: Nic Cope --- crossplane/function/request.py | 29 ++++++++++++++++++++++++++--- tests/test_request.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/crossplane/function/request.py b/crossplane/function/request.py index a9188b6..e059f16 100644 --- a/crossplane/function/request.py +++ b/crossplane/function/request.py @@ -133,6 +133,29 @@ def get_credentials(req: fnv1.RunFunctionRequest, name: str) -> Credentials: return empty +def advertises_capabilities(req: fnv1.RunFunctionRequest) -> bool: + """Check whether Crossplane advertises its capabilities. + + Args: + req: The RunFunctionRequest to check. + + Returns: + True if Crossplane advertises its capabilities. + + Crossplane v2.2 and later advertise their capabilities in the request + metadata. If this returns False, the calling Crossplane predates capability + advertisement and has_capability will always return False, even for features + the older Crossplane does support. + + if not request.advertises_capabilities(req): + # Pre-v2.2 Crossplane, capabilities are unknown. + ... + elif request.has_capability(req, fnv1.CAPABILITY_REQUIRED_SCHEMAS): + response.require_schema(rsp, "xr", xr_api_version, xr_kind) + """ + return fnv1.CAPABILITY_CAPABILITIES in req.meta.capabilities + + def has_capability( req: fnv1.RunFunctionRequest, cap: fnv1.Capability.ValueType, @@ -150,9 +173,9 @@ def has_capability( this to determine whether Crossplane will honor certain fields in their response, or populate certain fields in their request. - If CAPABILITY_CAPABILITIES is absent, the calling Crossplane predates - capability advertisement (pre-v2.2). In this case has_capability always - returns False, even for features the older Crossplane does support. + Use advertises_capabilities to check whether Crossplane advertises its + capabilities at all. If it doesn't, has_capability always returns False even + for features the older Crossplane does support. if request.has_capability(req, fnv1.CAPABILITY_REQUIRED_SCHEMAS): response.require_schema(rsp, "xr", xr_api_version, xr_kind) diff --git a/tests/test_request.py b/tests/test_request.py index c33419d..f7fdf00 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -264,6 +264,37 @@ class TestCase: dataclasses.asdict(case.want), dataclasses.asdict(got), case.reason ) + def test_advertises_capabilities(self) -> None: + @dataclasses.dataclass + class TestCase: + reason: str + req: fnv1.RunFunctionRequest + want: bool + + cases = [ + TestCase( + reason="Should return False when no capabilities are advertised.", + req=fnv1.RunFunctionRequest(), + want=False, + ), + TestCase( + reason="Should return True when CAPABILITY_CAPABILITIES is present.", + req=fnv1.RunFunctionRequest( + meta=fnv1.RequestMeta( + capabilities=[ + fnv1.CAPABILITY_CAPABILITIES, + fnv1.CAPABILITY_REQUIRED_SCHEMAS, + ], + ), + ), + want=True, + ), + ] + + for case in cases: + got = request.advertises_capabilities(case.req) + self.assertEqual(case.want, got, case.reason) + def test_has_capability(self) -> None: @dataclasses.dataclass class TestCase: