### Apply and Verify Function Installation Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Apply the function manifest and wait for it to become healthy. Verify the installation by listing and describing the function. ```bash kubectl apply -f function-cel-filter.yaml kubectl wait --for=condition=Healthy function function-cel-filter --timeout=300s ``` ```bash kubectl get functions kubectl describe function function-cel-filter ``` -------------------------------- ### Evaluate Function Usage Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/api-reference/evaluate.md Demonstrates how to use the Evaluate function to determine if a resource should be included based on a CEL expression. It shows the setup of the logger, function, and the RunFunctionRequest, including observed and desired states. ```go log, _ := function.NewLogger(false) fn, _ := NewFunction(log) req := &fnv1.RunFunctionRequest{ Observed: &fnv1.State{ Composite: &fnv1.Resource{ Resource: resource.MustStructJSON(`{ "spec": {"export": "S3"} }`), }, }, Desired: &fnv1.State{ Resources: map[string]*fnv1.Resource{ "bucket": {}, }, }, Context: resource.MustStructJSON(`{}`), } // Evaluate if the bucket should be included include, err := Evaluate(fn.env, req, `observed.composite.resource.spec.export == "S3"`) if err != nil { log.Errorf("evaluation failed: %v", err) // handle error } if include { // Keep the bucket resource } ``` -------------------------------- ### Render Example Manifests Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/example/README.md Call the locally running function with example manifests for a Crossplane Composite Resource (XR) and its Composition. This command renders the resources. ```shell $ crossplane beta render xr.yaml composition.yaml functions.yaml -r ``` -------------------------------- ### CLI Run Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/api-reference/cli.md Demonstrates how to instantiate and run the CLI with specific configurations for debugging, network, address, and TLS. ```go cli := &CLI{ Debug: true, Network: "tcp", Address: ":9443", TLSCertsDir: "/etc/function-certs", Insecure: false, } if err := cli.Run(); err != nil { log.Fatalf("Failed to run function: %v", err) } // Blocks until server is stopped ``` -------------------------------- ### RunFunction Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/api-reference/function.md Demonstrates how to use the RunFunction method with a sample request. The example shows how to construct a RunFunctionRequest, including input filters, observed state, and desired resources. After execution, it notes which resources are expected to remain in the response based on the filter logic. ```Go req := &fnv1.RunFunctionRequest{ Meta: &fnv1.RequestMeta{Tag: "my-tag"}, Input: resource.MustStructJSON(`{ "apiVersion": "cel.fn.crossplane.io/v1beta1", "kind": "Filters", "filters": [ { "name": "bucket", "expression": "observed.composite.resource.spec.export == \"S3\"" } ] }`), Observed: &fnv1.State{ Composite: &fnv1.Resource{ Resource: resource.MustStructJSON(`{ "spec": {"export": "S3"} }`), }, }, Desired: &fnv1.State{ Resources: map[string]*fnv1.Resource{ "bucket": {}, "table": {}, }, }, } response, err := fn.RunFunction(context.Background(), req) if err != nil { // Handle error } // response.Desired.Resources will only contain "table" // "bucket" is kept because the expression evaluates to true ``` -------------------------------- ### Run Method Implementation Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/api-reference/cli.md Initializes the logger and composition function, then starts the gRPC server with configured network, address, and TLS settings. ```go func (c *CLI) Run() error { // ... implementation details ... return nil } ``` -------------------------------- ### Simple CEL Expression Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Shows an example of a simple and clear CEL expression for filtering resources based on a label. ```yaml # Good: single clear condition - name: prod expression: "observed.composite.resource.metadata.labels.env == \"prod\"" ``` -------------------------------- ### Example Composition with CEL Filter Step Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/README.md This example demonstrates how to integrate the function-cel-filter into a Crossplane Composition pipeline. It shows a 'filter-composed-resources' step with a CEL filter that includes a bucket resource only if the XR's spec.export field is set to 'S3'. ```yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: function-template-go spec: compositeTypeRef: apiVersion: example.crossplane.io/v1 kind: NoSQL mode: Pipeline pipeline: - step: patch-and-transform functionRef: name: function-patch-and-transform input: apiVersion: pt.fn.crossplane.io/v1beta1 kind: Resources resources: - name: table base: apiVersion: dynamodb.aws.upbound.io/v1beta1 kind: Table metadata: name: crossplane-quickstart-database spec: forProvider: region: "us-east-2" writeCapacity: 1 readCapacity: 1 attribute: - name: S3ID type: S hashKey: S3ID - name: bucket base: apiVersion: s3.aws.upbound.io/v1beta1 kind: Bucket spec: forProvider: region: us-east-2 - step: filter-composed-resources functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: # Only create the bucket if the XR's spec.export field is set to "S3". - name: bucket expression: observed.composite.resource.spec.export == "S3" ``` -------------------------------- ### CEL Environment Setup Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Details the initialization of the CEL environment within the function, including type registration and variable definition. ```text NewFunction(logger) ├─ Create CEL Environment │ ├─ Register Type: fnv1.State │ │ └─ Used for observed, desired variables │ │ │ ├─ Register Type: structpb.Struct │ │ └─ Used for context variable │ │ │ ├─ Define Variable: observed │ │ └─ Type: apiextensions.fn.proto.v1.State │ │ │ ├─ Define Variable: desired │ │ └─ Type: apiextensions.fn.proto.v1.State │ │ │ └─ Define Variable: context │ └─ Type: google.protobuf.Struct │ └─ Return Function{ log, env } ``` -------------------------------- ### Example Usage of NewFunction Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/api-reference/function.md Demonstrates how to create a logger and then instantiate a new Function. Handles potential errors during logger and function creation. ```go log, err := function.NewLogger(debug) if err != nil { return fmt.Errorf("failed to create logger: %w", err) } fn, err := NewFunction(log) if err != nil { return fmt.Errorf("failed to create filter function: %w", err) } ``` -------------------------------- ### Meaningful Filter Name Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Illustrates the best practice of using clear and descriptive names for filters. ```yaml # Good: clear what the filter does - name: backup expression: "observed.composite.resource.spec.enableBackup == true" # Bad: unclear - name: r1 expression: "true" ``` -------------------------------- ### Basic Resource Filtering Examples Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Filter resources based on simple equality checks for spec fields or boolean values. ```cel observed.composite.resource.spec.export == "S3" ``` ```cel observed.composite.resource.spec.enabled == true ``` ```cel observed.composite.resource.spec.count > 0 ``` -------------------------------- ### Example Filter Expression Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md A basic example of a filter expression. ```yaml filters: # Only create expensive monitoring stack for production XRs - name: monitoring expression: "observed.composite.resource.metadata.labels.environment == \"production\"" # Only include high-availability cache for deployments expecting high load - name: cache expression: "observed.composite.resource.spec.expectedQPS > 1000" ``` -------------------------------- ### Manual CEL Expression Testing with Go Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Demonstrates how to manually test CEL expressions using the Go SDK, including environment setup and parsing. ```go import ( "github.com/google/cel-go/cel" fnv1 "github.com/crossplane/function-sdk-go/proto/v1" ) // Create environment with same variables env, _ := cel.NewEnv( cel.Variable("observed", cel.ObjectType("apiextensions.fn.proto.v1.State")), cel.Variable("desired", cel.ObjectType("apiextensions.fn.proto.v1.State")), cel.Variable("context", cel.ObjectType("google.protobuf.Struct")), ) // Parse and check expression ast, iss := env.Parse("observed.composite.resource.spec.export == \"S3\"") if iss.Err() != nil { panic(iss.Err()) } checked, iss := env.Check(ast) if iss.Err() != nil { panic(iss.Err()) } // Expression is valid if we get here ``` -------------------------------- ### Example XR Manifest Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/example/README.md A sample Crossplane Composite Resource (XR) of kind `NoSQL`. This manifest defines the desired state for a NoSQL database. ```yaml --- apiVersion: example.crossplane.io/v1 kind: NoSQL metadata: name: example-xr ``` -------------------------------- ### Standard Production Configuration with mTLS Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/configuration.md Starts the function with mTLS enabled, listening on all interfaces on port 9443. Requires TLS certificates in the specified directory. ```bash function-cel-filter \ --network tcp \ --address ":9443" \ --tls-server-certs-dir /etc/function-certs ``` -------------------------------- ### Example Filters Configuration Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/types.md Illustrates various filter rules using YAML format, including matching by name pattern, evaluating CEL expressions based on observed data, checking for resource existence, and inspecting connection details. ```yaml filters: # Include bucket only if export spec is "S3" - name: bucket expression: observed.composite.resource.spec.export == "S3" # Filter multiple resources matching a pattern - name: prod-.* expression: observed.composite.resource.metadata.labels.environment == "production" # Check for resource existence - name: table expression: "table" in desired.resources # Check connection details - name: db expression: observed.resources['db'].connection_details['username'] != b'' ``` -------------------------------- ### Filters JSON Structure Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/types.md An example of the JSON structure for the Filters type, demonstrating how to specify API version, kind, metadata, and a list of filter rules. ```json { "apiVersion": "cel.fn.crossplane.io/v1beta1", "kind": "Filters", "metadata": { "name": "example" }, "filters": [ { "name": "bucket", "expression": "observed.composite.resource.spec.export == \"S3\"" } ] } ``` -------------------------------- ### CEL Expression Examples Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/api-reference/evaluate.md Examples of valid CEL expressions that return boolean values, demonstrating access to observed, desired, and context variables. ```cel observed.composite.resource.spec.widgets == 42 ``` ```cel observed.resources['bucket'].connection_details['user'] == b'admin' ``` ```cel desired.resources['bucket'].resource.spec.widgets == 42 ``` ```cel "bucket" in desired.resources ``` ```cel observed.composite.resource.spec.export == "S3" ``` ```cel desired.resources['table'].resource.metadata.name.startsWith("prod-") ``` -------------------------------- ### CLI Command-Line Examples Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/api-reference/cli.md Illustrates various ways to invoke the CEL filter function from the command line, including production, development, debug, and environment variable configurations. ```bash # Production setup with TLS function-cel-filter --address :9443 --tls-server-certs-dir /etc/certs # Development setup without TLS function-cel-filter --insecure --address localhost:9443 # Debug mode function-cel-filter --debug --insecure # With environment variable for TLS directory export TLS_SERVER_CERTS_DIR=/etc/certs function-cel-filter --address :9443 ``` -------------------------------- ### Run Function Locally Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/example/README.md Execute the function locally with insecure and debug flags enabled. This command starts the function server. ```shell $ go run . --insecure --debug ``` -------------------------------- ### Filter Name Regex Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Demonstrates correct and incorrect regex patterns for filtering resource names. Remember that patterns are auto-anchored with `^` and `$`. ```yaml # Wrong: this matches "bucket-1" but not "bucket" - name: bucket-.* expression: "..." # Correct: this matches "bucket" or "bucket-1" - name: bucket.* expression: "..." ``` -------------------------------- ### Example CEL Expressions for Filtering Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/README.md These examples illustrate various CEL expressions that can be used within the function-cel-filter to determine whether composed resources should be included. They show how to access different parts of the observed and desired states, including resource specifications and connection details. ```cel observed.composite.resource.spec.widgets == 42 ``` ```cel observed.resources['bucket'].connection_details['user'] == b'admin' ``` ```cel desired.resources['bucket'].resource.spec.widgets == 42 ``` ```cel "bucket" in desired.resources ``` -------------------------------- ### Example Composition Resource Manifest Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/example/README.md A sample Kubernetes resource manifest for a DynamoDB Table, intended to be managed by a Crossplane Composition. It includes specific configurations for attributes, region, and capacity. ```yaml --- apiVersion: dynamodb.aws.upbound.io/v1beta1 kind: Table metadata: annotations: crossplane.io/composition-resource-name: table generateName: example-xr- labels: crossplane.io/composite: example-xr ownerReferences: - apiVersion: example.crossplane.io/v1 blockOwnerDeletion: true controller: true kind: NoSQL name: example-xr uid: "" spec: forProvider: attribute: - name: S3ID type: S hashKey: S3ID readCapacity: 1 region: us-east-2 writeCapacity: 1 ``` -------------------------------- ### Defensive Programming in Filter Expressions Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Example demonstrating how to check for field existence before accessing it in a filter expression to prevent errors. ```yaml # Check field existence before accessing - name: resource expression: "has(observed.composite.resource.spec.optional) && observed.composite.resource.spec.optional == true" ``` -------------------------------- ### Module Organization Structure Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Provides an overview of the project's directory structure, including the main entry point, core implementation files, tests, input definitions, generated code, and examples. ```text github.com/crossplane-contrib/function-cel-filter/ ├─ main.go │ ├─ CLI struct (config) │ └─ main() function │ ├─ fn.go │ ├─ Function struct (main implementation) │ ├─ NewFunction(log) │ ├─ RunFunction(ctx, req) │ └─ Evaluate(env, req, expr) │ ├─ fn_test.go │ └─ TestRunFunction(t) │ ├─ input/ │ ├─ generate.go (code generation directives) │ └─ v1beta1/ │ ├─ input.go │ │ ├─ Filters struct │ │ └─ Filter struct │ └─ zz_generated.deepcopy.go (generated) │ ├─ package/ │ └─ input/ (generated CRD manifests) │ ├─ example/ │ ├─ composition.yaml │ ├─ functions.yaml │ └─ xr.yaml │ ├─ go.mod ├─ go.sum └─ README.md ``` -------------------------------- ### Example Input Configuration for CEL Filters Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/errors.md This YAML snippet shows the expected structure for the input configuration of the CEL Filters. Ensure your Composition step input matches this schema, including the 'filters' array with 'name' and 'expression' fields. ```yaml input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: [] # Must be an array ``` -------------------------------- ### Environment-Based Filtering with CEL Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Filter resources based on the environment label defined in the XR. This example shows how to include different backup systems for production and development environments. ```yaml filters: - name: prod-.* expression: "observed.composite.resource.metadata.labels.environment == \"production\"" - name: dev-.* expression: "observed.composite.resource.metadata.labels.environment == \"development\"" ``` ```yaml pipeline: - step: create-resources functionRef: name: function-patch-and-transform input: resources: - name: prod-backup-vault base: {...} # High-cost backup system - name: dev-simple-backup base: {...} # Low-cost backup system - step: filter-by-environment functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: prod-.* expression: "observed.composite.resource.metadata.labels.environment == \"production\"" - name: dev-.* expression: "observed.composite.resource.metadata.labels.environment == \"development\"" ``` ```yaml apiVersion: example.crossplane.io/v1 kind: ExampleXR metadata: name: my-resource labels: environment: production ``` -------------------------------- ### Minimal Composition with CEL Filtering Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md A minimal Crossplane Composition example demonstrating the use of function-cel-filter to conditionally include or exclude resources based on XR specifications. ```yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: example-composition spec: compositeTypeRef: apiVersion: example.crossplane.io/v1 kind: ExampleXR mode: Pipeline pipeline: - step: create-resources functionRef: name: function-patch-and-transform input: apiVersion: pt.fn.crossplane.io/v1beta1 kind: Resources resources: - name: database base: apiVersion: database.example.com/v1 kind: Database spec: engine: postgres - step: filter-resources functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: database expression: "observed.composite.resource.spec.includeDatabases == true" ``` -------------------------------- ### Example Composition Configuration with CEL Filter Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/errors.md This YAML snippet shows how to configure a Composition pipeline step to use the CEL Filter Function. It specifies the function reference and provides the necessary input, including filter definitions with names and expressions. ```yaml pipeline: - step: filter-resources functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: "^bucket$" # Exact match (or use regex like bucket.*) expression: "observed.composite.resource.spec.export == \"S3\"" ``` -------------------------------- ### Universal Composition with CEL Filters Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Example of a single composition using the CEL filter function to manage different environments (production and development). This replaces multiple static compositions. ```yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: universal-composition spec: pipeline: - step: create-all functionRef: name: function-patch-and-transform input: resources: - name: prod-feature - name: dev-feature - name: common-feature - step: filter-by-env functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: prod-.* expression: "observed.composite.resource.metadata.labels.environment == \"production\"" - name: dev-.* expression: "observed.composite.resource.metadata.labels.environment == \"development\"" ``` -------------------------------- ### CEL Expression with 'has()' Check Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Demonstrates using the `has()` function in a CEL expression to defensively check for the existence of a field before accessing it. ```yaml # Check if a field exists and has expected value - name: resource expression: "has(observed.composite.resource.spec.field) && observed.composite.resource.spec.field == 'expected'" ``` -------------------------------- ### CEL Expression Boolean Return Correction Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Shows how to ensure a CEL expression returns a boolean value, typically by using comparison operators. ```text Wrong: observed.composite.resource.spec.size Fixed: observed.composite.resource.spec.size > 0 ``` -------------------------------- ### Composition Pipeline Usage with CEL Filter Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/README.md Integrates the function-cel-filter into a Crossplane Composition pipeline. This example shows a filter step that includes a bucket resource if its export spec is 'S3'. ```yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: example spec: mode: Pipeline pipeline: - step: create-resources functionRef: name: function-patch-and-transform input: { ... } - step: filter-resources functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: bucket expression: observed.composite.resource.spec.export == "S3" ``` -------------------------------- ### CEL Regex Pattern Correction Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Provides an example of an invalid RE2 regex pattern and its corrected version for matching resource names. ```text Wrong: prod-*-cache (invalid: * without preceding element) Fixed: prod-.*-cache (valid: .* means any characters) ``` -------------------------------- ### Main Function CLI Usage Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/api-reference/cli.md Shows how to parse CLI arguments using Kong and run the function, enabling command-line configuration. ```go func main() { ctx := kong.Parse(&CLI{}, kong.Description("A Crossplane Composition Function.")) ctx.FatalIfErrorf(ctx.Run()) } ``` -------------------------------- ### Startup Flow Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Describes the sequence of operations during the CEL Filter Function's startup, from parsing command-line arguments to initializing the gRPC server. ```text main() └─ kong.Parse(&CLI{}) └─ CLI.Run() ├─ function.NewLogger(debug) │ └─ Logger instance │ ├─ NewFunction(log) │ ├─ cel.NewEnv(...) │ │ └─ CEL environment │ │ │ └─ Function instance │ └─ function.Serve(fn, options...) ├─ Listen(network, address) ├─ MTLSCertificates(dir) [optional] └─ Insecure(bool) [optional] └─ gRPC server accepting requests ``` -------------------------------- ### Test Composition and Check Resources Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Apply a test XR and then inspect the created composed resources and their status to verify the function's behavior. Replace placeholders with actual resource types and names. ```bash # Apply test XR kubectl apply -f test-xr.yaml # Check the created resources kubectl get # Inspect the claim/XR status kubectl describe ``` -------------------------------- ### Filter Definition Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/00-START-HERE.md Defines a filter rule with a name pattern and a CEL expression. The expression is evaluated against the composition state. ```yaml - name: bucket expression: > observed.composite.resource.spec.export == "S3" ``` -------------------------------- ### Register function-cel-filter Function Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Register the function-cel-filter package in your Crossplane cluster. Ensure Crossplane is installed with Composition Functions support. ```yaml apiVersion: pkg.crossplane.io/v1 kind: Function metadata: name: function-cel-filter spec: package: xpkg.upbound.io/crossplane-contrib/function-cel-filter:v0.2.0 ``` -------------------------------- ### NewFunction Constructor Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/api-reference/function.md Creates a new Function instance. It requires a logger and initializes a CEL environment with predefined variables and types. ```go func NewFunction(log logging.Logger) (*Function, error) ``` -------------------------------- ### Test CEL Expressions Locally with Go Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/errors.md Use the CEL Go library to parse and type-check expressions locally before deploying them. This snippet demonstrates setting up an environment with variables and checking an expression for validity. ```go env, _ := cel.NewEnv( cel.Variable("observed", cel.ObjectType("apiextensions.fn.proto.v1.State")), cel.Variable("desired", cel.ObjectType("apiextensions.fn.proto.v1.State")), ) ast, iss := env.Parse("observed.composite.resource.spec.export == \"S3\"") if iss.Err() != nil { fmt.Printf("Parse error: %v\n", iss.Err()) } checked, iss := env.Check(ast) if iss.Err() != nil { fmt.Printf("Type check error: %v\n", iss.Err()) } // If no errors, expression is valid ``` -------------------------------- ### CEL Expression Type Correction Example Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Illustrates a common error where a numeric field is compared to a string, and the corrected version comparing numbers. ```text Wrong: observed.composite.resource.spec.size == "100" # comparing to string Fixed: observed.composite.resource.spec.size == 100 # comparing to number ``` -------------------------------- ### Deploying the Function Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/README.md Builds a Docker image for the function-cel-filter and provides commands to run it with TLS enabled or in insecure mode for development. ```bash # Build the function docker build -t function-cel-filter:v0.x.y . # Run with TLS function-cel-filter \ --address :9443 \ --tls-server-certs-dir /etc/certs # Or run insecure (development only) function-cel-filter \ --insecure \ --address :9443 ``` -------------------------------- ### Invalid CEL Expressions Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/errors.md Examples of syntactically invalid CEL expressions that cannot be parsed. These typically involve typos, incorrect operators, or unmatched quotes/parentheses. ```cel observed.composite.resource.spec.widgets == # incomplete ``` ```cel observed...spec.widget # invalid syntax ``` ```cel "unclosed string ``` -------------------------------- ### Performance: Optimization Strategy Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Outlines the time complexity of the RunFunction execution, detailing the steps involved in regex compilation, CEL expression evaluation, and resource filtering. ```text RunFunction: 1. Compile all regexes once O(m) where m = number of filters 2. Evaluate all CEL expressions once O(m) 3. Iterate resources and filter O(n*m) where n = number of resources - Most inner operations are O(1) regex/CEL lookups ``` -------------------------------- ### Conditional Logic in CEL Expressions Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Demonstrates conditional logic based on environment and replica count. ```cel observed.composite.resource.metadata.labels.environment == "production" ? observed.composite.resource.spec.replicas >= 3 : observed.composite.resource.spec.replicas >= 1 ``` -------------------------------- ### Minimal Function Initialization Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/README.md Initializes a new Crossplane Function logger and the Function itself. Ensure the logger is initialized before the Function. ```go import ( "github.com/crossplane/function-sdk-go" "log" ) log, err := function.NewLogger(false) // false = no debug if err != nil { panic(err) } fn, err := NewFunction(log) if err != nil { panic(err) } // fn is now ready to process requests ``` -------------------------------- ### Unit Testing Filters with Crossplane CLI Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Render a composition with a test XR using the Crossplane CLI to verify filter logic. ```bash # Render the composition with a test XR crossplane beta render xr.yaml composition.yaml functions.yaml # Check output resources ``` -------------------------------- ### Fast Filtering Loop with O(1) Lookups Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md This Go code snippet demonstrates an efficient filtering loop for resources using regular expressions and CEL expressions. It achieves O(1) lookups for filtering. ```Go for name := range resources { for i := range filters { if regexps[i].MatchString(name) && !celexps[i] { delete(resources, name) } } } ``` -------------------------------- ### Valid and Invalid Filter Name Patterns (YAML) Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/errors.md Examples of filter name patterns in YAML configuration, illustrating valid RE2 regular expressions and an invalid one that would cause a compilation error. ```yaml filters: # Valid: matches "bucket" or "bucket-1" etc. - name: "bucket.*" # Valid: matches "prod-db", "prod-cache", etc. - name: "prod-.*" # Valid: matches exact resource name - name: "exact-name" # Invalid: would become ^*invalid$ - name: "*invalid" ``` -------------------------------- ### Command Line Arguments Configuration Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Lists the available command-line arguments for configuring the CEL Filter Function, including debug, network, address, TLS settings, and insecure mode. ```text Command Line Arguments ├─ --debug: Boolean │ └─ Affects Logger level │ ├─ --network: String (default: "tcp") │ └─ Network type for server │ ├─ --address: String (default: ":9443") │ └─ Server listen address │ ├─ --tls-server-certs-dir: String │ │ env: TLS_SERVER_CERTS_DIR │ └─ Directory containing: │ ├─ tls.key (server key) │ ├─ tls.crt (server cert) │ └─ ca.crt (client CA) │ └─ --insecure: Boolean (disables TLS) └─ Skip certificate loading ``` -------------------------------- ### Performance: Caching Strategy Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Illustrates the caching strategy for regex patterns and CEL expression evaluations within the function to optimize performance. Regexes and expressions are compiled/evaluated once per request. ```go regexps := make([]*regexp.Regexp, len(filters)) celexps := make([]bool, len(filters)) # Compile/evaluate all filters once for i := range filters { regexps[i] = regexp.Compile(...) celexps[i] = Evaluate(...) } ``` -------------------------------- ### CEL Expression Type Checking Errors Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/errors.md Examples illustrating type checking errors in CEL expressions, where valid syntax leads to semantic issues like type mismatches or referencing non-existent fields. ```cel observed.composite.resource.spec.widgets.nonexistent_field ``` ```cel "string" + 42 ``` ```cel undefined_variable == "value" ``` -------------------------------- ### String Type Comparisons and Operations Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Compare string fields for equality and use string methods like 'startsWith' and '.size'. ```cel # String comparison resource.spec.kind == "S3" resource.metadata.namespace == "default" # String operations resource.metadata.name.startsWith("prod-") resource.spec.description.size > 0 ``` -------------------------------- ### State Access in CEL Expressions Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/types.md Demonstrates how to access observed and desired resource states within CEL expressions, including composite resource fields, composed resource specs, and connection details. ```cel observed.composite.resource.spec.field desired.resources['resource-name'].resource.spec.field observed.resources['name'].connection_details['key'] ``` -------------------------------- ### Data Flow: Filtering a Composition Request Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Demonstrates the step-by-step processing of a composition request through the CEL filter function, from input to output. Shows parsing, compilation, evaluation, filtering, and response building. ```text Input Composition Request: { "meta": {"tag": "example-tag"}, "observed": { "composite": { "resource": {"spec": {"export": "S3"}} } }, "desired": { "resources": { "bucket": {...}, "table": {...} } }, "input": { "apiVersion": "cel.fn.crossplane.io/v1beta1", "kind": "Filters", "filters": [ { "name": "bucket", "expression": "observed.composite.resource.spec.export == \"S3\"" } ] } } │ ▼ RunFunction Processing: ├─ Parse Filters from Input │ └─ filters = [Filter{name: "bucket", expr: "..."}] │ ├─ Compile Regex │ └─ regex[0] = /^bucket$/ │ ├─ Evaluate Expression │ └─ result[0] = true (export == "S3") │ ├─ Filter Resources │ ├─ "bucket" matches regex[0] │ │ ├─ CEL result = true │ │ └─ KEEP resource │ │ │ └─ "table" does not match any regex │ └─ KEEP resource (no filter applies) │ └─ Build Response └─ desired.resources = {bucket, table} (unchanged) │ ▼ Output Response: { "meta": {"tag": "example-tag"}, "desired": { "resources": { "bucket": {...}, "table": {...} } }, "results": [] # No errors } ``` -------------------------------- ### Enabling Debug Logging for CEL Filter Function Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/errors.md This bash command shows how to start the CEL Filter Function with the debug flag enabled. This will provide detailed logs during filter matching, expression evaluation, and resource inclusion/exclusion decisions. ```bash function-cel-filter --debug ``` -------------------------------- ### Conditional Resource Creation by Size Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Use CEL expressions to create resources like cache or CDN only for deployments exceeding specific size thresholds. ```yaml filters: - name: cache expression: "observed.composite.resource.spec.size >= 100" - name: cdn expression: "observed.composite.resource.spec.size >= 500" ``` ```yaml pipeline: - step: create-resources functionRef: name: function-patch-and-transform input: resources: - name: application base: {...} - name: cache base: {...} # Only for large deployments - name: cdn base: {...} # Only for very large deployments - step: filter-by-size functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: cache expression: "observed.composite.resource.spec.size >= 100" - name: cdn expression: "observed.composite.resource.spec.size >= 500" ``` ```yaml apiVersion: example.crossplane.io/v1 kind: ExampleXR metadata: name: small-deployment spec: size: 50 # No cache, no CDN --- apiVersion: example.crossplane.io/v1 kind: ExampleXR metadata: name: large-deployment spec: size: 200 # Includes cache, no CDN ``` -------------------------------- ### CLI Struct Definition Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/configuration.md Defines the structure for command-line interface configuration flags. ```go type CLI struct { Debug bool Network string Address string TLSCertsDir string Insecure bool } ``` -------------------------------- ### TLS Certificate Structure Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/configuration.md Illustrates the required file structure within the TLS certificate directory for mTLS configuration. ```text /etc/function-certs/ ├── tls.key # Server private key (PEM format) ├── tls.crt # Server certificate (PEM format) └── ca.crt # CA certificate for client verification (PEM format) ``` -------------------------------- ### High-Level Architecture Diagram Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Illustrates the function-cel-filter's position within the Crossplane Composition Pipeline, showing its interaction with previous and subsequent functions via gRPC. ```text ┌─────────────────────────────────────────────────────────┐ │ Crossplane Control Plane │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Composition Pipeline Execution │ │ │ │ ┌────────────────────────────────────────────┐ │ │ │ │ │ Step N-1: Previous Function │ │ │ │ │ │ (e.g., patch-and-transform) │ │ │ │ │ └──────────────────┬───────────────────────┘ │ │ │ │ │ RunFunctionRequest │ │ │ │ ┌──────────────────▼───────────────────────┐ │ │ │ │ │ Step N: function-cel-filter │ │ │ │ │ │ ┌──────────────────────────────────────┐ │ │ │ │ │ │ gRPC Server │ │ │ │ │ │ │ RunFunction() method │ │ │ │ │ │ └──────────┬───────────────────────────┘ │ │ │ │ │ │ RunFunctionResponse │ │ │ │ └──────────────────┬───────────────────────┘ │ │ │ │ │ │ │ │ │ ┌──────────────────▼───────────────────────┐ │ │ │ │ │ Step N+1: Next Function (if any) │ │ │ │ │ └────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` -------------------------------- ### Concurrency Model Overview Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Illustrates the stateless nature of the function with respect to individual requests, highlighting thread-safe shared state and request-local variables. Safe for concurrent execution. ```text Request 1: RunFunction(ctx, req1) Request 2: RunFunction(ctx, req2) (can execute in parallel) Request 3: RunFunction(ctx, req3) ┌─────────────────────────────────────┐ │ Shared Mutable State │ ├─────────────────────────────────────┤ │ Function.env (shared CEL env) │ │ - Thread-safe: cel-go env │ │ - Read-only operations: Parse, │ │ Check, Program, Eval │ │ - No expression state persistence │ │ │ │ Function.log (shared logger) │ │ - Thread-safe: structured logger │ │ - Write operations: Log lines │ └─────────────────────────────────────┘ Each Request: ├─ Local Variables: │ ├─ parsed regexes (stack) │ ├─ evaluation results (stack) │ └─ modified response (return value) │ └─ No Shared Mutable State Per Request └─ Safe for concurrent execution ``` -------------------------------- ### Conditional Resource Addition with CEL Filter Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Use a custom function to conditionally add resources, then use the CEL filter to manage their inclusion. ```go import ( context "context" fnv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" response "github.com/crossplane/crossplane-runtime/pkg/response" ) type MyFunction struct { // ... } func (f *MyFunction) RunFunction(ctx context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) { rsp := response.To(req, response.DefaultTTL) // Add resources conditionally if req.GetObserved().GetComposite().GetResource().GetFieldByKey("enableExtra") { rsp.GetDesired().Resources["extra-resource"] = &fnv1.Resource{...} } return rsp, nil } ``` ```yaml - step: filter-extras functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: extra-.* expression: "observed.composite.resource.spec.enableExtra == true" ``` -------------------------------- ### Insecure Mode (Development Only) Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/configuration.md Runs the function without TLS encryption or client certificate verification. Use only for local development or testing. ```bash function-cel-filter \ --insecure \ --address "localhost:9443" ``` -------------------------------- ### Composition Step with Filter Configuration Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/configuration.md Configures a Composition pipeline step to use the CEL filter function. Includes filter rules defined by an input Filters resource. ```yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: example-composition spec: mode: Pipeline pipeline: - step: filter-resources functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: bucket expression: observed.composite.resource.spec.export == "S3" ``` -------------------------------- ### CEL Expression Evaluation Pipeline Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Illustrates the stages involved in evaluating a CEL expression, from parsing to execution, including type checking and compilation. ```text Expression String ├─ "observed.composite.resource.spec.export == \"S3\"" │ ├─ Parse Phase │ ├─ Tokenize and build AST │ ├─ Detect syntax errors │ └─ Produce AST or ParseError │ ├─ Type Check Phase │ ├─ Resolve variable types from environment │ ├─ Validate field access │ ├─ Check operator compatibility │ └─ Verify output type is bool │ └─ If not bool: Type Error │ ├─ Compilation Phase │ ├─ Generate bytecode │ └─ Optimize operations │ └─ Evaluation Phase ├─ Bind variables to runtime values │ ├─ observed: req.GetObserved() │ ├─ desired: req.GetDesired() │ └─ context: req.GetContext() │ ├─ Execute bytecode ├─ Return result or ExecutionError │ └─ Assert result is bool (safety check) └─ Return bool value ``` -------------------------------- ### Regex Pattern Matching for Resource Names Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Use string manipulation functions to check patterns at the beginning, end, or within resource names. ```cel observed.composite.resource.metadata.name.startsWith("prod") ``` ```cel observed.composite.resource.metadata.name.endsWith("-backup") ``` ```cel observed.composite.resource.metadata.name.contains("test") ``` -------------------------------- ### Accessing Observed Composed Resource Connection Details Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Access connection details for a specific observed composed resource by its name. ```cel observed.resources['database'].connection_details['username'] ``` -------------------------------- ### CEL Environment Type Information Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/architecture.md Defines the structure of the CEL environment, including resource types and protobuf definitions used for type checking. ```protobuf fnv1.State { Composite: Resource { Resource: google.protobuf.Struct ConnectionDetails: map[string][]byte } Resources: map[string]Resource { Resource: google.protobuf.Struct ConnectionDetails: map[string][]byte } } google.protobuf.Struct { Fields: map[string]Value { Kind: (StringValue | NumberValue | BoolValue | ListValue | StructValue | null) } } ``` -------------------------------- ### Defensive Programming with Existence Checks Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Use the 'has()' function to safely check for the existence of optional fields before accessing them, preventing potential errors. ```cel # Safe: checks field exists before accessing has(observed.composite.resource.spec.optional) && observed.composite.resource.spec.optional == "value" # Risky: assumes field exists observed.composite.resource.spec.optional == "value" # May error if not present ``` -------------------------------- ### Chained Filters for Environment and Cost Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/integration-guide.md Apply multiple CEL filter steps sequentially to refine resources based on environment labels and budget constraints. ```yaml pipeline: - step: create-all functionRef: name: function-patch-and-transform input: resources: - name: app base: {...} - name: cache base: {...} - name: backup-cache base: {...} - name: monitoring base: {...} - step: filter-by-environment functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: ".*" expression: "observed.composite.resource.metadata.labels.environment == context.target_env" - step: filter-by-cost functionRef: name: function-cel-filter input: apiVersion: cel.fn.crossplane.io/v1beta1 kind: Filters filters: - name: cache expression: "observed.composite.resource.spec.budget > 1000" - name: monitoring expression: "observed.composite.resource.spec.budget > 500" ``` -------------------------------- ### Ensuring Boolean Return Values in CEL Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Shows how to ensure CEL expressions return a boolean value using comparisons. ```cel # Wrong: expression doesn't return boolean observed.composite.resource.spec.widgets ``` ```cel # Correct: use comparison to return boolean observed.composite.resource.spec.widgets == 42 ``` ```cel observed.composite.resource.spec.widgets > 0 ``` -------------------------------- ### Check Multiple Conditions (AND/OR) Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Combine multiple conditions using logical AND (&&) for all to be true, or OR (||) for at least one to be true. ```cel # All conditions must be true observed.composite.resource.spec.export == "S3" && observed.composite.resource.metadata.labels.environment == "prod" && "bucket" in desired.resources # At least one condition must be true observed.composite.resource.spec.export == "S3" || observed.composite.resource.spec.export == "GCS" || observed.composite.resource.spec.export == "AZ" ``` -------------------------------- ### String Length and Size Checks Source: https://github.com/crossplane-contrib/function-cel-filter/blob/main/_autodocs/expressions-guide.md Check the length of string fields using the '.size' attribute. ```cel # Include if name is longer than 10 characters observed.composite.resource.metadata.name.size > 10 # Include if description is not empty observed.composite.resource.spec.description.size > 0 ```