ValueFunction
ValueFunctions are pure functions which provide a means of validation, computation, and data reshaping. There are three common use cases for ValueFunction:
- Validating data and building "known-good" structures to be provided to other functions.
- Computing data structures, such as metadata, to overlay onto other resources in order to standardize them.
- Validating or reshaping return values into a structure that is more convenient to use in other locations within a Workflow.
Though ValueFunction is a very simple construct, they are a powerful means of reshaping or building data structures such as common labels, entire metadata blocks, or default values for use within other functions or Workflows.
Performing Validation
It is important to check preconditions in order to determine if it is possible
to evaluate a Function. For instance, it might be important to check that a
number falls within an allowed range or a that a string meets requirements
such as length or only contains allowed characters. preconditions
allows conditions to be asserted, and if the assertion fails, then the
Function will return a specified outcome.
apiVersion: koreo.dev/v1beta1
kind: ValueFunction
metadata:
name: simple-example.v1
namespace: koreo-demo
spec:
preconditions:
- assert: =inputs.values.int > 0
permFail:
message: ="The int input value must be positive, received '" + string(inputs.values.int) + "'"
- assert: =inputs.enabled
skip:
message: User disabled the ValueFunction
You may leverage a ValueFunction purely to run its preconditions
. This
can be helpful to cause a Workflow to Retry
or PermFail
due to some
condition. Note that in order to block other steps, they should express a
dependency on the ValueFunction via their inputs—otherwise those steps will
run.
Static and Interim Values
Because Koreo Expressions are often used to extract values
or reshape data structures, they can be rather long. locals
provides a means of naming expressions, which can improve readability of the
return value expression.
locals
is also useful for defining constant values, which may be complex
structures, such as lists or objects, or simple values. Locals are used to help
construct the return value, used within Koreo Expressions, or directly
returned.
apiVersion: koreo.dev/v1beta1
kind: ValueFunction
metadata:
name: simple-example.v1
namespace: koreo-demo
spec:
locals:
computedValues:
halfed: =inputs.values.int / 2
doubled: =inputs.values.int * 2
constantList: [NORTH, SOUTH, EAST, WEST]
# ...
Currently, locals
may not reference other locals
.
Returned Value
The primary use cases of ValueFunction is to reshape or compute a return
value expression. The expression in return
must be an object.
The keys of the object may be constant values, data structures, or Koreo
Expressions which reference inputs
or locals
.
apiVersion: koreo.dev/v1beta1
kind: ValueFunction
metadata:
name: simple-example.v1
namespace: koreo-demo
spec:
locals:
computedValues:
halfed: =inputs.values.int / 2
doubled: =inputs.values.int * 2
constantList: [NORTH, SOUTH, EAST, WEST]
return:
allowedRange:
lower: =locals.computedValues.halfed
upper: =locals.computedValues.doubled
lowerWords: =locals.constantList.map(word, word.lower())
ValueFunction Example
The following ValueFunction demonstrates some of the capabilities. Refer to the ValueFunction spec for the complete set of ValueFunction configurations.
apiVersion: koreo.dev/v1beta1
kind: ValueFunction
metadata:
name: simple-example.v1
namespace: koreo-demo
spec:
# Checking input values are within range or ensuring that a config is enabled
# are common needs. Preconditions support both use cases.
preconditions:
- assert: =inputs.values.int > 0
permFail:
message: ="The int input value must be positive, received '" + string(inputs.values.int) + "'"
- assert: =inputs.enabled
skip:
message: User disabled the ValueFunction
# Locals are especially useful for interim expressions to improve
# readability, make complex expressions more ergonomic to write, or for
# defining constant values for use within the return expression.
locals:
computedValues:
halfed: =inputs.values.int / 2
doubled: =inputs.values.int * 2
constantList: [NORTH, SOUTH, EAST, WEST]
# The return value of a ValueFunction must be an object. Koreo Expressions
# have access to the `locals` values.
return:
allowedRange:
lower: =locals.computedValues.halfed
upper: =locals.computedValues.doubled
lowerWords: =locals.constantList.map(word, word.lower())
Testing
FunctionTests provide a solution for testing the logic and error handling in a ValueFunction. These act as unit tests for Functions, allowing you to validate their behavior in isolation and quickly iterate on Logic during development. Refer to the FunctionTest documentation for information on their capabilities.
Below is an example FunctionTest used to test the ValueFunction shown above.
apiVersion: koreo.dev/v1beta1
kind: FunctionTest
metadata:
name: simple-example.v1
namespace: koreo-demo
spec:
# Specify the Function to test.
functionRef:
kind: ValueFunction
name: simple-example.v1
# Provide a base set of inputs.
inputs:
enabled: true
values:
int: 4
# Define your test cases. Each list item is a test case which acts as an
# iteration of the control loop.
testCases:
# Test the happy-path return.
- expectReturn:
allowedRange:
lower: 2
upper: 8
lowerWords: [north, south, east, west]
# Tweak the input, test again. This input tweak will carry forward.
- inputOverrides:
values:
int: 16
expectReturn:
allowedRange:
lower: 8
upper: 32
lowerWords: [north, south, east, west]
# Tweak the input and test an error case. Due to `variant`, this will not
# carry forward.
- variant: true
inputOverrides:
values:
int: 0
expectOutcome:
permFail:
message: must be positive
# Tweak the input and test another other error case. Due to `variant`, this
# will not carry forward.
- variant: true
inputOverrides:
enabled: false
expectOutcome:
skip:
message: User disabled
Specification
- v1beta1
Name | Type | Description | Required |
---|---|---|---|
apiVersion | string | koreo.dev/v1beta1 | true |
kind | string | ValueFunction | true |
metadata | object | Refer to the Kubernetes API documentation for the fields of the metadata field. | true |
spec | object | false | |
status | object | false |
spec
Name | Type | Description | Required |
---|---|---|---|
locals | object | Constant values or Koreo Expressions which will make
| false |
preconditions | []object | Optional set of preconditions which will be evaluated to determine if the Function can, or should, be run and if not specifies the outcome. | false |
return | object | The return value expression for this ValueFunction. It must
be an object composed of constant values or Koreo
Expressions with access to both | false |
spec.preconditions[index]
Name | Type | Description | Required |
---|---|---|---|
assert | string | A predicate which must evaluate to Validations: | true |
defaultReturn | object | A static, default return value. | false |
depSkip | object | Indicates that the Function did not run due to a dependency not being ready or being skipped. Use message to indicate why. Note this is not an error. | false |
permFail | object | Indicates that an unrecoverable error has occurred, intervention is required to correct this condition. This will cause Workflows to stop retrying. Use message to provide information to correct the issue. | false |
retry | object | Indicates that a condition is not yet met, so the function can not (or should not) evaluate yet. Wait and retry after delay seconds. | false |
skip | object | Indicates that the Function did not run due to a condition, such as a config value. Use message to indicate why. Note this is not an error. | false |
spec.preconditions[index].depSkip
Indicates that the Function did not run due to a dependency not being ready or being skipped. Use message to indicate why. Note this is not an error.
Name | Type | Description | Required |
---|---|---|---|
message | string | true |
spec.preconditions[index].permFail
Indicates that an unrecoverable error has occurred, intervention is required to correct this condition. This will cause Workflows to stop retrying. Use message to provide information to correct the issue.
Name | Type | Description | Required |
---|---|---|---|
message | string | true |
spec.preconditions[index].retry
Indicates that a condition is not yet met, so the function can not (or should not) evaluate yet. Wait and retry after delay seconds.
Name | Type | Description | Required |
---|---|---|---|
delay | integer | true | |
message | string | true |
spec.preconditions[index].skip
Indicates that the Function did not run due to a condition, such as a config value. Use message to indicate why. Note this is not an error.
Name | Type | Description | Required |
---|---|---|---|
message | string | true |