Add conditional envoy processing for compose records
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -21,6 +21,8 @@ type (
|
||||
Values map[string]string
|
||||
SysValues *rawSysValues
|
||||
RefUsers map[string]string
|
||||
|
||||
Config *EnvoyConfig
|
||||
}
|
||||
ComposeRecordRawSet []*ComposeRecordRaw
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace: ns1
|
||||
records:
|
||||
mod1:
|
||||
- (envoy):
|
||||
skipIf: "!empty"
|
||||
values:
|
||||
f1: f1 value
|
||||
|
||||
mod2:
|
||||
- (envoy):
|
||||
skipIf: "!empty"
|
||||
values:
|
||||
f1: f1 value
|
||||
Reference in New Issue
Block a user