diff --git a/proto/v1/run_function.pb.go b/proto/v1/run_function.pb.go index ce16c3e..5b69253 100644 --- a/proto/v1/run_function.pb.go +++ b/proto/v1/run_function.pb.go @@ -45,6 +45,63 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// A DependencyLifecycle is how a dependency constrains the order its endpoints +// are created and deleted. +type DependencyLifecycle int32 + +const ( + // Symmetric ordering: the resource is created only once what it depends on + // is ready, and what it depends on is deleted only once the resource is + // gone. This is the default, and the only valid value when depends_on is a + // required resource, because Crossplane never deletes a resource it didn't + // compose. + DependencyLifecycle_DEPENDENCY_LIFECYCLE_UNSPECIFIED DependencyLifecycle = 0 + // The resource may be created without waiting for what it depends on to be + // deleted. It must still exist and be ready before what it depends on is + // deleted. Use for a replacement that must exist before its predecessor is + // torn down. Only valid when depends_on is a composed resource. + DependencyLifecycle_DEPENDENCY_LIFECYCLE_CREATE_BEFORE_DESTROY DependencyLifecycle = 1 +) + +// Enum value maps for DependencyLifecycle. +var ( + DependencyLifecycle_name = map[int32]string{ + 0: "DEPENDENCY_LIFECYCLE_UNSPECIFIED", + 1: "DEPENDENCY_LIFECYCLE_CREATE_BEFORE_DESTROY", + } + DependencyLifecycle_value = map[string]int32{ + "DEPENDENCY_LIFECYCLE_UNSPECIFIED": 0, + "DEPENDENCY_LIFECYCLE_CREATE_BEFORE_DESTROY": 1, + } +) + +func (x DependencyLifecycle) Enum() *DependencyLifecycle { + p := new(DependencyLifecycle) + *p = x + return p +} + +func (x DependencyLifecycle) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DependencyLifecycle) Descriptor() protoreflect.EnumDescriptor { + return file_v1_run_function_proto_enumTypes[0].Descriptor() +} + +func (DependencyLifecycle) Type() protoreflect.EnumType { + return &file_v1_run_function_proto_enumTypes[0] +} + +func (x DependencyLifecycle) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DependencyLifecycle.Descriptor instead. +func (DependencyLifecycle) EnumDescriptor() ([]byte, []int) { + return file_v1_run_function_proto_rawDescGZIP(), []int{0} +} + // 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. @@ -73,6 +130,10 @@ const ( // OpenAPI schemas and Crossplane will return them in required_schemas. Added // in Crossplane v2.2. Capability_CAPABILITY_REQUIRED_SCHEMAS Capability = 5 + // Crossplane supports the dependencies field. Functions can declare ordering + // constraints over composed resources, and Crossplane will sequence the + // resources it creates, updates and deletes accordingly. + Capability_CAPABILITY_DEPENDENCIES Capability = 6 ) // Enum value maps for Capability. @@ -84,6 +145,7 @@ var ( 3: "CAPABILITY_CREDENTIALS", 4: "CAPABILITY_CONDITIONS", 5: "CAPABILITY_REQUIRED_SCHEMAS", + 6: "CAPABILITY_DEPENDENCIES", } Capability_value = map[string]int32{ "CAPABILITY_UNSPECIFIED": 0, @@ -92,6 +154,7 @@ var ( "CAPABILITY_CREDENTIALS": 3, "CAPABILITY_CONDITIONS": 4, "CAPABILITY_REQUIRED_SCHEMAS": 5, + "CAPABILITY_DEPENDENCIES": 6, } ) @@ -106,11 +169,11 @@ func (x Capability) String() string { } func (Capability) Descriptor() protoreflect.EnumDescriptor { - return file_v1_run_function_proto_enumTypes[0].Descriptor() + return file_v1_run_function_proto_enumTypes[1].Descriptor() } func (Capability) Type() protoreflect.EnumType { - return &file_v1_run_function_proto_enumTypes[0] + return &file_v1_run_function_proto_enumTypes[1] } func (x Capability) Number() protoreflect.EnumNumber { @@ -119,7 +182,7 @@ func (x Capability) Number() protoreflect.EnumNumber { // Deprecated: Use Capability.Descriptor instead. func (Capability) EnumDescriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{0} + return file_v1_run_function_proto_rawDescGZIP(), []int{1} } // Ready indicates whether a resource should be considered ready. @@ -158,11 +221,11 @@ func (x Ready) String() string { } func (Ready) Descriptor() protoreflect.EnumDescriptor { - return file_v1_run_function_proto_enumTypes[1].Descriptor() + return file_v1_run_function_proto_enumTypes[2].Descriptor() } func (Ready) Type() protoreflect.EnumType { - return &file_v1_run_function_proto_enumTypes[1] + return &file_v1_run_function_proto_enumTypes[2] } func (x Ready) Number() protoreflect.EnumNumber { @@ -171,7 +234,7 @@ func (x Ready) Number() protoreflect.EnumNumber { // Deprecated: Use Ready.Descriptor instead. func (Ready) EnumDescriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{1} + return file_v1_run_function_proto_rawDescGZIP(), []int{2} } // Severity of function results. @@ -219,11 +282,11 @@ func (x Severity) String() string { } func (Severity) Descriptor() protoreflect.EnumDescriptor { - return file_v1_run_function_proto_enumTypes[2].Descriptor() + return file_v1_run_function_proto_enumTypes[3].Descriptor() } func (Severity) Type() protoreflect.EnumType { - return &file_v1_run_function_proto_enumTypes[2] + return &file_v1_run_function_proto_enumTypes[3] } func (x Severity) Number() protoreflect.EnumNumber { @@ -232,7 +295,7 @@ func (x Severity) Number() protoreflect.EnumNumber { // Deprecated: Use Severity.Descriptor instead. func (Severity) EnumDescriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{2} + return file_v1_run_function_proto_rawDescGZIP(), []int{3} } // Target of function results and conditions. @@ -274,11 +337,11 @@ func (x Target) String() string { } func (Target) Descriptor() protoreflect.EnumDescriptor { - return file_v1_run_function_proto_enumTypes[3].Descriptor() + return file_v1_run_function_proto_enumTypes[4].Descriptor() } func (Target) Type() protoreflect.EnumType { - return &file_v1_run_function_proto_enumTypes[3] + return &file_v1_run_function_proto_enumTypes[4] } func (x Target) Number() protoreflect.EnumNumber { @@ -287,7 +350,7 @@ func (x Target) Number() protoreflect.EnumNumber { // Deprecated: Use Target.Descriptor instead. func (Target) EnumDescriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{3} + return file_v1_run_function_proto_rawDescGZIP(), []int{4} } type Status int32 @@ -326,11 +389,11 @@ func (x Status) String() string { } func (Status) Descriptor() protoreflect.EnumDescriptor { - return file_v1_run_function_proto_enumTypes[4].Descriptor() + return file_v1_run_function_proto_enumTypes[5].Descriptor() } func (Status) Type() protoreflect.EnumType { - return &file_v1_run_function_proto_enumTypes[4] + return &file_v1_run_function_proto_enumTypes[5] } func (x Status) Number() protoreflect.EnumNumber { @@ -339,7 +402,7 @@ func (x Status) Number() protoreflect.EnumNumber { // Deprecated: Use Status.Descriptor instead. func (Status) EnumDescriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{4} + return file_v1_run_function_proto_rawDescGZIP(), []int{5} } // A RunFunctionRequest requests that the function be run. @@ -399,8 +462,11 @@ type RunFunctionRequest struct { // sets the map key to an empty Schema message to indicate that it attempted // to satisfy the request. RequiredSchemas map[string]*Schema `protobuf:"bytes,9,rep,name=required_schemas,json=requiredSchemas,proto3" json:"required_schemas,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Optional ordering constraints over composed resources, accumulated by the + // functions that ran before this one. + Dependencies *Dependencies `protobuf:"bytes,10,opt,name=dependencies,proto3" json:"dependencies,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *RunFunctionRequest) Reset() { @@ -497,6 +563,13 @@ func (x *RunFunctionRequest) GetRequiredSchemas() map[string]*Schema { return nil } +func (x *RunFunctionRequest) GetDependencies() *Dependencies { + if x != nil { + return x.Dependencies + } + return nil +} + // Credentials that a function may use to communicate with an external system. type Credentials struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -657,6 +730,240 @@ func (x *Resources) GetItems() []*Resource { return nil } +// Dependencies is a set of ordering constraints over composed resources. +// +// This is a message wrapping a repeated field, rather than a bare repeated +// field, so that an unset value can be told apart from an empty one. A bare +// repeated field can't express that difference: proto3 has no presence for +// repeated fields, and an empty list and an unset field are both zero bytes on +// the wire. Crossplane relies on the difference, because an unset value means +// "this function has no opinion, carry my constraints forward" while an empty +// one means "this function wants no constraints at all." State wraps desired +// and observed resources for the same reason. +type Dependencies struct { + state protoimpl.MessageState `protogen:"open.v1"` + Items []*Dependency `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Dependencies) Reset() { + *x = Dependencies{} + mi := &file_v1_run_function_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Dependencies) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Dependencies) ProtoMessage() {} + +func (x *Dependencies) ProtoReflect() protoreflect.Message { + mi := &file_v1_run_function_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Dependencies.ProtoReflect.Descriptor instead. +func (*Dependencies) Descriptor() ([]byte, []int) { + return file_v1_run_function_proto_rawDescGZIP(), []int{4} +} + +func (x *Dependencies) GetItems() []*Dependency { + if x != nil { + return x.Items + } + return nil +} + +// A Dependency declares that one composed resource must be created after, and +// deleted before, another resource. It expresses ordering only. It doesn't move +// any data between resources. +type Dependency struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Name of the composed resource that has the dependency. A key into the + // desired or observed State.resources map. + Resource string `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` + // What the resource depends on. + // + // Types that are valid to be assigned to DependsOn: + // + // *Dependency_ComposedResource + // *Dependency_RequiredResource + DependsOn isDependency_DependsOn `protobuf_oneof:"depends_on"` + // How this dependency constrains the order its endpoints are created and + // deleted. Defaults to symmetric ordering. + Lifecycle DependencyLifecycle `protobuf:"varint,3,opt,name=lifecycle,proto3,enum=apiextensions.fn.proto.v1.DependencyLifecycle" json:"lifecycle,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Dependency) Reset() { + *x = Dependency{} + mi := &file_v1_run_function_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Dependency) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Dependency) ProtoMessage() {} + +func (x *Dependency) ProtoReflect() protoreflect.Message { + mi := &file_v1_run_function_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Dependency.ProtoReflect.Descriptor instead. +func (*Dependency) Descriptor() ([]byte, []int) { + return file_v1_run_function_proto_rawDescGZIP(), []int{5} +} + +func (x *Dependency) GetResource() string { + if x != nil { + return x.Resource + } + return "" +} + +func (x *Dependency) GetDependsOn() isDependency_DependsOn { + if x != nil { + return x.DependsOn + } + return nil +} + +func (x *Dependency) GetComposedResource() string { + if x != nil { + if x, ok := x.DependsOn.(*Dependency_ComposedResource); ok { + return x.ComposedResource + } + } + return "" +} + +func (x *Dependency) GetRequiredResource() *RequiredResourceDependency { + if x != nil { + if x, ok := x.DependsOn.(*Dependency_RequiredResource); ok { + return x.RequiredResource + } + } + return nil +} + +func (x *Dependency) GetLifecycle() DependencyLifecycle { + if x != nil { + return x.Lifecycle + } + return DependencyLifecycle_DEPENDENCY_LIFECYCLE_UNSPECIFIED +} + +type isDependency_DependsOn interface { + isDependency_DependsOn() +} + +type Dependency_ComposedResource struct { + // Name of another composed resource. A key into the desired or observed + // State.resources map. + ComposedResource string `protobuf:"bytes,2,opt,name=composed_resource,json=composedResource,proto3,oneof"` +} + +type Dependency_RequiredResource struct { + // A resource the pipeline required, rather than composed. Crossplane never + // deletes a resource it didn't compose, so these constrain only the order + // resources are created and updated. + RequiredResource *RequiredResourceDependency `protobuf:"bytes,4,opt,name=required_resource,json=requiredResource,proto3,oneof"` +} + +func (*Dependency_ComposedResource) isDependency_DependsOn() {} + +func (*Dependency_RequiredResource) isDependency_DependsOn() {} + +// A RequiredResourceDependency identifies a resource the pipeline required, +// for the purpose of ordering. +type RequiredResourceDependency struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The requirement name. A key into a RunFunctionRequest's required_resources + // map, and into a RunFunctionResponse's requirements.resources map. + RequirementName string `protobuf:"bytes,1,opt,name=requirement_name,json=requirementName,proto3" json:"requirement_name,omitempty"` + // Optional name of a single resource within the set the requirement matched. + // If unset, every resource the requirement matched must be ready. + Name *string `protobuf:"bytes,2,opt,name=name,proto3,oneof" json:"name,omitempty"` + // Namespace of name for a namespaced resource. Leave unset for a + // cluster-scoped resource. name and namespace together identify one match. + Namespace *string `protobuf:"bytes,3,opt,name=namespace,proto3,oneof" json:"namespace,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RequiredResourceDependency) Reset() { + *x = RequiredResourceDependency{} + mi := &file_v1_run_function_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RequiredResourceDependency) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequiredResourceDependency) ProtoMessage() {} + +func (x *RequiredResourceDependency) ProtoReflect() protoreflect.Message { + mi := &file_v1_run_function_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequiredResourceDependency.ProtoReflect.Descriptor instead. +func (*RequiredResourceDependency) Descriptor() ([]byte, []int) { + return file_v1_run_function_proto_rawDescGZIP(), []int{6} +} + +func (x *RequiredResourceDependency) GetRequirementName() string { + if x != nil { + return x.RequirementName + } + return "" +} + +func (x *RequiredResourceDependency) GetName() string { + if x != nil && x.Name != nil { + return *x.Name + } + return "" +} + +func (x *RequiredResourceDependency) GetNamespace() string { + if x != nil && x.Namespace != nil { + return *x.Namespace + } + return "" +} + // A RunFunctionResponse contains the result of a function run. type RunFunctionResponse struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -689,14 +996,21 @@ type RunFunctionResponse struct { // Optional output specific to this function invocation. // // Only Operations use function output. XRs will discard any function output. - Output *structpb.Struct `protobuf:"bytes,7,opt,name=output,proto3,oneof" json:"output,omitempty"` + Output *structpb.Struct `protobuf:"bytes,7,opt,name=output,proto3,oneof" json:"output,omitempty"` + // Optional ordering constraints over composed resources. A function that has + // an opinion about ordering must return the full set it wants going forward, + // including edges it received and still wants. Leaving this field unset means + // "no opinion" - Crossplane carries forward whatever it sent in the request. + // + // Dependencies are only used for composition. They're ignored by Operations. + Dependencies *Dependencies `protobuf:"bytes,8,opt,name=dependencies,proto3" json:"dependencies,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *RunFunctionResponse) Reset() { *x = RunFunctionResponse{} - mi := &file_v1_run_function_proto_msgTypes[4] + mi := &file_v1_run_function_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -708,7 +1022,7 @@ func (x *RunFunctionResponse) String() string { func (*RunFunctionResponse) ProtoMessage() {} func (x *RunFunctionResponse) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[4] + mi := &file_v1_run_function_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -721,7 +1035,7 @@ func (x *RunFunctionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RunFunctionResponse.ProtoReflect.Descriptor instead. func (*RunFunctionResponse) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{4} + return file_v1_run_function_proto_rawDescGZIP(), []int{7} } func (x *RunFunctionResponse) GetMeta() *ResponseMeta { @@ -773,6 +1087,13 @@ func (x *RunFunctionResponse) GetOutput() *structpb.Struct { return nil } +func (x *RunFunctionResponse) GetDependencies() *Dependencies { + if x != nil { + return x.Dependencies + } + return nil +} + // RequestMeta contains metadata pertaining to a RunFunctionRequest. type RequestMeta struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -789,7 +1110,7 @@ type RequestMeta struct { func (x *RequestMeta) Reset() { *x = RequestMeta{} - mi := &file_v1_run_function_proto_msgTypes[5] + mi := &file_v1_run_function_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -801,7 +1122,7 @@ func (x *RequestMeta) String() string { func (*RequestMeta) ProtoMessage() {} func (x *RequestMeta) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[5] + mi := &file_v1_run_function_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -814,7 +1135,7 @@ func (x *RequestMeta) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestMeta.ProtoReflect.Descriptor instead. func (*RequestMeta) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{5} + return file_v1_run_function_proto_rawDescGZIP(), []int{8} } func (x *RequestMeta) GetTag() string { @@ -853,7 +1174,7 @@ type Requirements struct { func (x *Requirements) Reset() { *x = Requirements{} - mi := &file_v1_run_function_proto_msgTypes[6] + mi := &file_v1_run_function_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -865,7 +1186,7 @@ func (x *Requirements) String() string { func (*Requirements) ProtoMessage() {} func (x *Requirements) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[6] + mi := &file_v1_run_function_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -878,7 +1199,7 @@ func (x *Requirements) ProtoReflect() protoreflect.Message { // Deprecated: Use Requirements.ProtoReflect.Descriptor instead. func (*Requirements) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{6} + return file_v1_run_function_proto_rawDescGZIP(), []int{9} } // Deprecated: Marked as deprecated in v1/run_function.proto. @@ -916,7 +1237,7 @@ type SchemaSelector struct { func (x *SchemaSelector) Reset() { *x = SchemaSelector{} - mi := &file_v1_run_function_proto_msgTypes[7] + mi := &file_v1_run_function_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -928,7 +1249,7 @@ func (x *SchemaSelector) String() string { func (*SchemaSelector) ProtoMessage() {} func (x *SchemaSelector) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[7] + mi := &file_v1_run_function_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -941,7 +1262,7 @@ func (x *SchemaSelector) ProtoReflect() protoreflect.Message { // Deprecated: Use SchemaSelector.ProtoReflect.Descriptor instead. func (*SchemaSelector) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{7} + return file_v1_run_function_proto_rawDescGZIP(), []int{10} } func (x *SchemaSelector) GetApiVersion() string { @@ -971,7 +1292,7 @@ type Schema struct { func (x *Schema) Reset() { *x = Schema{} - mi := &file_v1_run_function_proto_msgTypes[8] + mi := &file_v1_run_function_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -983,7 +1304,7 @@ func (x *Schema) String() string { func (*Schema) ProtoMessage() {} func (x *Schema) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[8] + mi := &file_v1_run_function_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -996,7 +1317,7 @@ func (x *Schema) ProtoReflect() protoreflect.Message { // Deprecated: Use Schema.ProtoReflect.Descriptor instead. func (*Schema) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{8} + return file_v1_run_function_proto_rawDescGZIP(), []int{11} } func (x *Schema) GetOpenapiV3() *structpb.Struct { @@ -1030,7 +1351,7 @@ type ResourceSelector struct { func (x *ResourceSelector) Reset() { *x = ResourceSelector{} - mi := &file_v1_run_function_proto_msgTypes[9] + mi := &file_v1_run_function_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1042,7 +1363,7 @@ func (x *ResourceSelector) String() string { func (*ResourceSelector) ProtoMessage() {} func (x *ResourceSelector) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[9] + mi := &file_v1_run_function_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1055,7 +1376,7 @@ func (x *ResourceSelector) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceSelector.ProtoReflect.Descriptor instead. func (*ResourceSelector) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{9} + return file_v1_run_function_proto_rawDescGZIP(), []int{12} } func (x *ResourceSelector) GetApiVersion() string { @@ -1132,7 +1453,7 @@ type MatchLabels struct { func (x *MatchLabels) Reset() { *x = MatchLabels{} - mi := &file_v1_run_function_proto_msgTypes[10] + mi := &file_v1_run_function_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1144,7 +1465,7 @@ func (x *MatchLabels) String() string { func (*MatchLabels) ProtoMessage() {} func (x *MatchLabels) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[10] + mi := &file_v1_run_function_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1157,7 +1478,7 @@ func (x *MatchLabels) ProtoReflect() protoreflect.Message { // Deprecated: Use MatchLabels.ProtoReflect.Descriptor instead. func (*MatchLabels) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{10} + return file_v1_run_function_proto_rawDescGZIP(), []int{13} } func (x *MatchLabels) GetLabels() map[string]string { @@ -1183,7 +1504,7 @@ type ResponseMeta struct { func (x *ResponseMeta) Reset() { *x = ResponseMeta{} - mi := &file_v1_run_function_proto_msgTypes[11] + mi := &file_v1_run_function_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1195,7 +1516,7 @@ func (x *ResponseMeta) String() string { func (*ResponseMeta) ProtoMessage() {} func (x *ResponseMeta) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[11] + mi := &file_v1_run_function_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1208,7 +1529,7 @@ func (x *ResponseMeta) ProtoReflect() protoreflect.Message { // Deprecated: Use ResponseMeta.ProtoReflect.Descriptor instead. func (*ResponseMeta) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{11} + return file_v1_run_function_proto_rawDescGZIP(), []int{14} } func (x *ResponseMeta) GetTag() string { @@ -1240,7 +1561,7 @@ type State struct { func (x *State) Reset() { *x = State{} - mi := &file_v1_run_function_proto_msgTypes[12] + mi := &file_v1_run_function_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1252,7 +1573,7 @@ func (x *State) String() string { func (*State) ProtoMessage() {} func (x *State) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[12] + mi := &file_v1_run_function_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1265,7 +1586,7 @@ func (x *State) ProtoReflect() protoreflect.Message { // Deprecated: Use State.ProtoReflect.Descriptor instead. func (*State) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{12} + return file_v1_run_function_proto_rawDescGZIP(), []int{15} } func (x *State) GetComposite() *Resource { @@ -1336,7 +1657,7 @@ type Resource struct { func (x *Resource) Reset() { *x = Resource{} - mi := &file_v1_run_function_proto_msgTypes[13] + mi := &file_v1_run_function_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1348,7 +1669,7 @@ func (x *Resource) String() string { func (*Resource) ProtoMessage() {} func (x *Resource) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[13] + mi := &file_v1_run_function_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1361,7 +1682,7 @@ func (x *Resource) ProtoReflect() protoreflect.Message { // Deprecated: Use Resource.ProtoReflect.Descriptor instead. func (*Resource) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{13} + return file_v1_run_function_proto_rawDescGZIP(), []int{16} } func (x *Resource) GetResource() *structpb.Struct { @@ -1403,7 +1724,7 @@ type Result struct { func (x *Result) Reset() { *x = Result{} - mi := &file_v1_run_function_proto_msgTypes[14] + mi := &file_v1_run_function_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1415,7 +1736,7 @@ func (x *Result) String() string { func (*Result) ProtoMessage() {} func (x *Result) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[14] + mi := &file_v1_run_function_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1428,7 +1749,7 @@ func (x *Result) ProtoReflect() protoreflect.Message { // Deprecated: Use Result.ProtoReflect.Descriptor instead. func (*Result) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{14} + return file_v1_run_function_proto_rawDescGZIP(), []int{17} } func (x *Result) GetSeverity() Severity { @@ -1486,7 +1807,7 @@ type Condition struct { func (x *Condition) Reset() { *x = Condition{} - mi := &file_v1_run_function_proto_msgTypes[15] + mi := &file_v1_run_function_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1498,7 +1819,7 @@ func (x *Condition) String() string { func (*Condition) ProtoMessage() {} func (x *Condition) ProtoReflect() protoreflect.Message { - mi := &file_v1_run_function_proto_msgTypes[15] + mi := &file_v1_run_function_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1511,7 +1832,7 @@ func (x *Condition) ProtoReflect() protoreflect.Message { // Deprecated: Use Condition.ProtoReflect.Descriptor instead. func (*Condition) Descriptor() ([]byte, []int) { - return file_v1_run_function_proto_rawDescGZIP(), []int{15} + return file_v1_run_function_proto_rawDescGZIP(), []int{18} } func (x *Condition) GetType() string { @@ -1553,7 +1874,7 @@ var File_v1_run_function_proto protoreflect.FileDescriptor const file_v1_run_function_proto_rawDesc = "" + "\n" + - "\x15v1/run_function.proto\x12\x19apiextensions.fn.proto.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xa6\t\n" + + "\x15v1/run_function.proto\x12\x19apiextensions.fn.proto.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xf3\t\n" + "\x12RunFunctionRequest\x12:\n" + "\x04meta\x18\x01 \x01(\v2&.apiextensions.fn.proto.v1.RequestMetaR\x04meta\x12<\n" + "\bobserved\x18\x02 \x01(\v2 .apiextensions.fn.proto.v1.StateR\bobserved\x12:\n" + @@ -1563,7 +1884,9 @@ const file_v1_run_function_proto_rawDesc = "" + "\x0fextra_resources\x18\x06 \x03(\v2A.apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntryB\x02\x18\x01R\x0eextraResources\x12`\n" + "\vcredentials\x18\a \x03(\v2>.apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntryR\vcredentials\x12s\n" + "\x12required_resources\x18\b \x03(\v2D.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntryR\x11requiredResources\x12m\n" + - "\x10required_schemas\x18\t \x03(\v2B.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntryR\x0frequiredSchemas\x1ag\n" + + "\x10required_schemas\x18\t \x03(\v2B.apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntryR\x0frequiredSchemas\x12K\n" + + "\fdependencies\x18\n" + + " \x01(\v2'.apiextensions.fn.proto.v1.DependenciesR\fdependencies\x1ag\n" + "\x13ExtraResourcesEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12:\n" + "\x05value\x18\x02 \x01(\v2$.apiextensions.fn.proto.v1.ResourcesR\x05value:\x028\x01\x1af\n" + @@ -1588,7 +1911,24 @@ const file_v1_run_function_proto_rawDesc = "" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\fR\x05value:\x028\x01\"F\n" + "\tResources\x129\n" + - "\x05items\x18\x01 \x03(\v2#.apiextensions.fn.proto.v1.ResourceR\x05items\"\xe3\x03\n" + + "\x05items\x18\x01 \x03(\v2#.apiextensions.fn.proto.v1.ResourceR\x05items\"K\n" + + "\fDependencies\x12;\n" + + "\x05items\x18\x01 \x03(\v2%.apiextensions.fn.proto.v1.DependencyR\x05items\"\x99\x02\n" + + "\n" + + "Dependency\x12\x1a\n" + + "\bresource\x18\x01 \x01(\tR\bresource\x12-\n" + + "\x11composed_resource\x18\x02 \x01(\tH\x00R\x10composedResource\x12d\n" + + "\x11required_resource\x18\x04 \x01(\v25.apiextensions.fn.proto.v1.RequiredResourceDependencyH\x00R\x10requiredResource\x12L\n" + + "\tlifecycle\x18\x03 \x01(\x0e2..apiextensions.fn.proto.v1.DependencyLifecycleR\tlifecycleB\f\n" + + "\n" + + "depends_on\"\x9a\x01\n" + + "\x1aRequiredResourceDependency\x12)\n" + + "\x10requirement_name\x18\x01 \x01(\tR\x0frequirementName\x12\x17\n" + + "\x04name\x18\x02 \x01(\tH\x00R\x04name\x88\x01\x01\x12!\n" + + "\tnamespace\x18\x03 \x01(\tH\x01R\tnamespace\x88\x01\x01B\a\n" + + "\x05_nameB\f\n" + + "\n" + + "_namespace\"\xb0\x04\n" + "\x13RunFunctionResponse\x12;\n" + "\x04meta\x18\x01 \x01(\v2'.apiextensions.fn.proto.v1.ResponseMetaR\x04meta\x12:\n" + "\adesired\x18\x02 \x01(\v2 .apiextensions.fn.proto.v1.StateR\adesired\x12;\n" + @@ -1598,7 +1938,8 @@ const file_v1_run_function_proto_rawDesc = "" + "\n" + "conditions\x18\x06 \x03(\v2$.apiextensions.fn.proto.v1.ConditionR\n" + "conditions\x124\n" + - "\x06output\x18\a \x01(\v2\x17.google.protobuf.StructH\x01R\x06output\x88\x01\x01B\n" + + "\x06output\x18\a \x01(\v2\x17.google.protobuf.StructH\x01R\x06output\x88\x01\x01\x12K\n" + + "\fdependencies\x18\b \x01(\v2'.apiextensions.fn.proto.v1.DependenciesR\fdependenciesB\n" + "\n" + "\b_contextB\t\n" + "\a_output\"j\n" + @@ -1674,7 +2015,10 @@ const file_v1_run_function_proto_rawDesc = "" + "\x06target\x18\x05 \x01(\x0e2!.apiextensions.fn.proto.v1.TargetH\x01R\x06target\x88\x01\x01B\n" + "\n" + "\b_messageB\t\n" + - "\a_target*\xc0\x01\n" + + "\a_target*k\n" + + "\x13DependencyLifecycle\x12$\n" + + " DEPENDENCY_LIFECYCLE_UNSPECIFIED\x10\x00\x12.\n" + + "*DEPENDENCY_LIFECYCLE_CREATE_BEFORE_DESTROY\x10\x01*\xdd\x01\n" + "\n" + "Capability\x12\x1a\n" + "\x16CAPABILITY_UNSPECIFIED\x10\x00\x12\x1b\n" + @@ -1682,7 +2026,8 @@ const file_v1_run_function_proto_rawDesc = "" + "\x1dCAPABILITY_REQUIRED_RESOURCES\x10\x02\x12\x1a\n" + "\x16CAPABILITY_CREDENTIALS\x10\x03\x12\x19\n" + "\x15CAPABILITY_CONDITIONS\x10\x04\x12\x1f\n" + - "\x1bCAPABILITY_REQUIRED_SCHEMAS\x10\x05*?\n" + + "\x1bCAPABILITY_REQUIRED_SCHEMAS\x10\x05\x12\x1b\n" + + "\x17CAPABILITY_DEPENDENCIES\x10\x06*?\n" + "\x05Ready\x12\x15\n" + "\x11READY_UNSPECIFIED\x10\x00\x12\x0e\n" + "\n" + @@ -1717,96 +2062,105 @@ func file_v1_run_function_proto_rawDescGZIP() []byte { return file_v1_run_function_proto_rawDescData } -var file_v1_run_function_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_v1_run_function_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_v1_run_function_proto_enumTypes = make([]protoimpl.EnumInfo, 6) +var file_v1_run_function_proto_msgTypes = make([]protoimpl.MessageInfo, 30) var file_v1_run_function_proto_goTypes = []any{ - (Capability)(0), // 0: apiextensions.fn.proto.v1.Capability - (Ready)(0), // 1: apiextensions.fn.proto.v1.Ready - (Severity)(0), // 2: apiextensions.fn.proto.v1.Severity - (Target)(0), // 3: apiextensions.fn.proto.v1.Target - (Status)(0), // 4: apiextensions.fn.proto.v1.Status - (*RunFunctionRequest)(nil), // 5: apiextensions.fn.proto.v1.RunFunctionRequest - (*Credentials)(nil), // 6: apiextensions.fn.proto.v1.Credentials - (*CredentialData)(nil), // 7: apiextensions.fn.proto.v1.CredentialData - (*Resources)(nil), // 8: apiextensions.fn.proto.v1.Resources - (*RunFunctionResponse)(nil), // 9: apiextensions.fn.proto.v1.RunFunctionResponse - (*RequestMeta)(nil), // 10: apiextensions.fn.proto.v1.RequestMeta - (*Requirements)(nil), // 11: apiextensions.fn.proto.v1.Requirements - (*SchemaSelector)(nil), // 12: apiextensions.fn.proto.v1.SchemaSelector - (*Schema)(nil), // 13: apiextensions.fn.proto.v1.Schema - (*ResourceSelector)(nil), // 14: apiextensions.fn.proto.v1.ResourceSelector - (*MatchLabels)(nil), // 15: apiextensions.fn.proto.v1.MatchLabels - (*ResponseMeta)(nil), // 16: apiextensions.fn.proto.v1.ResponseMeta - (*State)(nil), // 17: apiextensions.fn.proto.v1.State - (*Resource)(nil), // 18: apiextensions.fn.proto.v1.Resource - (*Result)(nil), // 19: apiextensions.fn.proto.v1.Result - (*Condition)(nil), // 20: apiextensions.fn.proto.v1.Condition - nil, // 21: apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntry - nil, // 22: apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry - nil, // 23: apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry - nil, // 24: apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntry - nil, // 25: apiextensions.fn.proto.v1.CredentialData.DataEntry - nil, // 26: apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntry - nil, // 27: apiextensions.fn.proto.v1.Requirements.ResourcesEntry - nil, // 28: apiextensions.fn.proto.v1.Requirements.SchemasEntry - nil, // 29: apiextensions.fn.proto.v1.MatchLabels.LabelsEntry - nil, // 30: apiextensions.fn.proto.v1.State.ResourcesEntry - nil, // 31: apiextensions.fn.proto.v1.Resource.ConnectionDetailsEntry - (*structpb.Struct)(nil), // 32: google.protobuf.Struct - (*durationpb.Duration)(nil), // 33: google.protobuf.Duration + (DependencyLifecycle)(0), // 0: apiextensions.fn.proto.v1.DependencyLifecycle + (Capability)(0), // 1: apiextensions.fn.proto.v1.Capability + (Ready)(0), // 2: apiextensions.fn.proto.v1.Ready + (Severity)(0), // 3: apiextensions.fn.proto.v1.Severity + (Target)(0), // 4: apiextensions.fn.proto.v1.Target + (Status)(0), // 5: apiextensions.fn.proto.v1.Status + (*RunFunctionRequest)(nil), // 6: apiextensions.fn.proto.v1.RunFunctionRequest + (*Credentials)(nil), // 7: apiextensions.fn.proto.v1.Credentials + (*CredentialData)(nil), // 8: apiextensions.fn.proto.v1.CredentialData + (*Resources)(nil), // 9: apiextensions.fn.proto.v1.Resources + (*Dependencies)(nil), // 10: apiextensions.fn.proto.v1.Dependencies + (*Dependency)(nil), // 11: apiextensions.fn.proto.v1.Dependency + (*RequiredResourceDependency)(nil), // 12: apiextensions.fn.proto.v1.RequiredResourceDependency + (*RunFunctionResponse)(nil), // 13: apiextensions.fn.proto.v1.RunFunctionResponse + (*RequestMeta)(nil), // 14: apiextensions.fn.proto.v1.RequestMeta + (*Requirements)(nil), // 15: apiextensions.fn.proto.v1.Requirements + (*SchemaSelector)(nil), // 16: apiextensions.fn.proto.v1.SchemaSelector + (*Schema)(nil), // 17: apiextensions.fn.proto.v1.Schema + (*ResourceSelector)(nil), // 18: apiextensions.fn.proto.v1.ResourceSelector + (*MatchLabels)(nil), // 19: apiextensions.fn.proto.v1.MatchLabels + (*ResponseMeta)(nil), // 20: apiextensions.fn.proto.v1.ResponseMeta + (*State)(nil), // 21: apiextensions.fn.proto.v1.State + (*Resource)(nil), // 22: apiextensions.fn.proto.v1.Resource + (*Result)(nil), // 23: apiextensions.fn.proto.v1.Result + (*Condition)(nil), // 24: apiextensions.fn.proto.v1.Condition + nil, // 25: apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntry + nil, // 26: apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry + nil, // 27: apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry + nil, // 28: apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntry + nil, // 29: apiextensions.fn.proto.v1.CredentialData.DataEntry + nil, // 30: apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntry + nil, // 31: apiextensions.fn.proto.v1.Requirements.ResourcesEntry + nil, // 32: apiextensions.fn.proto.v1.Requirements.SchemasEntry + nil, // 33: apiextensions.fn.proto.v1.MatchLabels.LabelsEntry + nil, // 34: apiextensions.fn.proto.v1.State.ResourcesEntry + nil, // 35: apiextensions.fn.proto.v1.Resource.ConnectionDetailsEntry + (*structpb.Struct)(nil), // 36: google.protobuf.Struct + (*durationpb.Duration)(nil), // 37: google.protobuf.Duration } var file_v1_run_function_proto_depIdxs = []int32{ - 10, // 0: apiextensions.fn.proto.v1.RunFunctionRequest.meta:type_name -> apiextensions.fn.proto.v1.RequestMeta - 17, // 1: apiextensions.fn.proto.v1.RunFunctionRequest.observed:type_name -> apiextensions.fn.proto.v1.State - 17, // 2: apiextensions.fn.proto.v1.RunFunctionRequest.desired:type_name -> apiextensions.fn.proto.v1.State - 32, // 3: apiextensions.fn.proto.v1.RunFunctionRequest.input:type_name -> google.protobuf.Struct - 32, // 4: apiextensions.fn.proto.v1.RunFunctionRequest.context:type_name -> google.protobuf.Struct - 21, // 5: apiextensions.fn.proto.v1.RunFunctionRequest.extra_resources:type_name -> apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntry - 22, // 6: apiextensions.fn.proto.v1.RunFunctionRequest.credentials:type_name -> apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry - 23, // 7: apiextensions.fn.proto.v1.RunFunctionRequest.required_resources:type_name -> apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry - 24, // 8: apiextensions.fn.proto.v1.RunFunctionRequest.required_schemas:type_name -> apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntry - 7, // 9: apiextensions.fn.proto.v1.Credentials.credential_data:type_name -> apiextensions.fn.proto.v1.CredentialData - 25, // 10: apiextensions.fn.proto.v1.CredentialData.data:type_name -> apiextensions.fn.proto.v1.CredentialData.DataEntry - 18, // 11: apiextensions.fn.proto.v1.Resources.items:type_name -> apiextensions.fn.proto.v1.Resource - 16, // 12: apiextensions.fn.proto.v1.RunFunctionResponse.meta:type_name -> apiextensions.fn.proto.v1.ResponseMeta - 17, // 13: apiextensions.fn.proto.v1.RunFunctionResponse.desired:type_name -> apiextensions.fn.proto.v1.State - 19, // 14: apiextensions.fn.proto.v1.RunFunctionResponse.results:type_name -> apiextensions.fn.proto.v1.Result - 32, // 15: apiextensions.fn.proto.v1.RunFunctionResponse.context:type_name -> google.protobuf.Struct - 11, // 16: apiextensions.fn.proto.v1.RunFunctionResponse.requirements:type_name -> apiextensions.fn.proto.v1.Requirements - 20, // 17: apiextensions.fn.proto.v1.RunFunctionResponse.conditions:type_name -> apiextensions.fn.proto.v1.Condition - 32, // 18: apiextensions.fn.proto.v1.RunFunctionResponse.output:type_name -> google.protobuf.Struct - 0, // 19: apiextensions.fn.proto.v1.RequestMeta.capabilities:type_name -> apiextensions.fn.proto.v1.Capability - 26, // 20: apiextensions.fn.proto.v1.Requirements.extra_resources:type_name -> apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntry - 27, // 21: apiextensions.fn.proto.v1.Requirements.resources:type_name -> apiextensions.fn.proto.v1.Requirements.ResourcesEntry - 28, // 22: apiextensions.fn.proto.v1.Requirements.schemas:type_name -> apiextensions.fn.proto.v1.Requirements.SchemasEntry - 32, // 23: apiextensions.fn.proto.v1.Schema.openapi_v3:type_name -> google.protobuf.Struct - 15, // 24: apiextensions.fn.proto.v1.ResourceSelector.match_labels:type_name -> apiextensions.fn.proto.v1.MatchLabels - 29, // 25: apiextensions.fn.proto.v1.MatchLabels.labels:type_name -> apiextensions.fn.proto.v1.MatchLabels.LabelsEntry - 33, // 26: apiextensions.fn.proto.v1.ResponseMeta.ttl:type_name -> google.protobuf.Duration - 18, // 27: apiextensions.fn.proto.v1.State.composite:type_name -> apiextensions.fn.proto.v1.Resource - 30, // 28: apiextensions.fn.proto.v1.State.resources:type_name -> apiextensions.fn.proto.v1.State.ResourcesEntry - 32, // 29: apiextensions.fn.proto.v1.Resource.resource:type_name -> google.protobuf.Struct - 31, // 30: apiextensions.fn.proto.v1.Resource.connection_details:type_name -> apiextensions.fn.proto.v1.Resource.ConnectionDetailsEntry - 1, // 31: apiextensions.fn.proto.v1.Resource.ready:type_name -> apiextensions.fn.proto.v1.Ready - 2, // 32: apiextensions.fn.proto.v1.Result.severity:type_name -> apiextensions.fn.proto.v1.Severity - 3, // 33: apiextensions.fn.proto.v1.Result.target:type_name -> apiextensions.fn.proto.v1.Target - 4, // 34: apiextensions.fn.proto.v1.Condition.status:type_name -> apiextensions.fn.proto.v1.Status - 3, // 35: apiextensions.fn.proto.v1.Condition.target:type_name -> apiextensions.fn.proto.v1.Target - 8, // 36: apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.Resources - 6, // 37: apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry.value:type_name -> apiextensions.fn.proto.v1.Credentials - 8, // 38: apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.Resources - 13, // 39: apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntry.value:type_name -> apiextensions.fn.proto.v1.Schema - 14, // 40: apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.ResourceSelector - 14, // 41: apiextensions.fn.proto.v1.Requirements.ResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.ResourceSelector - 12, // 42: apiextensions.fn.proto.v1.Requirements.SchemasEntry.value:type_name -> apiextensions.fn.proto.v1.SchemaSelector - 18, // 43: apiextensions.fn.proto.v1.State.ResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.Resource - 5, // 44: apiextensions.fn.proto.v1.FunctionRunnerService.RunFunction:input_type -> apiextensions.fn.proto.v1.RunFunctionRequest - 9, // 45: apiextensions.fn.proto.v1.FunctionRunnerService.RunFunction:output_type -> apiextensions.fn.proto.v1.RunFunctionResponse - 45, // [45:46] is the sub-list for method output_type - 44, // [44:45] is the sub-list for method input_type - 44, // [44:44] is the sub-list for extension type_name - 44, // [44:44] is the sub-list for extension extendee - 0, // [0:44] is the sub-list for field type_name + 14, // 0: apiextensions.fn.proto.v1.RunFunctionRequest.meta:type_name -> apiextensions.fn.proto.v1.RequestMeta + 21, // 1: apiextensions.fn.proto.v1.RunFunctionRequest.observed:type_name -> apiextensions.fn.proto.v1.State + 21, // 2: apiextensions.fn.proto.v1.RunFunctionRequest.desired:type_name -> apiextensions.fn.proto.v1.State + 36, // 3: apiextensions.fn.proto.v1.RunFunctionRequest.input:type_name -> google.protobuf.Struct + 36, // 4: apiextensions.fn.proto.v1.RunFunctionRequest.context:type_name -> google.protobuf.Struct + 25, // 5: apiextensions.fn.proto.v1.RunFunctionRequest.extra_resources:type_name -> apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntry + 26, // 6: apiextensions.fn.proto.v1.RunFunctionRequest.credentials:type_name -> apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry + 27, // 7: apiextensions.fn.proto.v1.RunFunctionRequest.required_resources:type_name -> apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry + 28, // 8: apiextensions.fn.proto.v1.RunFunctionRequest.required_schemas:type_name -> apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntry + 10, // 9: apiextensions.fn.proto.v1.RunFunctionRequest.dependencies:type_name -> apiextensions.fn.proto.v1.Dependencies + 8, // 10: apiextensions.fn.proto.v1.Credentials.credential_data:type_name -> apiextensions.fn.proto.v1.CredentialData + 29, // 11: apiextensions.fn.proto.v1.CredentialData.data:type_name -> apiextensions.fn.proto.v1.CredentialData.DataEntry + 22, // 12: apiextensions.fn.proto.v1.Resources.items:type_name -> apiextensions.fn.proto.v1.Resource + 11, // 13: apiextensions.fn.proto.v1.Dependencies.items:type_name -> apiextensions.fn.proto.v1.Dependency + 12, // 14: apiextensions.fn.proto.v1.Dependency.required_resource:type_name -> apiextensions.fn.proto.v1.RequiredResourceDependency + 0, // 15: apiextensions.fn.proto.v1.Dependency.lifecycle:type_name -> apiextensions.fn.proto.v1.DependencyLifecycle + 20, // 16: apiextensions.fn.proto.v1.RunFunctionResponse.meta:type_name -> apiextensions.fn.proto.v1.ResponseMeta + 21, // 17: apiextensions.fn.proto.v1.RunFunctionResponse.desired:type_name -> apiextensions.fn.proto.v1.State + 23, // 18: apiextensions.fn.proto.v1.RunFunctionResponse.results:type_name -> apiextensions.fn.proto.v1.Result + 36, // 19: apiextensions.fn.proto.v1.RunFunctionResponse.context:type_name -> google.protobuf.Struct + 15, // 20: apiextensions.fn.proto.v1.RunFunctionResponse.requirements:type_name -> apiextensions.fn.proto.v1.Requirements + 24, // 21: apiextensions.fn.proto.v1.RunFunctionResponse.conditions:type_name -> apiextensions.fn.proto.v1.Condition + 36, // 22: apiextensions.fn.proto.v1.RunFunctionResponse.output:type_name -> google.protobuf.Struct + 10, // 23: apiextensions.fn.proto.v1.RunFunctionResponse.dependencies:type_name -> apiextensions.fn.proto.v1.Dependencies + 1, // 24: apiextensions.fn.proto.v1.RequestMeta.capabilities:type_name -> apiextensions.fn.proto.v1.Capability + 30, // 25: apiextensions.fn.proto.v1.Requirements.extra_resources:type_name -> apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntry + 31, // 26: apiextensions.fn.proto.v1.Requirements.resources:type_name -> apiextensions.fn.proto.v1.Requirements.ResourcesEntry + 32, // 27: apiextensions.fn.proto.v1.Requirements.schemas:type_name -> apiextensions.fn.proto.v1.Requirements.SchemasEntry + 36, // 28: apiextensions.fn.proto.v1.Schema.openapi_v3:type_name -> google.protobuf.Struct + 19, // 29: apiextensions.fn.proto.v1.ResourceSelector.match_labels:type_name -> apiextensions.fn.proto.v1.MatchLabels + 33, // 30: apiextensions.fn.proto.v1.MatchLabels.labels:type_name -> apiextensions.fn.proto.v1.MatchLabels.LabelsEntry + 37, // 31: apiextensions.fn.proto.v1.ResponseMeta.ttl:type_name -> google.protobuf.Duration + 22, // 32: apiextensions.fn.proto.v1.State.composite:type_name -> apiextensions.fn.proto.v1.Resource + 34, // 33: apiextensions.fn.proto.v1.State.resources:type_name -> apiextensions.fn.proto.v1.State.ResourcesEntry + 36, // 34: apiextensions.fn.proto.v1.Resource.resource:type_name -> google.protobuf.Struct + 35, // 35: apiextensions.fn.proto.v1.Resource.connection_details:type_name -> apiextensions.fn.proto.v1.Resource.ConnectionDetailsEntry + 2, // 36: apiextensions.fn.proto.v1.Resource.ready:type_name -> apiextensions.fn.proto.v1.Ready + 3, // 37: apiextensions.fn.proto.v1.Result.severity:type_name -> apiextensions.fn.proto.v1.Severity + 4, // 38: apiextensions.fn.proto.v1.Result.target:type_name -> apiextensions.fn.proto.v1.Target + 5, // 39: apiextensions.fn.proto.v1.Condition.status:type_name -> apiextensions.fn.proto.v1.Status + 4, // 40: apiextensions.fn.proto.v1.Condition.target:type_name -> apiextensions.fn.proto.v1.Target + 9, // 41: apiextensions.fn.proto.v1.RunFunctionRequest.ExtraResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.Resources + 7, // 42: apiextensions.fn.proto.v1.RunFunctionRequest.CredentialsEntry.value:type_name -> apiextensions.fn.proto.v1.Credentials + 9, // 43: apiextensions.fn.proto.v1.RunFunctionRequest.RequiredResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.Resources + 17, // 44: apiextensions.fn.proto.v1.RunFunctionRequest.RequiredSchemasEntry.value:type_name -> apiextensions.fn.proto.v1.Schema + 18, // 45: apiextensions.fn.proto.v1.Requirements.ExtraResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.ResourceSelector + 18, // 46: apiextensions.fn.proto.v1.Requirements.ResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.ResourceSelector + 16, // 47: apiextensions.fn.proto.v1.Requirements.SchemasEntry.value:type_name -> apiextensions.fn.proto.v1.SchemaSelector + 22, // 48: apiextensions.fn.proto.v1.State.ResourcesEntry.value:type_name -> apiextensions.fn.proto.v1.Resource + 6, // 49: apiextensions.fn.proto.v1.FunctionRunnerService.RunFunction:input_type -> apiextensions.fn.proto.v1.RunFunctionRequest + 13, // 50: apiextensions.fn.proto.v1.FunctionRunnerService.RunFunction:output_type -> apiextensions.fn.proto.v1.RunFunctionResponse + 50, // [50:51] is the sub-list for method output_type + 49, // [49:50] is the sub-list for method input_type + 49, // [49:49] is the sub-list for extension type_name + 49, // [49:49] is the sub-list for extension extendee + 0, // [0:49] is the sub-list for field type_name } func init() { file_v1_run_function_proto_init() } @@ -1818,22 +2172,27 @@ func file_v1_run_function_proto_init() { file_v1_run_function_proto_msgTypes[1].OneofWrappers = []any{ (*Credentials_CredentialData)(nil), } - file_v1_run_function_proto_msgTypes[4].OneofWrappers = []any{} - file_v1_run_function_proto_msgTypes[8].OneofWrappers = []any{} - file_v1_run_function_proto_msgTypes[9].OneofWrappers = []any{ + file_v1_run_function_proto_msgTypes[5].OneofWrappers = []any{ + (*Dependency_ComposedResource)(nil), + (*Dependency_RequiredResource)(nil), + } + file_v1_run_function_proto_msgTypes[6].OneofWrappers = []any{} + file_v1_run_function_proto_msgTypes[7].OneofWrappers = []any{} + file_v1_run_function_proto_msgTypes[11].OneofWrappers = []any{} + file_v1_run_function_proto_msgTypes[12].OneofWrappers = []any{ (*ResourceSelector_MatchName)(nil), (*ResourceSelector_MatchLabels)(nil), } - file_v1_run_function_proto_msgTypes[11].OneofWrappers = []any{} file_v1_run_function_proto_msgTypes[14].OneofWrappers = []any{} - file_v1_run_function_proto_msgTypes[15].OneofWrappers = []any{} + file_v1_run_function_proto_msgTypes[17].OneofWrappers = []any{} + file_v1_run_function_proto_msgTypes[18].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_v1_run_function_proto_rawDesc), len(file_v1_run_function_proto_rawDesc)), - NumEnums: 5, - NumMessages: 27, + NumEnums: 6, + NumMessages: 30, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/v1/run_function.proto b/proto/v1/run_function.proto index e58a4b5..25bf397 100644 --- a/proto/v1/run_function.proto +++ b/proto/v1/run_function.proto @@ -97,6 +97,10 @@ message RunFunctionRequest { // sets the map key to an empty Schema message to indicate that it attempted // to satisfy the request. map required_schemas = 9; + + // Optional ordering constraints over composed resources, accumulated by the + // functions that ran before this one. + Dependencies dependencies = 10; } // Credentials that a function may use to communicate with an external system. @@ -118,6 +122,78 @@ message Resources { repeated Resource items = 1; } +// Dependencies is a set of ordering constraints over composed resources. +// +// This is a message wrapping a repeated field, rather than a bare repeated +// field, so that an unset value can be told apart from an empty one. A bare +// repeated field can't express that difference: proto3 has no presence for +// repeated fields, and an empty list and an unset field are both zero bytes on +// the wire. Crossplane relies on the difference, because an unset value means +// "this function has no opinion, carry my constraints forward" while an empty +// one means "this function wants no constraints at all." State wraps desired +// and observed resources for the same reason. +message Dependencies { + repeated Dependency items = 1; +} + +// A Dependency declares that one composed resource must be created after, and +// deleted before, another resource. It expresses ordering only. It doesn't move +// any data between resources. +message Dependency { + // Name of the composed resource that has the dependency. A key into the + // desired or observed State.resources map. + string resource = 1; + + // What the resource depends on. + oneof depends_on { + // Name of another composed resource. A key into the desired or observed + // State.resources map. + string composed_resource = 2; + + // A resource the pipeline required, rather than composed. Crossplane never + // deletes a resource it didn't compose, so these constrain only the order + // resources are created and updated. + RequiredResourceDependency required_resource = 4; + } + + // How this dependency constrains the order its endpoints are created and + // deleted. Defaults to symmetric ordering. + DependencyLifecycle lifecycle = 3; +} + +// A DependencyLifecycle is how a dependency constrains the order its endpoints +// are created and deleted. +enum DependencyLifecycle { + // Symmetric ordering: the resource is created only once what it depends on + // is ready, and what it depends on is deleted only once the resource is + // gone. This is the default, and the only valid value when depends_on is a + // required resource, because Crossplane never deletes a resource it didn't + // compose. + DEPENDENCY_LIFECYCLE_UNSPECIFIED = 0; + + // The resource may be created without waiting for what it depends on to be + // deleted. It must still exist and be ready before what it depends on is + // deleted. Use for a replacement that must exist before its predecessor is + // torn down. Only valid when depends_on is a composed resource. + DEPENDENCY_LIFECYCLE_CREATE_BEFORE_DESTROY = 1; +} + +// A RequiredResourceDependency identifies a resource the pipeline required, +// for the purpose of ordering. +message RequiredResourceDependency { + // The requirement name. A key into a RunFunctionRequest's required_resources + // map, and into a RunFunctionResponse's requirements.resources map. + string requirement_name = 1; + + // Optional name of a single resource within the set the requirement matched. + // If unset, every resource the requirement matched must be ready. + optional string name = 2; + + // Namespace of name for a namespaced resource. Leave unset for a + // cluster-scoped resource. name and namespace together identify one match. + optional string namespace = 3; +} + // A RunFunctionResponse contains the result of a function run. message RunFunctionResponse { // Metadata pertaining to this response. @@ -156,6 +232,14 @@ message RunFunctionResponse { // // Only Operations use function output. XRs will discard any function output. optional google.protobuf.Struct output = 7; + + // Optional ordering constraints over composed resources. A function that has + // an opinion about ordering must return the full set it wants going forward, + // including edges it received and still wants. Leaving this field unset means + // "no opinion" - Crossplane carries forward whatever it sent in the request. + // + // Dependencies are only used for composition. They're ignored by Operations. + Dependencies dependencies = 8; } // RequestMeta contains metadata pertaining to a RunFunctionRequest. @@ -201,6 +285,11 @@ enum Capability { // OpenAPI schemas and Crossplane will return them in required_schemas. Added // in Crossplane v2.2. CAPABILITY_REQUIRED_SCHEMAS = 5; + + // Crossplane supports the dependencies field. Functions can declare ordering + // constraints over composed resources, and Crossplane will sequence the + // resources it creates, updates and deletes accordingly. + CAPABILITY_DEPENDENCIES = 6; } // Requirements that must be satisfied for a function to run successfully. diff --git a/response/response.go b/response/response.go index 170d863..d5b04cb 100644 --- a/response/response.go +++ b/response/response.go @@ -22,6 +22,7 @@ import ( "time" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/structpb" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -35,16 +36,96 @@ import ( const DefaultTTL = 1 * time.Minute // To bootstraps a response to the supplied request. It automatically copies the -// desired state from the request. +// desired state, context and dependencies from the request. +// +// Copying dependencies means a function that adds one keeps the ones earlier +// functions declared. They're copied only when the request has them: unset +// dependencies mean "no opinion", which Crossplane reads as "carry mine +// forward", while an empty set means "drop every constraint". func To(req *v1.RunFunctionRequest, ttl time.Duration) *v1.RunFunctionResponse { return &v1.RunFunctionResponse{ Meta: &v1.ResponseMeta{ Tag: req.GetMeta().GetTag(), Ttl: durationpb.New(ttl), }, - Desired: req.GetDesired(), - Context: req.GetContext(), + Desired: req.GetDesired(), + Context: req.GetContext(), + Dependencies: dependenciesOf(req), + } +} + +// dependenciesOf copies the request's dependencies, so adding one to the +// response doesn't also add it to the request. +func dependenciesOf(req *v1.RunFunctionRequest) *v1.Dependencies { + if req.GetDependencies() == nil { + return nil + } + d, _ := proto.Clone(req.GetDependencies()).(*v1.Dependencies) + return d +} + +// A DependencyOption configures a dependency added by AddDependency. +type DependencyOption func(d *v1.Dependency) + +// WithCreateBeforeDestroy lets a resource be created without waiting for what +// it depends on to be deleted. Use it for a replacement that must exist before +// its predecessor is torn down. +func WithCreateBeforeDestroy() DependencyOption { + return func(d *v1.Dependency) { + d.Lifecycle = v1.DependencyLifecycle_DEPENDENCY_LIFECYCLE_CREATE_BEFORE_DESTROY + } +} + +// AddDependency declares that one composed resource depends on another. +// +// By default ordering is symmetric: the resource is created only once what it +// depends on is ready, and what it depends on is deleted only once the +// resource is gone. Dependencies express ordering only; they don't move any +// data between resources. +// +// A function must return the full set of dependencies it wants. To copies +// forward the ones the request carried, so add to a response it created. +// +// Only a Crossplane that advertises CAPABILITY_DEPENDENCIES honors +// dependencies. Use request.HasCapability to check before relying on them. +func AddDependency(rsp *v1.RunFunctionResponse, r, dependsOn resource.Name, o ...DependencyOption) { + d := &v1.Dependency{ + Resource: string(r), + DependsOn: &v1.Dependency_ComposedResource{ComposedResource: string(dependsOn)}, + } + for _, fn := range o { + fn(d) + } + addDependency(rsp, d) +} + +// AddRequiredResourceDependency declares that a composed resource depends on +// a resource the function requires but doesn't compose. Set the dependency's +// name, and namespace for a namespaced resource, to depend on one of the +// resources the requirement matched; leave them unset to wait for all of them. +// +// Crossplane never deletes a resource it didn't compose, so this orders only +// creation and updates. +func AddRequiredResourceDependency(rsp *v1.RunFunctionResponse, r resource.Name, dependsOn *v1.RequiredResourceDependency) { + addDependency(rsp, &v1.Dependency{ + Resource: string(r), + DependsOn: &v1.Dependency_RequiredResource{RequiredResource: dependsOn}, + }) +} + +// ClearDependencies declares that no composed resources should be ordered. It +// drops the dependencies earlier functions declared, which To copied forward. +// That's different from leaving dependencies unset, which carries them +// forward. +func ClearDependencies(rsp *v1.RunFunctionResponse) { + rsp.Dependencies = &v1.Dependencies{} +} + +func addDependency(rsp *v1.RunFunctionResponse, d *v1.Dependency) { + if rsp.GetDependencies() == nil { + rsp.Dependencies = &v1.Dependencies{} } + rsp.Dependencies.Items = append(rsp.Dependencies.Items, d) } // SetContextKey sets context to the supplied key. diff --git a/response/response_test.go b/response/response_test.go index 2187072..42a1981 100644 --- a/response/response_test.go +++ b/response/response_test.go @@ -236,3 +236,134 @@ func MustUnstructJSON(j string) *unstructured.Unstructured { } return u } + +func TestToDependencies(t *testing.T) { + edge := &v1.Dependency{Resource: "subnet", DependsOn: &v1.Dependency_ComposedResource{ComposedResource: "vpc"}} + + cases := map[string]struct { + reason string + req *v1.RunFunctionRequest + want *v1.Dependencies + }{ + "Unset": { + reason: "Unset dependencies mean no opinion, so they must stay unset rather than become an empty set.", + req: &v1.RunFunctionRequest{}, + want: nil, + }, + "Empty": { + reason: "An empty set means drop every constraint, and must be carried as such.", + req: &v1.RunFunctionRequest{Dependencies: &v1.Dependencies{}}, + want: &v1.Dependencies{}, + }, + "Carried": { + reason: "A function should keep the dependencies earlier functions declared.", + req: &v1.RunFunctionRequest{Dependencies: &v1.Dependencies{Items: []*v1.Dependency{edge}}}, + want: &v1.Dependencies{Items: []*v1.Dependency{edge}}, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got := To(tc.req, DefaultTTL).GetDependencies() + if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { + t.Errorf("%s\nTo(...).Dependencies: -want, +got:\n%s", tc.reason, diff) + } + }) + } +} + +func TestToDoesNotShareDependencies(t *testing.T) { + req := &v1.RunFunctionRequest{Dependencies: &v1.Dependencies{}} + rsp := To(req, DefaultTTL) + AddDependency(rsp, "subnet", "vpc") + + if n := len(req.GetDependencies().GetItems()); n != 0 { + t.Errorf("adding a dependency to the response added %d to the request", n) + } +} + +func TestAddDependency(t *testing.T) { + type args struct { + rsp *v1.RunFunctionResponse + r resource.Name + dependsOn resource.Name + o []DependencyOption + } + cases := map[string]struct { + reason string + args args + want *v1.RunFunctionResponse + }{ + "FirstDependency": { + reason: "Adding to a response with no dependencies should create the set.", + args: args{rsp: &v1.RunFunctionResponse{}, r: "subnet", dependsOn: "vpc"}, + want: &v1.RunFunctionResponse{Dependencies: &v1.Dependencies{Items: []*v1.Dependency{ + {Resource: "subnet", DependsOn: &v1.Dependency_ComposedResource{ComposedResource: "vpc"}}, + }}}, + }, + "Appends": { + reason: "Adding should keep the dependencies already there.", + args: args{ + rsp: &v1.RunFunctionResponse{Dependencies: &v1.Dependencies{Items: []*v1.Dependency{ + {Resource: "subnet", DependsOn: &v1.Dependency_ComposedResource{ComposedResource: "vpc"}}, + }}}, + r: "instance", + dependsOn: "subnet", + }, + want: &v1.RunFunctionResponse{Dependencies: &v1.Dependencies{Items: []*v1.Dependency{ + {Resource: "subnet", DependsOn: &v1.Dependency_ComposedResource{ComposedResource: "vpc"}}, + {Resource: "instance", DependsOn: &v1.Dependency_ComposedResource{ComposedResource: "subnet"}}, + }}}, + }, + "CreateBeforeDestroy": { + reason: "WithCreateBeforeDestroy should set the lifecycle.", + args: args{ + rsp: &v1.RunFunctionResponse{}, r: "new-db", dependsOn: "old-db", + o: []DependencyOption{WithCreateBeforeDestroy()}, + }, + want: &v1.RunFunctionResponse{Dependencies: &v1.Dependencies{Items: []*v1.Dependency{ + { + Resource: "new-db", + DependsOn: &v1.Dependency_ComposedResource{ComposedResource: "old-db"}, + Lifecycle: v1.DependencyLifecycle_DEPENDENCY_LIFECYCLE_CREATE_BEFORE_DESTROY, + }, + }}}, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + AddDependency(tc.args.rsp, tc.args.r, tc.args.dependsOn, tc.args.o...) + if diff := cmp.Diff(tc.want, tc.args.rsp, protocmp.Transform()); diff != "" { + t.Errorf("%s\nAddDependency(...): -want, +got:\n%s", tc.reason, diff) + } + }) + } +} + +func TestAddRequiredResourceDependency(t *testing.T) { + rsp := &v1.RunFunctionResponse{} + AddRequiredResourceDependency(rsp, "app-config", &v1.RequiredResourceDependency{RequirementName: "dbs"}) + + want := &v1.RunFunctionResponse{Dependencies: &v1.Dependencies{Items: []*v1.Dependency{ + { + Resource: "app-config", + DependsOn: &v1.Dependency_RequiredResource{RequiredResource: &v1.RequiredResourceDependency{RequirementName: "dbs"}}, + }, + }}} + if diff := cmp.Diff(want, rsp, protocmp.Transform()); diff != "" { + t.Errorf("AddRequiredResourceDependency(...): -want, +got:\n%s", diff) + } +} + +func TestClearDependencies(t *testing.T) { + rsp := &v1.RunFunctionResponse{Dependencies: &v1.Dependencies{Items: []*v1.Dependency{ + {Resource: "subnet", DependsOn: &v1.Dependency_ComposedResource{ComposedResource: "vpc"}}, + }}} + ClearDependencies(rsp) + + // Empty, not unset: unset would carry the dropped dependencies forward. + if rsp.GetDependencies() == nil || len(rsp.GetDependencies().GetItems()) != 0 { + t.Errorf("ClearDependencies(...): want an empty set, got %v", rsp.GetDependencies()) + } +}