in kubectl-utils/cmd/kubectl-expect/main.go [42:158]
func run(ctx context.Context) error {
// log := klog.FromContext(ctx)
namespace := ""
kubeconfig := ""
pflag.StringVarP(&namespace, "namespace", "n", namespace, "If present, the namespace scope for this CLI request")
pflag.StringVar(&kubeconfig, "kubeconfig", kubeconfig, "Path to the kubeconfig file to use for CLI requests.")
klog.InitFlags(nil)
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
args := pflag.Args()
if len(args) < 2 {
return fmt.Errorf("expected [target] [cel-expression]")
}
target := args[0]
celExpressionText := args[1]
kubeClient, err := kube.NewClient(kubeconfig)
if err != nil {
return err
}
tokens := strings.Split(target, "/")
if len(tokens) != 2 {
return fmt.Errorf("expected target like Pod/<name>")
}
// Find the resource (kind) the user is asking about
resource, err := kubeClient.FindResource(ctx, tokens[0])
if err != nil {
return err
}
// Compute namespace, defaulting to kubeconfig or default
if namespace == "" && resource.Namespaced {
namespace, err = kubeClient.DefaultNamespace()
if err != nil {
return err
}
}
// Compile the CEL expression
env, err := kel.NewEnv()
if err != nil {
return fmt.Errorf("initalizing CEL: %w", err)
}
celExpression, err := kel.NewExpression(env, celExpressionText)
if err != nil {
return err
}
// build a pretty-printer for outputing status while polling
printer, err := celExpression.BuildStatusPrinter(ctx)
if err != nil {
return fmt.Errorf("building status printer: %w", err)
}
// Get ready to get the object
id := types.NamespacedName{
Namespace: namespace,
Name: tokens[1],
}
gv := schema.GroupVersion{
Group: resource.Group,
Version: resource.Version,
}
gvr := gv.WithResource(resource.Name)
gvk := gv.WithKind(resource.Kind)
client := kubeClient.ForGVR(gvr, id.Namespace)
// Poll the object until the CEL expression returns true
for {
// We _could_ watch...
time.Sleep(1 * time.Second)
u, err := client.Get(ctx, id.Name, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("getting %s %s: %w", gvk.Kind, id.Name, err)
}
out, err := celExpression.Eval(ctx, u)
if err != nil {
return err
}
done := false
switch out.Type() {
case celtypes.BoolType:
v := out.Value().(bool)
if v {
done = true
}
default:
return fmt.Errorf("unhandled type for CEL expression: %v", out.Type())
}
if done {
break
}
// Pretty print some intermediate values if we can
if printer != nil {
s := printer(ctx, u)
fmt.Printf("waiting for %q (%s)\n", celExpression.CELText, s)
} else {
fmt.Printf("waiting for %q\n", celExpression.CELText)
}
}
return nil
}