### Resource Selector: Reference Type Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt Example of a ResourceSelector for the Reference type, using MatchName. ```go // Type: Reference → MatchName &fnv1.ResourceSelector{ ApiVersion: "apiextensions.crossplane.io/v1beta1", Kind: "EnvironmentConfig", Match: &fnv1.ResourceSelector_MatchName{ MatchName: "my-env-config", }, // Namespace: ptr.To("my-namespace"), // set when spec.namespace is provided } ``` -------------------------------- ### Call Function with Example Manifests Source: https://github.com/crossplane-contrib/function-extra-resources/blob/main/example/README.md Invoke the locally running function using `crossplane render` with XR, composition, and function definition manifests. This tests the function's response to the provided inputs. ```shell # Then, in another terminal, call it with these example manifests $ crossplane render xr.yaml composition.yaml functions.yaml -r --- apiVersion: example.crossplane.io/v1 kind: XR metadata: name: example-xr --- apiVersion: render.crossplane.io/v1beta1 kind: Result message: I was run with input "Hello world"! severity: SEVERITY_NORMAL step: run-the-template ``` -------------------------------- ### Resource Selector: Selector Type Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt Example of a ResourceSelector for the Selector type, using MatchLabels derived from composite resource fields. ```go // Type: Selector → MatchLabels (label value from XR field path) // Given XR spec: { "clusterEnv": "staging" } // and matchLabels entry: { key: "env", type: "FromCompositeFieldPath", valueFromFieldPath: "spec.clusterEnv" } &fnv1.ResourceSelector{ ApiVersion: "example.crossplane.io/v1", Kind: "XCluster", Match: &fnv1.ResourceSelector_MatchLabels{ MatchLabels: &fnv1.MatchLabels{ Labels: map[string]string{"env": "staging"}, }, }, } ``` -------------------------------- ### Run Function Locally Source: https://github.com/crossplane-contrib/function-extra-resources/blob/main/example/README.md Execute your function in debug mode locally. This command starts the function server. ```shell $ go run . --insecure --debug ``` -------------------------------- ### Build and Run Function Locally Source: https://github.com/crossplane-contrib/function-extra-resources/blob/main/README.md Commands for local development of the function-extra-resources. Includes code generation, testing, building the runtime image, and packaging the function. ```shell # Run code generation - see input/generate.go $ go generate ./... # Run tests - see fn_test.go $ go test ./... # Build the function's runtime image - see Dockerfile $ docker build . --tag=runtime # Build a function package - see package/crossplane.yaml $ crossplane xpkg build -f package --embed-runtime-image=runtime ``` -------------------------------- ### Verify and Sort Extra Resources (Go) Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt Enforces min/max match constraints and sorts multi-resource results by a field path for deterministic output. Returns a map keyed by 'into' names, with values as slices of raw resource objects. Handles error cases like insufficient resources or type mismatches. ```go // Demonstrates the sorting behaviour – given this selector: // into: clusters // selector: // minMatch: 1 // maxMatch: 3 // sortByFieldPath: metadata.name // // Input resources (unordered): net-staging-green, net-staging-blue, net-prod // After verifyAndSortExtras → ordered: net-prod, net-staging-blue, net-staging-green // // The resulting context value at "apiextensions.crossplane.io/extra-resources": // { // "clusters": [ // { "apiVersion": "example.crossplane.io/v1", "kind": "XCluster", "metadata": { "name": "net-prod" }, ... }, // { "apiVersion": "example.crossplane.io/v1", "kind": "XCluster", "metadata": { "name": "net-staging-blue" }, ... }, // { "apiVersion": "example.crossplane.io/v1", "kind": "XCluster", "metadata": { "name": "net-staging-green" }, ... } // ] // } // Error cases: // - len(resources) < minMatch → fatal: "expected at least N extra resources" // - Reference type returns 0 → fatal (unless policy.resolution=Optional): "Required extra resource not found" // - Reference type returns > 1 → fatal: "expected exactly one extra resource" // - Mixed field-path types → fatal: "cannot sort values of different types" ``` -------------------------------- ### Local Development and Build Commands for Crossplane Function Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt Commands for generating code, running tests, building Docker images, packaging the function, and running it locally with live-reload or for testing with `crossplane render`. ```bash # Run code generation (regenerates CRD YAML from Go types) go generate ./... # Run unit tests go test ./... # Build the runtime container image docker build . --tag=runtime # Package as a Crossplane function package (.xpkg) crossplane xpkg build -f package --embed-runtime-image=runtime # Run locally with live-reload (requires 'air') air -- --insecure --debug --address localhost:9443 # Test against the example using crossplane CLI render crossplane render \ --extra-resources example/extraResources.yaml \ --include-context \ example/xr.yaml example/composition.yaml example/functions.yaml # Run directly (production flags) ./function \ --address :9443 \ --tls-server-certs-dir /tls \ --max-recv-message-size 4 ``` -------------------------------- ### RunFunction: Core gRPC Handler Implementation Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt Implements the main entry point for the FunctionRunnerServiceServer. Orchestrates the two-phase extra-resource protocol, handling resource requirements declaration and validation. ```go package main import ( "context" fnv1 "github.com/crossplane/function-sdk-go/proto/v1" "github.com/crossplane/function-sdk-go/request" "github.com/crossplane/function-sdk-go/response" "github.com/crossplane-contrib/function-extra-resources/input/v1beta1" "google.golang.org/protobuf/types/known/structpb" ) func (f *Function) RunFunction(_ context.Context, req *fnv1.RunFunctionRequest) (*fnv1.RunFunctionResponse, error) { rsp := response.To(req, response.DefaultTTL) // 1. Parse Input in := &v1beta1.Input{} if err := request.GetInput(req, in); err != nil { response.Fatal(rsp, err) return rsp, nil } // 2. Read the observed composite resource (used for FromCompositeFieldPath labels) oxr, err := request.GetObservedCompositeResource(req) if err != nil { response.Fatal(rsp, err) return rsp, nil } // 3. Phase 1: declare requirements and return – Crossplane will re-call with resources requirements, err := buildRequirements(in, oxr) if err != nil { response.Fatal(rsp, err) return rsp, nil } rsp.Requirements = requirements if req.RequiredResources == nil { // First call: requirements declared, waiting for Crossplane to supply resources return rsp, nil } // 4. Phase 2: resources are present – validate, sort, and write to context extraResources, err := request.GetRequiredResources(req) if err != nil { response.Fatal(rsp, err) return rsp, nil } verifiedExtras, err := verifyAndSortExtras(in, extraResources) if err != nil { response.Fatal(rsp, err) return rsp, nil } s, _ := structpb.NewStruct(verifiedExtras) // Writes to "apiextensions.crossplane.io/extra-resources" by default response.SetContextKey(rsp, in.Spec.Context.GetKey(), structpb.NewStructValue(s)) return rsp, nil } ``` -------------------------------- ### Crossplane Composition with function-extra-resources and function-go-templating Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt This Composition defines a pipeline that first fetches 'EnvironmentConfig' and 'XCluster' resources using 'function-extra-resources' and then uses 'function-go-templating' to generate 'VaultRole' objects based on the fetched resources. ```yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: function-environment-configs spec: compositeTypeRef: apiVersion: example.crossplane.io/v1 kind: XR mode: Pipeline pipeline: # Step 1: fetch extra resources into context - step: pull-extra-resources functionRef: name: function-extra-resources input: apiVersion: extra-resources.fn.crossplane.io/v1beta1 kind: Input spec: extraResources: - kind: EnvironmentConfig into: envConfs apiVersion: apiextensions.crossplane.io/v1alpha1 type: Selector selector: maxMatch: 2 minMatch: 1 matchLabels: - key: type type: Value value: cluster - kind: XCluster into: XCluster apiVersion: example.crossplane.io/v1 type: Selector selector: maxMatch: 2 minMatch: 1 matchLabels: - key: type type: Value value: cluster # Step 2: consume context in a Go template to generate composed resources - step: go-templating functionRef: name: function-go-templating input: apiVersion: gotemplating.fn.crossplane.io/v1beta1 kind: GoTemplate source: Inline inline: template: | {{- $XClusters := index (index .context "apiextensions.crossplane.io/extra-resources") "XCluster" }} {{- range $i, $A := $XClusters }} --- apiVersion: vault.upbound.io/v1beta1 kind: VaultRole metadata: annotations: gotemplating.fn.fn.crossplane.io/composition-resource-name: {{ index (index $A "metadata") "name" }} spec: forProvider: {{- end }} ``` -------------------------------- ### Configure Extra Resources in Composition Source: https://github.com/crossplane-contrib/function-extra-resources/blob/main/README.md This YAML configuration demonstrates how to use the `function-extra-resources` to select extra resources within a Crossplane Composition. It specifies how to pull resources like XClusters based on labels and pass them to a subsequent Go templating function. ```yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: function-environment-configs spec: compositeTypeRef: apiVersion: example.crossplane.io/v1 kind: XR mode: Pipeline pipeline: - step: pull-extra-resources functionRef: name: function-extra-resources input: apiVersion: extra-resources.fn.crossplane.io/v1beta1 kind: Input spec: extraResources: - kind: XCluster into: XCluster apiVersion: example.crossplane.io/v1 type: Selector selector: maxMatch: 2 minMatch: 1 matchLabels: - key: type type: Value value: cluster - step: go-templating functionRef: name: function-go-templating input: apiVersion: gotemplating.fn.crossplane.io/v1beta1 kind: GoTemplate source: Inline inline: template: | {{- $XClusters := index (index .context "apiextensions.crossplane.io/extra-resources") "XCluster" }} {{- range $i, $A := $XClusters }} --- apiVersion: vault.upbound.io/v1beta1 kind: VaultRole metadata: annotations: gotemplating.fn.crossplane.io/composition-resource-name: {{index (index $A "metadata") "name"}} spec: forProvider: {{- end}} ``` -------------------------------- ### Check Optional Resolution Policy (Go) Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt Determines if the global resolution policy is set to 'Optional'. If true, missing 'Reference'-type resources are skipped instead of causing a fatal error. The default policy is 'Required'. ```go // policy: nil → Required (default) var p *v1beta1.Policy p.IsResolutionPolicyOptional() // → false (fatal if resource missing) // policy.resolution: "Optional" optional := xpv1.ResolutionPolicyOptional p = &v1beta1.Policy{Resolution: &optional} p.IsResolutionPolicyOptional() // → true (missing reference → silently skipped) // In a Composition Input: // spec: // policy: // resolution: Optional ← any Reference not found is skipped, not fatal // extraResources: // - type: Reference // into: maybeConfig // kind: EnvironmentConfig // apiVersion: apiextensions.crossplane.io/v1beta1 // ref: // name: optional-config ← if absent, pipeline continues normally ``` -------------------------------- ### Input API Configuration for function-extra-resources Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt Configure the function to fetch specific Kubernetes resources by name or label selector. Define the context key for results, resolution policy, and resource matching constraints. ```yaml apiVersion: extra-resources.fn.crossplane.io/v1beta1 kind: Input metadata: name: inline # name is required by KRM but not used by the function spec: # Optional: override the context key where results are written. # Defaults to "apiextensions.crossplane.io/extra-resources". context: key: apiextensions.crossplane.io/extra-resources # Optional: global resolution policy applied to all Reference-type entries. # "Required" (default) – fatal error if resource not found. # "Optional" – silently skip missing resources. policy: resolution: Required extraResources: # --- Reference by exact name --- - type: Reference # default; may be omitted kind: EnvironmentConfig apiVersion: apiextensions.crossplane.io/v1beta1 into: myEnvConfig # key in the context map ref: name: my-env-config # --- Selector by static label value --- - type: Selector kind: EnvironmentConfig apiVersion: apiextensions.crossplane.io/v1beta1 into: clusterConfigs selector: minMatch: 1 maxMatch: 5 sortByFieldPath: metadata.name # default matchLabels: - key: type type: Value # literal value value: cluster # --- Selector with value from composite field path --- - type: Selector kind: XCluster apiVersion: example.crossplane.io/v1 into: XCluster selector: minMatch: 1 maxMatch: 2 matchLabels: - key: env type: FromCompositeFieldPath # read label value from the XR valueFromFieldPath: spec.clusterEnv fromFieldPathPolicy: Required # or "Optional" to skip if missing # --- Namespaced resource by reference --- - type: Reference kind: Secret apiVersion: v1 namespace: my-namespace into: mySecret ref: name: db-credentials ``` -------------------------------- ### Sort Extra Resources by Field Path (Go) Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt Sorts a slice of resource.Required in-place by the value at a given dot-notation field path. Supports numeric and string types. Resources missing the field are sorted to the front. An empty path or mixed types return an error. ```go // Sorting by a numeric field: extras := []resource.Required{ resourceWithFieldPathValue("data.priority", 3), resourceWithFieldPathValue("data.priority", 1), resourceWithFieldPathValue("data.priority", 2), } err := sortExtrasByFieldPath(extras, "data.priority") // err == nil // extras order after call: priority=1, priority=2, priority=3 // Sorting by metadata.name (default): err = sortExtrasByFieldPath(extras, "metadata.name") // Alphabetical ascending order // Error – empty path: err = sortExtrasByFieldPath(extras, "") // err: "cannot sort by empty field path" // Error – inconsistent types (string mixed with int): err = sortExtrasByFieldPath(extras, "data.mixed") // err: "cannot sort values of different types" ``` -------------------------------- ### Context Key Resolution (Go) Source: https://context7.com/crossplane-contrib/function-extra-resources/llms.txt Retrieves the context key for resolved extra-resource objects. Defaults to 'apiextensions.crossplane.io/extra-resources' if the context field or its key is absent in the input spec. ```go // Default key (no context block in Input spec): var ctx *v1beta1.Context // nil ctx.GetKey() // → "apiextensions.crossplane.io/extra-resources" // Custom key (e.g. to feed function-patch-and-transform's environment): ctx = &v1beta1.Context{Key: ptr.To("apiextensions.crossplane.io/environment")} ctx.GetKey() // → "apiextensions.crossplane.io/environment" // Downstream consumption in a go-template pipeline step: // {{ $envs := index .context "apiextensions.crossplane.io/extra-resources" }} // {{ $clusters := index $envs "XCluster" }} // {{ range $clusters }} // # iterate over sorted XCluster objects // {{ end }} ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.