### Minimal function-shell Quick Start Example Source: https://github.com/crossplane-contrib/function-shell/blob/main/README.md A basic example demonstrating how to configure the function-shell to execute a simple echo command and capture its standard output and error. ```yaml input: apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellCommand: echo "Hello from shell!" stdoutField: status.atFunction.shell.stdout stderrField: status.atFunction.shell.stderr ``` -------------------------------- ### README.md Navigation Hierarchy Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/MANIFEST.md Illustrates the starting point and structure of the documentation, guiding users through different reference and guide files. ```markdown README.md (start here) ├── Quick Reference ├── File Organization └── Points to: ├── INDEX.md (complete reference) ├── REFERENCE.md (project overview) └── Specific guides: ├── api-reference/types.md ├── api-reference/function.md ├── configuration.md ├── errors.md └── examples.md ``` -------------------------------- ### Usage Example: Valid and Invalid Parameters Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/validation.md Provides examples of calling ValidateParameters with both valid and invalid Parameters objects, demonstrating how to check for errors. ```go in := &v1alpha1.Parameters{ ShellCommand: "echo 'hello'", StdoutField: "status.output", } err := ValidateParameters(in, oxr) if err != nil { // err is nil, validation passed } in2 := &v1alpha1.Parameters{ // Both empty } err2 := ValidateParameters(in2, oxr) if err2 != nil { // err2.Error() returns: "parameters: Invalid value: \"\"..." } ``` -------------------------------- ### Parameters Usage Example Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/types.md Illustrates how to configure the Parameters object for a Composition pipeline step. This example specifies an inline shell command, output field paths, and a cache TTL. ```yaml apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellCommand: echo "Hello World" stdoutField: status.output.message stderrField: status.output.error cacheTTL: 5m ``` -------------------------------- ### Function Shell Server Startup Commands Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/README.md Illustrates commands for starting the function-shell server, with options for insecure mode, debugging, and TLS configuration. ```bash ./function-shell --insecure --debug ``` ```bash ./function-shell --tls-certs-dir=/etc/ssl/certs --address=:9443 ``` -------------------------------- ### Example Usage of fromValueRef Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/environment.md Demonstrates how to use the fromValueRef function to resolve a required field and handle potential errors. ```go // Resolve a field, error if it doesn't exist value, err := fromValueRef(req, "spec.size") if err != nil { // Handle error: field not found or type conversion failed } // Use value ``` -------------------------------- ### Function Serve Example Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/dependencies.md Demonstrates how to serve a custom Function implementation using the function-sdk-go. This typically involves setting up a gRPC server and registering the Function handler. ```go func() { // ... CLI setup and logger initialization ... // Serve the function function.Serve(&Function{}) } ``` -------------------------------- ### API Reference and Guides Structure Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/MANIFEST.md Details the organization of API reference files and guides, specifying the content covered in each. ```markdown API Reference (6 files) ├── types.md — What: Type definitions ├── function.md — How: Core logic ├── cli.md — Where: Server setup ├── environment.md — How: Variable resolution ├── validation.md — Why: Validation rules └── dependencies.md — Why: Architecture Guides (3 files) ├── configuration.md — Configure ├── errors.md — Debug └── examples.md — Implement ``` -------------------------------- ### Referenced Secret Content Example Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/types.md Provides an example of the content expected within the Kubernetes secret referenced by the deploymentRuntimeConfig. It should be a JSON object with the desired environment variable keys and values. ```json { "DATADOG_API_KEY": "your-api-key", "DATADOG_APP_KEY": "your-app-key" } ``` -------------------------------- ### Handling Missing Optional Fields Example Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/examples.md Gracefully handle scenarios where optional fields may not be set by using the Optional policy and providing default values. This example configures environment variables and executes a shell command conditionally. ```yaml apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellEnvVars: - key: WEBHOOK_URL fieldRef: path: spec.webhook.url policy: Optional defaultValue: "" - key: NOTIFICATION_EMAIL fieldRef: path: spec.notifications.email policy: Optional defaultValue: "" shellCommand: | if [ -z "$WEBHOOK_URL" ]; then echo "No webhook configured, skipping notification" else curl -X POST "$WEBHOOK_URL" -d "Deployment completed" fi if [ -n "$NOTIFICATION_EMAIL" ]; then echo "Sending email notification to $NOTIFICATION_EMAIL" mail -s "Deployment Complete" "$NOTIFICATION_EMAIL" < /dev/stdin fi stdoutField: status.notifications.log stderrField: status.notifications.errors ``` -------------------------------- ### Example: Optional Field Reference with Default Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/types.md An example of a FieldRef configuration where the 'spec.debug' field is optional. If the field is missing, the defaultValue 'false' will be used. ```yaml fieldRef: path: spec.debug policy: Optional defaultValue: "false" ``` -------------------------------- ### Example XR and Result Manifests Source: https://github.com/crossplane-contrib/function-shell/blob/main/example/README.md Sample Kubernetes manifests for an XR (example.crossplane.io/v1) and a Result (render.crossplane.io/v1beta1). These are used as input for the Crossplane function. ```yaml --- 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 ``` -------------------------------- ### Function Shell Composition Usage Example Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/README.md Demonstrates how to use the function-shell within a Crossplane Composition, specifying the command and environment variables. ```yaml input: apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellCommand: echo "Hello from $REGION" shellEnvVars: - key: REGION fieldRef: path: spec.region stdoutField: status.output stderrField: status.errors ``` -------------------------------- ### Multi-Step Composition Pipeline with Function Shell Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/examples.md This example demonstrates a Composition in 'Pipeline' mode that uses the function-shell for validation and post-deployment configuration steps, alongside another function for resource creation. It shows how to define inputs for each step, including inline shell commands and output capture locations. ```yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: full-deployment spec: compositeTypeRef: apiVersion: example.io/v1 kind: XApp mode: Pipeline pipeline: # Step 1: Validate configuration - step: validate-config functionRef: name: function-shell input: apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellCommandField: spec.validationScript stdoutField: status.validation.output # Step 2: Create resources (e.g., using crossplane-compose) - step: create-resources functionRef: name: crossplane-compose input: apiVersion: compose.fn.crossplane.io/v1alpha1 kind: Composition resources: - apiVersion: compute.example.com/v1 kind: Instance # Step 3: Post-deployment configuration - step: configure-app functionRef: name: function-shell input: apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellCommand: | echo "Configuring application..." kubectl apply -f /app/config.yaml stdoutField: status.configuration.output ``` -------------------------------- ### Example DeploymentRuntimeConfig for Function Shell Source: https://github.com/crossplane-contrib/function-shell/blob/main/README.md A sample DeploymentRuntimeConfig that configures the function-shell deployment. It shows how to set arguments and inject environment variables, including referencing a Kubernetes secret. ```yaml --- apiVersion: pkg.crossplane.io/v1beta1 kind: DeploymentRuntimeConfig metadata: name: function-shell spec: deploymentTemplate: spec: selector: {} replicas: 1 template: spec: containers: - name: package-runtime args: - --debug env: - name: DATADOG_SECRET valueFrom: secretKeyRef: key: credentials name: datadog-secret ``` -------------------------------- ### Function Response Caching Example Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/examples.md Cache function results to reduce redundant execution. This example shows how to set a cache TTL and define environment variables and shell commands. ```yaml apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters cacheTTL: 5m shellEnvVars: - key: REGION fieldRef: path: spec.region shellCommand: | echo "Querying available instance types in $REGION..." aws ec2 describe-instance-types \ --region $REGION \ --query 'InstanceTypes[*].[InstanceType,VCpuInfo.DefaultVCpus]' \ --output table stdoutField: status.availableInstances ``` -------------------------------- ### Example: Direct Value Environment Variable Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/types.md Configures an environment variable with a static string value. The type is explicitly set to 'Value'. ```yaml shellEnvVars: - key: API_URL value: "https://api.example.com" type: Value ``` -------------------------------- ### Call Function with Example Manifests Source: https://github.com/crossplane-contrib/function-shell/blob/main/example/README.md Invoke the locally running function using `crossplane beta render` with provided XR, composition, and function manifests. The `-r` flag indicates a render operation. ```shell # Then, in another terminal, call it with these example manifests $ crossplane beta render xr.yaml composition.yaml functions.yaml -r ``` -------------------------------- ### Execute Echo with Static Environment Variable Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/examples.md This example shows a basic Composition that uses the function-shell to echo a base64-encoded message using a static environment variable. ```yaml apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: echo-example spec: compositeTypeRef: apiVersion: example.crossplane.io/v1 kind: XR mode: Pipeline pipeline: - step: shell functionRef: name: function-shell input: apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellEnvVars: - key: MESSAGE value: "SGVsbG8gZnJvbSBzaGVsbAo=" shellCommand: | echo ${MESSAGE} | base64 -d stdoutField: status.message stderrField: status.error ``` ```yaml apiVersion: example.crossplane.io/v1 kind: XR metadata: name: test spec: {} ``` -------------------------------- ### Configure Function Shell with Cache TTL Source: https://github.com/crossplane-contrib/function-shell/blob/main/README.md Example configuration for the function-shell, demonstrating how to set a cache Time-To-Live (TTL) and define shell environment variables and commands. The stdout and stderr are directed to specific fields. ```yaml input: apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters cacheTTL: 5m shellEnvVars: - key: ECHO value: "SGVsbG8gZnJvbSBzaGVsbAo=" shellCommand: | echo ${ECHO}|base64 -d|sed s/^h/H/ stdoutField: status.atFunction.shell.stdout stderrField: status.atFunction.shell.stderr ``` -------------------------------- ### Handle Optional Fields with Default Values Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/examples.md This example demonstrates how to use the function-shell to handle optional configuration fields by providing default values when the fields are not set in the composite resource. ```yaml apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellEnvVars: - key: LOG_LEVEL fieldRef: path: spec.logging.level policy: Optional defaultValue: INFO - key: TIMEOUT fieldRef: path: spec.timeout policy: Optional defaultValue: 300 shellCommand: | echo "Logging level: $LOG_LEVEL" echo "Timeout: $TIMEOUT seconds" application --log-level=$LOG_LEVEL --timeout=$TIMEOUT stdoutField: status.application.output ``` -------------------------------- ### Error Field Path Example Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/validation.md Demonstrates how validation errors are reported at the 'parameters' field path using field.Required. ```go field.NewPath("parameters") ``` -------------------------------- ### Example JSON Format for Environment Variable Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/types.md Illustrates the expected JSON structure for an environment variable referenced by ShellEnvVarsRef. It should contain string keys and string values. ```json { "KEY1": "value1", "KEY2": "value2", "API_KEY": "secret-key-value" } ``` -------------------------------- ### Example: Required Field Reference Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/types.md An example of a FieldRef configuration where the 'spec.region' field is required. If this field is missing, an error will be returned. ```yaml fieldRef: path: spec.region policy: Required ``` -------------------------------- ### Run Function Locally Source: https://github.com/crossplane-contrib/function-shell/blob/main/example/README.md Execute the function-shell locally with insecure and debug flags enabled. This command starts the local server for the function. ```shell # Run the function locally $ go run . --insecure --debug ``` -------------------------------- ### Example: Field Reference Environment Variable Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/types.md Configures an environment variable by referencing a required field from the spec. The type is explicitly set to 'FieldRef'. ```yaml shellEnvVars: - key: REGION fieldRef: path: spec.region policy: Required type: FieldRef ``` -------------------------------- ### Example: Context Field Reference Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/types.md An example of a FieldRef configuration that references a field within the composition context, specifically 'context[cluster].name'. This field is marked as required. ```yaml fieldRef: path: context[cluster].name policy: Required ``` -------------------------------- ### Example Secret for Environment Variables Source: https://github.com/crossplane-contrib/function-shell/blob/main/README.md An example of a Kubernetes secret formatted in JSON, which can be used to provide environment variables to the function-shell. The keys in the JSON become environment variable names. ```json { "ENV_FOO": "foo value", "ENV_BAR": "bar value" } ``` -------------------------------- ### Example Composite Resource Status Conditions Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/errors.md Examine the conditions in the XR status to understand the nature of the error, such as FunctionFailed or ReconcileFailed. ```yaml status: conditions: - lastTransitionTime: "2024-01-01T12:00:00Z" message: "composition function failed" reason: FunctionFailed status: "False" type: Composed - message: "Function returned a fatal result: shellCmd \"curl ...\" failed with exit code 1" reason: ReconcileFailed status: "False" type: Ready ``` -------------------------------- ### Composition Using Environment Variable References Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/examples.md An example Composition that references environment variables loaded from a Kubernetes secret. It uses these variables to construct and execute a curl command. ```yaml apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellEnvVarsRef: name: DATADOG_SECRET keys: - DATADOG_API_KEY - DATADOG_APP_KEY shellEnvVars: - key: DATADOG_API_URL value: https://api.datadoghq.com/api/v1/dashboard shellCommand: | curl -X GET "${DATADOG_API_URL}" \ -H "Accept: application/json" \ -H "DD-API-KEY: ${DATADOG_API_KEY}" \ -H "DD-APPLICATION-KEY: ${DATADOG_APP_KEY}" \ | jq '.dashboards[] | .id' stdoutField: status.dashboards stderrField: status.errors ``` -------------------------------- ### Load ProviderConfig with function-extra-resources Source: https://github.com/crossplane-contrib/function-shell/blob/main/example/aws/README.md Example of a ProviderConfig resource used to load AWS credentials and assume a role. Ensure the `roleARN` is correctly set for your environment. ```yaml apiVersion: aws.upbound.io/v1beta1 kind: ProviderConfig metadata: labels: account: demo name: demo spec: assumeRoleChain: - roleARN: arn:aws:iam::000000000001:role/eks-test-assume-role credentials: source: IRSA ``` -------------------------------- ### Example: Optional Field with Default Value Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/types.md Configures an environment variable using a field reference with an 'Optional' policy and a default value. The type is explicitly set to 'FieldRef'. ```yaml shellEnvVars: - key: DEBUG_MODE fieldRef: path: spec.debug policy: Optional defaultValue: "false" type: FieldRef ``` -------------------------------- ### Injecting Secrets and Values as Environment Variables Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/configuration.md Use DeploymentRuntimeConfig to define environment variables for function pods. This example injects a secret's content into API_CREDENTIALS and a direct URL into WEBHOOK_URL. ```yaml apiVersion: pkg.crossplane.io/v1beta1 kind: DeploymentRuntimeConfig metadata: name: function-shell spec: deploymentTemplate: spec: selector: {} replicas: 1 template: spec: containers: - name: package-runtime env: - name: API_CREDENTIALS valueFrom: secretKeyRef: name: api-secret key: credentials - name: WEBHOOK_URL value: https://webhook.example.com ``` -------------------------------- ### Capturing Error Details Example Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/examples.md Ensure errors are captured even when the command fails by using 'set +e' to prevent script exit on error. This allows for cleanup or rollback logic before final failure. ```yaml apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellCommand: | set +e # Don't exit on error echo "Attempting to deploy application..." if ! deployment_script; then echo "Deployment failed! Attempting rollback..." rollback_script exit 1 fi stderrField: status.errors.details stdoutField: status.deploy.log ``` -------------------------------- ### Main Entry Point Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/cli.md Parses CLI flags using kong and executes the Run method, handling errors. ```go func main() { ctx := kong.Parse(&CLI{}, kong.Description("A Crossplane Composition Function.")) ctx.FatalIfErrorf(ctx.Run()) } ``` -------------------------------- ### Shell Function Server Startup Sequence Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/INDEX.md Illustrates the sequence of calls during the Shell Function's server startup, from parsing CLI arguments to the gRPC server listening. ```plaintext main() → kong.Parse(&CLI{}) → CLI.Run() → function.NewLogger() → function.Serve(&Function{}) → gRPC server listening ``` -------------------------------- ### Parse and Execute Shell Commands with keegancsmith/shell Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/dependencies.md Use the `keegancsmith/shell` package to parse and execute shell commands. Configure `Stdout` and `Stderr` to capture command output and errors. The default shell is `/bin/sh`. ```go import "github.com/keegancsmith/shell" cmd := shell.Commandf("export KEY=value; " + shellCommand) cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() ``` -------------------------------- ### Export Environment Variables for Shell Command Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/environment.md Constructs export commands for all resolved environment variables and prepares them for shell command execution. ```go var exportCmds string for k, v := range shellEnvVars { exportCmds = exportCmds + "export " + k + \"=\"" + v + \"\";" } // Shell command execution: cmd := shell.Commandf(exportCmds + shellCmd) ``` -------------------------------- ### View Composite Resource Status Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/errors.md Use kubectl to get the YAML status of a composite resource to inspect composition conditions and identify errors. ```bash kubectl get xr -o yaml ``` -------------------------------- ### Shell Command Execution Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/function.md Prepares a shell command with environment variables for execution. The export statements ensure all variables are available to the shell and its subcommands. ```go cmd := shell.Commandf(exportCmds + shellCmd) ``` ```shell export KEY1="value1";export KEY2="value2"; ``` -------------------------------- ### Add Shell Environment Variables from Reference Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/environment.md Processes ShellEnvVarsRef if Keys are provided, adding environment variables from a reference. ```go if len(in.ShellEnvVarsRef.Keys) > 0 { shellEnvVars, err = addShellEnvVarsFromRef(in.ShellEnvVarsRef, shellEnvVars) } ``` -------------------------------- ### Docker Container Entrypoint Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/cli.md Configures the Docker container to run the function-shell with mTLS enabled. ```dockerfile ENTRYPOINT ["./function-shell", "--tls-certs-dir=/etc/ssl/certs", "--address=:9443"] ``` -------------------------------- ### Environment Variable Resolution from ValueRef Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/dependencies.md Demonstrates resolving environment variables using ValueRef, which directly references a value. This is used for required field references. ```go func fromValueRef(ctx context.Context, req *request.RunFunctionRequest, valueRef input.ValueRef) (string, error) { // ... implementation to resolve value directly ... return "", nil } ``` -------------------------------- ### Shell Function Invocation Lifecycle Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/INDEX.md Details the steps involved in a single Shell Function invocation, from receiving a gRPC request to building environment variables and executing commands. ```plaintext gRPC RunFunctionRequest → Function.RunFunction() → request.GetInput() → Parameters → ValidateParameters() → request.GetObservedCompositeResource() → request.GetDesiredCompositeResource() → Resolve: ShellCommand or ShellCommandField → Build env vars: - ShellEnvVars: Value/ValueRef/FieldRef - ShellEnvVarsRef: JSON from pod env var → shell.Commandf(exports + cmd) → Capture stdout/stderr → SetValue(stdoutField) → SetValue(stderrField) → Check exit code → response.Fatal() if error → gRPC RunFunctionResponse ``` -------------------------------- ### Capture and Set Command Output Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/function.md Trims whitespace from the captured standard output and standard error, then sets these values as fields in the desired composite resource. ```go sout := strings.TrimSpace(stdout.String()) serr := strings.TrimSpace(stderr.String()) err = dxr.Resource.SetValue(stdoutField, sout) err = dxr.Resource.SetValue(stderrField, serr) ``` -------------------------------- ### Development Usage Pattern Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/cli.md Runs the function-shell locally without TLS and with debug logging enabled. ```bash go run . --insecure --debug ``` -------------------------------- ### Secret Integration for Environment Variables Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/configuration.md Integrate with Kubernetes secrets to provide sensitive environment variables for shell commands. This example uses `shellEnvVarsRef` to reference a secret containing JSON-formatted variables and specifies output/error fields along with a cache TTL. ```yaml apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellCommand: | curl -H "Authorization: Bearer $API_TOKEN" \ https://api.example.com/resources shellEnvVarsRef: name: API_CREDENTIALS keys: - API_TOKEN - API_ENDPOINT stdoutField: status.api.response stderrField: status.api.error cacheTTL: 5m ``` ```json { "API_TOKEN": "secret-token-value", "API_ENDPOINT": "https://api.example.com" } ``` -------------------------------- ### Multi-Step Command with Pipes and Redirection Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/examples.md Execute complex shell commands involving pipes, external API calls, and JSON processing. This is useful for multi-step deployment or configuration processes. Ensure `jq` is available in the function environment for JSON parsing. The `set -e` command ensures that the script will exit immediately if any command fails. ```yaml apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellEnvVars: - key: ENVIRONMENT fieldRef: path: spec.environment shellCommand: | set -e echo "Starting deployment in $ENVIRONMENT environment" # Fetch configuration CONFIG=$(curl -s https://config.example.com/$ENVIRONMENT) # Extract and validate SERVICES=$(echo "$CONFIG" | jq -r '.services[]') # Deploy each service echo "$SERVICES" | while read service; echo "Deploying $service..." deploy_service "$service" done echo "Deployment complete" stdoutField: status.deployment.log stderrField: status.deployment.errors ``` -------------------------------- ### Function Shell Input Parameters Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/README.md Defines the structure for input parameters to the function-shell, specifying how to provide commands, environment variables, and output fields. ```go type Parameters struct { ShellCommand string // Inline command to execute ShellCommandField string // Field reference to command ShellEnvVars []ShellEnvVar // Environment variables ShellEnvVarsRef ShellEnvVarsRef // Reference to secret/pod env var StdoutField string // Where to write stdout StderrField string // Where to write stderr CacheTTL string // Cache duration (e.g., "5m") } ``` ```go type ShellEnvVar struct { Key string // Variable name Value string // Direct value (type: Value) ValueRef string // Composite field (type: ValueRef) FieldRef *FieldRef // Structured field ref (type: FieldRef) Type ShellEnvVarType // Auto-detected if omitted } ``` ```go type FieldRef struct { Path string // JSONPath (e.g., "spec.region") Policy string // "Required" or "Optional" DefaultValue string // Fallback if Optional and missing } ``` -------------------------------- ### Add Shell Environment Variables from Reference Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/environment.md Resolves environment variables from a pod environment variable containing JSON-formatted key-value pairs. Loads the environment variable by name, unmarshals it as JSON, and extracts the specified keys. Overwrites existing keys silently. ```go shellEnvVars["API_KEY"] = "secret-key-123" shellEnvVars["API_SECRET"] = "secret-456" ``` -------------------------------- ### Execute Shell Command Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/function.md Constructs and runs a shell command, capturing its standard output and standard error. The command is built from exported environment variables and the shell command string. ```go var stdout, stderr bytes.Buffer cmd := shell.Commandf(exportCmds + shellCmd) cmd.Stdout = &stdout cmd.Stderr = &stderr cmderr := cmd.Run() ``` -------------------------------- ### Initialize Function Logger Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/dependencies.md Initializes the Crossplane runtime logger. The logger is thread-safe and buffered, with flushing handled by the runtime. ```go log, err := function.NewLogger(debug bool) ``` -------------------------------- ### Loading Environment Variables from Pod JSON Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/dependencies.md Explains how to load shell environment variables from a JSON structure present in the pod's environment. This is handled by the addShellEnvVarsFromRef function. ```go func addShellEnvVarsFromRef(ctx context.Context, req *request.RunFunctionRequest, envRef input.ShellEnvVarsRef) error { // ... implementation to load env vars from JSON ... return nil } ``` -------------------------------- ### Initialize Response Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/function.md Initializes a new RunFunctionResponse object with a default cache TTL. This is typically the first step in processing a RunFunctionRequest. ```go rsp := response.To(req, response.DefaultTTL) ``` -------------------------------- ### Valid Input: Direct Command Source Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/validation.md This scenario demonstrates a valid input where the command is directly provided using 'shellCommand'. Validation passes, and the composition proceeds to shell command execution. ```yaml apiVersion: shell.fn.crossplane.io/v1alpha1 kind: Parameters shellCommand: | curl https://api.example.com | jq . stdoutField: status.output ``` -------------------------------- ### Navigate Context Fields with Unstructured and Fieldpath Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/dependencies.md Convert unstructured context data to Kubernetes `Unstructured` objects and use `fieldpath.Pave` for navigation. This allows for dynamic field access within unstructured context data. ```go context := &unstructured.Unstructured{} resource.AsObject(contextValue.GetStructValue(), context) value, err := fieldpath.Pave(context.Object).GetValue(fieldPath) ``` -------------------------------- ### Function Run Function Signature Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/README.md Shows the signature for the main RunFunction method, which is the entry point for processing requests within the function-shell. ```go func (f *Function) RunFunction( ctx context.Context, req *fnv1.RunFunctionRequest, ) (*fnv1.RunFunctionResponse, error) ``` -------------------------------- ### Implement Response-Based Error Handling in Functions Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/dependencies.md Instead of returning errors directly, use the `response.Fatal` method to halt the composition pipeline and signal errors. Always return the response object, even when an error occurs. ```go // NOT like this: return response, err // Instead like this: if err != nil { response.Fatal(rsp, errors.Wrap(err, "message")) return rsp, nil // Always return response, never error } ``` -------------------------------- ### View Function-Shell Pod Logs Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/errors.md Stream the logs from the Function-Shell deployment to monitor its activity and identify errors. ```bash kubectl logs -n crossplane-system deployment/crossplane-contrib-function-shell -f --tail=100 ``` -------------------------------- ### Function Shell Docker Entrypoint Configuration Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/configuration.md This Dockerfile snippet defines the entrypoint for the function-shell container, specifying TLS settings, listening address, and maximum message size. ```dockerfile ENTRYPOINT ["./function-shell", \ "--tls-certs-dir=/etc/ssl/certs", \ "--address=:9443", \ "--max-recv-message-size=8"] ``` -------------------------------- ### Create IAM Policy for Listing Roles Source: https://github.com/crossplane-contrib/function-shell/blob/main/example/aws/README.md Defines and creates an IAM policy that allows listing IAM roles. This policy is then attached to a role for cross-account access. ```bash aws iam create-policy \ --policy-name IAMRoleLister \ --policy-document \ '{ \ "Version": "2012-10-17", \ "Statement": [ \ { \ "Action": [ \ "iam:ListRoles" \ ], \ "Resource": "*", \ "Effect": "Allow" \ } \ ] \ }' ``` -------------------------------- ### CLI Struct Definition Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/cli.md Defines the command-line flags and configuration options for the function-shell server. ```go type CLI struct { Debug bool `help:"Emit debug logs in addition to info logs." short:"d" Network string `default:"tcp" help:"Network on which to listen for gRPC connections." Address string `default:":9443" help:"Address at which to listen for gRPC connections." TLSCertsDir string `env:"TLS_SERVER_CERTS_DIR" help:"Directory containing server certs (tls.key, tls.crt) and the CA used to verify client certificates (ca.crt)" Insecure bool `help:"Run without mTLS credentials. If you supply this flag --tls-server-certs-dir will be ignored." MaxRecvMessageSize int `default:"4" help:"Maximum size of received messages in MB." } ``` -------------------------------- ### Production Usage Pattern Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/cli.md Runs the function-shell with mTLS enabled and a larger message size for complex compositions. ```bash go run . \ --tls-certs-dir=/etc/ssl/certs \ --address=:9443 \ --max-recv-message-size=8 ``` -------------------------------- ### Function RunFunction Logic Source: https://github.com/crossplane-contrib/function-shell/blob/main/_autodocs/api-reference/dependencies.md Illustrates the core logic within the RunFunction method of the Function struct. It handles request processing, parameter validation, environment variable resolution, shell command execution, and response building. ```go func (f *Function) RunFunction(ctx context.Context, req *request.RunFunctionRequest, rsp *response.RunFunctionResponse) error { // ... parameter unmarshaling and validation ... // ... environment variable resolution ... // ... shell command execution ... // ... response serialization ... return nil } ```