Expand envoy configuration options

Better `skipIf` & `onExisting` support.
This commit is contained in:
Tomaž Jerman
2020-12-10 18:54:31 +01:00
parent 238ad3411c
commit cb5793d468
31 changed files with 384 additions and 106 deletions
+1 -1
View File
@@ -343,7 +343,7 @@ func (svc record) Import(ses *recordImportSession) (err error) {
// Build
cfg := &estore.EncoderConfig{
// For now the identifier is ignored, so this will never occur
OnExisting: estore.Skip,
OnExisting: resource.Skip,
Defer: func() {
ses.Progress.Completed++
},
+25 -1
View File
@@ -8,12 +8,14 @@ type (
ts *Timestamps
us *Userstamps
cfg *EnvoyConfig
urefs RefSet
}
EnvoyConfig struct {
// SkipIf determines when the encoding should be skipped for this resource
SkipIf string
SkipIf string
OnExisting MergeAlg
}
Timestamps struct {
@@ -29,6 +31,21 @@ type (
DeletedBy string
OwnedBy string
}
MergeAlg int
)
const (
// Default takes the operation defined default
Default MergeAlg = iota
// Skip skips the existing resource
Skip
// Replace replaces the existing resource
Replace
// MergeLeft updates the existing resource, giving priority to the existing data
MergeLeft
// MergeRight updates the existing resource, giving priority to the new data
MergeRight
)
// State management methods
@@ -85,6 +102,13 @@ func (t *base) Userstamps() *Userstamps {
return t.us
}
func (t *base) SetConfig(cfg *EnvoyConfig) {
t.cfg = cfg
}
func (t *base) Config() *EnvoyConfig {
return t.cfg
}
func (t *base) SetUserRefs(uu []string) {
if t.urefs == nil {
t.urefs = make(RefSet, 0, 4)
+12 -4
View File
@@ -21,7 +21,7 @@ type (
func NewApplicationState(res *resource.Application, cfg *EncoderConfig) resourceState {
return &applicationState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res,
}
}
@@ -82,6 +82,14 @@ func (n *applicationState) Encode(ctx context.Context, s store.Storer, state *en
}
}
// Evaluate the resource skip expression
// @todo expand available parameters; similar implementation to compose/types/record@Dict
if skip, err := basicSkipEval(ctx, n.cfg, !exists); err != nil {
return err
} else if skip {
return nil
}
// Create fresh application
if !exists {
return store.CreateApplication(ctx, s, res)
@@ -89,13 +97,13 @@ func (n *applicationState) Encode(ctx context.Context, s store.Storer, state *en
// Update existing application
switch n.cfg.OnExisting {
case Skip:
case resource.Skip:
return nil
case MergeLeft:
case resource.MergeLeft:
res = mergeApplications(n.app, res)
case MergeRight:
case resource.MergeRight:
res = mergeApplications(res, n.app)
}
+13 -4
View File
@@ -25,7 +25,7 @@ type (
func NewComposeChartState(res *resource.ComposeChart, cfg *EncoderConfig) resourceState {
return &composeChartState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res,
}
@@ -66,6 +66,7 @@ func (n *composeChartState) Prepare(ctx context.Context, s store.Storer, state *
if n.chr != nil {
n.res.Res.ID = n.chr.ID
n.res.Res.NamespaceID = n.chr.NamespaceID
}
return nil
}
@@ -127,6 +128,14 @@ func (n *composeChartState) Encode(ctx context.Context, s store.Storer, state *e
r.ModuleID = mod.ID
}
// Evaluate the resource skip expression
// @todo expand available parameters; similar implementation to compose/types/record@Dict
if skip, err := basicSkipEval(ctx, n.cfg, !exists); err != nil {
return err
} else if skip {
return nil
}
// Create fresh chart
if !exists {
return store.CreateComposeChart(ctx, s, res)
@@ -134,13 +143,13 @@ func (n *composeChartState) Encode(ctx context.Context, s store.Storer, state *e
// Update existing chart
switch n.cfg.OnExisting {
case Skip:
case resource.Skip:
return nil
case MergeLeft:
case resource.MergeLeft:
res = mergeComposeChart(n.chr, res)
case MergeRight:
case resource.MergeRight:
res = mergeComposeChart(res, n.chr)
}
+13 -4
View File
@@ -26,7 +26,7 @@ type (
func NewComposeModuleState(res *resource.ComposeModule, cfg *EncoderConfig) resourceState {
return &composeModuleState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res,
@@ -95,6 +95,7 @@ func (n *composeModuleState) Prepare(ctx context.Context, s store.Storer, state
if n.mod != nil {
n.res.Res.ID = n.mod.ID
n.res.Res.NamespaceID = n.mod.NamespaceID
}
return nil
}
@@ -177,6 +178,14 @@ func (n *composeModuleState) Encode(ctx context.Context, s store.Storer, state *
}
}
// Evaluate the resource skip expression
// @todo expand available parameters; similar implementation to compose/types/record@Dict
if skip, err := basicSkipEval(ctx, n.cfg, !exists); err != nil {
return err
} else if skip {
return nil
}
// Create a fresh module
if !exists {
err = store.CreateComposeModule(ctx, s, res)
@@ -194,14 +203,14 @@ func (n *composeModuleState) Encode(ctx context.Context, s store.Storer, state *
// Update existing module
switch n.cfg.OnExisting {
case Skip:
case resource.Skip:
return nil
case MergeLeft:
case resource.MergeLeft:
res = mergeComposeModule(n.mod, res)
res.Fields = mergeComposeModuleFields(n.mod.Fields, res.Fields)
case MergeRight:
case resource.MergeRight:
res = mergeComposeModule(res, n.mod)
res.Fields = mergeComposeModuleFields(res.Fields, n.mod.Fields)
}
+12 -4
View File
@@ -22,7 +22,7 @@ type (
func NewComposeNamespaceState(res *resource.ComposeNamespace, cfg *EncoderConfig) resourceState {
return &composeNamespaceState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res,
}
@@ -80,6 +80,14 @@ func (n *composeNamespaceState) Encode(ctx context.Context, s store.Storer, stat
}
}
// Evaluate the resource skip expression
// @todo expand available parameters; similar implementation to compose/types/record@Dict
if skip, err := basicSkipEval(ctx, n.cfg, !exists); err != nil {
return err
} else if skip {
return nil
}
// Create a fresh namespace
if !exists {
return store.CreateComposeNamespace(ctx, s, res)
@@ -87,13 +95,13 @@ func (n *composeNamespaceState) Encode(ctx context.Context, s store.Storer, stat
// Update existing namespace
switch n.cfg.OnExisting {
case Skip:
case resource.Skip:
return nil
case MergeLeft:
case resource.MergeLeft:
res = mergeComposeNamespaces(n.ns, res)
case MergeRight:
case resource.MergeRight:
res = mergeComposeNamespaces(res, n.ns)
}
+13 -4
View File
@@ -30,7 +30,7 @@ type (
func NewComposePageState(res *resource.ComposePage, cfg *EncoderConfig) resourceState {
return &composePageState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res,
@@ -113,6 +113,7 @@ func (n *composePageState) Prepare(ctx context.Context, s store.Storer, state *e
if n.pg != nil {
n.res.Res.ID = n.pg.ID
n.res.Res.NamespaceID = n.pg.NamespaceID
}
return nil
}
@@ -258,6 +259,14 @@ func (n *composePageState) Encode(ctx context.Context, s store.Storer, state *en
}
}
// Evaluate the resource skip expression
// @todo expand available parameters; similar implementation to compose/types/record@Dict
if skip, err := basicSkipEval(ctx, n.cfg, !exists); err != nil {
return err
} else if skip {
return nil
}
// Create a fresh page
if !exists {
return store.CreateComposePage(ctx, s, res)
@@ -265,13 +274,13 @@ func (n *composePageState) Encode(ctx context.Context, s store.Storer, state *en
// Update existing page
switch n.cfg.OnExisting {
case Skip:
case resource.Skip:
return nil
case MergeLeft:
case resource.MergeLeft:
res = mergeComposePage(n.pg, res)
case MergeRight:
case resource.MergeRight:
res = mergeComposePage(res, n.pg)
}
+11 -11
View File
@@ -64,17 +64,6 @@ 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.missing = len(rr) == 0
}
}
@@ -105,6 +94,17 @@ func (n *composeRecordState) Prepare(ctx context.Context, s store.Storer, state
return nil
}
// 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.missing = len(rr) == 0
// Try to get existing records
//
// @todo handle large amounts of
+5 -15
View File
@@ -11,17 +11,6 @@ import (
"github.com/cortezaproject/corteza-server/store"
)
const (
// Skip skips the existing resource
Skip mergeAlg = iota
// Replace replaces the existing resource
Replace
// MergeLeft updates the existing resource, giving priority to the existing data
MergeLeft
// MergeRight updates the existing resource, giving priority to the new data
MergeRight
)
type (
storeEncoder struct {
s store.Storer
@@ -33,11 +22,12 @@ type (
state map[resource.Interface]resourceState
}
mergeAlg int
// EncoderConfig allows us to configure the resource encoding process
EncoderConfig struct {
OnExisting mergeAlg
// OnExisting defines what to do if the resource exists
OnExisting resource.MergeAlg
// Skip if defines a pkg/expr expression when to skip the resource
SkipIf string
// Defer is called after the resource is encoded, regardles of the result
Defer func()
// DeferOk is called after the resource is encoded, only when successful
@@ -67,7 +57,7 @@ var (
func NewStoreEncoder(s store.Storer, cfg *EncoderConfig) envoy.PrepareEncoder {
if cfg == nil {
cfg = &EncoderConfig{
OnExisting: Skip,
OnExisting: resource.Skip,
}
}
+12 -4
View File
@@ -24,7 +24,7 @@ type (
func NewMessagingChannelState(res *resource.MessagingChannel, cfg *EncoderConfig) resourceState {
return &messagingChannelState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res,
}
}
@@ -108,6 +108,14 @@ func (n *messagingChannelState) Encode(ctx context.Context, s store.Storer, stat
}
}
// Evaluate the resource skip expression
// @todo expand available parameters; similar implementation to compose/types/record@Dict
if skip, err := basicSkipEval(ctx, n.cfg, !exists); err != nil {
return err
} else if skip {
return nil
}
// Create fresh messagingChannel
if !exists {
return store.CreateMessagingChannel(ctx, s, res)
@@ -115,13 +123,13 @@ func (n *messagingChannelState) Encode(ctx context.Context, s store.Storer, stat
// Update existing messagingChannel
switch n.cfg.OnExisting {
case Skip:
case resource.Skip:
return nil
case MergeLeft:
case resource.MergeLeft:
res = mergeMessagingChannels(n.ch, res)
case MergeRight:
case resource.MergeRight:
res = mergeMessagingChannels(res, n.ch)
}
+3 -3
View File
@@ -30,7 +30,7 @@ var (
func NewRbacRuleState(res *resource.RbacRule, cfg *EncoderConfig) resourceState {
return &rbacRuleState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res,
}
@@ -97,8 +97,8 @@ func (n *rbacRuleState) Encode(ctx context.Context, s store.Storer, state *envoy
// There isn't anything to merge really, so Skip & MergeLeft skip it;
// Replace & MergeRight replace it.
switch n.cfg.OnExisting {
case Skip,
MergeLeft:
case resource.Skip,
resource.MergeLeft:
return nil
}
+12 -4
View File
@@ -22,7 +22,7 @@ type (
func NewRole(res *resource.Role, cfg *EncoderConfig) resourceState {
return &roleState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res,
}
@@ -82,6 +82,14 @@ func (n *roleState) Encode(ctx context.Context, s store.Storer, state *envoy.Res
}
}
// Evaluate the resource skip expression
// @todo expand available parameters; similar implementation to compose/types/record@Dict
if skip, err := basicSkipEval(ctx, n.cfg, !exists); err != nil {
return err
} else if skip {
return nil
}
// Create a fresh role
if !exists {
return store.CreateRole(ctx, s, rl)
@@ -89,13 +97,13 @@ func (n *roleState) Encode(ctx context.Context, s store.Storer, state *envoy.Res
// Update existing roles
switch n.cfg.OnExisting {
case Skip:
case resource.Skip:
return nil
case MergeLeft:
case resource.MergeLeft:
rl = mergeRole(n.rl, rl)
case MergeRight:
case resource.MergeRight:
rl = mergeRole(rl, n.rl)
}
+5 -5
View File
@@ -26,7 +26,7 @@ var (
func NewSettingsState(res *resource.Settings, cfg *EncoderConfig) resourceState {
return &settingsState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res.Res,
}
@@ -68,12 +68,12 @@ func (n *settingsState) Encode(ctx context.Context, s store.Storer, state *envoy
if os != nil {
// Update existing setting
switch n.cfg.OnExisting {
case Skip,
MergeLeft:
case resource.Skip,
resource.MergeLeft:
ss = append(ss, os)
case Replace,
MergeRight:
case resource.Replace,
resource.MergeRight:
ss = append(ss, ns)
}
} else {
+12 -4
View File
@@ -22,7 +22,7 @@ type (
func NewUserState(res *resource.User, cfg *EncoderConfig) resourceState {
return &userState{
cfg: cfg,
cfg: mergeConfig(cfg, res.Config()),
res: res,
}
@@ -84,6 +84,14 @@ func (n *userState) Encode(ctx context.Context, s store.Storer, state *envoy.Res
}
}
// Evaluate the resource skip expression
// @todo expand available parameters; similar implementation to compose/types/record@Dict
if skip, err := basicSkipEval(ctx, n.cfg, !exists); err != nil {
return err
} else if skip {
return nil
}
// Create a fresh user
if !exists {
return store.CreateUser(ctx, s, res)
@@ -91,13 +99,13 @@ func (n *userState) Encode(ctx context.Context, s store.Storer, state *envoy.Res
// Update existing user
switch n.cfg.OnExisting {
case Skip:
case resource.Skip:
return nil
case MergeLeft:
case resource.MergeLeft:
res = mergeUsers(n.u, res)
case MergeRight:
case resource.MergeRight:
res = mergeUsers(res, n.u)
}
+51
View File
@@ -105,3 +105,54 @@ func resolveUserRefs(ctx context.Context, s store.Storer, pr []resource.Interfac
}
return nil
}
func mergeConfig(ec *EncoderConfig, rs *resource.EnvoyConfig) *EncoderConfig {
// Nothing we can do
if rs == nil {
return ec
}
// Take resource config as base
rr := &EncoderConfig{
OnExisting: rs.OnExisting,
SkipIf: rs.SkipIf,
}
// Default to store config
rr.Defer = ec.Defer
rr.DeferNok = ec.DeferNok
rr.DeferOk = ec.DeferOk
if rr.OnExisting == resource.Default {
rr.OnExisting = ec.OnExisting
}
if rr.SkipIf == "" {
rr.SkipIf = ec.SkipIf
}
return rr
}
func basicSkipEval(ctx context.Context, cfg *EncoderConfig, missing bool) (bool, error) {
if cfg == nil {
cfg = &EncoderConfig{}
}
if cfg.SkipIf != "" {
evl, err := exprP.NewEvaluable(cfg.SkipIf)
if err != nil {
return false, err
}
// @todo expand this
skip, err := evl.EvalBool(ctx, map[string]interface{}{
"missing": missing,
})
if err != nil {
return false, err
}
return skip, nil
}
// Don't skip by default
return false, nil
}
+8 -2
View File
@@ -10,8 +10,9 @@ import (
type (
application struct {
// when application is at least partially defined
res *types.Application `yaml:",inline"`
ts *resource.Timestamps
res *types.Application `yaml:",inline"`
ts *resource.Timestamps
config *resource.EnvoyConfig
// module's RBAC rules
rbac rbacRuleSet
@@ -78,6 +79,10 @@ func (wrap *application) UnmarshalYAML(n *yaml.Node) (err error) {
if wrap.res == nil {
wrap.res = &types.Application{}
}
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
if wrap.ts, err = decodeTimestamps(n); err != nil {
return
}
@@ -96,6 +101,7 @@ func (wrap *application) UnmarshalYAML(n *yaml.Node) (err error) {
func (wrap application) MarshalEnvoy() ([]resource.Interface, error) {
rs := resource.NewApplication(wrap.res)
rs.SetTimestamps(wrap.ts)
rs.SetConfig(wrap.config)
return envoy.CollectNodes(
rs,
+9 -2
View File
@@ -11,8 +11,10 @@ import (
type (
composeChart struct {
res *types.Chart
ts *resource.Timestamps
res *types.Chart
ts *resource.Timestamps
config *resource.EnvoyConfig
refNamespace string
// pointer to report and module reference
@@ -98,6 +100,10 @@ func (wrap *composeChart) UnmarshalYAML(n *yaml.Node) (err error) {
return
}
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
if wrap.ts, err = decodeTimestamps(n); err != nil {
return
}
@@ -135,6 +141,7 @@ func (wrap composeChart) MarshalEnvoy() ([]resource.Interface, error) {
}
rs := resource.NewComposeChart(wrap.res, wrap.refNamespace, vv)
rs.SetTimestamps(wrap.ts)
rs.SetConfig(wrap.config)
return envoy.CollectNodes(
rs,
wrap.rbac.bindResource(rs),
+9 -2
View File
@@ -24,8 +24,10 @@ type (
}
composeModule struct {
res *types.Module
ts *resource.Timestamps
res *types.Module
ts *resource.Timestamps
config *resource.EnvoyConfig
refNamespace string
rbac rbacRuleSet
@@ -108,6 +110,10 @@ func (wrap *composeModule) UnmarshalYAML(n *yaml.Node) (err error) {
return
}
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
if wrap.ts, err = decodeTimestamps(n); err != nil {
return
}
@@ -152,6 +158,7 @@ func (wrap *composeModule) UnmarshalYAML(n *yaml.Node) (err error) {
func (wrap composeModule) MarshalEnvoy() ([]resource.Interface, error) {
rs := resource.NewComposeModule(wrap.res, wrap.refNamespace)
rs.SetTimestamps(wrap.ts)
rs.SetConfig(wrap.config)
var crs *resource.ComposeRecordTemplate
if wrap.recTpl != nil {
+8 -2
View File
@@ -11,8 +11,9 @@ import (
type (
composeNamespace struct {
// when namespace is at least partially defined
res *types.Namespace `yaml:",inline"`
ts *resource.Timestamps
res *types.Namespace `yaml:",inline"`
ts *resource.Timestamps
config *resource.EnvoyConfig
// all known modules on a namespace
modules composeModuleSet
@@ -104,6 +105,10 @@ func (wrap *composeNamespace) UnmarshalYAML(n *yaml.Node) (err error) {
return
}
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
if wrap.ts, err = decodeTimestamps(n); err != nil {
return
}
@@ -131,6 +136,7 @@ func (wrap *composeNamespace) UnmarshalYAML(n *yaml.Node) (err error) {
func (wrap composeNamespace) MarshalEnvoy() ([]resource.Interface, error) {
nsr := resource.NewComposeNamespace(wrap.res)
nsr.SetTimestamps(wrap.ts)
nsr.SetConfig(wrap.config)
return envoy.CollectNodes(
nsr,
+9 -5
View File
@@ -11,8 +11,10 @@ import (
type (
composePage struct {
res *types.Page
ts *resource.Timestamps
res *types.Page
ts *resource.Timestamps
config *resource.EnvoyConfig
children composePageSet
refNamespace string
@@ -110,6 +112,10 @@ func (wrap *composePage) UnmarshalYAML(n *yaml.Node) (err error) {
return
}
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
if wrap.ts, err = decodeTimestamps(n); err != nil {
return
}
@@ -155,14 +161,12 @@ func (wrap *composePage) UnmarshalYAML(n *yaml.Node) (err error) {
func (wrap composePage) MarshalEnvoy() ([]resource.Interface, error) {
rs := resource.NewComposePage(wrap.res, wrap.refNamespace, wrap.refModule, wrap.refParent)
rs.SetTimestamps(wrap.ts)
rs.SetConfig(wrap.config)
return envoy.CollectNodes(
rs,
wrap.children.bindParent(rs),
wrap.rbac.bindResource(rs),
// @todo Not sure yet
// wrap.children,
)
}
+3 -4
View File
@@ -13,8 +13,7 @@ type (
values map[string]string
ts *resource.Timestamps
us *resource.Userstamps
eCfg *resource.EnvoyConfig
config *resource.EnvoyConfig
refModule string
refNamespace string
@@ -99,7 +98,7 @@ func (wset composeRecordSet) MarshalEnvoy() ([]resource.Interface, error) {
r := &resource.ComposeRecordRaw{
// @todo change this probably
ID: res.values["id"],
Config: res.eCfg,
Config: res.config,
Values: res.values,
Ts: res.ts,
Us: res.us,
@@ -160,7 +159,7 @@ func (wrap *composeRecord) UnmarshalYAML(n *yaml.Node) (err error) {
// return
//}
if wrap.eCfg, err = decodeEnvoyConfig(n); err != nil {
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
+9 -3
View File
@@ -10,9 +10,10 @@ import (
type (
messagingChannel struct {
// when messagingChannel is at least partially defined
res *types.Channel `yaml:",inline"`
ts *resource.Timestamps
us *resource.Userstamps
res *types.Channel `yaml:",inline"`
ts *resource.Timestamps
us *resource.Userstamps
config *resource.EnvoyConfig
// module's RBAC rules
rbac rbacRuleSet
@@ -78,6 +79,10 @@ func (wrap *messagingChannel) UnmarshalYAML(n *yaml.Node) (err error) {
return
}
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
if wrap.ts, err = decodeTimestamps(n); err != nil {
return
}
@@ -92,6 +97,7 @@ func (wrap messagingChannel) MarshalEnvoy() ([]resource.Interface, error) {
rs := resource.NewMessagingChannel(wrap.res)
rs.SetTimestamps(wrap.ts)
rs.SetUserstamps(wrap.us)
rs.SetConfig(wrap.config)
return envoy.CollectNodes(
rs,
wrap.rbac.bindResource(rs),
+35
View File
@@ -1,6 +1,8 @@
package yaml
import (
"strings"
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
"gopkg.in/yaml.v3"
)
@@ -24,8 +26,41 @@ func decodeEnvoyConfig(n *yaml.Node) (*resource.EnvoyConfig, error) {
switch k.Value {
case "skipIf", "skip":
return decodeScalar(v, "decode skip if", &ec.SkipIf)
case "onExisting", "mergeAlg":
return decodeMergeAlg(v, "decode merge alg", &ec.OnExisting)
}
return nil
})
}
func decodeMergeAlg(n *yaml.Node, refType string, val *resource.MergeAlg) error {
if n == nil {
return nil
}
if !isKind(n, yaml.ScalarNode) {
return nodeErr(n, "%s reference must be scalar", refType)
}
switch strings.ToLower(n.Value) {
case "skip",
"s":
*val = resource.Skip
case "replace",
"r":
*val = resource.Replace
case "mergeleft",
"left",
"ml":
*val = resource.MergeLeft
case "mergeright",
"right",
"mr":
*val = resource.MergeRight
default:
return nodeErr(n, "%s unknown algorithm", refType)
}
return nil
}
+8 -2
View File
@@ -10,8 +10,9 @@ import (
type (
role struct {
// when role is at least partially defined
res *types.Role
ts *resource.Timestamps
res *types.Role
ts *resource.Timestamps
config *resource.EnvoyConfig
// all known modules on a role
modules composeModuleSet
@@ -94,6 +95,10 @@ func (wrap *role) UnmarshalYAML(n *yaml.Node) (err error) {
return
}
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
if wrap.ts, err = decodeTimestamps(n); err != nil {
return
}
@@ -104,6 +109,7 @@ func (wrap *role) UnmarshalYAML(n *yaml.Node) (err error) {
func (wrap role) MarshalEnvoy() ([]resource.Interface, error) {
rs := resource.NewRole(wrap.res)
rs.SetTimestamps(wrap.ts)
rs.SetConfig(wrap.config)
return envoy.CollectNodes(
rs,
+10 -3
View File
@@ -7,9 +7,11 @@ import (
type (
settings struct {
res map[string]interface{}
ts *resource.Timestamps
us *resource.Userstamps
res map[string]interface{}
ts *resource.Timestamps
config *resource.EnvoyConfig
us *resource.Userstamps
}
)
@@ -26,6 +28,10 @@ func (wrap *settings) UnmarshalYAML(n *yaml.Node) (err error) {
return
}
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
if wrap.ts, err = decodeTimestamps(n); err != nil {
return
}
@@ -39,6 +45,7 @@ func (wrap settings) MarshalEnvoy() (nn []resource.Interface, err error) {
n := resource.NewSettings(wrap.res)
n.SetTimestamps(wrap.ts)
n.SetUserstamps(wrap.us)
n.SetConfig(wrap.config)
return []resource.Interface{n}, nil
}
+8 -2
View File
@@ -10,8 +10,9 @@ import (
type (
user struct {
// when user is at least partially defined
res *types.User `yaml:",inline"`
ts *resource.Timestamps
res *types.User `yaml:",inline"`
ts *resource.Timestamps
config *resource.EnvoyConfig
// module's RBAC rules
rbac rbacRuleSet
@@ -95,6 +96,10 @@ func (wrap *user) UnmarshalYAML(n *yaml.Node) (err error) {
return
}
if wrap.config, err = decodeEnvoyConfig(n); err != nil {
return
}
if wrap.ts, err = decodeTimestamps(n); err != nil {
return
}
@@ -105,6 +110,7 @@ func (wrap *user) UnmarshalYAML(n *yaml.Node) (err error) {
func (wrap user) MarshalEnvoy() ([]resource.Interface, error) {
rs := resource.NewUser(wrap.res)
rs.SetTimestamps(wrap.ts)
rs.SetConfig(wrap.config)
return envoy.CollectNodes(
rs,
+4 -3
View File
@@ -2,6 +2,9 @@ package provision
import (
"context"
"path/filepath"
"strings"
"github.com/cortezaproject/corteza-server/pkg/envoy"
"github.com/cortezaproject/corteza-server/pkg/envoy/directory"
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
@@ -9,8 +12,6 @@ import (
"github.com/cortezaproject/corteza-server/pkg/envoy/yaml"
"github.com/cortezaproject/corteza-server/store"
"go.uber.org/zap"
"path/filepath"
"strings"
)
// imports configuration files from path(s)
@@ -20,7 +21,7 @@ func importConfig(ctx context.Context, log *zap.Logger, s store.Storer, paths st
var (
yd = yaml.Decoder()
nn = make([]resource.Interface, 0, 200)
se = es.NewStoreEncoder(s, &es.EncoderConfig{OnExisting: es.Skip})
se = es.NewStoreEncoder(s, &es.EncoderConfig{OnExisting: resource.MergeLeft})
bld = envoy.NewBuilder(se)
sources = make([]string, 0, 16)
+4 -4
View File
@@ -55,17 +55,17 @@ func Import(storeInit func(ctx context.Context) (store.Storer, error)) *cobra.Co
}
opt := &es.EncoderConfig{
OnExisting: es.Skip,
OnExisting: resource.Skip,
}
if replaceOnExisting {
opt.OnExisting = es.Replace
opt.OnExisting = resource.Replace
}
if mergeLeftOnExisting {
opt.OnExisting = es.MergeLeft
opt.OnExisting = resource.MergeLeft
}
if mergeRightOnExisting {
opt.OnExisting = es.MergeRight
opt.OnExisting = resource.MergeRight
}
se := es.NewStoreEncoder(s, opt)
+5 -4
View File
@@ -4,6 +4,7 @@ import (
"context"
"testing"
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
su "github.com/cortezaproject/corteza-server/pkg/envoy/store"
"github.com/cortezaproject/corteza-server/store"
"github.com/stretchr/testify/require"
@@ -65,22 +66,22 @@ func TestProvision_overwriting(t *testing.T) {
req.NoError(err)
store.TruncateComposeRecords(ctx, s, nil)
req, err = prepare(ctx, s, t, "provision_batch/app_1", &su.EncoderConfig{OnExisting: su.Replace})
req, err = prepare(ctx, s, t, "provision_batch/app_1", &su.EncoderConfig{OnExisting: resource.Replace})
req.NoError(err)
checkBatchProvision(ctx, t, req, s, "ns1")
store.TruncateComposeRecords(ctx, s, nil)
req, err = prepare(ctx, s, t, "provision_batch/app_1", &su.EncoderConfig{OnExisting: su.Skip})
req, err = prepare(ctx, s, t, "provision_batch/app_1", &su.EncoderConfig{OnExisting: resource.Skip})
req.NoError(err)
checkBatchProvision(ctx, t, req, s, "ns1")
store.TruncateComposeRecords(ctx, s, nil)
req, err = prepare(ctx, s, t, "provision_batch/app_1", &su.EncoderConfig{OnExisting: su.MergeLeft})
req, err = prepare(ctx, s, t, "provision_batch/app_1", &su.EncoderConfig{OnExisting: resource.MergeLeft})
req.NoError(err)
checkBatchProvision(ctx, t, req, s, "ns1")
store.TruncateComposeRecords(ctx, s, nil)
req, err = prepare(ctx, s, t, "provision_batch/app_1", &su.EncoderConfig{OnExisting: su.MergeRight})
req, err = prepare(ctx, s, t, "provision_batch/app_1", &su.EncoderConfig{OnExisting: resource.MergeRight})
req.NoError(err)
checkBatchProvision(ctx, t, req, s, "ns1")
store.TruncateComposeRecords(ctx, s, nil)
+38
View File
@@ -113,6 +113,44 @@ func TestSimpleCases(t *testing.T) {
},
},
{
name: "simple mods; conditional",
suite: "simple",
file: "modules_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", "mod1 name"),
storeModuleField(ctx, s, 200, 300, "f1"),
storeModule(ctx, s, 100, 201, "mod2", "mod2 name"),
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)
// The first one overwrites merge alg to replace, the second one defaults to skip
req.Equal("mod1 name (EDITED)", mod1.Name)
req.Equal("mod2 name", mod2.Name)
},
},
{
name: "simple charts; no ns",
suite: "simple",
+17
View File
@@ -0,0 +1,17 @@
namespace: ns1
modules:
mod1:
(envoy): { onExisting: "replace" }
name: mod1 name (EDITED)
fields:
f1:
label: f1 label
kind: String
required: true
mod2:
name: mod2 name (EDITED)
fields:
f1:
label: f1 label
kind: String
required: true