Skip to content

Commit 088daa2

Browse files
feat: add standard CLI options
Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com>
1 parent bf17fa5 commit 088daa2

2 files changed

Lines changed: 126 additions & 0 deletions

File tree

crossplane/function/cli.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Copyright 2026 The Crossplane Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Standard CLI options for Python composition functions.
16+
17+
Provides reusable options and a run helper so that every composition
18+
function shares a standard set of flags, environment variables, and defaults.
19+
20+
Usage in a function's main.py::
21+
22+
import click
23+
from crossplane.function import cli as sdkcli
24+
from function import fn
25+
26+
@click.command()
27+
@sdkcli.standard_options
28+
def cli(**kwargs):
29+
sdkcli.run(fn.FunctionRunner(), **kwargs)
30+
31+
To add custom options, stack them with the decorator::
32+
33+
@click.command()
34+
@sdkcli.standard_options
35+
@click.option("--cache-size", default=100, envvar="CACHE_SIZE")
36+
def cli(cache_size, **kwargs):
37+
runner = fn.FunctionRunner(cache_size=cache_size)
38+
sdkcli.run(runner, **kwargs)
39+
"""
40+
41+
import functools
42+
from collections.abc import Callable
43+
from typing import TypeVar
44+
45+
import click
46+
47+
from crossplane.function import logging, runtime
48+
from crossplane.function.proto.v1 import run_function_pb2_grpc as grpcv1
49+
50+
F = TypeVar("F", bound=Callable)
51+
52+
DEFAULT_ADDRESS = "0.0.0.0:9443"
53+
DEFAULT_MAX_RECV_MESSAGE_SIZE = 4 # MB
54+
55+
56+
def standard_options(func: F) -> F:
57+
"""Apply the standard Composition Function CLI options to a Click command."""
58+
59+
@click.option(
60+
"--max-recv-message-size",
61+
type=int,
62+
default=DEFAULT_MAX_RECV_MESSAGE_SIZE,
63+
show_default=True,
64+
envvar="MAX_RECV_MESSAGE_SIZE",
65+
help="Maximum size of received gRPC messages in MB.",
66+
)
67+
@click.option(
68+
"--insecure",
69+
is_flag=True,
70+
envvar="INSECURE",
71+
help="Run without mTLS credentials. "
72+
"If you supply this flag --tls-certs-dir will be ignored.",
73+
)
74+
@click.option(
75+
"--tls-certs-dir",
76+
envvar="TLS_SERVER_CERTS_DIR",
77+
help="Serve using mTLS certificates.",
78+
)
79+
@click.option(
80+
"--address",
81+
default=DEFAULT_ADDRESS,
82+
show_default=True,
83+
envvar="ADDRESS",
84+
help="Address at which to listen for gRPC connections.",
85+
)
86+
@click.option(
87+
"--debug",
88+
"-d",
89+
is_flag=True,
90+
envvar="DEBUG",
91+
help="Emit debug logs.",
92+
)
93+
@functools.wraps(func)
94+
def wrapper(*args, **kwargs):
95+
return func(*args, **kwargs)
96+
97+
return wrapper
98+
99+
100+
def run( # noqa: PLR0913
101+
function_runner: grpcv1.FunctionRunnerServiceServicer,
102+
*,
103+
debug: bool,
104+
address: str,
105+
tls_certs_dir: str | None,
106+
insecure: bool,
107+
max_recv_message_size: int,
108+
) -> None:
109+
"""Start a composition function gRPC server with standard options."""
110+
level = logging.Level.DEBUG if debug else logging.Level.INFO
111+
logging.configure(level=level)
112+
113+
size_bytes = max_recv_message_size * 1024 * 1024
114+
options = [
115+
("grpc.max_receive_message_length", size_bytes),
116+
("grpc.max_send_message_length", size_bytes),
117+
]
118+
119+
runtime.serve(
120+
function_runner,
121+
address,
122+
creds=runtime.load_credentials(tls_certs_dir),
123+
insecure=insecure,
124+
options=options,
125+
)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ classifiers = [
1818
]
1919

2020
dependencies = [
21+
"click==8.*",
2122
"grpcio==1.83.1",
2223
"grpcio-reflection==1.*",
2324
"protobuf==7.36.1", # Must be compatible with grpcio-tools.

0 commit comments

Comments
 (0)