Expand envoy configuration options
Better `skipIf` & `onExisting` support.
This commit is contained in:
@@ -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++
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user