3
0

Add conditional envoy processing for compose records

This commit is contained in:
Tomaž Jerman
2020-12-01 14:23:12 +01:00
parent 3a9891431d
commit 22785ad10b
9 changed files with 181 additions and 1 deletions
+5
View File
@@ -6,6 +6,11 @@ type (
ii Identifiers
rr RefSet
}
EnvoyConfig struct {
// SkipIf determines when the encoding should be skipped for this resource
SkipIf string
}
)
// State management methods
+2
View File
@@ -21,6 +21,8 @@ type (
Values map[string]string
SysValues *rawSysValues
RefUsers map[string]string
Config *EnvoyConfig
}
ComposeRecordRawSet []*ComposeRecordRaw
+40
View File
@@ -9,6 +9,7 @@ import (
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/envoy"
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/store"
)
@@ -20,6 +21,9 @@ type (
relNS *types.Namespace
relMod *types.Module
// Little helper flag for conditional encoding
modEmpty bool
}
)
@@ -46,6 +50,7 @@ func (n *composeRecordState) Prepare(ctx context.Context, s store.Storer, state
return composeNamespaceErrUnresolved(n.res.NsRef.Identifiers)
}
n.modEmpty = true
n.relMod = findComposeModuleR(state.ParentResources, n.res.ModRef.Identifiers)
if n.relMod == nil && n.relNS.ID > 0 {
n.relMod, err = findComposeModuleS(ctx, s, n.relNS.ID, makeGenericFilter(n.res.ModRef.Identifiers))
@@ -58,6 +63,17 @@ func (n *composeRecordState) Prepare(ctx context.Context, s store.Storer, state
if err != nil {
return err
}
// Check if empty
rr, _, err := store.SearchComposeRecords(ctx, s, n.relMod, types.RecordFilter{
ModuleID: n.relMod.ID,
NamespaceID: n.relNS.ID,
Paging: filter.Paging{Limit: 1},
})
if err != nil && err != store.ErrNotFound {
return err
}
n.modEmpty = len(rr) == 0
}
}
@@ -129,6 +145,30 @@ func (n *composeRecordState) Encode(ctx context.Context, s store.Storer, state *
im := n.res.IDMap
return n.res.Walker(func(r *resource.ComposeRecordRaw) error {
// So we don't have to worry about nil
cfg := r.Config
if cfg == nil {
cfg = &resource.EnvoyConfig{}
}
if cfg.SkipIf != "" {
evl, err := exprP.NewEvaluable(cfg.SkipIf)
if err != nil {
return err
}
// @todo expand this
skip, err := evl.EvalBool(ctx, map[string]interface{}{
"empty": n.modEmpty,
})
if err != nil {
return err
}
if skip {
return nil
}
}
// Simple wrapper to do some post-processing steps
dfr := func(err error) error {
if n.cfg.Defer != nil {
+3
View File
@@ -5,6 +5,7 @@ import (
"strconv"
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
"github.com/cortezaproject/corteza-server/pkg/expr"
"github.com/cortezaproject/corteza-server/pkg/handle"
"github.com/cortezaproject/corteza-server/pkg/id"
)
@@ -26,6 +27,8 @@ var (
NextID = func() uint64 {
return id.Next()
}
exprP = expr.Parser()
)
// makeGenericFilter is a helper to determine the base resource filter.
+8 -1
View File
@@ -13,6 +13,8 @@ type (
values map[string]string
sysValues map[string]string
eCfg *resource.EnvoyConfig
refModule string
refNamespace string
// createdBy, updatedBy, deletedBy, ownedBy
@@ -95,7 +97,8 @@ func (wset composeRecordSet) MarshalEnvoy() ([]resource.Interface, error) {
r := &resource.ComposeRecordRaw{
// @todo change this probably
ID: res.values["id"],
ID: res.values["id"],
Config: res.eCfg,
}
r.ApplyValues(res.values)
r.ApplyValues(res.sysValues)
@@ -153,6 +156,10 @@ func (wrap *composeRecord) UnmarshalYAML(n *yaml.Node) (err error) {
// return
//}
if wrap.eCfg, err = decodeEnvoyConfig(n); err != nil {
return
}
return eachMap(n, func(k, v *yaml.Node) error {
switch k.Value {
case "module":
+31
View File
@@ -0,0 +1,31 @@
package yaml
import (
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
"gopkg.in/yaml.v3"
)
func decodeEnvoyConfig(n *yaml.Node) (*resource.EnvoyConfig, error) {
ec := &resource.EnvoyConfig{}
var ecNode *yaml.Node
for i, k := range n.Content {
if k.Value == "(envoy)" {
ecNode = n.Content[i+1]
break
}
}
if ecNode == nil {
return nil, nil
}
return ec, eachMap(ecNode, func(k, v *yaml.Node) (err error) {
switch k.Value {
case "skipIf", "skip":
return decodeScalar(v, "decode skip if", &ec.SkipIf)
}
return nil
})
}
+32
View File
@@ -2,6 +2,7 @@ package envoy
import (
"context"
"fmt"
"os"
"path"
@@ -127,6 +128,37 @@ func storeModuleField(ctx context.Context, s store.Storer, modID, fieldID uint64
return store.CreateComposeModuleField(ctx, s, f)
}
func storeRecord(ctx context.Context, s store.Storer, nsID, moduleID, recordID uint64, vv ...string) error {
r := &types.Record{
ID: recordID,
ModuleID: moduleID,
NamespaceID: nsID,
Values: make(types.RecordValueSet, 0, len(vv)),
}
mod := &types.Module{
ID: moduleID,
NamespaceID: nsID,
Fields: make(types.ModuleFieldSet, 0, len(vv)),
}
for i, v := range vv {
r.Values = append(r.Values, &types.RecordValue{
RecordID: recordID,
Name: fmt.Sprintf("f%d", i+1),
Value: v,
})
mod.Fields = append(mod.Fields, &types.ModuleField{
ModuleID: moduleID,
Kind: "String",
Name: fmt.Sprintf("f%d", i+1),
})
}
return store.CreateComposeRecord(ctx, s, mod, r)
}
func storeRole(ctx context.Context, s store.Storer, rID uint64, ss ...string) error {
r := &stypes.Role{
ID: rID,
+47
View File
@@ -513,6 +513,53 @@ func TestSimpleCases(t *testing.T) {
req.Equal("v1", v.Value)
},
},
{
name: "simple records; conditional",
suite: "simple",
file: "records_conditional",
pre: func() (err error) {
return ce(
s.TruncateComposeRecords(ctx, nil),
s.TruncateComposeModuleFields(ctx),
s.TruncateComposeModules(ctx),
s.TruncateComposeNamespaces(ctx),
storeNamespace(ctx, s, 100, "ns1"),
storeModule(ctx, s, 100, 200, "mod1"),
storeModuleField(ctx, s, 200, 300, "f1"),
storeRecord(ctx, s, 100, 200, 400, "existing value"),
storeModule(ctx, s, 100, 201, "mod2"),
storeModuleField(ctx, s, 201, 301, "f1"),
)
},
post: func(req *require.Assertions, err error) {
req.NoError(err)
},
check: func(req *require.Assertions) {
mod1, err := store.LookupComposeModuleByID(ctx, s, 200)
req.NoError(err)
req.NotNil(mod1)
mod2, err := store.LookupComposeModuleByID(ctx, s, 201)
req.NoError(err)
req.NotNil(mod2)
rr1, _, err := store.SearchComposeRecords(ctx, s, mod1, types.RecordFilter{ModuleID: mod1.ID, NamespaceID: mod1.NamespaceID})
req.NoError(err)
req.NotNil(rr1)
req.Len(rr1, 1)
req.Equal("existing value", rr1[0].Values.FilterByName("f1")[0].Value)
rr2, _, err := store.SearchComposeRecords(ctx, s, mod2, types.RecordFilter{ModuleID: mod2.ID, NamespaceID: mod2.NamespaceID})
req.NoError(err)
req.NotNil(rr2)
req.Len(rr2, 1)
req.Equal("f1 value", rr2[0].Values.FilterByName("f1")[0].Value)
},
},
}
for _, c := range cases {
+13
View File
@@ -0,0 +1,13 @@
namespace: ns1
records:
mod1:
- (envoy):
skipIf: "!empty"
values:
f1: f1 value
mod2:
- (envoy):
skipIf: "!empty"
values:
f1: f1 value