Skip to content

Commit 614d013

Browse files
authored
Merge pull request #193 from negz/schematics
Add support for requesting OpenAPI schemas
2 parents cccc0bf + f91254e commit 614d013

File tree

10 files changed

+718
-127
lines changed

10 files changed

+718
-127
lines changed

crossplane/function/proto/v1/run_function.proto

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ message RunFunctionRequest {
9090
// satisfy the request. This field is only populated when the function uses
9191
// resources in its requirements.
9292
map<string, Resources> required_resources = 8;
93+
94+
// Optional schemas that the function specified in its requirements. The map
95+
// key corresponds to the key in a RunFunctionResponse's requirements.schemas
96+
// field. If a function requested a schema that could not be found, Crossplane
97+
// sets the map key to an empty Schema message to indicate that it attempted
98+
// to satisfy the request.
99+
map<string, Schema> required_schemas = 9;
93100
}
94101

95102
// Credentials that a function may use to communicate with an external system.
@@ -156,6 +163,44 @@ message RequestMeta {
156163
// An opaque string identifying a request. Requests with identical tags will
157164
// be otherwise identical.
158165
string tag = 1;
166+
167+
// Capabilities supported by this version of Crossplane. Functions may use
168+
// this to determine whether Crossplane will honor certain fields in their
169+
// response, or populate certain fields in their request.
170+
repeated Capability capabilities = 2;
171+
}
172+
173+
// Capability indicates that Crossplane supports a particular feature.
174+
// Functions can check for capabilities to determine whether Crossplane will
175+
// honor a particular request or response field.
176+
enum Capability {
177+
CAPABILITY_UNSPECIFIED = 0;
178+
179+
// Crossplane sends capabilities in RequestMeta. If this capability is
180+
// present, the function knows that if another capability is absent, it's
181+
// because Crossplane doesn't support it (not because Crossplane predates
182+
// capability advertisement). Added in Crossplane v2.2.
183+
CAPABILITY_CAPABILITIES = 1;
184+
185+
// Crossplane supports the requirements.resources field. Functions can return
186+
// resource requirements and Crossplane will fetch the requested resources and
187+
// return them in required_resources. Added in Crossplane v1.15.
188+
CAPABILITY_REQUIRED_RESOURCES = 2;
189+
190+
// Crossplane supports the credentials field. Functions can receive
191+
// credentials from secrets specified in the Composition. Added in Crossplane
192+
// v1.16.
193+
CAPABILITY_CREDENTIALS = 3;
194+
195+
// Crossplane supports the conditions field. Functions can return status
196+
// conditions to be applied to the XR and optionally its claim. Added in
197+
// Crossplane v1.17.
198+
CAPABILITY_CONDITIONS = 4;
199+
200+
// Crossplane supports the requirements.schemas field. Functions can request
201+
// OpenAPI schemas and Crossplane will return them in required_schemas. Added
202+
// in Crossplane v2.2.
203+
CAPABILITY_REQUIRED_SCHEMAS = 5;
159204
}
160205

161206
// Requirements that must be satisfied for a function to run successfully.
@@ -169,6 +214,27 @@ message Requirements {
169214
// Resources that this function requires. The map key uniquely identifies the
170215
// group of resources.
171216
map<string, ResourceSelector> resources = 2;
217+
218+
// Schemas that this function requires. The map key uniquely identifies the
219+
// schema request.
220+
map<string, SchemaSelector> schemas = 3;
221+
}
222+
223+
// SchemaSelector identifies a resource kind whose OpenAPI schema is requested.
224+
message SchemaSelector {
225+
// API version of the resource kind, e.g. "example.org/v1".
226+
string api_version = 1;
227+
228+
// Kind of resource, e.g. "MyResource".
229+
string kind = 2;
230+
}
231+
232+
// Schema represents the OpenAPI schema for a resource kind.
233+
message Schema {
234+
// The OpenAPI v3 schema of the resource kind as unstructured JSON.
235+
// For CRDs this is the spec.versions[].schema.openAPIV3Schema field.
236+
// Empty if Crossplane could not find a schema for the requested kind.
237+
optional google.protobuf.Struct openapi_v3 = 1;
172238
}
173239

