Skip to content

Commit 3e27f84

Browse files
committed
feat: simplify string expressions management
Signed-off-by: Charles-Edouard Brétéché <[email protected]>
1 parent 8e36f27 commit 3e27f84

File tree

15 files changed

+210
-77
lines changed

15 files changed

+210
-77
lines changed

pkg/engine/bindings/bindings.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/jmespath-community/go-jmespath/pkg/binding"
99
"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
1010
"github.com/kyverno/chainsaw/pkg/engine/templating"
11+
"github.com/kyverno/chainsaw/pkg/expressions"
1112
)
1213

1314
var identifier = regexp.MustCompile(`^\w+$`)
@@ -24,7 +25,7 @@ func RegisterBinding(ctx context.Context, bindings binding.Bindings, name string
2425
}
2526

2627
func ResolveBinding(ctx context.Context, bindings binding.Bindings, input any, variable v1alpha1.Binding) (string, any, error) {
27-
name, err := templating.String(ctx, variable.Name, bindings)
28+
name, err := expressions.String(ctx, variable.Name, bindings)
2829
if err != nil {
2930
return "", nil, err
3031
}

pkg/engine/kubectl/describe.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@ import (
88
"github.com/jmespath-community/go-jmespath/pkg/binding"
99
"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
1010
"github.com/kyverno/chainsaw/pkg/client"
11-
"github.com/kyverno/chainsaw/pkg/engine/templating"
11+
"github.com/kyverno/chainsaw/pkg/expressions"
1212
)
1313

1414
func Describe(ctx context.Context, client client.Client, tc binding.Bindings, collector *v1alpha1.Describe) (string, []string, error) {
1515
if collector == nil {
1616
return "", nil, errors.New("collector is null")
1717
}
18-
name, err := templating.String(ctx, collector.Name, tc)
18+
name, err := expressions.String(ctx, collector.Name, tc)
1919
if err != nil {
2020
return "", nil, err
2121
}
22-
namespace, err := templating.String(ctx, collector.Namespace, tc)
22+
namespace, err := expressions.String(ctx, collector.Namespace, tc)
2323
if err != nil {
2424
return "", nil, err
2525
}
26-
selector, err := templating.String(ctx, collector.Selector, tc)
26+
selector, err := expressions.String(ctx, collector.Selector, tc)
2727
if err != nil {
2828
return "", nil, err
2929
}

pkg/engine/kubectl/get.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,26 @@ import (
77
"github.com/jmespath-community/go-jmespath/pkg/binding"
88
"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
99
"github.com/kyverno/chainsaw/pkg/client"
10-
"github.com/kyverno/chainsaw/pkg/engine/templating"
10+
"github.com/kyverno/chainsaw/pkg/expressions"
1111
)
1212

1313
func Get(ctx context.Context, client client.Client, tc binding.Bindings, collector *v1alpha1.Get) (string, []string, error) {
1414
if collector == nil {
1515
return "", nil, errors.New("collector is null")
1616
}
17-
name, err := templating.String(ctx, collector.Name, tc)
17+
name, err := expressions.String(ctx, collector.Name, tc)
1818
if err != nil {
1919
return "", nil, err
2020
}
21-
namespace, err := templating.String(ctx, collector.Namespace, tc)
21+
namespace, err := expressions.String(ctx, collector.Namespace, tc)
2222
if err != nil {
2323
return "", nil, err
2424
}
25-
selector, err := templating.String(ctx, collector.Selector, tc)
25+
selector, err := expressions.String(ctx, collector.Selector, tc)
2626
if err != nil {
2727
return "", nil, err
2828
}
29-
format, err := templating.String(ctx, string(collector.Format), tc)
29+
format, err := expressions.String(ctx, string(collector.Format), tc)
3030
if err != nil {
3131
return "", nil, err
3232
}

pkg/engine/kubectl/logs.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,26 @@ import (
77

88
"github.com/jmespath-community/go-jmespath/pkg/binding"
99
"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
10-
"github.com/kyverno/chainsaw/pkg/engine/templating"
10+
"github.com/kyverno/chainsaw/pkg/expressions"
1111
)
1212

1313
func Logs(ctx context.Context, tc binding.Bindings, collector *v1alpha1.PodLogs) (string, []string, error) {
1414
if collector == nil {
1515
return "", nil, errors.New("collector is null")
1616
}
17-
name, err := templating.String(ctx, collector.Name, tc)
17+
name, err := expressions.String(ctx, collector.Name, tc)
1818
if err != nil {
1919
return "", nil, err
2020
}
21-
namespace, err := templating.String(ctx, collector.Namespace, tc)
21+
namespace, err := expressions.String(ctx, collector.Namespace, tc)
2222
if err != nil {
2323
return "", nil, err
2424
}
25-
selector, err := templating.String(ctx, collector.Selector, tc)
25+
selector, err := expressions.String(ctx, collector.Selector, tc)
2626
if err != nil {
2727
return "", nil, err
2828
}
29-
container, err := templating.String(ctx, collector.Container, tc)
29+
container, err := expressions.String(ctx, collector.Container, tc)
3030
if err != nil {
3131
return "", nil, err
3232
}

pkg/engine/kubectl/mapping.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ import (
88
"github.com/jmespath-community/go-jmespath/pkg/binding"
99
"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
1010
"github.com/kyverno/chainsaw/pkg/client"
11-
"github.com/kyverno/chainsaw/pkg/engine/templating"
11+
"github.com/kyverno/chainsaw/pkg/expressions"
1212
"k8s.io/apimachinery/pkg/api/meta"
1313
"k8s.io/apimachinery/pkg/runtime/schema"
1414
)
1515

1616
func mapResource(ctx context.Context, client client.Client, tc binding.Bindings, resource v1alpha1.ObjectType) (string, bool, error) {
1717
if resource.APIVersion != "" && resource.Kind != "" {
18-
if apiVersion, err := templating.String(ctx, resource.APIVersion, tc); err != nil {
18+
if apiVersion, err := expressions.String(ctx, resource.APIVersion, tc); err != nil {
1919
return "", false, err
20-
} else if kind, err := templating.String(ctx, resource.Kind, tc); err != nil {
20+
} else if kind, err := expressions.String(ctx, resource.Kind, tc); err != nil {
2121
return "", false, err
2222
} else {
2323
return mapResourceFromApiVersionAndKind(client, apiVersion, kind)

pkg/engine/kubectl/proxy.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,26 @@ import (
88
"github.com/jmespath-community/go-jmespath/pkg/binding"
99
"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
1010
"github.com/kyverno/chainsaw/pkg/client"
11-
"github.com/kyverno/chainsaw/pkg/engine/templating"
11+
"github.com/kyverno/chainsaw/pkg/expressions"
1212
)
1313

1414
func Proxy(ctx context.Context, client client.Client, tc binding.Bindings, collector *v1alpha1.Proxy) (string, []string, error) {
1515
if collector == nil {
1616
return "", nil, errors.New("collector is null")
1717
}
18-
name, err := templating.String(ctx, collector.Name, tc)
18+
name, err := expressions.String(ctx, collector.Name, tc)
1919
if err != nil {
2020
return "", nil, err
2121
}
22-
namespace, err := templating.String(ctx, collector.Namespace, tc)
22+
namespace, err := expressions.String(ctx, collector.Namespace, tc)
2323
if err != nil {
2424
return "", nil, err
2525
}
26-
targetPath, err := templating.String(ctx, collector.TargetPath, tc)
26+
targetPath, err := expressions.String(ctx, collector.TargetPath, tc)
2727
if err != nil {
2828
return "", nil, err
2929
}
30-
targetPort, err := templating.String(ctx, collector.TargetPort, tc)
30+
targetPort, err := expressions.String(ctx, collector.TargetPort, tc)
3131
if err != nil {
3232
return "", nil, err
3333
}

pkg/engine/kubectl/wait.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,26 @@ import (
88
"github.com/jmespath-community/go-jmespath/pkg/binding"
99
"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
1010
"github.com/kyverno/chainsaw/pkg/client"
11-
"github.com/kyverno/chainsaw/pkg/engine/templating"
11+
"github.com/kyverno/chainsaw/pkg/expressions"
1212
)
1313

1414
func Wait(ctx context.Context, client client.Client, tc binding.Bindings, collector *v1alpha1.Wait) (string, []string, error) {
1515
if collector == nil {
1616
return "", nil, errors.New("collector is null")
1717
}
18-
name, err := templating.String(ctx, collector.Name, tc)
18+
name, err := expressions.String(ctx, collector.Name, tc)
1919
if err != nil {
2020
return "", nil, err
2121
}
22-
namespace, err := templating.String(ctx, collector.Namespace, tc)
22+
namespace, err := expressions.String(ctx, collector.Namespace, tc)
2323
if err != nil {
2424
return "", nil, err
2525
}
26-
selector, err := templating.String(ctx, collector.Selector, tc)
26+
selector, err := expressions.String(ctx, collector.Selector, tc)
2727
if err != nil {
2828
return "", nil, err
2929
}
30-
format, err := templating.String(ctx, string(collector.Format), tc)
30+
format, err := expressions.String(ctx, string(collector.Format), tc)
3131
if err != nil {
3232
return "", nil, err
3333
}
@@ -42,15 +42,15 @@ func Wait(ctx context.Context, client client.Client, tc binding.Bindings, collec
4242
if collector.WaitFor.Deletion != nil {
4343
args = append(args, "--for=delete")
4444
} else if collector.WaitFor.Condition != nil {
45-
name, err := templating.String(ctx, collector.WaitFor.Condition.Name, tc)
45+
name, err := expressions.String(ctx, collector.WaitFor.Condition.Name, tc)
4646
if err != nil {
4747
return "", nil, err
4848
}
4949
if name == "" {
5050
return "", nil, errors.New("a condition name must be specified for condition wait type")
5151
}
5252
if collector.WaitFor.Condition.Value != nil {
53-
value, err := templating.String(ctx, *collector.WaitFor.Condition.Value, tc)
53+
value, err := expressions.String(ctx, *collector.WaitFor.Condition.Value, tc)
5454
if err != nil {
5555
return "", nil, err
5656
}
@@ -59,14 +59,14 @@ func Wait(ctx context.Context, client client.Client, tc binding.Bindings, collec
5959
args = append(args, fmt.Sprintf("--for=condition=%s", name))
6060
}
6161
} else if collector.WaitFor.JsonPath != nil {
62-
path, err := templating.String(ctx, collector.WaitFor.JsonPath.Path, tc)
62+
path, err := expressions.String(ctx, collector.WaitFor.JsonPath.Path, tc)
6363
if err != nil {
6464
return "", nil, err
6565
}
6666
if path == "" {
6767
return "", nil, errors.New("a path must be specified for jsonpath wait type")
6868
}
69-
value, err := templating.String(ctx, collector.WaitFor.JsonPath.Value, tc)
69+
value, err := expressions.String(ctx, collector.WaitFor.JsonPath.Value, tc)
7070
if err != nil {
7171
return "", nil, err
7272
}

pkg/expressions/parse.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package expressions
2+
3+
import (
4+
"context"
5+
"reflect"
6+
"regexp"
7+
)
8+
9+
var (
10+
escapeRegex = regexp.MustCompile(`^\\(.+)\\$`)
11+
engineRegex = regexp.MustCompile(`^\((?:(\w+):)?(.+)\)$`)
12+
)
13+
14+
type Expression struct {
15+
Statement string
16+
Engine string
17+
}
18+
19+
func Parse(ctx context.Context, value string) *Expression {
20+
return parseExpressionRegex(ctx, reflect.ValueOf(value).String())
21+
}
22+
23+
func parseExpressionRegex(_ context.Context, in string) *Expression {
24+
expression := &Expression{}
25+
// 1. match escape, if there's no escaping then match engine
26+
if match := escapeRegex.FindStringSubmatch(in); match != nil {
27+
in = match[1]
28+
} else {
29+
if match := engineRegex.FindStringSubmatch(in); match != nil {
30+
expression.Engine = match[1]
31+
// account for default engine
32+
if expression.Engine == "" {
33+
expression.Engine = "jp"
34+
}
35+
in = match[2]
36+
}
37+
}
38+
// parse statement
39+
expression.Statement = in
40+
if expression.Statement == "" {
41+
return nil
42+
}
43+
return expression
44+
}

pkg/engine/templating/string.go renamed to pkg/expressions/string.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
1-
package templating
1+
package expressions
22

33
import (
44
"context"
55
"fmt"
66

77
"github.com/jmespath-community/go-jmespath/pkg/binding"
8-
"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
8+
"github.com/kyverno/chainsaw/pkg/engine/functions"
9+
"github.com/kyverno/kyverno-json/pkg/engine/template"
910
)
1011

1112
func String(ctx context.Context, in string, bindings binding.Bindings) (string, error) {
1213
if in == "" {
1314
return "", nil
1415
}
15-
if converted, err := Template(ctx, v1alpha1.Any{Value: in}, nil, bindings); err != nil {
16+
expression := Parse(ctx, in)
17+
if expression == nil || expression.Engine == "" {
18+
return in, nil
19+
}
20+
if converted, err := template.Execute(ctx, expression.Statement, nil, bindings, template.WithFunctionCaller(functions.Caller())); err != nil {
1621
return "", err
1722
} else {
1823
if converted, ok := converted.(string); !ok {

pkg/expressions/string_pointer.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package expressions
2+
3+
// import (
4+
// "context"
5+
// "fmt"
6+
7+
// "github.com/jmespath-community/go-jmespath/pkg/binding"
8+
// "github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
9+
// )
10+
11+
// func StringPointer(ctx context.Context, in *string, bindings binding.Bindings) (*string, error) {
12+
// if in == nil {
13+
// return nil, nil
14+
// }
15+
// if *in == "" {
16+
// return in, nil
17+
// }
18+
// if converted, err := Template(ctx, v1alpha1.Any{Value: *in}, nil, bindings); err != nil {
19+
// return nil, err
20+
// } else if converted == nil {
21+
// return nil, nil
22+
// } else {
23+
// if converted, ok := converted.(*string); ok {
24+
// return converted, nil
25+
// }
26+
// if converted, ok := converted.(string); ok {
27+
// return &converted, nil
28+
// }
29+
// return nil, fmt.Errorf("expression didn't evaluate to a string pointer (%s)", *in)
30+
// }
31+
// }

0 commit comments

Comments
 (0)