in kubectl-utils/pkg/kel/info.go [68:147]
func (x *Expression) buildFunctionPrinterFor(args []*exprpb.Expr) (InfoFunction, error) {
checkedExpr, err := cel.AstToCheckedExpr(x.AST)
if err != nil {
return nil, fmt.Errorf("parsing CEL ast: %w", err)
}
type debugValue struct {
Key string
Program cel.Program
}
var debugValues []debugValue
for _, arg := range args {
shouldPrint := true
v := arg.ExprKind
switch v := v.(type) {
case *exprpb.Expr_ConstExpr:
// Don't print constants, 2=2 is not informative
shouldPrint = false
case *exprpb.Expr_SelectExpr:
shouldPrint = true
default:
klog.Warningf("unhandled expression kind %T", v)
}
if !shouldPrint {
continue
}
checkedArg := proto.Clone(checkedExpr).(*exprpb.CheckedExpr)
checkedArg.Expr = arg
ast := cel.CheckedExprToAst(checkedArg)
celExpression, err := cel.AstToString(ast)
if err != nil {
return nil, fmt.Errorf("converting expression to string: %w", err)
}
compiled, issues := x.Env.Compile(celExpression)
if issues != nil && issues.Err() != nil {
return nil, fmt.Errorf("invalid expression %q: %w", celExpression, issues.Err())
}
prg, err := x.Env.Program(compiled)
if err != nil {
return nil, fmt.Errorf("invalid expression %q: %w", celExpression, err)
}
debugValues = append(debugValues, debugValue{
Key: celExpression,
Program: prg,
})
}
if len(debugValues) == 0 {
return nil, nil
}
return func(ctx context.Context, self *unstructured.Unstructured) string {
log := klog.FromContext(ctx)
inputs := x.buildInputs(self)
var values []string
for _, debugValue := range debugValues {
s := ""
out, details, err := debugValue.Program.Eval(inputs)
log.V(2).Info("evaluated CEL expression", "out", out, "details", details, "error", err)
if err == nil {
s = fmt.Sprintf("%s=%v", debugValue.Key, out.Value())
} else {
s = fmt.Sprintf("%s=%v", debugValue.Key, "???")
}
values = append(values, s)
}
return strings.Join(values, "; ")
}, nil
}