174240
// ResourceSelector selects a group of resources, either by name or by label.
@@ -267,7 +333,7 @@ message Resource {
267333
// * A function should set this field to READY_TRUE in a RunFunctionResponse
268334
// to indicate that a desired XR is ready. This overwrites the standard
269335
// readiness detection that determines the ready state of the composite by the
270-
// ready state of the the composed resources.
336+
// ready state of the composed resources.
271337
//
272338
// Ready is only used for composition. It's ignored by Operations.
273339
Ready ready = 3;
@@ -367,4 +433,4 @@ enum Status {
367433
STATUS_CONDITION_TRUE = 2;
368434

369435
STATUS_CONDITION_FALSE = 3;
370-
}
436+
}

crossplane/function/proto/v1/run_function_pb2.py

Lines changed: 70 additions & 56 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crossplane/function/proto/v1/run_function_pb2.pyi

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union
1111

1212
DESCRIPTOR: _descriptor.FileDescriptor
1313

14+
class Capability(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
15+
__slots__ = ()
16+
CAPABILITY_UNSPECIFIED: _ClassVar[Capability]
17+
CAPABILITY_CAPABILITIES: _ClassVar[Capability]
18+
CAPABILITY_REQUIRED_RESOURCES: _ClassVar[Capability]
19+
CAPABILITY_CREDENTIALS: _ClassVar[Capability]
20+
CAPABILITY_CONDITIONS: _ClassVar[Capability]
21+
CAPABILITY_REQUIRED_SCHEMAS: _ClassVar[Capability]
22+
1423
class Ready(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
1524
__slots__ = ()
1625
READY_UNSPECIFIED: _ClassVar[Ready]
@@ -36,6 +45,12 @@ class Status(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
3645
STATUS_CONDITION_UNKNOWN: _ClassVar[Status]
3746
STATUS_CONDITION_TRUE: _ClassVar[Status]
3847
STATUS_CONDITION_FALSE: _ClassVar[Status]
48+
CAPABILITY_UNSPECIFIED: Capability
49+
CAPABILITY_CAPABILITIES: Capability
50+
CAPABILITY_REQUIRED_RESOURCES: Capability
51+
CAPABILITY_CREDENTIALS: Capability
52+
CAPABILITY_CONDITIONS: Capability
53+
CAPABILITY_REQUIRED_SCHEMAS: Capability
3954
READY_UNSPECIFIED: Ready
4055
READY_TRUE: Ready
4156
READY_FALSE: Ready
@@ -52,7 +67,7 @@ STATUS_CONDITION_TRUE: Status
5267
STATUS_CONDITION_FALSE: Status
5368

5469
class RunFunctionRequest(_message.Message):
55-
__slots__ = ("meta", "observed", "desired", "input", "context", "extra_resources", "credentials", "required_resources")
70+
__slots__ = ("meta", "observed", "desired", "input", "context", "extra_resources", "credentials", "required_resources", "required_schemas")
5671
class ExtraResourcesEntry(_message.Message):
5772
__slots__ = ("key", "value")
5873
KEY_FIELD_NUMBER: _ClassVar[int]
@@ -74,6 +89,13 @@ class RunFunctionRequest(_message.Message):
7489
key: str
7590
value: Resources
7691
def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Resources, _Mapping]] = ...) -> None: ...
92+
class RequiredSchemasEntry(_message.Message):
93+
__slots__ = ("key", "value")
94+
KEY_FIELD_NUMBER: _ClassVar[int]
95+
VALUE_FIELD_NUMBER: _ClassVar[int]
96+
key: str
97+
value: Schema
98+
def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Schema, _Mapping]] = ...) -> None: ...
7799
META_FIELD_NUMBER: _ClassVar[int]
78100
OBSERVED_FIELD_NUMBER: _ClassVar[int]
79101
DESIRED_FIELD_NUMBER: _ClassVar[int]
@@ -82,6 +104,7 @@ class RunFunctionRequest(_message.Message):
82104
EXTRA_RESOURCES_FIELD_NUMBER: _ClassVar[int]
83105
CREDENTIALS_FIELD_NUMBER: _ClassVar[int]
84106
REQUIRED_RESOURCES_FIELD_NUMBER: _ClassVar[int]
107+
REQUIRED_SCHEMAS_FIELD_NUMBER: _ClassVar[int]
85108
meta: RequestMeta
86109
observed: State
87110
desired: State
@@ -90,7 +113,8 @@ class RunFunctionRequest(_message.Message):
90113
extra_resources: _containers.MessageMap[str, Resources]
91114
credentials: _containers.MessageMap[str, Credentials]
92115
required_resources: _containers.MessageMap[str, Resources]
93-
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: ...
116+
required_schemas: _containers.MessageMap[str, Schema]
117+
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: ...
94118

