Rework envoy node marshaling

This commit is contained in:
Denis Arh
2020-11-27 11:19:15 +01:00
committed by Tomaž Jerman
parent 4893f4ccd8
commit 70a61597bc
16 changed files with 482 additions and 227 deletions
+19 -21
View File
@@ -9,26 +9,27 @@ import (
type (
// ComposeModuleNode represents a ComposeModule
ComposeModuleNode struct {
Mod *types.Module
Module *types.Module
// Related namespace
Ns *types.Namespace
RefNamespaceSlug string
RefNamespaceID uint64
}
)
func (n *ComposeModuleNode) Identifiers() NodeIdentifiers {
ii := make(NodeIdentifiers, 0)
if n.Mod.Handle != "" {
ii = ii.Add(n.Mod.Handle)
if n.Module.Handle != "" {
ii = ii.Add(n.Module.Handle)
}
if n.Mod.Name != "" {
ii = ii.Add(n.Mod.Name)
if n.Module.Name != "" {
ii = ii.Add(n.Module.Name)
}
if n.Mod.ID > 0 {
ii = ii.Add(strconv.FormatUint(n.Mod.ID, 10))
if n.Module.ID > 0 {
ii = ii.Add(strconv.FormatUint(n.Module.ID, 10))
}
return ii
@@ -51,19 +52,17 @@ func (n *ComposeModuleNode) Relations() NodeRelationships {
// Related namespace
nsr := types.NamespaceRBACResource.String()
if n.Ns.Slug != "" {
rel.Add(nsr, n.Ns.Slug)
if n.RefNamespaceSlug != "" {
rel.Add(nsr, n.RefNamespaceSlug)
}
if n.Ns.Name != "" {
rel.Add(nsr, n.Ns.Name)
}
if n.Ns.ID > 0 {
rel.Add(nsr, strconv.FormatUint(n.Ns.ID, 10))
if n.RefNamespaceID > 0 {
rel.Add(nsr, strconv.FormatUint(n.RefNamespaceID, 10))
}
// Related modules via Record module fields
mdr := types.ModuleRBACResource.String()
for _, f := range n.Mod.Fields {
for _, f := range n.Module.Fields {
// @todo should a missing module property raise an error?
if f.Kind == "Record" && f.Options.String("module") != "" {
rel.Add(mdr, f.Options.String("module"))
@@ -86,25 +85,24 @@ func (n *ComposeModuleNode) updateNamespace(m Node) {
}
mn := m.(*ComposeNamespaceNode)
n.Ns = mn.Ns
n.Module.NamespaceID = mn.Ns.ID
}
func (n *ComposeModuleNode) updateRecFields(m Node) {
if m.Resource() != types.ModuleRBACResource.String() {
return
}
mn := m.(*ComposeModuleNode)
// Check what record module field we can link this to
for _, f := range n.Mod.Fields {
for _, f := range n.Module.Fields {
if f.Kind != "Record" {
continue
}
if mn.Identifiers().HasAny(f.Options.String("module")) {
f.Options["module"] = strconv.FormatUint(mn.Mod.ID, 10)
f.Options["module"] = strconv.FormatUint(mn.Module.ID, 10)
}
}
n.Ns = mn.Ns
}
+1 -3
View File
@@ -17,9 +17,7 @@ func (n *ComposeNamespaceNode) Identifiers() NodeIdentifiers {
if n.Ns.Slug != "" {
ii = ii.Add(n.Ns.Slug)
}
if n.Ns.Name != "" {
ii = ii.Add(n.Ns.Name)
}
if n.Ns.ID > 0 {
ii = ii.Add(strconv.FormatUint(n.Ns.ID, 10))
}
+27 -27
View File
@@ -11,13 +11,13 @@ type (
ComposeRecordNode struct {
Walk RecordIterator
// Metafields for relationship management
Mod *types.Module
RefModuleHandle string
}
)
func (n *ComposeRecordNode) Identifiers() NodeIdentifiers {
return identifiersForModule(n.Mod)
//return identifiersForModule(n.Mod)
return nil
}
func (n *ComposeRecordNode) Resource() string {
@@ -36,29 +36,29 @@ func (n *ComposeRecordNode) Relations() NodeRelationships {
// This omits the namespace rel. as it's transitively implied via the modules
rel := make(NodeRelationships)
mdr := types.ModuleRBACResource.String()
rrr := "compose:record:"
//mdr := types.ModuleRBACResource.String()
//rrr := "compose:record:"
//
//if n.Mod == nil {
// return rel
//}
if n.Mod == nil {
return rel
}
// Original module
mIdentifiers := identifiersForModule(n.Mod)
rel.Add(mdr, mIdentifiers...)
// Field relationships
for _, f := range n.Mod.Fields {
if f.Kind == "Record" {
modID := f.Options.String("module")
// For the module
rel.Add(mdr, modID)
// For the records.
// Since this record depends on another module, it also depends on those records.
rel.Add(rrr, modID)
}
}
//// Original module
//mIdentifiers := identifiersForModule(n.Mod)
//rel.Add(mdr, mIdentifiers...)
//
//// Field relationships
//for _, f := range n.Mod.Fields {
// if f.Kind == "Record" {
// modID := f.Options.String("module")
// // For the module
// rel.Add(mdr, modID)
//
// // For the records.
// // Since this record depends on another module, it also depends on those records.
// rel.Add(rrr, modID)
// }
//}
return rel
}
@@ -69,8 +69,8 @@ func (n *ComposeRecordNode) Update(mm ...Node) {
case types.ModuleRBACResource.String():
mn, _ := m.(*ComposeModuleNode)
// Direct module dependency
if n.Matches(n.Resource(), identifiersForModule(mn.Mod)...) {
n.Mod = mn.Mod
if n.Matches(n.Resource(), identifiersForModule(mn.Module)...) {
//n.Mod = mn.Module
}
}
}
+33
View File
@@ -0,0 +1,33 @@
package envoy
import "fmt"
type (
Marshaller interface {
MarshalEnvoy() ([]Node, error)
}
)
// MarshalMerge takes one or more nodes and Marshals and merges all nodes
//
//
func Merge(nn []Node, ii ...interface{}) ([]Node, error) {
for _, i := range ii {
switch c := i.(type) {
case Node:
nn = append(nn, c)
case Marshaller:
if tmp, err := c.(Marshaller).MarshalEnvoy(); err != nil {
println(err)
return nil, err
} else {
tmp = append(nn, tmp...)
}
default:
return nil, fmt.Errorf("failed to merge %T; expecting Node or Marshaller interface", i)
}
}
return nn, nil
}
+55 -51
View File
@@ -26,30 +26,28 @@ func NewStoreEncoder(s store.Storer) *StoreEncoder {
}
}
func (se *StoreEncoder) Encode(ctx context.Context, s store.Storer, nn ...envoy.Node) error {
return store.Tx(ctx, se.s, func(ctx context.Context, s store.Storer) error {
func (se *StoreEncoder) Encode(ctx context.Context, nn ...envoy.Node) error {
return store.Tx(ctx, se.s, func(ctx context.Context, s store.Storer) (err error) {
for _, n := range nn {
switch n.Resource() {
case types.NamespaceRBACResource.String():
ns := n.(*envoy.ComposeNamespaceNode)
_, err := se.encodeNamespace(ctx, s, ns)
if err != nil {
return err
if ns.Ns, err = se.encodeNamespace(ctx, s, ns); err != nil {
return
}
case types.ModuleRBACResource.String():
mod := n.(*envoy.ComposeModuleNode)
_, err := se.encodeModule(ctx, s, mod)
if err != nil {
return err
if mod.Module, err = se.encodeModule(ctx, s, mod); err != nil {
return
}
case "compose:record:":
rec := n.(*envoy.ComposeRecordNode)
err := se.encodeRecord(ctx, s, rec)
if err != nil {
return err
}
//case "compose:record:":
// rec := n.(*envoy.ComposeRecordNode)
//
// if err = se.encodeRecord(ctx, s, rec); err != nil {
// return
// }
}
}
@@ -60,6 +58,8 @@ func (se *StoreEncoder) Encode(ctx context.Context, s store.Storer, nn ...envoy.
func (se *StoreEncoder) encodeNamespace(ctx context.Context, s store.Storer, n *envoy.ComposeNamespaceNode) (*types.Namespace, error) {
cns := n.Ns
// @todo this should probably be refactored (together with services)
// so that core logic is handled in one place
cns.ID = nextID()
if cns.CreatedAt.IsZero() {
cns.CreatedAt = time.Now()
@@ -73,11 +73,11 @@ func (se *StoreEncoder) encodeNamespace(ctx context.Context, s store.Storer, n *
}
func (se *StoreEncoder) encodeModule(ctx context.Context, s store.Storer, m *envoy.ComposeModuleNode) (*types.Module, error) {
mod := m.Mod
cns := m.Ns
mod := m.Module
// @todo this should probably be refactored (together with services)
// so that core logic is handled in one place
mod.ID = nextID()
mod.NamespaceID = cns.ID
if mod.CreatedAt.IsZero() {
mod.CreatedAt = time.Now()
@@ -104,40 +104,44 @@ func (se *StoreEncoder) encodeModule(ctx context.Context, s store.Storer, m *env
return mod, nil
}
func (se *StoreEncoder) encodeRecord(ctx context.Context, s store.Storer, m *envoy.ComposeRecordNode) error {
mod := m.Mod
return m.Walk(func(rec *types.Record) error {
rec.ID = nextID()
rec.ModuleID = mod.ID
rec.NamespaceID = mod.NamespaceID
if rec.CreatedAt.IsZero() {
rec.CreatedAt = time.Now()
}
rec.Values = make(types.RecordValueSet, 0, 100)
// Process record values
for _, crv := range rec.Values {
crv.RecordID = rec.ID
rec.Values = append(rec.Values, crv)
}
rec.Values.SetUpdatedFlag(true)
rec.Values = se.setDefaultComposeRecordValues(mod, rec.Values)
rec.Values = rvSanitizer.Run(mod, rec.Values)
err := rvValidator.Run(ctx, s, mod, rec)
if err != nil {
return err
}
if err := store.CreateComposeRecord(ctx, s, m.Mod, rec); err != nil {
return err
}
return nil
})
}
//func (se *StoreEncoder) encodeRecord(ctx context.Context, s store.Storer, m *envoy.ComposeRecordNode) error {
// mod := m.Mod
//
// // @todo a bit less ad-hoc-ish solution
// return m.Walk(func(rec *types.Record) error {
// // @todo this should probably be refactored (together with services)
// // so that core logic is handled in one place
//
// rec.ID = nextID()
// rec.ModuleID = mod.ID
// rec.NamespaceID = mod.NamespaceID
//
// if rec.CreatedAt.IsZero() {
// rec.CreatedAt = time.Now()
// }
//
// rec.Values = make(types.RecordValueSet, 0, 100)
//
// // Process record values
// for _, crv := range rec.Values {
// crv.RecordID = rec.ID
// rec.Values = append(rec.Values, crv)
// }
// rec.Values.SetUpdatedFlag(true)
// rec.Values = se.setDefaultComposeRecordValues(mod, rec.Values)
// rec.Values = rvSanitizer.Run(mod, rec.Values)
// err := rvValidator.Run(ctx, s, mod, rec)
// if err != nil {
// return err
// }
//
// if err := store.CreateComposeRecord(ctx, s, m.Mod, rec); err != nil {
// return err
// }
//
// return nil
// })
//}
// @note this method is coppied over from the compose/service/record.
// Would it be better to unify the two methods?
+61 -5
View File
@@ -1,6 +1,7 @@
package yaml
import (
"github.com/cortezaproject/corteza-server/pkg/envoy"
"gopkg.in/yaml.v3"
)
@@ -20,19 +21,74 @@ func (c *compose) UnmarshalYAML(n *yaml.Node) error {
return nodeErr(n, "expecting mapping node")
}
return iterator(n, func(k, v *yaml.Node) error {
var (
nsRef string
err error
)
// 1st pass: handle doc-level references
err = iterator(n, func(k, v *yaml.Node) error {
switch k.Value {
case "namespace":
c.namespaces = ComposeNamespaceSet{&ComposeNamespace{}}
return v.Decode(&c.namespaces[0])
if def := findKeyNode(n, "namespaces"); def != nil {
return nodeErr(def, "cannot combine namespace reference and namespaces definition")
}
if err := decodeScalar(v, "namespace ref", &nsRef); err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
// 2nd pass: handle definitions
return iterator(n, func(k, v *yaml.Node) error {
switch k.Value {
case "namespaces":
return v.Decode(&c.namespaces)
case "modules":
return v.Decode(&c.modules)
if err = v.Decode(&c.modules); err != nil {
return err
}
return c.modules.setNamespaceRef(nsRef)
case "records":
return v.Decode(&c.records)
if err = v.Decode(&c.records); err != nil {
return err
}
return c.records.setNamespaceRef(nsRef)
}
return nil
})
}
func (wrap compose) MarshalEnvoy() ([]envoy.Node, error) {
nn := make([]envoy.Node, 0, 100)
if wrap.namespaces != nil {
if tmp, err := wrap.namespaces.MarshalEnvoy(); err != nil {
return nil, err
} else {
nn = append(nn, tmp...)
}
}
if wrap.modules != nil {
if tmp, err := wrap.modules.MarshalEnvoy(); err != nil {
return nil, err
} else {
nn = append(nn, tmp...)
}
}
return nn, nil
}
+58 -13
View File
@@ -3,25 +3,27 @@ package yaml
import (
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/envoy"
"github.com/cortezaproject/corteza-server/pkg/handle"
"gopkg.in/yaml.v3"
)
type (
ComposeModule struct {
res *types.Module
Rbac `yaml:",inline"`
res *types.Module
refNamespace string
*rbacRules
}
ComposeModuleSet []*ComposeModule
ComposeModuleField struct {
res *types.ModuleField `yaml:",inline"`
Rbac `yaml:",inline"`
res *types.ModuleField `yaml:",inline"`
*rbacRules
}
ComposeModuleFieldSet []*ComposeModuleField
)
func (set *ComposeModuleSet) UnmarshalYAML(n *yaml.Node) error {
func (wset *ComposeModuleSet) UnmarshalYAML(n *yaml.Node) error {
return iterator(n, func(k, v *yaml.Node) (err error) {
var (
wrap = &ComposeModule{}
@@ -48,11 +50,38 @@ func (set *ComposeModuleSet) UnmarshalYAML(n *yaml.Node) error {
wrap.res.Name = k.Value
}
*set = append(*set, wrap)
*wset = append(*wset, wrap)
return
})
}
func (wset ComposeModuleSet) setNamespaceRef(ref string) error {
for _, res := range wset {
if res.refNamespace != "" && ref != res.refNamespace {
return fmt.Errorf("cannot override namespace reference %s with %s", res.refNamespace, ref)
}
res.refNamespace = ref
}
return nil
}
func (wset ComposeModuleSet) MarshalEnvoy() ([]envoy.Node, error) {
// namespace usually have bunch of sub-resources defined
nn := make([]envoy.Node, 0, len(wset)*10)
for _, res := range wset {
if tmp, err := res.MarshalEnvoy(); err != nil {
return nil, err
} else {
nn = append(nn, tmp...)
}
}
return nn, nil
}
func (wrap *ComposeModule) UnmarshalYAML(n *yaml.Node) error {
if wrap.res == nil {
wrap.res = &types.Module{}
@@ -65,7 +94,8 @@ func (wrap *ComposeModule) UnmarshalYAML(n *yaml.Node) error {
return iterator(n, func(k, v *yaml.Node) (err error) {
switch k.Value {
case "name":
return decodeScalar(v, &wrap.res.Name)
return decodeScalar(v, "module name", &wrap.res.Name)
case "fields":
if !isKind(v, yaml.MappingNode) {
return nodeErr(n, "field definition must be a map")
@@ -81,12 +111,23 @@ func (wrap *ComposeModule) UnmarshalYAML(n *yaml.Node) error {
wrap.res.Fields = aux.set()
return nil
case "allow", "deny":
return decodeAccessRoleOps(wrap.rbacRules, types.ModuleRBACResource, k, v)
}
return nil
})
}
func (wrap ComposeModule) MarshalEnvoy() ([]envoy.Node, error) {
nn := make([]envoy.Node, 0, 16)
nn = append(nn, &envoy.ComposeModuleNode{Module: wrap.res})
return nn, nil
}
func (set *ComposeModuleFieldSet) UnmarshalYAML(n *yaml.Node) error {
return iterator(n, func(k, v *yaml.Node) (err error) {
var (
@@ -138,25 +179,25 @@ func (wrap *ComposeModuleField) UnmarshalYAML(n *yaml.Node) error {
return fmt.Errorf("name should be encoded as field definition key")
case "label":
return decodeScalar(v, &wrap.res.Label)
return decodeScalar(v, "module field label", &wrap.res.Label)
case "kind", "type":
return decodeScalar(v, &wrap.res.Kind)
return decodeScalar(v, "module field kind", &wrap.res.Kind)
case "options":
return v.Decode(&wrap.res.Options)
case "private":
return decodeScalar(v, &wrap.res.Private)
return decodeScalar(v, "module field private", &wrap.res.Private)
case "required":
return decodeScalar(v, &wrap.res.Required)
return decodeScalar(v, "module field required", &wrap.res.Required)
case "visible":
return decodeScalar(v, &wrap.res.Visible)
return decodeScalar(v, "module field visible", &wrap.res.Visible)
case "multi":
return decodeScalar(v, &wrap.res.Multi)
return decodeScalar(v, "module field multi", &wrap.res.Multi)
case "default":
return fmt.Errorf("field.default /// to be imple,emted")
@@ -169,6 +210,10 @@ func (wrap *ComposeModuleField) UnmarshalYAML(n *yaml.Node) error {
//
// return
//})
case "allow", "deny":
return decodeAccessRoleOps(wrap.rbacRules, types.ModuleFieldRBACResource, k, v)
}
return nil
+61 -7
View File
@@ -2,16 +2,24 @@ package yaml
import (
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/envoy"
"github.com/cortezaproject/corteza-server/pkg/handle"
"gopkg.in/yaml.v3"
)
type (
ComposeNamespace struct {
res *types.Namespace `yaml:",inline"`
ref string
Modules ComposeModuleSet
Rbac `yaml:",inline"`
// when namespace is at least partially defined
res *types.Namespace `yaml:",inline"`
// when we only have reference (slug) to namespace
ref string
// all known modules on a namespace
modules ComposeModuleSet
// module's RBAC rules
*rbacRules
}
ComposeNamespaceSet []*ComposeNamespace
)
@@ -53,7 +61,23 @@ func (wset *ComposeNamespaceSet) UnmarshalYAML(n *yaml.Node) error {
})
}
func (wset ComposeNamespaceSet) MarshalEnvoy() ([]envoy.Node, error) {
// namespace usually have bunch of sub-resources defined
nn := make([]envoy.Node, 0, len(wset)*10)
for _, res := range wset {
if tmp, err := res.MarshalEnvoy(); err != nil {
return nil, err
} else {
nn = append(nn, tmp...)
}
}
return nn, nil
}
func (wrap *ComposeNamespace) UnmarshalYAML(n *yaml.Node) error {
if isKind(n, yaml.ScalarNode) {
wrap.ref = n.Value
return nil
@@ -73,16 +97,46 @@ func (wrap *ComposeNamespace) UnmarshalYAML(n *yaml.Node) error {
return iterator(n, func(k, v *yaml.Node) (err error) {
switch k.Value {
case "slug":
return decodeScalar(v, &wrap.res.Slug)
return decodeScalar(v, "namespace slug", &wrap.res.Slug)
case "name":
return decodeScalar(v, &wrap.res.Name)
return decodeScalar(v, "namespace name", &wrap.res.Name)
case "enabled":
return decodeScalar(v, &wrap.res.Enabled)
return decodeScalar(v, "namespace enabled", &wrap.res.Enabled)
case "modules":
return v.Decode(&wrap.modules)
case "allow", "deny":
if wrap.rbacRules == nil {
wrap.rbacRules = &rbacRules{}
}
return decodeAccessRoleOps(wrap.rbacRules, types.NamespaceRBACResource, k, v)
}
return nil
})
}
func (wrap ComposeNamespace) MarshalEnvoy() ([]envoy.Node, error) {
nn := make([]envoy.Node, 0, 1+len(wrap.modules))
nn = append(nn, &envoy.ComposeNamespaceNode{Ns: wrap.res})
if tmp, err := wrap.modules.MarshalEnvoy(); err != nil {
return nil, err
} else {
nn = append(nn, tmp...)
}
// @todo rbac
//if tmp, err := wrap.rules.MarshalEnvoy(); err != nil {
// return nil, err
//} else {
// nn = append(nn, tmp...)
//}
return nn, nil
}
+13 -12
View File
@@ -2,7 +2,8 @@ package yaml
import (
"fmt"
"github.com/davecgh/go-spew/spew"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/envoy"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
"os"
@@ -64,17 +65,17 @@ func TestComposeNamespace_UnmarshalYAML(t *testing.T) {
req.Equal("crm", doc.compose.namespaces[0].res.Slug)
})
t.Run("compose namespace file 2", func(t *testing.T) {
doc, err := file(2)
req.NoError(err)
req.NotNil(doc)
spew.Dump(doc.compose)
req.NotNil(doc.compose)
req.Len(doc.compose.namespaces, 1)
req.NotNil(doc.compose.namespaces[0])
}
req.Equal("CRM", doc.compose.namespaces[0].res.Name)
req.Equal("crm", doc.compose.namespaces[0].res.Slug)
})
func TestComposeNamespace_MarshalEnvoy(t *testing.T) {
var (
req = require.New(t)
wrap = ComposeNamespace{res: &types.Namespace{ID: 42}}
nn, err = wrap.MarshalEnvoy()
)
req.NoError(err)
req.NotEmpty(nn)
req.Equal(uint64(42), nn[0].(*envoy.ComposeNamespaceNode).Ns.ID)
}
+38 -12
View File
@@ -1,7 +1,9 @@
package yaml
import (
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/envoy"
"github.com/cortezaproject/corteza-server/pkg/handle"
"gopkg.in/yaml.v3"
)
@@ -10,11 +12,12 @@ type (
ComposeRecord struct {
res *types.Record `yaml:",inline"`
values ComposeRecordValues `yaml:"values"`
moduleRef string
createdByRef string
updatedByRef string
deletedByRef string
ownedByRef string
refModule string
refNamespace string
refCreatedBy string
refUpdatedBy string
refDeletedBy string
refOwnedBy string
}
ComposeRecordSet []*ComposeRecord
@@ -51,7 +54,7 @@ func (wset *ComposeRecordSet) UnmarshalYAML(n *yaml.Node) error {
if isKind(v, yaml.SequenceNode) {
// multiple records defined
return iterator(v, func(_, r *yaml.Node) error {
var wrap = &ComposeRecord{moduleRef: moduleRef}
var wrap = &ComposeRecord{refModule: moduleRef}
if err = r.Decode(&wrap); err != nil {
return err
}
@@ -63,7 +66,7 @@ func (wset *ComposeRecordSet) UnmarshalYAML(n *yaml.Node) error {
if isKind(v, yaml.MappingNode) {
// one record defined
var wrap = &ComposeRecord{moduleRef: moduleRef}
var wrap = &ComposeRecord{refModule: moduleRef}
if err = v.Decode(&wrap); err != nil {
return
}
@@ -75,6 +78,29 @@ func (wset *ComposeRecordSet) UnmarshalYAML(n *yaml.Node) error {
})
}
func (wset ComposeRecordSet) MarshalEnvoy() ([]envoy.Node, error) {
// namespace usually have bunch of sub-resources defined
var (
nn = []envoy.Node{}
)
// @todo
return nn, nil
}
func (set ComposeRecordSet) setNamespaceRef(ref string) error {
for _, res := range set {
if res.refNamespace != "" && ref != res.refNamespace {
return fmt.Errorf("cannot override namespace reference %s with %s", res.refNamespace, ref)
}
res.refNamespace = ref
}
return nil
}
func (wrap *ComposeRecord) UnmarshalYAML(n *yaml.Node) error {
if !isKind(n, yaml.MappingNode) {
return nodeErr(n, "expecting mapping node for record definition")
@@ -87,7 +113,7 @@ func (wrap *ComposeRecord) UnmarshalYAML(n *yaml.Node) error {
return iterator(n, func(k, v *yaml.Node) error {
switch k.Value {
case "module":
return decodeRef(v, "module", &wrap.moduleRef)
return decodeRef(v, "module", &wrap.refModule)
case "values":
// Use aux structure to decode record values into RVS
@@ -106,13 +132,13 @@ func (wrap *ComposeRecord) UnmarshalYAML(n *yaml.Node) error {
case "deletedAt":
return v.Decode(&wrap.res.DeletedAt)
case "createdBy":
return decodeRef(v, "user", &wrap.createdByRef)
return decodeRef(v, "createdBy user", &wrap.refCreatedBy)
case "updatedBy":
return decodeRef(v, "user", &wrap.updatedByRef)
return decodeRef(v, "updatedBy user", &wrap.refUpdatedBy)
case "deletedBy":
return decodeRef(v, "user", &wrap.deletedByRef)
return decodeRef(v, "deletedBy user", &wrap.refDeletedBy)
case "ownedBy":
return decodeRef(v, "user", &wrap.ownedByRef)
return decodeRef(v, "ownedBy user", &wrap.refOwnedBy)
default:
return nodeErr(k, "unsupported key %s used for record definition", k.Value)
+2 -5
View File
@@ -34,13 +34,10 @@ func TestCompose_UnmarshalYAML(t *testing.T) {
req.Len(c.namespaces, 1)
c, err = parse(&compose{}, `namespace: { }`)
req.NoError(err)
req.NotNil(c)
req.Len(c.namespaces, 1)
req.Error(err)
c, err = parse(&compose{}, `namespace: foo`)
req.NoError(err)
req.NotNil(c)
req.Len(c.namespaces, 1)
req.Equal("foo", c.namespaces[0].ref)
req.Empty(c.namespaces, "namespace ref should not result in namespace definition")
}
+53 -54
View File
@@ -3,7 +3,6 @@ package yaml
import (
"context"
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/envoy"
"gopkg.in/yaml.v3"
"io"
@@ -94,7 +93,7 @@ func (y *decoder) Decode(ctx context.Context, r io.Reader, i os.FileInfo) ([]env
// for modRef, rr := range c.Records {
// // We can define a basic module representation as it will be updated later
// // during validation/runtime
// mod := &types.Module{}
// mod := &types.module{}
// mod.Handle = modRef
// mod.Name = modRef
//
@@ -109,55 +108,55 @@ func (y *decoder) Decode(ctx context.Context, r io.Reader, i os.FileInfo) ([]env
// return nn, nil
//}
func (y *decoder) convertNamespaces(nss ComposeNamespaceSet) ([]envoy.Node, error) {
nn := make([]envoy.Node, 0, 2)
for _, ns := range nss {
nn = append(nn, &envoy.ComposeNamespaceNode{Ns: ns.res})
// Nested modules
if ns.Modules != nil {
mm, err := y.convertModules(ns.Modules, ns.res)
if err != nil {
return nil, err
}
nn = append(nn, mm...)
}
// @todo nested RBAC
}
return nn, nil
}
func (y *decoder) convertModules(mm ComposeModuleSet, ns *types.Namespace) ([]envoy.Node, error) {
nn := make([]envoy.Node, 0)
for _, m := range mm {
nn = append(nn, &envoy.ComposeModuleNode{
Mod: m.res,
Ns: ns,
})
// @todo nested resources; should there be any?
}
return nn, nil
}
func (y *decoder) convertRecords(rr ComposeRecordSet, m *types.Module) ([]envoy.Node, error) {
// Iterator function for providing records to be imported.
// This doesn't do any validation; that should be handled by other layers.
f := func(f func(record *types.Record) error) error {
//for _, r := range rr {
//err := f(r.res)
//if err != nil {
// return err
//}
//}
return nil
}
return []envoy.Node{&envoy.ComposeRecordNode{Mod: m, Walk: f}}, nil
}
//func (y *decoder) convertNamespaces(nss ComposeNamespaceSet) ([]envoy.Node, error) {
// nn := make([]envoy.Node, 0, 2)
//
// for _, ns := range nss {
// nn = append(nn, &envoy.ComposeNamespaceNode{Ns: ns.res})
//
// // Nested modules
// if ns.modules != nil {
// mm, err := y.convertModules(ns.modules, ns.res)
// if err != nil {
// return nil, err
// }
// nn = append(nn, mm...)
// }
//
// // @todo nested RBAC
// }
//
// return nn, nil
//}
//
//func (y *decoder) convertModules(mm ComposeModuleSet, ns *types.Namespace) ([]envoy.Node, error) {
// nn := make([]envoy.Node, 0)
//
// for _, m := range mm {
// nn = append(nn, &envoy.ComposeModuleNode{
// module: m.res,
// Ns: ns,
// })
//
// // @todo nested resources; should there be any?
// }
//
// return nn, nil
//}
//
//func (y *decoder) convertRecords(rr ComposeRecordSet, m *types.Module) ([]envoy.Node, error) {
// // Iterator function for providing records to be imported.
// // This doesn't do any validation; that should be handled by other layers.
// f := func(f func(record *types.Record) error) error {
// //for _, r := range rr {
// //err := f(r.res)
// //if err != nil {
// // return err
// //}
// //}
//
// return nil
// }
//
// return []envoy.Node{&envoy.ComposeRecordNode{Mod: m, Walk: f}}, nil
//}
+11 -1
View File
@@ -30,6 +30,16 @@ func (doc *Document) UnmarshalYAML(n *yaml.Node) error {
func (doc *Document) Decode(ctx context.Context, l loader) ([]envoy.Node, error) {
nn := make([]envoy.Node, 0, 100)
if doc.compose != nil {
if tmp, err := doc.compose.MarshalEnvoy(); err != nil {
return nil, err
} else {
nn = append(nn, tmp...)
}
}
return nn, nil
//// In case of namespaces...
//if doc.Namespaces != nil {
// nodes, err := doc.Namespaces.Decode(ctx, l)
@@ -67,7 +77,7 @@ func (doc *Document) Decode(ctx context.Context, l loader) ([]envoy.Node, error)
// for modRef, rr := range doc.Records {
// // We can define a basic module representation as it will be updated later
// // during validation/runtime
// mod := &types.Module{}
// mod := &types.module{}
// mod.Handle = modRef
// mod.Name = modRef
//
+48 -4
View File
@@ -1,9 +1,53 @@
package yaml
import (
"github.com/cortezaproject/corteza-server/pkg/rbac"
"gopkg.in/yaml.v3"
)
type (
RbacRules map[string][]string
Rbac struct {
Allow RbacRules
Deny RbacRules
rbacRules struct {
// mapping unresolved roles to defined RBAC rules
rules map[string]rbac.RuleSet
}
)
// Decodes RBAC rules defined as access/role/ops...
func decodeAccessRoleOps(wrap *rbacRules, res rbac.Resource, k, v *yaml.Node) error {
var (
access rbac.Access
)
if wrap.rules == nil {
wrap.rules = make(map[string]rbac.RuleSet)
}
if !isKind(v, yaml.MappingNode) {
return nodeErr(v, "rbac rule definition must be a map")
}
if k.Value == "allow" {
access = rbac.Allow
}
return iterator(v, func(k, v *yaml.Node) error {
var (
role = k.Value
)
if _, set := wrap.rules[role]; !set {
wrap.rules[role] = rbac.RuleSet{}
}
if !isKind(v, yaml.SequenceNode) {
return nodeErr(v, "rbac rule operations list must be a sequence")
}
return iterator(v, func(_, v *yaml.Node) error {
rule := &rbac.Rule{Resource: res, Operation: rbac.Operation(v.Value), Access: access}
wrap.rules[role] = append(wrap.rules[role], rule)
return nil
})
})
}
-10
View File
@@ -1,10 +0,0 @@
namespace:
name: CRM
slug: crm
allow:
everyone:
- module.create
- read
deny:
everyone:
- delete
+2 -2
View File
@@ -84,9 +84,9 @@ func findKeyNode(n *yaml.Node, key string) *yaml.Node {
}
// Checks validity of ref node and sets the value to given arg ptr
func decodeScalar(n *yaml.Node, val interface{}) error {
func decodeScalar(n *yaml.Node, name string, val interface{}) error {
if !isKind(n, yaml.ScalarNode) {
return nodeErr(n, "expecting scalar value")
return nodeErr(n, "expecting scalar value for %s", name)
}
return n.Decode(val)