95119
class Credentials(_message.Message):
96120
__slots__ = ("credential_data",)
@@ -136,13 +160,15 @@ class RunFunctionResponse(_message.Message):
136160
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: ...
137161

138162
class RequestMeta(_message.Message):
139-
__slots__ = ("tag",)
163+
__slots__ = ("tag", "capabilities")
140164
TAG_FIELD_NUMBER: _ClassVar[int]
165+
CAPABILITIES_FIELD_NUMBER: _ClassVar[int]
141166
tag: str
142-
def __init__(self, tag: _Optional[str] = ...) -> None: ...
167+
capabilities: _containers.RepeatedScalarFieldContainer[Capability]
168+
def __init__(self, tag: _Optional[str] = ..., capabilities: _Optional[_Iterable[_Union[Capability, str]]] = ...) -> None: ...
143169

144170
class Requirements(_message.Message):
145-
__slots__ = ("extra_resources", "resources")
171+
__slots__ = ("extra_resources", "resources", "schemas")
146172
class ExtraResourcesEntry(_message.Message):
147173
__slots__ = ("key", "value")
148174
KEY_FIELD_NUMBER: _ClassVar[int]
@@ -157,11 +183,34 @@ class Requirements(_message.Message):
157183
key: str
158184
value: ResourceSelector
159185
def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[ResourceSelector, _Mapping]] = ...) -> None: ...
186+
class SchemasEntry(_message.Message):
187+
__slots__ = ("key", "value")
188+
KEY_FIELD_NUMBER: _ClassVar[int]
189+
VALUE_FIELD_NUMBER: _ClassVar[int]
190+
key: str
191+
value: SchemaSelector
192+
def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[SchemaSelector, _Mapping]] = ...) -> None: ...
160193
EXTRA_RESOURCES_FIELD_NUMBER: _ClassVar[int]
161194
RESOURCES_FIELD_NUMBER: _ClassVar[int]
195+
SCHEMAS_FIELD_NUMBER: _ClassVar[int]
162196
extra_resources: _containers.MessageMap[str, ResourceSelector]
163197
resources: _containers.MessageMap[str, ResourceSelector]
164-
def __init__(self, extra_resources: _Optional[_Mapping[str, ResourceSelector]] = ..., resources: _Optional[_Mapping[str, ResourceSelector]] = ...) -> None: ...
198+
schemas: _containers.MessageMap[str, SchemaSelector]
199+
def __init__(self, extra_resources: _Optional[_Mapping[str, ResourceSelector]] = ..., resources: _Optional[_Mapping[str, ResourceSelector]] = ..., schemas: _Optional[_Mapping[str, SchemaSelector]] = ...) -> None: ...
200+
201+
class SchemaSelector(_message.Message):
202+
__slots__ = ("api_version", "kind")
203+
API_VERSION_FIELD_NUMBER: _ClassVar[int]
204+
KIND_FIELD_NUMBER: _ClassVar[int]
205+
api_version: str
206+
kind: str
207+
def __init__(self, api_version: _Optional[str] = ..., kind: _Optional[str] = ...) -> None: ...
208+
209+
class Schema(_message.Message):
210+
__slots__ = ("openapi_v3",)
211+
OPENAPI_V3_FIELD_NUMBER: _ClassVar[int]
212+
openapi_v3: _struct_pb2.Struct
213+
def __init__(self, openapi_v3: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ...
165214

166215
class ResourceSelector(_message.Message):
167216
__slots__ = ("api_version", "kind", "match_name", "match_labels", "namespace")

crossplane/function/proto/v1beta1/run_function.proto

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ message RunFunctionRequest {
9292
// satisfy the request. This field is only populated when the function uses
9393
// resources in its requirements.
9494
map<string, Resources> required_resources = 8;
95+
96+
// Optional schemas that the function specified in its requirements. The map
97+
// key corresponds to the key in a RunFunctionResponse's requirements.schemas
98+
// field. If a function requested a schema that could not be found, Crossplane
99+
// sets the map key to an empty Schema message to indicate that it attempted
100+
// to satisfy the request.
101+
map<string, Schema> required_schemas = 9;
95102
}
96103

97104
// Credentials that a function may use to communicate with an external system.
@@ -158,6 +165,44 @@ message RequestMeta {
158165
// An opaque string identifying a request. Requests with identical tags will
159166
// be otherwise identical.
160167
string tag = 1;
168+
169+
// Capabilities supported by this version of Crossplane. Functions may use
170+
// this to determine whether Crossplane will honor certain fields in their
171+
// response, or populate certain fields in their request.
172+
repeated Capability capabilities = 2;
173+
}
174+
175+
// Capability indicates that Crossplane supports a particular feature.
176+
// Functions can check for capabilities to determine whether Crossplane will
177+
// honor a particular request or response field.
178+
enum Capability {
179+
CAPABILITY_UNSPECIFIED = 0;
180+
181+
// Crossplane sends capabilities in RequestMeta. If this capability is
182+
// present, the function knows that if another capability is absent, it's
183+
// because Crossplane doesn't support it (not because Crossplane predates
184+
// capability advertisement). Added in Crossplane v2.2.
185+
CAPABILITY_CAPABILITIES = 1;
186+
187+
// Crossplane supports the requirements.resources field. Functions can return
188+
// resource requirements and Crossplane will fetch the requested resources and
189+
// return them in required_resources. Added in Crossplane v1.15.
190+
CAPABILITY_REQUIRED_RESOURCES = 2;
191+
192+
// Crossplane supports the credentials field. Functions can receive
193+
// credentials from secrets specified in the Composition. Added in Crossplane
194+
// v1.16.
195+
CAPABILITY_CREDENTIALS = 3;
196+
197+
// Crossplane supports the conditions field. Functions can return status
198+
// conditions to be applied to the XR and optionally its claim. Added in
199+
// Crossplane v1.17.
200+
CAPABILITY_CONDITIONS = 4;
201+
202+
// Crossplane supports the requirements.schemas field. Functions can request
203+
// OpenAPI schemas and Crossplane will return them in required_schemas. Added
204+
// in Crossplane v2.2.
205+
CAPABILITY_REQUIRED_SCHEMAS = 5;
161206
}
162207

163208
// Requirements that must be satisfied for a function to run successfully.
@@ -171,6 +216,27 @@ message Requirements {
171216
// Resources that this function requires. The map key uniquely identifies the
172217
// group of resources.
173218
map<string, ResourceSelector> resources = 2;
219+
220+
// Schemas that this function requires. The map key uniquely identifies the
221+
// schema request.
222+
map<string, SchemaSelector> schemas = 3;
223+
}
224+
225+
// SchemaSelector identifies a resource kind whose OpenAPI schema is requested.
226+
message SchemaSelector {
227+
// API version of the resource kind, e.g. "example.org/v1".
228+
string api_version = 1;
229+
230+
// Kind of resource, e.g. "MyResource".
231+
string kind = 2;
232+
}
233+
234+
// Schema represents the OpenAPI schema for a resource kind.
235+
message Schema {
236+
// The OpenAPI v3 schema of the resource kind as unstructured JSON.
237+
// For CRDs this is the spec.versions[].schema.openAPIV3Schema field.
238+
// Empty if Crossplane could not find a schema for the requested kind.
239+
optional google.protobuf.Struct openapi_v3 = 1;
174240
}
175241

176242
// ResourceSelector selects a group of resources, either by name or by label.
@@ -269,7 +335,7 @@ message Resource {
269335
// * A function should set this field to READY_TRUE in a RunFunctionResponse
270336
// to indicate that a desired XR is ready. This overwrites the standard
271337
// readiness detection that determines the ready state of the composite by the
272-
// ready state of the the composed resources.
338+
// ready state of the composed resources.
273339
//
274340
// Ready is only used for composition. It's ignored by Operations.
275341
Ready ready = 3;

0 commit comments

Comments
 (0)